How to Interpret SARIF Output Format from NVIDIA SkillSpector for Security Tool Integration

NVIDIA SkillSpector emits static analysis results in SARIF 2.1.0 format, enabling direct integration with CI pipelines, vulnerability dashboards, and security orchestration platforms by consuming the structured JSON output defined in src/skillspector/sarif_models.py.

SkillSpector is an open-source static analysis tool from NVIDIA that generates security findings using the standardized Static Analysis Results Interchange Format (SARIF). To integrate these results with your security tooling, you must understand how SkillSpector structures its SARIF output and how to parse the specific fields defined in its Pydantic models. This guide walks through the exact schema definitions, validation methods, and integration patterns found in the SkillSpector repository.

Understanding the SARIF 2.1.0 Log Structure in SkillSpector

The Top-Level SarifLog Object

The root of every SkillSpector output is a SarifLog object defined in src/skillspector/sarif_models.py. This object contains three critical fields: version (fixed to "2.1.0"), schema_ (containing the URI "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.4.json"), and runs (a list of SarifRun objects).

A model validator at lines 15-19 ensures that the runs array is never empty, guaranteeing that every log contains at least one analysis run.

The SarifRun Container

Each run encapsulates the tool execution metadata and findings. According to the SarifRun definition at lines 99-104, each run includes a tool field (describing the analyzer via SarifTool and SarifDriver at lines 80-84), a results array containing individual findings, and an optional artifacts field.

SkillSpector does not populate the artifacts field (defined at lines 92-97), focusing instead on embedding file information within each result's location data.

Mapping SkillSpector Findings to SARIF Results

Result Objects and Severity Levels

Individual findings map to SarifResult objects, where the ruleId field corresponds to Finding.rule_id and the message.text field contains Finding.message. The _build_sarif function in src/skillspector/nodes/report.py (lines 5-38) handles this conversion, including severity translation via _severity_to_sarif_level (lines 64-71).

This function maps internal severity bands to standard SARIF levels: "error", "warning", or "note".

Location Information and Physical Regions

Each result contains a locations array with SarifLocation objects that specify exactly where the issue occurs. The physicalLocation contains an artifactLocation with a uri field, and a region object defining the line range.

SkillSpector populates these from Finding.start_line and Finding.end_line (lines 10-12 in report.py), providing precise file and line coordinates for every vulnerability.

Generating and Validating SARIF Output

The report() function in src/skillspector/nodes/report.py (lines 60-65) returns the final JSON under the key sarif_report. Before consumption, you can validate the structure using validate_sarif_report (lines 125-128 in sarif_models.py), which uses Pydantic to enforce SARIF 2.1.0 compliance.

The unit tests in tests/unit/test_sarif.py (lines 40-74) verify that valid documents round-trip correctly, while lines 105-141 confirm that malformed JSON raises pydantic.ValidationError.

Integrating SkillSpector SARIF with Security Tooling

Parsing with Pydantic Models

For Python-based integrations, import the models directly from skillspector.sarif_models to parse the JSON into typed objects. This approach provides IDE autocomplete and runtime validation, ensuring your integration handles the exact structure SkillSpector emits.

import json
from skillspector.sarif_models import SarifLog, validate_sarif_report

# Assume `sarif_json_str` is the string emitted by SkillSpector

sarif_dict = json.loads(sarif_json_str)

# Validate against the SARIF schema (raises ValidationError if broken)

validate_sarif_report(sarif_dict)

# Parse into strongly-typed objects for convenient access

log = SarifLog.model_validate(sarif_dict)

# Walk through findings

for run in log.runs:
    for result in run.results:
        print(f"Rule: {result.rule_id}")
        print(f"Message: {result.message.text}")
        print(f"Severity: {result.level}")
        for loc in result.locations:
            file_uri = loc.physical_location.artifact_location.uri
            region = loc.physical_location.region
            start = region.start_line if region else "?"
            end = region.end_line if region else start
            print(f"Location: {file_uri}:{start}-{end}")

CI/CD Pipeline Integration

Most modern CI platforms accept SARIF 2.1.0 uploads for security dashboards. You can run SkillSpector with --output-format sarif and feed the results directly into actions like github/codeql-action/upload-sarif.

name: SkillSpector Scan
on: [push, pull_request]

jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run SkillSpector (SARIF output)
        run: |
          pip install skillspector
          skillspector scan . --output-format sarif > skillspector.sarif.json
      - name: Upload SARIF to GitHub Security tab
        uses: github/codeql-action/upload-sarif@v2
        with:
          sarif_file: skillspector.sarif.json

Custom Aggregation Scripts

When building internal dashboards, extract specific fields from the validated SARIF log to aggregate findings by rule ID or file path.

def aggregate_by_rule(sarif_dict):
    """Return a dict mapping ruleId → list of (file, line) tuples."""
    log = SarifLog.model_validate(sarif_dict)
    agg = {}
    for result in log.runs[0].results:
        locations = [
            (loc.physical_location.artifact_location.uri,
             loc.physical_location.region.start_line)
            for loc in result.locations
        ]
        agg.setdefault(result.rule_id, []).extend(locations)
    return agg

Summary

  • SkillSpector emits standardized SARIF 2.1.0 output defined in src/skillspector/sarif_models.py, ensuring compatibility with security orchestration platforms.
  • The SarifLog contains runs with results that map Finding objects to SARIF-compliant ruleId, message, level, and location fields.
  • Use the provided Pydantic models or the validate_sarif_report function to ensure output integrity before processing.
  • Integration requires extracting the JSON from the sarif_report field and iterating over runs[0].results to access file paths, line numbers, and severity levels.

Frequently Asked Questions

What SARIF version does SkillSpector use?

SkillSpector strictly adheres to SARIF version 2.1.0, as enforced by the version field in SarifLog and the schema URI https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.4.json defined at line 24 of sarif_models.py.

How does SkillSpector map severity levels to SARIF?

The internal _severity_to_sarif_level function in src/skillspector/nodes/report.py (lines 64-71) translates SkillSpector's native severity bands to standard SARIF levels: "error" for high severity, "warning" for medium, and "note" for informational findings.

Can I validate SkillSpector SARIF output against the official schema?

Yes. The validate_sarif_report function in src/skillspector/sarif_models.py (lines 125-128) uses Pydantic validation to ensure the output conforms to the SARIF 2.1.0 specification, raising ValidationError for malformed documents as tested in tests/unit/test_sarif.py.

Where does the artifact location information come from in SkillSpector results?

The file paths and line numbers originate from Finding.start_line and Finding.end_line attributes, which the _build_sarif function (lines 10-12 in report.py) maps to the physicalLocation.artifactLocation.uri and region fields within each SarifResult.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →