pqc-scan is organized as a Rust workspace with clear module boundaries for CLI, core scanning, rule loading, detectors, and reporting.
pqc_scan_cli- CLI parsing (
clap) - command dispatch (
scan,rules list) - fail-on threshold behavior (
high,critical)
- CLI parsing (
pqc_scan_core- repository walking
- pipeline orchestration
- finding normalization and deduplication
- risk/severity adjustment
- runtime/dependency profiling
- recommendation enrichment
- source snippet extraction for findings
pqc_scan_rules- YAML rule loading and validation
- regex compilation at load time
- rule indexing and filtering by kind
pqc_scan_detectorstree_sitter_detectorregex_detectordependency_detectorcertificate_detectorkey_detector
pqc_scan_report- report writers for JSON / HTML / Markdown / SARIF
- CBOM and dependency SBOM output
- Load rules from
rules/default/(or custom--rules-dir) - Walk repository files with
.gitignoreawareness - Exclude default paths and large files (
> 2 MB) - Run detectors in parallel (file-level concurrency via
rayon) - Convert detector output (
Detection) into normalized findings (Finding) - Apply risk-aware severity adjustment
- Deduplicate repeated hits
- Build dependency inventory from detector metadata (
dependency-sbom.json) - Build runtime/dependency profile from repo manifests + dependency signals
- Enrich findings with recommended migration actions
- Attach source snippets (line window + highlighted hit line)
- Build CBOM from findings (
cbom.json) - Emit selected report formats
Rules are YAML-defined and loaded dynamically.
Supported kind values:
regextree_sitterdependencycertificatekey
Rule fields:
idkindcategoryseverityriskconfidencemigration_hintpatternscopedescription(optional)
Compilation strategy:
- Regex patterns are compiled once during rule loading
- Invalid regex fails fast with rule id context
- Rule IDs are deduplicated and indexed for O(1) lookup
All detectors implement the shared Detector trait:
name() -> &'static strdetect(file, rules) -> Vec<Detection>
- Parses source code and inspects semantic node types
- Applies tree-sitter scoped rules per language
- Current language support:
- Java
- Go
- JavaScript
- TypeScript
- Python
- Rust
- Ruby
- Fast lexical matching over text files
- Produces line/column offsets and masked evidence previews
- Parses common manifests and lock files
- Parses CycloneDX/SPDX JSON files as dependency input
- Emits both:
- dependency inventory entries
- rule-based dependency findings
- Parses PEM/DER certificate data (
x509-parser,pem) - Extracts signature algorithm, OID, key size, expiration
- Matches certificate rules against extracted metadata
- Uses efficient marker matching for private key blocks
- Classifies private-key hits as sensitive
- Never emits raw key material
Locationfile,line,column
Evidencetype,match,snippet_preview,metadata
Finding- rule/risk/severity/confidence metadata
migration_hintrecommended_actions[]source_snippet(optional)
RecommendedActionaction_id,title,priority,rationalesteps[],references[],code_examples[]
SourceSnippet- 4-5 line context window (default: hit line ±2 lines)
- explicit highlighted line flag
CbomEntry- component/algorithm/usage/location/quantum_risk/migration_hint
DependencySbomEntry- name/version/ecosystem/source_file/source_type/purl
Risk categories:
quantum-vulnerablequantum-uncertainquantum-safenon-quantum-risk
Severity levels:
infolowmediumhighcritical
Adjustment strategy:
- Sensitive categories (
TLS,PKI,JWT,auth) can be severity-boosted - Only high-confidence vulnerable findings are promoted
- Private key evidence is forced to highest severity path
The recommendation engine enriches each finding with concrete next actions.
Inputs:
- finding attributes (rule/category/risk/evidence/location)
- language signal (from AST metadata and file extension)
- runtime profile (Java/Node/Go/Python/Rust/Ruby hints)
- dependency signals (for example BouncyCastle presence)
Behavior:
- adds generic migration planning actions for quantum-vulnerable findings
- adds category-specific actions (JWT/TLS/PKI/CryptoAPI)
- adds language/runtime-specific migration suggestions
- includes references and optional before/after code examples
For each finding:
- read source text once per file (cache-backed)
- extract local line window around the matched line
- mark the hit line for highlight rendering in reports
- sanitize output:
- private key lines are masked
- overly long lines are clipped
- binary files are skipped
- full machine-readable scan result
- includes findings, recommendations, source snippets, summary
- analyst-friendly report UI
- severity badges, finding metadata, recommendation blocks
- line-numbered source snippets with highlighted hit line
- human-readable text report
- suitable for artifact archives and PR comments
- GitHub code scanning compatible output
- maps severity to SARIF levels (
error/warning/note) - includes migration hint and recommended action summary
cbom.json: cryptographic bill of materials from findingsdependency-sbom.json: normalized dependency inventory from manifests/SBOMs
- file-level parallel detector execution (
rayon) - precompiled rule regex for repeated scans
- bounded scan scope:
.gitignorerespected- default directory exclusions
- max file size guard
- low-overhead deduplication to reduce report noise
- sensitive material is always masked in evidence/snippets
- private key content is never exported
- detector output is normalized before reporting
- scan is read-only against repository contents
- Add a new detector:
- implement
Detectortrait - register in
pqc_scan_detectors::default_detectors() - add matching rule kind/patterns
- implement
- Add new rule packs:
- place YAML files under a rules directory
- load with
--rules-dir
- Extend recommendations:
- add templates in core recommendation module
- bind by category/language/runtime/dependency signals
- Add a new report format:
- implement writer module in
pqc_scan_report - register enum variant and output path mapping
- implement writer module in