How to: set up an LLM provider
Maintained in seebom-labs/VEXViper — edit it there.
Goal: VEXViper asks a language model for the verdict instead of using only the built-in rules, with a spend cap, and the model’s answer still passes the deterministic guardrails.
The provider only sees the evidence VEXViper collected (govulncheck result,
dependency depth, lockfile graph, OSV data). A not_affected without strong
evidence is always downgraded to under_investigation, whatever the model says.
Prerequisites
- VEXViper working with
provider: heuristic(see How to: run VEXViper as a CronJob). - One of:
- an OpenAI-compatible endpoint and key (OpenAI, Azure OpenAI, Ollama, vLLM, LiteLLM …);
- a GitHub account with a Copilot subscription — for GitHub Models a
fine-grained PAT with the
models: readpermission (billed to the plan); - the GitHub Copilot CLI installed and logged in on the machine that runs VEXViper (laptop or CI runner — the VEXViper container image does not ship it).
Steps
Pick one provider.
A. OpenAI-compatible endpoint
Configure:
llm: provider: openai min_confidence: 0.6 openai: base_url: https://api.openai.com/v1 # Ollama: http://localhost:11434/v1 model: gpt-4o-mini api_key_env: OPENAI_API_KEY timeout: 120sExport the key and run:
export OPENAI_API_KEY=… vexviper generate --sbom my-service.cdx.json --provider openaiHelm: put the key into the secret key
openai-api-key; the chart wires it toOPENAI_API_KEY.
B. GitHub Models with a Copilot subscription (works in CronJobs and CI)
Create a fine-grained personal access token with Account permissions → Models: Read-only. In GitHub Actions the workflow token works with
permissions: models: read.Configure:
llm: provider: github github: model: openai/gpt-4.1-mini # any id from https://github.com/marketplace/models token_env: GITHUB_TOKENRun:
export GITHUB_TOKEN=… vexviper generate --sbom my-service.cdx.json --provider githubHelm: secret key
github-token→GITHUB_TOKEN; setconfig.llm.provider: githubinvalues.yaml.
C. GitHub Copilot CLI (laptop or CI runner, no API key)
Install and log in once (
copilot, then/login), or let it usegh:gh auth login export GH_TOKEN=$(gh auth token) copilot --versionConfigure:
llm: provider: copilot copilot: command: copilot # model: gpt-5 # empty = CLI default in_repo: true # Copilot may read the cloned product code (never write) timeout: 180sRun:
vexviper generate --sbom my-service.cdx.json --provider copilotVEXViper starts
copilot -p … -s --output-format json --no-ask-user --deny-tool=shell --deny-tool=write --deny-tool=editper finding (about 15 s each) and bills premium requests to your Copilot seat.
Cap the spend
Whichever provider: set a budget per run (CLI) or per watch pass (CronJob). Findings beyond the cap are deferred — no statement, SBOM not marked done — and picked up by the next pass.
llm:
budget:
max_calls: 200
max_tokens: 0 # OpenAI / GitHub Models
max_premium_requests: 50 # Copilot CLI
Keep cache.enabled: true (default). Identical questions (same model, product
commit, vulnerability, package and evidence) reuse the stored verdict instead of
paying again.
Verify
- The CLI summary ends with
provider usage: N calls, … tokens, … premium requests, model=…; the per-findingassessedlog lines showprovider=openai|github|copilotinstead ofheuristic. - Statements in the document carry the model’s
justificationandimpact_statement; a downgraded one has the original verdict instatus_notes. vexviper watchwrites the lifetime usage to the state file (usage,last_pass_usage); inmode: deploymentthe same numbers are on/metrics.
When it does not work
- All verdicts come from
heuristicalthough a provider is set — the provider failed and VEXViper fell back. The log has the error: wrongbase_url, missing env var (api_key_env/token_envname, not the value), or a model id the endpoint does not know. 401/403from GitHub Models — the PAT lacksmodels: read, or the organisation has disabled GitHub Models.- Copilot CLI hangs or asks a question — an old CLI without
--no-ask-user; update it.copilotnot found: setcopilot.commandto the full path. - Many
under_investigationdespite the model sayingnot_affected— expected without strong evidence (no govulncheck result, no lockfile graph). Give VEXViper the repository (repo.sbomspins) so it can collect evidence; do not setallow_unsupported_not_affected. - Budget hit every pass — raise
max_calls, or look at cache hits in the usage line: a changing product commit on every run defeats the cache.
Reference: README – Assessment providers, Integration – using a Copilot subscription.