feat(cli): Implement report baseline comparison and suppression features - #324
Draft
misonijnik wants to merge 14 commits into
Draft
feat(cli): Implement report baseline comparison and suppression features#324misonijnik wants to merge 14 commits into
misonijnik wants to merge 14 commits into
Conversation
misonijnik
force-pushed
the
misonijnik/supressions
branch
from
July 30, 2026 11:17
82d35fc to
5cbbc0c
Compare
misonijnik
marked this pull request as draft
July 30, 2026 11:18
misonijnik
force-pushed
the
misonijnik/supressions
branch
from
July 30, 2026 21:25
5cbbc0c to
e8b01aa
Compare
Adds the report-level engine for baselines and suppressions: - identity.go: fingerprint-key resolution (source/sink hash by default), identity lookup and git-style prefix resolution - baseline.go: new/unchanged/updated/absent classification, baselineState and baselineGuid application, run GUID stamping - suppress.go: the read rule for suppression status, accept/defer/unsuppress, verbatim inheritance from a baseline, and summary counters - save.go: atomic report writing PropertyBag now preserves unknown keys as raw JSON. It previously modelled only "tags", so any read-modify-write of a report silently dropped the rest of every property bag — which the round-trip test caught.
internal/triage applies one pass of baseline inheritance, accept/defer decisions and baseline comparison over a report, and is the single implementation behind the triage command, scan's annotation step and summary's read-only view. Gate decides whether findings fail the build: suppressed findings never count, and with a baseline only new (or uncomparable) ones do. The summary grows Baseline and Suppressions subsections, rendered only when they apply, and the finding listing hides suppressed results unless asked for them.
- opentaint triage: compare a report against a baseline, record accept
("won't fix") and defer ("not fixing for now") decisions by fingerprint
prefix, and write the annotated report
- scan: --baseline, --baseline-state, --error-on-findings,
--error-on-severity, --fingerprint-key; the report the analyzer wrote is
rewritten only when triage actually changed it
- summary: --baseline, --baseline-state, --suppressed; runs the same engine
read-only so the file is never touched
Read-only mode still annotates the in-memory report, otherwise
--baseline-state could not filter on a state nobody had written.
Rule lists are scan-time rule selection, not suppression: an excluded rule never loads, so it produces nothing to suppress. The analyzer only supports inclusion, so exclusion is implemented by enumerating every rule id in the ruleset and subtracting, then re-expanding join refs so that excluding a library rule cannot silently break a rule that joins against it. Resolution happens before the --dry-run bail-out, so a list that selects nothing is reported by --dry-run rather than after a full compile. The --rule-id flag continues to win over the config file.
Adds the opentaint triage reference, the baseline/gating flags on scan and summary, a Baselines and suppressions section explaining that presence in a baseline is not acceptance, and the rules.only/rules.exclude configuration keys. Suggestion builders learn the new flags so rebuilt commands keep them.
- rename TestGateCountsUpdatedFindingsAsNew: the body asserts the opposite (updated findings do not trip the gate) - Gate.inScope reuses sarif.MatchesSeverity (exported) instead of re-implementing the case-insensitive level match - fingerprintValue delegates to Identity instead of duplicating the lookup - scan loads the baseline once, before compile, and passes it through to the triage step instead of reading the file a second time
Rule exclusion was config-only (rules.exclude); this adds the flag analogue on scan. It overrides the configured exclude list, and composes with --rule-id — both were asked for explicitly, so exclusion subtracts from the selection instead of one flag silently winning. Emptying the selection is an error either way, caught by --dry-run before any compile.
…matcher matchesPattern in rules/select.go had invented a fourth match form, globbing the bare leaf name, which summary's --rule-id filter does not support. Export the string-level matcher as sarif.MatchesRuleID and delegate rule selection (rules.only/rules.exclude, --exclude-rule-id) to it, so one grammar holds everywhere: exact full path.yaml:id, exact bare name, or a doublestar glob over the full id only. Docs examples updated off the removed leaf-glob form.
Verifying that --exclude-rule-id reaches the analyzer as concrete --semgrep-rule-id args surfaced a silence: excluding a typo'd rule id matched nothing and looked effective. Selection.Unmatched reports patterns that select no rule, and scan warns for each — on both the config-list path and the --rule-id/--exclude-rule-id flag path. The configuration example also used a rule id that does not exist in the shipped ruleset; replaced with a real one.
…-exclude
An exclusion-only selection lowers to just the excluded concrete ids, passed
via --semgrep-rule-id-exclude, instead of expanding into the ~150-rule
inclusion complement. rules.Select now returns Resolved{Include, Exclude};
the allow-list path keeps CLI-side subtraction and join-ref re-expansion,
since inclusion must be exact ids anyway. --rule-id composed with
--exclude-rule-id still subtracts CLI-side (tiny explicit lists).
Requires the analyzer's --semgrep-rule-id-exclude option (separate core
branch); older jars reject it, so exclusion fails fast until the analyzer
version is bumped.
… filter The single --baseline-state name carried two grammars: a boolean on scan/triage that persisted result.baselineState into the file, and a value list on summary that filtered the listing. Rename the scan/triage switch to --write-baseline-state (matching its WriteBaselineState field and its intent), leaving --baseline-state <state> exclusively as the summary filter. The filter help now spells out the accepted values (new | unchanged | updated | absent). No behavior change beyond the flag name; --error-on-severity is unchanged.
The flag validated each repeatable value as a single token, so the natural --error-on-severity error,warning was rejected with "invalid severity". Split each value on commas so the comma form and the repeated-flag form are equivalent. Purely CLI-side (the gate never reaches the analyzer); the docs already used the comma form, which now works.
A dedicated task-oriented guide for the new capabilities: the two-axis mental model (baseline state vs. suppression), the full lifecycle from establishing a baseline through triage inheritance to gating, and reference tables for baseline states, suppression statuses, fingerprint identity, the failure gate + exit codes, and rule selection. Includes copy-paste GitHub Actions (actions/cache to carry the baseline) and GitLab recipes, plus the SARIF 2.1.0 conformance notes. Linked from the docs index (Guides + CI/CD) and the usage guide, whose long inline section is trimmed to a concise pointer keeping the flag tables.
misonijnik
force-pushed
the
misonijnik/supressions
branch
from
August 1, 2026 21:33
e8b01aa to
4e8e975
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.