gruff-rs
gruff-rs is an opinionated quality analyzer for Rust projects. It scans Rust source, Cargo metadata, and common project files, then emits deterministic reports for terminals, CI annotations, SARIF consumers, static HTML, and a local dashboard. It is heuristic static analysis; run it beside Clippy, cargo audit, rustfmt, tests, and code review, not instead of them.
Status At A Glance
| Field | Value |
|---|---|
| Release line | Published 0.1.1 package line |
| Runtime | Prebuilt binary, or Rust 1.82+ when building from source |
| Package | gruff-rs on crates.io |
| Binary | gruff-rs |
| Rule catalogue | 80 rules across 11 pillars |
| Primary config | .gruff-rs.yaml |
| Analysis schema | gruff.analysis.v1 |
| Baseline schema | gruff.baseline.v1 |
| Severity gate | --fail-on with none, advisory, warning, error |
| Dashboard | 127.0.0.1:8766 by default |
Rule IDs, fingerprints, baseline identity, JSON schema version, and SARIF behavior are compatibility-sensitive inside the 0.1.x line.
Requirements
- No Rust toolchain is needed when using a prebuilt binary through
cargo-binstall. - Rust
1.82+is required when building from source with Cargo. - Git is not used by default; Git-backed diff mode requires explicit
--diff-git-unsafe.
Install
Install into a repository-local tool directory:
Prebuilt binary, also into a repository-local tool directory:
From a source checkout:
Quick Start
# Create a starter config.
# Review the current finding mix.
# Explore without failing because of findings.
# Gate on warning and error findings.
# Emit SARIF for code scanning.
# Generate a fresh-start baseline.
Commands
| Command | Purpose |
|---|---|
analyse [paths...] |
Run the analyzer and print findings. |
summary [paths...] |
Print compact score, pillar, rule, and file summaries. |
report [paths...] |
Render an HTML or JSON report to stdout or --output. |
init |
Generate a starter .gruff-rs.yaml. |
list-rules |
Print rule metadata as text or JSON, optionally filtered by selector. |
dashboard |
Serve the local browser dashboard. |
completion [shell] |
Print a shell completion script. |
Output Formats
analyse --format <fmt> accepts:
| Format | Use it for |
|---|---|
text |
Human terminal output. |
json |
Full gruff.analysis.v1 report. |
sarif |
SARIF 2.1.0 for code scanning. |
html |
Self-contained inspection report. |
markdown |
Pull-request or issue comment summary. |
github |
GitHub Actions workflow annotations. |
hotspot |
gruff.hotspot.v1 file-offender JSON. |
report --format <fmt> accepts html and json.
Exit Codes
| Code | Meaning |
|---|---|
0 |
Run completed and no finding met --fail-on. |
1 |
At least one finding met --fail-on. |
2 |
Fatal diagnostic such as config failure, missing path, parse error, baseline error, diff failure, or invalid input. |
analyse defaults to --fail-on error.
CI Usage
Generic CI command:
The repo ships a composite GitHub Action:
jobs:
gruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: blundergoat/gruff-rs@v0.1.1
with:
args: analyse . --format sarif --fail-on warning --no-baseline
The action installs the matching binary via cargo-binstall and runs gruff-rs with the supplied args. Pin to a tag for reproducibility. See action.yml for inputs.
Configuration
gruff-rs reads .gruff-rs.yaml by default. Use --config <path> to pass another YAML file, or --no-config to ignore project config. Unknown keys, unknown rule IDs, unknown selectors, and invalid threshold shapes fail closed.
paths:
ignore:
- target/**
- fixtures/**
allowlists:
acceptedAbbreviations:
secretPreviews:
rules:
select:
ignore:
complexity.cognitive:
threshold: 15
severity: warning
security.process-command:
severity: error
exclude:
- rule: security.process-command
paths:
message_contains: "Command::new"
reason: "test-only synthetic command"
Selectors can target exact rule IDs, dotted prefixes such as security.*, or public pillars such as Security.
Rules And Pillars
The v0.1 catalogue contains 80 rules:
| Pillar | Rules |
|---|---|
complexity |
5 |
dead-code |
3 |
design |
4 |
documentation |
11 |
maintainability |
12 |
modernisation |
6 |
naming |
5 |
security |
14 |
sensitive-data |
9 |
size |
3 |
test-quality |
8 |
Use ./.cargo-tools/bin/gruff-rs list-rules --format json for the exact rule metadata. See Rules for rule families, limits, and deferred checks.
Custom Rules
Top-level custom_rules entries register config-only regex rules under the reserved custom.<slug> namespace. They can be selected with exact IDs, custom.*, or their public pillar, and they use the normal fingerprint formula.
custom_rules:
- id: custom.no-hack-comment
pillar: Documentation
severity: warning
message: HACK comment marker
scope: comments
pattern: '(?m)^[ \t]*//[ \t]*HACK\b'
Custom rules are intentionally regex-only in 0.1.x; AST patterns, plugins, scripts, external runtimes, and Semgrep-style metavariables are out of scope.
Baselines And Changed-Code Scans
Baselines suppress reviewed findings by exact fingerprint, rule ID, and file path:
Patch diff filtering treats a unified diff as data and does not execute Git:
Pass --diff-patch - to read a patch from stdin. The older Git-backed --diff <mode> path is available only with --diff-git-unsafe.
Dashboard
The dashboard renders HTML reports on demand. It has no authentication and must not be exposed to untrusted networks; keep the default loopback bind unless the environment is trusted.
In polyglot repositories, gruff-rs defaults to port 8766 while gruff-go, gruff-php, and gruff-py default to 8765; use --port when running multiple dashboards at the same time.
Trust Boundary
Default scans are source-only and local-only. gruff-rs does not execute target code, run Cargo build scripts, call Git unless an unsafe Git diff mode is explicitly requested, query registries, read vulnerability feeds, or run benchmarks. Dependency checks read Cargo.toml and Cargo.lock as data. Candidate wording means the analyzer found a deterministic static signal, not type-aware or runtime certainty.
Stability Contract
0.1.x is the "mostly stable, with caveats" line. Rule IDs, finding fingerprints, baseline identity, JSON schema version gruff.analysis.v1, SARIF rendering, and CLI exit semantics are compatibility-sensitive. Breaking changes to those surfaces ship as 0.2.0, not inside 0.1.x. See UPGRADING.md for the full contract.
How It Compares
| Tool | Relationship |
|---|---|
| Clippy | Canonical Rust lint pass. gruff-rs adds deterministic reports, baselines, scoring, project-level rules, and SARIF. Run both. |
cargo audit / cargo deny |
Vulnerability and dependency policy tools. gruff-rs does not query advisory feeds. |
| rustfmt | Formatting only. gruff-rs does not format code. |
| rust-analyzer | IDE language server. gruff-rs is a CI/CLI gate with stable fingerprints and reports. |
| Tests and review | Still required; gruff findings are static review prompts, not runtime proof. |
Development
scripts/preflight-checks.sh runs formatting, Clippy, unit tests, rule listing, JSON and SARIF fixture scans, patch-input diff smoke tests, selector/exclusion/custom-rule smokes, and a dogfood scan of src/.
Documentation
Author
Built by Matthew Hansen.
License
Licensed under either of: