CI/CD Integration

aurora-lint 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:

  1. PR analysis (diff-only): fast feedback on changed files only

  2. 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+
aurora-lint . --diff --min-severity Medium --fail-on-severity High --export results.sarif

# Full scan: entire repo with cross-file context
aurora-lint . -d . --min-severity Medium --fail-on-severity High --export results.sarif

GitHub Actions

The repository includes a ready-to-use workflow at .github/workflows/aurora-lint-analysis.yml:

name: aurora-lint CERT C Analysis

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    name: Build aurora-lint
    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 aurora-lint
        run: cargo build --release

      - name: Upload binary
        uses: actions/upload-artifact@v4
        with:
          name: aurora-lint-binary
          path: target/release/aurora-lint

  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 aurora-lint
        uses: actions/download-artifact@v4
        with:
          name: aurora-lint-binary

      - run: chmod +x aurora-lint

      - name: Run aurora-lint (diff mode)
        run: |
          ./aurora-lint . --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 aurora-lint
        uses: actions/download-artifact@v4
        with:
          name: aurora-lint-binary

      - run: chmod +x aurora-lint

      - name: Run aurora-lint (full scan)
        run: |
          ./aurora-lint . -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:

# aurora-lint Static Analysis - Azure DevOps Example Pipeline
#
# This pipeline runs aurora-lint 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 aurora-lint-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 aurora-lint
    jobs:
      - job: BuildAuroraLint
        displayName: Build aurora-lint 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 aurora-lint

          - task: PublishPipelineArtifact@1
            inputs:
              targetPath: target/release/aurora-lint
              artifactName: aurora-lint-binary
            displayName: Publish aurora-lint 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: aurora-lint-binary
              targetPath: $(Build.SourcesDirectory)
            displayName: Download aurora-lint binary

          - script: |
              chmod +x aurora-lint
              ./aurora-lint . --diff \
                --min-severity Medium \
                --fail-on-severity High \
                --export results.sarif
            displayName: Run aurora-lint (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: aurora-lint-binary
              targetPath: $(Build.SourcesDirectory)
            displayName: Download aurora-lint binary

          - script: |
              chmod +x aurora-lint
              ./aurora-lint . -d . \
                --min-severity Medium \
                --fail-on-severity High \
                --export results.sarif
            displayName: Run aurora-lint (full scan)

          - task: PublishBuildArtifacts@1
            inputs:
              pathToPublish: results.sarif
              artifactName: sarif-results
            displayName: Publish SARIF results
            condition: always()

Knowing What the Scan Could Not See

A clean scan of code the analyzer could not fully read is not the same as a clean scan. aurora-lint works without a preprocessor, so heavy macro use or a header it never found can leave parts of a tree opaque to the dataflow rules without any finding saying so. --report-macro-gaps=FILE writes where that happened as JSON (skipped macro definitions, unresolved #includes, calls it could not attribute) without changing a single finding; keep the file as a build artifact next to the SARIF, and treat a jump in its per-kind totals the way you would treat a jump in findings:

aurora-lint . -d . --export results.sarif --report-macro-gaps=macro-gaps.json

The kinds and what each means are in Advanced CLI Usage.

SARIF Integration Tips

  • GitHub Code Scanning: Use github/codeql-action/upload-sarif@v3 to surface aurora-lint 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 .sarif files with the SARIF Viewer extension for inline annotations.

  • IDE Integration: Any tool that consumes SARIF 2.1.0 can display aurora-lint results.

CI/CD Readiness

Component

Status

Readiness

Output Formats

CSV, XLSX, JSON, SARIF 2.1.0

100%

Exit Codes

--fail-on-violation, --fail-on-severity

100%

Severity Filtering

--min-severity, --fail-on-severity

100%

Rule Filtering

--rules ARR30-C,MEM30-C

100%

Incremental

--diff (git modified files)

90%

CI Workflows

GitHub Actions + Azure DevOps templates

100%

Suppressions

SHA-256 code-location

70%

Docker

No image published

0%

Remaining gaps:

  1. No baseline-aware suppression — can’t report “only new violations since last run”

  2. No Docker image for containerized CI/CD

  3. Unclassified real-world violation density — no ground truth to split TP vs FP on production code