<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>BOMHort on BOMHort Documentation</title><link>https://docs.bomhort.dev/</link><description>Recent content in BOMHort on BOMHort Documentation</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://docs.bomhort.dev/index.xml" rel="self" type="application/rss+xml"/><item><title>Overview</title><link>https://docs.bomhort.dev/docs/ecosystem/go-client/overview/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.bomhort.dev/docs/ecosystem/go-client/overview/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Maintained in &lt;a href="https://github.com/seebom-labs/bomhort-go/blob/main/README.md"&gt;seebom-labs/bomhort-go&lt;/a&gt; — edit it there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/seebom-labs/bomhort-go/actions/workflows/ci.yml"&gt;&lt;img src="https://github.com/seebom-labs/bomhort-go/actions/workflows/ci.yml/badge.svg" alt="CI"&gt;&lt;/a&gt;
&lt;a href="https://github.com/seebom-labs/bomhort-go/actions/workflows/e2e.yml"&gt;&lt;img src="https://github.com/seebom-labs/bomhort-go/actions/workflows/e2e.yml/badge.svg" alt="E2E"&gt;&lt;/a&gt;
&lt;a href="https://pkg.go.dev/github.com/seebom-labs/bomhort-go"&gt;&lt;img src="https://pkg.go.dev/badge/github.com/seebom-labs/bomhort-go.svg" alt="Go Reference"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The Go client for the &lt;a href="https://github.com/seebom-labs/BOMHort"&gt;BOMHort&lt;/a&gt; REST API.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Complete:&lt;/strong&gt; every public endpoint of the BOMHort api-gateway — SBOMs, findings, dependency trees, licenses, VEX, projects, clusters, namespaces, fleet, statistics, search, push-model uploads and source attribution (&lt;a href="https://docs.bomhort.dev/docs/ecosystem/go-client/api-coverage/"&gt;coverage&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zero dependencies:&lt;/strong&gt; standard library only.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Production behaviour built in:&lt;/strong&gt; API key / service token auth, client-side rate limiting, 429 retries honouring &lt;code&gt;Retry-After&lt;/code&gt;, typed errors, iterator-based pagination, streaming downloads.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Testable:&lt;/strong&gt; &lt;a href="https://github.com/seebom-labs/bomhort-go/blob/main/bomhorttest"&gt;&lt;code&gt;bomhorttest&lt;/code&gt;&lt;/a&gt; is an in-memory fake gateway with BOMHort&amp;rsquo;s real upload, VEX scoping and matching semantics.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Verified against real BOMHort:&lt;/strong&gt; every PR runs the integration suite with strict decoding against the pinned BOMHort release; a weekly job also runs it against BOMHort &lt;code&gt;main&lt;/code&gt; to catch API drift.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Versioned with BOMHort:&lt;/strong&gt; &lt;code&gt;bomhort-go v0.8.x&lt;/code&gt; is the client for BOMHort 0.8.x (&lt;a href="https://docs.bomhort.dev/docs/ecosystem/go-client/compatibility/"&gt;compatibility&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Extracted from &lt;a href="https://github.com/seebom-labs/VEXViper"&gt;VEXViper&lt;/a&gt;&amp;rsquo;s &lt;code&gt;internal/bomhort&lt;/code&gt; (&lt;a href="https://github.com/seebom-labs/VEXViper/blob/main/docs/INTEGRATION.md#8-should-the-bomhort-go-client-be-its-own-module"&gt;why&lt;/a&gt;).&lt;/p&gt;</description></item><item><title>Overview</title><link>https://docs.bomhort.dev/docs/ecosystem/vexviper/overview/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.bomhort.dev/docs/ecosystem/vexviper/overview/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Maintained in &lt;a href="https://github.com/seebom-labs/VEXViper/blob/main/README.md"&gt;seebom-labs/VEXViper&lt;/a&gt; — edit it there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;LLM-assisted OpenVEX generation for &lt;a href="https://bomhort.dev"&gt;BOMHort&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;BOMHort ingests SBOMs, matches them against OSV and applies OpenVEX statements — but it
cannot &lt;em&gt;produce&lt;/em&gt; VEX. Every CVE stays &amp;ldquo;effective&amp;rdquo; until somebody hand-writes an OpenVEX
document. VEXViper closes that loop:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;BOMHort findings ──► resolve product repo ──► clone + govulncheck + evidence
 ▲ │
 │ ▼
 └──── upload ◄── validated OpenVEX ◄── assessment (heuristic | OpenAI-compatible | MCP tool)
&lt;/code&gt;&lt;/pre&gt;&lt;ol&gt;
&lt;li&gt;reads the vulnerability findings BOMHort already computed for an SBOM (&lt;code&gt;vuln_id&lt;/code&gt;, &lt;code&gt;purl&lt;/code&gt;,
&lt;code&gt;fixed_version&lt;/code&gt;, &lt;code&gt;vex_status&lt;/code&gt;, …) — BOMHort is the &lt;strong&gt;single source of truth&lt;/strong&gt;, VEXViper
does not rescan anything;&lt;/li&gt;
&lt;li&gt;resolves the product&amp;rsquo;s source repository (from the SBOM&amp;rsquo;s VCS metadata / PURLs, or
&lt;code&gt;--repo owner/name@ref&lt;/code&gt;), clones it shallowly and gathers &lt;strong&gt;deterministic evidence&lt;/strong&gt;:
installed vs fixed version, direct/transitive depth, &lt;code&gt;govulncheck&lt;/code&gt; reachability for Go
products, lockfile-graph / manifest / import evidence for npm, PyPI, Cargo, RubyGems,
Composer, Maven, NuGet and Dart products (see &lt;a href="#evidence-per-ecosystem"&gt;Evidence per ecosystem&lt;/a&gt;),
RustSec vulnerable-function references for Rust, Go symbol references, OSV details;&lt;/li&gt;
&lt;li&gt;asks an assessment provider for &lt;code&gt;status/justification/confidence/reasoning&lt;/code&gt; per finding —
a rules-only &lt;strong&gt;heuristic&lt;/strong&gt; (default, offline), any &lt;strong&gt;OpenAI-compatible&lt;/strong&gt; endpoint,
&lt;strong&gt;GitHub Models&lt;/strong&gt; or the &lt;strong&gt;GitHub Copilot CLI&lt;/strong&gt; (your Copilot subscription), or a tool on a
&lt;strong&gt;configurable MCP server&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;applies guardrails and emits an OpenVEX document built with
&lt;a href="https://github.com/openvex/go-vex"&gt;&lt;code&gt;openvex/go-vex&lt;/code&gt;&lt;/a&gt; whose every statement passes
&lt;code&gt;Statement.Validate()&lt;/code&gt; and reuses BOMHort&amp;rsquo;s &lt;code&gt;(vuln_id, purl)&lt;/code&gt; verbatim so BOMHort&amp;rsquo;s
exact-match join applies it;&lt;/li&gt;
&lt;li&gt;optionally uploads it through &lt;code&gt;POST /api/v1/sboms/upload&lt;/code&gt; and waits until BOMHort shows
the new &lt;code&gt;vex_status&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It is also an &lt;strong&gt;MCP server&lt;/strong&gt; itself, so an LLM host (Claude Desktop, VS Code/Copilot, an
agent) can drive or review the triage interactively.&lt;/p&gt;</description></item><item><title>Testing</title><link>https://docs.bomhort.dev/docs/development/testing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.bomhort.dev/docs/development/testing/</guid><description>&lt;h2 id="quick-start"&gt;Quick Start&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Run all tests&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd backend &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; go test ./... -count&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Run with verbose output&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go test ./... -v -count&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Run tests for a specific package&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go test ./internal/vex/ -v -count&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Run a single test by name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go test ./internal/vex/ -run TestNormalizeVulnID -v
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Run with race detection (used in CI)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go test ./... -count&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; -race
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Check coverage&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go test ./... -coverprofile&lt;span style="color:#f92672"&gt;=&lt;/span&gt;coverage.out
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go tool cover -html&lt;span style="color:#f92672"&gt;=&lt;/span&gt;coverage.out
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="test-structure"&gt;Test Structure&lt;/h2&gt;
&lt;p&gt;Tests live next to the code they test, using Go&amp;rsquo;s &lt;code&gt;_test.go&lt;/code&gt; convention:&lt;/p&gt;</description></item><item><title>Why we renamed SeeBOM to BOMHort</title><link>https://docs.bomhort.dev/docs/getting-started/rename/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.bomhort.dev/docs/getting-started/rename/</guid><description>&lt;h2 id="what-changed"&gt;What changed&lt;/h2&gt;
&lt;p&gt;The project name is now &lt;strong&gt;BOMHort&lt;/strong&gt; (formerly known as &lt;strong&gt;SeeBOM&lt;/strong&gt;).&lt;/p&gt;
&lt;p&gt;The rename only affects branding and repository naming. The mission and technical direction stay the same: Kubernetes-native SBOM ingestion, enrichment, visualization, and governance.&lt;/p&gt;
&lt;h2 id="why-we-renamed"&gt;Why we renamed&lt;/h2&gt;
&lt;p&gt;The name &lt;strong&gt;SeeBOM&lt;/strong&gt; served us well, but it created confusion: spoken out loud, it sounds very similar to &lt;strong&gt;CBOM&lt;/strong&gt; (Cryptography Bill of Materials).&lt;/p&gt;
&lt;p&gt;In the xBOM ecosystem, names like CBOM usually refer to &lt;strong&gt;BOM document types&lt;/strong&gt;, not to tools. Ahead of OpenSSF sandbox intake, we wanted a project name that is clearly identifiable as a platform.&lt;/p&gt;</description></item><item><title>Contributor Ladder</title><link>https://docs.bomhort.dev/docs/development/contributor-ladder/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.bomhort.dev/docs/development/contributor-ladder/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;BOMHort uses a transparent contributor ladder inspired by the &lt;a href="https://github.com/cncf/project-template/blob/main/CONTRIBUTOR_LADDER.md"&gt;CNCF contributor ladder template&lt;/a&gt;. Each rung provides clear expectations and privileges, so you always know what the next step looks like.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;┌─────────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ Maintainer — merge, release, direction │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├─────────────────────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ Reviewer — approve PRs in their area │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├─────────────────────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ Contributor — regular code/docs/tests │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├─────────────────────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;│ Community — issues, discussions, usage │
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└─────────────────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="-community-member"&gt;🌱 Community Member&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Who:&lt;/strong&gt; Anyone who uses BOMHort, files issues, or participates in discussions.&lt;/p&gt;</description></item><item><title>SBOM Parsers</title><link>https://docs.bomhort.dev/docs/development/parsers/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.bomhort.dev/docs/development/parsers/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;BOMHort supports multiple SBOM formats through a &lt;strong&gt;format-detection dispatch layer&lt;/strong&gt; at &lt;code&gt;internal/sbom/parse.go&lt;/code&gt;. When a file is processed, the dispatcher:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Reads the raw bytes&lt;/li&gt;
&lt;li&gt;Probes JSON fields to identify the format&lt;/li&gt;
&lt;li&gt;Routes to the appropriate parser backend&lt;/li&gt;
&lt;li&gt;Returns a unified &lt;code&gt;ParseResult&lt;/code&gt; (SBOM metadata + packages)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This happens transparently — the parsing worker simply calls &lt;code&gt;sbom.Parse(reader, sourceFile, hash)&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="supported-formats"&gt;Supported Formats&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Format&lt;/th&gt;
 &lt;th&gt;File Extension&lt;/th&gt;
 &lt;th&gt;Detection Method&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;SPDX 2.3 JSON&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;.spdx.json&lt;/code&gt;, &lt;code&gt;.json&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;&amp;quot;spdxVersion&amp;quot;&lt;/code&gt; field present&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;In-toto attestation (SPDX)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;.spdx.json&lt;/code&gt;, &lt;code&gt;.json&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;&amp;quot;predicateType&amp;quot;&lt;/code&gt; contains &amp;ldquo;spdx&amp;rdquo;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;CycloneDX 1.0–1.7 JSON&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;.cdx.json&lt;/code&gt;, &lt;code&gt;.json&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;&amp;quot;bomFormat&amp;quot;: &amp;quot;CycloneDX&amp;quot;&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="parser-backends"&gt;Parser Backends&lt;/h2&gt;
&lt;h3 id="built-in-default"&gt;Built-in (Default)&lt;/h3&gt;
&lt;p&gt;The default parsers use &lt;code&gt;goccy/go-json&lt;/code&gt; for high-performance streaming and add &lt;strong&gt;zero additional dependencies&lt;/strong&gt; beyond what BOMHort already requires.&lt;/p&gt;</description></item><item><title>AI Usage Policy</title><link>https://docs.bomhort.dev/docs/development/ai-policy/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.bomhort.dev/docs/development/ai-policy/</guid><description>&lt;h2 id="policy"&gt;Policy&lt;/h2&gt;
&lt;p&gt;BOMHort &lt;strong&gt;welcomes AI-assisted contributions&lt;/strong&gt;. We use AI tools extensively in our own development workflow (see &lt;a href="https://github.com/seebom-labs/BOMHort/blob/main/AGENTS.md"&gt;AGENTS.md&lt;/a&gt;). However, we have clear rules to ensure accountability and code quality.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="rules"&gt;Rules&lt;/h2&gt;
&lt;h3 id="1-you-own-it"&gt;1. You own it&lt;/h3&gt;
&lt;p&gt;If you use AI to generate code, &lt;strong&gt;you are responsible&lt;/strong&gt; for that code. Review it, test it, and understand it before submitting. &amp;ldquo;The AI wrote it&amp;rdquo; is not an excuse for bugs, security issues, or convention violations.&lt;/p&gt;
&lt;h3 id="2-sign-your-commits"&gt;2. Sign your commits&lt;/h3&gt;
&lt;p&gt;Every commit must carry your DCO sign-off (&lt;code&gt;Signed-off-by: Your Name &amp;lt;your@email.com&amp;gt;&lt;/code&gt;). This is &lt;strong&gt;non-negotiable&lt;/strong&gt; — it certifies that &lt;em&gt;you&lt;/em&gt; are the author and take responsibility, regardless of whether AI assisted you.&lt;/p&gt;</description></item><item><title>How to: Upload VEX</title><link>https://docs.bomhort.dev/docs/ecosystem/go-client/how-to-upload-vex/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.bomhort.dev/docs/ecosystem/go-client/how-to-upload-vex/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Maintained in &lt;a href="https://github.com/seebom-labs/bomhort-go/blob/main/docs/VEX.md"&gt;seebom-labs/bomhort-go&lt;/a&gt; — edit it there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is the contract between a VEX producer and BOMHort ≥ 0.7.0, as implemented in BOMHort&amp;rsquo;s parser (&lt;code&gt;internal/vex/parser.go&lt;/code&gt;), parsing worker (&lt;code&gt;cmd/parsing-worker/vex_scope.go&lt;/code&gt;, &lt;code&gt;vex_rescue.go&lt;/code&gt;) and queries (&lt;code&gt;internal/clickhouse&lt;/code&gt;). The E2E suite verifies each rule below against a real BOMHort, and &lt;code&gt;bomhorttest&lt;/code&gt; implements the same rules.&lt;/p&gt;
&lt;h2 id="1-every-statement-belongs-to-exactly-one-sbom"&gt;1. Every statement belongs to exactly one SBOM&lt;/h2&gt;
&lt;p&gt;BOMHort has no fleet-wide VEX. A statement only ever affects findings of the SBOM it is &lt;strong&gt;scoped&lt;/strong&gt; to:&lt;/p&gt;</description></item><item><title>Integration with BOMHort</title><link>https://docs.bomhort.dev/docs/ecosystem/vexviper/integration/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.bomhort.dev/docs/ecosystem/vexviper/integration/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Maintained in &lt;a href="https://github.com/seebom-labs/VEXViper/blob/main/docs/INTEGRATION.md"&gt;seebom-labs/VEXViper&lt;/a&gt; — edit it there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This document records how VEXViper couples to BOMHort, which API contract it relies on,
and what an upstream integration could look like.&lt;/p&gt;
&lt;h2 id="1-integration-model"&gt;1. Integration model&lt;/h2&gt;
&lt;p&gt;BOMHort (&lt;code&gt;backend/&lt;/code&gt;, Go 1.25, stdlib HTTP, ClickHouse) exposes &lt;strong&gt;no plugin mechanism&lt;/strong&gt;:
no Go &lt;code&gt;plugin&lt;/code&gt; loading, no gRPC/webhook hooks, no MCP. Its contribution guidelines require
stdlib-only tests, discourage frameworks and ask contributors to &lt;em&gt;ask first&lt;/em&gt; before adding
Go dependencies. VEXViper needs &lt;code&gt;openvex/go-vex&lt;/code&gt;, the MCP Go SDK, &lt;code&gt;packageurl-go&lt;/code&gt; and
&lt;code&gt;yaml.v3&lt;/code&gt; (plus the stdlib-only &lt;a href="https://github.com/seebom-labs/bomhort-go"&gt;&lt;code&gt;bomhort-go&lt;/code&gt;&lt;/a&gt; client), so the correct integration is an &lt;strong&gt;out-of-tree sidecar speaking the public REST
API&lt;/strong&gt; (&lt;code&gt;docs/api-reference&lt;/code&gt; calls this &amp;ldquo;custom tooling&amp;rdquo;). Benefits:&lt;/p&gt;</description></item><item><title>How to: Migrate from VEXViper's client</title><link>https://docs.bomhort.dev/docs/ecosystem/go-client/how-to-migrate-from-vexviper/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.bomhort.dev/docs/ecosystem/go-client/how-to-migrate-from-vexviper/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Maintained in &lt;a href="https://github.com/seebom-labs/bomhort-go/blob/main/docs/MIGRATING-FROM-VEXVIPER.md"&gt;seebom-labs/bomhort-go&lt;/a&gt; — edit it there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;bomhort-go started as VEXViper&amp;rsquo;s &lt;code&gt;internal/bomhort&lt;/code&gt; package and its &lt;code&gt;bomhorttest&lt;/code&gt; fake. It keeps the same shape (functional options, &lt;code&gt;APIError&lt;/code&gt;, &lt;code&gt;UploadVEX(ctx, filename, doc, sbomID)&lt;/code&gt;, sliding-window &lt;code&gt;RateLimiter&lt;/code&gt;), but extends it to the full BOMHort API, which required a few breaking changes.&lt;/p&gt;
&lt;h2 id="imports"&gt;Imports&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-diff" data-lang="diff"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-import &amp;#34;github.com/seebom-labs/vexviper/internal/bomhort&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;-import &amp;#34;github.com/seebom-labs/vexviper/internal/bomhort/bomhorttest&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;+import bomhort &amp;#34;github.com/seebom-labs/bomhort-go&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;+import &amp;#34;github.com/seebom-labs/bomhort-go/bomhorttest&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="client"&gt;Client&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;VEXViper&lt;/th&gt;
 &lt;th&gt;bomhort-go&lt;/th&gt;
 &lt;th&gt;Notes&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;ListSBOMs(ctx, page, pageSize, search)&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;ListSBOMs(ctx, &amp;amp;bomhort.SBOMListOptions{ListOptions: bomhort.ListOptions{Page: page, PageSize: pageSize}, Search: search})&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;options struct; &lt;code&gt;nil&lt;/code&gt; = server defaults&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;AllSBOMs(ctx)&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;AllSBOMs(ctx, nil)&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;or iterate lazily with &lt;code&gt;SBOMs(ctx, nil)&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;VEXStatements(ctx, page, pageSize)&lt;/code&gt; (one page)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;ListVEXStatements(ctx, &amp;amp;bomhort.ListOptions{Page: page, PageSize: pageSize})&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;VEXStatements&lt;/code&gt; is now the iterator&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;AllVEXStatements(ctx)&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;unchanged&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;FindSBOM(ctx, ref)&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;unchanged&lt;/td&gt;
 &lt;td&gt;now also matches uploaded filenames (&lt;code&gt;pushed/&amp;lt;uuid&amp;gt;-&amp;lt;name&amp;gt;&lt;/code&gt;) and uses &lt;code&gt;?search=&lt;/code&gt; first&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;Vulnerabilities(ctx, id)&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;Vulnerabilities(ctx, id, nil)&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;&amp;amp;bomhort.VulnerabilityOptions{Scope: bomhort.ScopeDirect}&lt;/code&gt; filters by dependency scope (BOMHort ≥ 0.8)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;Healthy&lt;/code&gt;, &lt;code&gt;Dependencies&lt;/code&gt;, &lt;code&gt;DownloadSBOM&lt;/code&gt;, &lt;code&gt;UploadVEX&lt;/code&gt;, &lt;code&gt;BaseURL&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;unchanged&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;WithAPIKey&lt;/code&gt;, &lt;code&gt;WithServiceToken&lt;/code&gt;, &lt;code&gt;WithHTTPClient&lt;/code&gt;, &lt;code&gt;WithRateLimit&lt;/code&gt;, &lt;code&gt;WithMaxRetries&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;unchanged&lt;/td&gt;
 &lt;td&gt;new: &lt;code&gt;WithRateLimiter&lt;/code&gt;, &lt;code&gt;WithUserAgent&lt;/code&gt;, &lt;code&gt;WithStrictDecoding&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;IsNotFound(err)&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;unchanged&lt;/td&gt;
 &lt;td&gt;new: &lt;code&gt;IsBadRequest&lt;/code&gt;, &lt;code&gt;IsUnauthorized&lt;/code&gt;, &lt;code&gt;IsForbidden&lt;/code&gt;, &lt;code&gt;IsRateLimited&lt;/code&gt;, &lt;code&gt;IsUnavailable&lt;/code&gt;, &lt;code&gt;StatusCode&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Behaviour changes:&lt;/p&gt;</description></item><item><title>Testing</title><link>https://docs.bomhort.dev/docs/ecosystem/go-client/testing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.bomhort.dev/docs/ecosystem/go-client/testing/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Maintained in &lt;a href="https://github.com/seebom-labs/bomhort-go/blob/main/docs/TESTING.md"&gt;seebom-labs/bomhort-go&lt;/a&gt; — edit it there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;bomhort-go is tested at four levels. The first three run without network access or Docker.&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Level&lt;/th&gt;
 &lt;th&gt;Where&lt;/th&gt;
 &lt;th&gt;Command&lt;/th&gt;
 &lt;th&gt;Runs in CI&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Unit / wire contract&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;*_test.go&lt;/code&gt; in the root package&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;make test-race&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;every push/PR (&lt;code&gt;ci.yml&lt;/code&gt;)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Fake gateway&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;bomhorttest/server_test.go&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;make test-race&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;every push/PR&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Examples&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;example_test.go&lt;/code&gt; (&lt;code&gt;// Output:&lt;/code&gt; checked)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;make test&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;every push/PR&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Integration / E2E&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;test/integration&lt;/code&gt; (&lt;code&gt;-tags integration&lt;/code&gt;)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;make test-integration&lt;/code&gt; / &lt;code&gt;make e2e&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;every push/PR against the pinned BOMHort, weekly also against BOMHort &lt;code&gt;main&lt;/code&gt; (&lt;code&gt;e2e.yml&lt;/code&gt;)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="unit-tests"&gt;Unit tests&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;endpoints_test.go&lt;/code&gt; is a table with one row per endpoint. Each row asserts method, escaped path, query string, headers, request body and the decoded response. Add a row for every new method.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;client_test.go&lt;/code&gt; covers auth headers, retries on 429 (&lt;code&gt;Retry-After&lt;/code&gt; and back-off; the sleep function is injected), context cancellation, error decoding and strict decoding.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;misc_test.go&lt;/code&gt; covers upload validation, pagination helpers, &lt;code&gt;FindSBOM&lt;/code&gt; and streaming downloads; &lt;code&gt;ratelimit_test.go&lt;/code&gt; covers the limiter.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;make cover&lt;/code&gt; enforces a minimum total coverage (&lt;code&gt;COVER_MIN&lt;/code&gt;, default 85 %).&lt;/p&gt;</description></item><item><title>API Coverage</title><link>https://docs.bomhort.dev/docs/ecosystem/go-client/api-coverage/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.bomhort.dev/docs/ecosystem/go-client/api-coverage/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Maintained in &lt;a href="https://github.com/seebom-labs/bomhort-go/blob/main/docs/API-COVERAGE.md"&gt;seebom-labs/bomhort-go&lt;/a&gt; — edit it there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Every route of the BOMHort api-gateway (&lt;code&gt;backend/cmd/api-gateway/main.go&lt;/code&gt;) and the client method that calls it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Since&lt;/strong&gt; is the first BOMHort release with the route (≤ 0.6 = present in 0.6.1, the oldest release checked). Routes newer than the server answer &lt;code&gt;404&lt;/code&gt; (&lt;code&gt;IsNotFound&lt;/code&gt;); newer query parameters are ignored and newer fields stay empty (&lt;a href="https://docs.bomhort.dev/docs/ecosystem/go-client/compatibility/"&gt;COMPATIBILITY.md&lt;/a&gt;). Pagination column: ✓ = &lt;code&gt;ListX&lt;/code&gt; page call + &lt;code&gt;X&lt;/code&gt; iterator (+ &lt;code&gt;AllX&lt;/code&gt; where useful).&lt;/p&gt;</description></item><item><title>How to: run VEXViper as a CronJob</title><link>https://docs.bomhort.dev/docs/ecosystem/vexviper/how-to-cronjob/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.bomhort.dev/docs/ecosystem/vexviper/how-to-cronjob/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Maintained in &lt;a href="https://github.com/seebom-labs/VEXViper/blob/main/docs/HOWTO-CRONJOB.md"&gt;seebom-labs/VEXViper&lt;/a&gt; — edit it there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A BOMHort ≥ 0.7 api-gateway reachable from the cluster with &lt;code&gt;AUTH_ENABLED=true&lt;/code&gt;
and an API key (or service token) that may upload.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;helm&lt;/code&gt; 3 and &lt;code&gt;kubectl&lt;/code&gt; against the target cluster.&lt;/li&gt;
&lt;li&gt;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).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="steps"&gt;Steps&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create the namespace and the secret. The chart reads &lt;code&gt;api-key&lt;/code&gt;; &lt;code&gt;github-token&lt;/code&gt;
is optional and only needed for GitHub Models or private clones.&lt;/p&gt;</description></item><item><title>Compatibility &amp; Versioning</title><link>https://docs.bomhort.dev/docs/ecosystem/go-client/compatibility/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.bomhort.dev/docs/ecosystem/go-client/compatibility/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Maintained in &lt;a href="https://github.com/seebom-labs/bomhort-go/blob/main/docs/COMPATIBILITY.md"&gt;seebom-labs/bomhort-go&lt;/a&gt; — edit it there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="versions-follow-bomhort"&gt;Versions follow BOMHort&lt;/h2&gt;
&lt;p&gt;bomhort-go is released in &lt;strong&gt;lockstep with BOMHort&lt;/strong&gt;: &lt;code&gt;bomhort-go vX.Y.*&lt;/code&gt; is the client for &lt;code&gt;BOMHort X.Y.*&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Major.minor&lt;/strong&gt; is BOMHort&amp;rsquo;s. &lt;code&gt;v0.8.0&lt;/code&gt; ships when BOMHort 0.8.0 is final and covers its complete public API; a BOMHort minor without API changes still gets a (trivial) bomhort-go minor so the mapping stays obvious.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Patch&lt;/strong&gt; is ours: client fixes, &lt;code&gt;bomhorttest&lt;/code&gt; improvements, docs. &lt;code&gt;v0.8.3&lt;/code&gt; still targets BOMHort 0.8.x.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pre-releases&lt;/strong&gt; (&lt;code&gt;v0.8.0-rc.N&lt;/code&gt;) track BOMHort release candidates when a consumer needs them early.&lt;/li&gt;
&lt;li&gt;A newer client works against the previous BOMHort minor for everything that minor has (new routes answer &lt;code&gt;404&lt;/code&gt; → &lt;code&gt;IsNotFound&lt;/code&gt;, new fields are empty, new query parameters are ignored). An older client works against a newer BOMHort because decoding is lenient by default.&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;bomhort-go&lt;/th&gt;
 &lt;th&gt;Go&lt;/th&gt;
 &lt;th&gt;BOMHort&lt;/th&gt;
 &lt;th&gt;Tested in CI against&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;v0.8.x&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;1.25+ (&lt;code&gt;go.mod&lt;/code&gt;) and latest stable&lt;/td&gt;
 &lt;td&gt;0.8.x&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;v0.8.0&lt;/strong&gt; (pinned, every PR) · &lt;strong&gt;&lt;code&gt;main&lt;/code&gt;&lt;/strong&gt; (weekly)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The pinned BOMHort ref lives in &lt;code&gt;.github/workflows/e2e.yml&lt;/code&gt; (&lt;code&gt;BOMHORT_PINNED_REF&lt;/code&gt;). Bump it — and this table — when a new BOMHort release (or RC) ships; see &lt;a href="https://github.com/seebom-labs/bomhort-go/blob/main/docs/RELEASING.md"&gt;RELEASING.md&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>How to: review VEX drafts in pull requests</title><link>https://docs.bomhort.dev/docs/ecosystem/vexviper/how-to-gitops/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.bomhort.dev/docs/ecosystem/vexviper/how-to-gitops/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Maintained in &lt;a href="https://github.com/seebom-labs/VEXViper/blob/main/docs/HOWTO-GITOPS.md"&gt;seebom-labs/VEXViper&lt;/a&gt; — edit it there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Goal: every VEX document VEXViper produces lands as a pull request in a git
repository; a human reviews and merges it, and only merged statements are
uploaded to BOMHort.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A git repository for the statements, e.g. &lt;code&gt;github.com/acme/vex-statements&lt;/code&gt;,
with a base branch (&lt;code&gt;main&lt;/code&gt;) that is protected so bots cannot merge.&lt;/li&gt;
&lt;li&gt;A GitHub token with &lt;code&gt;contents: write&lt;/code&gt; and &lt;code&gt;pull_requests: write&lt;/code&gt; on that
repository (fine-grained PAT or a GitHub App installation token). For GitHub
Enterprise Server note the API URL (&lt;code&gt;https://ghe.example.com/api/v3&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;VEXViper installed (CLI or Helm, see &lt;a href="https://docs.bomhort.dev/docs/ecosystem/vexviper/how-to-cronjob/"&gt;How to: run VEXViper as a CronJob&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="steps"&gt;Steps&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Configure the publishing target. CLI (&lt;code&gt;vexviper.yaml&lt;/code&gt;):&lt;/p&gt;</description></item><item><title>How to: set up an LLM provider</title><link>https://docs.bomhort.dev/docs/ecosystem/vexviper/how-to-llm/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.bomhort.dev/docs/ecosystem/vexviper/how-to-llm/</guid><description>&lt;blockquote&gt;
&lt;p&gt;Maintained in &lt;a href="https://github.com/seebom-labs/VEXViper/blob/main/docs/HOWTO-LLM.md"&gt;seebom-labs/VEXViper&lt;/a&gt; — edit it there.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Goal: VEXViper asks a language model for the verdict instead of using only the
built-in rules, with a spend cap, and the model&amp;rsquo;s answer still passes the
deterministic guardrails.&lt;/p&gt;
&lt;p&gt;The provider only sees the evidence VEXViper collected (govulncheck result,
dependency depth, lockfile graph, OSV data). A &lt;code&gt;not_affected&lt;/code&gt; without strong
evidence is always downgraded to &lt;code&gt;under_investigation&lt;/code&gt;, whatever the model says.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;VEXViper working with &lt;code&gt;provider: heuristic&lt;/code&gt; (see
&lt;a href="https://docs.bomhort.dev/docs/ecosystem/vexviper/how-to-cronjob/"&gt;How to: run VEXViper as a CronJob&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;One of:
&lt;ul&gt;
&lt;li&gt;an &lt;strong&gt;OpenAI-compatible endpoint&lt;/strong&gt; and key (OpenAI, Azure OpenAI, Ollama, vLLM, LiteLLM …);&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;GitHub account with a Copilot subscription&lt;/strong&gt; — for GitHub Models a
fine-grained PAT with the &lt;code&gt;models: read&lt;/code&gt; permission (billed to the plan);&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;GitHub Copilot CLI&lt;/strong&gt; installed and logged in on the machine that runs
VEXViper (laptop or CI runner — the VEXViper container image does not ship it).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="steps"&gt;Steps&lt;/h2&gt;
&lt;p&gt;Pick one provider.&lt;/p&gt;</description></item></channel></rss>