CI/CD integration
Vulkro is designed for CI as a primary use case. This page covers the three most common setups; deeper config lives under Integrations.
Exit-code contract
vulkro scan exits 1 if any Critical or High finding survives the
--min-confidence display filter. Otherwise 0. There are no partial-success
codes, so you can wire it into any CI runner that respects POSIX exit codes:
vulkro scan . # ci preset: exits 1 on Critical/High
vulkro scan . --fail-on critical,high,medium # also fail the build on Medium severity
vulkro scan . --all-confidence # show every finding; still gates on severity
--min-confidence (default medium) controls which findings are
displayed; --fail-on controls which severities make the build exit
non-zero. Bare vulkro scan runs the ci preset, whose default policy
is --fail-on critical,high.
GitHub Actions
name: vulkro
on:
push:
branches: [main]
pull_request:
jobs:
scan:
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write # required to upload SARIF
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # required for git-history secret audit
- name: Install vulkro
run: curl -fsSL https://dist.vulkro.com/install.sh | bash
- name: Run scan (SARIF)
run: vulkro scan . --format sarif > vulkro.sarif
- name: Upload to GitHub Code Scanning
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: vulkro.sarif
- name: Block PR on new Critical/High
run: vulkro scan . --min-confidence high
The two vulkro scan calls are intentional:
- The first run produces SARIF for GitHub Code Scanning (always succeeds, so the upload always happens).
- The second run is the gate - exits
1if there are unmitigated High/Critical findings, blocking the merge.
GitLab CI
vulkro:
stage: test
image: ubuntu:24.04
script:
- curl -fsSL https://dist.vulkro.com/install.sh | bash
- vulkro scan . --format junit > vulkro-junit.xml
- vulkro scan . --min-confidence high
artifacts:
when: always
reports:
junit: vulkro-junit.xml
paths:
- vulkro-junit.xml
expire_in: 30 days
JUnit output renders directly in GitLab's MR test report - every finding becomes a "test failure" with the file/line surfaced.
pre-commit
For fast local feedback:
repos:
- repo: local
hooks:
- id: vulkro-fast
name: vulkro (fast pass, source only)
entry: vulkro scan . --min-confidence high --scope src
language: system
pass_filenames: false
stages: [pre-commit]
--scope src skips Dockerfile / lockfile / template / IaC findings to keep
the hook fast. For a deeper local run, swap in vulkro scan . --min-confidence medium.
PR-comment integration
--format gh-pr produces a markdown comment intended for gh pr comment:
vulkro scan . --format gh-pr > comment.md
gh pr comment "$PR_NUMBER" --body-file comment.md
The comment summarises severity counts, lists Critical/High findings with
deep links to source lines, and notes diff vs. baseline if --baseline
is set.
Gate on new findings vs a baseline
Block the build only on new findings vs. main:
vulkro gate --base origin/main
vulkro gate scans the working tree and the base ref, then exits 1 only on
findings present now but not in the base, so re-orderings, whitespace changes,
and pre-existing tech debt never fail the build.
See also: Baselines explained - covers the
.vulkro-baseline.json ratchet file, the UI's baseline scan, and the
Export-for-CI bridge.
Environment variables you'll want
| Variable | Effect |
|---|---|
VULKRO_OFFLINE=1 | Skip the CVE bundle fetch in air-gapped CI runners. |
VULKRO_DISABLE_INTERPROC_TAINT=1 | Temporarily skip cross-file taint propagation when an FP regression breaks a build. |
VULKRO_GIT_BLAME=1 | Populate git_owner on every finding for ownership reports. |
What's next
- GitHub Actions deep-dive -> - caching, matrix, monorepo strategies.
- Output formats -> - CycloneDX SBOM, RoPA for GDPR Art. 30, exec HTML.
- Compliance gating -> - block PRs on PCI-DSS / SOC 2 / HIPAA control failures.