Rust release, CI, security and versioning plumbing
Release engineering, CI, security and versioning plumbing for the Rust SDK. Stacked on the conformance runner PR (#160), which sits on rust-sdk (the crate): the Rust CI jobs here exercise both workspaces. Card: W4 releng.
What
release-rust.yml— shaped after basecamp-sdk'srelease-python.yml:smithy→test→package→publish.packageverifies the tag is onmainand[package] version == tag(read withcargo metadata, not a regex), runscargo package --lockedunderSOURCE_DATE_EPOCH, asserts.cargo_vcs_info.json(sha1 == HEAD,path_in_vcs == rust/fizzy-sdk) before anything irreversible, and uploads the.crate.publish(if: push, environmentrelease-crates,id-token: write) downloads the artifact, repackages the same commit and refuses unless the bytes match; then asks crates.io for the version and publishes only on 404. A 200 must carry the same checksum (rerun after a partial failure) or fail; a yanked version fails; any other status fails closed. OIDC viarust-lang/crates-io-auth-action(SHA-pinned). After publishing, the registry checksum is compared to the packaged sha256.workflow_dispatchis a packaging rehearsal (cargo publish --dry-run) and never mints a token.- Verified locally that
cargo packageis byte-reproducible across runs (with and withoutSOURCE_DATE_EPOCH; cargo normalizes mtimes itself), so the publish-side comparison is sound.
test.yml—test-rustmatrix{msrv, stable}setsRUSTUP_TOOLCHAINper leg (the MSRV fromcargo metadata'srust_version, stable fromrust-toolchain.toml) so the toolchain file cannot make both legs test stable, and assertsrustc --versionin both workspaces. Stable:rs-lint,rs-test,rs-doc,rs-deny,rs-check-drift,rs-publish-check, semver-checks (advisory, skipped until a crates.io baseline exists); MSRV: the library alone across feature sets. Both: lockfiles unchanged.conformance-rustneeds: test-rust.security.yml— Trivy over both workspaces;cargo denyweekly (the samemake rs-denyPR CI runs).- Dependabot —
cargofor/rustand/conformance/runner/rust. release-github.yml—release-rust.ymlinWORKFLOWS,cargo add fizzy-sdk@Xin the install body, and--event pushon the waiter so aworkflow_dispatchrehearsal can never satisfy the publish gate (this was a latent hole for all six workflows).- Makefiles / scripts — root
rs-*targets delegating torust/Makefile(both workspaces: fmt, clippy, tests, deny under onedeny.toml; the conformance targets themselves are in #164);make releasereads the crate version viacargo metadataand refuses a stale lock in either workspace;bump-version.shedits only the[package]table and refreshes bothCargo.locks;sync-api-version.shseds the generatedAPI_VERSION(toolchain-free; drift check catches disagreement);scripts/check-rs-service-drift.shis the operationId census. - Hygiene —
.editorconfig,.gitignore, pre-commitcargo fmt, CONTRIBUTING, AGENTS (six generated service layers).
crates.io bootstrap (human step)
Trusted publishing needs the crate to exist first. The exact values (crate fizzy-sdk, owner basecamp, repo fizzy-sdk, workflow release-rust.yml, environment release-crates, owner github:basecamp:cli) and the procedure are on the W4 card. The release-crates environment must be restricted to v* tags with required reviewers.
Gates
actionlint clean; zizmor: only the pre-existing by-design self-repository finding (7 across all workflows, 0 low+). Locally at rust-sdk @ 607730b with the pinned 1.98.1: rs-check-drift, rs-deny, rs-publish-check green; make conformance-rust 127/127.
Adversarial review (Codex, gpt-6-astra, xhigh, read-only)
Accepted: --event push on the waiter; dead-code lint failures in the runner draft (fixed there); document the bootstrap on the publish job. Declined: none on this PR's surface.
Review round 1: restacked so the runner precedes this PR; dropped --offline from the lockfile refresh.