Use A Private OSV Mirror¶
Use a private OSV-compatible endpoint when your SBOM includes package names, versions, or dependency inventory that should not be sent to the public OSV service.
Prerequisites¶
A local CycloneDX JSON/XML SBOM supported by Vexcalibur, or a GitHub repository whose Dependency Graph SBOM should be used as the package inventory.
An internal endpoint that implements the OSV
/v1/querybatchresponse shape.Network access from the runner to that endpoint.
Generate VEX With The Mirror¶
Pass the mirror base URL with --osv-url:
uv run --frozen vexcalibur generate \
path/to/private-sbom.json \
--osv-url https://osv.internal.example \
--output /tmp/vexcalibur-vex.json
Do not pass --allow-public-osv for private inventories. That flag is only for
workflows where sending package URLs and versions to https://api.osv.dev is
explicitly approved.
Private mirror URLs must be absolute https:// URLs with a hostname. Cleartext
http:// is accepted only for loopback hosts such as http://127.0.0.1:8080
when testing a local OSV-compatible service.
Expected success signal: the command exits with status 0 and writes
CycloneDX 1.6 VEX JSON to /tmp/vexcalibur-vex.json.
Use the same mirror when the package inventory comes from GitHub Dependency Graph:
uv run --frozen vexcalibur generate \
--github-repo internal/example \
--github-token-env GH_ENTERPRISE_TOKEN \
--github-api-url https://github.example.test/api/v3 \
--osv-url https://osv.internal.example \
--output /tmp/vexcalibur-vex.json
Fetching the SBOM from GitHub is separate from querying OSV. Keep using
--osv-url to avoid sending the GitHub-derived package inventory to public OSV.
Query A Package URL With The Mirror¶
Use the same --osv-url option for direct package URL checks:
uv run --frozen vexcalibur query-osv \
pkg:pypi/example@1.0.0 \
--osv-url https://osv.internal.example
Expected success signal: the command exits with status 0 and prints one line
for the submitted package URL.
Failure Modes¶
Vexcalibur treats OSV-compatible providers as source systems, not as trusted local data. It fails the command when the mirror returns invalid JSON, a non-object response, a mismatched batch response shape, repeated pagination tokens, or too many pages.
If a private mirror is unavailable, either fix the mirror before generating VEX
or use local findings with --offline.