Skip to content

Fix Graphify audit findings - #414

Merged
panbanda merged 1 commit into
mainfrom
fix/graphify-audit-hardening
May 29, 2026
Merged

Fix Graphify audit findings#414
panbanda merged 1 commit into
mainfrom
fix/graphify-audit-hardening

Conversation

@panbanda

@panbanda panbanda commented May 28, 2026

Copy link
Copy Markdown
Owner

Summary

  • ran Graphify static extraction on the repo: 4,446 nodes, 7,548 links, 280 communities
  • fixed security/path correctness issues in MCP and semantic search indexing
  • fixed usability issue where CLI glob/exclude filters were parsed but ignored
  • fixed staff-maintainability issue where Rust impl methods inherited whole-impl complexity
  • added regression coverage for the fixed behavior
  • ignored Graphify-generated outputs so local graph artifacts stay out of git

Findings by lens

  • Security: MCP tool calls built AnalysisContext from the server root instead of the requested path; semantic indexing read relative paths from the process cwd.
  • Usability: analyzer --glob and --exclude flags did not scope most command output; search now uses the resolved repo path.
  • Staff: Rust method complexity could be inflated by returning impl_item before the actual method node.
  • Coverage: added red/green tests for CLI filters, MCP requested paths, semantic indexing root handling, and Rust impl method complexity.
  • Compliance: graphify-out/, GRAPH_REPORT.md, and root graph.json are ignored.

Verification

  • cargo fmt --check
  • cargo test
  • cargo clippy --all-targets --all-features -- -D warnings
  • git diff --check
  • git check-ignore -v graphify-out/ GRAPH_REPORT.md graph.json
  • uvx --from graphifyy graphify update .
  • uvx --from graphifyy graphify diagnose multigraph --json --graph graphify-out/graph.json

Summary by CodeRabbit

  • Bug Fixes

    • Improved path handling for multi-repository analysis scenarios
    • Enhanced semantic indexing to correctly identify files relative to repository roots
  • Refactor

    • Consolidated analyzer command dispatch for consistent filtering behavior across all analysis commands
  • Tests

    • Updated integration tests to validate JSON output structure
  • Chores

    • Added Graphify-generated artifacts to build configuration ignore list

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@panbanda, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 37 minutes. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, 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 include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ce8f04f1-0afd-4f0b-b8b8-d706f44777c0

📥 Commits

Reviewing files that changed from the base of the PR and between b2b73e7 and 1cc88b9.

📒 Files selected for processing (6)
  • .gitignore
  • src/analyzers/complexity.rs
  • src/main.rs
  • src/mcp/mod.rs
  • src/semantic/sync.rs
  • tests/integration_tests.rs
📝 Walkthrough

Walkthrough

CLI filtering arguments now propagate to all analyzers via a new filtered_file_set helper. Function detection in complexity analysis narrows to explicit function/method kinds. Path construction in semantic indexing uses root-relative paths consistently. Tool-invoked analyses use the requested directory as context root instead of server root.

Changes

Analyzer Dispatch and Path Resolution

Layer / File(s) Summary
Analyzer dispatch and filtering infrastructure
src/main.rs
run_analyzer now accepts optional AnalyzerArgs and uses a new filtered_file_set helper to apply glob/exclude filters. All command handlers (complexity, changes, flags, churn, score, search) route through this pattern.
Complexity analysis function detection
src/analyzers/complexity.rs
find_function_at_line filters AST nodes to only kinds containing "function" or "method". Test verifies methods in impl blocks are analyzed individually with appropriate complexity baselines.
Semantic index path construction
src/semantic/sync.rs
File indexing now derives paths relative to root_path via root_path.join(path) and path.to_string_lossy() instead of strip_prefix. Removal detection uses direct PathBuf lookup. Test confirms indexing respects the provided root.
Tool invocation path context
src/mcp/mod.rs
handle_tool_call uses tool-requested path as analysis root instead of server root_path. Test verifies complexity tool reads from the requested directory.
Filter output validation
tests/integration_tests.rs
Glob and exclude filter tests parse JSON output structure, extracting the files array and validating paths by extension instead of substring matching.
Gitignore update
.gitignore
Adds patterns for Graphify-generated artifacts.

Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error)

Check name Status Explanation Resolution
Pr Test Coverage & Quality Check ❌ Error Three new/modified functions in src/main.rs lack unit tests: run_analyzer(), filtered_file_set(), dispatch_analyzer(). Criterion 1.1 requires tests for every modified function. Add unit tests for run_analyzer, filtered_file_set, and dispatch_analyzer functions to verify filter application and dispatch logic.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title aligns with the main objective: fixing Graphify audit findings across multiple components including path correctness, usability, and maintainability issues.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/graphify-audit-hardening

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

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

@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown

Note

Unit test generation is a public access feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

@panbanda
panbanda force-pushed the fix/graphify-audit-hardening branch from 0f13828 to b2b73e7 Compare May 28, 2026 23:10
@panbanda
panbanda changed the base branch from chore/tree-sitter-upgrade to main May 28, 2026 23:10
@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown

✅ Created PR with unit tests: #415

@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown

Note

Unit test generation is a public access feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

@panbanda

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown

✅ Created PR with unit tests: #416

@panbanda

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
✅ Actions performed

Full review triggered.

@panbanda
panbanda force-pushed the fix/graphify-audit-hardening branch from b2b73e7 to ca449cb Compare May 28, 2026 23:25
@github-actions

github-actions Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Omen Analysis

Diff Risk

Risk Score 46%
Risk Level MEDIUM
Files Modified 6
Lines Added +259
Lines Deleted -49
Commits 2
Risk Factors
Factor Score
entropy 0.1039
lines_added 0.1036
file_churn 0.1
file_complexity 0.0356
num_files 0.032
lines_deleted 0.0196
commits 0.0140
ownership_diffusion 0
Recommendations
  • Touches historically volatile files - changes here often introduce bugs

Repository Health

Health Score 77.95594595606879 / 100
Grade C
Files Analyzed 101
Critical Issues 1
Score Components
Component Score Weight
complexity 93 1
duplication 42 0.8
cohesion 94.2 0.6
tdg 85.1 0.6
coupling 53.1 0.4
satd 91.1 0.4
smells 100 0.2
Tips for AI agents

Use these commands to investigate and improve low-scoring areas.

Run full analysis:

omen -f json score    # health score with component breakdown
omen -f json diff     # PR risk analysis
omen hotspot          # high-churn + high-complexity files

Coupling (score: 53.110891089108904) -- needs attention

omen graph && omen smells

Break cyclic dependencies by introducing interfaces or extracting shared types. Reduce fan-out from hub modules by splitting responsibilities.


Duplication (score: 41.962757623237316) -- needs attention

omen clones

Look for Type-1 (exact) and Type-2 (renamed) clones. Extract shared logic into reusable functions or modules. Prioritize clones in high-churn files.


General workflow for improving scores:

  1. Run the relevant analyzer command to identify specific files
  2. Focus on the highest-weight components first (complexity 25%, duplication 20%, cohesion 15%, TDG 15%)
  3. Make targeted improvements -- small refactors that reduce complexity or eliminate duplication
  4. Re-run omen score to verify improvement

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

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

73-96: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Path format: FileSet::files() is relative, so sync removal matching is consistent.

  • src/core/file_set.rs stores FileSet.files as owned.strip_prefix(root) and test_file_set_stores_relative_paths asserts every file_set.files() entry is path.is_relative(), so the PathBuf::from(indexed_path) vs current_files comparison at src/semantic/sync.rs is aligned on “relative vs absolute”.
  • Still ensure sync.rs strips indexed_path using the same root_path that FileSet uses when generating current_files.
🤖 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 `@src/semantic/sync.rs` around lines 73 - 96, The removal check compares
indexed_path (possibly absolute) to current_files (relative), so normalize
indexed_path the same way FileSet::files() does: derive a relative path by
stripping root_path (use root_path.strip_prefix or PathBuf::strip_prefix) and
compare that rel_indexed to current_files; still call
self.cache.remove_file(indexed_path) with the original indexed identifier when
removing and keep use of stats.removed and functions like check_file_changed and
current_files unchanged.
🧹 Nitpick comments (2)
.gitignore (1)

61-63: ⚡ Quick win

Anchor all patterns to root for consistency.

Only /graph.json is root-anchored. graphify-out/ and GRAPH_REPORT.md will match anywhere. Graphify generates at root; anchor all three.

📌 Root-anchor all patterns
-graphify-out/
-GRAPH_REPORT.md
+/graphify-out/
+/GRAPH_REPORT.md
 /graph.json
🤖 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 @.gitignore around lines 61 - 63, Update the .gitignore patterns so all
entries are anchored to the repository root: change the unanchored patterns
"graphify-out/" and "GRAPH_REPORT.md" to root-anchored equivalents (like
"/graphify-out/" and "/GRAPH_REPORT.md") to match the already-root-anchored
"/graph.json" and ensure these generated files are ignored only at the repo
root.
src/semantic/sync.rs (1)

451-457: ⚡ Quick win

Add a second sync() to lock incremental behavior.

One sync passes whether paths are relative or absolute. A re-sync would catch the rel_path mismatch described above (should report indexed == 0).

💚 Proposed addition
         assert_eq!(stats.checked, 1);
         assert_eq!(stats.indexed, 1);
         assert_eq!(stats.errors, 0);
         assert_eq!(cache.symbol_count().unwrap(), 1);
+
+        // Re-sync: nothing changed, so no file should be re-indexed.
+        let stats2 = sync.sync(&file_set, temp.path()).unwrap();
+        assert_eq!(stats2.checked, 1);
+        assert_eq!(stats2.indexed, 0);
+        assert_eq!(stats2.removed, 0);
     }
🤖 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 `@src/semantic/sync.rs` around lines 451 - 457, Add a second call to
sync.sync(...) after the first to exercise incremental re-sync behavior: call
sync.sync(&file_set, temp.path()) a second time, capture the returned stats, and
assert that the incremental run reports checked == 1, indexed == 0 (no
re-indexing due to rel_path mismatch), and errors == 0 while
cache.symbol_count() remains 1; this should follow the existing symbols
(sync.sync, file_set, temp.path(), stats.indexed, cache.symbol_count) so the
test fails if relative-vs-absolute rel_path handling is incorrect.
🤖 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.

Outside diff comments:
In `@src/semantic/sync.rs`:
- Around line 73-96: The removal check compares indexed_path (possibly absolute)
to current_files (relative), so normalize indexed_path the same way
FileSet::files() does: derive a relative path by stripping root_path (use
root_path.strip_prefix or PathBuf::strip_prefix) and compare that rel_indexed to
current_files; still call self.cache.remove_file(indexed_path) with the original
indexed identifier when removing and keep use of stats.removed and functions
like check_file_changed and current_files unchanged.

---

Nitpick comments:
In @.gitignore:
- Around line 61-63: Update the .gitignore patterns so all entries are anchored
to the repository root: change the unanchored patterns "graphify-out/" and
"GRAPH_REPORT.md" to root-anchored equivalents (like "/graphify-out/" and
"/GRAPH_REPORT.md") to match the already-root-anchored "/graph.json" and ensure
these generated files are ignored only at the repo root.

In `@src/semantic/sync.rs`:
- Around line 451-457: Add a second call to sync.sync(...) after the first to
exercise incremental re-sync behavior: call sync.sync(&file_set, temp.path()) a
second time, capture the returned stats, and assert that the incremental run
reports checked == 1, indexed == 0 (no re-indexing due to rel_path mismatch),
and errors == 0 while cache.symbol_count() remains 1; this should follow the
existing symbols (sync.sync, file_set, temp.path(), stats.indexed,
cache.symbol_count) so the test fails if relative-vs-absolute rel_path handling
is incorrect.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3c8b48ee-1e3c-4dcc-8fb3-66f03be640bf

📥 Commits

Reviewing files that changed from the base of the PR and between dfd0dfd and b2b73e7.

📒 Files selected for processing (6)
  • .gitignore
  • src/analyzers/complexity.rs
  • src/main.rs
  • src/mcp/mod.rs
  • src/semantic/sync.rs
  • tests/integration_tests.rs

@panbanda
panbanda force-pushed the fix/graphify-audit-hardening branch from ca449cb to 1cc88b9 Compare May 28, 2026 23:41
@panbanda
panbanda merged commit 4529430 into main May 29, 2026
7 of 8 checks passed
@panbanda
panbanda deleted the fix/graphify-audit-hardening branch May 29, 2026 00:20
@github-actions github-actions Bot mentioned this pull request May 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant