Repository navigation
Output Formats
Choose a format with -format. Every format goes to stdout, so redirect it to a file in a pipeline.
| Format | For |
|---|---|
text (default) |
people, and the console log. Coloured with -color
|
json |
the tf-snag run tab in Azure DevOps, or your own tooling |
markdown |
a section on the pipeline run's Summary tab (##vso[task.uploadsummary]) |
sarif |
the SARIF SAST Scans Tab extension, and the baseline for the next run |
junit |
the built-in Tests tab (PublishTestResults@2). Drift only |
teams |
the Microsoft Teams card, printed instead of posted, to inspect or diff it |
To produce several formats, run tf-snag once per format with -exit-code=false, then once more for the console and the exit code.
The report carries a schema version, currently 3: drift, deprecations, retirements and pending changes, ignore-rule suppression, per-finding file and line with -source, and with -baseline a baseline_state (new or updated) and first_seen timestamp on every finding. Findings tracked by a work item carry work_item and work_item_url.
Schema 3 added retirements — one object per catalogue entry, with its retires_on, urgency, days and the instances it matched — and retirement_catalogue, which says where the catalogue came from and how old it is. Both are present only when -check retirements ran. See Retirements.
JSON lists live findings only. Absent ones appear in SARIF.
Drift is one result per resource under the rule resource-drift. The message leads with the kind:
| Scans tab column | From | e.g. |
|---|---|---|
| severity icon | level |
⛔ delete or create · ⚠ update |
| Result | message |
Deleted — name=kv01 · Updated — tags.Owner: null → "Wes"
|
| Path |
physicalLocation, needs -source
|
terraform/modules/kv/main.tf |
| Baseline | baselineState |
see Baselines and Provenance |
One changed attribute stays on the first line; two or more get a line each. Without a -source match, the Path is the resource address as plain text.
Deprecations are one result per distinct notice under the rule deprecation: summary on line one, detail on line two, then one address (file:line) line per location. The first location is the result's location, the rest are relatedLocations. The Scans tab shows the two rules as collapsible groups, ordered by result count.
Stable identity. Every result carries a deterministic guid (a UUID v5 of the finding's kind and identity) and a partialFingerprints entry (driftAddress/v1 or deprecation/v1). A finding keeps its guid from run to run, which is what baselines, work items and the run tab all match on.
Ignored findings stay in the file as result.suppressions, with kind inSource for inline comments or external for the ignore file. The Scans tab hides them unless you change its Suppression filter.
Ignored findings are listed separately (an ignored section in text, an ### Ignored table in markdown, a <skipped> case in junit) and never trip -exit-code.
Start here
How it works
Integrations
Project