Layer (b) — core/clippy.toml bans rand::random and rand::thread_rng crate-wide, each with a reason naming KEY-05 and pointing at the evidence doc. No CI change was needed: the Rust job already runs `cargo clippy --all-targets --all-features -- -D warnings` from core/, so a disallowed_methods hit is already a build failure. --all-targets covers tests deliberately — a fixture keeping the default is a template for the next production call site. Ordering was asserted before the file was written, not after: the residual count of unmigrated call sites is 0, so this cannot turn CI red for other agents on this shared tree. Layer (c) — core/deny.toml makes the rand major split change-detecting: global multiple-versions = "allow", a per-crate deny-multiple-versions for rand, and a dated grandfather skip pinning =0.9.2 exactly. The tree as it stands passes; a third version or a change to either member fails. Both gates were OBSERVED working, not assumed: - Reintroducing one banned call produced the disallowed_methods error with the reason text reaching the developer at the failure point; reverting returned the residual count to 0. - `cargo deny check bans` exits 0 as-is. Removing the grandfather entry made it exit 2 and print both dependency trees, independently confirming F-07's account of where each rand version comes from. Restored, it exits 0 again. Policy (checkpoint Task 5, human-approved): bans-only. The advisories gate is NOT enabled — it fails builds when a new CVE is published against an existing dep with no local change, which on a tree where several agents push continuously would block everyone at an arbitrary hour, with remediation often meaning a bump to an exactly-pinned crypto dependency. No break-glass procedure exists. F-07's advisory half stays OPEN and is recorded as such. cargo-deny is pinned to 0.20.2 and installed from crates.io rather than via EmbarkStudios/cargo-deny-action, because that action exposes no input to pin the tool version — an unpinned supply-chain checker would reintroduce, at the CI layer, the exact "backend fixed by configuration rather than stated" shape this plan exists to remove. crates.io is also the source vetted at the Task 5 legitimacy gate (EmbarkStudios, repo resolves, ~4.79M downloads). RECORDED HONESTLY: layer (b)'s gate is live but not yet EFFECTIVE. The tree carries 42 pre-existing clippy warnings — unused imports, dead code, ~39 style lints — that are already errors under -D warnings, so that CI step cannot pass today for reasons unrelated to KEY-05. Until a dedicated lint-clearing pass lands, a new banned RNG call would be one error among many rather than a distinctive build-stopper. Pre-existing and out of scope; clearing it right before an OTA would be poor sequencing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
45 lines
2.9 KiB
TOML
45 lines
2.9 KiB
TOML
# KEY-05 layer (b) — the crate-wide compile-time ban on defaulted RNG entry points.
|
|
#
|
|
# WHY THIS FILE EXISTS
|
|
# `rand::random()` and `rand::thread_rng()` are not broken today: on the pinned
|
|
# `rand 0.8.5` both resolve to a ChaCha12 CSPRNG seeded from `getrandom(2)`.
|
|
# What they lack is a STATED entropy backend. The backend is fixed by dependency
|
|
# and build configuration rather than by the calling code, and nothing produces a
|
|
# compile error if that changes underneath us. That is the exact structural shape
|
|
# ("T1") behind the 2026-07-30 COLDCARD entropy defect — and here the blast radius
|
|
# includes Cashu blinded-key-exchange values, X3DH prekey material, session bearer
|
|
# tokens and a ChaCha20-Poly1305 nonce.
|
|
#
|
|
# So every draw must name `rand::rngs::OsRng` at its own call site, and key
|
|
# material and AEAD nonces must additionally run the degenerate-entropy predicate
|
|
# in `archipelago::entropy`.
|
|
#
|
|
# HOW IT IS ENFORCED
|
|
# No CI change was needed for this layer. The existing Rust job already runs
|
|
# `cargo clippy --all-targets --all-features -- -D warnings` from `core/`, so a
|
|
# `disallowed_methods` hit is already a build failure. `--all-targets` means test
|
|
# code is covered too, which is deliberate: test fixtures migrate to `OsRng` as
|
|
# readily as production code does, and a fixture that keeps the default is a
|
|
# template for the next production call site.
|
|
#
|
|
# SCOPE, STATED HONESTLY
|
|
# This reaches the five workspace members (archipelago, archipelago-container,
|
|
# archipelago-openwrt, archipelago-performance, archipelago-security), verified
|
|
# via `cargo metadata --no-deps`. It does NOT reach `core/models`, which is not a
|
|
# workspace member and therefore not in the clippy build graph; the two matches
|
|
# there are recorded as a stated limitation in the evidence document.
|
|
#
|
|
# IF YOU ARE HITTING THIS LINT
|
|
# Do not add `#[allow]` reflexively. Use `rand::rngs::OsRng` at the call site. If
|
|
# the value is key material or an AEAD nonce of at least 12 bytes, route it through
|
|
# `crate::entropy::draw_key_bytes`. An `#[allow(clippy::disallowed_methods)]` needs a
|
|
# justification comment on the line above stating why the DEFAULT is required here —
|
|
# "it is a test" is not a justification.
|
|
#
|
|
# See: docs/security/KEY-05-ENTROPY-ENFORCEMENT.md
|
|
|
|
disallowed-methods = [
|
|
{ path = "rand::random", reason = "KEY-05: inherits its entropy backend from a dependency default instead of stating it. Use rand::rngs::OsRng at the call site; for key material or AEAD nonces >= 12 bytes use crate::entropy::draw_key_bytes. See docs/security/KEY-05-ENTROPY-ENFORCEMENT.md" },
|
|
{ path = "rand::thread_rng", reason = "KEY-05: inherits its entropy backend from a dependency default instead of stating it. Use rand::rngs::OsRng at the call site; for key material or AEAD nonces >= 12 bytes use crate::entropy::draw_key_bytes. See docs/security/KEY-05-ENTROPY-ENFORCEMENT.md" },
|
|
]
|