Generate and transform VEX documents from SBOMs and vulnerability data sources.
Project description
Vexcalibur
Vexcalibur is a general-purpose VEX toolkit for vulnerability exploitability workflows across SBOM, package URL, and vulnerability data ecosystems.
Vexcalibur currently ingests CycloneDX JSON and XML SBOM files, can fetch GitHub Dependency Graph SBOMs, collects findings from OSV-compatible APIs or local findings files, and renders CycloneDX 1.6 VEX JSON. It is intended to replace legacy vexy usage over time while staying provider-neutral and ecosystem-neutral.
Status
Usable for the workflows listed below, with unstable public contracts before the first 1.0 release.
| Area | Current status |
|---|---|
| SBOM ingest | Supports CycloneDX JSON/XML files for CycloneDX 1.4, 1.5, and 1.6, plus GitHub Dependency Graph SBOM input from repository SPDX JSON. |
| Vulnerability sources | Supports public OSV with explicit opt-in, private OSV-compatible endpoints, and no-network local findings files. |
| VEX output | Emits CycloneDX 1.6 VEX JSON with deterministic output when --timestamp is provided. |
| GitHub Actions | Use vexcalibur-action for CI workflows. |
Legacy vexy compatibility |
Supports a narrow vexy CLI subset for CycloneDX JSON VEX generation while preserving the public OSV opt-in boundary. |
| Stability | CLI flags, Python APIs, and output details can change before 1.0. Pin exact versions after releases begin. |
Current workflows:
- Query OSV-compatible APIs for one or more package URLs with
vexcalibur query-osv. - Generate CycloneDX 1.6 VEX JSON from CycloneDX JSON/XML SBOM files or GitHub Dependency Graph SBOM input with
vexcalibur generate. - Generate VEX from local findings without contacting a vulnerability service.
- Run selected legacy
vexycommands through the compatibility executable. - Run Vexcalibur from GitHub Actions through the companion action.
Development
Prerequisites:
- Python 3.10 or newer
- uv 0.11.17
Install dependencies:
uv sync
Run offline tests:
uv run --frozen pytest -m "not live" --cov-fail-under=75
Run live compatibility smoke tests only when you intentionally want to call the covered public services:
uv run --frozen pytest -m live -q
Run static checks:
uv run --frozen ruff check src tests docs/conf.py
uv run --frozen mypy src
Build the documentation:
uv sync --extra docs
make docs
The canonical generated documentation is available on the Vexcalibur documentation site.
Try the CLI:
uv run --frozen vexcalibur --help
Query OSV for a package URL:
uv run --frozen vexcalibur query-osv pkg:pypi/django@1.2 --allow-public-osv
Expected result: the command prints the submitted package URL and any OSV vulnerability IDs returned by https://api.osv.dev.
Like generate, query-osv requires --allow-public-osv for the public OSV API and accepts --osv-url for private mirrors.
Generate CycloneDX VEX JSON from a CycloneDX SBOM:
generate refuses to send package URLs or component versions to the public OSV API unless you pass --allow-public-osv. Do not use that flag with private SBOMs or sensitive package inventories. Use --osv-url for a private OSV mirror. Library callers that inject an OSV client must also provide the matching osv_base_url; the same public-OSV opt-in check is enforced before the client is used.
uv run --frozen vexcalibur generate tests/fixtures/sbom/cyclonedx-json-simple.json --allow-public-osv --output /tmp/vexcalibur-vex.json
Illustrative private-mirror command, replacing the URL with your internal OSV endpoint:
uv run --frozen vexcalibur generate tests/fixtures/sbom/cyclonedx-json-simple.json --osv-url https://osv.internal.example --output /tmp/vexcalibur-vex.json
Generate from a GitHub repository's Dependency Graph SBOM. This fetches the SBOM from GitHub, then still requires an explicit opt-in before sending the resulting package inventory to public OSV:
uv run --frozen vexcalibur generate --github-repo vexcalibur-dev/vexcalibur --allow-public-osv --output /tmp/vexcalibur-vex.json
Offline command using local findings, replacing the file paths with your SBOM and findings JSON:
uv run --frozen vexcalibur generate path/to/sbom.json --offline --findings-file path/to/findings.json --output /tmp/vexcalibur-vex.json
Legacy vexy compatibility command using the same no-network findings source:
uv run --frozen vexy -c tests/fixtures/vexy/legacy-config.yml -i tests/fixtures/sbom/cyclonedx-xml-1.5-simple.xml --format json --schema-version 1.6 --output - --offline --findings-file tests/fixtures/findings/all-analysis-states.json --timestamp 2026-06-23T00:00:00Z
The compatibility command accepts -c/--config for argument compatibility but
does not read legacy data-source credentials. Select a Vexcalibur source mode
with --findings-file, --osv-url, or --allow-public-osv.
For a deterministic document timestamp, provide --timestamp. Live OSV data can change over time, so identical inputs can still produce different vulnerability findings unless OSV responses are controlled.
uv run --frozen vexcalibur generate tests/fixtures/sbom/cyclonedx-json-simple.json --allow-public-osv --timestamp 2026-06-23T00:00:00Z --output /tmp/vexcalibur-vex.json
python - <<'PY'
import json
from pathlib import Path
vex = json.loads(Path("/tmp/vexcalibur-vex.json").read_text())
assert vex["bomFormat"] == "CycloneDX"
assert vex["specVersion"] == "1.6"
assert vex["metadata"]["timestamp"] == "2026-06-23T00:00:00+00:00"
print(f"validated {len(vex.get('vulnerabilities', []))} generated VEX findings")
PY
The OSV-backed generator queries OSV for versioned components with package URLs, emits CycloneDX vulnerability entries for OSV matches, and marks findings in_triage by default. Local findings can provide explicit VEX analysis states and details.
Supported input for all generate source modes:
- CycloneDX JSON SBOMs with
specVersion1.4,1.5, or1.6; JSON input must be UTF-8. - CycloneDX XML SBOMs rooted at
bomin thehttp://cyclonedx.org/schema/bom/1.4,/1.5, or/1.6namespace; XML may use parser-detected XML encodings such as UTF-8 or UTF-16, and DTD, entity, and external-reference declarations are rejected. - GitHub Dependency Graph SBOM input with
--github-repo OWNER/REPO; Vexcalibur requests an SPDX JSON report from GitHub's asynchronous SBOM API and extracts package URL references. - Local SBOM files and GitHub SBOM report downloads up to 10 MiB, up to 10,000 components, and component nesting up to 50 levels.
- Unique component refs for components with package URLs. Duplicate queried component refs are rejected because VEX
affectsentries refer to components by ref. - Explicit source configuration. Public OSV requires
--allow-public-osv; private mirrors use--osv-url; offline local findings use--findings-file.
Additional OSV-backed requirements:
- Components need package URLs and either a PURL version, a CycloneDX component
version, or GitHub SPDXversionInfo; unversioned components are not queried. - The OSV query set must be non-empty. If no component can be queried precisely, the command fails instead of producing an empty VEX that looks authoritative.
Local findings mode can produce an empty VEX document when the findings file explicitly contains "findings": [].
Project Links
- Documentation
- Documentation source
- Quickstart tutorial
- No-network local findings tutorial
- Generate CycloneDX VEX
- Use a private OSV mirror
- CI and recurring checks
- Project status
- CLI reference
- CycloneDX VEX output reference
- Provider contract reference
- GitHub Action
- Security policy
- Contributing
- Python style policy
- AI agent and style guidance
- License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file vexcalibur-0.1.1.tar.gz.
File metadata
- Download URL: vexcalibur-0.1.1.tar.gz
- Upload date:
- Size: 734.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4715dfa6bb3c11157cff8ef65d2c2dcf8bcb7f6fe845b215322ec58db5d41d7b
|
|
| MD5 |
55051c27da78ac011db25147c15337ec
|
|
| BLAKE2b-256 |
40dd698a6e9f8375324d341631520c006a63c008154c46f8526c8a76976da34d
|
Provenance
The following attestation bundles were made for vexcalibur-0.1.1.tar.gz:
Publisher:
pypi.yml on vexcalibur-dev/vexcalibur
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
vexcalibur-0.1.1.tar.gz -
Subject digest:
4715dfa6bb3c11157cff8ef65d2c2dcf8bcb7f6fe845b215322ec58db5d41d7b - Sigstore transparency entry: 2120672316
- Sigstore integration time:
-
Permalink:
vexcalibur-dev/vexcalibur@1aa7944a611a865c9b84347a78d2cb7f534d82b9 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/vexcalibur-dev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yml@1aa7944a611a865c9b84347a78d2cb7f534d82b9 -
Trigger Event:
release
-
Statement type:
File details
Details for the file vexcalibur-0.1.1-py3-none-any.whl.
File metadata
- Download URL: vexcalibur-0.1.1-py3-none-any.whl
- Upload date:
- Size: 40.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
179e5d059000e43b4439fc21b0cd46ed6a99915a2777e19063417e09a7512467
|
|
| MD5 |
a782b9851074ecf6c056e38f62db1471
|
|
| BLAKE2b-256 |
dc1321d13c550ed24acac17a9b65080d339fd2adf343f33ffd24f968389f6895
|
Provenance
The following attestation bundles were made for vexcalibur-0.1.1-py3-none-any.whl:
Publisher:
pypi.yml on vexcalibur-dev/vexcalibur
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
vexcalibur-0.1.1-py3-none-any.whl -
Subject digest:
179e5d059000e43b4439fc21b0cd46ed6a99915a2777e19063417e09a7512467 - Sigstore transparency entry: 2120672362
- Sigstore integration time:
-
Permalink:
vexcalibur-dev/vexcalibur@1aa7944a611a865c9b84347a78d2cb7f534d82b9 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/vexcalibur-dev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yml@1aa7944a611a865c9b84347a78d2cb7f534d82b9 -
Trigger Event:
release
-
Statement type: