Vexcalibur
Vexcalibur turns software bills of materials and vulnerability findings into VEX documents. It reads CycloneDX SBOMs or a GitHub Dependency Graph SBOM. Findings come from an OSV-compatible service or a local file.
Current releases write CycloneDX 1.6, OpenVEX 0.2.0, and CSAF 2.0 JSON. CSAF
output uses the csaf_vex profile. This branch also writes SPDX 3.0.1
JSON-LD through the security profile's VEX relationships; no release through
v0.6.3 includes it.
The project is usable, but still pre-1.0. Pin an exact release because command flags, Python APIs, and detailed output may change.
What works today
| Area | Support |
|---|---|
| SBOM input | CycloneDX JSON and XML 1.4–1.6; GitHub Dependency Graph SPDX 2.3 JSON |
| Finding sources | Public OSV with explicit consent; private OSV-compatible endpoints; local findings files |
| VEX output | CycloneDX 1.6 JSON; OpenVEX 0.2.0 JSON; CSAF 2.0 JSON with the csaf_vex profile; SPDX 3.0.1 JSON-LD with the security profile |
| Automation | A companion GitHub Action |
| Migration | A narrow vexy command-line compatibility layer |
| Python | 3.10–3.14 |
Install a release
Open the release page
and choose an exact version. The commands prompt for that version so an
unresolved placeholder cannot reach pip:
set -euo pipefail
read -r -p "Vexcalibur version from the release page: " VEXCALIBUR_VERSION
if [[ ! "$VEXCALIBUR_VERSION" =~ ^(0|[1-9][0-9]{0,5})\.(0|[1-9][0-9]{0,5})\.(0|[1-9][0-9]{0,5})$ ]]; then
printf 'Enter a MAJOR.MINOR.PATCH release version\n' >&2
exit 2
fi
VEXCALIBUR_VENV=".venv-vexcalibur-${VEXCALIBUR_VERSION}"
if [[ -e "$VEXCALIBUR_VENV" ]]; then
printf 'Refusing to reuse %s\n' "$VEXCALIBUR_VENV" >&2
exit 2
fi
python -m venv "$VEXCALIBUR_VENV"
"$VEXCALIBUR_VENV/bin/python" -m pip install \
"vexcalibur==${VEXCALIBUR_VERSION}"
INSTALLED_VERSION="$("$VEXCALIBUR_VENV/bin/python" -c \
'from importlib.metadata import version; print(version("vexcalibur"))')"
test "$INSTALLED_VERSION" = "$VEXCALIBUR_VERSION"
"$VEXCALIBUR_VENV/bin/vexcalibur" --help
In PowerShell 7.3 or newer, use:
$ErrorActionPreference = "Stop"
$PSNativeCommandUseErrorActionPreference = $true
$VEXCALIBUR_VERSION = Read-Host "Vexcalibur version from the release page"
if ($VEXCALIBUR_VERSION -notmatch '^(0|[1-9][0-9]{0,5})\.(0|[1-9][0-9]{0,5})\.(0|[1-9][0-9]{0,5})$') {
throw "Enter a MAJOR.MINOR.PATCH release version"
}
$VEXCALIBUR_VENV = ".venv-vexcalibur-$VEXCALIBUR_VERSION"
if (Test-Path -LiteralPath $VEXCALIBUR_VENV) {
throw "Refusing to reuse $VEXCALIBUR_VENV"
}
py -m venv $VEXCALIBUR_VENV
$PYTHON = Join-Path $VEXCALIBUR_VENV "Scripts/python.exe"
$VEXCALIBUR = Join-Path $VEXCALIBUR_VENV "Scripts/vexcalibur.exe"
& $PYTHON -m pip install "vexcalibur==$VEXCALIBUR_VERSION"
$INSTALLED_VERSION = & $PYTHON -c `
'from importlib.metadata import version; print(version("vexcalibur"))'
if ($INSTALLED_VERSION -ne $VEXCALIBUR_VERSION) {
throw "Installed $INSTALLED_VERSION instead of $VEXCALIBUR_VERSION"
}
& $VEXCALIBUR --help
Try local generation
Clone the repository, then install its locked dependencies:
uv sync
Dependency installation may contact the configured package index. The generation command below uses only local inputs and does not contact a vulnerability service.
Generate a VEX document from the committed example files:
uv run --frozen vexcalibur generate \
tests/fixtures/sbom/cyclonedx-json-simple.json \
--offline \
--findings-file tests/fixtures/findings/all-analysis-states.json \
--timestamp 2026-06-23T00:00:00Z \
--output /tmp/vexcalibur-vex.json
Check the result:
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 len(vex["vulnerabilities"]) == 5
print("generated CycloneDX VEX")
PY
See the quickstart for the guided version of this example.
CycloneDX remains the default output. Add --format openvex and identify the
document author to create OpenVEX. Add --format csaf and the required
document and publisher metadata to create a CSAF 2.0 VEX document. Follow the OpenVEX
guide
or CSAF
guide
for a runnable example and the format's evidence rules.
Choose a finding source
Vexcalibur requires one finding source for each generation run.
| Inventory and trust boundary | Use |
|---|---|
| Findings already exist locally | Use --findings-file findings.json. Add --offline for a local SBOM. |
| Inventory may go to an internal service | --osv-url https://osv.internal.example |
| Inventory is approved for public OSV | --allow-public-osv |
Warning:
--allow-public-osvsends package URLs and versions tohttps://api.osv.dev. Do not use it with a private SBOM or sensitive package inventory unless that disclosure is approved.
The default public endpoint fails closed without that flag. Fetching an SBOM from GitHub is a separate network boundary and does not grant permission to send the resulting inventory to public OSV.
Documentation
- Start with the quickstart.
- Follow the CycloneDX, OpenVEX, or CSAF generation guide.
- Use the CLI reference for flags and failure behavior.
- Use the Python API guide and API reference when embedding Vexcalibur.
- The default-branch execution report reference covers machine-readable generation metadata. The Python report guide covers the cross-platform API. Before using either path, verify that the selected release contains the report API or lists
--execution-reportinvexcalibur generate --help. - The CLI report transaction supports Linux and macOS. Windows embeddings can construct and validate the same report through the supported Python facade.
- Read the provider contract and renderer contract before adding an integration.
- Read the CycloneDX, OpenVEX, or CSAF output contract before consuming generated files.
- Read the architecture before adding a source or output format.
- Read the self-release evidence design, inspect a local bundle, or follow the immutable release runbook.
- Check project status for current limits.
The complete manual is at vexcalibur-dev.github.io/vexcalibur.
Contributing
The complete local gate runs on Linux and needs the host tools listed in Reproduce important gates. That guide includes exact portable commands for macOS and Windows. Required pull-request CI runs the Linux-only checks.
On Linux, run the quality gate:
make check
Documentation changes must also build without warnings:
uv sync --extra docs
make docs
Parser, source-client, package-URL, and terminal-safety changes must also run the deterministic fuzz smoke profile:
make fuzz-smoke
See the contribution guide, the security policy, the fuzzing guide, and the Python style policy before opening a pull request.
Use the issue forms for questions, bugs, and feature requests. The organization support policy explains which public route to use, and the code of conduct applies to project spaces.
Vexcalibur is licensed under the Apache License 2.0.
Release files for vexcalibur 0.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| vexcalibur-0.7.0.tar.gz | 1.2 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| vexcalibur-0.7.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.3 MB
Release files / vexcalibur-0.7.0.tar.gz
| Download URL | vexcalibur-0.7.0.tar.gz |
|---|---|
| Size | 1.2 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b4404a30227dbfce87510f23bdb67da340c7871ee2772b3345a295673b960054
|
|
BLAKE2b-256 checksum How to use checksums |
3fa834efe05a198228fcf74eaf6b72a83cb44ed932b5c9cb72e71b55dff909e3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.
Transparency logRelease files / vexcalibur-0.7.0-py3-none-any.whl
| Download URL | vexcalibur-0.7.0-py3-none-any.whl |
|---|---|
| Size | 122.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d738b78138ac5e91fb204473d2092c334eba8e7b8b8be7ad295df4555a9cac0d
|
|
BLAKE2b-256 checksum How to use checksums |
5e2655989331076480ed4e1e47402fb5d82b09fac8bcc2de614b368366aacb01
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.
Transparency log