How to: run VEXViper as a CronJob
Maintained in seebom-labs/VEXViper — edit it there.
Goal: VEXViper runs every few hours in your cluster, assesses every new BOMHort finding, uploads OpenVEX statements, and you can see them applied in BOMHort.
Prerequisites
- A BOMHort ≥ 0.7 api-gateway reachable from the cluster with
AUTH_ENABLED=trueand an API key (or service token) that may upload. helm3 andkubectlagainst the target cluster.- The source repositories of your products reachable from the cluster (public GitHub works out of the box; private hosts need a token, see step 3).
Steps
Create the namespace and the secret. The chart reads
api-key;github-tokenis optional and only needed for GitHub Models or private clones.kubectl create namespace vexviper kubectl -n vexviper create secret generic vexviper \ --from-literal=api-key="$BOMHORT_API_KEY"Write
values.yaml. The heuristic provider needs no key and is the safe baseline; switch to an LLM later with How to: set up an LLM provider.mode: cronjob schedule: "0 */6 * * *" bomhort: url: http://bomhort-api-gateway.bomhort.svc:8080 existingSecret: vexviper upload: true persistence: enabled: true # keeps repo clones, verdict cache and watch state between runs size: 10Gi config: llm: provider: heuristic watch: reassess_after: 168h # re-check open verdicts weekly; not_affected/fixed stay closed concurrency: 2Map SBOMs to repositories when BOMHort has no
source_repofor them. VEXViper first uses the SBOM’ssource_repo/source_reffrom BOMHort, then VCS hints in the SBOM, then these pins.matchis compared with the SBOM id, document name and file name (glob allowed);{version}expands from the file name.config: repo: sboms: - match: "kubelb-*" repo: kubermatic/kubelb - match: "my-service.cdx.json" repo: https://gitlab.example.com/team/my-service@release-{version}Private https clones use
GITHUB_TOKENfrom the secret keygithub-token(kubectl -n vexviper create secret generic vexviper --from-literal=api-key=… --from-literal=github-token=…).Install the chart.
helm install vexviper oci://ghcr.io/seebom-labs/charts/vexviper \ -n vexviper -f values.yamlRun the first pass now instead of waiting for the schedule.
kubectl -n vexviper create job --from=cronjob/vexviper vexviper-first kubectl -n vexviper logs -f job/vexviper-firstThe log ends with one
assessedline per finding (vuln,purl,status,confidence) and anuploadedline per SBOM.
Verify
BOMHort shows the statements on the SBOM. Every finding VEXViper handled now carries
vex_status, andvex_toolingstarts withvexviper/:curl -s -H "X-API-Key: $BOMHORT_API_KEY" \ "$BOMHORT_URL/api/v1/sboms/<sbom-id>/vulnerabilities" \ | jq '.[] | {vuln_id, purl, vex_status, vex_tooling}'In the BOMHort UI the SBOM’s vulnerability list shows the VEX badge and the
under_investigation/not_affectedcounts move.The next run skips what is already done. Trigger a second job and look for
skippedin the summary; nothing should be re-assessed unlessreassess_afterexpired. Verdicts written by people (any othervex_tooling) are never touched.
When it does not work
401on upload — the key in the secret is not accepted. Check the chartNOTES.txtwarning and that BOMHort runs withAUTH_ENABLED=trueand this key.- Every statement is
under_investigation— VEXViper could not clone the product repository (repo unavailablein the log). Add a pin in step 3 or setsource_repoon the SBOM in BOMHort (PATCH /api/v1/sboms/{id}). - Statements uploaded but
vex_statusstays empty — the statement did not match. VEXViper matches on the exactvuln_id+purlBOMHort returned; runvexviper generate --sbom <id> --upload --wait 2mfrom a laptop to get a per- statement applied/not-matched report. - Run takes longer than
timeout(30 m) — raiseconfig.timeoutor lowerwatch.concurrency; govulncheck on large Go modules is the usual cost. - Costs —
vexviper_findings_*metrics exist only inmode: deployment; for CronJobs read the usage summary at the end of the job log.
Reference: README, Integration.