CI/CD Integration
SqC is designed for CI/CD pipelines with exit codes, severity thresholds, diff-only analysis, and SARIF output for code scanning integrations.
General Strategy
A typical CI setup uses two modes:
PR analysis (diff-only): fast feedback on changed files only
Push/merge analysis (full scan): comprehensive scan on the main branch
Both modes export SARIF for integration with code scanning dashboards.
# PR mode: fast, only changed files, fail on High+
sqc . --diff --min-severity Medium --fail-on-severity High --export results.sarif
# Full scan: entire repo with cross-file context
sqc . -d . --min-severity Medium --fail-on-severity High --export results.sarif
GitHub Actions
The repository includes a ready-to-use workflow at
.github/workflows/sqc-analysis.yml:
name: SqC CERT C Analysis
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
name: Build SqC
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Cache Cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Build SqC
run: cargo build --release
- name: Upload binary
uses: actions/upload-artifact@v4
with:
name: sqc-binary
path: target/release/sqc
analyze-pr:
name: Analyze PR (diff only)
if: github.event_name == 'pull_request'
needs: build
runs-on: ubuntu-latest
permissions:
security-events: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for --diff mode
- name: Download SqC
uses: actions/download-artifact@v4
with:
name: sqc-binary
- run: chmod +x sqc
- name: Run SqC (diff mode)
run: |
./sqc . --diff \
--min-severity Medium \
--fail-on-severity High \
--export results.sarif
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: results.sarif
analyze-full:
name: Full Analysis
if: github.event_name == 'push'
needs: build
runs-on: ubuntu-latest
permissions:
security-events: write
steps:
- uses: actions/checkout@v4
- name: Download SqC
uses: actions/download-artifact@v4
with:
name: sqc-binary
- run: chmod +x sqc
- name: Run SqC (full scan)
run: |
./sqc . -d . \
--min-severity Medium \
--fail-on-severity High \
--export results.sarif
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: results.sarif
Azure DevOps
A ready-to-use Azure Pipelines configuration is provided at
docs/azure-pipelines.yml:
# SqC Static Analysis - Azure DevOps Example Pipeline
#
# This pipeline runs SqC CERT C analysis on your C/C++ codebase.
# - On PRs: analyzes only changed files (--diff mode)
# - On push to main: full repository scan
# - Publishes SARIF results as a build artifact
#
# Prerequisites:
# - Rust toolchain installed on the agent (or use a Rust container)
# - A sqc-rules.toml manifest (or use built-in defaults)
trigger:
branches:
include:
- main
pr:
branches:
include:
- main
pool:
vmImage: 'ubuntu-latest'
variables:
CARGO_TERM_COLOR: always
stages:
- stage: Build
displayName: Build SqC
jobs:
- job: BuildSqC
displayName: Build SqC binary
steps:
- task: Cache@2
inputs:
key: 'cargo | "$(Agent.OS)" | Cargo.lock'
restoreKeys: |
cargo | "$(Agent.OS)"
path: $(Pipeline.Workspace)/.cargo
displayName: Cache Cargo
- script: |
cargo build --release
displayName: Build SqC
- task: PublishPipelineArtifact@1
inputs:
targetPath: target/release/sqc
artifactName: sqc-binary
displayName: Publish SqC binary
- stage: Analyze
displayName: Run Analysis
dependsOn: Build
jobs:
- job: AnalyzePR
displayName: Analyze PR (diff only)
condition: eq(variables['Build.Reason'], 'PullRequest')
steps:
- checkout: self
fetchDepth: 0 # Full history for --diff mode
- task: DownloadPipelineArtifact@2
inputs:
artifactName: sqc-binary
targetPath: $(Build.SourcesDirectory)
displayName: Download SqC binary
- script: |
chmod +x sqc
./sqc . --diff \
--min-severity Medium \
--fail-on-severity High \
--export results.sarif
displayName: Run SqC (diff mode)
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: results.sarif
artifactName: sarif-results
displayName: Publish SARIF results
condition: always()
- job: AnalyzeFull
displayName: Full Analysis
condition: ne(variables['Build.Reason'], 'PullRequest')
steps:
- checkout: self
- task: DownloadPipelineArtifact@2
inputs:
artifactName: sqc-binary
targetPath: $(Build.SourcesDirectory)
displayName: Download SqC binary
- script: |
chmod +x sqc
./sqc . -d . \
--min-severity Medium \
--fail-on-severity High \
--export results.sarif
displayName: Run SqC (full scan)
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: results.sarif
artifactName: sarif-results
displayName: Publish SARIF results
condition: always()
SARIF Integration Tips
GitHub Code Scanning: Use
github/codeql-action/upload-sarif@v3to surface SqC violations as code scanning alerts on PRs and the Security tab.Azure DevOps: Publish SARIF as a build artifact. Third-party extensions (e.g., SARIF SAST Scans Tab) can render results inline.
VS Code: Open
.sariffiles with the SARIF Viewer extension for inline annotations.IDE Integration: Any tool that consumes SARIF 2.1.0 can display SqC results.
CI/CD Readiness
Component |
Status |
Readiness |
|---|---|---|
Output Formats |
CSV, XLSX, JSON, SARIF 2.1.0 |
100% |
Exit Codes |
|
100% |
Severity Filtering |
|
100% |
Rule Filtering |
|
100% |
Incremental |
|
90% |
CI Workflows |
GitHub Actions + Azure DevOps templates |
100% |
Suppressions |
SHA-256 code-location |
70% |
Docker |
No image published |
0% |
Remaining gaps:
No baseline-aware suppression — can’t report “only new violations since last run”
No Docker image for containerized CI/CD
Unclassified real-world violation density — no ground truth to split TP vs FP on production code