Skip to main content

csaf

Reference implementation for the Common Security Advisory Framework (CSAF) standard.

The csaf package makes the Common Security Advisory Framework (CSAF) standard actionable: Converting, creating, mocking, rendering, validating, and viewing CSAF documents per Python API, CLI, and LSP.

Requires Python 3.11 or later.

Install

Minimal feature set is installed per: pip install csaf. Optional extras activate a faster JSON Schema validation or additional capabilities:

fast-schema : allows the use of a compiled json schema validator - typically ten or more times faster then the builtin variant (adds jsonschema-rs).

lsp : adds an lsp server to support editor integration (adds pygls).

render : enables html and markdown rendering of advisories (adds jinja2).

tui : enables the textual user interface used for edit, interactive markdown render, and view mode (adds textual).

yaml : enables yaml as edit mode and output format (adds ruamel.yaml).

Installation of extras is by including these as a comma separated list in square brackets. For example:

pip install csaf[fast-schema,lsp,render,tui,yaml]  # all extras - you may need to quote, depending on your shell

Source Distribution

You can find a link to the source distribution in the Files-tab on PyPI.

Manual

The man pages provide the full CLI reference. To install these locally in the user account:

csaf eject man --man-path ~/.local/share/man

Quickstart

CLI

Validate a CSAF 2.1 advisory and get a human-readable report:

csaf validate advisory.json
File: advisory.json
Overall: FAIL

  [PASS] schema - JSON Schema (CSAF 2.1)
  [FAIL] 6.1.1 - Missing Definition of Product ID
          /product_tree/product_groups/0/product_ids/0: product id `CSAFPID-9080700` is not defined in product_tree
  [PASS] 6.1.2 - Multiple Definition of Product ID
  ...

Exit code is 0 for a valid, 1 for invalid document, and 2 for usage errors.

Validation presets - run additional test tiers:

# Basic: schema + mandatory (6.1.x) - default
csaf validate advisory.json

# Extended: + recommended (6.2.x)
csaf validate --preset extended advisory.json

# Full: + informative (6.3.x)
csaf validate --preset full advisory.json

Output formats:

# TC-compatible JSON (matches the OASIS test-result schema)
csaf validate --format json advisory.json

# SARIF 2.2 (GitHub code scanning, VS Code SARIF viewer)
csaf validate --format sarif advisory.json > results.sarif

# GitHub-flavored markdown - paste directly into a GitHub issue or PR comment
csaf validate --format markdown advisory.json

Batch validation:

# All files in a directory
csaf validate advisories/*.json

# Recursive glob (quote to let Python expand it - avoids shell ARG_MAX limits)
csaf validate 'advisories/**/*.json'

# Batch markdown for a GitHub issue
csaf validate --format markdown 'advisories/*.json'

Rule filtering - suppress or allow-list specific rules:

# Skip by ID or from a YAML file (shown as [SKIP])
csaf validate --skip-rules 6.1.9 advisory.json
csaf validate --skip-rules skip.yaml advisory.json

# Run only specific rules (allowlist; composes with --skip-rules)
csaf validate --only-rules 6.1.1,6.1.2 advisory.json
csaf validate --only-rules rules.yaml advisory.json

Suppress output:

csaf validate --quiet advisory.json    # hide passing rules
csaf validate --silent advisory.json   # exit code only

Performance instrumentation:

# Per-rule timing and peak RSS delta - report to stderr
csaf validate --perf advisory.json

# Save a JSON baseline for later comparison
csaf validate --preset full --perf --perf-format json \
    --perf-output baseline.json advisory.json

Exit code is unchanged by --perf. On Windows the RSS delta column shows n/a (the resource module is POSIX-only); wall-clock timing works on all platforms.

Advisory browser (TUI):

# Open an advisory in the interactive terminal browser
csaf view advisory.json

# Multiple files - navigate with arrow keys in the sidebar
csaf view advisories/*.json

# Pipe from the producer API
python build_advisory.py | csaf view

Requires pip install 'csaf[tui]'. Five tabs: Summary (metadata and conformance status), Validation (rule-by-rule table), Dimensions (Appendix C soft-limit report, computed lazily in the background), Document (full structured rendering of the CSAF document), and Log (append-only per-file validation record that persists across rule re-runs). The loading screen streams rule results in real time as validation runs in the background; the advisory view is available immediately once all files finish loading. The theme indicator in the header subtitle (e.g. advisory.json [textual-dark]) updates automatically when the theme is changed via the command palette (Ctrl+P).

JSON editor (TUI):

# Edit a CSAF advisory file
csaf edit advisory.json

# Choose a file from an in-app directory browser
csaf edit

# Pipe from a script (stdin is re-routed so Ctrl+S works)
python draft_advisory.py | csaf edit

Requires pip install 'csaf[tui]'. The editor formats the JSON canonically (2-space indent, POSIX newline) on load. A Fields pane on the right tracks the cursor and shows the CSAF schema field's title, description, type, and all active constraints (enum values, format, pattern, minLength/maxLength, numeric ranges). Key bindings: Ctrl+S save, Ctrl+Q quit (unsaved-changes guard), Ctrl+F toggle / F7 narrow / F8 widen the fields pane, Ctrl+Z undo, Ctrl+R redo, Ctrl+Y copy current field constraints to clipboard, Ctrl+P command palette.

Form editor (TUI):

# Open the schema-driven full document editor
csaf edit --form advisory.json

# Pipe from a script
python draft_advisory.py | csaf edit --form

Requires pip install 'csaf[tui]'. The form editor renders every field in the advisory as a purpose-built widget: enum-constrained fields become Select drop-downs (including all CVSS metric fields), and free-text fields become Input boxes. Nested objects and arrays of objects are shown as indented section groups driven by the CSAF 2.1 JSON schema, with Add and Delete controls on each array section. CVSS v2, v3, and v4 objects are rendered from their referenced external schemas; cvss_v3 resolves the correct sub-schema (v3.0 or v3.1) by matching the document's version field. A Hints pane on the right shows the JSON path, schema title, description, allowed values, type, and constraints for the focused field, plus the external schema URL for CVSS and other referenced-schema fields. Below the schema metadata the pane shows editorial guidance from the built-in hints catalog (14 entries covering key CSAF 2.1 fields); organizations can extend the catalog via csaf eject hints, the [hints] config section, or the --hints-dir PATH flag. Key bindings: Ctrl+S save, Ctrl+Q quit, Ctrl+F toggle hints pane, F5/F6 narrow/widen label column, F7/F8 narrow/widen hints pane, and Ctrl+Y copy hints pane to clipboard.

Advisory renderer:

# Render to Markdown - print to stdout (requires csaf[render])
csaf render markdown advisory.json

# Render to a self-contained HTML page (requires csaf[render])
csaf render html advisory.json > advisory.html
csaf render html advisory.json --output advisory.html

# Interactive TUI Markdown browser with TOC pane (requires csaf[tui])
csaf render markdown --interactive advisory.json

# Customise the template
csaf eject template --output my.md.jinja           # Markdown template
csaf eject template --format html --output my.html.jinja  # HTML template
csaf render markdown --style my.md.jinja advisory.json
csaf render html     --style my.html.jinja advisory.json

The Markdown renderer produces a structured report with metadata, notes, vulnerabilities, product tree, references, and revision history. The HTML renderer produces a single self-contained file with inline CSS, dark-mode support, and TLP label colour badges. render_markdown(), render_html(), and their *_bytes() variants are available as public Python API.

Language Server Protocol:

Start the LSP server (requires installation of csaf[lsp]): csaf serve lsp.

The server speaks JSON-RPC 2.0 over stdio (Content-Length framing). It validates the open advisory on every didOpen/didChange event at the recommended preset and pushes diagnostics via publishDiagnostics. Rule IDs are in the diagnostic code field. See the man page for per-editor configuration snippets (Neovim, VS Code, Helix, Emacs/eglot).

Shell completion:

csaf completion bash >> ~/.bash_completion    # bash
csaf completion zsh  >> ~/.zshrc              # zsh
csaf completion fish > ~/.config/fish/completions/csaf.fish

Version and info -- machine-readable output:

csaf version                      # plain-text version string
csaf version --format json        # {"version": "2026.8.10", "package": "csaf"}
csaf version --format yaml        # same fields in YAML
csaf info version --format json   # same content via info subcommand group
csaf config explain --format json # effective config as a JSON dict (dataclasses.asdict)
csaf config explain --format yaml # same as YAML

Configuration:

csaf config eject --format toml              # generate a ready-to-edit config template
csaf config explain                          # show effective values with source provenance
csaf config explain --format json            # machine-readable config dict
csaf config doctor                           # validate all discovered config files

User config lives in ~/.config/csaf/config.toml; project config in .csaf.toml (or .yaml/.json) in the project root. CLI flags override both. Multi-word keys are written in kebab-case in the template (skip-rules, url-cache, etc.); both kebab-case and snake_case are accepted when reading.

The [ui] section controls TUI appearance across all interactive screens:

[ui]
theme = "gruvbox"     # Textual theme name; try also: nord, dracula, catppuccin-mocha
dialog-style = "text" # "text" for ASCII [ Label ] buttons, "native" for Textual Button

Set CSAF_UI_THEME and CSAF_UI_DIALOG_STYLE to override per-invocation.

The [log] section enables audit logging of CLI and TUI operations (off by default):

[log]
level = "info"   # debug, info, warning, error, critical, or off
sink  = "stderr" # stderr (default), stdout, or a file path

Set CSAF_LOG_LEVEL and CSAF_LOG_SINK to override per-invocation. See the Configuration tutorial for all supported keys.

Rule catalog:

csaf info rules                         # full list
csaf info rules --only-groups mandatory # filter by tier
csaf info rules --format json           # machine-readable
Spec   ID         Group           Status           Title
--------------------------------------------------------------------------------
2.1    6.1.1      mandatory       implemented      Missing Definition of Product ID
2.1    6.1.2      mandatory       implemented      Multiple Definition of Product ID
...
61 rule(s) in catalog (CSAF 2.1).

Environment info:

csaf info env                    # CSAF support, catalogs, interpreter, platform
csaf info env --preset extended   # + runtime config, paths, host OS identity
csaf info env --preset full       # + interpreter detail, flags, CPU, resource usage
csaf info env --format json      # machine-readable

Mock advisory generator:

# Generate a single document (base profile, default size 0.05)
csaf mock

# Specific profile; seed printed to stderr for reproduction
csaf mock --profile security-advisory --seed demo42

# Write to a file and validate at basic preset
csaf mock --profile vex --validate --seed workshop1 advisory.json

# Richer document (more optional fields)
csaf mock --size 0.5 --profile security-advisory

# Batch: three documents as RFC 7464 JSON Text Sequences on stdout
csaf mock --count 3 --seed batch1

# Batch to separate files (doc-1.json, doc-2.json, doc-3.json)
csaf mock --count 3 --seed batch1 'doc-{}.json'

# Pin specific fields with a YAML overlay
cat > overlay.yaml << 'EOF'
/document/publisher/name: "ACME Corp"
/document/title: "Test Advisory"
EOF
csaf mock --template overlay.yaml --seed pinned

The resolved seed is always printed to stderr. Repeat a run exactly by passing --seed <resolved-seed>. Mock advisories satisfy the CSAF 2.1 JSON Schema and all mandatory profile-based rules but contain synthetic data and MUST NOT be published as genuine advisories.

See the Mock advisories tutorial for step-by-step coverage of all profiles, overlays, and batch output.

For a condensed single-page reference see the Quickstart guide. For tutorials covering validation and document production see the Tutorial index.

Python API - consumer (validate)

from csaf import validate, validate_file

# From a file path
report = validate_file("advisory.json")

# From an already-parsed dict
import msgspec
doc = msgspec.json.decode(open("advisory.json", "rb").read())
report = validate(doc, path="advisory.json")

print("valid:", report.overall_valid)
for result in report.results:
    if not result.passed:
        print(f"[FAIL] {result.id} - {result.title}")
        for err in result.errors:
            print(f"       {err.instance_path}: {err.message}")

The ValidationReport is a frozen msgspec.Struct. Pass it to the formatters to render as text, JSON, SARIF, or markdown:

from csaf import to_text, to_tc_json, to_sarif, to_markdown

print(to_text(report))
print(to_tc_json(report))
print(to_sarif(report, version='0.0.0'))
print(to_markdown(report))

Python API - producer (build)

Construct a typed document and call build() to get validated JSON:

from csaf import (
    Document, Distribution, FullProductName, Note, Publisher, ProductStatus,
    ProductTree, Revision, Tlp, Tracking, Vulnerability,
    Metric, MetricContent, cvss31_from_vector, cwe_entry,
)

doc = Document(
    category='csaf_security_advisory',
    title='Acme Corp - Advisory 2026-001',
    publisher=Publisher(category='vendor', name='Acme Corp',
                        namespace='https://acme.example.com'),
    tracking=Tracking(
        id='ACME-2026-SA-001', status='final', version='1',
        initial_release_date='2026-01-15T10:00:00Z',
        current_release_date='2026-01-15T10:00:00Z',
        revision_history=[Revision(date='2026-01-15T10:00:00Z', number='1',
                                   summary='Initial release.')],
    ),
    distribution=Distribution(tlp=Tlp(label='CLEAR')),
    product_tree=ProductTree(full_product_names=[
        FullProductName(name='Widget 1.0', product_id='CSAFPID-W100'),
    ]),
    vulnerabilities=[
        Vulnerability(
            cve='CVE-2026-10001',
            cwes=[cwe_entry('CWE-122')],
            notes=[Note(category='description', text='Heap overflow in widget parser.')],
            product_status=ProductStatus(known_affected=['CSAFPID-W100']),
            metrics=[Metric(
                content=MetricContent(
                    cvss_v3=cvss31_from_vector(
                        'CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H'
                    ),
                ),
                products=['CSAFPID-W100'],
            )],
        ),
    ],
)

json_str, report = doc.build()   # raises BuildError on structural violations
assert report.overall_valid
import pathlib
pathlib.Path('advisory.json').write_text(json_str, encoding='utf-8')

build() validates the document and returns (json_str, ValidationReport). The JSON output has sorted keys, two-space indentation, and an auto-injected generator block. See the producer tutorial for step-by-step coverage of all five profiles, CVSS helpers, and build modes.

URL reachability cache

Rules 6.3.06 and 6.3.07 check that URLs in advisory documents resolve to live endpoints. Because HTTP requests are slow and advisory corpora can be large, the validator provides a four-mode URL cache:

Mode Behaviour When to use
run In-memory dedup within the current invocation Default; interactive use
disk Persist results to disk with a configurable TTL CI pipelines
disk-ro Read disk cache; skip on cache miss (no network) Air-gapped or offline builds
none No caching; each URL is checked fresh every run Debugging
# Default: in-memory dedup (no flags needed)
csaf validate --preset full advisory.json

# Disk cache with default TTL (24h) and default directory (~/.cache/csaf)
csaf validate --preset full --url-cache disk advisory.json

# Custom TTL and cache directory
csaf validate --preset full \
    --url-cache disk \
    --url-cache-ttl 7d \
    --url-cache-dir /var/cache/csaf \
    advisory.json

# Read-only: use cache, skip URL rules on miss (no network calls)
csaf validate --preset full --url-cache disk-ro advisory.json

# Disable URL rules entirely (shown as [SKIP]; implies --skip-rules 6.3.06,6.3.07)
csaf validate --preset full --no-network advisory.json

TTL accepts: 30m, 6h, 7d (minutes, hours, days). The disk cache is stored as a JSON file; entries expire individually based on their write time.

Recommended CI pattern:

csaf validate \
    --preset full \
    --url-cache disk \
    --url-cache-dir .cache/csaf \
    --url-cache-ttl 24h \
    'advisories/**/*.json'

Document dimension report (measure)

The measure subcommand measures advisory documents against the informative soft limits defined in Appendix C of the CSAF 2.1 specification - file size, array lengths, string lengths, URIs, dates, and enumerations. It does not perform conformance validation.

Each dimension is rated ok (at or below the caution threshold), caution (above threshold but within the limit), or exceeds (above the limit). The overall posture is the worst-case rating across all dimensions.

# Single file - human-readable text
csaf measure advisory.json

# Structured output
csaf measure --format json advisory.json
csaf measure --format yaml advisory.json

# SARIF 2.2 - for GitHub code scanning or VS Code SARIF viewer
csaf measure --format sarif 'advisories/**/*.json' > measure.sarif

# Batch - text report with grand total footer
csaf measure 'advisories/**/*.json'

Adjusting the caution threshold:

# Rate a dimension caution when it exceeds 75% of the limit (default: 50%)
csaf measure --caution-fraction 0.75 advisory.json

Selecting the taxonomy version:

# v21 (default), v20, or the alias v21csd02
csaf measure --spec-version v20 advisory.json
csaf measure --spec-version v21csd02 advisory.json

Exit codes: 0 (all ok or caution), 1 (any exceeds, or a file could not be read), 2 (usage error).

The four official OASIS Appendix examples (docs/example/appendix/) all pass at ok posture. See example for the full per-file dimension reports.

Single-pass combined conformance + dimension report:

The command validate --with-measure runs both pipelines on the same decoded document - no second parse. The dimension block is appended to each file's conformance output.

# Single file: conformance + dimensions in one invocation
csaf validate --with-measure advisory.json

# Also fail on any exceeds posture (default: dimension posture does not affect exit code)
csaf validate --with-measure --measure-exit advisory.json

# Machine-readable output with embedded measure key
csaf validate --format json --with-measure advisory.json

# SARIF with two runs per file (validation run + measure run)
csaf validate --format sarif --with-measure advisory.json

Skip rules

Rules can be suppressed individually or via a YAML skip file. Suppressed rules appear as [SKIP] in the output and do not affect the exit code.

CSV on the command line:

csaf validate --skip-rules 6.1.9,6.2.39.02 advisory.json

# May be specified multiple times (processed left to right)
csaf validate --skip-rules 6.1.9 --skip-rules 6.2.39.02 advisory.json

Re-enable a rule skipped by a previous argument or file (prefix with +):

csaf validate --skip-rules base.yaml --skip-rules +6.1.9 advisory.json

YAML skip file - supports structured entries with reason and expiry:

# skip.yaml
- "schema"
- id: "6.1.9"
  reason: "CVSS v3 scorer deviation - under review"
  expires: "2026-12-31"
csaf validate --skip-rules skip.yaml advisory.json

Expired entries still take effect; the validator prints a warning to stderr.

Official examples

The example directory contains official OASIS CSAF 2.1 advisory examples from the CSAF TC repository: six general advisories, four normative appendix examples (collapsing product paths, examples 11–14), and thirteen VEX use-case documents.

See example for per-example validation reports and notes on findings.

To refresh the examples from upstream:

python bin/sync_examples.py           # download/update all files
python bin/sync_examples.py --show    # list bundled files and sizes
python bin/sync_examples.py --dry-run # compare with upstream without writing

Bundled catalogs

All external reference data is bundled and kept up to date within the package. No network access is required for validation.

Catalog Bundled version Sync script
CWE v4.9–v4.20 (969 weaknesses) python bin/fetch_cwe.py
SPDX 3.28.0 + ScanCode licensedb python bin/sync_spdx.py
SSVC format_version 3 python bin/sync_ssvc.py
CSAF translations v2.1 (de) python bin/sync_translations.py

Life Cycle Management

Four categories of data bundled in the package require periodic maintenance.

Category Location Update trigger
TC fixture data csaf/v21/data/ New TC test suite release
Spec schema files csaf/v21/schema/ Schema normative change
Reference catalogs csaf/v21/{cwe,spdx,ssvc,translations}/ Upstream version release
Official examples docs/example/ New CSAF TC release (main, appendix, or VEX)

TC fixture data

The test suite reads fixture files from csaf/csaf/v21/data/{mandatory,recommended,informative}/. These are a snapshot of the OASIS CSAF TC test suite and require a sibling checkout of the TC repository to refresh.

make sync-fixtures csaf_tc_root=../csaf-2.1   # default: csaf_tc_root=../csaf-2.1

After syncing, run the test suite to confirm all fixture-driven tests still pass:

python -m pytest test/ -q

New fixtures for rules that were previously not_implemented will cause new tests to be collected; updated fixtures may change pass/fail counts. Investigate any unexpected failures before committing.

Once the test suite is green, stage and commit the changed files:

fossil add csaf/csaf/v21/data/
fossil commit -m "sync: TC fixture data YYYY-MM-DD"

CWE catalog

The CWE catalog at csaf/csaf/v21/cwe/catalog.json covers twelve historic versions (4.9–4.20) in a single compact file. Refresh it by running the fetch script, which downloads the XML archives from MITRE and rebuilds the catalog:

python bin/fetch_cwe.py

Pass --cache-dir PATH to keep downloaded ZIP files locally and avoid re-fetching on subsequent runs. Pass --min-version VERSION to start from a different earliest version (default: 4.9). The script auto-detects the current latest version from MITRE's cwec_latest.xml.zip.

SPDX license catalog

The SPDX catalog at csaf/csaf/v21/spdx/catalog.json combines the SPDX license list with the ScanCode license database.

Network (default):

python bin/sync_spdx.py

Air-gapped - supply locally downloaded source files:

python bin/sync_spdx.py --spdx-licenses licenses.json --spdx-exceptions exceptions.json --scancode scancode-index.json

Download sources from the SPDX license list JSON API and the ScanCode licensedb index.

SSVC decision point catalog

The SSVC catalog at csaf/csaf/v21/ssvc/catalog.json is built from the CERTCC/SSVC repository.

python bin/sync_ssvc.py --sync ssvc --sync cvss   # sync both namespaces
python bin/sync_ssvc.py --show                    # print current catalog
python bin/sync_ssvc.py --namespace ssvc --key A --latest-version 3.0.0  # manual override

Syncing requires network access to the GitHub Contents API. For air-gapped environments, review the upstream repository offline and apply changes with --namespace / --key / --latest-version.

CSAF translations catalog

The translations catalog at csaf/csaf/v21/translations/translations.json is maintained by the OASIS CSAF TC.

python bin/sync_translations.py             # fetch and write
python bin/sync_translations.py --show      # print current catalog
python bin/sync_translations.py --dry-run   # compare with upstream without writing

OASIS examples

The official OASIS CSAF 2.1 examples are bundled in docs/example/ (main advisories), docs/example/appendix/ (Appendix normative examples), and docs/example/csaf_vex/ (VEX use cases). All three groups are refreshed via bin/sync_examples.py.

python bin/sync_examples.py             # download/refresh all groups
python bin/sync_examples.py --show      # print bundled filenames and sizes
python bin/sync_examples.py --dry-run   # compare with upstream without writing
python bin/sync_examples.py --no-appendix  # skip appendix/ group
python bin/sync_examples.py --no-vex       # skip csaf_vex/ group

After syncing, stage and commit the changed files:

fossil add docs/example/
fossil commit -m "sync: OASIS CSAF examples YYYY-MM-DD"

Adding a new bundled catalog

To add a new reference catalog following the established pattern:

  1. Create bin/sync_<name>.py with network and (where possible) air-gap modes.
  2. Create csaf/csaf/v21/<name>/ and add the generated JSON file.
  3. Add package-data globs to pyproject.toml.
  4. Add an lru_cache loader in csaf/csaf/v21/rules/_shared.py.
  5. Add a section provider in csaf/_env.py for info env output.
  6. Add the catalog to the "Bundled catalogs" table in this README.

Development Workflow

The standard pre-release gate sequence is:

make distclean check-wheel check-completions quality test-compat

Each target in the sequence guards a distinct concern.

distclean

Removes all generated artefacts — compiled bytecode, coverage data, dist/, site/, virtual environments, and fuzz findings — leaving only committed source. Run this first to ensure the wheel build and test suite start from a clean state.

make distclean

check-wheel

Builds the source distribution and wheel via python -m build, then verifies that every source data file declared in pyproject.toml is present in the wheel. Guards against accidental omission of bundled catalogs, schema files, TC fixture data, manual markdown pages, or completion scripts from the published package.

make check-wheel

check-completions

Regenerates shell completion scripts for bash, fish, and zsh into a temporary directory and diffs them against the committed scripts in docs/completion/. Exits 1 and prints the diff if any script is stale. Skipped silently when shtab is not installed.

make check-completions   # check only
make completions         # regenerate and overwrite docs/completion/

check-completions also runs automatically as part of make lint (and therefore make quality).

quality

Runs the full static-analysis and test pipeline:

make quality

Dependency chain:

lint : check-completions, check-vcs, check-docs, check-manual-md, validate-pyproject, ruff, black, pylint

types : mypy --strict

test : pytest (after lint and types)

coverage : pytest with branch coverage report

secure : bandit

check-vcs verifies that every script in bin/ is tracked by version control. check-manual-md verifies that the generated markdown in csaf/manual/ is in sync with the troff sources in docs/man/.

test-compat

Runs the full test suite in parallel under CPython 3.11, 3.12, 3.13, and 3.14 via uv. Each interpreter gets its own isolated virtual environment under /tmp/. Snapshot tests (test/test_tui_snapshot.py) are excluded because they are terminal-geometry-sensitive. Logs for each version are written to /tmp/csaf-compat-3.1N.log and summarised on exit.

make test-compat

Requires uv and pre-downloaded interpreter builds; runs fully offline (--offline flag passed to uv run).

Fuzzing

Coverage-guided fuzz testing uses AFL via python-afl. The different harnesses cover the parser and filter functions with the largest attack surfaces.

Target Harness Functions covered
cvss-vector fuzz/fuzz_cvss_vector.py _parse_cvss_vector, _cvss2/3/4_base_score
distribute-aggregator fuzz/fuzz_distribute_aggregator.py JSON parsing + jsonschema validation against bundled aggregator schema
distribute-provider fuzz/fuzz_distribute_provider.py JSON parsing + jsonschema validation against bundled provider schema
env-coerce fuzz/fuzz_env_coerce.py _coerce_typed (all config field types)
interface fuzz/fuzz_interface.py handle_interface_early, _fmt_choice
locate fuzz/fuzz_locate.py normalize_domain, _parse_security_txt_csaf
only-groups fuzz/fuzz_only_groups.py _filter_by_groups
prefix fuzz/fuzz_prefix.py _disambiguate, _expand_option_values
purl fuzz/fuzz_purl.py _validate_purl, _purl_base, _purl_version
rolie fuzz/fuzz_rolie.py check_rolie_feed/service/category, detect_and_check
skip-rules fuzz/fuzz_skip_rules.py _build_skip_rules (CSV branch)
spdx-expr fuzz/fuzz_spdx_expr.py _parse_spdx_expression
trusted fuzz/fuzz_trusted.py _extract_advisory_urls_from_feed
ttl fuzz/fuzz_ttl.py _parse_ttl
vers fuzz/fuzz_vers.py _parse_vls, _get_vers_pairs

Prerequisites: afl-fuzz and python-afl must be installed and on PATH. On macOS with pyenv, ensure the virtualenv is active so PYTHON_BIN resolves to the real interpreter (not the pyenv shim).

# Run all targets sequentially (default: 60 s each)
make fuzz

# Run a single target
make fuzz-ttl

# Adjust the time budget
make fuzz-cvss-vector fuzz_time=300

# After a run, promote AFL-discovered queue entries into the seed corpus
make fuzz-update-seeds
# Review fuzz/seeds/ and commit any valuable new seeds

Crash and hang findings land in fuzz/findings/<target>/. The seed corpus lives in fuzz/seeds/<target>/. Each target's seed directory contains at least one valid, non-crashing input so AFL can establish a baseline before mutation begins.

Design and requirements

Requirements and design specification are both presented in the MIL-STD-498 SRS and SDD structures.

Software Requirements Specification : CSAF-PROD-SRS-001 - SRS

Software Design Description : CSAF-PROD-SDD-001 - SDD

Bug Tracker

Feature requests and bug reports go to the todos of csaf.

Primary Source repository

The main source of csaf is on a mountain in Central Switzerland under configuration control (fossil).

Contributions

To share small changes under the repository's license, kindly send a patchset per email using git send-email.

Support

Submit issues at https://todo.sr.ht/~sthagen/csaf or write plain text email to ~sthagen/csaf@lists.sr.ht.

Security Policy

See SECURITY.md for the security policy.

Changes

See releases for release summaries and releases/changes for the detailed change log.

Coverage

The test suite maintains a branch coverage above 80% during prototyping and documented at coverage/.

SBOM

Runtime dependency information is published in SPDX 3.0 (JSON-LD) and CycloneDX 1.6 (JSON) formats. See SBOM for a human readablke summary of the component inventory and a validation guide.

Download files

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

Source Distribution

csaf-2026.9.1.tar.gz (832.6 kB view details)

Uploaded Source

Built Distribution

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

csaf-2026.9.1-py3-none-any.whl (1.5 MB view details)

Uploaded Python 3

File details

Details for the file csaf-2026.9.1.tar.gz.

File metadata

  • Download URL: csaf-2026.9.1.tar.gz
  • Upload date:
  • Size: 832.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for csaf-2026.9.1.tar.gz
Algorithm Hash digest
SHA256 fc0b8edbab9bafb24e0b73c2ec0a0208c8f451544de71611bf9aec7fcf460112
MD5 0613d9e67e6be47e4624a4e18b6ad21c
BLAKE2b-256 4b1f3921356d0d53b726eb4487c47b6fc7f78718125b326ddad97150c1792cb5

See more details on using hashes here.

File details

Details for the file csaf-2026.9.1-py3-none-any.whl.

File metadata

  • Download URL: csaf-2026.9.1-py3-none-any.whl
  • Upload date:
  • Size: 1.5 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for csaf-2026.9.1-py3-none-any.whl
Algorithm Hash digest
SHA256 b02537b7019d9b28e7e46c157fb9f8de27909850754c1b310c35156e7a670bd7
MD5 2ae135fc75941017d9730d346683dc52
BLAKE2b-256 d4ca6707840506f35e00134f8fc7cfbf549111dbae7829d6a2ea7166e027cfdd

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

2026.9.1 This release

2 files

2026.2.1

2 files

2025.10.2

2 files

2024.12.18

2 files

2023.11.27

2 files

2023.10.18

2 files

2023.6.18

2 files

2023.5.9

2 files

2023.5.8

2 files

2023.5.6

2 files

2022.3.13

2 files

2022.3.12

2 files

0.0.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page