ci: automate the skiplang bootstrap bump (manual workflow)#1479
Merged
Conversation
The mechanical core of a bootstrap bump, previously a careful manual sequence: build stage1 with the current bootstrap, promote its IR into the bootstrap submodule, then verify the promoted compiler in isolation by rebuilding it clean and asserting the self-hosting fixpoint (stage2 and stage3 skc.ll identical) plus the full test suite. The Makefile's own fixpoint check is `-diff` (leading dash, exit code ignored), so it never fails a build; this asserts it and exits non-zero on any failure, leaving the promoted files in place for the caller to commit but guaranteeing a non-converging or test-failing compiler is never published.
Wraps bin/bump_bootstrap.sh in a workflow_dispatch action that, once the rebuild and verification pass, pushes the new IR to SkipLabs/skiplang-bootstrap and opens a PR here bumping the submodule pointer. Manual only: whether to bump is a judgement call, and merging the PR -- the step that changes what everyone builds from -- stays a human decision that re-runs CI against the new pointer. Two things an adversarial review caught and this handles: - The IR is reparented onto the current skiplang-bootstrap main tip before pushing, so the push is always a fast-forward. Committing on top of the pinned (possibly stale) submodule SHA would be rejected non-fast-forward whenever main had advanced -- e.g. an earlier bump whose PR had not merged -- wedging every later run. IR snapshots are self-contained, so the parent commit is immaterial. - The job runs in a `bootstrap-publish` environment. workflow_dispatch executes the workflow and its scripts from the selected ref with full secret access, so the cross-repo token is gated behind an environment whose deployment-branch policy allows only main; a crafted-branch dispatch cannot reach it. A dry_run input builds and verifies without pushing or opening a PR.
The token's write access was first exercised at the push step, i.e. only after bin/bump_bootstrap.sh had already spent ~40 minutes rebuilding and testing the compiler. A fine-grained PAT that is unscoped, read-only, or not yet approved by the org would waste that whole build before failing -- the same late-failure the docker-publish check_push_access preflight was added to avoid. Add bin/check_bootstrap_token.sh, run as the first step after checkout: GET /repos/<repo> for both skiplang-bootstrap and skip and assert .permissions.push, so a mis-scoped token fails in about a second with a clear remedy.
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.
Automates the bootstrap-compiler bump — today a careful, ~40-minute manual sequence across two repos — behind a single manual trigger, so the toil goes away and the verification is guaranteed to run.
What it does
workflow_dispatch→ onubuntu-24.04:bin/bump_bootstrap.sh: build stage1 with the current bootstrap,make promote, then verify the promoted compiler on a clean rebuild — the self-hosting fixpoint (stage2andstage3skc.llidentical) and the full compiler test suite. Any failure exits non-zero and nothing is published.SkipLabs/skiplang-bootstrap.skiplang/compiler/bootstrapsubmodule pointer.Merging that PR — the step that changes what everyone builds from — stays a human decision, and CI re-runs the fixpoint + tests against the new pointer before it can land. A
dry_runinput builds and verifies without pushing or opening a PR.Two issues an adversarial review caught, and how they're handled
skiplang-bootstrapmain is rejected whenever main has advanced (e.g. an earlier bump whose PR hasn't merged), wedging every future run after a 40-min rebuild. Fixed by reparenting the IR onto the current remote main tip (fetch+reset --soft+commit), so the push is always a fast-forward. Reproduced the wedge and confirmed the fix locally; main stays linear with every IR reachable.workflow_dispatchruns the workflow and its scripts from the selected ref with full secret access, so a write-access user could dispatch a crafted branch to steal the cross-repo token. The job runs in abootstrap-publishenvironment whose deployment-branch policy must allow onlymain, which blocks the secret for any other ref.The review also flagged — and I verified as not an issue — that
SKIP_CAPACITYis unneeded on the 16 GB runner (the same compiler builds on the same runners indocker-publishwithout it).Maintainer setup before the first run
SkipLabs), repo access to bothskiplang-bootstrapandskip, permissions Contents: R/W + Pull requests: R/W + Metadata.bootstrap-publishonSkipLabs/skip: deployment-branch policy → selected branches →mainonly; store the PAT as an environment secret namedBOOTSTRAP_BUMP_TOKEN(environment, not repo/org — a repo secret isn't gated by the environment). Optionally add required reviewers for a per-run approval gate.dry_runfrommain(build + verify, no writes) before the first real bump.Verified as far as is possible without running it: actionlint + shellcheck clean; the
makesequence traced against the real Makefile; thecheck-bootstrap/uncommitted-submodule interaction, the fast-forward fix, and thegit submodule statusbehaviour reproduced locally. The compiler build/test itself can only be exercised on the runner — hence thedry_run-from-main first.— Mehdi (with Claude Opus 4.8, xhigh effort)
🤖 Generated with Claude Code