ci: adopt cargo-dist for signed binary releases - #262
Conversation
Replace the changelog-only release workflow with a cargo-dist (v0.32.0) pipeline. On a `v*` semver tag it cross-compiles the `ourios-server` binary for Linux, generates per-artifact + aggregate sha256 checksums, a CycloneDX SBOM, and GitHub build-provenance attestations, then publishes the GitHub Release. The signed release assets (attestations + SBOM) are what flips OpenSSF Scorecard's Signed-Releases check. - targets: x86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu (gnu-only for v0). musl was tried in config but dropped: the cross-build could not be verified clean in this environment (macOS host, no Linux/musl toolchain), and shipping an unverified target into a tag-triggered pipeline is not worth it for v0. macOS/Windows are out of scope for a Linux server backend. - installers: shell only (npm/msi/homebrew skipped for v0). - cargo-cyclonedx = true (CycloneDX SBOM per release). - github-attestations = true (build provenance via actions/attest). - All crates are `version = 0.0.0` / `publish = false`; `dist = true` in ourios-server's `[package.metadata.dist]` opts the one binary back in as the sole distributable, leaving the library crates excluded. - cargo-dist now owns the GitHub Release + its release notes (read from CHANGELOG.md), replacing the git-cliff step. cliff.toml is left in place but is no longer wired into the release pipeline. Fixes the one upstream-template typo in the generated workflow (`steps.cargo-cyclonedx.output.paths` -> `outputs.paths`) so the SBOM files are actually collected into the upload glob; without it the SBOM silently drops out. The cargo-dist-generated actions are left pinned as dist generates them (by major tag, by design). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
📝 WalkthroughWalkthroughReplaces the hand-written GitHub release workflow with an autogenerated Changescargo-dist Release Pipeline
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
This PR switches the project’s release workflow from a simple changelog-driven GitHub Release to a cargo-dist–generated pipeline that builds and publishes signed release artifacts for ourios-server, including checksums, a CycloneDX SBOM, and GitHub provenance attestations.
Changes:
- Add
dist-workspace.tomlconfiguring cargo-dist v0.32.0 for Linux GNU targets, SBOM generation, and GitHub attestations. - Opt
ourios-serverback into cargo-dist outputs via[package.metadata.dist] dist = truewhile keeping cratespublish = false. - Replace
.github/workflows/release.ymlwith the cargo-dist generated multi-job pipeline and add a dedicated[profile.dist]build profile.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 19 comments.
| File | Description |
|---|---|
| dist-workspace.toml | Introduces cargo-dist workspace configuration (targets, SBOM, attestations). |
| crates/ourios-server/Cargo.toml | Marks ourios-server as the sole dist-enabled distributable package. |
| Cargo.toml | Adds a profile.dist build profile inheriting from release with thin LTO. |
| .github/workflows/release.yml | Replaces prior release workflow with cargo-dist build/package/upload/release pipeline. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Hand-pin the floating GitHub Action references in the cargo-dist 0.32.0 generated release pipeline to immutable commit SHAs, matching the repo's supply-chain hardening posture. Renovate will keep these pinned after any future `dist generate`: - actions/checkout@v6 -> df4cb1c069e1874edd31b4311f1884172cec0e10 - actions/upload-artifact@v7 -> 043fb46d1a93c77aae656e7c1c64a875d1fc6a0a - actions/download-artifact@v8 -> 3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c - actions/attest@v4 -> 59d89421af93a897026c735860bf21b6eb4f7b26 cargo-dist's own actions (axodotdev/*, the installer) are left as dist pins them. Also fix three real bugs in the generated workflow. These live in cargo-dist-generated code and a future `dist generate` would revert them: - on.push.tags used a regex-style pattern (`**[0-9]+.[0-9]+.[0-9]+*`), but GitHub `tags:` uses glob matching where `+` is literal, so it would not match `vX.Y.Z`. Use a glob that matches the project's v-prefixed semver tags. - actions/attest subject-path was built from `join(matrix.targets, ', ')`, producing one comma+space glob that matches nothing. Compute a newline-separated list of per-target globs (which the attest action accepts) in a bash step and pass it through. - The cyclonedx `find . -name '*.cdx.xml' -exec mv ... target/distrib/` also matched files already under target/distrib/, risking a self-move error. Prune that subtree with `-not -path './target/distrib/*'`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Per Copilot review on #262: cargo-dist generates workflow-level contents: write, which would grant write to every job (incl. PR runs) and drop the repo's Token-Permissions posture. Narrow the top level to contents: read and grant contents: write only to the host job, which is the one that runs gh release create. (Reverts on dist generate; Renovate doesn't manage permissions, so this is a manual re-apply.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Per Copilot review on #262: the v[0-9]*.[0-9]*.[0-9]* glob didn't reliably match prerelease tags (v0.1.0-rc.1), which cargo-dist supports and marks as GitHub prereleases. Use 'v[0-9]*' — any v-prefixed version tag, prereleases included. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The dist plan job failed (exit 255): cargo-dist's CI-consistency check diffs the committed release.yml against what it would regenerate, and our hand-pinned action SHAs (+ perms/tag/bug edits) make it differ. Set allow-dirty = ["ci"] — cargo-dist's documented escape hatch for a hand-customized CI file — so plan/generate no longer fail on the deviations. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/release.yml:
- Line 55: The tag-flag variable derived from github.ref_name is injected into
multiple run commands without proper quoting, creating a shell injection
vulnerability where malicious tags containing metacharacters like $(cmd) or ;cmd
could execute arbitrary commands. To fix this, ensure the tag-flag variable is
either wrapped in single quotes when used in all run commands where it appears,
or better yet, pass the tag value as a properly escaped environment variable
instead of inline command templating, and validate the tag format more strictly
to reject tags containing shell metacharacters beyond the current v[0-9]*
pattern.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 6712c38d-970c-4072-88fe-f85ab341d3a8
📒 Files selected for processing (4)
.github/workflows/release.ymlCargo.tomlcrates/ourios-server/Cargo.tomldist-workspace.toml
What
Delivers the binary-release track of the first shipping milestone. Replaces the old changelog-only
.github/workflows/release.yml(a single git-cliff +action-gh-releasestep) with a cargo-dist v0.32.0 pipeline that, on av*semver tag, cross-compiles theourios-serverbinary, then generates checksums, a CycloneDX SBOM, and GitHub build-provenance attestations before publishing the GitHub Release.The complex workflow is tool-generated (
dist init+dist generate), not hand-authored.Why
The signed release assets — GitHub Artifact Attestations + the CycloneDX SBOM — are what flips OpenSSF Scorecard's Signed-Releases check, which is the remaining gap from the supply-chain hardening track.
Config (
dist-workspace.toml)cargo-dist-version0.32.0targetsx86_64-unknown-linux-gnu,aarch64-unknown-linux-gnuinstallers["shell"](npm/msi/homebrew skipped for v0)cargo-cyclonedxtrue(CycloneDX SBOM per release)github-attestationstrue(provenance viaactions/attest)Targets — musl dropped for v0
I configured all four Linux targets (gnu + musl, both arches) and
dist planplanned them cleanly. But the actual musl cross-build (which surfaces datafusion/parquet/ring-via-rustls issues) could not be verified clean in this environment — the host is macOS with only theaarch64-apple-darwintarget installed and no Linux/musl cross-toolchain (the project uses containerd, not Docker, socrossisn't wired up locally either). Rather than ship an unverified target into a tag-triggered release pipeline, musl is dropped to gnu-only for v0 (matching the "gnu only for v0" default). The stack is rustls +ring(no openssl/aws-lc), so musl is plausibly fine and can be added in a follow-up once it's verified on a Linux runner. macOS/Windows are out of scope for a Linux server backend.Distributable selection
All workspace crates are
version = "0.0.0"/publish = false, which hides every binary from cargo-dist ("this workspace doesn't have anything for dist to Release"). Per dist's own guidance,dist = trueinourios-server's[package.metadata.dist]opts the one server binary back in as the sole distributable; the library crates stay excluded.Changelog (git-cliff)
cargo-dist owns the GitHub Release and its release notes, reading them from
CHANGELOG.md(Keep-a-Changelog format, already in the repo). This cleanly replaces the git-cliff auto-generation step.cliff.tomlis left in the tree but is no longer wired into the release pipeline; pruning it can be a separate cleanup.One upstream-template fix
cargo-dist v0.32.0's generated workflow has a typo in the SBOM upload glob:
steps.cargo-cyclonedx.output.paths(should beoutputs.paths).actionlintflags it as an undefined-property expression. Left unfixed, the.cdx.xmlSBOM files silently fall out of the upload. Fixed tooutputs.paths. The cargo-dist-generated actions are otherwise left exactly as dist emits them (pinned by major tag, by design).Validation
dist --version->cargo-dist 0.32.0dist plan(dry-run) succeeded:python3 -c "import yaml; yaml.safe_load(...)"-> YAML OKactionlint .github/workflows/release.yml-> only SC2086/SC2129 info/style shellcheck notes inside cargo-dist's own generatedrun:blocks (left as generated; the repo has no actionlint CI gate). The one real expression error was theoutput.pathstypo, now fixed.cargo metadata --no-deps-> OK (workspace still resolves with the new[package.metadata.dist]+[profile.dist]).Note
Builds were not run end-to-end locally (cross-compile not possible on this host); the real cross-build + attestation + SBOM steps execute on the GitHub Linux runners when a
v*tag is pushed.🤖 Generated with Claude Code
Summary by CodeRabbit