Skip to content

Baselines and Provenance

Wes Key edited this page Sep 14, 2026 · 1 revision

A single run knows what is wrong now. A baseline tells it what was wrong last time, so it can say which findings are new, how long the rest have been there, and which have gone.

Using a baseline

Keep each run's SARIF report, and pass the previous one in:

tf-snag -check all -plan plan.json -plan-log plan.jsonl \
  -baseline prev/tf-snag.sarif -format sarif > tf-snag.sarif

The tf-snag@0 pipeline task does this for you: it publishes each run's reports as the tf-snag artifact, and the next run downloads it. See Azure DevOps Pipelines.

A missing baseline file is fine. Every finding then reads as new.

What it adds

tf-snag matches findings on their stable guid and marks each one:

State Meaning
new not in the previous run
updated also in the previous run, whether or not its details changed
absent in the previous run, gone now: the drift was fixed or the deprecation resolved. SARIF only

Every finding also gets a first seen time, carried forward from the previous run or set to now for a new one. It is accurate from the second baselined run on, since the first has no earlier time to carry.

With -run-url, the URL of the run that first found each finding is carried forward too, so a long-standing finding still links back to the run that caught it.

Where it shows

Surface Shows
tf-snag run tab a new badge, or first seen with its age
SARIF / Scans tab baselineState, provenance.firstDetectionTimeUtc, and a (first seen <date>, <n> days ago) note on the message, since that tab has no age column
JSON baseline_state and first_seen on each finding
Teams card new findings first with a New badge. The rest show their age
Work items -ado-raise new raises only for new findings
Exceptions register how long each suppressed finding has been there

Why there is no unchanged. The Azure DevOps Scans tab's default Baseline filter shows new, updated and absent. An unchanged result would vanish from view while the drift was still live, so everything carried over is updated.

Without -baseline, SARIF leaves baselineState and provenance unset and the Scans tab shows every row as new.

No longer ignored

Removing an ignore rule brings its finding back. It is badged No longer ignored rather than new, and keeps its real first-seen date: the tracking is new, the drift is not. It still counts as new for -teams-notify new and -ado-raise new, because it was invisible yesterday and is actionable today.

Clone this wiki locally