feat(release): crates.io trusted publishing + toolchain SBOM (Phases 4+6)#136
Merged
Conversation
…BOM)
Phase 4 — crates.io OIDC trusted publishing
- new .github/workflows/publish-to-crates-io.yml, triggered in
parallel with release.yml on every v* tag push
- rust-lang/crates-io-auth-action@v1 exchanges the workflow OIDC
token for a short-lived crates.io token; no CRATES_IO_TOKEN
secret stored
- scripts/publish.rs walks the curated dependency order with retry
on index-propagation lag (mirrors pulseengine/sigil's helper)
- workspace version bumped 0.1.0 -> 0.6.0 (trusted publishing
needs real semvers; bumped in lockstep with the next release tag)
- publishable crates carry homepage/keywords/categories via
workspace inheritance; internal path deps add explicit version
so cargo publish rewrites them to crates.io coordinates
- publish set (11 crates): synth-cli, synth-core, synth-frontend,
synth-synthesis, synth-backend, synth-backend-{awsm,wasker,riscv},
synth-cfg, synth-opt, synth-verify
- publish = false for synth-analysis, synth-abi, synth-memory,
synth-qemu, synth-test, synth-wit (not on the synth-cli public
face; promotion later only needs removing the line)
- MODULE.bazel version bumped 0.1.0 -> 0.6.0 to match
- blocker: per-crate trusted-publisher registration on crates.io
is a manual one-time step the maintainer must do; documented in
docs/release-process.md "Phase 4 user-side setup"
Phase 6 — toolchain SBOM auto-emit in release.yml
- cargo cyclonedx generates a CycloneDX 1.5 JSON SBOM rooted at
synth-cli and writes release-assets/synth-v<VERSION>.cdx.json
- SBOM is produced before SHA256SUMS so its digest is captured
in the signed checksum manifest; the existing cosign signature
over SHA256SUMS.txt transitively covers the SBOM
- distinct from the per-compilation SBOM `synth compile --sbom`
added in #129; docs/sbom.md now opens with the comparison table
Validation: cargo test --workspace --exclude synth-verify clean,
cargo clippy --workspace --exclude synth-verify --all-targets
-- -D warnings clean, cargo fmt --check clean, both workflow YAMLs
parse with python yaml.safe_load. cargo publish --dry-run is
blocked in this environment; the dry-run gate runs first in the
workflow itself before any real publish.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
avrabe
added a commit
that referenced
this pull request
May 24, 2026
This was referenced May 24, 2026
avrabe
added a commit
that referenced
this pull request
May 25, 2026
The Cargo.toml workspace-package version was bumped to 0.7.0 in PR #142, but the per-crate `version = "0.6.0"` pins on path dependencies (introduced in #136 to give `cargo publish` real crates.io coordinates to rewrite to) were not swept. Cargo refuses to resolve `synth-backend = "^0.6.0"` against the local 0.7.0 path-dep, breaking both release.yml and publish-to-crates-io.yml on the v0.7.0 tag. This commit sweeps all 23 intra-workspace `version = "0.6.0"` pins (across 8 crate manifests) to `"0.7.0"`, and bumps the MODULE.bazel `module(version = ...)` declaration to match. The v0.7.0 tag was deleted from origin (no GitHub Release was produced — release.yml's build matrix failed before the 'Create GitHub Release' job, which was skipped) and will be re-pushed against this commit. Local validation: cargo metadata --no-deps # resolves at 0.7.0 cargo build --release -p synth-cli # green Follow-up tracked separately: docs/release-process.md should gain an explicit 'sweep intra-workspace pins' step (or a CI gate that fails when workspace version diverges from path-dep pins) so v0.8.0 doesn't repeat this.
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.
Summary
Closes Phases 4 (crates.io trusted publishing) and 6 (toolchain SBOM auto-emit) of synth's release roadmap, defined in
docs/release-process.md. Together with PR #135 (Phase 5, sigil ELF signing) this completes the supply-chain evidence layers for synth — Phases 1-6 all implemented.Phase 4 — crates.io trusted publishing
Publish set (11 crates) —
synth-cli,synth-core,synth-frontend,synth-synthesis,synth-backend,synth-backend-{awsm,wasker,riscv},synth-cfg,synth-opt,synth-verify.publish = false(6 crates, kept private) —synth-analysis,synth-abi,synth-memory,synth-qemu,synth-test,synth-wit. None are onsynth-cli's transitive face; promotion later is a one-line change.Metadata — every publishable Cargo.toml has
description,license,repository(already present), plus newly-addedhomepage.workspace,keywords.workspace,categories.workspace. Internalpath = "..."deps on publishable crates now carryversion = "0.6.0"socargo publishrewrites to crates.io coordinates.Versioning — workspace
versionbumped0.1.0→0.6.0(alsoMODULE.bazel). Convention going forward: bump pre-tag in lockstep with the release tag; the new workflow refuses to run if they disagree.Workflow —
.github/workflows/publish-to-crates-io.ymltriggers onv*tag (parallel torelease.yml);if: github.repository == 'pulseengine/synth';permissions: id-token: write; usesrust-lang/crates-io-auth-action@v1for OIDC. Dependency-order walk lives inscripts/publish.rs(rustc-compiled at workflow start, mirrors sigil's pattern) with a 10-attempt × 40s retry loop for index propagation. Injection-safe:inputs.tagbound viaenv: INPUT_TAG, dereferenced as$INPUT_TAGin shell.Phase 6 — toolchain SBOM in release pipeline
Added two steps to the
create-releasejob in.github/workflows/release.yml:cargo install --locked cargo-cyclonedxcargo cyclonedx --format json --spec-version 1.5 -p synth-cli→ renamed tosynth-v<VERSION>.cdx.jsonin release assetsEmitted before
SHA256SUMS.txt, so its digest is in the manifest and the existing cosign keyless signature overSHA256SUMS.txttransitively covers it — no new signing step.This is the complement to the per-compilation SBOM (
synth compile --sbom, PR #129): that one documents what synth compiles; this one documents what synth is. Comparison table indocs/sbom.md.Honest blocker — needs the maintainer (verified clean-room)
Per-crate trusted-publisher registration on crates.io. For each of the 11 publishable crates, the repo owner must visit
https://crates.io/crates/<NAME>/settings → Trusted Publishingand registerpulseengine/synthwith workflow filenamepublish-to-crates-io.yml. For brand-new crates not yet on crates.io, a manual first publish is needed before the registration page exists. Documented indocs/release-process.md§ "Phase 4 — user-side setup".cargo publish --dry-runwas blocked in the agent's sandbox; the workflow's./publish verifystep runs the full dry-run gate before any real publish.Clean-room verification
A clean-room subagent independently verified the report: 15 of 16 claims CONFIRMED with file:line citations (including the publish set, the
publish = falseset, the workspace version bump, MODULE.bazel diff, per-crate metadata, path-dep versions, workflow injection-safety,scripts/publish.rsshape, SBOM-before-SHA256SUMS ordering, docs updates, both YAMLs parse, blocker documented). 1 CANNOT-VERIFY (historical CI run — structurally unverifiable).Test plan
v*tag push after this lands: watch the newPublish to crates.ioworkflow — will likely needworkflow_dispatchre-runs as each crate is registeredsynth-v0.6.0.cdx.jsonin the release assets🤖 Generated with Claude Code