@quantakrypto/qscan 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Baseline support for qScan — a thin adapter over the **canonical** baseline
3
+ * implementation in `@quantakrypto/core` (P1-1).
4
+ *
5
+ * Historically qScan carried its own baseline scheme (12-char hash of
6
+ * `ruleId|file|snippet|line`) that was incompatible with the GitHub Action's.
7
+ * Both have been unified onto core's single source of truth, so this module no
8
+ * longer defines its own format or hashing — it re-exports core's primitives
9
+ * and adds only the small filename-resolution / API-shape conveniences the CLI
10
+ * and `@quantakrypto/action` rely on.
11
+ *
12
+ * The on-disk format is core's {@link Baseline}: `{ version, fingerprints }`,
13
+ * where each fingerprint is a full, line-INSENSITIVE SHA-256 (so unrelated edits
14
+ * that shift line numbers no longer invalidate a baseline).
15
+ */
16
+ import { applyBaseline as coreApplyBaseline, baselineFromFindings, BASELINE_VERSION, fingerprintFinding, loadBaseline, saveBaseline, } from "@quantakrypto/core";
17
+ // Re-export core's canonical primitives so downstream tools (and tests) can use
18
+ // them through `@quantakrypto/qscan` without reaching into `@quantakrypto/core` internals.
19
+ export { baselineFromFindings, BASELINE_VERSION, fingerprintFinding, loadBaseline, saveBaseline };
20
+ /**
21
+ * Compute a stable fingerprint for a finding. Alias for core's
22
+ * {@link fingerprintFinding}; kept under the historical name `fingerprint` for
23
+ * source compatibility with existing call sites and tests.
24
+ */
25
+ export const fingerprint = fingerprintFinding;
26
+ /**
27
+ * Partition findings into those kept and those suppressed by a baseline.
28
+ *
29
+ * Wraps core's {@link coreApplyBaseline} (which takes a {@link Baseline} and
30
+ * returns `{ newFindings, suppressed }`) but preserves qScan's historical
31
+ * `{ kept, suppressed }` shape and its lenient `ReadonlySet<string>` overload so
32
+ * existing callers keep working.
33
+ *
34
+ * @param findings All findings produced by a scan.
35
+ * @param baseline Either a {@link Baseline} object or a set of accepted
36
+ * fingerprints.
37
+ */
38
+ export function applyBaseline(findings, baseline) {
39
+ const resolved = baseline instanceof Set
40
+ ? { version: BASELINE_VERSION, fingerprints: [...baseline] }
41
+ : baseline;
42
+ const { newFindings, suppressed } = coreApplyBaseline(findings, resolved);
43
+ return { kept: newFindings, suppressed };
44
+ }
45
+ /**
46
+ * Build a {@link Baseline} from a set of findings (deduped + sorted). Alias for
47
+ * core's {@link baselineFromFindings} under qScan's historical name.
48
+ */
49
+ export function buildBaseline(findings) {
50
+ return baselineFromFindings(findings);
51
+ }
52
+ /**
53
+ * Read a baseline file from disk and return its accepted fingerprints as a set.
54
+ *
55
+ * Unlike core's tolerant {@link loadBaseline} (which returns an empty baseline
56
+ * for a missing/unparseable file), this preserves qScan's historical *strict*
57
+ * contract: a missing or malformed file is an error, surfaced to the CLI as an
58
+ * I/O failure (exit 2).
59
+ *
60
+ * @throws {Error} If the file cannot be read or is not valid baseline JSON.
61
+ */
62
+ export async function readBaseline(path) {
63
+ const { readFile } = await import("node:fs/promises");
64
+ let raw;
65
+ try {
66
+ raw = await readFile(path, "utf8");
67
+ }
68
+ catch (cause) {
69
+ throw new Error(`could not read baseline file "${path}": ${errMessage(cause)}`);
70
+ }
71
+ let parsed;
72
+ try {
73
+ parsed = JSON.parse(raw);
74
+ }
75
+ catch (cause) {
76
+ throw new Error(`baseline file "${path}" is not valid JSON: ${errMessage(cause)}`);
77
+ }
78
+ if (!isBaselineFile(parsed)) {
79
+ throw new Error(`baseline file "${path}" is missing a string "fingerprints" array`);
80
+ }
81
+ return new Set(parsed.fingerprints);
82
+ }
83
+ /** Serialize and write a baseline to disk (pretty-printed, trailing newline). */
84
+ export async function writeBaseline(path, baseline) {
85
+ const { writeFile } = await import("node:fs/promises");
86
+ const json = `${JSON.stringify(baseline, null, 2)}\n`;
87
+ try {
88
+ await writeFile(path, json, "utf8");
89
+ }
90
+ catch (cause) {
91
+ throw new Error(`could not write baseline file "${path}": ${errMessage(cause)}`);
92
+ }
93
+ }
94
+ /** Narrowing type guard for parsed baseline JSON. */
95
+ function isBaselineFile(value) {
96
+ if (typeof value !== "object" || value === null)
97
+ return false;
98
+ const obj = value;
99
+ return Array.isArray(obj.fingerprints) && obj.fingerprints.every((f) => typeof f === "string");
100
+ }
101
+ /** Extract a human message from an unknown thrown value. */
102
+ function errMessage(cause) {
103
+ return cause instanceof Error ? cause.message : String(cause);
104
+ }
105
+ //# sourceMappingURL=baseline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseline.js","sourceRoot":"","sources":["../src/baseline.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * qScan command-line entry point.
4
+ *
5
+ * Thin shell over the programmatic API in `./index.ts`:
6
+ * parse argv → runQscan → print/write report → process.exit(code).
7
+ *
8
+ * All policy (scanning, baseline, thresholds, rendering) lives in `index.ts`;
9
+ * this file only deals with argv, stdout/stderr, files, and exit codes.
10
+ */
11
+ /** Run the CLI and return the desired process exit code (never throws). */
12
+ export declare function main(argv: readonly string[]): Promise<number>;
13
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AAeH,2EAA2E;AAC3E,wBAAsB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA+FnE"}
package/dist/cli.js ADDED
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * qScan command-line entry point.
4
+ *
5
+ * Thin shell over the programmatic API in `./index.ts`:
6
+ * parse argv → runQscan → print/write report → process.exit(code).
7
+ *
8
+ * All policy (scanning, baseline, thresholds, rendering) lives in `index.ts`;
9
+ * this file only deals with argv, stdout/stderr, files, and exit codes.
10
+ */
11
+ import { writeFile } from "node:fs/promises";
12
+ import process from "node:process";
13
+ import { pathToFileURL } from "node:url";
14
+ import { ConfigError } from "@quantakrypto/core";
15
+ import { ArgError, parseArgs } from "./args.js";
16
+ import { resolveConfig } from "./config.js";
17
+ import { HELP_TEXT, versionLine } from "./help.js";
18
+ import { EXIT, runQscan } from "./index.js";
19
+ /** Run the CLI and return the desired process exit code (never throws). */
20
+ export async function main(argv) {
21
+ let parsed;
22
+ try {
23
+ parsed = parseArgs(argv);
24
+ }
25
+ catch (err) {
26
+ if (err instanceof ArgError) {
27
+ process.stderr.write(`qscan: ${err.message}\n`);
28
+ process.stderr.write(`Run "qscan --help" for usage.\n`);
29
+ return EXIT.ERROR;
30
+ }
31
+ throw err;
32
+ }
33
+ if (parsed.kind === "help") {
34
+ process.stdout.write(HELP_TEXT);
35
+ return EXIT.OK;
36
+ }
37
+ if (parsed.kind === "version") {
38
+ process.stdout.write(`${versionLine()}\n`);
39
+ return EXIT.OK;
40
+ }
41
+ // Resolve `quantakrypto.config.json` (flags > config > defaults) before scanning.
42
+ let options;
43
+ try {
44
+ const resolved = await resolveConfig(parsed.options, parsed.explicit);
45
+ options = resolved.options;
46
+ if (!options.quiet) {
47
+ for (const w of resolved.warnings) {
48
+ process.stderr.write(`qscan: config warning: ${w}\n`);
49
+ }
50
+ if (resolved.configPath) {
51
+ process.stderr.write(`qscan: using config ${resolved.configPath}\n`);
52
+ }
53
+ }
54
+ }
55
+ catch (err) {
56
+ if (err instanceof ConfigError) {
57
+ process.stderr.write(`qscan: ${err.message}\n`);
58
+ return EXIT.ERROR;
59
+ }
60
+ const message = err instanceof Error ? err.message : String(err);
61
+ process.stderr.write(`qscan: ${message}\n`);
62
+ return EXIT.ERROR;
63
+ }
64
+ // Color only when writing the human report to an interactive stdout.
65
+ const color = options.format === "human" &&
66
+ !options.output &&
67
+ Boolean(process.stdout.isTTY) &&
68
+ process.env.NO_COLOR === undefined;
69
+ let run;
70
+ try {
71
+ run = await runQscan(options, { color });
72
+ }
73
+ catch (err) {
74
+ const message = err instanceof Error ? err.message : String(err);
75
+ process.stderr.write(`qscan: ${message}\n`);
76
+ return EXIT.ERROR;
77
+ }
78
+ // --write-baseline: report what was written and stop.
79
+ if (run.baselineWritten) {
80
+ if (!options.quiet) {
81
+ const n = run.baselineWritten.fingerprints.length;
82
+ process.stderr.write(`qscan: wrote baseline with ${n} fingerprint${n === 1 ? "" : "s"} to ${options.writeBaseline}\n`);
83
+ }
84
+ return run.exitCode;
85
+ }
86
+ const report = run.report ?? "";
87
+ try {
88
+ if (options.output) {
89
+ await writeFile(options.output, report.endsWith("\n") ? report : `${report}\n`, "utf8");
90
+ if (!options.quiet) {
91
+ process.stderr.write(`qscan: wrote ${options.format} report to ${options.output}\n`);
92
+ }
93
+ }
94
+ else if (!options.quiet || options.format !== "human") {
95
+ // In quiet mode we still emit machine formats to stdout (the point of a
96
+ // pipe), but suppress the human banner.
97
+ process.stdout.write(report.endsWith("\n") ? report : `${report}\n`);
98
+ }
99
+ }
100
+ catch (err) {
101
+ const message = err instanceof Error ? err.message : String(err);
102
+ process.stderr.write(`qscan: ${message}\n`);
103
+ return EXIT.ERROR;
104
+ }
105
+ if (!options.quiet && run.suppressed.length > 0) {
106
+ process.stderr.write(`qscan: suppressed ${run.suppressed.length} finding(s) via baseline\n`);
107
+ }
108
+ return run.exitCode;
109
+ }
110
+ // Only auto-run when invoked as a script (not when imported by a test).
111
+ const invokedDirectly = process.argv[1] !== undefined && import.meta.url === pathToFileURL(process.argv[1]).href;
112
+ if (invokedDirectly) {
113
+ main(process.argv.slice(2))
114
+ .then((code) => process.exit(code))
115
+ .catch((err) => {
116
+ const message = err instanceof Error ? (err.stack ?? err.message) : String(err);
117
+ process.stderr.write(`qscan: fatal: ${message}\n`);
118
+ process.exit(EXIT.ERROR);
119
+ });
120
+ }
121
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * qScan-side resolution of `quantakrypto.config.json` (ROADMAP P2-9, docs/CONFIG.md).
3
+ *
4
+ * core's {@link loadConfig} does the reading + type-validation; this module
5
+ * applies the file's values onto parsed CLI options with the documented
6
+ * precedence:
7
+ *
8
+ * CLI flags > quantakrypto.config.json > built-in defaults
9
+ *
10
+ * Resolution is **per-key**: a key set by a flag (tracked in the `explicit` set
11
+ * from `parseArgs`) is left alone; otherwise the config value fills it. The
12
+ * list-valued keys (`include` / `ignore`→`exclude`) *append* — the config
13
+ * provides a base set and any CLI flags add to it (docs/CONFIG.md §4.2).
14
+ */
15
+ import type { QuantakryptoFileConfig } from "@quantakrypto/core";
16
+ import type { ConfigurableKey, QscanOptions } from "./args.js";
17
+ /** What {@link resolveConfig} returns: the merged options + provenance. */
18
+ export interface ResolvedConfig {
19
+ /** Options with config applied under the flags > config > defaults rule. */
20
+ options: QscanOptions;
21
+ /** Absolute path of the config file that was applied, when one was. */
22
+ configPath?: string;
23
+ /** Non-fatal warnings from parsing (unknown keys, future version, …). */
24
+ warnings: string[];
25
+ }
26
+ /**
27
+ * Load and merge `quantakrypto.config.json` into the parsed CLI options.
28
+ *
29
+ * @param options Fully-resolved options from {@link parseArgs} (defaults filled).
30
+ * @param explicit The set of configurable keys the user set via a flag.
31
+ * @returns The merged options plus the applied config path + any warnings.
32
+ * @throws {ConfigError} (from core) on a malformed config or a missing
33
+ * explicitly-named `--config` file. The CLI maps this to exit 2.
34
+ */
35
+ export declare function resolveConfig(options: QscanOptions, explicit: ReadonlySet<ConfigurableKey>): Promise<ResolvedConfig>;
36
+ /**
37
+ * Apply a parsed config onto options under the precedence rule. Pure; returns a
38
+ * new options object. Scalars: config fills only keys NOT set by a flag. Lists:
39
+ * config provides the base and the CLI flag values are appended.
40
+ */
41
+ export declare function applyConfig(options: QscanOptions, config: QuantakryptoFileConfig, explicit: ReadonlySet<ConfigurableKey>): QscanOptions;
42
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAEjE,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE/D,2EAA2E;AAC3E,MAAM,WAAW,cAAc;IAC7B,4EAA4E;IAC5E,OAAO,EAAE,YAAY,CAAC;IACtB,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,WAAW,CAAC,eAAe,CAAC,GACrC,OAAO,CAAC,cAAc,CAAC,CAkBzB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,sBAAsB,EAC9B,QAAQ,EAAE,WAAW,CAAC,eAAe,CAAC,GACrC,YAAY,CAoCd"}
package/dist/config.js ADDED
@@ -0,0 +1,78 @@
1
+ /**
2
+ * qScan-side resolution of `quantakrypto.config.json` (ROADMAP P2-9, docs/CONFIG.md).
3
+ *
4
+ * core's {@link loadConfig} does the reading + type-validation; this module
5
+ * applies the file's values onto parsed CLI options with the documented
6
+ * precedence:
7
+ *
8
+ * CLI flags > quantakrypto.config.json > built-in defaults
9
+ *
10
+ * Resolution is **per-key**: a key set by a flag (tracked in the `explicit` set
11
+ * from `parseArgs`) is left alone; otherwise the config value fills it. The
12
+ * list-valued keys (`include` / `ignore`→`exclude`) *append* — the config
13
+ * provides a base set and any CLI flags add to it (docs/CONFIG.md §4.2).
14
+ */
15
+ import { loadConfig } from "@quantakrypto/core";
16
+ /**
17
+ * Load and merge `quantakrypto.config.json` into the parsed CLI options.
18
+ *
19
+ * @param options Fully-resolved options from {@link parseArgs} (defaults filled).
20
+ * @param explicit The set of configurable keys the user set via a flag.
21
+ * @returns The merged options plus the applied config path + any warnings.
22
+ * @throws {ConfigError} (from core) on a malformed config or a missing
23
+ * explicitly-named `--config` file. The CLI maps this to exit 2.
24
+ */
25
+ export async function resolveConfig(options, explicit) {
26
+ // `--no-config-file` disables discovery entirely; nothing to merge.
27
+ if (options.noConfigFile && options.configFile === undefined) {
28
+ return { options, warnings: [] };
29
+ }
30
+ // `--config <path>` names the file explicitly (a missing file is then fatal);
31
+ // otherwise auto-discover at the scan root.
32
+ const target = options.configFile ?? options.path;
33
+ const loaded = await loadConfig(target, { explicit: options.configFile !== undefined });
34
+ if (loaded.path === undefined) {
35
+ // No file found (auto-discovery, tolerant): options unchanged.
36
+ return { options, warnings: loaded.warnings };
37
+ }
38
+ const merged = applyConfig(options, loaded.config, explicit);
39
+ return { options: merged, configPath: loaded.path, warnings: loaded.warnings };
40
+ }
41
+ /**
42
+ * Apply a parsed config onto options under the precedence rule. Pure; returns a
43
+ * new options object. Scalars: config fills only keys NOT set by a flag. Lists:
44
+ * config provides the base and the CLI flag values are appended.
45
+ */
46
+ export function applyConfig(options, config, explicit) {
47
+ const out = {
48
+ ...options,
49
+ ignore: [...options.ignore],
50
+ include: [...options.include],
51
+ };
52
+ /** Set a scalar key from config only when the user didn't set it via a flag. */
53
+ const fillScalar = (key, value) => {
54
+ if (value === undefined)
55
+ return;
56
+ if (explicit.has(key))
57
+ return; // flag wins.
58
+ out[key] = value;
59
+ };
60
+ fillScalar("severityThreshold", config.severityThreshold);
61
+ fillScalar("source", config.source);
62
+ fillScalar("dependencies", config.dependencies);
63
+ fillScalar("config", config.config);
64
+ fillScalar("noDefaultIgnores", config.noDefaultIgnores);
65
+ fillScalar("scanMinified", config.scanMinified);
66
+ fillScalar("maxFileSize", config.maxFileSize);
67
+ fillScalar("baseline", config.baseline);
68
+ // List-valued keys: config is the base, CLI flags append (config first so the
69
+ // committed policy reads as the baseline, ad-hoc CLI excludes/includes after).
70
+ if (config.exclude && config.exclude.length > 0) {
71
+ out.ignore = [...config.exclude, ...options.ignore];
72
+ }
73
+ if (config.include && config.include.length > 0) {
74
+ out.include = [...config.include, ...options.include];
75
+ }
76
+ return out;
77
+ }
78
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
package/dist/help.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Static help / usage text for the qScan CLI.
3
+ *
4
+ * Kept in its own module so it can be unit-tested and reused without pulling in
5
+ * filesystem or process side effects.
6
+ */
7
+ /** The full `--help` screen. */
8
+ export declare const HELP_TEXT = "qscan \u2014 find quantum-vulnerable cryptography in any codebase\n\nUSAGE\n qscan [path] [options]\n\nARGUMENTS\n path Directory or file to scan (default: \".\")\n\nOPTIONS\n --format <human|json|sarif|cbom>\n Output format (default: human)\n --cbom Alias for --format cbom (CycloneDX CBOM)\n -o, --output <file> Write the report to a file instead of stdout\n --severity-threshold <level> Fail (exit 1) on findings at/above this level;\n one of critical|high|medium|low|info\n (default: high)\n --no-source Skip scanning source files for inline crypto\n --no-deps Skip scanning dependency manifests\n --no-config Skip scanning config files (TLS/certificates)\n --config <path> Use this quantakrypto.config.json instead of\n auto-discovering one at the scan root\n --no-config-file Disable quantakrypto.config.json auto-discovery\n --ignore <pattern> Exclude paths matching <pattern> (repeatable)\n --include <pattern> Restrict the scan to matching paths (repeatable)\n --max-file-size <bytes> Skip files larger than <bytes> (default: 2 MiB)\n --no-default-ignores Don't skip node_modules/.git/dist by default\n --scan-minified Scan minified/generated/bundled files too\n --changed Scan only files changed in the git work tree\n --since <git-ref> With --changed, diff against <git-ref>\n --parallel Scan using a worker-thread pool when worthwhile\n --concurrency <n> Worker count for --parallel (implies --parallel)\n --baseline <file> Suppress findings listed in a baseline file\n --write-baseline <file> Write current findings as a baseline, then exit 0\n --quiet Suppress the human summary banner\n -v, --version Print version and exit\n -h, --help Print this help and exit\n\nEXIT CODES\n 0 No findings at/above the threshold (or a baseline was written)\n 1 One or more findings at/above the severity threshold\n 2 Usage error or I/O failure\n\nEXAMPLES\n qscan . Scan the current directory\n qscan src --format sarif -o qscan.sarif\n qscan . --severity-threshold critical\n qscan . --write-baseline qscan-baseline.json\n qscan . --baseline qscan-baseline.json\n qscan . --include src --include lib\n qscan . --config ./ci/quantakrypto.config.json\n qscan . --changed --since origin/main\n qscan . --parallel --concurrency 4\n qscan . --cbom -o qscan-cbom.json\n";
9
+ /** The `--version` line. */
10
+ export declare function versionLine(): string;
11
+ //# sourceMappingURL=help.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,gCAAgC;AAChC,eAAO,MAAM,SAAS,uuFAqDrB,CAAC;AAEF,4BAA4B;AAC5B,wBAAgB,WAAW,IAAI,MAAM,CAEpC"}
package/dist/help.js ADDED
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Static help / usage text for the qScan CLI.
3
+ *
4
+ * Kept in its own module so it can be unit-tested and reused without pulling in
5
+ * filesystem or process side effects.
6
+ */
7
+ import { VERSION } from "@quantakrypto/core";
8
+ /** The full `--help` screen. */
9
+ export const HELP_TEXT = `qscan — find quantum-vulnerable cryptography in any codebase
10
+
11
+ USAGE
12
+ qscan [path] [options]
13
+
14
+ ARGUMENTS
15
+ path Directory or file to scan (default: ".")
16
+
17
+ OPTIONS
18
+ --format <human|json|sarif|cbom>
19
+ Output format (default: human)
20
+ --cbom Alias for --format cbom (CycloneDX CBOM)
21
+ -o, --output <file> Write the report to a file instead of stdout
22
+ --severity-threshold <level> Fail (exit 1) on findings at/above this level;
23
+ one of critical|high|medium|low|info
24
+ (default: high)
25
+ --no-source Skip scanning source files for inline crypto
26
+ --no-deps Skip scanning dependency manifests
27
+ --no-config Skip scanning config files (TLS/certificates)
28
+ --config <path> Use this quantakrypto.config.json instead of
29
+ auto-discovering one at the scan root
30
+ --no-config-file Disable quantakrypto.config.json auto-discovery
31
+ --ignore <pattern> Exclude paths matching <pattern> (repeatable)
32
+ --include <pattern> Restrict the scan to matching paths (repeatable)
33
+ --max-file-size <bytes> Skip files larger than <bytes> (default: 2 MiB)
34
+ --no-default-ignores Don't skip node_modules/.git/dist by default
35
+ --scan-minified Scan minified/generated/bundled files too
36
+ --changed Scan only files changed in the git work tree
37
+ --since <git-ref> With --changed, diff against <git-ref>
38
+ --parallel Scan using a worker-thread pool when worthwhile
39
+ --concurrency <n> Worker count for --parallel (implies --parallel)
40
+ --baseline <file> Suppress findings listed in a baseline file
41
+ --write-baseline <file> Write current findings as a baseline, then exit 0
42
+ --quiet Suppress the human summary banner
43
+ -v, --version Print version and exit
44
+ -h, --help Print this help and exit
45
+
46
+ EXIT CODES
47
+ 0 No findings at/above the threshold (or a baseline was written)
48
+ 1 One or more findings at/above the severity threshold
49
+ 2 Usage error or I/O failure
50
+
51
+ EXAMPLES
52
+ qscan . Scan the current directory
53
+ qscan src --format sarif -o qscan.sarif
54
+ qscan . --severity-threshold critical
55
+ qscan . --write-baseline qscan-baseline.json
56
+ qscan . --baseline qscan-baseline.json
57
+ qscan . --include src --include lib
58
+ qscan . --config ./ci/quantakrypto.config.json
59
+ qscan . --changed --since origin/main
60
+ qscan . --parallel --concurrency 4
61
+ qscan . --cbom -o qscan-cbom.json
62
+ `;
63
+ /** The `--version` line. */
64
+ export function versionLine() {
65
+ return `qscan ${VERSION}`;
66
+ }
67
+ //# sourceMappingURL=help.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.js","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C,gCAAgC;AAChC,MAAM,CAAC,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDxB,CAAC;AAEF,4BAA4B;AAC5B,MAAM,UAAU,WAAW;IACzB,OAAO,SAAS,OAAO,EAAE,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * @quantakrypto/qscan — programmatic API.
3
+ *
4
+ * `runQscan` is the single entry point shared by the CLI (`src/cli.ts`) and by
5
+ * `@quantakrypto/action`. It runs a scan via `@quantakrypto/core`, applies an optional
6
+ * baseline, decides an exit code from the severity threshold, and (optionally)
7
+ * renders a report. The CLI is a thin shell around it.
8
+ *
9
+ * The module also re-exports the argument-parsing and baseline helpers so
10
+ * downstream tools can reuse them without reaching into internal paths.
11
+ */
12
+ import type { Baseline, Finding, ParallelScanOptions, ScanResult } from "@quantakrypto/core";
13
+ import type { QscanOptions } from "./args.js";
14
+ export type { QscanOptions, ParsedArgs, ParsedRun, QscanFormat } from "./args.js";
15
+ export type { Baseline } from "./baseline.js";
16
+ export { ArgError, asFormat, asInt, asSeverity, defaultOptions, meetsThreshold, parseArgs, severityRank, SEVERITY_ORDER, } from "./args.js";
17
+ export { applyBaseline, baselineFromFindings, BASELINE_VERSION, buildBaseline, fingerprint, fingerprintFinding, loadBaseline, readBaseline, saveBaseline, writeBaseline, } from "./baseline.js";
18
+ export { renderCbom, renderHuman, renderJson, renderSarif } from "./report.js";
19
+ export { HELP_TEXT, versionLine } from "./help.js";
20
+ export { applyConfig, resolveConfig } from "./config.js";
21
+ export type { ResolvedConfig } from "./config.js";
22
+ export type { ConfigurableKey } from "./args.js";
23
+ /** Process-style exit codes qScan uses. */
24
+ export declare const EXIT: {
25
+ /** No findings at/above threshold, or a baseline was written. */
26
+ readonly OK: 0;
27
+ /** One or more findings at/above the severity threshold. */
28
+ readonly FINDINGS: 1;
29
+ /** Usage error or I/O failure. */
30
+ readonly ERROR: 2;
31
+ };
32
+ /** Outcome of {@link runQscan}. */
33
+ export interface QscanRun {
34
+ /** The scan result, with the baseline already applied to `findings`. */
35
+ result: ScanResult;
36
+ /** Findings suppressed because their fingerprint was in the baseline. */
37
+ suppressed: Finding[];
38
+ /** Rendered report in the requested format (`undefined` for a baseline write). */
39
+ report?: string;
40
+ /** The baseline that was written, when `writeBaseline` was requested. */
41
+ baselineWritten?: Baseline;
42
+ /** Suggested process exit code. */
43
+ exitCode: number;
44
+ }
45
+ /**
46
+ * The scan implementation `runQscan` calls. Matches `@quantakrypto/core`'s `scan` /
47
+ * `scanParallel` (parallel options are a superset of `ScanOptions`).
48
+ * Injectable so the GitHub Action and tests can supply a custom scanner.
49
+ */
50
+ export type ScanFn = (options: ParallelScanOptions) => Promise<ScanResult>;
51
+ /**
52
+ * Resolve the changed-file list for incremental scans. Injectable for testing;
53
+ * defaults to core's git-aware {@link changedFiles}.
54
+ */
55
+ export type ChangedFilesFn = (root: string, since?: string) => Promise<string[]>;
56
+ /** Behavioral hooks for {@link runQscan}, mainly for testing. */
57
+ export interface RunQscanHooks {
58
+ /** Emit raw ANSI color in the human report. Default: false. */
59
+ color?: boolean;
60
+ /** Override the scanner. Default: `scan` / `scanParallel` from `@quantakrypto/core`. */
61
+ scanFn?: ScanFn;
62
+ /** Override changed-file resolution. Default: `changedFiles` from `@quantakrypto/core`. */
63
+ changedFilesFn?: ChangedFilesFn;
64
+ }
65
+ /**
66
+ * Run a complete qScan pass: scan → baseline → threshold → render.
67
+ *
68
+ * This never touches `process` or stdout; the CLI is responsible for printing
69
+ * `report`/writing `output` and calling `process.exit(exitCode)`. That keeps
70
+ * the function pure enough to unit-test and to embed in the GitHub Action.
71
+ *
72
+ * Behavior:
73
+ * - The walk is configured by `include` / `ignore` / `maxFileSize` /
74
+ * `noDefaultIgnores` / `scanMinified`.
75
+ * - With `changed` set, only the files git reports as changed (relative to
76
+ * `since`, if given) are scanned via `ScanOptions.files`. A non-git tree
77
+ * yields an empty list, so nothing is scanned.
78
+ * - With `parallel` (or `concurrency`) set, the scan is routed through core's
79
+ * `scanParallel`, which itself falls back to the serial path for small
80
+ * inputs.
81
+ * - When `opts.writeBaseline` is set, the scan runs, a baseline is built from
82
+ * *all* findings, written to disk, and `exitCode` is {@link EXIT.OK}. No
83
+ * report is rendered.
84
+ * - When `opts.baseline` is set, its fingerprints are loaded and matching
85
+ * findings are moved to `suppressed` (and removed from `result.findings`).
86
+ * - `exitCode` is {@link EXIT.FINDINGS} when any *kept* finding meets the
87
+ * severity threshold, else {@link EXIT.OK}.
88
+ *
89
+ * @throws {Error} Propagates scan / baseline I/O errors; the CLI maps these to
90
+ * {@link EXIT.ERROR}.
91
+ */
92
+ export declare function runQscan(opts: Partial<QscanOptions> & {
93
+ path: string;
94
+ }, hooks?: RunQscanHooks): Promise<QscanRun>;
95
+ /** Render a scan result in the requested format. */
96
+ export declare function renderReport(result: ScanResult, format: QscanOptions["format"], color?: boolean): string;
97
+ /** Re-export the core result types consumers commonly need. */
98
+ export type { Finding, ScanResult, ScanOptions } from "@quantakrypto/core";
99
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAI7F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAG9C,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAClF,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,UAAU,EACV,cAAc,EACd,cAAc,EACd,SAAS,EACT,YAAY,EACZ,cAAc,GACf,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,kBAAkB,EAClB,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACzD,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,YAAY,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEjD,2CAA2C;AAC3C,eAAO,MAAM,IAAI;IACf,iEAAiE;;IAEjE,4DAA4D;;IAE5D,kCAAkC;;CAE1B,CAAC;AAEX,mCAAmC;AACnC,MAAM,WAAW,QAAQ;IACvB,wEAAwE;IACxE,MAAM,EAAE,UAAU,CAAC;IACnB,yEAAyE;IACzE,UAAU,EAAE,OAAO,EAAE,CAAC;IACtB,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,eAAe,CAAC,EAAE,QAAQ,CAAC;IAC3B,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;AAE3E;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;AAEjF,iEAAiE;AACjE,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,wFAAwF;IACxF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2FAA2F;IAC3F,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAsBD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAC9C,KAAK,GAAE,aAAkB,GACxB,OAAO,CAAC,QAAQ,CAAC,CA+CnB;AAED,oDAAoD;AACpD,wBAAgB,YAAY,CAC1B,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,EAC9B,KAAK,UAAQ,GACZ,MAAM,CAYR;AAED,+DAA+D;AAC/D,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC"}