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
SarifLogcontainsrunswithresultsthat mapFindingobjects to SARIF-compliantruleId,message,level, andlocationfields. - Use the provided Pydantic models or the
validate_sarif_reportfunction to ensure output integrity before processing. - Integration requires extracting the JSON from the
sarif_reportfield and iterating overruns[0].resultsto 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →