csaf-check
Validate CSAF 2.0 advisories from Python, using the same validator Secvisogram runs — and get an honest answer when that validator is not installed.
The problem
If you publish security advisories as CSAF, you want schema validation in your release pipeline,
not in a browser tab at the end. The authoritative implementation of the CSAF 2.0 mandatory tests
is @secvisogram/csaf-validator-lib, which is
JavaScript. Reimplementing the schema in Python means maintaining a second, subtly different
opinion about what "valid" means — and yours will be the wrong one.
So this package does not reimplement anything. It bridges to the real validator and handles the part that is annoying to get right: what happens when the validator is not there.
The contract
validate() never raises. Not when Node is missing, not when the library is absent, not when the
validator times out or returns something unexpected. Each of those returns a result that says so:
from csaf_check import validate
result = validate(advisory_dict)
result.available # could the validator run at all?
result.is_valid # True / False / None when no verdict was reached
result.errors # one message per failed mandatory test
result.note # why there is no verdict, when there isn't
result.conclusive # available and a verdict exists
This matters because the alternative — a validator that throws on a missing optional dependency —
turns a quality gate into a hard dependency, and every caller ends up wrapping it in try/except
and swallowing real failures along with the boring ones.
Install
pip install csaf-check
That gives you the Python API and CLI. For actual validation you also need Node.js and the validator library:
npm install @secvisogram/csaf-validator-lib
The default is intentionally lenient: without the JavaScript validator, csaf-check prints
UNKNOWN - validator unavailable and exits 0, so CI environments without Node or the validator
do not break. Strict handling is an explicit opt-in: add --require-validator to make validator
unavailability exit 3.
The validator is found either next to the installed package or under node_modules in your current
working directory, so running npm install in your own project directory is enough — you do not
have to install it into site-packages. NODE_PATH is honoured as well.
CLI
csaf-check examples/advisory-minimal.json # human-readable verdict
csaf-check examples/advisory-minimal.json --json # machine-readable
csaf-check - < examples/advisory-minimal.json # stdin
csaf-check examples/advisory-minimal.json --require-validator # fail if no verdict is possible
Exit codes: 0 valid (or inconclusive without --require-validator) — 1 invalid —
2 unreadable or malformed input — 3 no verdict possible and --require-validator was set.
Python API
import json
from csaf_check import validate, validator_available
if not validator_available():
print("install Node.js to enable strict validation")
with open("advisory.json", encoding="utf-8") as fh:
result = validate(json.load(fh))
if result.conclusive and not result.is_valid:
for message in result.errors:
print("FAIL", message)
What this does NOT do
- It does not generate CSAF documents. It only validates ones you already have.
- It runs the mandatory tests only, not the informative or optional profiles.
- It does not check that your advisory is correct, only that it is well-formed. A schema-valid document can still describe the wrong product or the wrong affected range.
- It does not publish anything, sign anything, or talk to any network service.
- It is not legal advice about the EU Cyber Resilience Act. CRA is format-neutral and does not mandate CSAF. CSAF is a good machine-readable choice for advisories and VEX, not a compliance checkbox.
Examples
examples/advisory-minimal.json is a small synthetic advisory for a fictional vendor using a
placeholder CVE identifier. examples/advisory-invalid.json is deliberately missing the mandatory
tracking object. Both exist to exercise this wrapper; neither describes a real product or a real
vulnerability.
Testing
pip install -e ".[dev]"
pytest -q
The suite runs without Node.js on purpose — the degradation path is the part most likely to rot.
License
Apache-2.0. See LICENSE.
Built and maintained by Gexiro Global Enterprises Ltd.
Third-party attribution: see NOTICE.
Part of the Gexiro open-source toolkit.
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 csaf_check-0.1.1.tar.gz.
File metadata
- Download URL: csaf_check-0.1.1.tar.gz
- Upload date:
- Size: 20.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
457d7c7f3607062ea1270d0110c7ac53c5bcc2a9dbcba127d8fcb543f68845f1
|
|
| MD5 |
aaf8759a5d34ab3a928a417cb3018ae5
|
|
| BLAKE2b-256 |
6b04ae777205216f8204f173530fe779ab6aa42be2a85209ca5c0141da9a6b60
|
Provenance
The following attestation bundles were made for csaf_check-0.1.1.tar.gz:
Publisher:
release.yml on gexiro-global/csaf-check
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
csaf_check-0.1.1.tar.gz -
Subject digest:
457d7c7f3607062ea1270d0110c7ac53c5bcc2a9dbcba127d8fcb543f68845f1 - Sigstore transparency entry: 2413225211
- Sigstore integration time:
-
Permalink:
gexiro-global/csaf-check@b2d54e440155c7942da32a5230fe7c0384bfe849 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/gexiro-global
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b2d54e440155c7942da32a5230fe7c0384bfe849 -
Trigger Event:
release
-
Statement type:
File details
Details for the file csaf_check-0.1.1-py3-none-any.whl.
File metadata
- Download URL: csaf_check-0.1.1-py3-none-any.whl
- Upload date:
- Size: 17.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d0fae8413778aed030cee3b66a4a5f044026938a9347eaa9d2be796066182094
|
|
| MD5 |
bd22f1873079fb5942272234ac663f2d
|
|
| BLAKE2b-256 |
123f2aff291b5c5090bbd21bdc8207abfa0e302706ea0e986842ba8d73ac8154
|
Provenance
The following attestation bundles were made for csaf_check-0.1.1-py3-none-any.whl:
Publisher:
release.yml on gexiro-global/csaf-check
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
csaf_check-0.1.1-py3-none-any.whl -
Subject digest:
d0fae8413778aed030cee3b66a4a5f044026938a9347eaa9d2be796066182094 - Sigstore transparency entry: 2413225398
- Sigstore integration time:
-
Permalink:
gexiro-global/csaf-check@b2d54e440155c7942da32a5230fe7c0384bfe849 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/gexiro-global
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b2d54e440155c7942da32a5230fe7c0384bfe849 -
Trigger Event:
release
-
Statement type: