release: sign GoReleaser's tap/scoop bot commits before routing them through signed repos #434
Labels
No labels
breaking
bug
documentation
enhancement
epic
good first issue
help wanted
refactoring
resolution/duplicate
resolution/invalid
resolution/wontfix
security
severity/critical
severity/high
severity/low
severity/medium
status/abandoned
status/blocked
status/needs-decision
status/needs-info
status/needs-verification
testing
upstream
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Blocks
#759 epic: code and supply-chain security hardening
sixfold-space/madtea
Reference
sixfold-space/madtea#434
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
Each release, GoReleaser bumps the Homebrew cask and Scoop manifest as a commit in
sixfold-space/homebrew-tapandsixfold-space/scoop-bucket(scripts/release.sh:67-74,docs/contributing/releasing.md:102,114-115). Those bot commits are UNSIGNED. GoReleaser authenticates withGITHUB_TOKENand targets the GitHub distribution edge (docs/contributing/release-credentials.md:71, ADR 0032).The sixfold-space repos on git.cheshirecube.cloud now enforce
require_signed_commitsonmain(2026-08-17), includinghomebrew-tapandscoop-bucket.Current state - no break today
The cheshirecube
homebrew-tap/scoop-bucketare migrated-from-Codeberg copies withmirror=false, and GoReleaser pushes the tap/scoop to the GitHub edge, not to these. So the newrequire_signedon the cheshirecube copies does NOT reject the current release flow. Confirmed before enabling.The gap
brew/scoopinstall).Fix
Give the release bot its own signing key. Same posture as #231: the private half lives only in Bitwarden SM, never on any forge, and the bot is an author, not the platform. Configure GoReleaser to sign its tap/scoop/plugin commits with it. Then
require_signedsafely covers wherever those commits land.Related
Status 2026-09-14 (corrects the facts above)
.goreleaser.yamlgitea_urlspoints atgit.cheshirecube.cloud(DIST_HOST). It writes the cask and manifest intosixfold-space/homebrew-tapandsixfold-space/scoop-bucketthrough the forge contents API, with authorhexajon <jon@sixfold.space>.branch_protectionsreturns[]). The claim that they enforcerequire_signed_commitsis no longer true, which is why releases still succeed.gpg.error.not_signed_commit, from v0.18.1 through v0.18.5 (for examplec8628dbdand73be9b3afor v0.18.5). These are the repos thatbrewandscoopread from.commit_author.signing(GPG, X.509 or SSH) and a git push mode (repository.gitwithurlandprivate_key), so signing means switching these two repos to git push mode. That needs a signing key and a push key.checksums.txt), or with a new release-bot key held only in Bitwarden SM, or accept unsigned. Not decided yet.Decided: the release key,
madtea release signing (sixfold.space) <releases@sixfold.space>(fingerprint4CF168E8EF9E40DC9173505F07D6FBD4B0D2A065), also signs the tap and bucket commits. It is the same key that signschecksums.txtand thatmadtea updatetrusts. I accept that a leak of this key then affects both jobs, in exchange for no second key to hold.What the build needs, from the GoReleaser v2 docs for
homebrew_casksandscoops:repository.git.url(an SSH URL for each repo) andrepository.git.private_key. The docs say the key "must not be password-protected". Commit signing works only in this mode.commit_author.signing:enabled: true,key: "{{ .Env.GPG_FINGERPRINT }}"(the variablescripts/release.shalready sets),format: openpgp.Before the config change:
homebrew-tapandscoop-bucket, with no passphrase.hexajon <jon@sixfold.space>, and the key's identity isreleases@sixfold.space. I still have to confirm how Forgejo matches a signing key to the committer, and whether the author email must change toreleases@sixfold.space.The change is tested with the first release after it lands: the forge must report both new commits as verified.
On point 2, forge verification: Forgejo's docs do not state how the forge matches a signing key to the commit author. The user guide has no page on commit signatures. The admin page on signing (
/docs/latest/admin/advanced/signing/) covers only the commits the instance signs itself: initial commits, wiki edits, web-editor and API file changes, and merges.So whether a commit authored as
hexajon <jon@sixfold.space>and signed with thereleases@sixfold.spacekey shows as verified is still open. The first release after the change answers it: the commits API reports each commit's verification and its reason, andfinishalready reads that (VerifyBranchSignaturesOnForge). If it reports an email mismatch, the fix iscommit_author.email: releases@sixfold.space, with that address added and verified on the committing account and the key uploaded there.