Two CI jobs sweep the workspace against public supply-chain policy on
every push and pull request: security-audit (RustSec advisories) and
dep-policy (bans / licenses / duplicate versions / registry sources).
Both are hard-fail merge blockers — a red mark stops the PR. They were
promoted from continue-on-error: true once the wasmtime 26 -> 46
coordinated bump closed out the last 19-entry advisory tail (see
"Known follow-ups" below).
| Job | Tool | Config | Duration (cached) |
|---|---|---|---|
security-audit |
cargo-audit |
.cargo/audit.toml |
~1 s |
dep-policy |
cargo-deny |
deny.toml |
~1 s |
Both tools are cached in ~/.cargo/bin on the CI runner and only
reinstall when the pinned version in the workflow env block changes.
cargo install --locked --version 0.22.0 cargo-audit
cargo install --locked --version 0.19.9 cargo-deny
# Advisory scan (RustSec DB).
cargo audit
# Full sweep (advisories + licenses + bans + sources).
cargo deny check
Both commands are workspace-root only. They pick up
.cargo/audit.toml and deny.toml automatically.
Every ignore is temporary by policy. Adding one requires a one-line rationale in the surrounding comment block AND a follow-up path (bump, upstream migration, or dep swap).
.cargo/audit.toml— forcargo audit. Comment above each ID explains why the advisory is accepted.deny.toml— the[advisories].ignorelist mirrors.cargo/audit.tomlone-for-one. Keep the two in lockstep or a green audit run may still trip the deny job.
Duplicate-version warnings are informational (multiple-versions = "warn"); the top three offenders as of the initial pass are called
out in deny.toml and should be revisited when the ecosystem lands
majority-adopted upgrades.
Every unsafe {} block and every body of an unsafe fn MUST carry a
// SAFETY: comment stating the invariant the caller (or the
surrounding call site) upholds. The rule is enforced by the workspace
lint
[workspace.lints.clippy]
undocumented_unsafe_blocks = "deny"promoted from the pedantic-group warn default. CI already runs
RUSTFLAGS="-D warnings" cargo clippy --workspace --all-targets --all-features --locked, so a missing SAFETY comment fails the build
without any additional wiring. The initial promotion audited the ~262
existing unsafe sites in tree — every one already carried a comment;
enabling the lint at deny locks the invariant so a future patch
cannot silently regress.
How to write the SAFETY comment. One or two lines, placed on the
line(s) immediately preceding the unsafe block (after any
attributes on that block, not before them). State the invariant the
caller upholds — the CPU-feature check, the length precondition, the
lifetime, the pointer-provenance argument — using the same variable
names as the surrounding code so the reader can trace it. Example:
#[allow(unsafe_code, reason = "SIMD intrinsic wrappers are unsafe by declaration")]
// SAFETY: is_x86_feature_detected!("avx2") returned true; NEON is
// enabled via `#[target_feature]` and `off + BLOCK <= len` upholds
// the 16-byte read from `a`.
let simd_result = unsafe { simd::x86_avx2::distance(&a, &b) };Two adjacent unsafe { … } blocks each need their own comment (the
lint checks per block, not per statement). A shared invariant can be
referenced tersely on the second block — // SAFETY: as above, k * 2
- 1 < 64
under the loop bound.— but the comment must be present.
Machine-generated code. The src/bindings.rs files that
wit-bindgen emits into every *-component crate contain many
unsafe extern blocks without SAFETY comments. Each such module is
declared with
#[allow(
unsafe_code,
unsafe_op_in_unsafe_fn,
missing_docs,
clippy::all,
clippy::pedantic,
clippy::nursery,
clippy::restriction
)]
mod bindings;so the pedantic-group undocumented_unsafe_blocks lint is silenced
for generated code only. Do not re-emit the generated file to add
SAFETY comments — it will be overwritten the next time
wit-bindgen runs. If you add a NEW component crate, mirror the same
#[allow] on its mod bindings; declaration.
wasmtime 26 → 46 major bump.Landed. The sixstringcheese-*-componentcrates now pinwasmtime = "46"/wasmtime-wasi = "46"for the WIT component-model smoke tests, up from26. This closed 19 advisories including the two 9.0-critical sandbox-escape entries (RUSTSEC-2026-0095 Winch sandbox-escape memory, RUSTSEC-2026-0096 aarch64 Cranelift sandbox escape). Thewasip1 → wasip2reactor adapter shipped alongside wasmtime 46 emits thewasi:@0.2.12import surface, up from the earlierwasi:@0.2.1— the WIT sources incomponent/wit/import nowasi:interfaces themselves, so the world bump lives in the adapter/host coupling only. wasmtime 46 requires rustc 1.94; the workspacerust-versionstays at 1.88 (the component crates' public API compiles unchanged, only their dev-deps for the smoke tests need the newer toolchain) and the MSRV CI row excludes the six*-componentcrates from its test sweep. See the.cargo/audit.tomlhistory for the full 19-advisory table this bump closed.- bio 2 → 4 bump. Two unmaintained transitives (
custom_derive,fxhash) enter the tree only through theoracle-benchesfeature ofstringcheese-align. A bio major bump drops both. - atomic-polyfill.
wasmtime 46 -> cranelift -> postcard -> heapless 0.7still pulls in the unmaintainedatomic-polyfillcrate.heapless 0.8drops the polyfill; clearing this ignore needs upstreampostcardand/orwasmtimeto bump. Informational only, no CVE.