How to Integrate SkillSpector into CI/CD Pipelines Using SARIF Output

SkillSpector generates standardized SARIF 2.1.0 output through the --format sarif CLI flag or Python API, enabling direct ingestion by GitHub Actions, Azure DevOps, and GitLab CI for automated security scanning and pull request annotations.

NVIDIA's SkillSpector analyzes AI skill packages for security vulnerabilities and configuration errors. When configured to output SARIF (Static Analysis Results Interchange Format), it produces a standardized JSON document that CI/CD platforms can ingest directly to annotate code reviews, block merges, and enforce security gates.

Understanding the SARIF Generation Architecture

The SARIF pipeline in SkillSpector follows a LangGraph-based workflow that transforms raw findings into a standardized report.

From CLI Flags to Graph State

In src/skillspector/cli.py, the skillspector scan command parses the --format flag. When set to sarif, the CLI stores "output_format": "sarif" in the initial graph state (_scan_state at lines 95-101). This state object orchestrates the entire analysis workflow, including static pattern matchers, optional LLM semantic checks, and OSV lookups.

The Report Node and SARIF Assembly

The LangGraph workflow (graph.invoke) executes analyzer nodes that populate filtered_findings in the state. The report node in src/skillspector/nodes/report.py (lines 48-66) processes these findings through the _build_sarif function. This function iterates over each Finding object and constructs a SarifResult using Pydantic models defined in src/skillspector/sarif_models.py. Each result includes the rule ID, severity-mapped level, and precise file location (line/column ranges).

Serialization and Exit Behavior

The SarifLog object serializes to a Python dictionary via model_dump(..., by_alias=True) and returns as sarif_report in the node's output dictionary. The CLI's _write_result helper writes this as pretty-printed JSON using json.dumps(..., indent=2). SkillSpector exits with a non-zero status when the aggregated risk_score exceeds 50, enabling automatic pipeline failure configurations.

GitHub Actions Integration

GitHub Actions can upload SARIF files directly to Code Scanning alerts using the upload-sarif action.

name: SkillSpector CI
on: [push, pull_request]

jobs:
  scan-skill:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - name: Install SkillSpector
        run: |
          python -m pip install --upgrade pip
          pip install skillspector[all]

      - name: Export LLM env vars
        env:
          SKILLSPECTOR_PROVIDER: ${{ secrets.SKILLSPECTOR_PROVIDER }}
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          echo "SKILLSPECTOR_PROVIDER=${SKILLSPECTOR_PROVIDER}" >> $GITHUB_ENV
          echo "ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}" >> $GITHUB_ENV

      - name: Run SkillSpector (SARIF)
        id: scan
        run: |
          skillspector scan . \
            --format sarif \
            --output skill_report.sarif

      - name: Upload SARIF report
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: skill_report.sarif

The upload-sarif action automatically creates Code Scanning alerts in the Security tab and annotates pull requests with findings.

Azure Pipelines Integration

Azure DevOps supports SARIF ingestion through the PublishTestResults task.

trigger:
- main

pool:
  vmImage: 'ubuntu-latest'

steps:
- script: |
    python -m pip install --upgrade pip
    pip install skillspector[all]
  displayName: 'Install SkillSpector'

- script: |
    skillspector scan $(Build.SourcesDirectory) \
      --format sarif \
      --output $(Build.ArtifactStagingDirectory)/skill.sarif
  displayName: 'Run SkillSpector'

- task: PublishTestResults@2
  inputs:
    testResultsFormat: 'SARIF'
    testResultsFiles: '$(Build.ArtifactStagingDirectory)/skill.sarif'
    mergeTestResults: true

GitLab CI/CD Integration

GitLab's security reports UI automatically renders SARIF artifacts when declared in the artifacts:reports:sarif section.

stages:
  - scan

skill_scan:
  image: python:3.12-slim
  stage: scan
  script:
    - pip install skillspector[all]
    - skillspector scan $CI_PROJECT_DIR --format sarif --output skill.sarif
  artifacts:
    paths:
      - skill.sarif
    reports:
      sarif: skill.sarif

GitLab parses the SARIF file and displays findings in the pipeline's Security tab and merge request security widget.

Programmatic Integration with the Python API

For custom pipeline scripts or orchestration tools, invoke the graph directly without subprocess calls.

from skillspector import graph
import json
import pathlib

# Build the initial state with SARIF output format

state = {
    "input_path": "/path/to/skill",
    "output_format": "sarif",
    "use_llm": False,   # optional, static-only for speed

}

# Execute the full analysis workflow

result = graph.invoke(state)

# The SARIF document is available as a dict under sarif_report

sarif_report = result["sarif_report"]

# Write to file for downstream CI consumption

path = pathlib.Path("skill_report.sarif")
path.write_text(json.dumps(sarif_report, indent=2))
print("SARIF saved to", path)

Key Source Files for Custom Integrations

When extending SkillSpector's CI/CD capabilities, these files constitute the SARIF generation path:

Summary

  • SkillSpector produces SARIF 2.1.0 output via the --format sarif flag, compatible with major CI/CD platforms.
  • The reporting pipeline uses a LangGraph report node (report()) in src/skillspector/nodes/report.py to assemble findings into standardized results.
  • Exit codes are non-zero when risk_score exceeds 50, enabling automatic pipeline failure.
  • GitHub Actions, Azure Pipelines, and GitLab CI all support native SARIF ingestion for security dashboards and pull request annotations.
  • The Python API exposes the same SARIF generation through graph.invoke() without requiring subprocess calls.

Frequently Asked Questions

What is SARIF and why does SkillSpector use it?

SARIF (Static Analysis Results Interchange Format) is an industry-standard JSON schema for static analysis results. SkillSpector uses SARIF 2.1.0 because GitHub, Azure DevOps, and GitLab natively parse it to create security alerts and annotate pull requests with precise line-level findings. The format includes rich metadata such as rule IDs, severity levels, and artifact locations that make diagnostics reproducible across different analysis environments.

How do I fail a CI/CD pipeline based on SkillSpector findings?

SkillSpector automatically exits with a non-zero status code when the aggregated risk_score exceeds 50. You can rely on this behavior to fail CI jobs naturally, or parse the SARIF output programmatically to check the results array length and implement custom thresholds. For platform-specific configurations, use GitHub's soft_fail option or Azure's failOnStandardError settings alongside the SARIF upload tasks.

Can I customize the SARIF output format?

Yes, by modifying src/skillspector/sarif_models.py to extend the Pydantic models (such as adding custom properties to the SarifLog or SarifResult objects) or by transforming the dictionary output in src/skillspector/nodes/report.py before serialization. The _build_sarif function serves as the primary extension point for adding custom fields without breaking downstream consumers that expect standard SARIF 2.1.0 structure.

Does the Python API return SARIF differently than the CLI?

No, both use the same underlying graph implementation in src/skillspector/graph.py. The Python API returns the SARIF document as a Python dictionary in the sarif_report key of the result object, while the CLI writes the identical data to a JSON file via json.dumps(..., indent=2). Both formats conform to the SARIF 2.1.0 specification and can be consumed by the same CI/CD ingestion mechanisms.

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 →