feat(reporters): file output, rdjson/sonar formats, SARIF safeguards + remediation#263
Merged
Merged
Conversation
…+ remediation A single coherent change to the reporter/output layer, landing five related issues that all live in `vibeguard/reporters/` + the CLI output dispatch. - #233 `--output PATH` (`-o`, `-`=stdout) on scan/gate/publish-check, plus repeatable `--report FORMAT=PATH` to emit several formats from one scan. Generated workflow uses `--output` instead of shell redirection. New `reporters/registry.py` centralizes format→string rendering. - #237 reviewdog rdjson reporter (`--rdjson`) + golden. - #244 SonarQube Generic Issue Import reporter (`--sonar`) + golden. - #227 SARIF result cap for GitHub Code Scanning ingestion limits: severity ordered, overflow notification, configurable via `output.sarif_max_results`; output byte-identical at/below the cap. - #238 structured `Finding.remediation` model (machine-actionable fixes), populated on sourcemaps + committed-env findings, serialized to JSON and mapped to SARIF `fixes` for replace-span/add-line kinds. Docs: docs/output-schemas.md (formats 4-8), docs/github-actions.md (file output + large-repo guidance), README output examples. Tests: new rdjson/ sonar/remediation suites, SARIF cap + fixes, CLI --output/--report e2e; goldens regenerated. Closes #233 Closes #237 Closes #244 Closes #227 Closes #238 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X8ZPCcEw5r2augVrtDqdyJ
There was a problem hiding this comment.
Pull request overview
This PR expands VibeGuard’s reporter/output layer to support writing reports to files (including multi-report output from a single scan), adds two new machine formats (reviewdog rdjson and SonarQube Generic Issue Import), and enhances SARIF output with ingestion safeguards and optional machine-actionable remediation metadata.
Changes:
- Add
--outputand repeatable--report FORMAT=PATHtoscan/gate/publish-check, with a centralized reporter registry for “format → rendered string”. - Introduce new reporters:
rdjson(reviewdog) andsonar(SonarQube), plus goldens and targeted tests. - Add SARIF result-capping + overflow notification and a new
Finding.remediationmodel mapped to SARIFfixesfor precise edit kinds.
Reviewed changes
Copilot reviewed 22 out of 22 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| vibeguard/rules/sourcemaps.py | Adds structured remediation metadata to sourcemap-related findings. |
| vibeguard/rules/secrets.py | Adds structured remediation metadata to committed-env findings. |
| vibeguard/reporters/sonar.py | New SonarQube Generic Issue Import JSON renderer. |
| vibeguard/reporters/sarif.py | Adds SARIF max-results cap + overflow notice and SARIF fixes mapping. |
| vibeguard/reporters/registry.py | Centralizes format-name → rendered-string dispatch for CLI and multi-report. |
| vibeguard/reporters/rdjson.py | New reviewdog rdjson renderer. |
| vibeguard/models.py | Introduces RemediationKind/Remediation and adds Finding.remediation. |
| vibeguard/config.py | Adds output.sarif_max_results configuration. |
| vibeguard/cli.py | Implements --output/--report plumbing and unified output dispatch. |
| vibeguard/ci_setup.py | Updates generated workflow to use --output instead of shell redirection. |
| tests/test_sonar.py | Adds Sonar reporter/CLI tests. |
| tests/test_sarif.py | Adds SARIF cap tests and SARIF fixes tests. |
| tests/test_reporters_golden.py | Adds golden coverage for rdjson and sonar outputs. |
| tests/test_remediation.py | Adds remediation model + rule integration tests. |
| tests/test_rdjson.py | Adds rdjson reporter/CLI tests. |
| tests/test_cli_e2e.py | Adds e2e coverage for --output and --report. |
| tests/fixtures/golden/scan_result.sonar.json | Adds sonar golden fixture. |
| tests/fixtures/golden/scan_result.rdjson | Adds rdjson golden fixture. |
| tests/fixtures/golden/scan_result.json | Updates JSON golden for remediation: null. |
| README.md | Documents new output flags and formats. |
| docs/output-schemas.md | Documents remediation metadata, SARIF cap, rdjson/sonar formats, and file output. |
| docs/github-actions.md | Updates Actions docs for --output and SARIF cap guidance. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…dout Address PR review: - models.py: the Remediation docstring listed `add-ignore-entry` among the kinds mapped to SARIF `fixes`, but `_build_fixes` only maps `add-line` / `replace-span`. Correct the docstring to match the reporter. - cli.py: `_write_report` computed a newline-normalized string but echoed the raw text on the `-` (stdout) path, so a renderer ending in `\n` would emit a double trailing newline and diverge from the file path. Echo `normalized` with `nl=False` so stdout matches file output byte-for-byte. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X8ZPCcEw5r2augVrtDqdyJ
…e-line SARIF fix
Two audit follow-ups on the reporter layer:
- Sonar: the IaC rule tags findings with their family ("iac"/"terraform"/
"kubernetes") but no generic "security" tag, so they were typed CODE_SMELL
instead of VULNERABILITY. Add those families to _VULNERABILITY_TAGS so
security-relevant infra findings classify correctly.
- SARIF: a replace-span remediation with empty content (delete the line, e.g.
the sourceMappingURL comment) emitted a single-line region that blanked the
line in place. Span to column 1 of the next line so the line and its newline
are removed, leaving no empty line behind.
Both paths gain tests; goldens are unaffected (the canonical fixture has no IaC
finding and no remediation).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QDQxGQtbVN2CqXkCtkCJwK
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.
Linked issues
Closes #233
Closes #237
Closes #244
Closes #227
Closes #238
Summary of changes
A single coherent change to the reporter / output layer (
vibeguard/reporters/+ the CLI output dispatch), landing five related issues that share the same code area and implementation path.--output FILE(and multi-report output) to scan, gate, and publish-check #233 — file output & multi-report.--output PATH(-o,-= stdout) onscan/gate/publish-check, and a repeatable--report FORMAT=PATHthat emits several formats from one scan (no shell redirection, no double scan). Newvibeguard/reporters/registry.pycentralizesformat → stringrendering (also useful for the embedding API). The generated GitHub Actions workflow now uses--outputinstead of> file.--rdjsonreporter (reporters/rdjson.py) emitting reviewdog's Diagnostic Format; severity map INFO/LOW→INFO, MEDIUM→WARNING, HIGH/CRITICAL→ERROR.--sonarreporter (reporters/sonar.py) emitting the Generic Issue Import JSON forsonar.externalIssuesReportPaths, with a documented severity/type mapping.render_sarifcaps results atoutput.sarif_max_results(default 5,000 — GitHub's per-run limit), ordering by severity and appending atoolExecutionNotificationsoverflow notice. Output is byte-identical at/below the cap.Finding.remediationmodel (kind/target/line/content/description/confidence), populated on the sourcemaps + committed-.envfindings, serialized in JSON and mapped to SARIFfixesfor thereplace-span/add-linekinds (GitHub renders these as one-click suggestions).Type of change
sourcemaps/secrets)How verified
python -m pytest tests/— 1072 passed (+~50 new)ruff check vibeguard/ tests/ benchmarks/— All checks passedruff format --check vibeguard/ tests/ benchmarks/— 140 files already formattedpython -m mypy vibeguard/— Success: no issues found in 62 source files (withtypes-PyYAMLinstalled; the bare-mypyyaml-stub note is the pre-existing environment artifact)make docs-check,make bench-precision-check,make check-versions— all clean (no rule-metadata or precision drift; remediation adds no findings)vibeguardentrypoint):--report sarif=… --report rdjson=…writes both from one scan;--sonar --output -streams to stdout;--outputwithout a format flag, an unwritable path, mixing--reportwith a format flag, and a bad/unknown--reportspec all exit 2; generated workflow renders and is valid YAML with--output.Docs impact
docs/output-schemas.md§4–§8 (remediation, SARIF cap, rdjson, sonar, file output);docs/github-actions.md(file output + large-repo guidance)docs/rules.mdnot regenerated — rule metadata is unchanged (remediation is per-finding data, not registry metadata);make docs-checkconfirms no drift.Scope / risk
--output,--report,--rdjson,--sonar,output.sarif_max_results) — added to the stability contract; mutual-exclusion and error paths are tested."remediation": nullby default. Consumers that ignore unknown/null fields are unaffected; the JSON golden was regenerated for this. SARIF and Markdown goldens are byte-identical. (Per the requester: no backward-compat constraint.)replace-span/add-linebecome SARIF fixes. A wrong auto-fix is worse than none.vibeguard fixwork).Checklist
pytest)make lintandmake format-check)make typecheck) — clean withtypes-PyYAML; only the known pre-existingyaml-stub note otherwise🤖 Generated with Claude Code
https://claude.ai/code/session_01X8ZPCcEw5r2augVrtDqdyJ
Generated by Claude Code