Skip to content

ci: move release.yml to GitHub-hosted runners with SLSA provenance - #3

Merged
hermanngeorge15 merged 4 commits into
mainfrom
fix/1-hosted-release
Oct 9, 2026
Merged

hermanngeorge15 merged 4 commits into
mainfrom
fix/1-hosted-release

Conversation

@hermanngeorge15

Copy link
Copy Markdown
Contributor

Closes #1.

Why

This repo is public, and the UnityInFlow org runner group enforces allows_public_repositories: false. A self-hosted job therefore cannot be scheduled here at all. The next release tag would have queued for 24 hours and then been cancelled. v0.0.1 shipped only because it was built while the repo was still private.

This takes option 2 from the issue, the same exception injection-scanner took in #45:

  • the release uses no org secret, only the built-in GITHUB_TOKEN;
  • the Homebrew tap is updated by hand, outside the workflow;
  • the workflow fires only on tag pushes, which a fork cannot make.

What changes

release.yml

  • All three jobs run on ubuntu-latest.
  • Least privilege: the workflow default is contents: read. Only the release job gets contents: write, id-token: write and attestations: write.
  • Signed SLSA build provenance (actions/attest-build-provenance) covers every tarball and SHA256SUMS.txt, and is created before the Release. The release notes include the gh attestation verify command.
  • Every action is pinned to a verified commit SHA.
  • The trigger narrows from v* to v[0-9]+.[0-9]+.[0-9]+. GSD milestone tags start with v too: run 29185695331 fired on v1.0-milestone. On a hosted runner, that would have published a real Release with binaries. Pre-release tags (v0.1.0-rc.1) no longer trigger either; Phase 6 can widen the filter if its dry run needs one.
  • The asset contract is unchanged:
    • the same six targets, with the same 4 required / 2 best-effort musl split;
    • agent-memory-<triple>.tar.gz with the binary at the archive root;
    • SHA256SUMS.txt.

ci.yml and spike-cross-compile.yml

  • Pinned to the same SHAs. This PR's own CI run is therefore the only evidence before merge that the new checkout and rust-toolchain pins work here.

CONTRIBUTING.md and README.md

  • They described a self-hosted-only policy that can't work on this repo. They now describe the real one.

Pins

Action Version SHA
actions/checkout v7.0.1 3d3c42e5aac5ba805825da76410c181273ba90b1
dtolnay/rust-toolchain stable 4360b52568e2003a75bf9bc1d59f33a8e3fc893c
actions/upload-artifact v7.0.1 043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
actions/download-artifact v8.0.1 3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
actions/attest-build-provenance v4.2.2 4d101475d8b20a2381f78447822ac1eab6504dd8
softprops/action-gh-release v3.0.3 efb35369e0ad2afab669f228072c1b0d510eae64

These are the same pins injection-scanner's v0.1.0 release ran green with, including the attest step.

Verification

  • actionlint is clean on all three workflows. Before this change it reported three unknown-runner-label errors.
  • A structural check of release.yml covers:
    • the trigger, and that the filter matches v0.1.0 but not v1.0-milestone or v0.1.0-rc.1;
    • the permissions;
    • all six matrix legs, unchanged;
    • the step order SHA256SUMS → attest → release;
    • a 40-hex pin on every uses:;
    • toolchain: stable on every rust-toolchain step.
  • No self-hosted label and no secrets. expression remain in any workflow.

Not verifiable before merge (by design)

release.yml runs only on a vX.Y.Z tag, and that tag-only trigger is the safety property behind this exception. The first hosted run is the Phase 6 release dry run. It must confirm:

  • the darwin zigbuild cross-link from an x86_64 host (v0.0.1 was built on ARM64);
  • the attest step;
  • the native x86_64 --version smoke test;
  • gh attestation verify on a downloaded tarball.

Follow-ups (not in this PR)

  • Bump the dtolnay/rust-toolchain pin to a commit after upstream fix #187, in this repo and injection-scanner together. The risk is accepted for now because every caller passes fixed inputs.
  • Consider porting injection-scanner's check that the tag matches the Cargo.toml version.

🤖 Generated with Claude Code

hermanngeorge15 and others added 4 commits October 9, 2026 12:43
…loses #1)

This repo is public and the org runner group enforces
allows_public_repositories: false, so the self-hosted release jobs could
never be scheduled: the next tag would have queued 24 h and been
cancelled. v0.0.1 shipped only because it was built while the repo was
still private.

Moves all three jobs to ubuntu-latest under the same exception
injection-scanner took in its #45. The release uses no org secret, only
the built-in GITHUB_TOKEN, and fires only on tag pushes, which a fork
cannot make.

- Least privilege: the workflow default is contents: read. Only the
  release job holds contents/id-token/attestations: write.
- Signed SLSA build provenance (actions/attest-build-provenance) over
  every tarball and SHA256SUMS.txt, created before the Release. The
  release notes give the gh attestation verify command.
- Every action is pinned to a verified commit SHA. checkout moves v5 to
  v7.0.1; upload and download artifact move together to v7.0.1/v8.0.1.
- The trigger narrows from v* to v[0-9]+.[0-9]+.[0-9]+. GSD milestone
  tags match v* too: run 29185695331 fired on v1.0-milestone, and on a
  hosted runner it would have published a real Release.
- The asset contract is unchanged: six targets, the 4 required + 2
  best-effort split, the same tarball shape, SHA256SUMS.txt.

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

ci.yml runs on this PR, so pinning it to the same commits as release.yml
is the only evidence before merge that the checkout v7.0.1 and pinned
rust-toolchain steps run on a hosted runner in this repo. The spike gets
the same pins so that every workflow is SHA-pinned. A SHA-pinned
dtolnay/rust-toolchain loses its branch-name default, so each step now
passes `toolchain: stable` explicitly.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ification (#1)

CONTRIBUTING.md and README.md still said CI runs on self-hosted runners
only and that a maintainer may need to bring one online. Neither is
possible on this public repo. They now describe the real policy: hosted
fork CI with a read-only token, a hosted release fired only by exact
vX.Y.Z tags under the issue #1 exception, the gh attestation verify
command, and that the cross-compile spike is not a release gate.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…loses #1)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@hermanngeorge15
hermanngeorge15 merged commit 1f7c566 into main Oct 9, 2026
1 check passed
@hermanngeorge15
hermanngeorge15 deleted the fix/1-hosted-release branch October 9, 2026 10:48
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.

ci: release.yml targets [orangepi] on a public repo — the next release cannot be scheduled

1 participant