Audit and compliance

CI audit gate

ci_gate() is the recommended entry point for CI pipelines. It scans a directory, evaluates a policy, optionally writes SARIF/JSON output, and returns an exit code:

import sys
from quantum_safe.audit import Auditor, AuditPolicy

exit_code = Auditor.ci_gate(
    "./src",
    policy=AuditPolicy(allow_classical_only=False, hybrid_required=True),
    output_sarif="audit.sarif",    # GitHub Code Scanning
    output_json="audit.json",
)
sys.exit(exit_code)

Audit policies

AuditPolicy controls which findings block the CI gate. Four presets are available:

Preset

Behaviour

permissive

Never blocks; reports only.

transition

Blocks on CRITICAL only. Allows hybrid during migration.

standard

Blocks on HIGH+. Classical-only is a warning. Default.

strict

Blocks on MEDIUM+. Requires hybrid for all new key usage.

from quantum_safe.audit import AuditPolicy

# Use a preset
policy = AuditPolicy.from_preset("strict")

# Or configure manually
policy = AuditPolicy(
    allow_classical_only=False,
    hybrid_required=True,
    block_on_severity="HIGH",
)

Auditor

Auditor exposes the full audit pipeline for programmatic use:

from quantum_safe.audit import Auditor, AuditPolicy
from quantum_safe.migrate import Scanner

report = Auditor.audit_source("./src", policy=AuditPolicy.from_preset("standard"))
print(report.summary())

# Individual finding fields
for f in report.critical:
    print(f.file, f.line, f.rule_id, f.message, f.fix_hint)

NIST compliance report

NISTComplianceChecker maps scanner findings to specific NIST/CISA controls:

from quantum_safe.audit import NISTComplianceChecker
from quantum_safe.migrate import Scanner

scan   = Scanner.scan_directory("./src")
report = NISTComplianceChecker.check(scan, target="./src")
print(report.to_json())

Each finding is annotated with the relevant standards:

  • FIPS 203 (ML-KEM)

  • FIPS 204 (ML-DSA)

  • FIPS 205 (SLH-DSA)

  • NIST SP 800-208

  • CISA Post-Quantum Cryptography Checklist

CycloneDX SBOM enrichment

SBOMEnricher annotates a CycloneDX SBOM with PQC-readiness assessments for each component:

import json
from quantum_safe.audit import SBOMEnricher

with open("sbom.json") as f:
    sbom = json.load(f)

enriched, assessments = SBOMEnricher.enrich(sbom)

not_ready = [a for a in assessments if a.readiness.value == "NOT_READY"]
for a in not_ready:
    print(f"NOT READY: {a.name} {a.version}")
    print(f"  Action: {a.action}")

with open("sbom-pqc.json", "w") as f:
    json.dump(enriched, f, indent=2)

Readiness values:

  • READY — uses hybrid or pure PQC algorithms

  • PARTIAL — partially migrated

  • NOT_READY — classical-only

  • UNKNOWN — insufficient information

From a requirements.txt:

enriched, assessments = SBOMEnricher.from_requirements("requirements.txt")

CLI

# Scan with text output (default)
qs-audit scan ./src

# SARIF for GitHub Code Scanning
qs-audit scan ./src --format sarif --output audit.sarif

# JSON report
qs-audit scan ./src --format json --output audit.json

# Use a policy preset
qs-audit scan ./src --preset-policy strict

# Fail CI on HIGH or above findings
qs-audit scan ./src --fail-on high

# Enrich a CycloneDX SBOM
qs-audit sbom sbom.json --output sbom-pqc.json

# Quick requirements.txt check
qs-audit requirements requirements.txt

# NIST compliance report
qs-audit compliance ./src --format json --output compliance.json