Skip to content

chore: enforce dependency license allowlist via cargo-deny#499

Merged
avihut merged 2 commits into
masterfrom
daft-477/chore/dependency-license
May 15, 2026
Merged

chore: enforce dependency license allowlist via cargo-deny#499
avihut merged 2 commits into
masterfrom
daft-477/chore/dependency-license

Conversation

@avihut
Copy link
Copy Markdown
Owner

@avihut avihut commented May 15, 2026

Summary

  • Adds cargo-deny pinned through mise with a permissive license allowlist, RustSec advisory gating, and source-registry restriction. Enforced in CI on every PR that touches Cargo.toml, Cargo.lock, or deny.toml.
  • Mirrors the existing cargo-cooldown / .dep-age-allowlist supply-chain pattern: small dedicated tool + CI gate + allowlist with # why: rationale.
  • [bans] (duplicate-version detection) deferred to a follow-up — daft has natural duplicate transitive versions today (winnow, windows_*) that need curation before that gate can land cleanly.

Baseline curation

The initial run surfaced three real findings, all triaged in this PR:

  • BSL-1.0 (Boost Software License 1.0) on clipboard-win / error-code, transitive through arboardedtui. Added to the allowlist — permissive, OSI-approved, FSF Free.
  • RUSTSEC-2025-0141 (bincode unmaintained) — transitive through syntect. No safe upgrade exists; added to advisories.ignore with rationale. Revisit when syntect drops bincode 1.x.
  • RUSTSEC-2024-0320 (yaml-rust unmaintained) — same dependency chain. Revisit when syntect migrates to yaml-rust2.

Test plan

  • mise install fetches cargo-deny 0.19.4 through the cargo backend (covered by the existing 7-day minimum_release_age gate)
  • mise run deny passes locally: advisories ok, bans ok, licenses ok, sources ok
  • mise run fmt:check clean
  • mise run clippy zero warnings
  • mise run test:unit 1703 passed, 0 failed
  • CI: dep-license-check job appears and passes on this PR
  • CI: docs-only follow-up commit (if any) skips the new job via the lockfile path gate

Closes #477.

@avihut avihut added this to the Public Launch milestone May 15, 2026
@avihut avihut added the chore Maintenance tasks label May 15, 2026
@avihut avihut self-assigned this May 15, 2026
@avihut
Copy link
Copy Markdown
Owner Author

avihut commented May 15, 2026

/claude review

@claude
Copy link
Copy Markdown

claude Bot commented May 15, 2026

Claude finished @avihut's task in 2m 2s —— View job


PR Review: chore: enforce dependency license allowlist via cargo-deny

  • Gather context (read changed files)
  • Review deny.toml configuration
  • Review CI workflow changes (.github/workflows/test.yml)
  • Review mise.toml and mise.lock changes
  • Review mise-tasks/deny and mise-tasks/ci changes
  • Review docs/about/contributing.md changes
  • Final assessment and summary

This is a well-structured supply-chain gate with good rationale throughout. A few observations below, ordered by severity.


Minor issues

1. deny.toml in the lockfile bucket causes spurious dep-age-check runs

In .github/workflows/test.yml line 79, deny.toml is added to the lockfile regex:

(Cargo\.lock|bun\.lock|\.dep-age-allowlist|cooldown\.toml|bunfig\.toml|deny\.toml)

lockfile=true triggers both dep-age-check and dep-license-check. When someone edits only deny.toml (e.g., to add an advisory exception), dep-age-check spins up a runner and runs scripts/check-lockfile-age.sh against an unchanged Cargo.lock — wasted minutes. The straightforward fix is to add a separate deny output in the changes job (analogous to lockfile) and gate dep-license-check on it independently. Alternatively, gate dep-age-check only on the explicit lock-file names (Cargo.lock, bun.lock, .dep-age-allowlist, cooldown.toml, bunfig.toml) and put deny.toml only in a new group. This is minor since the dep-age check is cheap, but it's cleaner.

Fix this →

2. MPL-2.0 in the global allowlist without a named crate

deny.toml line 65 includes MPL-2.0 in the blanket allow list. MPL-2.0 is file-level copyleft rather than permissive (modifications to MPL files must be shared). The PR body doesn't identify a specific current dependency that requires it — if it was added defensively, consider removing it from the global list and using a named [licenses.exceptions] entry when a concrete dep actually needs it. This keeps the allowlist accurately documenting what's actually in the graph rather than what might theoretically appear.

3. all-features = false silently skips optional-dep licenses

deny.toml line 21. For a binary crate where you control feature selection, this is usually fine. Worth a brief comment explaining the tradeoff so future maintainers don't assume the check is exhaustive (# optional features are not checked; any --features flag that pulls in new crates requires a manual cargo deny --all-features check`).


Observations (not blocking)

CI job will be slow on first cache miss: dep-license-check installs cargo-deny via the cargo backend (source compile). With Swatinem/rust-cache@v2, subsequent runs should be fast, but cold runs will take several minutes. If that becomes a problem, the mise cargo backend supports binstall for pre-built binaries — not worth changing now, just worth noting.

cargo-deny pinned to "latest" in mise.toml: Consistent with the existing cargo-cooldown = "latest" pattern — the mise.lock entry (0.19.4) provides the actual pin, and minimum_release_age = "7d" gates upgrades. This is fine.

Advisory rationale quality is excellent: Both RUSTSEC-2025-0141 and RUSTSEC-2024-0320 entries have accurate descriptions (not-CVE, root cause, upstream dependency chain, and explicit revisit trigger). This is exactly the right standard for ignore entries.


Summary

The core implementation is solid: the [sources] config is tight, the multi-platform [graph] targets cover all release arches, the exceptions array is empty but documented with a worked example, mise run ci now includes the deny gate, and the contributing doc update gives contributors a clear path for adding exceptions. The only actionable items are the spurious dep-age-check trigger and the MPL-2.0 question — both are easy to address before merge if desired, but neither is a blocker.

avihut and others added 2 commits May 15, 2026 13:00
Adds cargo-deny pinned through mise with a permissive license allowlist,
RustSec advisory gating, and source-registry restriction. The same
"small dedicated tool + CI gate + allowlist with `# why:` rationale"
pattern as the existing cargo-cooldown / .dep-age-allowlist supply-chain
gate. [bans] (duplicate-version detection) is deferred to a follow-up;
the daft tree has natural duplicate transitive versions today (winnow,
windows_*) that need curation before that gate can land cleanly.

Initial baseline surfaced and curated three real findings: BSL-1.0
(Boost Software License) on clipboard-win/error-code transitive through
arboard → edtui (added to allowlist — permissive, OSI-approved), and
two `unmaintained` advisories on bincode (RUSTSEC-2025-0141) and
yaml-rust (RUSTSEC-2024-0320) reaching us through syntect with no safe
upgrade available (added to advisories.ignore with rationale; revisit
when syntect drops these deps).

Closes #477.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two follow-ups from the cargo-deny rollout review (PR #499):

- Move MPL-2.0 from the global allow list into per-crate exceptions.
  MPL-2.0 is file-level copyleft, materially different in posture from
  the permissive licenses in the global list. Two named entries today:
  nucleo-matcher (transitive through ratatui's fuzzy-matcher) and
  option-ext (transitive through `dirs`). Each carries a # why: rationale
  matching the project's .dep-age-allowlist discipline.

- Document the all-features = false scope. daft has no [features] table
  today so the setting is a no-op, but a future feature flag could pull
  in optional deps that this check would silently skip. Inline comment
  spells out the trigger for revisiting.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@avihut avihut force-pushed the daft-477/chore/dependency-license branch from bf9810f to 3317a4d Compare May 15, 2026 10:02
@avihut avihut merged commit c24c882 into master May 15, 2026
13 checks passed
@avihut avihut deleted the daft-477/chore/dependency-license branch May 15, 2026 11:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore Maintenance tasks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

chore: dependency license allowlist policy via cargo-deny

1 participant