Skip to main content

Generate and transform VEX documents from SBOMs and vulnerability data sources.

Project description

Vexcalibur

Vexcalibur wordmark and sword logo

CI CodeQL OpenSSF Scorecard Dependency Review

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 vexy commands 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 specVersion 1.4, 1.5, or 1.6; JSON input must be UTF-8.
  • CycloneDX XML SBOMs rooted at bom in the http://cyclonedx.org/schema/bom/1.4, /1.5, or /1.6 namespace; 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 affects entries 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 SPDX versionInfo; 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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

vexcalibur-0.1.0.tar.gz (732.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

vexcalibur-0.1.0-py3-none-any.whl (39.0 kB view details)

Uploaded Python 3

File details

Details for the file vexcalibur-0.1.0.tar.gz.

File metadata

  • Download URL: vexcalibur-0.1.0.tar.gz
  • Upload date:
  • Size: 732.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for vexcalibur-0.1.0.tar.gz
Algorithm Hash digest
SHA256 9f44850a00232a08e1169a437baea69895f5de9978e057f8a30a68c5c564c90a
MD5 5b1aba6fb8b4c8d13bbd537a6b08d342
BLAKE2b-256 61400051ee01abc40376f9dbf8303fb5bdae156875a2bbdac4c96960ba93e6ac

See more details on using hashes here.

Provenance

The following attestation bundles were made for vexcalibur-0.1.0.tar.gz:

Publisher: pypi.yml on vexcalibur-dev/vexcalibur

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file vexcalibur-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: vexcalibur-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 39.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for vexcalibur-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 96e4983831689390307bf079640cde765959ad3f555979d05468324d75f6bb41
MD5 1bd55afeecde3963876404ad371958c5
BLAKE2b-256 109bb53089508fdc8983e0e83245f2a1f12a136b757a5e39fe8e56f9f7da9c36

See more details on using hashes here.

Provenance

The following attestation bundles were made for vexcalibur-0.1.0-py3-none-any.whl:

Publisher: pypi.yml on vexcalibur-dev/vexcalibur

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page