chore: add cargo-deny + dependency-review + commitlint workflows#31
Conversation
Mirrors the supply-chain hygiene already running on sentrix-labs/sentrix. Explorer-v2 is deployed as a public-facing WASM app — license + vuln gating on the dep tree matters because users trust the binary served from scan.sentriscloud.com. deny.toml: license allowlist + advisory yank-block. cargo-deny.yml: runs `cargo deny check` on PR + push to main. dependency-review.yml: pre-merge diff-only gate; license list mirrors deny.toml. commitlint.yml + .commitlintrc.json: Conventional Commits enforce. Bans `multiple-versions = warn` rather than `deny` because the leptos + alloy ecosystems regularly need two majors during migration.
📝 WalkthroughWalkthroughThis PR adds Commitlint configuration and a workflow to lint commit messages, a deny.toml policy and cargo-deny workflow to scan Rust dependencies, and a dependency-review workflow to check PR dependency changes and license compliance. All workflows run on pull requests targeting main; cargo-deny also runs on pushes and can be dispatched manually. ChangesCode Quality and Security Gates
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Two CI failures from the initial hardening PR: 1. `paste` (RUSTSEC-2024-0436) and `rustls-pemfile` (RUSTSEC-2025-0134) are unmaintained / deprecated advisories with no actual vulnerability. Add to ignore list mirroring indexer-rs + chain repo policy. 2. `xxhash-rust` (transitive via leptos's hashing layer) ships under BSL-1.0 (Boost Software License). Permissive, OSI-approved. Add to the license allowlist. Tested locally: `cargo deny --all-features check` → all four checks ok.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
deny.toml (1)
9-17: ⚡ Quick winAdd reason fields to advisory ignores for context and revalidation awareness.
Advisory ignores currently lack documentation. While cargo-deny does not support automatic expiration dates, adding a
reasonfield makes exceptions self-documenting and signals intent for periodic revalidation:ignore = [ { id = "RUSTSEC-2024-0436", reason = "paste is unmaintained but transitive via alloy/sqlx/prost with no known vulnerability. Mirrors ignores in indexer-rs and chain repo." }, { id = "RUSTSEC-2025-0134", reason = "rustls-pemfile is deprecated in favour of rustls-pki-types; transitive via reqwest → rustls. No vulnerability." }, ]This makes suppression rationale explicit for maintainers reviewing the configuration later.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@deny.toml` around lines 9 - 17, Update the deny.toml ignore entries to include structured reason metadata so each advisory ignore documents why it’s suppressed and signals revalidation intent; replace the plain string entries "RUSTSEC-2024-0436" and "RUSTSEC-2025-0134" with table entries that use id keys and a reason field (e.g., { id = "RUSTSEC-2024-0436", reason = "…" } and { id = "RUSTSEC-2025-0134", reason = "…" }) so maintainers can see context for the ignores.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@deny.toml`:
- Around line 22-41: The global licenses.allow list currently contains
"BUSL-1.1" which should be removed and instead added as a crate-scoped exception
using cargo-deny's exceptions; remove the "BUSL-1.1" entry from the allow array
and add an exceptions entry under the [licenses] section (exceptions = [ { crate
= "specific-crate-name", allow = ["BUSL-1.1"] } ]) targeting the exact crate(s)
that need BUSL-1.1 so the rest of the repo no longer globally allowlists that
restrictive license.
---
Nitpick comments:
In `@deny.toml`:
- Around line 9-17: Update the deny.toml ignore entries to include structured
reason metadata so each advisory ignore documents why it’s suppressed and
signals revalidation intent; replace the plain string entries
"RUSTSEC-2024-0436" and "RUSTSEC-2025-0134" with table entries that use id keys
and a reason field (e.g., { id = "RUSTSEC-2024-0436", reason = "…" } and { id =
"RUSTSEC-2025-0134", reason = "…" }) so maintainers can see context for the
ignores.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: f040dd75-8259-40a2-9ab4-e34797189c0f
📒 Files selected for processing (1)
deny.toml
| allow = [ | ||
| "MIT", | ||
| "Apache-2.0", | ||
| "Apache-2.0 WITH LLVM-exception", | ||
| "BSD-2-Clause", | ||
| "BSD-3-Clause", | ||
| "ISC", | ||
| "MPL-2.0", | ||
| "Unicode-DFS-2016", | ||
| "Unicode-3.0", | ||
| "CC0-1.0", | ||
| "Zlib", | ||
| "0BSD", | ||
| "BUSL-1.1", | ||
| # webpki-roots v1.x: CDLA-Permissive-2.0 (transitive via reqwest -> rustls). | ||
| "CDLA-Permissive-2.0", | ||
| # Boost Software License — permissive OSI-approved, transitive via | ||
| # xxhash-rust used by leptos's hashing layer. | ||
| "BSL-1.0", | ||
| ] |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, locate and examine the deny.toml file
find . -name "deny.toml" -type fRepository: Sentriscloud/sentrix-explorer-v2
Length of output: 88
🏁 Script executed:
# Check the full deny.toml file to understand structure
cat deny.tomlRepository: Sentriscloud/sentrix-explorer-v2
Length of output: 1551
🌐 Web query:
cargo-deny per-crate license exceptions allow
💡 Result:
cargo-deny does support per-crate license exceptions, and they’re configured under the [licenses] section via an exceptions array using crate selectors (PackageSpecs) so you can allow additional licenses for specific crates only (instead of allowing that license globally across the whole dependency graph). [1] Example (deny.toml or project exceptions file): exceptions = [ # This exception applies only to the specified crate (and optional version constraints) { crate = "inferno", allow = ["CDDL-1.0"] }, ] This is explicitly described as: the exceptions field “is meant to allow additional licenses only for particular crates” and uses PackageSpecs to select “the crate the exception applies to.” [1] Notes that matter for “allow”: - The general [licenses] allow list applies to the entire crate graph, meaning any license you allow there becomes permitted for any crate that matches the license checker (including crates that may introduce that license later). [1] - The exceptions mechanism exists to make those additional allowances more selective and avoid implicitly allowing licenses in future/unrelated dependency paths. [1]
Citations:
🏁 Script executed:
# Search for BUSL-1.1 references in lock files or dependencies
find . -name "Cargo.lock" -o -name "Cargo.toml" | head -5Repository: Sentriscloud/sentrix-explorer-v2
Length of output: 102
🏁 Script executed:
# Check for any crates or dependencies that might use BUSL-1.1
rg "BUSL" --type tomlRepository: Sentriscloud/sentrix-explorer-v2
Length of output: 134
🏁 Script executed:
# Check if there's a Cargo.lock file to see which crates use BUSL-1.1
head -100 Cargo.lockRepository: Sentriscloud/sentrix-explorer-v2
Length of output: 2650
🏁 Script executed:
# Search the full Cargo.lock for any BUSL-1.1 licensed dependencies
rg "license.*BUSL-1.1" Cargo.lock -A 5 -B 5Repository: Sentriscloud/sentrix-explorer-v2
Length of output: 58
🏁 Script executed:
# More comprehensive search for BUSL in Cargo.lock
rg -i "busl" Cargo.lock -A 10 -B 10Repository: Sentriscloud/sentrix-explorer-v2
Length of output: 58
🏁 Script executed:
# Check if there are actual crates with BUSL-1.1 in the lock file
wc -l Cargo.lockRepository: Sentriscloud/sentrix-explorer-v2
Length of output: 92
🏁 Script executed:
# Search for package names that might have BUSL-1.1
grep -n "^\[\[package\]\]" Cargo.lock | tail -20Repository: Sentriscloud/sentrix-explorer-v2
Length of output: 416
🌐 Web query:
cargo-deny project own license vs dependencies BUSL-1.1
💡 Result:
cargo-deny checks licenses for all crates in the dependency graph (dependencies and transitive deps), but does not check the project's own license specified in its Cargo.toml[1][2]. The licenses check (cargo deny check licenses) evaluates every crate's license expression against the deny.toml configuration to ensure acceptable terms[1][2][3]. BUSL-1.1 (Business Source License 1.1) is a valid SPDX identifier[4]. It is not OSI-approved or FSF Free/Libre[4][5], so with default allow-osi-fsf-free = "neither" and no explicit allow/deny, it falls to default = "deny" (implicitly rejected)[1][6][3][7]. To allow BUSL-1.1 in dependencies: - Add "BUSL-1.1" to [licenses].allow (allows everywhere)[3]. - Or use per-crate exceptions: exceptions = [ { allow = ["BUSL-1.1"], crate = "specific-crate" } ][8][9][3]. Examples: - wasmer-upstream allows BUSL-1.1 for specific crates like wasmer-compiler-singlepass[8]. - vouch-sh uses exception for its own vouch-server crate under BUSL-1.1 and clarifies the license file[9]. The project's own license is irrelevant to cargo-deny's licenses check; configure policies based on what deps are acceptable regardless of your project's license[10].
Citations:
- 1: https://docs.rs/crate/cargo-deny/0.4.1
- 2: https://embarkstudios.github.io/cargo-deny/checks/licenses/index.html
- 3: https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html
- 4: https://spdx.github.io/license-list-data/BUSL-1.1.html
- 5: https://en.wikipedia.org/wiki/Business_Source_License
- 6: https://crates.io/crates/cargo-deny/0.4.2
- 7: https://github.com/crate-ci/typos/blob/v1.20.10/deny.toml
- 8: https://github.com/OffchainLabs/wasmer-upstream/blob/main/deny.toml
- 9: https://github.com/vouch-sh/vouch/blob/v2026.3.15/deny.toml
- 10: https://sts10.github.io/2023/04/18/cargo-deny-licenses.html
Move BUSL-1.1 from global allow list to a crate-specific exception.
BUSL-1.1 is restrictive and non-OSI-approved. Keeping it globally allowlisted means any future BUSL-1.1 dependency automatically passes without review. Use cargo-deny's exceptions mechanism instead to scope this to specific crates only:
Example
[licenses]
allow = [
"MIT",
"Apache-2.0",
# ... other licenses ...
]
exceptions = [
{ crate = "specific-crate-name", allow = ["BUSL-1.1"] },
]This follows the pattern used by other projects (wasmer, vouch) for restrictive licenses and ensures each BUSL-1.1 dependency receives explicit evaluation.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@deny.toml` around lines 22 - 41, The global licenses.allow list currently
contains "BUSL-1.1" which should be removed and instead added as a crate-scoped
exception using cargo-deny's exceptions; remove the "BUSL-1.1" entry from the
allow array and add an exceptions entry under the [licenses] section (exceptions
= [ { crate = "specific-crate-name", allow = ["BUSL-1.1"] } ]) targeting the
exact crate(s) that need BUSL-1.1 so the rest of the repo no longer globally
allowlists that restrictive license.
There was a problem hiding this comment.
Skip — same forward-compat reasoning as sister comments on sdk-rs#22 + sentrix-grpc-wasm#16. Sentrix Chain workspace crates are all BUSL-1.1; if explorer-v2 ever adds a path-dep on a chain crate (currently only depends on sentrix-proto v0.1.1 from crates.io which is BUSL-1.1 already in tree) the allowlist needs BUSL-1.1. Acknowledging the per-crate exceptions mechanism would be more precise — defer until the dep tree stabilises post-migration.
There was a problem hiding this comment.
@satyakwok, understood — the global BUSL-1.1 allowlist is intentional given that Sentrix Chain workspace crates are all BUSL-1.1 and sentrix-proto v0.1.1 (already in tree) carries that license. Deferring the migration to per-crate exceptions until the dep tree stabilises post-migration makes sense. I'll note this context to avoid re-raising it in future reviews.
(ᵔᴥᵔ)
✏️ Learnings added
Learnt from: satyakwok
Repo: Sentriscloud/sentrix-explorer-v2 PR: 31
File: deny.toml:22-41
Timestamp: 2026-05-13T17:31:57.824Z
Learning: In the Sentriscloud/sentrix-explorer-v2 repository, `BUSL-1.1` is intentionally kept in the global `[licenses].allow` list in `deny.toml` because Sentrix Chain workspace crates are all licensed under BUSL-1.1, and `sentrix-proto v0.1.1` (from crates.io) — already a direct dependency — carries BUSL-1.1. The plan is to migrate to per-crate `exceptions` once the dependency tree stabilises post-migration. Do not flag BUSL-1.1 in the global allowlist as an issue in this repo. The same reasoning applies to sister repos sdk-rs and sentrix-grpc-wasm.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
Why
Mirrors the supply-chain hygiene already running on `sentrix-labs/sentrix`. Explorer-v2 is deployed as a public-facing WASM app at `scan.sentriscloud.com` — license + vuln gating on the dep tree matters because users trust the binary served from there.
Per the repo hardening matrix (`research/02_repo_hardening_matrix.md`), this is MEDIUM priority — `gitleaks` was already in place; this PR closes the remaining 3 supply-chain gaps.
What
`bans.multiple-versions = "warn"` (not `deny`) because the leptos + alloy ecosystems regularly need two majors during migration.
Test plan
Summary by CodeRabbit