fix(release): verify the tag, and publish the changelog not the blurb - #38
Closed
serialexperimentslainnnn wants to merge 2 commits into
Closed
serialexperimentslainnnn wants to merge 2 commits into
serialexperimentslainnnn wants to merge 2 commits into
Conversation
Release 5.0.0
v5.0.0 shipped with an UNVERIFIED tag. Three things had to be wrong at once, and
all three were:
- gen-ci-signing-key.sh generated the key with Name-Real but no Name-Email, so
its uid carried no address at all. GitHub reported it as `emails=` — empty.
- bootstrap-ci.sh never registered the key on the GitHub ACCOUNT. It certified
the key with the YubiKey, which is a different mechanism: certification makes
`gpg --verify` meaningful to a human, registration is what the "Verified"
badge reads. The two were conflated.
- release.yml tagged as `github-actions[bot]@users.noreply.github.com`, an
address that cannot appear on anyone's key.
GitHub marks a signature verified only when the tagger email, an email on a uid
of a registered key, and a verified account email all agree. Any one of the above
defeats it permanently.
The address is now DERIVED, never written down. gen-ci-signing-key.sh reads it
from the maintainer key via `git config user.signingkey`; release.yml reads it
from the signing key it just imported. Each link derives from the previous one,
so rotating the key is sufficient on its own and nothing can drift out of step.
It also keeps the address out of the repository — this project deliberately
publishes no contact email anywhere (CHANGELOG 5.0.0), and a committed script is
published.
Both now fail loudly where they used to continue: the workflow aborts if the
imported key has no email rather than producing another unverifiable tag, and the
generator aborts rather than minting another unusable key.
Also in bootstrap-ci.sh: it no longer re-adds a required reviewer (publication is
automatic on merge to main, and on a single-collaborator repository the merge
already is the human act), and it adds `main` to the deployment branch policy —
without that entry the job is rejected before the workflow is even reached, which
is how the first attempt failed.
Finally, the GitHub Release now carries CHANGELOG.md instead of RELEASE_NOTES.md.
The latter is the Marketplace copy — emoji-led, second person — and that register
belongs on a storefront where someone is deciding whether to install, not in
front of a person who arrived at a release page because something broke.
Different readers, different documents: build.gradle.kts still feeds the
Marketplace panel from RELEASE_NOTES.md. The extracted section is ~27 KB against
a 125 000-character limit, and an empty extraction now fails the release rather
than publishing blank notes.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
v5.0.0 shipped with an unverified tag. Three things had to be wrong at once, and all three were:
gen-ci-signing-key.shName-Realbut noName-Email— GitHub reported the registered key asemails=, emptybootstrap-ci.shrelease.ymlgithub-actions[bot]@users.noreply.github.com, an address that cannot appear on anyone's keyGitHub marks a signature Verified only when the tagger email, an email on a uid of a registered
key, and a verified account email all agree. Any one of the above defeats it permanently, and the
failure is silent: the signature is valid,
gpg --verifypasses, only the badge is missing.Certification and registration were the conflated pair. Certifying with the hardware key makes the CI
key trustworthy to a human checking a signature by hand; registration is what the badge reads. The
scripts did the first and never the second.
The fix, and why it cannot drift again
The address is derived, never written down:
Each link derives from the previous one, so rotating the key is sufficient on its own — there is no
second place to remember to update. It also keeps the address out of the repository, which matters
beyond tidiness: this project deliberately publishes no contact email anywhere (CHANGELOG 5.0.0), and a
committed script is published. The first draft of this fix hardcoded it and undid that decision.
Both now fail loudly where they used to continue. The workflow aborts if the imported key has no
email rather than minting another unverifiable tag; the generator aborts rather than producing another
unusable key.
Also in here
bootstrap-ci.shno longer re-adds a required reviewer. Publication is automatic on merge tomainnow, and re-running the script would have silently restored the gate. On a single-collaboratorrepository the merge is already the human act. What is lost is named in the script rather than glossed:
nobody confirms which version is about to go out.
bootstrap-ci.shaddsmainto the deployment branch policy. It only ever addedv*.*.*, so thepush-to-main path was rejected before the workflow was even reached — that is how the first attempt
failed.
CHANGELOG.md.RELEASE_NOTES.mdis the Marketplace copy —emoji-led, second person, "one more thing" — and that register belongs on a storefront page where
someone is deciding whether to install, not in front of a person who arrived at a release page because
something broke. Different readers, different documents:
build.gradle.ktsstill feeds the Marketplacepanel from
RELEASE_NOTES.md. Measured before switching: the section is ~27 KB against GitHub's125 000-character limit, and an empty extraction now fails the release instead of publishing blank notes.
Type of change
Risk and rollback
Risk: confined to the release path. The sharpest edge is that this branch changes what happens on a
merge to
main, and there is no manual approval any more — the merge publishes. The failure modethat remains is the one worth watching: if the CI key is ever rotated without an email, the release now
fails rather than shipping unverified, which is the intended direction.
Rollback: revert. Nothing here has reached a user; v5.0.0's release was deleted before this.
How was this tested?
release.ymlparses; both scripts passbash -n.appears in any committed file (
grepfor it comes back clean).CHANGELOG.md— 70 lines, 26 871 characters.gh api user/gpg_keys;the old email-less key has been removed from the account.
mainis the test.Notes for reviewers
The prerequisite is already done: the CI key was rotated and re-registered before this PR, so the
account now lists a signing key with an email. Without that, this change would abort the release
rather than fix it — which is the intended behaviour, but worth knowing before merging.