Files
Zoltan Kochan 290bb5bd38 ci: create release tags by hand, signed (#13607)
Version tags were created in CI with `git tag "$tag" "$SHA"` — a lightweight tag,
which has no tag object to carry a signature. Since v11.18.0 that made
`git verify-tag` fail with "cannot verify a non-tag object of type commit",
breaking downstream packagers who verify the tag before building.

Signing those tags in CI would restore verify-tag but not the property that makes
it worth verifying: the key would live in Actions secrets, inside the same trust
boundary the signature is meant to attest independently of. Cut tags from a
maintainer machine instead, and have release.yml verify the tag before any
publish job runs.

verify-release-tag imports the public keys committed under .github/release-keys
into a throwaway GNUPGHOME and runs `git verify-tag` on the pushed tag. Every
publish path descends from `plan` and `plan` descends from that job, so one edge
gates all three products. Verified against a signed tag, a lightweight tag, an
annotated unsigned tag, and a tag signed by a key outside the directory: only the
first proceeds.

The keyring is isolated so verification cannot succeed against a key already on
the runner, and checkout sets fetch-tags because a tag push checks out the commit
while the signature lives on the tag object. The non-tag verify_ts_release
dispatch exits from inside the step rather than a job-level `if`, since a skipped
job skips everything that needs it.

This guards against unsigned tags, not against an actor who can push arbitrary
ones: a tag push runs the workflow file and checks out the tree from the pushed
tag. Restricting creation of v* and pnpr@* tags is a repository ruleset concern.

RELEASING.md documents the manual procedure: tag an explicit commit, verify every
tag before pushing, and retag at the fixed commit to retry a failed release.

Related to pnpm/pnpm#13578
2026-08-03 15:43:58 +02:00
..