GitHub Actions
Runs on every PR + push to the default branch, caches the SQLite store, uploads SARIF to the Security tab, fails the check on blocking CVEs.
# .github/workflows/packguard.yml
name: packguard
on:
pull_request:
push:
branches: [main]
# Nightly intel refresh — keeps OSV + GHSA cache fresh without
# slowing PR runs. Omit if you don't want scheduled runs.
schedule:
- cron: "0 6 * * *"
permissions:
contents: read
security-events: write # required for upload-sarif
pull-requests: read
jobs:
packguard:
name: packguard · scan + audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: install packguard
run: |
curl -fsSL https://raw.githubusercontent.com/Tmauc/packguard/main/install.sh | sh
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
- name: restore cache
uses: actions/cache@v4
with:
# Store + intel both live under ~/.packguard — one cache
# entry covers both. Hash over lockfiles so we only re-scan
# when deps actually change.
path: ~/.packguard
key: packguard-${{ runner.os }}-${{ hashFiles('**/package-lock.json', '**/pnpm-lock.yaml', '**/yarn.lock', '**/poetry.lock', '**/uv.lock', '**/requirements*.txt') }}
restore-keys: |
packguard-${{ runner.os }}-
- name: scan
run: packguard scan .
- name: sync intel (scheduled only)
if: github.event_name == 'schedule' || github.event_name == 'push'
run: packguard sync
- name: report (SARIF + fail-on-violation)
run: packguard report . --format sarif --fail-on-violation > packguard.sarif
- name: upload SARIF to Security tab
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: packguard.sarif
category: packguardWhat each piece does
| Block | Why |
|---|---|
install.sh pipe | ~46 MB binary, no Docker, no node. Dropping it in ~/.local/bin keeps the step cache-agnostic across runners. |
actions/cache@v4 | Restores ~/.packguard/ when lockfiles are unchanged. Cold run ~30-90s; warm run ~2s. |
packguard sync on schedule | Nightly intel refresh is enough in 99% of cases — fresh OSV/GHSA every 24h. PR runs reuse yesterday’s cache. |
--fail-on-violation | Exit 2 on blocking CVE/malware — the workflow turns red + blocks merges if branch protection requires the check. |
upload-sarif with if: always() | Upload even when the audit fails, so the Security tab reflects the actual state, not the passing state. |
Container-based variant
If you’d rather run inside the published image (same result, slightly heavier cold start):
jobs:
packguard:
runs-on: ubuntu-latest
container:
image: ghcr.io/tmauc/packguard:latest
steps:
- uses: actions/checkout@v4
- run: packguard scan .
- run: packguard sync
- run: packguard report . --format sarif --fail-on-violation > packguard.sarif
- uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: packguard.sarif
category: packguardMatrix over a monorepo
If the repo hosts multiple workspaces, scan them in parallel and aggregate per-workspace SARIF:
strategy:
fail-fast: false
matrix:
workspace: [app-web, app-api, worker-ingest]
steps:
- uses: actions/checkout@v4
- run: packguard scan ./${{ matrix.workspace }}
- run: packguard report ./${{ matrix.workspace }} --format sarif --fail-on-violation > packguard.sarif
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: packguard.sarif
category: packguard/${{ matrix.workspace }}Each category: gets its own row in the Security tab, so you can spot which workspace introduced the regression without sifting through a merged report.
Variant — gate on prioritized actions (v0.4.0+)
If you want the Security tab to list the exact fix commands reviewers should run — rather than the policy rule that was violated — swap report for actions. Same SARIF upload pipeline, richer message.markdown per finding:
- name: actions (SARIF + fail-on-severity)
run: |
packguard actions --format sarif > packguard.sarif
packguard actions --fail-on-severity highpackguard actions --format sarifemits one result per action withruleId: packguard/<kind>, level mappingMalware/Critical/High → error, andpartialFingerprintscarrying both the action id and the advisory CVE id (GitHub Code Scanning uses them to dedup across runs + cluster by advisory).packguard actions --fail-on-severity <level>exits1when ≥1 active action sits at or above the given threshold. Usemalwarefor a paranoia gate that tolerates CVE noise;highfor a tighter bar;criticalfor the strictest.
Related
packguard report— the command the workflow runs as its gate.packguard actions— the alternative gate that emits fix commands inline.- GitLab CI — equivalent recipe for GitLab.
Last updated on