Skip to content

ci(release): verify-ci gate, dry_run, --locked, arm64 recollapse - #757

Merged
norrietaylor merged 1 commit into
mainfrom
ci/pr9-release-overhaul
Jul 14, 2026
Merged

ci(release): verify-ci gate, dry_run, --locked, arm64 recollapse#757
norrietaylor merged 1 commit into
mainfrom
ci/pr9-release-overhaul

Conversation

@norrietaylor

@norrietaylor norrietaylor commented Jul 14, 2026

Copy link
Copy Markdown
Member

What

Overhauls release.yml (PR9-core; the smoke-the-shipped-artifacts jobs are a
follow-up PR9b).

Change Detail
verify-ci replaces the test job Asserts the five lane aggregators reported success on the exact release commit (they are the required checks on main), instead of re-running the workspace suite (a duplicate of ci-linux-native's core-tests). checks: read perm; queries commits/{sha}/check-runs.
dry_run input Builds/signs/assembles everything but publishes nothing: the archive is still packaged (validates the tar), while the GCS upload, gh release create, and the whole stage-installer job (bucket write + channel advance) are skipped. Defined on both workflow_dispatch and workflow_call so it resolves on nightly's reusable call (which passes nothing → real release).
--locked Added to all five release build invocations (amd64 static + minvmd, arm64 cross, macOS minvmd + minimal).
arm64 recollapse Three sequential single-package cross builds → one combined build of all three packages (mirrors amd64); timeout right-sized 90 → 60.

Behavior change (safer)

verify-ci means a commit whose CI is not reported-green will not release
(the old test job would rebuild-and-hope). A nightly on such a commit skips the
release — and nightly's promote step already tolerates a skipped release.
skip_ci_verify is the admin override.

Deliberately out of scope

  • Smoke-the-shipped-artifacts jobs → PR9b (only validatable by a real release
    dispatch on the self-hosted mini).
  • Canonical basenames (Runtime dependencies #4) → no-op: artifacts already ship as amd64/arm64
    and install.sh normalizes x86_64→amd64 / aarch64→arm64.
  • Release cache discipline (N4 save-if) → skipped: release runs only on
    main/dispatch, never PR branches.

Validation

actionlint clean; nightly.yml's workflow_call (no inputs → real verified
release) is compatibility-checked. The build/sign path is fully exercisable
without shipping via a workflow_dispatch with dry_run: true — the
recommended proof before a real cut.

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 3 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7f9c9e61-7d9e-4da6-a08c-6985f12e868c

📥 Commits

Reviewing files that changed from the base of the PR and between 4de4a5f and 2bd22ca.

📒 Files selected for processing (1)
  • .github/workflows/release.yml

Comment @coderabbitai help to get the list of available commands.

Overhauls release.yml (PR9-core; the smoke-the-shipped-artifacts jobs are a
follow-up):

- verify-ci replaces the `test` job. Instead of re-running the workspace suite
  (a duplicate of ci-linux-native's core-tests), it asserts the five lane
  aggregators reported success on the exact commit being released (they are the
  required checks on main). `skip_ci_verify` is the admin override for a
  known-good but unreported commit. Behavior change: a commit whose CI is not
  green will not release (nightly's promote step already tolerates a skipped
  release) — safer than the old rebuild-and-hope.
- dry_run input builds/signs/assembles everything but publishes nothing: the
  archive is still packaged (validating the tar) while the GCS upload, GitHub
  release create, and the whole stage-installer job (bucket write + channel
  advance) are skipped. Defined on both workflow_dispatch and workflow_call so
  it resolves on nightly's reusable call (which passes nothing → real release).
- --locked on all five release build invocations (amd64 static + minvmd, arm64
  cross, macOS minvmd + minimal) — a release must build against the locked
  dependency versions.
- arm64: three sequential single-package cross builds collapse into one build
  of all three packages (mirrors amd64), timeout right-sized 90 -> 60.

The `test` job also carried a bespoke mTLS proxy step
(`--features networking-proxy`); it is dropped, not moved. Those tests are
already feature-gated in minimald and should run wherever the feature is
enabled, not via a hand-wired release-YAML step (the feature is mothballed
from CI per #687).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HbXL6jxHTY2YuLPaMxc1yU
@norrietaylor
norrietaylor force-pushed the ci/pr9-release-overhaul branch from 342ff7c to 2bd22ca Compare July 14, 2026 22:34
@norrietaylor
norrietaylor marked this pull request as ready for review July 14, 2026 22:53
@norrietaylor
norrietaylor merged commit 89bc29b into main Jul 14, 2026
27 checks passed
@norrietaylor
norrietaylor deleted the ci/pr9-release-overhaul branch July 14, 2026 23:01
norrietaylor added a commit that referenced this pull request Jul 15, 2026
…762)

* ci(release): restore arm64 build timeout to 90m

The arm64 recollapse in #757 cut timeout-minutes 90->60 on the
assumption the single combined cross build would be faster. A post-merge
dry-run (run 29375276363) showed the cold-cache build runs ~65m and hit
the 60m cap, cancelling the job and skipping initramfs/release/stage. The
recollapse saves link time, not the dominant aws-lc-sys musl compile, so
restore the 90m headroom the split had.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ci(release): cache release builds with rust-cache (pruned, main-only save)

The two linux release builds cached the whole target/ (the largest in the
repo) via raw actions/cache into the 10 GB per-repo LRU shared with every
PR lane, so entries were evicted fast and release builds kept starting cold
— the arm64 dry-run ran ~65m from cold. Swap to Swatinem/rust-cache, which
prunes target/ to the dependency artifacts (the dominant aws-lc-sys compile)
so the entry is small enough to survive; save-if main-only stops branch and
dry-run dispatches from churning the budget. cross reads ~/.cargo and writes
target/ on the host, so rust-cache caches the arm64 build the same as a
native one. The 90m arm64 cap stays: a cache miss is still cold.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
norrietaylor added a commit that referenced this pull request Jul 17, 2026
release.yml's verify-ci gate (#757) requests checks: read at the job
level. When release.yml runs as a workflow_call from nightly.yml, it
cannot hold any scope the caller's permissions block doesn't grant, and
nightly.yml granted only contents: write and id-token: write — so every
scheduled run since #757 merged died at workflow compile time with
startup_failure (Jul 15 and Jul 16), cutting no nightly release. Manual
release.yml dispatches kept working because a directly-dispatched
workflow uses its own permissions, which is why this went unnoticed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
twitchyliquid64 pushed a commit that referenced this pull request Jul 17, 2026
…efore pushing unstable (#759)

* ci(release): smoke-test the shipped artifacts before publish

Prove the just-built RELEASE binaries actually run before publishing any of
them. Three new jobs download the uploaded artifacts by name, put the SHIPPED
binaries on PATH (never a fresh target/ build), and run the ONE shared session
e2e (scripts/session-e2e.sh — the same proof the CI lanes run):

- smoke-linux-amd64 (ubuntu): DM2 native minimald — the static-musl
  min/minimald boot a host daemon and pass the session e2e.
- smoke-linux-kvm (KVM-capable ubuntu): DM3 — boot a real microVM from the
  shipped native-glibc minvmd + shipped guest kernel/rootfs/initramfs +
  pinned gvproxy; libkrun is materialized from the upstream package (not
  shipped on Linux) via the shipped static mip.
- smoke-macos (self-hosted mini): DM1 — lay the SIGNED min/minvmd/libkrun.1.dylib/
  gvproxy + arm64 guest payload into the installer layout (libkrun.1.dylib a
  lib/ sibling of bin/, resolved via @loader_path/../lib) and boot the microVM.

A new skip-tolerant smoke-success aggregator (if: always(), fails only on
failure/cancellation) is added to the release job's needs, so a smoke failure
blocks every publish step while a skipped smoke-macos (RUN_MACOS_CI kill-switch)
reads as pass. Smoke has no !inputs.dry_run guard: a dry run builds, signs,
assembles, and SMOKES, then publishes nothing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(ci): grant nightly the checks scope its release call needs

release.yml's verify-ci gate (#757) requests checks: read at the job
level. When release.yml runs as a workflow_call from nightly.yml, it
cannot hold any scope the caller's permissions block doesn't grant, and
nightly.yml granted only contents: write and id-token: write — so every
scheduled run since #757 merged died at workflow compile time with
startup_failure (Jul 15 and Jul 16), cutting no nightly release. Manual
release.yml dispatches kept working because a directly-dispatched
workflow uses its own permissions, which is why this went unnoticed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci(nightly): smoke the shipped artifacts before advancing the channel

Move the three smoke jobs and their skip-tolerant aggregator from
release.yml into nightly.yml. The workflow_call jobs are part of the
caller's run, so each smoke job still downloads the just-built artifacts
by name and runs the one shared session e2e against the shipped bytes;
what changes is what the smoke gates. In release.yml it gated the
publish step of every release; here it gates promote-nightly, so a
failed smoke leaves the nightly channel pointing at yesterday's build
instead of blocking the release machinery itself. On a no-op night
(HEAD already staged) release and the smokes both skip and the channel
flip proceeds against bytes that were smoked the night they were cut.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ci): point the smoke VMs at the shipped gvproxy explicitly

minvmd never resolves gvproxy from PATH — resolve_gvproxy_path() honours
only MINVMD_GVPROXY_BIN, the installer bin dir ($MINIMAL_BIN /
~/.local/bin), and /usr/lib/minimal/bin. Renaming the shipped binary
onto PATH therefore left both VM smokes switchless: gvproxy resolution
is best-effort, so minvmd boots without guest egress and the in-guest
pkgs clone during session mint dies with 'Could not resolve host' —
the exact 10/10 failure the Jul 16 session-e2e-soak hit for the same
reason. Set MINVMD_GVPROXY_BIN on both session-e2e steps, as the KVM
and macOS lanes do.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ci): stage gvproxy for the session-e2e soak

#760 deepened session-e2e.sh with the in-sandbox min add proof, whose
session mint clones the pkgs upstream inside the guest, and added
fetch-gvproxy + MINVMD_GVPROXY_BIN to the KVM and macOS lanes — but not
to nightly-tests' session-e2e-soak. With no gvproxy staged, minvmd
boots the VM switchless (resolution is best-effort and never errors),
the guest has no egress or DNS, and every one of the soak's 10
iterations dies with 'Could not resolve host: github.com' (first seen
on the Jul 16 scheduled run, the first after #760 merged). Stage the
pinned gvproxy and point MINVMD_GVPROXY_BIN at it, exactly as the KVM
lane does.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants