release: stage dist before signing, and sign via a named volume #188

Merged
sirius merged 1 commit from wt/t_3e3bc228 into main 2026-10-21 02:59:22 +00:00
Owner

Fixes the two publish-job bugs that blocked v0.5.0.

1. The sign step could not see .ci-tools. It ran
docker run --rm -v "${GITHUB_WORKSPACE}:/work" .... GITHUB_WORKSPACE is a
path inside the job container; docker resolves a bind mount's source on the
host, where it does not exist, so /work arrived empty and the script was
missing. Run 768: bash: .ci-tools/scripts/sign-release.sh: No such file or directory (exit 127).

Reproduced against the pinned image locally, then fixed with the same pattern
the build jobs already use — named volume + docker cp in/out:

$ docker run --rm -v "/workspace/sirius/onionwire:/work" -w /work rust@sha256:93ce... bash -c 'ls -la /work; bash .ci-tools/scripts/sign-release.sh x'
--- /work contents (host path does not exist) ---
total 8
drwxr-xr-x 2 root root 4096 .
drwxr-xr-x 1 root root 4096 ..
bash: .ci-tools/scripts/sign-release.sh: No such file or directory
exit=127

Named-volume rehearsal, same image, same script, throwaway key:

KEYGEN_OK
sign-release: signed and verified onionwire-aarch64-unknown-linux-gnu -> onionwire-aarch64-unknown-linux-gnu.minisig
sign-release: signed and verified onionwire-aarch64-unknown-linux-gnu.sha256 -> onionwire-aarch64-unknown-linux-gnu.sha256.minisig
sign-release: signed and verified onionwire-x86_64-unknown-linux-gnu -> onionwire-x86_64-unknown-linux-gnu.minisig
sign-release: signed and verified onionwire-x86_64-unknown-linux-gnu.sha256 -> onionwire-x86_64-unknown-linux-gnu.sha256.minisig
container exit=0

2. Signing ran before dist/ was populated. The find+cp loop lived in
the publish step, i.e. after the signature step, so dist/ was empty when
the signer looked at it. It is now its own Stage both arch artifacts into dist
step before signing; publish only validates dist/.

Step order is now: download artifacts → stage into dist/ → sign (fail closed)
→ verify the four .minisig files came back out → publish → fail-closed tag
cleanup. No change to the fail-closed design: no key, no publish.

docs/RELEASING.md's description of the publish job is updated to match.

Fixes the two publish-job bugs that blocked `v0.5.0`. **1. The sign step could not see `.ci-tools`.** It ran `docker run --rm -v "${GITHUB_WORKSPACE}:/work" ...`. `GITHUB_WORKSPACE` is a path *inside* the job container; docker resolves a bind mount's source on the **host**, where it does not exist, so `/work` arrived empty and the script was missing. Run 768: `bash: .ci-tools/scripts/sign-release.sh: No such file or directory` (exit 127). Reproduced against the pinned image locally, then fixed with the same pattern the build jobs already use — named volume + `docker cp` in/out: ``` $ docker run --rm -v "/workspace/sirius/onionwire:/work" -w /work rust@sha256:93ce... bash -c 'ls -la /work; bash .ci-tools/scripts/sign-release.sh x' --- /work contents (host path does not exist) --- total 8 drwxr-xr-x 2 root root 4096 . drwxr-xr-x 1 root root 4096 .. bash: .ci-tools/scripts/sign-release.sh: No such file or directory exit=127 ``` Named-volume rehearsal, same image, same script, throwaway key: ``` KEYGEN_OK sign-release: signed and verified onionwire-aarch64-unknown-linux-gnu -> onionwire-aarch64-unknown-linux-gnu.minisig sign-release: signed and verified onionwire-aarch64-unknown-linux-gnu.sha256 -> onionwire-aarch64-unknown-linux-gnu.sha256.minisig sign-release: signed and verified onionwire-x86_64-unknown-linux-gnu -> onionwire-x86_64-unknown-linux-gnu.minisig sign-release: signed and verified onionwire-x86_64-unknown-linux-gnu.sha256 -> onionwire-x86_64-unknown-linux-gnu.sha256.minisig container exit=0 ``` **2. Signing ran before `dist/` was populated.** The `find`+`cp` loop lived in the publish step, i.e. *after* the signature step, so `dist/` was empty when the signer looked at it. It is now its own `Stage both arch artifacts into dist` step before signing; publish only validates `dist/`. Step order is now: download artifacts → stage into `dist/` → sign (fail closed) → verify the four `.minisig` files came back out → publish → fail-closed tag cleanup. No change to the fail-closed design: no key, no publish. `docs/RELEASING.md`'s description of the publish job is updated to match.
The publish job has never completed. Two plumbing bugs, no crypto involved:

1. The sign step ran `docker run -v "${GITHUB_WORKSPACE}:/work"`.
   GITHUB_WORKSPACE is a path INSIDE the job container, but docker resolves a
   bind mount's source on the HOST, where that path does not exist — so /work
   arrived empty and the script was absent. Run 768 failed with
   "bash: .ci-tools/scripts/sign-release.sh: No such file or directory" (127).
   Rehearsed locally against the pinned image: the bind mount yields an empty
   /work, the same command with a named volume + docker cp signs and
   self-verifies all four assets. Use the build jobs' pattern.

2. Signing ran before the files it signs existed. The find+cp loop that fills
   dist/ lived in the publish step, after the signature step. Move it into its
   own "Stage both arch artifacts into dist" step before signing, and let
   publish only validate dist/.

Fail-closed design unchanged: no MINISIGN_SECRET_KEY stops before any upload,
signing still precedes publishing, and the tag cleanup step is untouched.
docs/RELEASING.md described the old publish job; it now matches the workflow.
sirius merged commit 08bf6649df into main 2026-10-21 02:59:22 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
sirius/onionwire!188
No description provided.