Problem Statement
OpenShell has no automated supply-chain vulnerability scanning against the RustSec advisory database. The project has ~300+ transitive dependencies in Cargo.lock, and known CVEs in those dependencies go undetected. There is no license compliance checking or protection against dependencies pulled from unknown registries or git sources.
Proposed Design
Add cargo-deny to CI to gate PRs against known vulnerabilities, license violations, and untrusted dependency sources.
1. deny.toml configuration
Advisories: Check all dependencies against the RustSec advisory database. Enforce a 30-day maximum DB staleness (maximum-db-staleness = "P30D") so CI cannot silently pass against outdated data. Warn on yanked crates. Flag unmaintained workspace crates. Acknowledge pre-existing transitive advisories with documented ignore entries (to be removed as upstream deps are upgraded):
RUSTSEC-2026-0190 — anyhow unsoundness in downcast_mutRUSTSEC-2026-0204 — crossbeam-epoch pointer deref (transitive via metrics/quanta)RUSTSEC-2023-0071 — rsa Marvin attack (transitive via spiffe, no direct exposure)RUSTSEC-2025-0134 — rustls-pemfile unmaintained (transitive via older kube/hyper)RUSTSEC-2026-0098, RUSTSEC-2026-0099, RUSTSEC-2026-0104 — rustls-webpki vulnerabilities (transitive via older rustls)RUSTSEC-2025-0068 — serde_yml unsound+unmaintained (transitive via kube)
Licenses: Allow only permissive licenses (Apache-2.0, MIT, BSD variants, ISC, Zlib, CC0-1.0, Unlicense, Unicode-3.0, etc.). Ignore private/unpublished workspace crates.
Bans: Warn on duplicate crate versions (informational, not blocking).
Sources: Deny dependencies from unknown registries or git sources. Only allow crates.io. (Verified: the workspace currently has zero git dependencies.)
2. CI workflow (.github/workflows/cargo-deny.yml)
- Triggers: merge group checks, PR branches (
pull-request/*), daily scheduled run (catch newly disclosed CVEs), and manual dispatch. - Smart change detection: Skip the check on PRs that don't touch
Cargo.toml, Cargo.lock, deny.toml, or the workflow file itself. Always run on schedule and manual dispatch. - Runner: Use the existing
linux-amd64-cpu8 CI container image with mise for tool installation.
3. Local developer task
- Add a
rust:deny mise task so developers can run mise run rust:deny locally before pushing.
Alternatives Considered
cargo audit instead of or alongside cargo deny — cargo deny check advisories covers the same RustSec DB scan. Using cargo deny alone avoids redundant tooling while also providing license, ban, and source checks that cargo audit doesn't offer.
Snyk — Evaluated but found to handle Rust codebases poorly. cargo-deny is purpose-built for the Rust ecosystem.
Strict wildcard ban (wildcards = "deny") — Requires all workspace crates to set publish = false in their Cargo.toml. Our workspace crates use version = "*" for internal path dependencies and cargo-deny treats crates without that flag as publishable. Not worth a mass Cargo.toml change since these are internal workspace deps, not a supply-chain risk.
Hard-fail on all unmaintained crates (unmaintained = "all") — Would require skip-tree entries for unfixable transitive deps we can't control. Scoping to "workspace" catches our own crates without that maintenance burden.
Agent Investigation
- Identified eight pre-existing transitive advisories that need acknowledged ignore entries
- Verified that
cargo deny check passes cleanly with the proposed configuration - Verified zero git dependencies in the workspace — crates.io-only source restriction is safe
cc @alangou
Problem Statement
OpenShell has no automated supply-chain vulnerability scanning against the RustSec advisory database. The project has ~300+ transitive dependencies in
Cargo.lock, and known CVEs in those dependencies go undetected. There is no license compliance checking or protection against dependencies pulled from unknown registries or git sources.Proposed Design
Add
cargo-denyto CI to gate PRs against known vulnerabilities, license violations, and untrusted dependency sources.1.
deny.tomlconfigurationAdvisories: Check all dependencies against the RustSec advisory database. Enforce a 30-day maximum DB staleness (
maximum-db-staleness = "P30D") so CI cannot silently pass against outdated data. Warn on yanked crates. Flag unmaintained workspace crates. Acknowledge pre-existing transitive advisories with documented ignore entries (to be removed as upstream deps are upgraded):RUSTSEC-2026-0190— anyhow unsoundness indowncast_mutRUSTSEC-2026-0204— crossbeam-epoch pointer deref (transitive via metrics/quanta)RUSTSEC-2023-0071— rsa Marvin attack (transitive via spiffe, no direct exposure)RUSTSEC-2025-0134— rustls-pemfile unmaintained (transitive via older kube/hyper)RUSTSEC-2026-0098,RUSTSEC-2026-0099,RUSTSEC-2026-0104— rustls-webpki vulnerabilities (transitive via older rustls)RUSTSEC-2025-0068— serde_yml unsound+unmaintained (transitive via kube)Licenses: Allow only permissive licenses (Apache-2.0, MIT, BSD variants, ISC, Zlib, CC0-1.0, Unlicense, Unicode-3.0, etc.). Ignore private/unpublished workspace crates.
Bans: Warn on duplicate crate versions (informational, not blocking).
Sources: Deny dependencies from unknown registries or git sources. Only allow crates.io. (Verified: the workspace currently has zero git dependencies.)
2. CI workflow (
.github/workflows/cargo-deny.yml)pull-request/*), daily scheduled run (catch newly disclosed CVEs), and manual dispatch.Cargo.toml,Cargo.lock,deny.toml, or the workflow file itself. Always run on schedule and manual dispatch.linux-amd64-cpu8CI container image with mise for tool installation.3. Local developer task
rust:denymise task so developers can runmise run rust:denylocally before pushing.Alternatives Considered
cargo auditinstead of or alongsidecargo deny—cargo deny check advisoriescovers the same RustSec DB scan. Usingcargo denyalone avoids redundant tooling while also providing license, ban, and source checks thatcargo auditdoesn't offer.Snyk — Evaluated but found to handle Rust codebases poorly.
cargo-denyis purpose-built for the Rust ecosystem.Strict wildcard ban (
wildcards = "deny") — Requires all workspace crates to setpublish = falsein theirCargo.toml. Our workspace crates useversion = "*"for internal path dependencies and cargo-deny treats crates without that flag as publishable. Not worth a mass Cargo.toml change since these are internal workspace deps, not a supply-chain risk.Hard-fail on all unmaintained crates (
unmaintained = "all") — Would requireskip-treeentries for unfixable transitive deps we can't control. Scoping to"workspace"catches our own crates without that maintenance burden.Agent Investigation
cargo deny checkpasses cleanly with the proposed configurationcc @alangou