Skip to content

CI Integration

Integrate spanforge-secrets into your CI/CD pipeline to automatically block merges or deployments that contain PII or exposed API keys.


GitHub Actions

Basic gate (fail on violations)

# .github/workflows/secrets-gate.yml
name: Secrets Gate

on:
  pull_request:
  push:
    branches: [main]

jobs:
  scan:
    name: PII & Secrets Scan
    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 scanners
        run: pip install spanforge-secrets spanforge

      - name: Run Spanforge Secrets Gate
        run: spanforge-secrets scan prompts/ data/

The job fails automatically when the scanner exits with code 1.


With SARIF upload (GitHub Advanced Security)

Upload findings to GitHub Code Scanning so they appear as pull-request annotations and in the Security tab.

name: Secrets Gate

on:
  pull_request:
  push:
    branches: [main]

jobs:
  scan:
    name: PII & Secrets Scan
    runs-on: ubuntu-latest
    permissions:
      security-events: write    # required for upload-sarif
      contents: read

    steps:
      - uses: actions/checkout@v4

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

      - name: Install scanners
        run: pip install spanforge-secrets spanforge

      - name: Run scan (SARIF output)
        # continue-on-error so the upload step always runs
        run: spanforge-secrets scan prompts/ data/ --format sarif > secrets.sarif
        continue-on-error: true

      - name: Upload SARIF to GitHub
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: secrets.sarif

      - name: Fail on violations
        run: spanforge-secrets scan prompts/ data/

SARIF severity mapping:

SensitivitySARIF levelGitHub annotation
higherrorRed blocking annotation
mediumwarningYellow annotation
lownoteBlue informational annotation

Caching pip dependencies

      - name: Cache pip
        uses: actions/cache@v4
        with:
          path: ~/.cache/pip
          key: ${{ runner.os }}-pip-spanforge-${{ hashFiles('**/requirements*.txt') }}

      - name: Install scanners
        run: pip install spanforge-secrets spanforge

Pin to a specific version

      - name: Install scanners
        run: pip install "spanforge-secrets==1.0.0" "spanforge>=2.0.2"

GitLab CI

Basic gate

# .gitlab-ci.yml
secrets-gate:
  stage: test
  image: python:3.12-slim
  before_script:
    - pip install spanforge-secrets spanforge
  script:
    - spanforge-secrets scan prompts/ data/
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"

With artifact upload

secrets-gate:
  stage: test
  image: python:3.12-slim
  before_script:
    - pip install spanforge-secrets spanforge
  script:
    - spanforge-secrets scan prompts/ data/ --format sarif > secrets.sarif || true
    - spanforge-secrets scan prompts/ data/
  artifacts:
    when: always
    paths:
      - secrets.sarif
    expire_in: 7 days

Pre-commit hook

Setup

Install pre-commit:

pip install pre-commit

Add to .pre-commit-config.yaml:

repos:
  - repo: local
    hooks:
      - id: spanforge-secrets
        name: Spanforge Secrets Gate
        language: system
        entry: spanforge-secrets scan --diff
        pass_filenames: false
        stages: [pre-commit]

Install the hook:

pre-commit install

The scanner now runs automatically on every git commit and blocks the commit if violations are found in the staged diff.

Run manually against all files

pre-commit run spanforge-secrets --all-files

Docker image

Build a lightweight scanner image:

FROM python:3.12-slim

RUN pip install --no-cache-dir spanforge-secrets spanforge

ENTRYPOINT ["spanforge-secrets"]

Build and run:

docker build -t spanforge-secrets:latest .
docker run --rm -v "$PWD:/workspace" -w /workspace spanforge-secrets:latest scan data/

Exit code handling

All CI systems that treat non-zero exit codes as failures will work correctly out of the box:

ScenarioExit codeCI result
No violations found0Pass
PII or API key found1Fail
Wrong arguments2Fail
Unreadable file / bad JSON3Fail

Suppressing known violations

Use an ignore file to exclude known false positives or intentional test fixtures:

# .spanforge-secretsignore

# Test fixtures contain intentional PII for unit tests
tests/fixtures/*
tests/data/*

# Anonymised sample data — reviewed and approved
data/samples/anonymised_chats.jsonl

The ignore file is auto-detected in the current working directory, or pass it explicitly:

spanforge-secrets scan data/ --ignore-file ci/secrets-ignore.txt

Combine scan + verify-chain in one workflow

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

      - name: Install
        run: pip install spanforge-secrets spanforge

      - name: PII & Secrets Gate
        run: spanforge-secrets scan prompts/ data/

      - name: Verify Audit Chain
        run: |
          spanforge-secrets verify-chain audit.jsonl --secret "${{ secrets.AUDIT_HMAC_SECRET }}"
        env:
          AUDIT_HMAC_SECRET: ${{ secrets.AUDIT_HMAC_SECRET }}