Status: IMPLEMENTED. This document describes the
optional project configuration file that qScan and @quantakrypto/core consume.
core's loadConfig reads + validates the file; qScan applies it under the
precedence rule below. This page is both the spec and the reference; where the
implementation narrows a "proposed" detail (see notes inline), the behavior here
is authoritative.
Today qScan is configured entirely by CLI flags (qscan README),
and ScanOptions carries a few options that are not yet wired. A committed config file lets a project encode its scan
policy once — include/exclude globs, size limits, the severity gate, which
detector families/languages to run, and a baseline path — so CI, the editor (MCP),
and local runs agree without repeating long flag lists.
- File name:
quantakrypto.config.json, discovered at the scanroot(i.e.<root>/quantakrypto.config.json). An absent file is tolerated — the scan proceeds on flags + defaults. (The implementation looks at the scan root directly rather than walking up the tree; root-relative discovery is simpler and auditable, and--configcovers the "config lives elsewhere" case.) - A
--config <path>flag overrides discovery and names the file explicitly; a missing explicitly-named file is a usage error (exit 2). --no-config-filedisables discovery entirely. Note the naming: the file controls are--config/--no-config-file, deliberately distinct from the pre-existing--no-configflag, which toggles config/TLS detector scanning (a different concern). They do not collide.- Exactly one config file applies per run; configs do not merge across directories (no cascading), to keep precedence simple and auditable.
No tool requires it: --baseline and --policy take any path, and the config
file itself is discovered at the scan root. But every example in this repository
writes the files a project commits into .quantakrypto/:
| File | Path |
|---|---|
Baseline (--write-baseline / --baseline) |
.quantakrypto/baseline.json |
Org cryptography policy (--policy) |
.quantakrypto/crypto-policy.json |
qProbe ownership manifest (--owned-hosts) |
.quantakrypto/owned-hosts.txt |
One convention, so a reader who has seen one of our examples can guess the rest,
and so a project's quantakrypto state is one reviewable directory rather than
loose files at the repository root. The docs used to disagree with themselves
here (qscan-baseline.json, .quantakrypto/baseline.json and .qscan/ all
appeared), which is worth nothing but costs a reader a moment of doubt every
time.
Effective options are resolved with a strict, documented order. Flags beat config; config beats defaults. There is no environment-variable layer in this spec.
CLI flags > quantakrypto.config.json > built-in defaults
(highest) (lowest)
Resolution is per-key, not all-or-nothing: a flag overrides only the key it
sets, leaving other keys to come from config or defaults. List-valued keys
(include, exclude) follow the rule in §4.2 (flags append by default, with an
explicit replace form) — chosen so a config baseline of excludes is additive with
ad-hoc CLI excludes, which is the common case.
A single JSON object. All keys optional. Unknown keys are a warning, not an
error (forward compatibility), except a malformed value for a known key, which
is a usage error (exit 2). JSON only (no comments) so it parses with JSON.parse
under ADR-0001's zero-dep rule.
| Key | Type | Default | Maps to | Notes |
|---|---|---|---|---|
version |
int | 1 |
— | Config schema version. Unknown future versions are a warning + best-effort. |
include |
string[] | (all scannable) | ScanOptions.include |
Substring/prefix/glob patterns (§4.2). Empty/omitted = scan everything not excluded. |
exclude |
string[] | [] |
ScanOptions.exclude |
Added to the built-in default ignores unless noDefaultIgnores. |
noDefaultIgnores |
bool | false |
ScanOptions.noDefaultIgnores |
Disables node_modules/.git/dist/… defaults. |
maxFileSize |
int (bytes) | 2097152 |
ScanOptions.maxFileSize |
Files larger are skipped; the perf/security 2 MiB cap rationale applies. |
detectors.<family> |
bool | true |
maps to source/config/dependencies scan toggles + per-family selection |
Family names mirror @quantakrypto/core's detector families and the --no-source/--no-deps/--no-config flags. Turning a family off is equivalent to its --no-* flag. |
disabledRules |
string[] | [] |
ScanOptions.disabledRules |
Rule ids to suppress (e.g. "node-crypto-ecdh", "tls-weak-cipher"). Finer-grained than detectors.<family>. See the catalog via the MCP list_rules tool (or the quantakrypto://rules resource). Unknown ids are harmless (never match). |
languages |
string[] | (all built-in) | (forward-looking) | See §4.3 — has no effect until the detector-registry/plugin work lands. |
severityThreshold |
enum | high |
runQscan({severityThreshold}) |
Drives the exit code. CLI --severity-threshold overrides. |
baseline |
string (path) | none | runQscan({baseline}) |
Relative to the config file's directory. CLI --baseline overrides. |
- Patterns support globs and plain matching: a pattern containing
*,?, or[…]is matched as an anchored glob (*within a path segment,**across segments,**/an optional path prefix, e.g.src/**,**/*.ts,**/vendor/**); a pattern with no glob metacharacter keeps the historical substring / path-prefix semantics ("src"matchessrc/a.ts,"secrets"matches anywhere). excludefrom config is unioned with built-in default ignores (unlessnoDefaultIgnores: true) and with any CLI--ignoreflags (CLI appends).includefrom config sets the base inclusion set; CLI include flags (if added) append. An explicit replace form ("include!"/ a--include-onlyflag) is reserved for a future revision and out of scope here.- Exclude always wins over include when both match a path.
languages is specified now so the file format is stable, but it is inert
until makes detectors a real plugin point with a
declared language/scope per detector. Until then, detector selection is via
detectors.<family>. When the registry lands, languages filters the active
detector set by declared language (e.g. ["python","go"]).
baselinein the config is equivalent to passing--baseline(resolved relative to the config file's directory);--write-baselineremains CLI-only (it is an action, not config state).- Only the
qscanCLI readsquantakrypto.config.json. The Action callsrunQscanwith its own inputs and does not auto-discover a config file, and the MCP server does not read one either. This is deliberate, not a gap: both run over trees the operator may not control (an untrusted fork PR; a hosted workspace), and a discovered config is authored by whoever owns that tree — letting it change scan strictness there would be a scan-integrity bypass. Config-as-shared-policy is a trusted-local-operator feature. - Auto-discovered vs explicit trust (CLI). Because an auto-discovered config can
come from the scanned tree, the CLI warns for each policy-weakening key a
discovered config applies (disabled rules, a raised severity-threshold, excludes,
scope toggles, a size cap) and points at
--no-config-fileto ignore it. A config named explicitly with--config <path>is the operator's own choice and applies quietly. Use--no-config-fileto scan an untrusted tree with zero config influence.
- Parse with
JSON.parse; on syntax error, exit 2 with the file path and offset. - Validate value types against this schema; an out-of-range enum or wrong type for a known key is a usage error (exit 2). Unknown keys warn and are ignored.
- The implementation should treat the parsed object as untrusted input in the same spirit as scanned manifests (THREAT-MODEL Q-09): no deep merge of parsed config into prototypes; membership-test keys only.
- An env-var configuration layer.
- Cascading/merged configs across directories.
- A JSON Schema file artifact (the
$schemaURL above is a placeholder for when one is published). - Per-rule severity overrides and CWE mapping config (would pair with CWE tagging).
{ "$schema": "https://quantakrypto.com/schema/quantakrypto.config.v1.json", "version": 1, // ── file selection ────────────────────────────────────────────── "include": ["src/**", "packages/*/src/**"], // patterns to scan (see §4.2) "exclude": ["**/vendor/**", "legacy/**"], // patterns to skip (added to defaults) "noDefaultIgnores": false, // disable node_modules/.git/dist/… ignores "maxFileSize": 2097152, // bytes; default 2 MiB // ── what to scan ──────────────────────────────────────────────── "detectors": { // toggle detector families "node-crypto": true, "webcrypto": true, "crypto-libs": true, "jwt-jose": true, "tls-config": true, "pem-material": true, "dependencies": true }, "languages": ["js", "ts"], // forward-looking; see §4.3 // ── policy ────────────────────────────────────────────────────── "severityThreshold": "high", // gate: critical|high|medium|low|info "baseline": ".quantakrypto/baseline.json" // path to a baseline file }