Skip to main content

CI/CD integration

Vulkro is built to run in CI. This page covers the common setups. For more depth, see Integrations.

How the exit code works

vulkro scan exits 1 if it finds any Critical or High issue, and 0 otherwise. That is the whole contract, so it drops into any CI runner:

vulkro scan . # fails the build on Critical/High
vulkro scan . --fail-on critical,high,medium # also fail on Medium
vulkro scan . --all-confidence # show everything; still gates on severity

--min-confidence controls which findings are shown. --fail-on controls which severities fail the build.

A severity exit policy is Free: --fail-on and a plain scan --gate are what the default preset uses, and no account is needed for them. The diff-scoped family (vulkro gate, scan --gate-vs and the ratchet), the pull-request comment and annotation formats, and vulkro ci are part of Pro. See Pricing.

GitHub Actions

.github/workflows/vulkro.yml
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 to scan git history for secrets

- 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 the PR on Critical/High
run: vulkro scan . --min-confidence high

There are two scan steps on purpose. The first always succeeds and produces SARIF, so the results always show up in GitHub Code Scanning. The second is the gate: it fails the build if there are unresolved Critical or High findings.

GitLab CI

.gitlab-ci.yml
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

The JUnit output shows up directly in GitLab's merge-request report, with every finding as a failed test and its file and line attached.

pre-commit (fast local check)

.pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: vulkro-fast
name: vulkro (fast, source only)
entry: vulkro scan . --min-confidence high --scope src
language: system
pass_filenames: false
stages: [pre-commit]

--scope src skips Dockerfiles, lockfiles, and templates to keep the hook fast.

Post results as a PR comment

The pull-request output (gh-pr, gh-pr-inline-comments, github-annotations, gitlab-mr, bitbucket-pr, azure-pr) is part of Pro: Pull-request output (pr-comments), findings as review comments and CI annotations.

vulkro scan . --format gh-pr > comment.md
gh pr comment "$PR_NUMBER" --body-file comment.md

The comment summarizes the severity counts and links each Critical and High finding straight to the line of code.

Gate only on new problems

Part of Pro: Release gate (release-gate), fail a build on new findings, with the exit-code contract and the baseline diff. To fail the build only on issues that are new compared to main:

vulkro gate --base origin/main

vulkro gate scans both your branch and the base, then fails only on findings that are new. Existing tech debt, re-ordering, and whitespace changes never fail the build. See Baselines explained.

Useful environment variables

VariableEffect
VULKRO_OFFLINE=1Skip the CVE download in air-gapped runners.
VULKRO_GIT_BLAME=1Attach the code owner to each finding for reports.

What's next