wasviking-sentinel in CI/CD
Drop the same Go binary in your pipeline for SBOM, secrets, mobile assessment, and policy-driven cloud scans. Independent gates, one preflight, deterministic exit codes.
The same wasviking-sentinel binary that opens the mTLS tunnel also
runs as a one-shot tool in CI/CD pipelines. In a CI/CD context the
agent does not need to be registered (no mTLS bootstrap, no
certificates). It authenticates with an organization API key.
Three independent gates ship today, each a top-level subcommand:
| Subcommand | Gate | OWASP |
|---|---|---|
wasviking-sentinel sbom |
Vulnerable components (SCA). | A06 |
wasviking-sentinel secrets |
Hard-coded credentials. | A07 / CWE-798 |
wasviking-sentinel scan |
Cloud DAST, template-driven. | varies |
Each subcommand is documented in detail on its own page:
- wasviking-sentinel sbom
- wasviking-sentinel secrets
- (scan subcommand reference: see Cloud DAST below)
For ready-to-paste recipes, see CI/CD DAST with GitHub Actions, CI/CD SCA, SBOM & Secrets with GitHub Actions, and CI/CD SCA, SBOM & Secrets with Bitbucket Pipelines.
Quick start (GitHub Actions)
# .github/workflows/security.yml
- name: WASViking · SCA
run: ./wasviking-sentinel sbom --path . --fail-on high --submit
env:
WASV_API_KEY: ${{ secrets.WASVIKING_CI_KEY }}
- name: WASViking · Secrets
run: ./wasviking-sentinel secrets --path . --verify --submit
env:
WASV_API_KEY: ${{ secrets.WASVIKING_CI_KEY }}
- name: WASViking · Cloud DAST
run: ./wasviking-sentinel scan --template prod-web-strict --target https://staging.example.com
env:
WASV_API_KEY: ${{ secrets.WASVIKING_CI_KEY }}
The same three commands run on Bitbucket Pipelines (worked example in CI/CD SCA, SBOM & Secrets with Bitbucket Pipelines), GitLab CI, CircleCI, Jenkins, and Buildkite. Any Linux runner that can execute the binary works.
Authentication
export WASV_API_KEY=wv_live_xxxxxxxxxxxxxxxxxxxxxxxx
./wasviking-sentinel version
API keys are created in the portal under Settings → API Keys. The key needs the right scopes for what you actually do:
| Subcommand | Required scopes |
|---|---|
sbom (license check only) |
any active org key |
sbom --submit |
sca:submit |
secrets (license check only) |
any active org key |
secrets --submit |
secrets:submit |
scan |
scans:run, templates:read |
Use a dedicated CI key with only the scopes you need.
License check (preflight)
Every sbom, secrets, and CI-side scan invocation calls
POST /api/v1/sentinel/preflight before doing any work. The preflight
is mandatory: an empty or rejected API key blocks the run.
--api-key(or envWASV_API_KEY) is required, even when you are not submitting results.- Successful approvals cache at
~/.wasviking/preflight_cache.json(mode0600) for 30 minutes. - 24-hour grace window if the API is unreachable but a recent approval exists on disk.
- Active rejection (401 / 403) does not get the grace window: revoked keys block on the next cache expiration.
- Cache invalidates on key rotation (cache key is a truncated SHA-256 of the API key).
For the full preflight model, see the License check section on the sbom page.
SCA gate (sbom)
./wasviking-sentinel sbom \
--path . \
--app-name checkout-api \
--app-version "$CI_COMMIT_TAG" \
--fail-on high \
--submit
Behavior:
- Walk manifests under
--path(recursive). - Build a CycloneDX 1.5 SBOM.
- Enrich with OSV.dev advisories and CISA KEV.
- Apply
--fail-onpolicy. - If
--submit, POST to the WASViking API.
Exit codes:
| Exit code | Meaning |
|---|---|
| 0 | OK. Nothing at or above --fail-on. |
| 1 | Generic failure (parse, IO, network). |
| 2 | Invalid argument, or --submit without an API key. |
| 70 | KEV-flagged finding at or above --fail-on. |
| 71 | Findings at or above --fail-on, none of them in KEV. |
| 79 | Coverage failure. See below. |
A failed OSV enrichment or a failed submission warns and keeps going. Neither one fails the build on its own.
Default threshold: high. Full flag reference:
wasviking-sentinel sbom.
Secrets gate (secrets)
./wasviking-sentinel secrets \
--path . \
--git \
--verify \
--fail-on high \
--submit
Behavior:
- Walk the working tree under
--path. - With
--git, also walk the local git history. - Match against 32 detectors.
- With
--verify, probe provider identity endpoints (read-only) for the 10 detectors that support live verification. - Apply
--fail-onpolicy. - If
--submit, POST to the WASViking API (hash + masked preview; raw secrets never leave the host).
Exit codes:
| Exit code | Meaning |
|---|---|
| 0 | OK. Nothing at or above --fail-on. |
| 1 | Generic failure. |
| 2 | Invalid argument, or --submit without an API key. |
| 73 | A credential at or above --fail-on that --verify confirmed live. |
| 74 | Matches at or above --fail-on that were not verified. |
| 79 | Coverage failure. See below. |
Default threshold: high. Full flag reference:
wasviking-sentinel secrets.
Cloud DAST gate (scan)
./wasviking-sentinel scan \
--template prod-web-strict \
--target https://staging.example.com
The scan subcommand triggers a cloud scan using an org-scoped scan
template. The template is resolved server-side, so secrets configured
in the template never reach the CI runner. The binary tracks the scan
to completion and exits with a policy-aware code.
Common exit codes:
| Exit code | Meaning |
|---|---|
| 0 | Scan completed, findings under the threshold. |
| 1 | Findings at or above the threshold, or an unmapped failure (provisioning rejected, engine error, timeout). |
| 2 | Invalid argument, for example a --baseline other than all or new. |
| 70 | Scan template not found for this organization. |
| 71 | Scan template not accessible to this organization. |
| 79 | Coverage failure on the local --sca or --secrets pass. See below. |
Default threshold: critical.
scan can also run the local SCA and secrets gates in the same pass,
with --sca and --secrets. Those run before the cloud scan starts and
keep their own codes (70, 71, 73, 74). On a run with --sca, a 70 means
a KEV-flagged dependency, not a missing template.
scan is the cloud counterpart of the local sbom and secrets
gates. It does not require the mTLS agent to be registered.
Coverage failures (exit 79)
A gate that scans nothing will find nothing, and without a check that looks exactly like a clean run. Exit 79 exists to keep those two apart.
The agent reads the scan root before walking it, then compares what it covered against what was there. When the root holds entries and the walk reached none of them, the run stops with exit 79 instead of reporting a pass. The same applies when the root cannot be listed at all, usually a permission problem on the runner.
What exit 79 is not: a finding, and a complaint about an empty
project. A repository with no files, or one whose entire content sits in
excluded directories such as node_modules, walks correctly and passes.
So does a project with no supported manifest, which reports how many
entries it walked so you can see the difference.
Common causes, in the order worth checking:
| Cause | What to do |
|---|---|
| The path does not point where you think it does. | Check the Root: line in the log against the repository layout. |
| The build step lacks permission to read the checkout. | Fix the ownership or mode on the runner. |
| The path is a mount or volume that is not populated yet. | Move the gate after the step that populates it. |
Directory exclusions never cause exit 79. They apply to
sub-directories only, so a project checked out into a directory named
build, dist, target or vendor is scanned normally. When that
happens the log says so explicitly.
Pointing a path at a .git directory is refused up front with a message
pointing at --git, which is the flag that scans commit history.
Concurrency and metering
For the scan subcommand, the platform enforces two limits per
organization:
- A concurrent-scan cap. Provisioning is rejected with HTTP 429 once the org's in-flight CI scans reach the cap.
- A monthly metering window. Starting a scan is rejected with HTTP 402 once the meter is exhausted.
The agent neither queues nor retries in either case. The rejection reaches the build log and the step exits 1, so a capped pipeline fails fast instead of holding a runner for nothing. Both events are surfaced in the portal's CI Usage tab.
What you should pin in CI
- Binary version. Distribute a specific signed release and verify with cosign before running.
- Template slug for
scan. Templates are versioned server-side; the slug always resolves to the active version of the template. - API key scopes. Use the minimum scope per pipeline stage.
--fail-onthresholds per pipeline lane (strict onmain, permissive on feature branches).
What this binary is NOT in CI mode
- It does not open the mTLS tunnel.
runis the tunneling mode;sbom,secrets, andscanare one-shot CI subcommands. - It does not call the portal's session login. The API key is the credential.
- It does not store findings locally beyond the SBOM / report
artifacts in
--out. Persistence is portal-side after--submit.
