pqcheck 0.1.1 → 0.2.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.
Files changed (3) hide show
  1. package/README.md +35 -10
  2. package/bin/pqcheck.js +60 -14
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -55,20 +55,45 @@ $ npx pqcheck chase.com
55
55
  ## Usage
56
56
 
57
57
  ```
58
- npx pqcheck <domain> Scan and print human-readable report
59
- npx pqcheck <domain> --json Output raw JSON for piping / scripting
60
- npx pqcheck --help Show all options
61
- npx pqcheck --version Show version
58
+ npx pqcheck <domain> Scan and print human-readable report
59
+ npx pqcheck <domain> --format json Output raw JSON for piping / scripting
60
+ npx pqcheck <domain> --threshold 7 Exit 2 if score ≥ 7 (CI gate)
61
+ npx pqcheck <domain> --quiet Print only the numeric score
62
+ npx pqcheck --help Show all options
63
+ npx pqcheck --version Show version
62
64
  ```
63
65
 
64
- The `--json` flag is useful for integrating into CI / monitoring tools:
66
+ ### Exit codes
67
+
68
+ | Code | Meaning |
69
+ |------|---------|
70
+ | 0 | Success — score below threshold (or no threshold set) |
71
+ | 1 | Usage / network / scan error |
72
+ | 2 | Score met or exceeded `--threshold` |
73
+
74
+ ### CI integration
75
+
76
+ The `--threshold` flag turns `pqcheck` into a quantum-risk gate for any pipeline:
77
+
78
+ ```yaml
79
+ # .github/workflows/quantum-risk-gate.yml
80
+ - name: Check public-surface quantum-decryption risk
81
+ run: npx pqcheck mycompany.com --threshold 7
82
+ ```
83
+
84
+ If the score is 7.0 or higher, the step fails and the PR can't merge.
85
+
86
+ For finer control, combine `--quiet` with shell logic:
87
+
88
+ ```bash
89
+ SCORE=$(npx pqcheck mybank.com --quiet)
90
+ echo "Public surface blast radius: $SCORE / 10"
91
+ ```
92
+
93
+ Or grab the full JSON for richer analysis:
65
94
 
66
95
  ```bash
67
- # In a GitHub Actions workflow:
68
- SCORE=$(npx pqcheck mybank.com --json | jq '.score')
69
- if (( $(echo "$SCORE > 7" | bc -l) )); then
70
- echo "Score regressed above threshold"; exit 1
71
- fi
96
+ npx pqcheck mybank.com --format json | jq '.findings[] | select(.severity=="high")'
72
97
  ```
73
98
 
74
99
  ## Web version
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.1.1";
10
+ const VERSION = "0.2.0";
11
11
 
12
12
  const ANSI = {
13
13
  reset: "\x1b[0m",
@@ -41,16 +41,22 @@ async function main() {
41
41
  process.exit(1);
42
42
  }
43
43
 
44
- const json = args.includes("--json");
44
+ const quiet = args.includes("--quiet") || args.includes("-q");
45
+ const format = parseFormat(args);
46
+ const threshold = parseThreshold(args);
47
+ if (threshold === "invalid") {
48
+ console.error(color("red", "error: --threshold requires a number 0-10"));
49
+ process.exit(1);
50
+ }
45
51
 
46
- process.stderr.write(color("dim", `Scanning ${domain} ...`));
52
+ if (!quiet) process.stderr.write(color("dim", `Scanning ${domain} ...`));
47
53
  let report;
48
54
  try {
49
55
  const resp = await fetch(`${API_BASE}/api/scan?domain=${encodeURIComponent(domain)}`, {
50
56
  method: "GET",
51
57
  headers: { accept: "application/json", "user-agent": `pqcheck-cli/${VERSION}` },
52
58
  });
53
- process.stderr.write("\r\x1b[K"); // clear "Scanning ..." line
59
+ if (!quiet) process.stderr.write("\r\x1b[K"); // clear "Scanning ..." line
54
60
  if (!resp.ok) {
55
61
  const errBody = await safeJSON(resp);
56
62
  console.error(color("red", `error: ${resp.status} ${errBody?.error || resp.statusText}`));
@@ -59,17 +65,45 @@ async function main() {
59
65
  }
60
66
  report = await resp.json();
61
67
  } catch (err) {
62
- process.stderr.write("\r\x1b[K");
68
+ if (!quiet) process.stderr.write("\r\x1b[K");
63
69
  console.error(color("red", `error: ${err.message}`));
64
70
  process.exit(1);
65
71
  }
66
72
 
67
- if (json) {
73
+ if (quiet) {
74
+ // Numeric score on stdout, nothing else. Suitable for piping.
75
+ console.log(typeof report.score === "number" ? report.score : "");
76
+ } else if (format === "json") {
68
77
  console.log(JSON.stringify(report, null, 2));
69
- process.exit(0);
78
+ } else {
79
+ printReport(report);
70
80
  }
71
81
 
72
- printReport(report);
82
+ // Threshold gating: exit 2 if score >= threshold (distinct from exit 1 = error)
83
+ if (threshold !== null && typeof report.score === "number" && report.score >= threshold) {
84
+ if (!quiet) {
85
+ console.error(color("red", `threshold breach: score ${report.score} >= ${threshold}`));
86
+ }
87
+ process.exit(2);
88
+ }
89
+ process.exit(0);
90
+ }
91
+
92
+ function parseFormat(args) {
93
+ if (args.includes("--json")) return "json"; // back-compat alias
94
+ const i = args.indexOf("--format");
95
+ if (i === -1) return "text";
96
+ const v = (args[i + 1] || "").toLowerCase();
97
+ return v === "json" ? "json" : "text";
98
+ }
99
+
100
+ function parseThreshold(args) {
101
+ const i = args.indexOf("--threshold");
102
+ if (i === -1) return null;
103
+ const raw = args[i + 1];
104
+ const n = Number(raw);
105
+ if (!Number.isFinite(n) || n < 0 || n > 10) return "invalid";
106
+ return n;
73
107
  }
74
108
 
75
109
  function printReport(r) {
@@ -163,17 +197,29 @@ ${color("bold", "pqcheck")} ${color("dim", `v${VERSION}`)}
163
197
  Public Surface Blast Radius — quantum-decryption risk for any domain.
164
198
 
165
199
  ${color("bold", "Usage:")}
166
- npx pqcheck <domain> Scan and print human-readable report
167
- npx pqcheck <domain> --json Output raw JSON
200
+ npx pqcheck <domain> Scan and print human-readable report
201
+ npx pqcheck <domain> --format json Output raw JSON
202
+ npx pqcheck <domain> --threshold 7 Exit 2 if score ≥ 7 (CI-friendly)
203
+ npx pqcheck <domain> --quiet Print just the score, nothing else
168
204
 
169
205
  ${color("bold", "Options:")}
170
- -h, --help Show this help
171
- -v, --version Show version
172
- --json Print raw JSON output
206
+ -h, --help Show this help
207
+ -v, --version Show version
208
+ --format <text|json> Output format (default: text)
209
+ --json Alias for --format json
210
+ --threshold <0-10> Exit code 2 if score meets/exceeds this value
211
+ -q, --quiet Print only the numeric score (pipe-friendly)
212
+
213
+ ${color("bold", "Exit codes:")}
214
+ 0 success
215
+ 1 usage / network / scan error
216
+ 2 score met or exceeded --threshold
173
217
 
174
218
  ${color("bold", "Examples:")}
175
219
  npx pqcheck chase.com
176
- npx pqcheck quantapact.com --json
220
+ npx pqcheck quantapact.com --format json
221
+ npx pqcheck mybank.com --threshold 7 ${color("dim", "# fail CI if exposed")}
222
+ echo "score: $(npx pqcheck mybank.com -q)"
177
223
 
178
224
  Backed by the patented Decryption Blast Radius methodology.
179
225
  ${color("violet", "https://quantapact.com")}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pqcheck",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
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",