pqcheck 0.7.0 → 0.7.2
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.
- package/bin/pqcheck.js +59 -30
- package/package.json +1 -1
package/bin/pqcheck.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// =============================================================================
|
|
8
8
|
|
|
9
9
|
const API_BASE = process.env.PQCHECK_API_BASE || "https://quantapact.com";
|
|
10
|
-
const VERSION = "0.7.
|
|
10
|
+
const VERSION = "0.7.2";
|
|
11
11
|
|
|
12
12
|
const ANSI = {
|
|
13
13
|
reset: "\x1b[0m",
|
|
@@ -498,41 +498,64 @@ ${color("bold", "pqcheck")} ${color("dim", `v${VERSION}`)}
|
|
|
498
498
|
|
|
499
499
|
Public Surface Blast Radius — quantum-decryption risk for any domain.
|
|
500
500
|
|
|
501
|
-
${color("bold", "
|
|
501
|
+
${color("bold", "Commands:")}
|
|
502
502
|
npx pqcheck <domain> Scan + print human-readable report
|
|
503
|
-
npx pqcheck lock <domain> Generate quantapact.lock (QXM)
|
|
504
|
-
npx pqcheck deps <domain> Scan third-party origins (supply-chain HNDL)
|
|
505
|
-
npx pqcheck
|
|
506
|
-
npx pqcheck <domain>
|
|
507
|
-
npx pqcheck <
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
npx pqcheck
|
|
511
|
-
npx pqcheck
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
503
|
+
npx pqcheck lock <domain> Generate quantapact.lock (QXM) committable manifest
|
|
504
|
+
npx pqcheck deps <domain> Scan all third-party origins on the page (supply-chain HNDL)
|
|
505
|
+
npx pqcheck diff <old.lock> <new.lock> Compare two QXM lockfiles; exit 2 on regression
|
|
506
|
+
npx pqcheck history <domain> Show 90-day score history (sparkline + samples)
|
|
507
|
+
npx pqcheck cert <file.pem> Analyze a local PEM/CRT cert file (offline, no network)
|
|
508
|
+
|
|
509
|
+
${color("bold", "Multi-domain:")}
|
|
510
|
+
npx pqcheck a.com b.com c.com Multi-domain scan (positional)
|
|
511
|
+
npx pqcheck --file domains.txt Bulk scan from a newline-separated file (# comments allowed)
|
|
512
|
+
|
|
513
|
+
${color("bold", "Output formats:")}
|
|
514
|
+
--format text Human-readable (default)
|
|
515
|
+
--format json (or --json) Raw JSON / NDJSON for multi
|
|
516
|
+
--format markdown GitHub-issue / Slack-ready Markdown
|
|
517
|
+
--format csv Spreadsheet-friendly CSV row
|
|
518
|
+
--format sarif SARIF 2.1.0 for GitHub Code Scanning upload
|
|
519
|
+
--gh-action GitHub Actions ::notice/::warning/::error annotations
|
|
520
|
+
|
|
521
|
+
${color("bold", "Common flags:")}
|
|
515
522
|
-h, --help Show this help
|
|
516
523
|
-v, --version Show version
|
|
517
|
-
--
|
|
518
|
-
--json Alias for --format json
|
|
519
|
-
--threshold <0-10> Exit 2 if score meets or exceeds this
|
|
524
|
+
--threshold <0-10> Exit 2 if score meets or exceeds this (CI gate)
|
|
520
525
|
-q, --quiet Print only the numeric score
|
|
521
526
|
--watch [seconds] Poll every N seconds (default 300) and report changes
|
|
522
527
|
--webhook <url> POST scan results to a URL (one-shot or each watch tick)
|
|
523
528
|
|
|
529
|
+
${color("bold", "Subcommand-specific:")}
|
|
530
|
+
pqcheck deps:
|
|
531
|
+
--lock Also write quantapact-deps.lock + .md
|
|
532
|
+
-o <dir> Output directory for --lock files
|
|
533
|
+
--max=<N> Max third parties to scan (default 20)
|
|
534
|
+
--allowlist <file> Exit 3 if any third-party not in allowlist (CI gate)
|
|
535
|
+
pqcheck lock:
|
|
536
|
+
-o <dir> Output directory
|
|
537
|
+
--stdout Print JSON to stdout instead of writing files
|
|
538
|
+
pqcheck history:
|
|
539
|
+
--days <N> History window (default 90)
|
|
540
|
+
--json Raw JSON
|
|
541
|
+
|
|
524
542
|
${color("bold", "Exit codes:")}
|
|
525
543
|
0 success
|
|
526
544
|
1 usage / network / scan error
|
|
527
|
-
2 score met or exceeded --threshold
|
|
545
|
+
2 score met or exceeded --threshold (or diff regression)
|
|
546
|
+
3 allowlist violation (deps --allowlist)
|
|
528
547
|
|
|
529
548
|
${color("bold", "Examples:")}
|
|
530
549
|
npx pqcheck chase.com
|
|
531
|
-
npx pqcheck mycompany.com mythirdparty.com --format csv > posture.csv
|
|
532
550
|
npx pqcheck mybank.com --threshold 7 ${color("dim", "# fail CI if score ≥ 7")}
|
|
533
|
-
npx pqcheck
|
|
534
|
-
npx pqcheck
|
|
535
|
-
|
|
551
|
+
npx pqcheck deps stripe.com --lock
|
|
552
|
+
npx pqcheck deps acme.com --allowlist allowed-vendors.txt ${color("dim", "# CI vendor-risk gate")}
|
|
553
|
+
npx pqcheck diff main.lock pr.lock ${color("dim", "# regression detection in PR")}
|
|
554
|
+
npx pqcheck history quantapact.com
|
|
555
|
+
npx pqcheck cert ./mycert.pem ${color("dim", "# offline cert analysis")}
|
|
556
|
+
npx pqcheck --file domains.txt --format json > scans.ndjson
|
|
557
|
+
npx pqcheck mybank.com --format sarif > pqcheck.sarif ${color("dim", "# upload to Code Scanning")}
|
|
558
|
+
npx pqcheck mybank.com --gh-action ${color("dim", "# inline PR annotations")}
|
|
536
559
|
|
|
537
560
|
Backed by the patented Decryption Blast Radius methodology.
|
|
538
561
|
${color("violet", "https://quantapact.com")}
|
|
@@ -1238,20 +1261,26 @@ async function runHistoryCommand(args) {
|
|
|
1238
1261
|
console.log(` ${color("bold", domain)} ${color("dim", "·")} score history (${days}d, ${sorted.length} samples)`);
|
|
1239
1262
|
console.log(` ${color("dim", `range ${min.toFixed(1)} – ${max.toFixed(1)} · trend ${trend}`)}`);
|
|
1240
1263
|
console.log("");
|
|
1241
|
-
// Compact ASCII sparkline
|
|
1242
|
-
const
|
|
1243
|
-
const ramp = "▁▂▃▄▅▆▇█";
|
|
1264
|
+
// Compact ASCII sparkline (flat → centered dots; varying → ramp blocks)
|
|
1265
|
+
const isFlat = Math.abs(max - min) < 0.05;
|
|
1244
1266
|
let bar = "";
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1267
|
+
if (isFlat) {
|
|
1268
|
+
bar = "·".repeat(sorted.length);
|
|
1269
|
+
} else {
|
|
1270
|
+
const range = max - min;
|
|
1271
|
+
const ramp = "▁▂▃▄▅▆▇█";
|
|
1272
|
+
for (const p of sorted) {
|
|
1273
|
+
const idx = Math.min(ramp.length - 1, Math.floor(((p.score - min) / range) * (ramp.length - 1)));
|
|
1274
|
+
bar += ramp[idx];
|
|
1275
|
+
}
|
|
1248
1276
|
}
|
|
1249
1277
|
console.log(` ${color("violet", bar)}`);
|
|
1250
1278
|
console.log("");
|
|
1251
|
-
// Tail of recent samples
|
|
1279
|
+
// Tail of recent samples — accept either recordedAt or scannedAt or date
|
|
1252
1280
|
console.log(` ${color("dim", "Recent samples (most-recent first):")}`);
|
|
1253
1281
|
for (const p of points.slice(0, 8)) {
|
|
1254
|
-
const
|
|
1282
|
+
const dateRaw = p.recordedAt || p.scannedAt || p.date || "";
|
|
1283
|
+
const date = String(dateRaw).slice(0, 10) || "—".padEnd(10, " ");
|
|
1255
1284
|
console.log(` ${color("dim", date)} score ${color("bold", p.score?.toFixed(1) ?? "?")} grade ${p.grade ?? "?"}`);
|
|
1256
1285
|
}
|
|
1257
1286
|
console.log("");
|