feat(release): reproducible source archives, reproducibility checks, and ASF automated signing - #1296
Merged
Merged
Conversation
potiuk
marked this pull request as ready for review
September 20, 2026 14:17
…and ASF automated signing The source artefact is now a reproducible export of the tag. A new stdlib-only tool, tools/reproducible-archive (repro-archive build | check | compare | recipe | epoch), wraps `git archive` (tracked files only, .gitattributes export-ignore honoured) and applies every rule from reproducible-builds.org/docs/archives/: one SOURCE_DATE_EPOCH mtime, sorted members, uid/gid 0, a=rX,u+w modes, no PAX atime/ctime, gzip -n, zip -X. Two builders of the same tag get byte-identical bytes regardless of their git/tar/zip version. release-rc-cut emits it as the source build command; release-verify-rc rebuilds and compares. release-build.md gains "Source archive" (source_archive_method, format, prefix, export_ignore_reviewed) and "Reproducibility checks" (reproducibility_source, reproducibility_binaries with byte-identical or documented-divergence modes). The checks run as release-rc-cut Step 2b (RM self-check before signing) and release-verify-rc Step 9 (every voter); the hand-back step moved to Step 10. release-prepare prep Step 2e is the first-release .gitattributes education step: it classifies every top-level path, checks references before proposing an export-ignore, confirms each entry with the RM, lands .gitattributes in the prep PR and records the review marker. release-rc-cut blocks while the review is outstanding. ASF-specific (organization: ASF only, marked as such): release-prepare automated-signing drafts, never files or sends, the Infra key-request ticket, the Security Team notification and a reproducible-build workflow PR from projects/_template/workflows/release-candidate.yml (no key material, ATR OIDC upload), per Infra's automated release signing policy. When enabled, verify-rc's reproducibility check becomes the mandatory bit-by-bit validation on trusted hardware and release-promote blocks without the attestation. The option is resolved from release_process.automated_signing in the ASF organization manifest and is null for independent projects. Every [VOTE] body release-vote-draft produces now carries a "How to verify this candidate" section: the reproducibility record (commit, SOURCE_DATE_EPOCH, sha512), the agentic one-liner (/magpie-release-management:verify-rc), the human-readable verification page and reproducibility page at the RC tag, the ATR candidate link and the voter-obligation sentence. New config keys vote_verification_doc_url, reproducibility_doc_url and vote_verification_skill; the ATR runbook and the manual voter guide (with a reply template) match. Docs: new docs/release-management/reproducibility.md; process, spec, both runbooks, source-release-contents, the capability taxonomy (new substrate:release value) and the spec-loop spec updated. Evals: new suites for rc-cut Step 2b and verify-rc Step 9, new cases for the unreviewed-archive block, the repro-archive build command, the first-release review and the ASF-only gate; vote-draft step-2 asserts the verification section. Generated-by: Claude Code (Fable 5.1)
potiuk
force-pushed
the
release-reproducibility
branch
from
September 20, 2026 14:22
aa0bb2c to
6aa8233
Compare
…ducibility The release skills assumed one shape of "binary": a global binary_rebuild_command and a hard-coded list of the framework's own validators in verify-rc Step 7. Both were Magpie-specific. Convenience artefacts are project-specific by nature — a binary tarball, wheels, jars, a container image, a chart, each built, staged, voted on and published its own way — so the framework now assumes none and reads what each project declares. release-build.md gains "Convenience artefacts": one entry per artefact with its own build_command, staging / stage_command, reproducibility mode (byte-identical | documented-divergence, default reproducibility_binaries), vote_included flag and publish_channel / publish_command; and "Source-tree validators": the project's own integrity checks for verify-rc Step 7 (Magpie's list moves to projects/magpie/release-build.md). Each skill consumes the list: release-rc-cut emits every artefact's build command under the tag's SOURCE_DATE_EPOCH, the per-artefact rebuild-and-compare self-check, and registry staging commands; release-verify-rc Step 9 rebuilds and compares every artefact and names the ones that did not reproduce; release-vote-draft lists the artefacts, where each is staged and which are in the vote; release-promote publishes each artefact to its declared channel only when the recorded verify-rc run reproduced it, and emits a HOLD note otherwise (the source promotion is never held back); release-announce-draft names the channels. Reproducibility is stated, in the config, the docs and the skills, as the check that decides whether a convenience artefact is good: a binary cannot be reviewed, only rebuilt, so rebuilding it from the voted tag and comparing is the one way to establish that it is what the source produces. Evals: promote step-2 case-5 (publish the reproduced wheel, hold the container image that differed), verify-rc step-9 case-5 (source identical, artefact differs → FAIL), rc-cut step-2b and vote-draft fixtures updated to the per-artefact shape. Generated-by: Claude Code (Fable 5.1)
…origin
A commit id names a repository object; the Software Heritage identifier
of the expanded archive content (swh:1:dir:<sha1>) names what shipped.
It is computed from names, modes and contents alone, exactly as git
computes a tree id, so it does not depend on the archive format, the
compression or who packed it: a voter recomputes it from the staged
bytes, ATR computes the same value at compose time, and it equals the
repository tree at the tag unless .gitattributes altered the export —
in which case the difference is itself the record of what was left
out. It also gives a convenience artefact something precise to point at
as the source it was built from.
repro-archive: `build` now prints swhid_rev (swh:1:rev:<commit>),
swhid_dir (the content identifier, qualified with origin=<repo URL>
and anchor=swh:1:rev:…) and a note saying whether the content SWHID
equals the repository tree; `swhid` computes the identifiers for an
archive and/or a ref; `check --swhid` asserts an archive against a
recorded value; `compare` reports both archives' SWHIDs. The in-memory
tree hashing is tested against `git write-tree` over the extracted
tree and against `git rev-parse <ref>^{tree}` when nothing is
export-ignored, so it agrees with asfswhid / swh identify by
construction.
Two more machine-dependent inputs are pinned, following the review of
apache/tooling-actions#37: the builder's core.autocrlf / core.eol
(which `git archive` would apply to text files) are neutralised, and
the commit id travels in the archive the way `git archive` carries it
(a global PAX `comment` in tar, the archive comment in zip; `check`
accepts exactly that comment).
Skills: release-rc-cut records repository URL, commit, SWHIDs, epoch
and sha512 on the planning issue; release-verify-rc checks the staged
archive against the recorded SWHID (`swhid_matches`); the [VOTE] body's
reproducibility record lists repository, commit, SWHID, epoch, sha512,
and its agentic-path paragraph is fixed text. The CI workflow template
prints the record into the job summary.
Docs: docs/designs/2026-09-20-reproducible-releases.md records the
decisions, rejected alternatives and known limits; reproducibility.md
and the tool README explain the record and the extra fixes.
Generated-by: Claude Code (Fable 5.1)
…r's platform `lstat` reports a symlink as 0755 on macOS and 0777 on Linux. The writers already pack every symlink as 0777 and the SWHID uses git's fixed 120000, so a macOS-built and a Linux-built archive of the same tag are byte-identical; this adds the test that says so, documents the rule in the README table and the module, and warns in the shell recipe that not every tar's --mode rewrites symlink modes. Generated-by: Claude Code (Fable 5.1)
Member
Author
|
This one should make our ATR release process smooth :) |
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
tools/reproducible-archive(repro-archive build | check | compare | recipe | epoch), wrapsgit archive(tracked files only,.gitattributesexport-ignorehonoured) and applies every rule from reproducible-builds.org § Archive metadata: oneSOURCE_DATE_EPOCHmtime, sorted members, uid/gid 0,a=rX,u+w, no PAXatime/ctime,gzip -n,zip -X. Two builders of the same tag get byte-identical bytes regardless of theirgit/tar/zipversion.release-rc-cutemits it as the source build; the single-file module can be copied verbatim into a CI workflow.release-build.md § Reproducibility checksturns on a rebuild-and-compare inrelease-rc-cutStep 2b (RM self-check before signing) andrelease-verify-rcStep 9 (every voter), withidentical/content-identical/differsverdicts; binaries bybyte-identicalordocumented-divergence. Motivation: Magpie's own0.1.0-rc1got a-1for a non-reproduciblezip -rartefact (PRINCIPLES.md§ 11)..gitattributeseducation step.release-prepare prepStep 2e walks the operator through every top-level path, classifies it, checks references before proposing anexport-ignore, confirms each entry, lands.gitattributesin the prep PR and recordsexport_ignore_reviewed;release-rc-cutblocks while the review is outstanding.organization: ASF).release-prepare automated-signingdrafts (never files/sends) the Infra key-request ticket, the Security Team notification and a reproducible-build workflow PR fromprojects/_template/workflows/release-candidate.yml(no key material, ATR OIDC upload), per Infra § Automated release signing. When enabled, verify-rc's reproducibility check becomes the mandatory bit-by-bit validation on trusted hardware andrelease-promoteblocks without the attestation. Non-ASF adopters never see it.repro-archive buildprintsswh:1:rev:<commit>andswh:1:dir:<tree>of the archive's expanded content (withorigin=/anchor=qualifiers), computed in memory the way git computes a tree id and tested againstgit write-treeover the extracted tree, so it agrees withasfswhidand with what ATR computes at compose time; a note says whether it equals the repository tree (i.e. whether.gitattributesaltered the export).check --swhidandswhidlet a voter recompute and compare from the staged bytes;release-verify-rcreportsswhid_matches; the[VOTE]record lists repository, commit, SWHID, epoch and sha512. Two more machine-dependent inputs are pinned as well: the builder'score.autocrlf/core.eol(whichgit archivewould apply), and the commit id travels in the archive asgit archivedoes it (global PAXcomment/ zip comment). Shape follows the discussion on apache/tooling-actions#37.docs/designs/2026-09-20-reproducible-releases.mdrecords the decisions, the rejected alternatives and the known limits (compression bytes across zlib builds,export-subst, the ATR SWHID exposure).release-build.md § Convenience artefactslists each artefact a project ships besides the source (binary tarball, wheels, jars, container image, chart, …) with its ownbuild_command,staging/stage_command,reproducibilitymode,vote_includedflag andpublish_channel/publish_command.release-rc-cutbuilds and stages them under the tag'sSOURCE_DATE_EPOCH,release-verify-rcrebuilds and compares each one (a binary cannot be reviewed, only rebuilt — that check is what establishes it is what the voted source produces),release-vote-draftlists them with their vote scope,release-promotepublishes only the ones that reproduced and emits a HOLD for any that did not (the source promotion is never held back), andrelease-announce-draftnames their channels.release-verify-rcStep 7 now runs the project's ownsource_tree_validatorsinstead of hard-coded framework tools.[VOTE]template tells PMC members how to verify. Everyrelease-vote-draftbody carries a How to verify this candidate section: the reproducibility record (commit,SOURCE_DATE_EPOCH, sha512), the agentic one-liner (/magpie-release-management:verify-rc <rc>), the human-readable verification page and reproducibility page at the RC tag, the ATR candidate link, and the voter-obligation sentence. New config keysvote_verification_doc_url,reproducibility_doc_url,vote_verification_skill; ATR runbook and the manual voter guide (with a reply template) updated to match.Type of change
.claude/skills/<name>/) — eval fixtures updated belowtools/<system>/*.md)tools/*/withpyproject.toml)docs/,README.md,CONTRIBUTING.md)projects/_template/)prek, workflows, validators)Test plan
prek run --all-filespassesuv run pytest/ruff check/mypypasses —reproducible-archivehas 21 tests: every reproducible-builds.org rule has a positive case (the builder applies it) and a negative case (checkcatches a violation),compareon all three verdicts, and two builds at different wall-clock times under a different umask are byte-identicalclaude -p: release-prepare 15/15, release-rc-cut 14/14, release-promote 8/8, release-vote-draft step-2 3/3, release-verify-rc 16/17 (the one failure is the untouchedstep-2-verify-signatures/case-2, where the semantic grader objected to the model pickingdownloads.apache.orgoverdist.apache.orgfor the KEYS URL — pre-existing grader sensitivity, not touched by this PR)release-rc-cut/step-2b-reproducibility(3) andrelease-verify-rc/step-9-reproducibility(5, incl. a convenience artefact whose rebuild differs); new cases for the unreviewed-archive block, therepro-archive buildsource command, the first-release archive review, the ASF-onlyautomated-signinggate (blocked for non-ASF, proceeds for ASF), andrelease-promotepublishing a reproduced wheel while holding a container image that did not reproduce;release-vote-draftstep-2 now asserts the How to verify section viaassertions.json, including the case that must omit the reproducibility record rather than invent ittools/spec-loop/specs/release-management-lifecycle.mdupdated by hand for the new behaviour;.last-syncnot bumpedRFC-AI-0004 compliance
.gitattributesentries confirmed one by one, the Infra ticket and Security Team mail are drafts, the workflow PR opens as a draft,release-verify-rcnever asserts trusted hardware on the committer's behalf (--trusted-hardwareis theirs)repro-archiveruns offline on the local clone; no new network reachorganizations/ASF/organization.md→release_process.automated_signing(nullinindependent) and marked 🪶 wherever it appears--allow-unreviewed-archive,--skip-repro-check,--skip-repro,--review-archiveare the explicit, logged overrides; config keys default to today's behaviour forsource_archive_method: customLinked issues
Refs the
0.1.0-rc1-1recorded indocs/release-management/manual-release-process.md§ Caveats.Notes for reviewers (optional)
substrate:release, was added todocs/labels-and-capabilities.mdand the validator'sTOOL_CAPABILITIES, since none of the existingsubstrate:*values fit an adopter-facing release helper. Happy to fold it into an existing value if you prefer.projects/_template/workflows/release-candidate.ymlare placeholders (<COMMIT_SHA>,# files:); the template says to confirm them againstapache/tooling-actionswhen rendering. The workflow deliberately contains no signing step: the mechanism is whatever Infra agrees on the ticket.release-verify-rcrenumbered its hand-back step from 9 to 10 to make room for the reproducibility step; no eval referenced the old number.source_tree_validators(Magpie's own list moved toprojects/magpie/release-build.md). Remaining "Magpie" mentions in the skills are references to the framework (skill names, the shared pre-flight block).Gen-AI disclosure
Authored with Claude Code (Fable 5.1) driving the edits, tests and eval runs; reviewed and directed by the PR author.
🤖 Generated with Claude Code