Modes¶
sarifix has five modes. They run the same pipeline and differ only in what triggers them, which findings they look at, and where the result goes.
Report and issues modes are shipped
report and issues work today. local, pr and review arrive in phases 2 to 4 of the roadmap; asking for one now exits with an error naming its phase. Their sections describe the design so you can see where the project is heading.
| Mode | Trigger | Publishes | Typical use | Phase |
|---|---|---|---|---|
report |
Anything | Enriched SARIF and a JSON summary. No edits. | Dry runs, triage, metrics | 1 |
issues |
A scan of the default branch | One GitHub issue per batch, for a person or an agent queue to fix | Backlog burn-down with Claude in Actions | 1 |
local |
CLI or an agent hook | Edits in your working tree. No git operations. | Laptop use, Claude Code hooks | 2 |
pr |
A scan of the default branch | One PR per rule batch | Backlog burn-down, migrations, CVE response | 3 |
review |
A scan of a pull request | Suggested-change comments on that PR | PR assist | 4 |
report¶
Writes no code. It runs ingest, fingerprint, filter and group, then writes two files to --out-dir (default sarifix-report/):
sarifix.sarif: every input run, unchanged except that each finding gets aproperties.sarifixblock with its status (batched,deferredorskipped), the skip reason, its batch and the branch a fix would use. It validates against the SARIF 2.1.0 schema, so code scanning and other SARIF viewers still read it.summary.json: counts by status and skip reason, and the batches in the order a run would attempt them.
$ sarifix fix --mode report --sarif 'sarif/*.sarif'
...
✓ sarifix-report/sarifix.sarif
✓ sarifix-report/summary.json
A deferred finding from that run carries:
"properties": {
"sarifix": {
"status": "deferred",
"scanner": "checkov",
"ruleKey": "checkov/CKV_AWS_24",
"batch": "checkov/CKV_AWS_24",
"branch": "sarifix/checkov/ckv_aws_24",
"fingerprint": "fcadca11a498b6d6f0a7012e1e3081fc:1"
}
}
Use it to see what sarifix would do before you let it do anything, and to feed dashboards. sarifix plan shows the same batches without writing files.
Skip reasons¶
Checks run in this order, and a finding gets the first reason that applies:
| Reason | Meaning |
|---|---|
unrouted |
No scanner's match covers the SARIF tool name. Kept in the report, never fixable. |
no_location |
No file location inside the repo. |
in_baseline |
Also in the --baseline scan, so not new. |
below_min_level |
Level is under rules.min_level. |
rule_denied |
Matches rules.deny. |
rule_not_allowed |
Not in rules.allow and not in a campaign. |
path_denied |
The file matches paths.deny (which always includes .github/workflows/**). |
not_selected |
Excluded by --rule or --campaign. |
issues¶
Writes no code either. It plans batches exactly as report mode does, then keeps one open GitHub issue per batch, in the agent-ready format of the task-queue plugin: the findings with links to their lines, acceptance criteria, the commands that prove a fix, and what is out of scope.
$ sarifix fix --mode issues --sarif 'sarif/*.sarif' --queue 1
✓ opened #1 checkov/CKV_TF_1
✓ opened #2 checkov/CKV2_AWS_6
...
✓ queued #1 checkov/CKV_TF_1
Each run opens issues for the most severe batches up to publish.issues.max_open, refreshes an issue whose findings changed (unless it's labeled agent-working), closes an issue whose batch is no longer reported, and labels the most severe open issues publish.issues.queue_label until publish.issues.queue are queued or in progress. Issues are matched to batches by a hidden <!-- sarifix-batch: ... --> marker, and sarifix never touches an issue without both the marker and publish.issues.label. An issue is closed only when its scanner's SARIF was part of the run, so a scanner that failed or was left out doesn't make its batches look fixed; sarifix warns about each configured scanner it got no SARIF from.
It needs a token that can write issues (GITHUB_TOKEN, else GH_TOKEN) and the repository (GITHUB_REPOSITORY, or --github-repo). Links use GITHUB_SERVER_URL and GITHUB_SHA when set, else github.com and the checkout's HEAD. --dry-run prints what would change without writing. Turn findings into issues Claude works through sets it up in GitHub Actions.
local¶
Runs the full fix and verify loop and leaves verified edits in your working tree, then prints a summary. It never commits or pushes. A Claude Code PostToolUse hook can call it with --baseline so an agent cleans up the findings it just introduced.
pr¶
Runs on pushes to the default branch only, never on fork pull requests. Each verified batch becomes a branch, a commit with a conventional message and a pull request. The PR body lists each finding, the one-line rationale per finding, before and after counts from verification, the test results and a hidden marker used to avoid duplicates on re-runs. Reviewers come from CODEOWNERS. sarifix never auto-merges.
review¶
Takes the baseline diff between the pull request and its merge base, so only findings the PR introduced are considered. Fixes for lines inside the PR diff come back as GitHub suggested changes the author can accept. A fix that spans lines outside the diff becomes a summary comment. On fork PRs it posts suggestions only and never runs with a write token against fork code.
What every mode shares¶
- Findings come from SARIF through the fingerprint pipeline.
- Nothing is published until a rescan and your own
verify.commandspass. .github/workflows/**is never edited. See Security.