Skip to content

fix(cli): diff-aware mode must not fall back to full scan on empty diff#712

Merged
shivasurya merged 3 commits into
mainfrom
shiva/diff-aware-handle-deletes
May 22, 2026
Merged

fix(cli): diff-aware mode must not fall back to full scan on empty diff#712
shivasurya merged 3 commits into
mainfrom
shiva/diff-aware-handle-deletes

Conversation

@shivasurya
Copy link
Copy Markdown
Owner

Summary

A delete-only PR was dumping every full-repo finding instead of the expected zero. Surfaced as 207 findings on #693, which only deletes one YAML workflow file. Compare with #692 — same shape (single YAML change) but an addition — which correctly returned 0 findings.

Two paired bugs:

  1. diff/git_provider.go ran git diff --name-only --diff-filter=ACMR, excluding deletions. A delete-only PR therefore produced changedFiles=[].
  2. cmd/ci.go guarded the filter with diffEnabled && len(changedFiles) > 0. When the list was empty, the filter was skipped entirely and ALL full-scan findings were returned. The same guard was on the filesScanned count, so the JSON also claimed the whole repo was scanned.

Fix

  • ACMRACMRD. Deletions show up in changedFiles. A delete-only PR now returns the deleted path, distinguishing it from a genuinely empty PR.
  • Drop the len(changedFiles) > 0 guard at both call sites in cmd/ci.go. If diff-aware is requested, honour it: an empty intersection returns zero findings, not "full repo." The two states (diff-aware on, nothing matched vs diff-aware off, scan everything) must stay separable.

Test plan

  • Updated TestGitDiffProvider_DeletedFileExcludedTestGitDiffProvider_DeletedFileIncluded. The contract change is named in the test.
  • New TestGitDiffProvider_DeletionOnlyPR covering the exact PR chore(ci): remove self-scan workflow, superseded by hosted scanner #693 shape (one workflow file deleted, nothing else).
  • go test ./diff/... ./cmd/... passes.
  • go vet, golangci-lint: clean.
  • Coverage on diff package: 91.5% (GetChangedFiles 100%, diffFiles 72.7% — unchanged baseline; error-path branches are timeout-only).
  • End-to-end: deploying the rebuilt scanner image to the production runner immediately after opening this PR. Will re-trigger the PR chore(ci): remove self-scan workflow, superseded by hosted scanner #693 scan and confirm it now returns 0 findings.

Docs

CLAUDE.md gains a Diff-Aware Scanning section documenting the new contract — including the explicit "do not reintroduce the full-scan fallback" rule — so this regression can't sneak back in.

Two paired bugs caused a delete-only PR to dump every full-repo finding
instead of the expected zero. Surfaced as 207 findings on PR #693, which
only deletes one YAML workflow file.

The wire: pathfinder ci computes changedFiles via git diff, then filters
scan results to that set when diff-aware is on. Both halves were broken:

1. diff/git_provider.go ran `git diff --diff-filter=ACMR`, excluding
   deletions. A delete-only PR therefore produced changedFiles=[].

2. cmd/ci.go guarded the filter with `diffEnabled && len(changedFiles) > 0`.
   When the list was empty, the filter was skipped entirely and ALL
   full-scan findings were returned. The same guard was on the filesScanned
   count, so the report also claimed "scanned full repo."

Fix:

- ACMR -> ACMRD so deletions show up in changedFiles. A delete-only PR
  now returns the deleted path, distinguishing it from an empty PR.
- Drop the `len(changedFiles) > 0` guard at both call sites. If
  diff-aware is on, honour it: an empty intersection returns zero
  findings, not "full repo." The two states (diff-aware on, nothing
  matched vs diff-aware off, scan everything) must stay separable.

Updated the existing TestGitDiffProvider_DeletedFileExcluded test (now
TestGitDiffProvider_DeletedFileIncluded) and added a deletion-only
regression covering exactly the PR #693 shape.

CLAUDE.md gains a "Diff-Aware Scanning" section documenting the new
contract so future maintainers don't reintroduce the fallback.
@shivasurya shivasurya added bug Something isn't working go Pull requests that update go code labels May 22, 2026
@shivasurya shivasurya self-assigned this May 22, 2026
@shivasurya shivasurya added the go Pull requests that update go code label May 22, 2026
@safedep
Copy link
Copy Markdown

safedep Bot commented May 22, 2026

SafeDep Report Summary

Green Malicious Packages Badge Green Vulnerable Packages Badge Green Risky License Badge

No dependency changes detected. Nothing to scan.

View complete scan results →

This report is generated by SafeDep Github App

@github-actions
Copy link
Copy Markdown

Code Pathfinder Security Scan

Pass Critical High Medium Low Info

No security issues detected.

Metric Value
Files Scanned 4
Rules 205

Powered by Code Pathfinder

@code-pathfinder
Copy link
Copy Markdown

code-pathfinder Bot commented May 22, 2026

Pathfinder Report

No security findings on the changed files. This pull request is clean.

View report on the dashboard


Powered by Code Pathfinder.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 22, 2026

Codecov Report

❌ Patch coverage is 77.27273% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.54%. Comparing base (8a39ca7) to head (810f8d0).

Files with missing lines Patch % Lines
sast-engine/cmd/scan.go 0.00% 4 Missing ⚠️
sast-engine/cmd/ci.go 88.88% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #712      +/-   ##
==========================================
+ Coverage   85.52%   85.54%   +0.02%     
==========================================
  Files         190      191       +1     
  Lines       27467    27467              
==========================================
+ Hits        23492    23498       +6     
+ Misses       3083     3079       -4     
+ Partials      892      890       -2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…tput.DiffFilter

Codecov caught that the two diff-filter call-site changes in PR #712
weren't directly unit-tested (33% patch coverage). Pulling the gate
logic into a named helper makes both branches testable as pure
functions and exposes a deeper instance of the same bug.

Changes:

- cmd/diff_filter.go: new applyDiffFilter + countScannedFiles
  helpers. applyDiffFilter is the single source of truth for "if
  diff-aware is on, run the filter; an empty changedFiles list is a
  valid input that yields zero detections, NOT a pass-through."
- cmd/ci.go, cmd/scan.go: both call sites switched to applyDiffFilter.
  cmd/scan.go previously had the same `diffAware && len(changedFiles) > 0`
  guard as cmd/ci.go — same regression risk, fixed here too.
- output/filter.go: removed the `if len(f.changedFiles) == 0 { return
  detections }` short-circuit in both Filter and FilteredCount. That
  was the deeper instance of the bug: even after fixing the cmd-layer
  guard, output.NewDiffFilter([]).Filter(d) would still pass d
  through, defeating the cmd-layer fix for genuinely empty diffs.
  Callers that want "no filtering" must skip Filter entirely (which
  applyDiffFilter now enforces via the diffEnabled gate).
- output/filter_test.go: flipped two test cases that hard-coded the
  buggy pass-through behaviour to assert the new contract.
- cmd/diff_filter_test.go: 10 tests covering every branch of both
  helpers (100% function coverage).

go vet, golangci-lint: 0 issues.
@shivasurya shivasurya merged commit a7e137f into main May 22, 2026
6 of 7 checks passed
@shivasurya shivasurya deleted the shiva/diff-aware-handle-deletes branch May 22, 2026 02:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working go Pull requests that update go code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant