ci: enforce the crate map with cargo-deny and a closure-ban script #174

Merged
natsukium merged 2 commits from ci/deny-crate-map into main 2026-10-18 23:11:34 +09:00
Owner

The library crates get published from v0.3.0 (#160). crates/felis-protocol/tests/crate_purity.rs and crates/felis-grid/tests/no_render_deps.rs ran cargo tree over the workspace from a crate's own tests, so they would ship in the published package and fail outside the workspace. This moves every dependency rule into repository tooling and, on the way, makes the whole crate map tool-enforced instead of "review enforces the rest".

  • deny.toml encodes the "Depends on" column. Each felis library crate gets a wrappers entry listing exactly the crates allowed to depend on it directly, so a new felis→felis edge fails cargo deny until the map and deny.toml change together. Plus swash only under felis-shaping (next to #171's wgpu/winit). Dev parents are listed after a # dev marker: [graph] exclude-dev would also drop dev dependencies from the license and advisory checks. [graph] all-features = true so optional edges are judged too.
  • tools/dep_bans.py encodes the "MUST NOT depend on" column over each crate's closure (cargo tree --edges normal,build --target all --all-features), for what wrappers cannot express (e.g. felis-protocol's OS-crate ban: libc, rustix, windows-sys have dozens of external parents). With --self-test; run by just deny (already in pr.yml/release.yml) and just selftest.
  • Every entry of both deleted tests' ban lists is still caught (same edge/target flags, now with --all-features); newly enforced: tokio in vt/grid, OS crates in vt, felis-crate bans for pty/transport, render crates for daemon, swash/wgpu/winit closures for client-core/cli/shaping/render-core/render-wgpu.
  • Verified by deliberate violations, each reverted: grid→shaping fails both checks; protocol + libc, and protocol + cfg(windows) windows-sys, fail the script.
  • Docs: workspace.md enforcement paragraph, testing.md, security-audits.md, overview.md ("Rejected workspace shapes": a dependency ban written as a test in its own crate), test-strategy skill, READMEs, CONTRIBUTING.

Known gap, stated in workspace.md: a crate already listed as a dev parent that promotes the edge to a normal dependency passes cargo deny; the script catches it only when the target is in that crate's MUST NOT cell. Not caught today: client-core/cli → daemon or pty, daemon → client-core. Closing it means adding those to the MUST NOT cells, a normative change left out of this PR.

Verified: just check green locally; sol review PASS (round 2; round 1's finding fixed in the second commit).

The library crates get published from v0.3.0 (#160). `crates/felis-protocol/tests/crate_purity.rs` and `crates/felis-grid/tests/no_render_deps.rs` ran `cargo tree` over the workspace from a crate's own tests, so they would ship in the published package and fail outside the workspace. This moves every dependency rule into repository tooling and, on the way, makes the whole crate map tool-enforced instead of "review enforces the rest". - **`deny.toml` encodes the "Depends on" column.** Each felis library crate gets a `wrappers` entry listing exactly the crates allowed to depend on it directly, so a new felis→felis edge fails `cargo deny` until the map and `deny.toml` change together. Plus `swash` only under felis-shaping (next to #171's `wgpu`/`winit`). Dev parents are listed after a `# dev` marker: `[graph] exclude-dev` would also drop dev dependencies from the license and advisory checks. `[graph] all-features = true` so optional edges are judged too. - **`tools/dep_bans.py` encodes the "MUST NOT depend on" column** over each crate's closure (`cargo tree --edges normal,build --target all --all-features`), for what `wrappers` cannot express (e.g. felis-protocol's OS-crate ban: libc, rustix, windows-sys have dozens of external parents). With `--self-test`; run by `just deny` (already in pr.yml/release.yml) and `just selftest`. - Every entry of both deleted tests' ban lists is still caught (same edge/target flags, now with `--all-features`); newly enforced: tokio in vt/grid, OS crates in vt, felis-crate bans for pty/transport, render crates for daemon, swash/wgpu/winit closures for client-core/cli/shaping/render-core/render-wgpu. - Verified by deliberate violations, each reverted: grid→shaping fails both checks; protocol + `libc`, and protocol + `cfg(windows)` `windows-sys`, fail the script. - Docs: workspace.md enforcement paragraph, testing.md, security-audits.md, overview.md ("Rejected workspace shapes": a dependency ban written as a test in its own crate), test-strategy skill, READMEs, CONTRIBUTING. **Known gap, stated in workspace.md:** a crate already listed as a dev parent that promotes the edge to a normal dependency passes `cargo deny`; the script catches it only when the target is in that crate's MUST NOT cell. Not caught today: client-core/cli → daemon or pty, daemon → client-core. Closing it means adding those to the MUST NOT cells, a normative change left out of this PR. Verified: `just check` green locally; sol review PASS (round 2; round 1's finding fixed in the second commit).
The felis-protocol and felis-grid dependency bans ran as tests in the
crates' own tests/, shelling out to cargo tree. Once those crates are
published, the tests ship in the package and check repository policy
wherever a packager runs them; the bans now run from the repository root
under just deny, which CI already runs.

deny.toml encodes the "Depends on" column as wrappers, so a felis->felis
edge the map does not list fails cargo deny. Dev parents are listed in the
wrappers under a marker: cargo-deny's graph has dev edges and its only way
to drop them, graph.exclude-dev, would also drop dev dependencies from the
license and advisory checks. tools/dep_bans.py covers the transitive
"MUST NOT depend on" bans that wrappers cannot express.
ci: run cargo-deny over every feature
Some checks failed
fuzz / cargo fuzz nightly long-run (pull_request) Has been skipped
darwin / detect relevant changes (pull_request) Successful in 9s
darwin / darwin docs-only no-op (pull_request) Has been skipped
windows / detect relevant changes (pull_request) Successful in 15s
windows / windows docs-only no-op (pull_request) Has been skipped
bench / instruction-count regression gate (pull_request) Successful in 1m20s
darwin / build felis (aarch64-darwin) (pull_request) Successful in 1m13s
fuzz / cargo fuzz smoke (per target) (pull_request) Successful in 55s
pr / nix flake check (pull_request) Successful in 52s
windows / cargo nextest (Windows) (pull_request) Successful in 3m16s
pr / wire schema is compatible with the base (pull_request) Successful in 4s
pr / frontend smoke (x86_64-linux) (pull_request) Successful in 29s
windows / frontend smoke (Windows) (pull_request) Successful in 1m20s
windows / cargo clippy (Windows cross) (pull_request) Successful in 15s
pr / cargo build / clippy / test / deny (pull_request) Has been cancelled
73df197db7
The crate-map wrappers judge direct edges only in the graph cargo-deny
builds, which left optional dependencies out: an unlisted parent could
reach a felis crate behind a non-default feature. dep_bans.py already
checks closures with --all-features; the deny graph now matches.
natsukium force-pushed ci/deny-crate-map from 73df197db7
Some checks failed
fuzz / cargo fuzz nightly long-run (pull_request) Has been skipped
darwin / detect relevant changes (pull_request) Successful in 9s
darwin / darwin docs-only no-op (pull_request) Has been skipped
windows / detect relevant changes (pull_request) Successful in 15s
windows / windows docs-only no-op (pull_request) Has been skipped
bench / instruction-count regression gate (pull_request) Successful in 1m20s
darwin / build felis (aarch64-darwin) (pull_request) Successful in 1m13s
fuzz / cargo fuzz smoke (per target) (pull_request) Successful in 55s
pr / nix flake check (pull_request) Successful in 52s
windows / cargo nextest (Windows) (pull_request) Successful in 3m16s
pr / wire schema is compatible with the base (pull_request) Successful in 4s
pr / frontend smoke (x86_64-linux) (pull_request) Successful in 29s
windows / frontend smoke (Windows) (pull_request) Successful in 1m20s
windows / cargo clippy (Windows cross) (pull_request) Successful in 15s
pr / cargo build / clippy / test / deny (pull_request) Has been cancelled
to e41b54cf32
Some checks failed
fuzz / cargo fuzz nightly long-run (pull_request) Has been skipped
darwin / detect relevant changes (pull_request) Successful in 11s
darwin / darwin docs-only no-op (pull_request) Has been skipped
darwin / build felis (aarch64-darwin) (pull_request) Successful in 1m12s
windows / detect relevant changes (pull_request) Successful in 8s
windows / windows docs-only no-op (pull_request) Has been skipped
bench / instruction-count regression gate (pull_request) Has been cancelled
fuzz / cargo fuzz smoke (per target) (pull_request) Has been cancelled
pr / nix flake check (pull_request) Has been cancelled
pr / cargo build / clippy / test / deny (pull_request) Has been cancelled
pr / wire schema is compatible with the base (pull_request) Has been cancelled
pr / frontend smoke (x86_64-linux) (pull_request) Has been cancelled
windows / cargo clippy (Windows cross) (pull_request) Has been cancelled
windows / frontend smoke (Windows) (pull_request) Has been cancelled
windows / cargo nextest (Windows) (pull_request) Has been cancelled
2026-10-18 22:50:15 +09:00
Compare
natsukium force-pushed ci/deny-crate-map from e41b54cf32
Some checks failed
fuzz / cargo fuzz nightly long-run (pull_request) Has been skipped
darwin / detect relevant changes (pull_request) Successful in 11s
darwin / darwin docs-only no-op (pull_request) Has been skipped
darwin / build felis (aarch64-darwin) (pull_request) Successful in 1m12s
windows / detect relevant changes (pull_request) Successful in 8s
windows / windows docs-only no-op (pull_request) Has been skipped
bench / instruction-count regression gate (pull_request) Has been cancelled
fuzz / cargo fuzz smoke (per target) (pull_request) Has been cancelled
pr / nix flake check (pull_request) Has been cancelled
pr / cargo build / clippy / test / deny (pull_request) Has been cancelled
pr / wire schema is compatible with the base (pull_request) Has been cancelled
pr / frontend smoke (x86_64-linux) (pull_request) Has been cancelled
windows / cargo clippy (Windows cross) (pull_request) Has been cancelled
windows / frontend smoke (Windows) (pull_request) Has been cancelled
windows / cargo nextest (Windows) (pull_request) Has been cancelled
to 416a63805e
Some checks failed
fuzz / cargo fuzz nightly long-run (pull_request) Has been skipped
darwin / detect relevant changes (pull_request) Successful in 10s
darwin / darwin docs-only no-op (pull_request) Has been skipped
bench / instruction-count regression gate (pull_request) Has been cancelled
fuzz / cargo fuzz smoke (per target) (pull_request) Has been cancelled
darwin / build felis (aarch64-darwin) (pull_request) Has been cancelled
pr / nix flake check (pull_request) Has been cancelled
pr / cargo build / clippy / test / deny (pull_request) Has been cancelled
pr / wire schema is compatible with the base (pull_request) Has been cancelled
pr / frontend smoke (x86_64-linux) (pull_request) Has been cancelled
windows / detect relevant changes (pull_request) Has been cancelled
windows / cargo clippy (Windows cross) (pull_request) Has been cancelled
windows / cargo nextest (Windows) (pull_request) Has been cancelled
windows / frontend smoke (Windows) (pull_request) Has been cancelled
windows / windows docs-only no-op (pull_request) Has been cancelled
2026-10-18 22:59:08 +09:00
Compare
natsukium force-pushed ci/deny-crate-map from 416a63805e
Some checks failed
fuzz / cargo fuzz nightly long-run (pull_request) Has been skipped
darwin / detect relevant changes (pull_request) Successful in 10s
darwin / darwin docs-only no-op (pull_request) Has been skipped
bench / instruction-count regression gate (pull_request) Has been cancelled
fuzz / cargo fuzz smoke (per target) (pull_request) Has been cancelled
darwin / build felis (aarch64-darwin) (pull_request) Has been cancelled
pr / nix flake check (pull_request) Has been cancelled
pr / cargo build / clippy / test / deny (pull_request) Has been cancelled
pr / wire schema is compatible with the base (pull_request) Has been cancelled
pr / frontend smoke (x86_64-linux) (pull_request) Has been cancelled
windows / detect relevant changes (pull_request) Has been cancelled
windows / cargo clippy (Windows cross) (pull_request) Has been cancelled
windows / cargo nextest (Windows) (pull_request) Has been cancelled
windows / frontend smoke (Windows) (pull_request) Has been cancelled
windows / windows docs-only no-op (pull_request) Has been cancelled
to d1f60cd8ff
All checks were successful
fuzz / cargo fuzz nightly long-run (pull_request) Has been skipped
darwin / detect relevant changes (pull_request) Successful in 10s
darwin / darwin docs-only no-op (pull_request) Has been skipped
darwin / build felis (aarch64-darwin) (pull_request) Successful in 1m13s
bench / instruction-count regression gate (pull_request) Successful in 1m6s
fuzz / cargo fuzz smoke (per target) (pull_request) Successful in 51s
pr / nix flake check (pull_request) Successful in 38s
pr / cargo build / clippy / test / deny (pull_request) Successful in 1m36s
pr / wire schema is compatible with the base (pull_request) Successful in 3s
pr / frontend smoke (x86_64-linux) (pull_request) Successful in 38s
windows / cargo clippy (Windows cross) (pull_request) Successful in 15s
windows / detect relevant changes (pull_request) Successful in 8s
windows / windows docs-only no-op (pull_request) Has been skipped
windows / cargo nextest (Windows) (pull_request) Successful in 4m37s
windows / frontend smoke (Windows) (pull_request) Successful in 1m0s
2026-10-18 22:59:20 +09:00
Compare
natsukium scheduled this pull request to auto merge when all checks succeed 2026-10-18 23:06:28 +09:00
natsukium deleted branch ci/deny-crate-map 2026-10-18 23:11:35 +09:00
Sign in to join this conversation.
No reviewers
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
felis-terminal/felis!174
No description provided.