release: move publication orchestration into tools/release.zig, pin rotated subkey
Gates / package (push) Successful in 8m51s
Release / guard (push) Successful in 1m33s
Gates / test-aarch64 (push) Successful in 4m24s
Gates / frontend (push) Successful in 44s
Gates / package (push) Successful in 33s
Gates / container (push) Successful in 35s
Release / gates (push) Successful in 8m24s
Gates / test-aarch64 (push) Successful in 7m56s
Gates / frontend (push) Successful in 1m31s
Gates / test (push) Failing after 16m8s
Gates / container (push) Successful in 5m11s
CI / gates (push) Failing after 30m3s
Gates / test (push) Successful in 2m7s
Release / publish (push) Failing after 10m20s
Gates / package (push) Successful in 8m51s
Release / guard (push) Successful in 1m33s
Gates / test-aarch64 (push) Successful in 4m24s
Gates / frontend (push) Successful in 44s
Gates / package (push) Successful in 33s
Gates / container (push) Successful in 35s
Release / gates (push) Successful in 8m24s
Gates / test-aarch64 (push) Successful in 7m56s
Gates / frontend (push) Successful in 1m31s
Gates / test (push) Failing after 16m8s
Gates / container (push) Successful in 5m11s
CI / gates (push) Failing after 30m3s
Gates / test (push) Successful in 2m7s
Release / publish (push) Failing after 10m20s
This commit is contained in:
@@ -580,6 +580,53 @@ was reproduced before it was fixed.
|
||||
would have turned a licence check into an unpinned fetch. Reproduced: it
|
||||
fetched `vite@8.2.0` over the pinned `8.1.5`.
|
||||
|
||||
23. **`actions/checkout` destroys the annotated tag object.** Found by the first
|
||||
live dry run, not by review: on a tag ref, checkout fetches the *commit* SHA
|
||||
into `refs/tags/<tag>`, so the signed tag reads as lightweight and the guard
|
||||
refuses it as unannotated. Both jobs that read the tag object — signature
|
||||
verification in the guard, the tagger date in the publish job — now force-
|
||||
refetch `refs/tags/$TAG` from origin first. The same run also proved the
|
||||
fail-closed secret guard for real: the first dry-run attempt ran with no
|
||||
secrets configured (they were on the wrong repository) and stopped in the
|
||||
guard with nothing built or pushed.
|
||||
|
||||
24. **Publication orchestration moved out of workflow shell into
|
||||
`tools/release.zig`.** Ruling 5 already moved the packaging asserts out of
|
||||
CI shell for one reason — "checks that only exist inside a workflow file are
|
||||
the brittleness this exists to remove" — and the release job was the larger
|
||||
half of the same problem, left in place. Three live failures came out of it,
|
||||
and each was found by executing the workflow, which is the most expensive
|
||||
place to find anything: `actions/checkout` replacing the annotated tag object
|
||||
(deviation 23), the refetch that fixed it having no credentials because
|
||||
`persist-credentials` is off, and the multiline armored subkey escaping the
|
||||
runner's log masker, which masks per line.
|
||||
|
||||
Twelve subcommands, one per step group: `guard-tag`, `guard-ancestry`,
|
||||
`guard-releases`, `resolve`, `changelog`, `image`,
|
||||
`verify-image-binaries`, `sign`, `draft`, `latest`, `publish`, `scrub`. Every
|
||||
behaviour recorded in deviations 10 to 15 and 23 is carried over unchanged —
|
||||
probe-adopt, the VALIDSIG last field, the subkey-only import and signing
|
||||
probe, the array-shape guard on the releases payload, the `:latest` label
|
||||
read, the publish re-read, the per-home `gpgconf --kill`, the tag refetch.
|
||||
What is new is that the semver ordering, VALIDSIG field selection, challenge
|
||||
parsing, changelog extraction, checksum-line parsing, colon-format parsing
|
||||
and payload-shape guard are 25 unit tests in `zig build test` rather than
|
||||
shell that only ever runs on a tag push. `release.yml` keeps the triggers,
|
||||
the concurrency group, the job graph, the SHA pins, the two pinned
|
||||
fingerprints and the fail-closed secret presence check — which stays as
|
||||
shell, deliberately, so that it runs before the tool is even compiled.
|
||||
|
||||
The same reasoning applies to the `jq` pipeline of the bundled-package gate,
|
||||
which moved to `web/scripts/bundledPackages.mjs` with its own vitest
|
||||
coverage and an `npm run assert-bundled` entry point.
|
||||
|
||||
**Secret contract change:** `RELEASE_GPG_SUBKEY` becomes
|
||||
`RELEASE_GPG_SUBKEY` and holds `base64 -w0` of the armored
|
||||
`--export-secret-subkeys` output rather than the armored text. Manual
|
||||
prerequisite 1 and 3 change accordingly. The tool decodes it in memory and
|
||||
writes it to a mode-600 file inside the temporary `GNUPGHOME`. A single-line
|
||||
secret is one the masker can actually mask.
|
||||
|
||||
### Not verified, and why
|
||||
|
||||
- **No workflow has ever executed.** `release.yml` and `gates.yml` were validated
|
||||
|
||||
Reference in New Issue
Block a user