pqcheck 0.7.6 → 0.7.7

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/README.md CHANGED
@@ -185,7 +185,7 @@ curl -s "https://www.quantapact.com/api/scan?domain=stripe.com" | jq '.grade, .s
185
185
 
186
186
  Full API reference at [quantapact.com/api](https://quantapact.com/api).
187
187
 
188
- **Rate limit:** ~60 requests/minute per IP. No API key required. Returns HTTP 429 if exceeded — back off and retry.
188
+ **Rate limits:** 300 scans per hour per IP, 20 `--fresh` (force-refresh) scans per hour per IP. No API key required. Returns HTTP 429 if exceeded — back off and retry, or [let us know via the feedback form](https://quantapact.com/feedback) if you need higher limits (we're prioritizing the API tier based on real demand).
189
189
 
190
190
  ## Methodology
191
191
 
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.6";
10
+ const VERSION = "0.7.7";
11
11
 
12
12
  const ANSI = {
13
13
  reset: "\x1b[0m",
@@ -107,20 +107,31 @@ async function main() {
107
107
  return; // runWatch handles its own exit; in practice it runs until killed.
108
108
  }
109
109
 
110
+ // --fresh: bypass server cache, force a fresh scan. Useful when verifying
111
+ // a cert/key change you just deployed. Subject to a 20/hr per-IP cap on
112
+ // the server side.
113
+ const fresh = args.includes("--fresh") || args.includes("--force");
114
+
110
115
  // One-shot scan(s)
111
116
  let worstExit = 0;
112
117
  for (const domain of domains) {
113
- const exit = await runOneScan({ domain, format, quiet, threshold, webhookUrl, multi: domains.length > 1 });
118
+ const exit = await runOneScan({ domain, format, quiet, threshold, webhookUrl, multi: domains.length > 1, fresh });
114
119
  if (exit > worstExit) worstExit = exit;
115
120
  }
116
121
  process.exit(worstExit);
117
122
  }
118
123
 
119
- async function runOneScan({ domain, format, quiet, threshold, webhookUrl, multi }) {
120
- if (!quiet && format === "text") process.stderr.write(color("dim", `Scanning ${domain} ...`));
124
+ async function runOneScan({ domain, format, quiet, threshold, webhookUrl, multi, fresh }) {
125
+ if (!quiet && format === "text") process.stderr.write(color("dim", `Scanning ${domain}${fresh ? " (forcing fresh)" : ""} ...`));
121
126
  let report;
122
127
  try {
123
- const resp = await fetch(`${API_BASE}/api/scan?domain=${encodeURIComponent(domain)}`, {
128
+ // --fresh appends ?force=1 to bypass the smart-cache. Use when verifying
129
+ // a cert/key change you just deployed — otherwise scans hit the 1h SWR
130
+ // cache and return up-to-1h-old data. Subject to a 20/hr per-IP cap on
131
+ // the server side; if exceeded, the server silently downgrades to a
132
+ // cached scan and returns that instead of erroring.
133
+ const qs = fresh ? `?domain=${encodeURIComponent(domain)}&force=1` : `?domain=${encodeURIComponent(domain)}`;
134
+ const resp = await fetch(`${API_BASE}/api/scan${qs}`, {
124
135
  method: "GET",
125
136
  headers: { accept: "application/json", "user-agent": `pqcheck-cli/${VERSION} (scan)` },
126
137
  });
@@ -129,6 +140,12 @@ async function runOneScan({ domain, format, quiet, threshold, webhookUrl, multi
129
140
  const errBody = await safeJSON(resp);
130
141
  console.error(color("red", `error scanning ${domain}: ${resp.status} ${errBody?.error || resp.statusText}`));
131
142
  if (errBody?.detail) console.error(color("dim", errBody.detail));
143
+ // Surface the 429 upsell hint if present — tells users how to ask for
144
+ // higher limits via the feedback form. Same demand signal we capture
145
+ // on the homepage.
146
+ if (resp.status === 429 && errBody?.need_more?.feedback_url) {
147
+ console.error(color("dim", `${errBody.need_more.message} → ${errBody.need_more.feedback_url}`));
148
+ }
132
149
  return 1;
133
150
  }
134
151
  report = await resp.json();
@@ -547,6 +564,7 @@ ${color("bold", "Common flags:")}
547
564
  -q, --quiet Print only the numeric score
548
565
  --watch [seconds] Poll every N seconds (default 300) and report changes
549
566
  --webhook <url> POST scan results to a URL (one-shot or each watch tick)
567
+ --fresh Bypass server cache, force a fresh scan (subject to 20/hr per-IP cap)
550
568
 
551
569
  ${color("bold", "Subcommand-specific:")}
552
570
  pqcheck deps:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pqcheck",
3
- "version": "0.7.6",
3
+ "version": "0.7.7",
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",