Skip to content

ci: move release toolchain builds to hosted runners - #777

Open
luisleo526 wants to merge 4 commits into
mainfrom
fix/toolchain-ar-origin
Open

luisleo526 wants to merge 4 commits into
mainfrom
fix/toolchain-ar-origin

Conversation

@luisleo526

Copy link
Copy Markdown
Collaborator

The x86 release job depends on a preloaded self-hosted toolchain. Move it to a standard hosted runner using a digest-pinned Bookworm image from Artifact Registry, and separate the platform builds from the write-scoped upload job.

Keep the dedicated read-only image identity, exact release admission, non-root isolated build and packed-artifact consumer, released-baseline GLIBC comparison and archive checksums before publication. Add a secret-free hosted diagnostic and mutation checks for the image reference, authentication, workflow ordering and artifact bytes.

Validation: the complete release-gate test module passed 294 tests, followed by seven admission tests and three source-loading smoke tests, without skips. The parent’s stale negative control failed at its unchanged-input assertion; the corrected control changes the active repository segment and verifies rejection.

Current-head PR CI and parity remain required. Whole current-head preflight/helper module coverage and real hosted authentication, pull, image-id/storage-driver behavior, build, consumer execution and release-leg timing remain to be observed through their normal runs.

🤖 Generated with Claude Code

Split hosted x86 and ARM builds from one write-scoped release upload. Bind the
private toolchain reader and verify actual archive bytes before publication.
Retain the released-archive GLIBC comparison and packed native consumer.

Update the routing documentation and explicitly supersede these earlier claims:
- Release keeps its exact protected GKE pins in runner group 15; baseline
  promotion runs on hosted ubuntu-24.04.
- e7fa559's short sentence "Hosted workflows declare nothing." is replaced by
  the current explicit per-job hosted runner map.
- Credentialed release work keeps protected GKE runner group 15.
- Only release.yml still names protected gkp-od-* scale sets.
- Release uses protected GKE runner group 15 for its x64 artifact only.
- Linux x64 prebuilt uses gkp-od-16cpu-32gb-amd64-128gb; baseline promote uses
  hosted ubuntu-24.04.
- The x86_64 prebuilt requires 16 CPU/32 GB and 128 GB storage, plus the
  preloaded immutable Bookworm Docker image.
- The secret-free gke-* credential ban stays binding.
- The workflow-level contents: write setting scopes GITHUB_TOKEN.
- Protected runner group 15 admits only allowlisted workflow refs at
  refs/heads/main; the probe keeps its release environment.
- PRs build Ubuntu Release only (ci.yml);
- Debug, sanitizers, kernel-only and the macOS cell run post-merge (ci-post.yml).
- Only release.yml still names a protected scale set, in protected runner
  group 15: its x86_64 prebuilt cell.
- Group 14's mirror .github/runner-group-allowlist.txt is empty because no
  workflow uses a group-14 label; group 15's required ref is replaced by the
  current empty mirror.
- Release's x86_64 prebuilt cell uses gkp-od-16cpu-32gb-amd64-128gb, installs
  Eigen and asserts exactly 3.4.0 before CMake; the arm64 cell retains hosted
  execution under its separately named build job.

The replacement text names the split jobs and their actual permissions,
toolchain inputs and artifact checks. Source-byte and release protections
remain enforced by the current admission contracts.

Also supersede these bd1fa2f routing/resource statements as the named jobs
move to hosted runners:
- The protected 2 CPU/4 GB set runs promotion's API/tree checks, Node campaign
  tooling and Cloud SQL proxy; the probe reads rulesets with Python/gh.
- Docs uses 4 CPU/8 GB for Doxygen and Graphviz over the full public header
  set before Pages upload.
- The group 15 mirror lists only docs-post, promote-baseline,
  release-ruleset-probe and release at refs/heads/main; the current hosted
  routes replace that required-ref inventory.
Retain the digest-pinned repository reference and exact RepoDigests checks.
Compare Docker's inspected image Id with the separately recorded config pin.
Exercise the distinct identities and refusal cases in both transports, and
bind admission to the actual updated helper bytes.
Use engine-release-toolchains instead of gke-runner-images for the pinned
Bookworm image. Keep the manifest and Docker config identities, dedicated
reader authentication, release admission and isolated build/consumer checks.

Update all three release workflow image guards and their exact workflow
contract. Compare the tracked image input with its complete approved
repository@sha256 line, including its final newline. Add refusal controls
for retired and different origins, digest and line shapes, and each
pull/build/consume guard.
Make the negative control change the current pinned repository while
retaining the assertions that the input changed and validation rejects it.
from unittest import mock

import hashlib
import ci_preflight

@graphify-labs graphify-labs Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 3 advisory finding(s) below merit a look before merge.

Not checked: tests were not run; formal verification proved 0 of 6 changed function(s) (4 sampled, not proven, 2 not verified).

Formal verification. PR-changed functions: 4/6 verified (0 proven, 4 may-equivalent, 0 distinguished) · 2 not verified (2 vacuous).

Not verified on this run: main (vacuous: never exercised), runner\_findings (vacuous: never exercised).


Graphify review — findings

Moves the x86_64 prebuilt build off the protected self-hosted GKE runner onto hosted ubuntu-24.04. The prebuilt-x86 job authenticates over OIDC as a dedicated toolchain reader, pulls a digest-pinned private Bookworm image whose reference is validated against a strict regex from a committed file instead of a repo variable, and exposes tarball and sha256 outputs for later jobs. Drops the self-hosted runner label and the group-15 allowlist entry, and defaults workflow permissions to contents: read with contents: write granted only on the release job. Adds a PR-triggered diagnostic workflow that records host identity and Docker driver/version on a hosted runner, limited to same-repo PRs touching the release build inputs. The preflight and release-gate tests are updated to pin the new hosted routing, the file-based image binding, and the emptied runner-group mirror.

Worth a look

  • Release asset upload bypasses protected environment — .github/workflows/release.yml:714 · Escalate · high
    • NOT verified (no proof, no reproducing execution) — needs human review
  • Self-hosted label and group-15 route removed while release.yml still appears to use them — .github/actionlint.yaml:3 · Escalate · medium
    • NOT verified (no proof, no reproducing execution) — needs human review
  • Job output sha256 is wired to the hex digest, not the .sha256 checksum file — .github/workflows/release.yml:372 · Escalate · medium
    • NOT verified (no proof, no reproducing execution) — needs human review

Review partial — this diff was larger than one review pass covers, so later files were not reviewed; some findings may be missing.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 1524 functions depend on the 1517 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: ci_workflow_findings() — 84 callers, 24 callees
  • worse: _job_values() — 32 callers, 3 callees
  • worse: _job_block() — 19 callers, 3 callees
  • worse: runner_findings() — 2 callers, 28 callees
  • worse: release_prebuilt_workflow_findings() — 8 callers, 7 callees
  • new: release_option_c_workflow_findings() — 3 callers, 8 callees
  • worse: legacy_release_workflow() — 5 callers, 3 callees
  • worse: main() — 1 callers, 14 callees

Verification — 1524 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 1524 function(s) in the blast radius were not formally verified this run

Docs that may be stale (advisory)

…and 9 more.

Formal verification

No difference found (not proven): No behavior difference found in actionlint\_runner\_label\_findings (not a proof).

The verifier ran both versions of actionlint\_runner\_label\_findings on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

No difference found (not proven): No behavior difference found in ci\_workflow\_findings (not a proof).

The verifier ran both versions of ci\_workflow\_findings on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

Could not verify: Could not verify main.

The verifier did not have enough to check main, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 1 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly NameError — names the real obstacle, not a sampling gap)

No difference found (not proven): No behavior difference found in release\_credential\_findings (not a proof).

The verifier ran both versions of release\_credential\_findings on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

No difference found (not proven): No behavior difference found in release\_prebuilt\_workflow\_findings (not a proof).

The verifier ran both versions of release\_prebuilt\_workflow\_findings on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

Could not verify: Could not verify runner\_findings.

The verifier did not have enough to check runner\_findings, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: non-vacuity: domain too small (only 2 distinct inputs exercised, need 3) — 'no divergence' would be near-vacuous

· 3 grounded finding(s) anchored inline below; 5 more finding(s) on lines outside this diff (see the check run).

Comment thread scripts/ci_preflight.py
docker info --format '{{.Driver}}'
'''

def release_option_c_workflow_findings(workflow: str) -> list[str]:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regression — release_option_c_workflow_findings()

fans out to 8 callees (efferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread scripts/ci_preflight.py
@@ -3575,6 +4116,8 @@ def release_prebuilt_consumer_findings(source: str) -> list[str]:

def release_prebuilt_workflow_findings(workflow: str) -> list[str]:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regression — release_prebuilt_workflow_findings()

fans out to 7 callees (efferent coupling); 8 callers depend on it (afferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

' needs: [release, prebuilt]\n', 1)


def legacy_release_workflow(workflow):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regression — legacy_release_workflow()

high coupling complexity (Ca·Ce = 15).

Grounded coupling-delta finding (deterministic), not an LLM guess.

This branch has not been deployed

No deployments
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.

1 participant