Skip to content

feat: Add SARIF 2.1.0 report output with shared reporting layer#56

Merged
304NotModified merged 7 commits intomainfrom
copilot/add-sarif-report-output-support
Apr 6, 2026
Merged

feat: Add SARIF 2.1.0 report output with shared reporting layer#56
304NotModified merged 7 commits intomainfrom
copilot/add-sarif-report-output-support

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 6, 2026

  • Understand codebase structure
  • Create Core/Reporting/RuleSeverity.cs (renamed from SonarRuleSeverity)
  • Create Core/Reporting/Rule.cs (renamed from RuleMetadata)
  • Create Core/Reporting/RuleProvider.cs (renamed from RuleMetadataProvider, Create() returns tuple to eliminate duplicate error code keys, default MAJOR severity)
  • Update all SonarRuleSeverity references to RuleSeverity
  • Update SonarReporter.GetRuleDefinition() to use RuleProvider
  • Create Core/SarifReporting/ with individual files per DTO, ISarifReporter.cs, SarifReporter.cs
  • Wire SARIF into CLI (--sarif-report-file option, ValidatorRunnerOptions, Program.cs, ValidatorRunner.cs, ServiceCollectionExtensions.cs)
  • Write SarifReporterTests (unit tests + snapshot tests, 16 new tests)
  • Update README: --sarif-report-file section with SARIF intro, benefits, viewers with correct extension links
  • Remove <remarks> from RuleSeverity; keep per-value <summary> with SARIF mapping
  • Split SarifModels.cs into separate files
  • Update rule names: "SLNX file not found", "Invalid solution file extension", "SLNX file is not a text file"
  • Fix: Visual Studio requires SARIF Viewer extension (not built-in); corrected link and wording
  • All 88 tests passing
Original prompt

Goal

Add SARIF (Static Analysis Results Interchange Format) report output support to slnx-validator, following "Option A" — extracting shared rule metadata and severity into a common reporting layer so there is zero duplication between the SonarQube and SARIF reporters.

Architecture changes

1. Extract shared reporting layer

Rename SonarRuleSeverityRuleSeverity (the enum is already used as the universal severity across the entire app — in ValidatorRunnerOptions, SeverityOverridesParser, ValidationReporter, ValidatorRunner.IsFailingError() — so the rename is justified).

Create a new shared namespace/folder Core/Reporting/ with:

  • RuleSeverity.cs — the renamed enum (values: BLOCKER, CRITICAL, MAJOR, MINOR, INFO)
  • RuleMetadata.cs — a record holding the format-agnostic rule info: Id (string, e.g. "SLNX011"), Name (string), Description (string), DefaultSeverity (RuleSeverity)
  • RuleMetadataProvider.cs — a static class with a Get(ValidationErrorCode) method containing the switch expression currently in SonarReporter.GetRuleDefinition(), but returning only the shared fields (no SonarQube-specific fields like CleanCodeAttribute, Type, Impacts)

Update all references from SonarRuleSeverity to RuleSeverity across the entire codebase:

  • ValidatorRunnerOptions.cs
  • SeverityOverridesParser.cs
  • ValidationReporter.cs
  • ValidatorRunner.cs
  • ISonarReporter.cs
  • SonarReporter.cs
  • SonarRule.cs (keep a SonarQube-specific Severity property, but typed as RuleSeverity)
  • All test files referencing SonarRuleSeverity

2. Update SonarReporter to use shared provider

SonarReporter.GetRuleDefinition() should use RuleMetadataProvider.Get(code) for the shared fields (Id, Name, Description, default Severity) and only add the SonarQube-specific fields itself (EngineId, CleanCodeAttribute, Type, Impacts).

The IsIgnored() helper logic is also needed by the SARIF reporter. Either extract it to a shared place, or keep it simple and let each reporter have its own trivial one-liner.

3. Add SARIF reporter

Create a new namespace/folder Core/SarifReporting/ with:

  • SarifReporter.cs — implements a new ISarifReporter interface. Uses RuleMetadataProvider for rule metadata. Maps RuleSeverity to SARIF levels:
    • BLOCKER, CRITICAL, MAJOR → "error"
    • MINOR → "warning"
    • INFO → "note"
  • SARIF model DTOs — the minimal set of records needed to produce a valid SARIF 2.1.0 JSON document:
    • SarifLog with $schema ("https://json.schemastore.org/sarif-2.1.0.json"), version ("2.1.0"), runs array
    • SarifRun with tool and results
    • SarifTool with driver
    • SarifToolComponent (driver) with name ("slnx-validator"), informationUri, rules array
    • SarifReportingDescriptor (rule) with id, shortDescription, fullDescription, defaultConfiguration (with level)
    • SarifResult with ruleId, level, message, locations
    • SarifLocation, SarifPhysicalLocation, SarifArtifactLocation, SarifRegion
    • SarifMessage with text
  • ISarifReporter.cs — interface mirroring ISonarReporter pattern:
    Task WriteReportAsync(IReadOnlyList<FileValidationResult> results, string outputPath,
        IReadOnlyDictionary<ValidationErrorCode, RuleSeverity?>? severityOverrides = null);
    Task WriteReportAsync(IReadOnlyList<FileValidationResult> results, Stream outputStream,
        IReadOnlyDictionary<ValidationErrorCode, RuleSeverity?>? severityOverrides = null);

The file-writing pattern (create directory, open stream) should follow the same pattern as SonarReporter.

4. Wire up CLI

In Program.cs, add:

var sarifReportOption = new Option<string?>("--sarif-report-file")
{
    Description = "Write a SARIF v2.1.0 report to the specified file path."
};

Add it to the root command and pass it through to ValidatorRunnerOptions.

In ValidatorRunnerOptions.cs, add string? SarifReportPath.

In ValidatorRunner.RunAsync(), add the SARIF report writing block (same pattern as the SonarQube block):

if (options.SarifReportPath is not null)
{
    await sarifReporter.WriteReportAsync(results, options.SarifReportPath, overrides);
    var size = fileSystem.GetFileSize(options.SarifReportPath);
    Console.WriteLine($"SARIF report written to: {options.SarifReportPath} ({size} bytes)");
}

In ServiceCollectionExtensions.cs, register ISarifReporterSarifReporter.

5. Tests

Add SarifReporterTests.cs in the test project, covering at minimum:

  • No errors → empty results array
  • With error → correct rule and result in output
  • Error with line → region with startLine
  • Error without line → no region
  • Same error code twice → rule listed once
  • Different error codes → multiple rules
  • Severity override reflected in output
  • Ignored code excluded from output
  • Snapshot test if the project uses Verify

6. Update README.md docum...

This pull request was created from Copilot chat.

…tadata layer

- Rename SonarRuleSeverity → RuleSeverity in Core/Reporting/
- Add RuleMetadata record and RuleMetadataProvider static class
- Add SarifReporter with SARIF 2.1.0 DTOs (no external NuGet deps)
- Add --sarif-report-file CLI option and wire into ValidatorRunner
- Update all SonarRuleSeverity references to RuleSeverity
- Add SarifReporterTests with snapshot tests
- Update README with SARIF docs and GitHub Code Scanning example

Agent-Logs-Url: https://github.com/304NotModified/SLNX-validator/sessions/5d6c6f75-d638-45f6-a4ec-d404d306a102

Co-authored-by: 304NotModified <5808377+304NotModified@users.noreply.github.com>
Copilot AI changed the title [WIP] Add SARIF report output support to slnx-validator feat: Add SARIF 2.1.0 report output with shared reporting layer (Option A) Apr 6, 2026
Copilot AI requested a review from 304NotModified April 6, 2026 03:26
@304NotModified 304NotModified changed the title feat: Add SARIF 2.1.0 report output with shared reporting layer (Option A) feat: Add SARIF 2.1.0 report output with shared reporting layer Apr 6, 2026
- Split SarifModels.cs into individual files per class
- Add XML doc comments to RuleSeverity enum with SARIF/SonarQube mapping
- Move --sarif-report-file section before --continue-on-error in README
- Remove unclear .sarif.json tip line from README
- Update severity override flags table to include SARIF level column
- Add short SARIF explanation to GitHub Code Scanning section

Agent-Logs-Url: https://github.com/304NotModified/SLNX-validator/sessions/c8bac85a-7f8b-43c1-911f-a7724715655c

Co-authored-by: 304NotModified <5808377+304NotModified@users.noreply.github.com>
- Rename RuleMetadata -> Rule, RuleMetadataProvider -> RuleProvider
- Convert switch expression in RuleProvider to private dictionary
- Remove <remarks> block from RuleSeverity (keep per-value <summary>)
- README: expand --sarif-report-file section with SARIF intro, benefits, links, viewers
- README: add internal links in severity mapping section
- README: update severity override description to mention console + SQ + SARIF

Agent-Logs-Url: https://github.com/304NotModified/SLNX-validator/sessions/24076cbf-30ba-4777-8367-61481287936c

Co-authored-by: 304NotModified <5808377+304NotModified@users.noreply.github.com>
Copilot AI requested a review from 304NotModified April 6, 2026 04:23
@304NotModified 304NotModified marked this pull request as ready for review April 6, 2026 04:33
{
private static readonly Dictionary<ValidationErrorCode, Rule> Rules = new()
{
[ValidationErrorCode.FileNotFound] = new(
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create a helper to dedup. Use smart default to reduce duplications.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a private Create() helper with RuleSeverity.MAJOR as the default parameter. All 7 MAJOR entries no longer repeat code.ToCode() or the explicit severity, and only the 2 MINOR entries pass an override. (024cddb)

- RuleProvider: add Create() helper with default MAJOR severity to eliminate repeated code.ToCode() and explicit MAJOR
- README: replace VS Code -> Visual Studio Code, VS -> Visual Studio throughout
- README: fix out-of-the-box claim (Visual Studio built-in, VS Code/Azure DevOps need extensions)
- README: fix Visual Studio link to SARIF viewer docs (was Roslyn analyzers)
- README: fix Azure DevOps link to SARIF SAST Scans Tab extension (was code coverage docs)

Agent-Logs-Url: https://github.com/304NotModified/SLNX-validator/sessions/f238c504-01a4-4790-a858-136add863e89

Co-authored-by: 304NotModified <5808377+304NotModified@users.noreply.github.com>
- RuleProvider: dedup error codes by having Create() return (Key, Rule) tuple,
  build dictionary via .ToDictionary() so each ValidationErrorCode only appears once
- RuleProvider: rename rules: "Input file not found" -> "SLNX file not found",
  "Invalid file extension" -> "Invalid solution file extension",
  "File is not a text file" -> "SLNX file is not a text file"
- Update snapshot tests to match new rule names
- README: link "Visual Studio" in benefits bullet to official SARIF viewer docs
- README: viewers section - Visual Studio/Code/Azure DevOps no longer hyperlinks;
  only the extension/docs links are clickable, no duplicate links

Agent-Logs-Url: https://github.com/304NotModified/SLNX-validator/sessions/e6c871f9-f7c6-4137-9c1d-716db710bb21

Co-authored-by: 304NotModified <5808377+304NotModified@users.noreply.github.com>
…lt-in

The previously linked docs URL returned 404. Visual Studio does not have
a built-in SARIF viewer; it requires the Microsoft SARIF Viewer extension.

- Benefits bullet: removed "built-in" claim, now says "via extensions for
  Visual Studio, Visual Studio Code, and Azure DevOps"
- Viewers list: Visual Studio entry now links to the correct Marketplace
  extension (WDGIS.MicrosoftSarifViewer2022)

Agent-Logs-Url: https://github.com/304NotModified/SLNX-validator/sessions/273158ae-504a-46bd-9190-2e9f6a642aa7

Co-authored-by: 304NotModified <5808377+304NotModified@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 6, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • marketplace.visualstudio.com
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node /home/REDACTED/work/_temp/ghcca-node/node/bin/node --enable-source-maps /home/REDACTED/work/_temp/copilot-developer-action-main/dist/index.js (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copy link
Copy Markdown
Owner

@304NotModified 304NotModified left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Links give 404. See open code comments

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 6, 2026

Links give 404. See open code comments

Fixed in 61baa80 — the 404 link (learn.microsoft.com/.../working-with-sarif-reports) was removed. The Visual Studio entry in the viewers list now links to the Microsoft SARIF Viewer extension on the VS Marketplace, and the benefits bullet no longer has a broken link.

@304NotModified 304NotModified merged commit 620739e into main Apr 6, 2026
6 checks passed
@304NotModified 304NotModified deleted the copilot/add-sarif-report-output-support branch April 6, 2026 05:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants