Skip to content

Release cargo-bless 0.1.1 with code audit#22

Merged
Ruffian-L merged 1 commit intomainfrom
release/0.1.1-code-audit
May 1, 2026
Merged

Release cargo-bless 0.1.1 with code audit#22
Ruffian-L merged 1 commit intomainfrom
release/0.1.1-code-audit

Conversation

@Ruffian-L
Copy link
Copy Markdown
Owner

Summary

  • Add the bullshit detector static Rust code audit with tree-sitter string/comment filtering
  • Add audit-only, diff-only, verbose, JSON, and policy suppression flows
  • Exclude the copied old detector crate from git/package output

Verification

  • cargo fmt
  • cargo test
  • cargo run --bin cargo-bless -- bless --offline
  • cargo run --bin cargo-bless -- bs --diff
  • cargo publish --dry-run

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 1, 2026

Warning

Rate limit exceeded

@Ruffian-L has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 35 minutes and 30 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 264b9d15-30c2-49e1-a2af-d80ce403e9eb

📥 Commits

Reviewing files that changed from the base of the PR and between e1f8ff9 and 79ad343.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • tests/fixtures/old-rust-project/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (21)
  • .coderabbit.yaml
  • .github/workflows/ci.yml
  • .gitignore
  • Cargo.toml
  • README.md
  • data/suggestions.json
  • src/cli.rs
  • src/code_audit.rs
  • src/fix.rs
  • src/intel.rs
  • src/lib.rs
  • src/main.rs
  • src/output.rs
  • src/parser.rs
  • src/policy.rs
  • src/suggestions.rs
  • src/updater.rs
  • tests/fixtures/old-rust-project/Cargo.toml
  • tests/fixtures/old-rust-project/src/main.rs
  • tests/integration.rs
  • tests/real_project_test.rs

Walkthrough

This pull request introduces a comprehensive code-audit system to cargo-bless that scans Rust projects for suspicious patterns and structural issues. A new code-audit module uses tree-sitter for parsing and detects patterns like Arc, excessive unwrap calls, and complexity heuristics. CLI support includes a dedicated bs subcommand and audit flags integrated into the bless command. A policy file system enables configurable suppressions and suggestion filtering. New dependencies, integration tests, and output rendering complete the feature.

Changes

Cohort / File(s) Summary
Project Configuration
.gitignore, Cargo.toml
Added excluded directories (.firecrawl/, bullshitdetector/, .agents/) and new dependencies (regex, tree-sitter, tree-sitter-rust) with toml_edit serde feature enabled.
Code Audit Core
src/code_audit.rs, src/policy.rs
New code-audit module detecting suspicious Rust patterns via regex and tree-sitter with suppression/config support; new policy module loading bless.toml for suggestion filtering and settings.
CLI & Entry Points
src/cli.rs, src/main.rs
Added Bs subcommand and CodeAuditOpts struct; BlessOpts extended with audit flags; main.rs integrates policy loading, code-audit scanning, and JSON report generation.
Dependency Processing
src/fix.rs, src/parser.rs
fix.rs adds cargo check validation and expands across dev/build dependencies; parser.rs splits features into enabled_features and available_features and refactors dependency extraction logic.
Suggestion Analysis
src/suggestions.rs, src/updater.rs
suggestions.rs reformatted signature and updated tests for new ResolvedDep fields; updater.rs formatting and test fixture adjustments.
Output & Library
src/output.rs, src/lib.rs
New code-audit report rendering and unified JsonReport structure; lib.rs exports new code_audit and policy modules.
Integration Tests
tests/integration.rs, tests/real_project_test.rs
Comprehensive end-to-end tests for bless/bs subcommands, audit modes, JSON output, policy suppression, and git diff filtering; real-project tests validate against ripgrep codebase.
Test Fixtures & Documentation
tests/fixtures/old-rust-project/..., README.md, data/suggestions.json
New fixture project demonstrating legacy crate patterns; README documents code-audit feature, CLI flags, and policy file configuration; suggestions.json adds 12 new modernization patterns.

Sequence Diagram

sequenceDiagram
    participant CLI as CLI Entry Point
    participant Policy as Policy Loader
    participant Audit as Code Audit Scanner
    participant Parser as Tree-Sitter Parser
    participant Output as Output Renderer

    CLI->>Policy: Load policy from bless.toml/path
    Policy-->>CLI: CodeAuditConfig (suppressions/settings)
    
    CLI->>Audit: scan_project(manifest_path, config)
    Audit->>Parser: Parse Rust files with tree-sitter
    Parser-->>Audit: AST + masked comments/strings
    Audit->>Audit: Detect patterns (Arc<RwLock>, unwrap, etc.)
    Audit->>Audit: Filter alerts by config & dedup
    Audit-->>CLI: CodeAuditReport (alerts by kind)
    
    CLI->>Output: render_code_audit_report(report)
    Output-->>CLI: Terminal output with heat score & findings
    
    alt JSON mode
        CLI->>Output: render_json_report(suggestions, audit)
        Output-->>CLI: Unified JSON {dependency_suggestions, code_audit}
    end
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 Hop-hop, found the bugs that hide,
Arc and Mutex on the side,
Unwraps and clones that stack so high,
The auditor's eye catches every sigh!
A bless for code that's crisp and clean,

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and clearly summarizes the main change: releasing version 0.1.1 with a code audit feature.
Description check ✅ Passed The description is directly related to the changeset, detailing the code audit implementation, new flows, and exclusions added in this release.
Docstring Coverage ✅ Passed Docstring coverage is 91.26% which is sufficient. The required threshold is 80.00%.
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 release/0.1.1-code-audit

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 35 minutes and 30 seconds.

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

@Ruffian-L Ruffian-L force-pushed the release/0.1.1-code-audit branch from e1f8ff9 to e69311f Compare May 1, 2026 04:48
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: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main.rs (1)

155-169: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Wire --fail-on into the exit path.

BlessOpts.fail_on is parsed and documented, but nothing in this command checks it before returning Ok(()). cargo bless --fail-on=high will still exit 0 even when matching findings are present.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main.rs` around lines 155 - 169, The command currently returns Ok(())
without considering opts.fail_on; add a check before the final Ok(()) that
evaluates whether any findings meet the threshold specified by opts.fail_on (for
code audit results in report when run_code_audit is true, and for lint/format
suggestions in suggestions), and if so return an error or non-zero exit (e.g.,
propagate a failure Result) so cargo bless exits non‑zero when matching findings
are present; locate the check near the end of main where report, suggestions,
run_code_audit, and opts are in scope and use opts.fail_on to decide the exit
outcome.
🧹 Nitpick comments (1)
tests/real_project_test.rs (1)

155-170: ⚡ Quick win

Make the JSON contract test fail on non-JSON output.

The fallback branch explicitly passes when --json prints arbitrary text, so regressions in the JSON path won't be caught. Since this PR wires --json in src/main.rs, this test should always parse stdout after the command succeeds.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/real_project_test.rs` around lines 155 - 170, The test currently allows
non-JSON text when "--json" is used; change it so any non-empty stdout must be
valid JSON by removing the fallback pass and always attempting to parse the
output. In tests/real_project_test.rs, after calling run_bless(&project_dir,
&["--json"]) on the output variable, call
serde_json::from_str::<serde_json::Value>(trimmed) and expect a successful parse
(i.e., fail the test if parsing errors) instead of only checking
trimmed.starts_with('{') or '[' and returning early; ensure the assertion
triggers whenever the command succeeds and stdout is non-empty so regressions in
the JSON path are caught.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@data/suggestions.json`:
- Around line 123-127: The mapping that replaces "proc-macro-error" with
"thiserror" is incorrect; update the suggestions.json entry for the object with
"pattern": "proc-macro-error" (currently "replacement": "thiserror", "kind":
"ModernAlternative") so it either (A) uses a correct compile-time diagnostic
alternative such as "proc-macro-error2" (or leaves replacement empty/null) and
adjusts "reason" to explain that proc-macro diagnostics require compile-time
APIs, or (B) remove the mapping entirely; ensure you modify the "replacement",
"kind", and "reason" fields for the entry referencing "proc-macro-error" rather
than introducing runtime-error crates like "thiserror".

In `@src/cli.rs`:
- Around line 41-47: Add a parse-time rejection for contradictory flags by
marking the two fields as conflicting in the CLI derive: annotate the audit_code
and no_audit_code fields with clap conflict attributes (e.g. add
#[arg(conflicts_with = "no_audit_code")] to the audit_code field and/or
#[arg(conflicts_with = "audit_code")] to the no_audit_code field) so the parser
will error if both --audit-code and --no-audit-code are passed; alternatively,
implement an early validation after parsing that checks opts.audit_code &&
opts.no_audit_code and returns a parse error—refer to the audit_code and
no_audit_code fields in the CLI struct to locate where to add this
check/attribute.

In `@src/code_audit.rs`:
- Around line 121-145: When diff_filter is set, we should skip files not in the
diff before reading and scanning to avoid full-workspace costs and inflated
files_scanned; modify the loop over files so that after the
is_ignored_path(file, config) check you test the diff_filter and skip the file
early if it is not part of the diff (i.e., call the appropriate include-check on
diff_filter for the current file path before fs::read_to_string), then only call
scan_code(&code, file, config) and increment the count that becomes
files_scanned for files you actually read/scan; keep existing behavior of
filtering alerts with filter.includes(alert) but ensure files_scanned reflects
only scanned files.

In `@src/fix.rs`:
- Around line 221-231: The current loop over
["dependencies","dev-dependencies","build-dependencies"] removes the crate and
returns on the first hit (using deps.remove(crate_name) and early return),
leaving other occurrences untouched; change the logic in the removal helper to
iterate all sections, call deps.remove(crate_name) for each, collect which
sections were modified (e.g., into a Vec<String>), and after the loop return a
single success message listing all modified sections (or bail if none were
removed); apply the same fix to the analogous helper mentioned at lines 237-248
so both functions remove the crate from every matching section instead of
stopping at the first.
- Around line 267-301: The code removes extra_crate from the manifest before
verifying main_crate exists, which can leave a partial edit; modify
apply_feature_opt() to first locate both crates (search doc for main_crate and
extra_crate across the sections array) and only perform the mutation if
main_crate is found, or if you prefer minimal change: record the removed
entry/value when you remove extra_crate and defer committing it—so if you later
fail to find main_crate, restore the removed entry into the same deps table;
reference the existing symbols doc, sections, extra_crate, main_crate,
extra_removed_section and use add_feature_to_dep only after confirming
main_crate exists (or after successfully committing both removal and
feature-add).
- Around line 144-179: The cargo check post-write currently only prints warnings
but doesn't signal failure to the caller, so make the cargo check result cause
the fix operation to fail: in the cargo check block in src/fix.rs (the
check_status match using check_status) return an Err (or propagate a non-ok
Result) when Ok(s) where s.success() is false or when Err(e) occurs, instead of
just printing a warning; ensure the apply() caller in src/main.rs receives that
error and causes the process to exit non-zero (or have apply() return a Result
that main treats as failure).

In `@src/main.rs`:
- Around line 20-23: The CLI scope flags (--workspace, --package, --all-targets)
are currently ignored because calls always pass only manifest; update the calls
to cargo_bless::parser::get_deps and cargo_bless::parser::scan_project (and any
other parser invocations around the opts.json branch and the other noted
locations) to forward the resolved scope from the CLI (e.g. fields on opts such
as workspace, package, all_targets) so the parser receives the intended scope;
adjust the argument list or construct a scope/config struct and pass it into
get_deps(manifest, scope) and scan_project(manifest, scope, ...), and update
cargo_bless::parser signatures if needed to accept and honor these scope flags.

In `@src/parser.rs`:
- Around line 80-86: The variable named `enabled_features` in `get_deps` (where
`MetadataCommand::features(CargoOpt::AllFeatures)` is used) is misleading
because it represents features from an all-features build; rename it to
something explicit like `all_features_build` or `features_with_all_enabled`,
update its documentation to state it reflects the all-features resolved plan
(not defaults), and adjust any other occurrences (including the similar block
around lines 132-140) to use the new name and docstring; ensure references to
`resolve.nodes[].features` and any downstream logic treating these as "actually
enabled in the resolved build" are updated to clarify the all-features context.

In `@src/policy.rs`:
- Around line 107-110: Change load_policy so it returns a Result<Option<Policy>,
E> instead of swallowing all errors into None: call fs::read_to_string(path) and
match the Err case to return Err unless the io::Error.kind() is NotFound (in
which case return Ok(None)); then call toml_edit::de::from_str(&content) and
return Err on parse errors (do not map them to None). Update the function
signature (load_policy) and callers accordingly and prefer a concrete error type
(or anyhow/Box<dyn Error>) so read and TOML deserialization failures are
propagated while only missing files produce Ok(None).
- Around line 123-126: The filter currently uses substring matching
(s.current.contains(p)) which erroneously suppresses packages by partial
matches; update the check in the filter closure that references
policy.ignore_packages and s.current to compare package names exactly by
splitting s.current on '+' (the same tokenization used elsewhere) and returning
false only if any token == p, i.e. perform an exact-name match against each
ignore_packages entry instead of contains.

In `@tests/fixtures/old-rust-project/src/main.rs`:
- Around line 6-10: The lazy_static! block has an invalid `static ref`
declaration for CONFIG; change the declaration inside lazy_static! so it uses
the correct syntax `static ref CONFIG: String = EXPR;` (i.e., add the `=` and
terminating `;`) and assign the initializer `"default_config".to_string()` to
CONFIG; locate the lazy_static! macro and the `static ref CONFIG: String` symbol
to update the declaration accordingly.

In `@tests/real_project_test.rs`:
- Around line 13-40: The test uses a brittle hardcoded bless_bin path and
ignores command exit status; replace bless_bin() to return
PathBuf::from(env!("CARGO_BIN_EXE_cargo-bless")) (or inline that env! call in
run_bless) and modify run_bless(project_dir, args) to check the Command output
status (output.status.success()) and panic or assert with output.stderr/stdout
on failure so tests fail on non-zero exit instead of silently returning stdout.

---

Outside diff comments:
In `@src/main.rs`:
- Around line 155-169: The command currently returns Ok(()) without considering
opts.fail_on; add a check before the final Ok(()) that evaluates whether any
findings meet the threshold specified by opts.fail_on (for code audit results in
report when run_code_audit is true, and for lint/format suggestions in
suggestions), and if so return an error or non-zero exit (e.g., propagate a
failure Result) so cargo bless exits non‑zero when matching findings are
present; locate the check near the end of main where report, suggestions,
run_code_audit, and opts are in scope and use opts.fail_on to decide the exit
outcome.

---

Nitpick comments:
In `@tests/real_project_test.rs`:
- Around line 155-170: The test currently allows non-JSON text when "--json" is
used; change it so any non-empty stdout must be valid JSON by removing the
fallback pass and always attempting to parse the output. In
tests/real_project_test.rs, after calling run_bless(&project_dir, &["--json"])
on the output variable, call serde_json::from_str::<serde_json::Value>(trimmed)
and expect a successful parse (i.e., fail the test if parsing errors) instead of
only checking trimmed.starts_with('{') or '[' and returning early; ensure the
assertion triggers whenever the command succeeds and stdout is non-empty so
regressions in the JSON path are caught.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ab1a038a-aa4a-4645-96f6-4e120d4f2db6

📥 Commits

Reviewing files that changed from the base of the PR and between 1d6d73c and e1f8ff9.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • tests/fixtures/old-rust-project/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (18)
  • .gitignore
  • Cargo.toml
  • README.md
  • data/suggestions.json
  • src/cli.rs
  • src/code_audit.rs
  • src/fix.rs
  • src/lib.rs
  • src/main.rs
  • src/output.rs
  • src/parser.rs
  • src/policy.rs
  • src/suggestions.rs
  • src/updater.rs
  • tests/fixtures/old-rust-project/Cargo.toml
  • tests/fixtures/old-rust-project/src/main.rs
  • tests/integration.rs
  • tests/real_project_test.rs

Comment thread data/suggestions.json
Comment thread src/cli.rs
Comment thread src/code_audit.rs
Comment thread src/fix.rs
Comment thread src/fix.rs
Comment thread src/parser.rs
Comment thread src/policy.rs
Comment thread src/policy.rs
Comment thread tests/fixtures/old-rust-project/src/main.rs
Comment thread tests/real_project_test.rs
@Ruffian-L Ruffian-L force-pushed the release/0.1.1-code-audit branch 2 times, most recently from b51eef1 to cf789a8 Compare May 1, 2026 04:59
@Ruffian-L Ruffian-L force-pushed the release/0.1.1-code-audit branch from cf789a8 to 79ad343 Compare May 1, 2026 05:10
@Ruffian-L Ruffian-L merged commit 178404e into main May 1, 2026
3 checks passed
@Ruffian-L Ruffian-L deleted the release/0.1.1-code-audit branch May 1, 2026 05:13
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