Documentation
¶
Overview ¶
Package diffanalysis ports src/sec_af/diff_analysis.py — the diff-aware file selection SEC-AF uses in PR mode.
The orchestrator builds one DiffAnalysis per run when the audit input is a PR (`is_pr` with a `base_commit_sha`) and feeds AllRelevantFiles to the hunt phase as `include_paths`, so the set of files this package computes decides what the hunters look at.
self.diff_analysis = analyze_diff(
str(self.repo_path), input.base_commit_sha, input.commit_sha or "HEAD",
)
Everything here shells out to git and swallows failures the way Python does: a git that cannot be started, or that takes longer than 30 seconds, yields an EMPTY analysis (for the diff) or is skipped (for a blast-radius grep). A git that runs and exits non-zero is NOT a failure — Python passes check=False, so the (usually empty) stdout is used as-is.
Index ¶
Constants ¶
const DefaultHeadSHA = "HEAD"
DefaultHeadSHA is the value Python's `head_sha` parameter defaults to:
def analyze_diff(repo_path: str, base_sha: str, head_sha: str = "HEAD")
Go has no default arguments, so callers pass it explicitly. The only production caller (orchestrator.py) always supplies `input.commit_sha or "HEAD"`, i.e. this constant whenever the input carries no commit.
Variables ¶
This section is empty.
Functions ¶
func FileToModule ¶
FileToModule converts a file path to the importable module name used for the blast-radius grep.
Ports diff_analysis.py _file_to_module. Exported for the same reason as IsScannable.
Python parity — the three branches are literal transliterations, quirks included (VERIFIED against the venv interpreter):
"src/service/user.py" -> "user" (dots, drop ".py", last segment)
"src/service/user.test.py" -> "test" (same, so an infix dot wins)
"foo..py" -> "" (empty last segment; callers skip it)
"a.js.ts" -> "a" (".ts" stripped, then ".js")
"a.ts.js" -> "a.ts" (".ts" does not match, ".js" does)
"a/b.tar.gz" -> "b" (fallback: basename up to first dot)
"a/.hidden" -> "" (fallback on a dotfile)
func IsScannable ¶
IsScannable reports whether a file should be included in security scanning.
Ports diff_analysis.py _is_scannable. Exported because the orchestrator's PR-mode path and the hunt include_paths plumbing want the same predicate; Python keeps it private only because the module is self-contained.
Python parity, two quirks worth stating out loud:
- The directory test is str.startswith, NOT a path-segment containment test. "src/tests/x.py" is scannable; only a TOP-LEVEL tests/ dir is skipped. ("atests/x.py" is likewise scannable — the prefix is "tests/", with the slash.)
- The extension test is str.endswith and therefore case-sensitive: "a.lock" is skipped, "a.LOCK" is not.
Types ¶
type DiffAnalysis ¶
type DiffAnalysis struct {
ChangedFiles []string `json:"changed_files"`
BlastRadiusFiles []string `json:"blast_radius_files"`
AllRelevantFiles []string `json:"all_relevant_files"`
BaseSHA string `json:"base_sha"`
HeadSHA string `json:"head_sha"`
}
DiffAnalysis is the result of analyzing the git diff between base and head.
Ports the diff_analysis.py dataclass of the same name. The three list fields have `field(default_factory=list)`, so the zero value of a Go DiffAnalysis (nil slices) is NOT the Python default — use NewDiffAnalysis, which every constructor path in this package does, so the slices are always non-nil and marshal as `[]` rather than `null`.
func AnalyzeDiff ¶
func AnalyzeDiff(ctx context.Context, repoPath, baseSHA, headSHA string) DiffAnalysis
AnalyzeDiff analyzes the git diff to find changed files and their blast radius.
Ports src/sec_af/diff_analysis.py analyze_diff. Blast radius = files that import from, or are imported by, changed files — approximated by grepping the head tree for each changed file's module name.
Never returns an error: every git failure degrades to an empty or partial result, exactly as the Python function does.
func NewDiffAnalysis ¶
func NewDiffAnalysis() DiffAnalysis
NewDiffAnalysis returns the dataclass defaults: three empty lists, base_sha "" and head_sha "HEAD".
func (DiffAnalysis) FileCount ¶
func (d DiffAnalysis) FileCount() int
FileCount ports the `file_count` property: the number of files the hunters will actually be pointed at.