GitHub Actions is the recommended CI platform for Vibgrate, with native SARIF integration for code scanning alerts and PR annotations.
Quick Start
vg init --ci github
This writes .github/workflows/vibgrate.yml, which uses the vibgrate/cli Action to scan every pull request and upload SARIF to GitHub Security. The same workflow by hand:
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@v4
- uses: vibgrate/cli@v1
with:
upload-sarif: true
max-score: 40 # optional: fail the job when DriftScore is above 40
max-score takes a number from 0 to 100 (lower is better) and maps to --drift-budget. Leave it out to never fail on the score.
Read the score in a later step
The Action exposes the result as step outputs and adds a line to the job summary:
| Output | Value |
|---|---|
drift-score | DriftScore, 0-100 (lower is better). Empty when drift could not be measured, never 0 |
risk-level | low, moderate or high |
score-delta | Change since the baseline (positive is worse). Empty without a baseline |
summary-file | Path of the JSON the scan wrote (vibgrate-summary.json) |
- id: drift
uses: vibgrate/cli@v1
with:
upload-sarif: true
- run: echo "DriftScore is ${{ steps.drift.outputs.drift-score }}"
The outputs need a scanner image that supports --summary-out, and jq on the runner (present on GitHub-hosted runners). With an older image-tag the scan still runs and the outputs stay empty, with a notice in the log.
Fail when drift gets worse
Create a baseline once and commit it:
vg baseline
git add .vibgrate/baseline.json
Then point the Action at it:
- uses: vibgrate/cli@v1
with:
upload-sarif: true
baseline: .vibgrate/baseline.json
max-worsening: 5 # fail when drift worsens by more than 5% vs the baseline
baseline is a path inside the repository, and max-worsening needs it. Refresh the baseline when you accept a new level of drift. vg init --ci github --baseline writes the baseline and a workflow that already references it.
Basic Workflow
Minimal setup that fails on critical drift issues:
name: Vibgrate Drift Scan
on:
push:
branches: [main]
pull_request:
jobs:
drift-scan:
name: Upgrade Drift Analysis
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Run Vibgrate Scan
run: npx @vibgrate/cli scan --format sarif --out vibgrate.sarif --fail-on error
- name: Upload SARIF Results
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: vibgrate.sarif
Note: The if: always() ensures SARIF is uploaded even when the scan fails, so you can see findings in the PR.
With Vibgrate Cloud Push
Track drift trends across your organization:
- name: Run Vibgrate Scan
run: npx @vibgrate/cli scan --format sarif --out vibgrate.sarif --fail-on error
- name: Upload SARIF Results
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: vibgrate.sarif
- name: Push to Vibgrate Cloud
if: github.ref == 'refs/heads/main'
env:
VIBGRATE_DSN: ${{ secrets.VIBGRATE_DSN }}
run: npx @vibgrate/cli@latest push --file .vibgrate/scan_result.json
Tip: Only push from the main branch to get clean trend data without PR noise.
With Baseline Gates
Prevent drift regression on pull requests:
- name: Run Vibgrate Scan with Gates
run: |
npx @vibgrate/cli scan \
--baseline .vibgrate/baseline.json \
--drift-budget 40 \
--drift-worsening 5 \
--format sarif \
--out vibgrate.sarif \
--fail-on error
This fails the PR if:
- Drift score exceeds 40 (budget gate)
- Drift increased by >5% compared to baseline (regression gate)
- Any error-level findings exist
Production-Ready Workflow
Complete workflow with all features:
name: Vibgrate Drift Governance
on:
push:
branches: [main]
pull_request:
schedule:
- cron: '0 9 * * 1' # Weekly Monday scan
env:
NODE_VERSION: '20'
jobs:
drift-scan:
name: Upgrade Drift Analysis
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Run Vibgrate Scan
id: scan
run: |
npx @vibgrate/cli scan \
--baseline .vibgrate/baseline.json \
--drift-budget 40 \
--drift-worsening 5 \
--format sarif \
--out vibgrate.sarif \
--fail-on error
continue-on-error: true
- name: Upload SARIF Results
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: vibgrate.sarif
- name: Push to Vibgrate Cloud (main only)
if: github.ref == 'refs/heads/main' && steps.scan.outcome == 'success'
env:
VIBGRATE_DSN: ${{ secrets.VIBGRATE_DSN }}
run: npx @vibgrate/cli@latest push --file .vibgrate/scan_result.json --strict
- name: Archive Scan Artifact
uses: actions/upload-artifact@v4
with:
name: vibgrate-scan-${{ github.sha }}
path: |
vibgrate.sarif
.vibgrate/scan_result.json
- name: Fail on Gate Violation
if: steps.scan.outcome == 'failure'
run: exit 1
Setting Up Secrets
For dashboard push, add your DSN as a repository secret:
- Go to Settings → Secrets and variables → Actions
- Click New repository secret
- Name:
VIBGRATE_DSN - Value: Your DSN from
vg dsn create
Example Templates
Find ready-to-use templates in the CLI package:
| Template | Use Case |
|---|---|
driftscore-ci.yml | JSON artifact + drift gate |
driftscore-sarif.yml | SARIF upload to code scanning |
driftscore-full.yml | Complete governance workflow |