feat(bootstrap): let a consumer pin the reusables to a toolkit branch, to try unreleased changes before a cut #1534
Labels
No labels
bump
major
bump
minor
bump
patch
kind
bug
kind
chore
kind
docs
kind
epic
kind
feature
loop/paused
mirror-drift
priority
critical
priority
high
priority
low
priority
medium
size
L
size
M
size
S
size
XL
status
blocked
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
frankenbit/release-toolkit#1534
Loading…
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?
A feature for later. Pick it up when someone needs to try an unreleased toolkit change on a real adopter before a cut. Until then there are two routes:
@mainafter the change merges (off-contract, but it works);rt prep --dry-runlocally, with anrtbuilt from the branch, against a scratch clone of the adopter.Measured
A wrapper pinned
uses: .../reusable-release.yml@<branch>gets through the first two steps and stops at the third,bootstrap rt.1. resolve-ref.
REFstarts as the baked marker (reusable-release.yml:268).mainnor 40-hex, so it can reach only the #1222 wrapper-ref fallback (:344-347). That fallback fires only when the baked value is empty ormain.bootstrap rtthen fetches the released binary, and the branch's Go code silently does not run.2. checkout release-toolkit.
actions/checkoutat the branch (:357-362) works.3. bootstrap rt.
scripts/bootstrap-rt.shhas two arms:v[0-9]*)FETCHes the asset (:32-44), minisign-authenticated and checksum-verified throughfetch-rt.sh;main)BUILDs from source (:45-68).Any other ref stops at
:79. That is deliberate and pinned by a test:tests/bootstrap-rt.bats:93-100requiresRT_REF=feature/861to be refused.Local probe. Git Bash,
HOMEredirected to a scratch dir, toolkit exported from origin/main8086700:The sketch gets two things wrong that a real change must not:
rt devrecords nothing about which commit was built.A one-off trial needs nothing on main.
.release-toolkitat the pinned ref (reusable-release.yml:422,composite/bootstrap-rt/action.yml:64-67). A throwaway branch made of the commit under test plus the bootstrap patch is therefore enough.branches: [main](build-c4, check-self-bootstrap, gitea-twin-check, prepared-uncut-check, release, tests),branches: [main, v2/next](go-ci) ortags: ['v*'](goreleaser, build-ref-check).Why it matters, and what it costs
Security: unsigned, unreviewed code runs with the adopter's secrets.
fetch-rt.sh's minisign and checksum verification.rtit produces runs inreusable-release.ymlwith the secrets that job reads throughsecrets: inherit:RELEASE_TOOLKIT_TOKEN,RELEASE_TOOLKIT_GIT_TOKEN,RELEASE_TOOLKIT_API_TOKENandGITHUB_TOKEN.@mainalready builds unsigned (ADR-0008 section 4a calls this "convention-guarded, not structural"), but main is protected and reviewed and a branch is not.go.sumstill pins dependencies.An ADR amendment.
docs/adr/0008-go-port-architecture.md:193-212grants the build exception tomainonly. It rejects build-per-run for adopters because of the Go-on-every-runner dependency.A deleted branch breaks the pin.
@refwithGetRefCommitIDand errors with "failed to resolve reference" when the ref is gone (services/actions/reusable_workflows.go:141-144). This was read from the source, not measured on this instance.A moving branch. Forgejo loads the reusable YAML when it expands the workflow and checks out the toolkit later, so a push in between can mix two commits.
@mainhas the same exposure.Compile time on every job.
rt: ac-closure-check, changelog-body-check, changelog-fragment-check, manifest-check, prepared-uncut-check, recover-pending-cut, register-check and release.v(action.yml:46), so each of those jobs compiles.go build ./cmd/rtat8086700, module cache warm, on a 32-thread workstation:GOCACHE;-a -p 2;gorunner has not been measured.bootstrap-rt.sh:51). Storey's release wrapper runs onruns_on: go; other adopters may not.Branch-name traps.
v[0-9]*takes the FETCH arm and fails for lack of an asset.:76-78).action.yml:46runs the cache step for any ref that starts withv.Real cuts. Merging an adopter's rolling PR while it is branch-pinned cuts a real release with unreleased toolkit code.
Relation to #1517
#1517 (SHA pins) lists the same mechanism as its option (B): BUILD
rtfrom.release-toolkitat the pinned commit, with Go on adopter runners and an amendment to ADR-0008 section 4a.A branch arm and a SHA build arm are one change to
bootstrap-rt.sh: build any ref that is not a version tag. They differ in trust:Decide the two together. If #1517 picks (A) or (C), this issue needs its own build arm and its own amendment.
Acceptance criteria
rtthat runs. It is made together with #1517's decision, or after it.scripts/bootstrap-rt.shbuilds a ref that is neither a version tag nor SHA-shaped from.release-toolkit. Its log line names the ref and the commit it built (git -C .release-toolkit rev-parse HEAD), and no longer calls the build the toolkit-self exception..giteatwins are regenerated.tests/bootstrap-rt.bats:93-100is flipped, and a branch row is added to the #1514 composition table (:189-195). Both are mutation-verified.composite/bootstrap-rt/action.yml:8-12, the pins section ofdocs/SECURITY.mdanddocs/integration.mdsay what a branch pin means:rtis unsigned and unreviewed;gorunner and recorded here.Out of scope
v*tag firesgoreleaser.ymlandbuild-ref-check.yml(AGENTS.md section 14);rt repinbakes fromorigin/main, not from a branch;Anchor
Found while reviewing PR #1531 / issue #1529 on 2026-10-03. The operator asked whether Storey could be pinned to
@claude/1529-commit-notesto try the PR before merge. It cannot: resolve-ref and the checkout pass, andbootstrap rtrefuses. The review's research simulated that path against Storey's two wrappers, then ran a localrt prep --dry-runon a scratch Storey clone instead. Related: #1517, #1514, #456, #582, #336, #1222.