pqcheck 0.16.14 → 0.16.15
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 +38 -20
- package/package.json +1 -1
package/bin/pqcheck.js
CHANGED
|
@@ -24,7 +24,25 @@
|
|
|
24
24
|
})();
|
|
25
25
|
|
|
26
26
|
const API_BASE = process.env.PQCHECK_API_BASE || "https://cipherwake.io";
|
|
27
|
-
const VERSION = "0.16.
|
|
27
|
+
const VERSION = "0.16.15";
|
|
28
|
+
|
|
29
|
+
// v0.16.15 — attribution suffix. When the CLI runs inside GitHub Actions
|
|
30
|
+
// (GH sets GITHUB_ACTIONS=true automatically in every step) we append
|
|
31
|
+
// "(pqcheck-action)" to the User-Agent so the server-side classifier
|
|
32
|
+
// (lib/events.ts) buckets the call as `action` rather than `cli`. Lets
|
|
33
|
+
// the analytics dashboard split humans/CI invocations cleanly.
|
|
34
|
+
//
|
|
35
|
+
// No new data is collected — the User-Agent string was already being
|
|
36
|
+
// sent on every call; this is a labeling change.
|
|
37
|
+
//
|
|
38
|
+
// Opt out via PQCHECK_DISABLE_ACTION_ATTRIBUTION=1 (UA stays plain
|
|
39
|
+
// `pqcheck-cli/X.Y.Z` even under GitHub Actions). The env var is only
|
|
40
|
+
// honored when GITHUB_ACTIONS=true — it does nothing in other contexts.
|
|
41
|
+
const CI_ACTION_SUFFIX =
|
|
42
|
+
process.env.GITHUB_ACTIONS === "true" &&
|
|
43
|
+
process.env.PQCHECK_DISABLE_ACTION_ATTRIBUTION !== "1"
|
|
44
|
+
? " (pqcheck-action)"
|
|
45
|
+
: "";
|
|
28
46
|
|
|
29
47
|
// API-key support — paid tier (Founder Pro $19.99/mo launch pricing, locked while sub active) gets
|
|
30
48
|
// per-account monthly quotas instead of the per-IP rate limit. Set via:
|
|
@@ -38,7 +56,7 @@ const QP_API_KEY = (process.env.CIPHERWAKE_API_KEY || "").trim();
|
|
|
38
56
|
// Builds headers with optional Authorization. Use for every CLI → API call
|
|
39
57
|
// so a single env-var toggle authenticates every endpoint at once.
|
|
40
58
|
function apiHeaders(extra = {}) {
|
|
41
|
-
const h = { accept: "application/json", "user-agent": `pqcheck-cli/${VERSION}`, ...extra };
|
|
59
|
+
const h = { accept: "application/json", "user-agent": `pqcheck-cli/${VERSION}${CI_ACTION_SUFFIX}`, ...extra };
|
|
42
60
|
if (QP_API_KEY) h.authorization = `Bearer ${QP_API_KEY}`;
|
|
43
61
|
return h;
|
|
44
62
|
}
|
|
@@ -274,7 +292,7 @@ async function runOneScan({ domain, format, quiet, threshold, webhookUrl, multi,
|
|
|
274
292
|
const qs = fresh ? `?domain=${encodeURIComponent(domain)}&force=1` : `?domain=${encodeURIComponent(domain)}`;
|
|
275
293
|
const resp = await fetch(`${API_BASE}/api/scan${qs}`, {
|
|
276
294
|
method: "GET",
|
|
277
|
-
headers: apiHeaders({ "user-agent": `pqcheck-cli/${VERSION} (scan)` }),
|
|
295
|
+
headers: apiHeaders({ "user-agent": `pqcheck-cli/${VERSION}${CI_ACTION_SUFFIX} (scan)` }),
|
|
278
296
|
});
|
|
279
297
|
if (!quiet && format === "text") process.stderr.write("\r\x1b[K");
|
|
280
298
|
if (!resp.ok) {
|
|
@@ -321,7 +339,7 @@ async function runOneScan({ domain, format, quiet, threshold, webhookUrl, multi,
|
|
|
321
339
|
if (webhookUrl) {
|
|
322
340
|
fetch(webhookUrl, {
|
|
323
341
|
method: "POST",
|
|
324
|
-
headers: { "content-type": "application/json", "user-agent": `pqcheck-cli/${VERSION}` },
|
|
342
|
+
headers: { "content-type": "application/json", "user-agent": `pqcheck-cli/${VERSION}${CI_ACTION_SUFFIX}` },
|
|
325
343
|
body: JSON.stringify({ domain, report, source: "pqcheck-cli", at: new Date().toISOString() }),
|
|
326
344
|
}).catch(() => { /* best-effort — never fail the scan on webhook delivery */ });
|
|
327
345
|
}
|
|
@@ -543,7 +561,7 @@ async function runWatch({ domains, format, quiet, threshold, webhookUrl, interva
|
|
|
543
561
|
try {
|
|
544
562
|
const resp = await fetch(`${API_BASE}/api/scan?domain=${encodeURIComponent(domain)}`, {
|
|
545
563
|
method: "GET",
|
|
546
|
-
headers: apiHeaders({ "user-agent": `pqcheck-cli/${VERSION} (watch)` }),
|
|
564
|
+
headers: apiHeaders({ "user-agent": `pqcheck-cli/${VERSION}${CI_ACTION_SUFFIX} (watch)` }),
|
|
547
565
|
});
|
|
548
566
|
if (!resp.ok) continue;
|
|
549
567
|
const report = await resp.json();
|
|
@@ -554,7 +572,7 @@ async function runWatch({ domains, format, quiet, threshold, webhookUrl, interva
|
|
|
554
572
|
if (changed && webhookUrl) {
|
|
555
573
|
fetch(webhookUrl, {
|
|
556
574
|
method: "POST",
|
|
557
|
-
headers: { "content-type": "application/json", "user-agent": `pqcheck-cli/${VERSION}` },
|
|
575
|
+
headers: { "content-type": "application/json", "user-agent": `pqcheck-cli/${VERSION}${CI_ACTION_SUFFIX}` },
|
|
558
576
|
body: JSON.stringify({
|
|
559
577
|
type: "score_changed",
|
|
560
578
|
domain,
|
|
@@ -899,7 +917,7 @@ async function refreshVersionCacheInBackground(cachePath) {
|
|
|
899
917
|
const controller = new AbortController();
|
|
900
918
|
const timeout = setTimeout(() => controller.abort(), 2500);
|
|
901
919
|
const resp = await fetch(VERSION_REGISTRY_URL, {
|
|
902
|
-
headers: { "Accept": "application/json", "User-Agent": `pqcheck-cli/${VERSION}` },
|
|
920
|
+
headers: { "Accept": "application/json", "User-Agent": `pqcheck-cli/${VERSION}${CI_ACTION_SUFFIX}` },
|
|
903
921
|
signal: controller.signal,
|
|
904
922
|
});
|
|
905
923
|
clearTimeout(timeout);
|
|
@@ -1829,7 +1847,7 @@ async function runLockCommand(args) {
|
|
|
1829
1847
|
try {
|
|
1830
1848
|
const resp = await fetch(`${API_BASE}/api/scan?domain=${encodeURIComponent(domain)}`, {
|
|
1831
1849
|
method: "GET",
|
|
1832
|
-
headers: apiHeaders({ "user-agent": `pqcheck-cli/${VERSION} (lock)` }),
|
|
1850
|
+
headers: apiHeaders({ "user-agent": `pqcheck-cli/${VERSION}${CI_ACTION_SUFFIX} (lock)` }),
|
|
1833
1851
|
});
|
|
1834
1852
|
if (!stdout) process.stderr.write("\r\x1b[K");
|
|
1835
1853
|
if (!resp.ok) {
|
|
@@ -1909,7 +1927,7 @@ function buildQxmManifest(report, crypto) {
|
|
|
1909
1927
|
return {
|
|
1910
1928
|
schema: "https://cipherwake.io/schemas/qxm/v1",
|
|
1911
1929
|
schemaVersion: 1,
|
|
1912
|
-
generator: `pqcheck-cli/${VERSION}`,
|
|
1930
|
+
generator: `pqcheck-cli/${VERSION}${CI_ACTION_SUFFIX}`,
|
|
1913
1931
|
generatedAt: report.generatedAt || new Date().toISOString(),
|
|
1914
1932
|
domain: report.domain,
|
|
1915
1933
|
reachable: !!report.reachable,
|
|
@@ -2152,7 +2170,7 @@ async function runDepsCommand(args) {
|
|
|
2152
2170
|
batch.map(async (h) => {
|
|
2153
2171
|
try {
|
|
2154
2172
|
const r = await fetch(`${API_BASE}/api/scan?domain=${encodeURIComponent(h.host)}&source=cli-deps`, {
|
|
2155
|
-
headers: apiHeaders({ "user-agent": `pqcheck-cli/${VERSION} (deps)` }),
|
|
2173
|
+
headers: apiHeaders({ "user-agent": `pqcheck-cli/${VERSION}${CI_ACTION_SUFFIX} (deps)` }),
|
|
2156
2174
|
});
|
|
2157
2175
|
if (!r.ok) return { ...h, types: Array.from(h.types), scan: null, error: `${r.status}` };
|
|
2158
2176
|
const body = await r.json();
|
|
@@ -2391,7 +2409,7 @@ async function fetchPageHTML(domain) {
|
|
|
2391
2409
|
method: "GET",
|
|
2392
2410
|
redirect: "follow",
|
|
2393
2411
|
signal: ctrl.signal,
|
|
2394
|
-
headers: { "User-Agent": `pqcheck-cli/${VERSION} (deps; +https://cipherwake.io)` },
|
|
2412
|
+
headers: { "User-Agent": `pqcheck-cli/${VERSION}${CI_ACTION_SUFFIX} (deps; +https://cipherwake.io)` },
|
|
2395
2413
|
});
|
|
2396
2414
|
clearTimeout(t);
|
|
2397
2415
|
if (!resp.ok) return null;
|
|
@@ -2848,7 +2866,7 @@ async function runHistoryCommand(args) {
|
|
|
2848
2866
|
let h;
|
|
2849
2867
|
try {
|
|
2850
2868
|
const r = await fetch(`${API_BASE}/api/history?domain=${encodeURIComponent(domain)}&days=${days}`, {
|
|
2851
|
-
headers: apiHeaders({ "user-agent": `pqcheck-cli/${VERSION} (history)` }),
|
|
2869
|
+
headers: apiHeaders({ "user-agent": `pqcheck-cli/${VERSION}${CI_ACTION_SUFFIX} (history)` }),
|
|
2852
2870
|
});
|
|
2853
2871
|
if (!r.ok) {
|
|
2854
2872
|
console.error(color("red", `error: ${r.status} ${r.statusText}`));
|
|
@@ -2931,7 +2949,7 @@ async function runChangesCommand(args) {
|
|
|
2931
2949
|
let summary;
|
|
2932
2950
|
try {
|
|
2933
2951
|
const r = await fetch(`${API_BASE}/api/changes-summary?domain=${encodeURIComponent(domain)}`, {
|
|
2934
|
-
headers: apiHeaders({ "user-agent": `pqcheck-cli/${VERSION} (changes)` }),
|
|
2952
|
+
headers: apiHeaders({ "user-agent": `pqcheck-cli/${VERSION}${CI_ACTION_SUFFIX} (changes)` }),
|
|
2935
2953
|
});
|
|
2936
2954
|
if (!r.ok) {
|
|
2937
2955
|
console.error(color("red", `error: ${r.status} ${r.statusText}`));
|
|
@@ -3025,7 +3043,7 @@ async function runChangesCommand(args) {
|
|
|
3025
3043
|
async function runScanBasedDeployCheck(domain, args) {
|
|
3026
3044
|
const headers = {
|
|
3027
3045
|
"Content-Type": "application/json",
|
|
3028
|
-
"User-Agent": `pqcheck-cli/${VERSION}`,
|
|
3046
|
+
"User-Agent": `pqcheck-cli/${VERSION}${CI_ACTION_SUFFIX}`,
|
|
3029
3047
|
};
|
|
3030
3048
|
if (QP_API_KEY) headers["Authorization"] = `Bearer ${QP_API_KEY}`;
|
|
3031
3049
|
|
|
@@ -3198,7 +3216,7 @@ async function runTrustDiffCommand(args) {
|
|
|
3198
3216
|
// anonymous per-IP rate limit path (just like /api/scan).
|
|
3199
3217
|
const headers = {
|
|
3200
3218
|
"Content-Type": "application/json",
|
|
3201
|
-
"User-Agent": `pqcheck-cli/${VERSION}`,
|
|
3219
|
+
"User-Agent": `pqcheck-cli/${VERSION}${CI_ACTION_SUFFIX}`,
|
|
3202
3220
|
};
|
|
3203
3221
|
if (QP_API_KEY) {
|
|
3204
3222
|
headers["Authorization"] = `Bearer ${QP_API_KEY}`;
|
|
@@ -3696,7 +3714,7 @@ async function runPreviewDiffCommand(args) {
|
|
|
3696
3714
|
|
|
3697
3715
|
const headers = {
|
|
3698
3716
|
"Content-Type": "application/json",
|
|
3699
|
-
"User-Agent": `pqcheck-cli/${VERSION}`,
|
|
3717
|
+
"User-Agent": `pqcheck-cli/${VERSION}${CI_ACTION_SUFFIX}`,
|
|
3700
3718
|
};
|
|
3701
3719
|
if (QP_API_KEY) {
|
|
3702
3720
|
headers["Authorization"] = `Bearer ${QP_API_KEY}`;
|
|
@@ -4766,7 +4784,7 @@ async function fetchVendorOrigins(domain) {
|
|
|
4766
4784
|
try {
|
|
4767
4785
|
resp = await fetch(`${API_BASE}/api/deps?domain=${encodeURIComponent(domain)}`, {
|
|
4768
4786
|
method: "GET",
|
|
4769
|
-
headers: apiHeaders({ "user-agent": `pqcheck-cli/${VERSION} (vendors)` }),
|
|
4787
|
+
headers: apiHeaders({ "user-agent": `pqcheck-cli/${VERSION}${CI_ACTION_SUFFIX} (vendors)` }),
|
|
4770
4788
|
signal: ac.signal,
|
|
4771
4789
|
});
|
|
4772
4790
|
} catch (err) {
|
|
@@ -4814,7 +4832,7 @@ function normalizeObservedOrigin(value) {
|
|
|
4814
4832
|
function buildVendorLockfile(domain, origins) {
|
|
4815
4833
|
return {
|
|
4816
4834
|
schema_version: 1,
|
|
4817
|
-
generator: `pqcheck-cli/${VERSION}`,
|
|
4835
|
+
generator: `pqcheck-cli/${VERSION}${CI_ACTION_SUFFIX}`,
|
|
4818
4836
|
domain,
|
|
4819
4837
|
generated_at: new Date().toISOString(),
|
|
4820
4838
|
approved_script_origins: origins,
|
|
@@ -4930,7 +4948,7 @@ async function runVendorsSync(domain, outPath) {
|
|
|
4930
4948
|
resp = await fetch(`${API_BASE}/api/vendor-allowlist?domain=${encodeURIComponent(domain)}`, {
|
|
4931
4949
|
method: "GET",
|
|
4932
4950
|
headers: {
|
|
4933
|
-
"user-agent": `pqcheck-cli/${VERSION} (vendors-sync)`,
|
|
4951
|
+
"user-agent": `pqcheck-cli/${VERSION}${CI_ACTION_SUFFIX} (vendors-sync)`,
|
|
4934
4952
|
"authorization": "Bearer " + QP_API_KEY,
|
|
4935
4953
|
},
|
|
4936
4954
|
});
|
|
@@ -5084,7 +5102,7 @@ async function runOnboardCommand(args) {
|
|
|
5084
5102
|
try {
|
|
5085
5103
|
const resp = await fetch(`${API_BASE}/api/scan?domain=${encodeURIComponent(domain)}&source=onboard`, {
|
|
5086
5104
|
method: "GET",
|
|
5087
|
-
headers: apiHeaders({ "user-agent": `pqcheck-cli/${VERSION} (onboard)` }),
|
|
5105
|
+
headers: apiHeaders({ "user-agent": `pqcheck-cli/${VERSION}${CI_ACTION_SUFFIX} (onboard)` }),
|
|
5088
5106
|
});
|
|
5089
5107
|
if (resp.ok) {
|
|
5090
5108
|
const report = await resp.json();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pqcheck",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.15",
|
|
4
4
|
"description": "Deploy gate for AI-coded web apps. `pqcheck deploy-check --ai` returns ship_decision=pass|review|block for Claude Code / Cursor / Copilot / Aider to gate deploys before they ship. Anonymous, no signup, free for first use.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-coder",
|