diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 03c671a5a..f4265a777 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -426,6 +426,27 @@ jobs: # correct everywhere else). Run the table; do not re-read the regex. - name: "`apr`-pinning guard must still turn RED (case table + surfaces)" run: bash scripts/check_apr_bin_pinned.sh --self-test + # deny.toml is 7.2 KB of licence / banned-crate / source-allowlist policy + # that ran in NO workflow -- only `make deny`, which is not a prerequisite + # of any tier, so nothing but a human typing it ever invoked it. Meanwhile + # cargo-deny 0.20.2 ships INSIDE the CI image already. + # + # Because nothing ran it, the policy drifted out of sync with the repo's + # own deliberate architecture and now fails on main: + # advisories ok, bans FAILED, licenses FAILED, sources ok + # Both failures were config drift, not defects (see the deny.toml comments). + # Fixed there; wired here so it cannot drift unnoticed again. + # + # `ci / security` from the reusable workflow runs `cargo audit`, which does + # NOT read deny.toml -- so this covers licences, bans and sources, which + # nothing else does. + - name: cargo-deny (licences, bans, sources, advisories) + run: | + docker run --rm \ + -v "${GITHUB_WORKSPACE}:/workspace" \ + -w /workspace \ + "$IMAGE" \ + cargo deny check # Poka-yoke: `set` in a SOURCED file mutates the caller's shell. apr_bin.sh # opened with `set -euo pipefail`; qwen-story.sh sources it and had chosen # `set -uo pipefail` deliberately (it must run every beat and tally the diff --git a/Makefile b/Makefile index cd3ccdebe..5fd2858c5 100644 --- a/Makefile +++ b/Makefile @@ -214,6 +214,8 @@ tier3: @bash scripts/check_include_files.sh @echo "Checking publish safety (symlinks, companion lookups)..." @bash scripts/check_publish_safety.sh + @echo "Checking cargo-deny policy (licences, bans, sources, advisories)..." + @$(MAKE) --no-print-directory deny @echo "Checking exclude patterns are root-anchored (CB-510 class)..." @bash scripts/check_exclude_anchored.sh @echo "Checking build.rs crate-root escapes (v0.31.1 yank class)..." diff --git a/deny.toml b/deny.toml index 26820aa32..9562f5088 100644 --- a/deny.toml +++ b/deny.toml @@ -92,9 +92,40 @@ allow = [ ] confidence-threshold = 0.8 +# NCSA, scoped to the ONE crate that carries it rather than added to `allow` +# above. Provenance: +# +# libfuzzer-sys (MIT OR Apache-2.0) AND NCSA +# <- rav1e <- ravif <- image <- aprender-test-lib +# +# i.e. it arrives through an AV1 encoder pulled in by `image`, not through +# anything this project chose directly. NCSA is OSI-approved and FSF Free/Libre +# and is permissive, so it is acceptable here -- but as an EXCEPTION, so that a +# future NCSA dependency arriving by some other path is still flagged for a +# decision instead of being silently admitted. +[[licenses.exceptions]] +name = "libfuzzer-sys" +allow = ["NCSA"] + [bans] multiple-versions = "warn" wildcards = "deny" +# Sibling dev-dependencies in this monorepo are DELIBERATELY path-only, with no +# `version` field: +# +# aprender-core -> aprender-train, aprender-profile (dev) +# aprender-compute -> aprender-core, aprender-simulate, ... (dev) +# aprender-serve -> aprender-cuda-edge (dev) +# +# That is how the crates.io publish cycle is broken: `cargo publish` strips +# dev-dependencies, so a path-only dev-dep cannot create a circular version +# requirement. Giving them a `version` would reintroduce the cycle. +# +# cargo-deny reports a path dep with no version as a WILDCARD, so without this +# it flags all 10 as banned -- every one of them a deliberate, load-bearing +# choice. `wildcards = "deny"` still applies to real (non-path) dependencies, +# which is the case worth banning. +allow-wildcard-paths = true highlight = "all" [sources]