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.
Files changed (2) hide show
  1. package/bin/pqcheck.js +59 -30
  2. 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.0";
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", "Usage:")}
501
+ ${color("bold", "Commands:")}
502
502
  npx pqcheck <domain> Scan + print human-readable report
503
- npx pqcheck lock <domain> Generate quantapact.lock (QXM) for repo commit
504
- npx pqcheck deps <domain> Scan third-party origins (supply-chain HNDL); --lock for committable manifest
505
- npx pqcheck a.com b.com c.com Multi-domain scan
506
- npx pqcheck <domain> --format json Raw JSON
507
- npx pqcheck <domain> --format markdown GitHub-issue / Slack-ready Markdown
508
- npx pqcheck <domain> --format csv Spreadsheet-friendly CSV row
509
- npx pqcheck <domain> --threshold 7 Exit 2 if score ≥ 7 (CI gate)
510
- npx pqcheck <domain> --quiet Print just the score number
511
- npx pqcheck <domain> --watch [seconds] Continuously poll and report changes
512
- npx pqcheck <domain> --webhook <url> POST report JSON to URL on each scan
513
-
514
- ${color("bold", "Options:")}
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
- --format <text|json|markdown|csv> Output format (default: text)
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 mybank.com --format markdown >> issue.md
534
- npx pqcheck mybank.com --watch 600 --webhook https://hooks.slack.com/services/...
535
- echo "score: $(npx pqcheck mybank.com -q)"
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 range = Math.max(0.1, max - min);
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
- for (const p of sorted) {
1246
- const idx = Math.min(ramp.length - 1, Math.floor(((p.score - min) / range) * (ramp.length - 1)));
1247
- bar += ramp[idx];
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 date = (p.scannedAt || p.date || "").slice(0, 10);
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("");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pqcheck",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
4
4
  "description": "Decryption Blast Radius scanner — find out how much of your data unlocks when quantum decryption arrives.",
5
5
  "keywords": [
6
6
  "post-quantum",