Skip to content

chore: add cargo-deny + dependency-review + commitlint workflows#31

Merged
satyakwok merged 2 commits into
mainfrom
chore/add-supply-chain-hardening
May 13, 2026
Merged

chore: add cargo-deny + dependency-review + commitlint workflows#31
satyakwok merged 2 commits into
mainfrom
chore/add-supply-chain-hardening

Conversation

@satyakwok
Copy link
Copy Markdown
Member

@satyakwok satyakwok commented May 13, 2026

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

  • `deny.toml` — license allowlist + advisory yank-block + wildcard warning
  • `.github/workflows/cargo-deny.yml` — `cargo deny check` on PR + push
  • `.github/workflows/dependency-review.yml` — pre-merge diff-only license + vuln gate
  • `.github/workflows/commitlint.yml` + `.commitlintrc.json` — Conventional Commits enforce

`bans.multiple-versions = "warn"` (not `deny`) because the leptos + alloy ecosystems regularly need two majors during migration.

Test plan

  • PR check shows cargo-deny + dependency-review + commitlint green

Summary by CodeRabbit

  • Chores
    • Added commit message linting and configuration to enforce formatting rules
    • Added CI workflow to run commitlint on pull requests
    • Enabled dependency vulnerability and license scanning for PRs
    • Added Rust dependency auditing with configuration to enforce crate and license policies
    • Configured additional security and quality checks for repository maintenance

Review Change Stack

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.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 13, 2026

📝 Walkthrough

Walkthrough

This 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.

Changes

Code Quality and Security Gates

Layer / File(s) Summary
Commit message linting setup
.commitlintrc.json, .github/workflows/commitlint.yml
Commitlint configuration enforces a 100-character header limit, restricts commit types to conventional types (build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test), and disables body/footer max line length checks. Workflow runs on PRs to main with full commit history.
Cargo dependency security scanning
deny.toml, .github/workflows/cargo-deny.yml
cargo-deny policy enables full feature graph scanning, denies yanked crates/advisories (with explicit ignores), enforces an allowed-license set with confidence threshold, warns on configured bans, and denies unknown registry/git sources. Workflow runs on PRs, pushes to main, and workflow_dispatch.
GitHub dependency review automation
.github/workflows/dependency-review.yml
Dependency review workflow checks PR dependency diffs, fails on HIGH-severity vulnerabilities, enforces an allowlist of licenses with specific exceptions, and posts PR comment summaries on failures. Triggers on PRs targeting main.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

A rabbit builds walls made of rules so fine,
Commits must be clean, dependencies align,
No wandering packages, no unsafe supply,
Quality gates standing guard way up high! 🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: adding cargo-deny, dependency-review, and commitlint workflows for supply-chain hardening.
Description check ✅ Passed The description covers the required sections: Why (supply-chain hygiene rationale), What (detailed changes to each file), and Test plan (verification checklist), aligning well with the template structure.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/add-supply-chain-hardening

Comment @coderabbitai help to get the list of available commands and usage tips.

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.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
deny.toml (1)

9-17: ⚡ Quick win

Add 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 reason field 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

📥 Commits

Reviewing files that changed from the base of the PR and between 29427dd and 397b0d3.

📒 Files selected for processing (1)
  • deny.toml

Comment thread deny.toml
Comment on lines +22 to +41
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",
]
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# First, locate and examine the deny.toml file
find . -name "deny.toml" -type f

Repository: Sentriscloud/sentrix-explorer-v2

Length of output: 88


🏁 Script executed:

# Check the full deny.toml file to understand structure
cat deny.toml

Repository: 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 -5

Repository: 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 toml

Repository: 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.lock

Repository: 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 5

Repository: 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 10

Repository: 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.lock

Repository: 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 -20

Repository: 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:


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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@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.

@satyakwok satyakwok merged commit 3165b61 into main May 13, 2026
11 of 12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant