ruvector/deny.toml
ruvnet 7962366713 ci(security): add 5-layer supply-chain CI + clear 3 npm criticals
Mirrors the pattern landed on sublinear-time-solver#25:
  1. dependency-review  (PRs only, informational)
  2. cargo-audit        (RustSec advisory DB, vulnerabilities only)
  3. cargo-deny         (license/source/ban policy via deny.toml)
  4. npm-audit          (workspace npm/ at --audit-level=critical)
  5. lockfile-integrity (cargo metadata --locked)

npm criticals cleared via package.json overrides:
  - vm2:                 transitively dropped via @google-cloud/redis 5.x
  - fast-xml-parser:     >=5.7.0 (was <=5.6.0 vuln)
  - protobufjs:          >=7.5.6 (was <=7.5.5 vuln)
  - @google-cloud/redis: >=5.0.0 (was <=3.3.0 vuln)
  - handlebars:          picked up >=4.7.9 via override resolution

Result: 73 vulns → 33 (3 crit → 0, 36 high → 19, 17 medium → 5).
19 highs remain (mostly devDep transitives + ML helpers) and are
tracked via the new dependabot.yml — Dependabot will chip away
weekly.

deny.toml ignore-list with re-review dates covers:
  - RUSTSEC-2023-0071  rsa Marvin Attack (no patched version yet,
                       local-only signing for Kalshi API; re-review
                       2026-08-01)
  - RUSTSEC-2026-0097  rand unsoundness (not triggerable in our
                       usage — no logging inside RNG draws)
  - RUSTSEC-2026-0115/0116/0117  imageproc unsoundness (scipix
                       offline examples only, never published)
  - 8 unmaintained advisories (paste, bincode, instant, rand_os,
    proc-macro-error, rustls-pemfile, rusttype, number_prefix,
    core2) — all transitive, no CVE, tracked for migration

Added BSL-1.0, CDLA-Permissive-2.0, NCSA licenses to allowlist
(present in transitive deps via xxhash-rust, tch-rs, LLVM family).

dependabot.yml schedules weekly Tuesday 09:35 UTC for cargo +
npm + github-actions ecosystems with patch+minor grouping.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-05-19 08:59:46 -04:00

215 lines
10 KiB
TOML

# cargo-deny configuration — supply-chain policy for the ruvector
# workspace. See the supply-chain CI workflow (`.github/workflows/
# supply-chain.yml`) for how this gets enforced on every PR + on a
# weekly scheduled scan.
#
# Run locally:
# cargo install --locked cargo-deny
# cargo deny check
#
# Four sub-checks run: advisories, bans, licenses, sources.
# Each fails the run independently; together they form the crate-graph
# half of our supply-chain defence (npm side is in the same workflow).
[graph]
# Sensible target set so we don't pull in checks for triples we never
# build day-to-day. wasm32-unknown-unknown is gated per-crate by the
# `wasm` features and gets its own checks in the wasm CI jobs.
targets = [
{ triple = "x86_64-unknown-linux-gnu" },
{ triple = "aarch64-unknown-linux-gnu" },
{ triple = "x86_64-apple-darwin" },
{ triple = "aarch64-apple-darwin" },
]
# ─────────────────────────────────────────────────────────────────────
# 1) advisories — RustSec DB scan
# ─────────────────────────────────────────────────────────────────────
[advisories]
db-urls = ["https://github.com/RustSec/advisory-db"]
version = 2
# Surface yanked crates as warnings. Promote to `deny` once we've
# migrated off whichever transitive holds the yanked version.
yanked = "warn"
# Whitelist specific RUSTSEC IDs with justification + re-review date.
# Every entry MUST carry a justification and an explicit re-review
# date — we revisit on each minor release at minimum. Dependabot will
# auto-resolve most of these as upstreams publish fixes; this list is
# meant to shrink over time.
ignore = [
# ── Real vulnerabilities (need active migration path) ────────────
# rsa 0.9.x — Marvin Attack timing sidechannel (RUSTSEC-2023-0071).
# No patched version exists; the RustCrypto/RSA team is rewriting
# to constant-time. Used by `ruvector-kalshi` for Kalshi exchange
# API signing (RSA-PSS-SHA256, mandated by the exchange). Mitigation
# per the advisory: "local use on a non-compromised computer is
# fine" — we sign locally and an attacker would need to observe
# sub-ms timing across many requests through the network response
# timing to recover the key. Risk is acceptable for trading-bot
# use; re-review on 2026-08-01 or when `rsa 0.10` ships with the
# constant-time fix (track: https://github.com/RustCrypto/RSA/issues/626).
"RUSTSEC-2023-0071",
# ── Unsoundness (no exploit path in our usage) ───────────────────
# rand 0.8.5 — unsound only when paired with a *custom logger* that
# logs during random number generation (RUSTSEC-2026-0097). We use
# `tracing` and never log inside RNG draws; the unsound condition
# cannot be triggered. Re-review on `rand 0.9` adoption across the
# workspace.
"RUSTSEC-2026-0097",
# imageproc 0.25.0 — three unsoundness advisories around image
# sampling / bounds checks. Pulled transitively via the scipix
# examples crate, never reached by the publish artifacts of any
# crates.io-published member. Unsound != exploitable here: inputs
# are caller-controlled image buffers in offline experiments.
# Re-review on 2026-08-01 or when imageproc publishes 0.26 with
# the fixes.
"RUSTSEC-2026-0115",
"RUSTSEC-2026-0116",
"RUSTSEC-2026-0117",
# ── Unmaintained transitive deps (informational, no CVE) ─────────
# proc-macro-error 1.x — unmaintained, transitively required by
# several proc-macro deps (clap-derive ecosystem). 2.x is API
# incompatible. Dependabot tracking. Re-review on 2026-07-01.
"RUSTSEC-2024-0370",
# number_prefix — unmaintained, used transitively by indicatif. No
# known successor; indicatif itself is still maintained. Informational.
"RUSTSEC-2025-0119",
# paste 1.0.x — archived upstream 2024-10. Pulled transitively via
# nalgebra/simba and several proc-macro deps. No vulnerability,
# just informational. Re-review on 2026-08-01.
"RUSTSEC-2024-0436",
# bincode 1.x — unmaintained, 2.x is API-incompatible. Multiple
# call sites across rvf + serialization layers; migration queued.
# Re-review on 2026-07-01.
"RUSTSEC-2025-0141",
# instant 0.1.x — unmaintained. Transitive via async-std / wasm
# adapters. Replacement is `web-time` but several transitives still
# pin instant directly. Re-review on 2026-07-15.
"RUSTSEC-2024-0384",
# rand_os 0.x — unmaintained, replaced by getrandom. Transitive via
# legacy rand internals; modern paths use getrandom directly.
"RUSTSEC-2021-0140",
# core2 0.4.0 — yanked, but pulled transitively via the rav1e/
# image/imageproc chain (offline-only scipix examples crate).
# Re-review when imageproc bumps off ravif 0.13.
"RUSTSEC-2025-0124",
# rustls-pemfile 1.x — unmaintained, replaced by rustls-pki-types'
# builtin PEM parser. Transitive via reqwest / tokio-tungstenite.
# Migration is a transitive bump; Dependabot tracking.
"RUSTSEC-2025-0134",
# rusttype 0.9 — unmaintained (RUSTSEC-2026-0105). Used by
# imageproc's text-rendering path which we don't exercise (scipix
# offline experiments only). No safe upgrade available. Re-review
# 2026-08-01.
"RUSTSEC-2026-0105",
]
# ─────────────────────────────────────────────────────────────────────
# 2) bans — explicit crate-name allow/block list
# ─────────────────────────────────────────────────────────────────────
[bans]
# 136-member workspace pulls both Tokio and async-std families,
# producing legitimate version skew (e.g. nalgebra 0.32 vs 0.33 across
# linear-algebra crates). Track for cleanup but `warn`, not `deny`.
multiple-versions = "warn"
# Refuse `version = "*"` for crates.io deps in any of our Cargo.tomls
# — that's how typosquatting + accidental floats land malicious
# versions. Demoted to `warn` for now because several internal/path
# wildcards exist in the mcp-brain + consciousness experiment crates
# (those use `workspace = "*"` for path-only deps which cargo-deny
# can't always distinguish from registry wildcards). Tracked for
# tightening to `deny` once those are migrated to explicit version
# constraints. Re-review on 2026-08-01.
wildcards = "warn"
# Highlight transitively-pulled-in deep deps so reviewers can audit
# tree growth without explicit blessing.
highlight = "all"
# Concretely forbidden crates — empty for now. Use this slot to
# quickly block a compromised package mid-flight without editing the
# workflow.
deny = []
# Allow internal workspace path deps to use `version = "*"` until the
# tighten-up pass lands. Listed crates have been audited as path-only.
allow-wildcard-paths = true
# ─────────────────────────────────────────────────────────────────────
# 3) licenses — what we'll allow in the graph
# ─────────────────────────────────────────────────────────────────────
[licenses]
version = 2
# Matches `actions/dependency-review-action`'s allow-list in the
# supply-chain workflow so the two checks agree.
#
# Additions vs sublinear-time-solver's allowlist:
# * BSL-1.0 — Boost Software License (xxhash-rust transitive
# via rvf-wire → mcp-brain-server + benchmarks)
# * CDLA-Permissive-2.0 — used by tch-rs / onnxruntime style deps
# * NCSA — University of Illinois/NCSA Open Source
# License (LLVM family deps)
allow = [
"MIT",
"Apache-2.0",
"Apache-2.0 WITH LLVM-exception",
"BSD-2-Clause",
"BSD-3-Clause",
"ISC",
"Unicode-DFS-2016",
"Unicode-3.0",
"MPL-2.0",
"Zlib",
"CC0-1.0",
"BSL-1.0",
"CDLA-Permissive-2.0",
"NCSA",
]
confidence-threshold = 0.8
exceptions = []
# Workspace-internal crates without `license = "..."` set are research
# / examples crates with `publish = false`. Ignore them rather than
# failing the run — they're never shipped to crates.io. If one is ever
# flipped to `publish = true`, the publish flow's `cargo publish` step
# will refuse it without an explicit license, so this is safe.
private = { ignore = true }
# ─────────────────────────────────────────────────────────────────────
# 4) sources — which registries / git remotes the graph can pull from
# ─────────────────────────────────────────────────────────────────────
[sources]
# Default: only the official crates.io registry. Anything else (private
# mirror, git dep) must be explicitly allowed.
unknown-registry = "deny"
# `warn` instead of `deny` for ruvector because the workspace pulls
# several legitimate git deps (vendored hailo bindings, in-flight
# upstream fixes pinned to commits). Promote to `deny` once those
# have crates.io releases. Each unknown-git appearance shows up in
# the CI log so reviewers can challenge it on a per-PR basis.
unknown-git = "warn"
# Allow-list for git remotes — populated on demand. If a future PR
# needs a git dep, this is where the reviewer adds it with a
# justification comment.
allow-git = []
allow-registry = ["https://github.com/rust-lang/crates.io-index"]