fix(scripts): resolve the personal signing key from the repo and overwrite partial signatures - #3904
Conversation
…write partial signatures `cmd_sign` and `cmd_cosign` read `user.signingkey` after `enter_release_dir` has moved into the release staging directory, so a repo-local key is never seen and the global one is used. With a global SSH signing key that is a `.pub` path, and gpg aborts with "No secret key" after the first Start9 signature. Read the key from `$REPO_ROOT`, and skip the personal signature when that repo signs with SSH, which gpg cannot use. Pass `--yes` to the detach-sign calls so re-running `sign` or `cosign` after a partial failure overwrites the half-written `signatures/*.asc` instead of stopping at gpg's overwrite prompt. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
@helix-nine review this PR |
helix-nine
left a comment
There was a problem hiding this comment.
Reviewed git diff origin/master...HEAD with a high-effort fan-out and independent verification of each candidate. bash -n scripts/manage-release.sh passes.
Two changes are needed:
-
scripts/manage-release.sh:316-317— respect the configured OpenPGP format and program. The guard excludes onlyssh, but Git also supportsx509; an X.509user.signingkeytherefore reaches the literal OpenPGPgpgcalls and aborts signing/cosigning with “No secret key.” The new repo-local key lookup can also select a key provided through repo-localgpg.openpgp.program/gpg.program, while the script still invokes literalgpg. Please retain the personal key only whengpg.formatis unset oropenpgp, and use the configured OpenPGP program (falling back togpg) for signing and export. -
projects/start-os/docs/src/installing-startos.md:127— align the documented archive contents with SSH signing. This change intentionally omits the releaser signature and key when the repo uses SSH signing, but the user guide unconditionally promises a second releaser signature. Remove that assertion so an expected omission is not mistaken for an incomplete archive.
The comment pass was clean.
…e configured program `gpg.format` can also be `x509`, whose key the literal `gpg` calls cannot use, so the personal signature is kept only when the format is unset or `openpgp`. The sign and export calls for that key go through the repo's `gpg.openpgp.program`, then `gpg.program`, then `gpg`, so a key that only a configured program can reach still signs. The install guide no longer promises the second signature unconditionally. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Both addressed in 37010e8: the personal key is kept only when |
helix-nine
left a comment
There was a problem hiding this comment.
Re-reviewed the fix as git diff 61ade9ea8b5404b689524bca093d56b030d9f947..37010e8cd3eb849de0668709c36f7045c9101079 with a high-effort fan-out and independent verification. bash -n scripts/manage-release.sh passes. My first review's recommendation to use Git's configured program was underspecified; the fix exposed three additional configuration semantics that need handling.
-
scripts/manage-release.sh:321-323,1340,1346,1376,1378— the configured program resolution does not match Git's contract. Three valid configurations fail:gpg.programandgpg.openpgp.programare aliases applied in configuration order, but these separate lookups always prefer any modern-name value. A globalgpg.openpgp.programtherefore incorrectly beats a repo-localgpg.program.- Git runs a slash-relative program from the worktree root; the script invokes it later from the release directory, producing exit 127.
- Git only guarantees that a custom OpenPGP program supports its
-bsau/--verifyinterface. It need not support the full--detach-sign --armor -oand--export -ainterface now assumed here.
Please preserve Git's alias ordering and relative-path semantics, and do not infer full GnuPG compatibility from the Git setting. The release flow needs either a separately explicit full-GPG contract/override or signing through Git's guaranteed interface with export capability handled separately.
-
scripts/manage-release.sh:1336-1350— skipped personal signing can republish stale files. On asignrerun after the personal signer becomes unavailable or changes to SSH/X.509, the guarded writes are skipped but the previous*.${GH_USER}.ascand${GH_USER}.key.ascfiles remain insignatures/and are archived again. If the staged artifacts changed, those retained signatures are invalid. Ensure skipped regeneration cannot silently republish the current signer's stale files while preserving intentionally retained cosigners. -
projects/start-os/docs/src/installing-startos.md:127— the remaining attribution is still too narrow.cmd_cosigncan append signatures from additional maintainers after the release was cut, so there may be multiple signatures and they need not belong to the release cutter. “Additional maintainer signatures may be included” states the archive shape without asserting unsupported provenance.
The comment pass was clean.
…tale copies on rerun The release tooling's signing contract is GnuPG on PATH: the Start9 key, the apt suite and pre-check all go through `gpg`, and the personal signature now does too. Git's `gpg.program` is not consulted: Git guarantees only its own `-bsau`/`--verify` interface for that program and resolves a relative path from the worktree, neither of which holds for the `--detach-sign`/`--export` calls made from the release directory. A `sign` rerun removes the current signer's earlier `*.<user>.asc` and `<user>.key.asc` before regenerating, so a signature that is skipped this time cannot ride along stale. Other maintainers' cosignatures are left in place. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Addressed in b70b50f.
|
helix-nine
left a comment
There was a problem hiding this comment.
Re-reviewed git diff 37010e8cd3eb849de0668709c36f7045c9101079..b70b50f044ff741f86406003060bd31ed08ecb65 with a high-effort fan-out and independent verification. The configured-program and documentation findings are addressed, and bash -n scripts/manage-release.sh passes. I also added the required StartOS label for the book change.
Two retry-path issues remain:
-
scripts/manage-release.sh:316,1338-1344,1359-1376— a configured key is assumed to be available to PATHgpg. Keeping GnuPG-on-PATH as the release contract is coherent, but a nonempty Gituser.signingkeydoes not prove that thisgpgcan access it. A stale key or one backed only by Git's custom program passes the guards, then optional personal signing abortssignafter the release has already been tagged/published.cosigndownloads the archive before failing the same way. Please preflight the personal key against PATHgpg: skip it with the existing warning insign, and fail before downloading anything incosign. -
scripts/manage-release.sh:1333-1348,1365-1378— persistent staging can republish stale signatures. The new cleanup removes only the resolved current user's files. On a forced re-pull, signatures from other maintainers can remain against replaced artifact bytes; ifGH_USERresolution fails, no personal files are removed.cosignalso extracts the downloaded archive over the persistent local directory, so local-only or obsolete files can be resurrected. Rebuildsign's signature directory from empty. Forcosign, extract the current remote archive into an empty directory, then remove the current user's entries before regenerating them; that preserves other signatures actually present in the downloaded archive without retaining local residue.
The comment pass was clean.
…signature dir on every run A configured `user.signingkey` proves nothing about the `gpg` on PATH, so the personal key is kept only if `gpg --list-secret-keys` knows it; `sign` then skips it with the existing warning and `cosign` fails before downloading. `sign` rebuilds `signatures/` from empty, and `cosign` extracts the release's current archive into an empty directory and drops the current user's entries before regenerating them, so nothing left in the staging directory from an earlier run can ride along against replaced artifacts. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Addressed in a13c38c.
|
Helix-Harness: pi Helix-Model: openai-codex/gpt-5.6-sol
|
Addressed the remaining signer-namespace collision in |
helix-nine
left a comment
There was a problem hiding this comment.
Re-reviewed through effd10284. All requested changes are addressed; the final reserved-namespace guard passes the focused tests, shell syntax check, and diff check.
Summary
cmd_signandcmd_cosignresolveuser.signingkeyafterenter_release_dirhascd'd into the release staging directory, so the repo-local key is never seen and the global one is used. With a global SSH signing key that is a.pubpath, and gpg aborts withNo secret keyafter writing the first Start9 signature. This happened cutting start-cli 2.0.0.$REPO_ROOT, and keep the personal signature only when the repo'sgpg.formatis unset oropenpgpandgpg --list-secret-keyson PATH knows the key. Otherwisesignskips it with the existing warning andcosignfails before downloading anything. Signing stays ongpgfrom PATH, the contract the Start9 key, the apt suite signature and pre-check already rely on; Git'sgpg.programis deliberately not consulted, since Git guarantees only its-bsau/--verifyinterface for it and resolves a relative path from the worktree.signrebuildssignatures/from empty on every run.cosignextracts the release's current archive into an empty directory and removes the current user's entries before regenerating them, so other maintainers' signatures actually present in the archive survive and nothing left in the staging directory from an earlier run is republished. Thestart9signer name is reserved for the organizational signature files.--yesto the detach-sign calls so re-runningsignorcosignafter a partial failure overwrites the half-writtensignatures/*.ascinstead of stopping at gpg's overwrite prompt.signatures.tar.gz, without asserting who they belong to.Verified by signing start-cli 2.0.0, start-tunnel 1.3.0 and start-registry 1.1.0 with the patched script.