CI / verify (pull_request) Successful in 1m1s
CI / infrastructure-smoke (pull_request) Successful in 35s
CI / migration-smoke (pull_request) Successful in 1m53s
CI / package-release (pull_request) Failing after 43s
CI / package-publication (pull_request) Skipped
CI / image-build (pull_request) Successful in 29s
CI / deploy-smoke (split) (pull_request) Canceled after 0s
CI / deploy-smoke (same-origin) (pull_request) Canceled after 38s
Publishes one package release train to the Gitea npm registry under River_of_Glory_Church, whose packages are publicly readable on purpose: exactly the .tgz files the package-release gate proved, and nothing else. Nothing is published by this change. - scripts/publish-package-train.ts validates the whole local train before any request (gate manifest hash, version, revision, unmodified source, the nine packages, every artifact's size, SHA-256, integrity, SHA256SUMS line, and inner package.json), then publishes in dependency order with `npm publish <file.tgz>` under a staging tag. Each package is reconciled first (absent: publish; same bytes: accept; other bytes: hard stop, version burned), then read back: metadata (name, version, integrity, dependency maps, normalized bin, tarball on the registry) and the tarball itself, byte for byte, also anonymously. `latest` moves only after all nine verify; reruns converge and never delete anything. It writes a publication record. The token comes from EKKLESIA_PACKAGES_PUBLISH_TOKEN only, through a temporary npm config that refers to the variable. - scripts/test-package-publication.sh proves it against a disposable Gitea 1.27.2 with public owners, a publisher team and an outsider: anonymous reads, refused unauthorized publishing, byte-identical round trips, the registry's own 409, partial-train recovery, the burned version hard stop, and dist-tag retry convergence. - CI: package-release keeps its proven release and hands it on as an artifact with its manifest hash; the new package-publication job publishes exactly that artifact to the disposable Gitea. Artifact actions v3 (node20): v4 refuses any server other than github.com. - .github/workflows/publish-packages.yml publishes to the real registry only by manual dispatch on main, after its own gate run, with the secret in the publish step alone. - docs: the public-read model, the workflow, the record, credentials, immutability policy, provider moves, and the first-publication steps. Co-Authored-By: Claude Opus 5.5 <[email protected]>
93 lines
4.0 KiB
Bash
Executable File
93 lines
4.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# The package release gate (ADR 0053): what must pass before a future step may publish a package
|
|
# train. It publishes nothing.
|
|
#
|
|
# bash scripts/test-package-release.sh [--allow-modified] [--keep <directory>]
|
|
#
|
|
# 1. Builds the public package train from this checkout (`scripts/package-release.ts`): clean build
|
|
# output, pack, inspect, release manifest.
|
|
# 2. Builds it again from a separate worktree of the same commit, at another absolute path, and
|
|
# requires the two release directories to be byte-identical: every tarball, SHA256SUMS, and the
|
|
# manifest.
|
|
# 3. Builds Core's verifier, then installs the release into the standalone fixture and proves it
|
|
# builds, packages, and verifies (`scripts/test-standalone-module.sh`).
|
|
#
|
|
# Nothing is built before step 1: the release builder asserts a clean source tree first, builds, and
|
|
# asserts the build changed none of it. Every offline install uses the workspace install's own store.
|
|
#
|
|
# `--allow-modified` is for local development on a modified source tree. The second build is then
|
|
# made in this checkout again, because a worktree of the commit would not hold the modifications.
|
|
set -euo pipefail
|
|
|
|
repository_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
allow_modified=() keep=""
|
|
while (($#)); do
|
|
case "$1" in
|
|
--allow-modified)
|
|
allow_modified=(--allow-modified)
|
|
shift
|
|
;;
|
|
--keep)
|
|
keep="${2:-}"
|
|
[[ -n "$keep" ]] || { echo "usage: --keep <directory>" >&2; exit 64; }
|
|
shift 2
|
|
;;
|
|
*)
|
|
echo "usage: test-package-release.sh [--allow-modified] [--keep <directory>]" >&2
|
|
exit 64
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# The workspace install's own pnpm store. pnpm chooses a store per file system, so an install in a
|
|
# temporary directory would otherwise look in another, empty one; every install here is offline.
|
|
store="$(dirname "$(cd "$repository_root" && pnpm store path)")"
|
|
export EKKLESIA_PNPM_STORE="$store"
|
|
|
|
work="$(mktemp -d "${TMPDIR:-/tmp}/ekklesia-package-release-XXXXXX")"
|
|
worktree="$work/second-checkout"
|
|
cleanup() {
|
|
if [[ -d "$worktree" ]]; then
|
|
git -C "$repository_root" worktree remove --force "$worktree" >/dev/null 2>&1 || true
|
|
fi
|
|
rm -rf "$work"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
echo "==> Building the package train"
|
|
node "$repository_root/scripts/package-release.ts" --out "$work/first" "${allow_modified[@]}"
|
|
release="$(find "$work/first" -mindepth 1 -maxdepth 1 -type d)"
|
|
|
|
echo "==> Building it again, to prove the artifacts are reproducible"
|
|
if ((${#allow_modified[@]})); then
|
|
node "$repository_root/scripts/package-release.ts" --out "$work/second" "${allow_modified[@]}" >/dev/null
|
|
else
|
|
git -C "$repository_root" worktree add --detach --quiet "$worktree" HEAD
|
|
(cd "$worktree" && pnpm install --offline --frozen-lockfile --store-dir "$store" --reporter=silent)
|
|
node "$worktree/scripts/package-release.ts" --out "$work/second" >/dev/null
|
|
fi
|
|
if ! diff -r "$release" "$(find "$work/second" -mindepth 1 -maxdepth 1 -type d)"; then
|
|
echo "package release gate failed: two builds of the same commit produced different artifacts" >&2
|
|
exit 1
|
|
fi
|
|
echo " byte-identical: $(ls "$release" | wc -l) files"
|
|
|
|
# The consumer proof verifies with Core's own verifier. Built only now, after both releases: the
|
|
# release builder asserts a clean source tree before it builds anything.
|
|
echo "==> Building Core's verifier"
|
|
(cd "$repository_root" && pnpm exec turbo run build --filter=@ekklesia/core --output-logs=errors-only >/dev/null)
|
|
|
|
echo "==> Consuming the release from a standalone module"
|
|
bash "$repository_root/scripts/test-standalone-module.sh" --release "$release" "${allow_modified[@]}"
|
|
|
|
# The release this gate proved, for a later job to publish exactly (`--keep`): copied only now, after
|
|
# every check passed, into a directory that must not hold an earlier one.
|
|
if [[ -n "$keep" ]]; then
|
|
mkdir -p "$keep"
|
|
[[ ! -e "$keep/$(basename "$release")" ]] || { echo "$keep already holds this release" >&2; exit 1; }
|
|
cp -R "$release" "$keep/"
|
|
echo " kept in $keep/$(basename "$release")"
|
|
fi
|
|
|
|
echo "Package release gate passed."
|