x402-surface-check 0.2.21 → 0.2.22
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 +4 -1
- package/bin/x402-surface-check.mjs +15 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ npx --yes x402-surface-check https://api.example.com/.well-known/x402
|
|
|
11
11
|
npx --yes x402-surface-check https://api.example.com/openapi.json report.md
|
|
12
12
|
npx --yes x402-surface-check --endpoint --method POST https://x402.rpc.ankr.com/eth
|
|
13
13
|
npx --yes x402-surface-check --endpoint --method POST --body '{"prompt":"price CPI"}' https://api.example.com/paid-post
|
|
14
|
+
npx --yes x402-surface-check --strict-cache https://api.example.com/openapi.json
|
|
14
15
|
```
|
|
15
16
|
|
|
16
17
|
## What It Checks
|
|
@@ -30,7 +31,7 @@ npx --yes x402-surface-check --endpoint --method POST --body '{"prompt":"price C
|
|
|
30
31
|
- Testnet or staging rails such as Base Sepolia and Solana devnet
|
|
31
32
|
- HTTPS resource URLs and stable resource metadata
|
|
32
33
|
- Browser CORS allowance for the requesting origin and `X-PAYMENT`, including the actual 402 challenge response
|
|
33
|
-
- Cache-Control posture on no-payment challenge responses, with warnings for explicitly cacheable payment gates
|
|
34
|
+
- Cache-Control posture on no-payment challenge responses, with warnings for explicitly cacheable payment gates and optional strict-cache findings for missing policy headers
|
|
34
35
|
- Grouped finding summaries for repeated route-wide issues, so large manifests keep the patch order readable
|
|
35
36
|
- Contextual reference guides for CORS, cache policy, Worker gates, resource echo, validation/auth ordering, and launch controls
|
|
36
37
|
- Over-broad public method surfaces
|
|
@@ -66,6 +67,7 @@ x402-surface-check --endpoint --method POST <paid-endpoint-url> [output.md]
|
|
|
66
67
|
--body-file <p> Read JSON request body for direct endpoint mode from a file
|
|
67
68
|
--origin <url> Origin to use for browser-style CORS preflight
|
|
68
69
|
--limit <n> Maximum endpoints to probe, default 6
|
|
70
|
+
--strict-cache Flag missing Cache-Control on no-payment 402 responses
|
|
69
71
|
--json Print JSON instead of Markdown
|
|
70
72
|
--help Show usage
|
|
71
73
|
--version Show package version
|
|
@@ -76,6 +78,7 @@ Environment variables are also supported:
|
|
|
76
78
|
```bash
|
|
77
79
|
X402_CHECK_ORIGIN=https://example.com x402-surface-check https://api.example.com/openapi.json
|
|
78
80
|
X402_CHECK_LIMIT=12 x402-surface-check https://api.example.com/.well-known/x402
|
|
81
|
+
X402_STRICT_CACHE=1 x402-surface-check https://api.example.com/.well-known/x402
|
|
79
82
|
```
|
|
80
83
|
|
|
81
84
|
## Scope
|
|
@@ -22,6 +22,7 @@ Options:
|
|
|
22
22
|
--body-file <p> Read JSON request body for direct endpoint mode from a file
|
|
23
23
|
--origin <url> Origin to use for browser-style CORS preflight
|
|
24
24
|
--limit <n> Maximum endpoints to probe, default ${defaultLimit}
|
|
25
|
+
--strict-cache Flag missing Cache-Control on no-payment 402 responses
|
|
25
26
|
--json Print JSON instead of Markdown
|
|
26
27
|
--help Show this help
|
|
27
28
|
--version Show package version
|
|
@@ -38,6 +39,7 @@ function parseArgs(argv) {
|
|
|
38
39
|
body: process.env.X402_CHECK_BODY,
|
|
39
40
|
bodyFile: process.env.X402_CHECK_BODY_FILE,
|
|
40
41
|
outputPath: '',
|
|
42
|
+
strictCache: process.env.X402_STRICT_CACHE === '1',
|
|
41
43
|
url: '',
|
|
42
44
|
}
|
|
43
45
|
|
|
@@ -55,6 +57,9 @@ function parseArgs(argv) {
|
|
|
55
57
|
else if (arg === '--endpoint') {
|
|
56
58
|
args.endpoint = true
|
|
57
59
|
}
|
|
60
|
+
else if (arg === '--strict-cache') {
|
|
61
|
+
args.strictCache = true
|
|
62
|
+
}
|
|
58
63
|
else if (arg === '--method') {
|
|
59
64
|
args.method = String(argv[index + 1] ?? '').toUpperCase()
|
|
60
65
|
index += 1
|
|
@@ -721,7 +726,7 @@ function looksLikeOperationalHealthEndpoint(result) {
|
|
|
721
726
|
return /(^|[/_\s-])(health|healthz|ready|readiness|live|liveness|status)([/_\s-]|$)/.test(value)
|
|
722
727
|
}
|
|
723
728
|
|
|
724
|
-
function findingList(documentResult, challengeResults, preflightResults, entries) {
|
|
729
|
+
function findingList(documentResult, challengeResults, preflightResults, entries, options = {}) {
|
|
725
730
|
const document = documentResult.body.json ?? {}
|
|
726
731
|
const findings = []
|
|
727
732
|
const networks = valueList(document.networks)
|
|
@@ -795,6 +800,9 @@ function findingList(documentResult, challengeResults, preflightResults, entries
|
|
|
795
800
|
if (looksExplicitlyCacheable(result.headers)) {
|
|
796
801
|
findings.push(`P2 - ${result.name} payment challenge response is explicitly cacheable (${cachePolicy(result.headers)}); paid routes should use no-store/private cache policy or bypass shared caches.`)
|
|
797
802
|
}
|
|
803
|
+
else if (options.strictCache && !cachePolicy(result.headers)) {
|
|
804
|
+
findings.push(`P3 - ${result.name} payment challenge response did not expose Cache-Control; for payment-gated routes, document or send no-store/private cache policy and confirm paid 200 responses are never shared-cacheable.`)
|
|
805
|
+
}
|
|
798
806
|
}
|
|
799
807
|
|
|
800
808
|
for (const result of preflightResults) {
|
|
@@ -853,6 +861,9 @@ function groupedFindingLabel(finding) {
|
|
|
853
861
|
if (/challenge advertises placeholder-looking payTo/.test(finding)) {
|
|
854
862
|
return 'P1 - Challenges advertise placeholder-looking payTo recipients.'
|
|
855
863
|
}
|
|
864
|
+
if (/payment challenge response did not expose Cache-Control/.test(finding)) {
|
|
865
|
+
return 'P3 - Payment challenge responses do not expose Cache-Control in strict cache mode.'
|
|
866
|
+
}
|
|
856
867
|
return null
|
|
857
868
|
}
|
|
858
869
|
|
|
@@ -1013,7 +1024,9 @@ async function runCheck(options) {
|
|
|
1013
1024
|
preflights,
|
|
1014
1025
|
sourceDocument,
|
|
1015
1026
|
}
|
|
1016
|
-
report.findings = findingList(document, challenges, preflights, entries
|
|
1027
|
+
report.findings = findingList(document, challenges, preflights, entries, {
|
|
1028
|
+
strictCache: options.strictCache,
|
|
1029
|
+
})
|
|
1017
1030
|
return report
|
|
1018
1031
|
}
|
|
1019
1032
|
|