ax-audit 4.0.0 → 4.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.
- package/CHANGELOG.md +23 -0
- package/dist/checks/agent-json.d.ts +14 -0
- package/dist/checks/agent-json.d.ts.map +1 -0
- package/dist/checks/agent-json.js +167 -0
- package/dist/checks/agent-json.js.map +1 -0
- package/dist/checks/auth-discovery.d.ts.map +1 -1
- package/dist/checks/auth-discovery.js +100 -11
- package/dist/checks/auth-discovery.js.map +1 -1
- package/dist/checks/html-rendering.d.ts +1 -1
- package/dist/checks/html-rendering.d.ts.map +1 -1
- package/dist/checks/html-rendering.js +24 -6
- package/dist/checks/html-rendering.js.map +1 -1
- package/dist/checks/html-utils.d.ts +19 -0
- package/dist/checks/html-utils.d.ts.map +1 -1
- package/dist/checks/html-utils.js +27 -0
- package/dist/checks/html-utils.js.map +1 -1
- package/dist/checks/mcp.d.ts +4 -0
- package/dist/checks/mcp.d.ts.map +1 -0
- package/dist/checks/mcp.js +162 -0
- package/dist/checks/mcp.js.map +1 -0
- package/dist/checks/openapi.d.ts +4 -0
- package/dist/checks/openapi.d.ts.map +1 -0
- package/dist/checks/openapi.js +121 -0
- package/dist/checks/openapi.js.map +1 -0
- package/dist/checks/structured-data.js +27 -1
- package/dist/checks/structured-data.js.map +1 -1
- package/dist/checks/well-known-ai.d.ts +17 -0
- package/dist/checks/well-known-ai.d.ts.map +1 -0
- package/dist/checks/well-known-ai.js +123 -0
- package/dist/checks/well-known-ai.js.map +1 -0
- package/dist/cli.d.ts +1 -3
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -16
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +20 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -1
- package/dist/index.js.map +1 -1
- package/dist/scorer.d.ts +14 -1
- package/dist/scorer.d.ts.map +1 -1
- package/dist/scorer.js +27 -1
- package/dist/scorer.js.map +1 -1
- package/docs/api.md +58 -2
- package/docs/checks.md +4 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to ax-audit are documented here.
|
|
4
4
|
|
|
5
|
+
## [4.2.0] - 2026-09-04
|
|
6
|
+
|
|
7
|
+
**Three checks stop grading the wrong thing.** Every change can raise scores; none can lower one, so baselines written by 4.1 gain no false regressions.
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **`html-rendering` measures the text-to-markup ratio against structural markup.** Script and style bodies, svg interiors, comments and the `<head>` no longer count in the denominator: a framework's hydration payload and a logo's path data are not markup an agent reads for content. Measured raw, vercel.com, stripe.com and nextjs.org all sat under the 5% threshold while serving hundreds of words of visible text — the old ratio graded framework choice, not agent experience. And when the content thresholds are met, a still-low ratio reports as a warn that moves nothing: the ratio exists as a SPA-shell symptom, and text above threshold disproves the shell. A page that misses the content thresholds keeps the −10.
|
|
12
|
+
- **`auth-discovery` honours an API's own statement that it is public.** An OpenAPI description that declares no security scheme — or pins it down with root-level `security: []` — is the machine-readable claim that every operation is anonymous, and a security requirement cannot legally reference an undeclared scheme, so the absence of schemes is decisive. Such a description no longer counts as a surface needing OAuth discovery; a site whose only surface is a credential-free API reports **n/a** instead of 0. The check's own hint already conceded "if everything is public, this is nothing to fix" while charging the full weight for it. An MCP server card has no field for that claim, so the remote endpoint is asked directly: a server requiring OAuth answers an unauthenticated request with 401 — the very challenge the RFC 9728 chain begins from — and a card whose remotes never answer 401, or that names no remotes at all (a locally-run server has no HTTP resource to protect), no longer counts as a surface either. API catalogs and commerce profiles still do: neither carries a machine-readable "no credentials" claim, and there is nothing to probe.
|
|
13
|
+
- **`structured-data` follows `@id` references before reading authorship.** `author: {"@id": "...#organization"}` pointing at a node in the same `@graph` is the canonical JSON-LD idiom — it is what Yoast emits for millions of WordPress sites — and the provenance reader treated it as an empty object and reported "No author declared in structured data". Pure references (an object whose only key is `@id`) now resolve against the graph before names are read.
|
|
14
|
+
|
|
15
|
+
## [4.1.0] - 2026-09-04
|
|
16
|
+
|
|
17
|
+
**The reference tables are importable.** A consumer could always run an audit and never describe one: `CHECK_WEIGHTS`, `CHECK_CATEGORIES` and the crawler lists sat behind an `exports` map that admits only the entry point, so anything printing what a check is worth, grouping results by area, or naming the crawlers worth naming kept a hand-copied table and a test to catch the day it went stale. That is a duplication this package caused.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **`VERSION`, `CHECK_WEIGHTS`, `CHECK_CATEGORIES`, `GRADES`** exported from the entry point.
|
|
22
|
+
- **`AI_CRAWLERS`, `ALL_AI_CRAWLERS`, `CORE_AI_CRAWLERS`, `LEGACY_AI_CRAWLERS`, `CRAWLER_META`, `CONTENT_SIGNALS`**, with `crawlerInfo`, `crawlerPurpose` and `legacyCrawlerNote` for looking a token up, and the `CrawlerInfo` / `CrawlerPurpose` types.
|
|
23
|
+
- **`categoryScore(results, category)`** exported. It was in `cli.ts`, which meant importing `commander` to reach it; it belongs beside `calculateOverallScore` and now lives there. `--fail-on-category` is one caller and a report grouped by area is another.
|
|
24
|
+
- **`test/public-api.test.js`**, which fails both ways: on a promised export that disappeared, and on a new name that leaked out of a refactor. It also holds the tables against the registered checks — every shipped check is weighed and categorised, nothing retired lingers in either, no crawler token sits in two purposes, and a check declaring its own `meta.category` agrees with the table.
|
|
25
|
+
|
|
26
|
+
Nothing else changed: no check, no weight, no score. The rest of `constants.ts` stays private, because a consumer pinned to a threshold or a required-field list would make every check's internals a breaking change.
|
|
27
|
+
|
|
5
28
|
## [4.0.0] - 2026-09-04
|
|
6
29
|
|
|
7
30
|
**Scores change on every site.** This release redistributes the weights, makes protocol checks conditional, and retires a check whose premise did not survive verification. Baselines written by earlier versions are read normally, but regression gating is suspended across the change — a rescore is not something the site did.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CheckContext, CheckResult, CheckMeta } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* "agent-json" — `/.well-known/agent.json` per the A2A (Agent-to-Agent) protocol.
|
|
4
|
+
*
|
|
5
|
+
* Validates the document on three axes:
|
|
6
|
+
* 1. JSON well-formedness
|
|
7
|
+
* 2. Required fields per the A2A spec (`name`, `description`, `url`, `skills`)
|
|
8
|
+
* 3. Field semantics: `url` should resolve to the same origin as the audited site,
|
|
9
|
+
* `skills[]` should each declare an `id` and `description`, and protocol/optional
|
|
10
|
+
* fields are present where expected.
|
|
11
|
+
*/
|
|
12
|
+
export declare const meta: CheckMeta;
|
|
13
|
+
export default function check(ctx: CheckContext): Promise<CheckResult>;
|
|
14
|
+
//# sourceMappingURL=agent-json.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-json.d.ts","sourceRoot":"","sources":["../../src/checks/agent-json.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAW,MAAM,aAAa,CAAC;AAGjF;;;;;;;;;GASG;AACH,eAAO,MAAM,IAAI,EAAE,SAKlB,CAAC;AAEF,wBAA8B,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CA0I3E"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { AGENT_JSON_REQUIRED_FIELDS } from '../constants.js';
|
|
2
|
+
import { guideUrl } from '../guide-urls.js';
|
|
3
|
+
import { buildResult, checkContentType } from './utils.js';
|
|
4
|
+
/**
|
|
5
|
+
* "agent-json" — `/.well-known/agent.json` per the A2A (Agent-to-Agent) protocol.
|
|
6
|
+
*
|
|
7
|
+
* Validates the document on three axes:
|
|
8
|
+
* 1. JSON well-formedness
|
|
9
|
+
* 2. Required fields per the A2A spec (`name`, `description`, `url`, `skills`)
|
|
10
|
+
* 3. Field semantics: `url` should resolve to the same origin as the audited site,
|
|
11
|
+
* `skills[]` should each declare an `id` and `description`, and protocol/optional
|
|
12
|
+
* fields are present where expected.
|
|
13
|
+
*/
|
|
14
|
+
export const meta = {
|
|
15
|
+
id: 'agent-json',
|
|
16
|
+
name: 'Agent Card (A2A)',
|
|
17
|
+
description: 'Checks /.well-known/agent.json A2A protocol compliance',
|
|
18
|
+
weight: 7,
|
|
19
|
+
};
|
|
20
|
+
export default async function check(ctx) {
|
|
21
|
+
const start = performance.now();
|
|
22
|
+
const findings = [];
|
|
23
|
+
let score = 100;
|
|
24
|
+
const res = await ctx.fetch(`${ctx.url}/.well-known/agent.json`);
|
|
25
|
+
if (!res.ok) {
|
|
26
|
+
findings.push({
|
|
27
|
+
status: 'fail',
|
|
28
|
+
message: '/.well-known/agent.json not found',
|
|
29
|
+
detail: `HTTP ${res.status || 'network error'}`,
|
|
30
|
+
hint: "Create a /.well-known/agent.json file following the A2A (Agent-to-Agent) protocol. It should include name, description, url, and skills fields describing your site's capabilities.",
|
|
31
|
+
learnMoreUrl: guideUrl(meta.id, 'not-found'),
|
|
32
|
+
});
|
|
33
|
+
return buildResult(meta, 0, findings, start);
|
|
34
|
+
}
|
|
35
|
+
findings.push({ status: 'pass', message: '/.well-known/agent.json exists' });
|
|
36
|
+
const ctFinding = checkContentType(res, ['application/json'], {
|
|
37
|
+
checkId: meta.id,
|
|
38
|
+
resourceLabel: '/.well-known/agent.json',
|
|
39
|
+
anchor: 'wrong-content-type',
|
|
40
|
+
});
|
|
41
|
+
if (ctFinding) {
|
|
42
|
+
findings.push(ctFinding);
|
|
43
|
+
score -= 5;
|
|
44
|
+
}
|
|
45
|
+
let data;
|
|
46
|
+
try {
|
|
47
|
+
data = JSON.parse(res.body);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
findings.push({
|
|
51
|
+
status: 'fail',
|
|
52
|
+
message: 'Invalid JSON',
|
|
53
|
+
hint: 'Fix the JSON syntax in your agent.json file. Validate it with a JSON linter.',
|
|
54
|
+
learnMoreUrl: guideUrl(meta.id, 'invalid-json'),
|
|
55
|
+
});
|
|
56
|
+
return buildResult(meta, 10, findings, start);
|
|
57
|
+
}
|
|
58
|
+
findings.push({ status: 'pass', message: 'Valid JSON' });
|
|
59
|
+
for (const field of AGENT_JSON_REQUIRED_FIELDS) {
|
|
60
|
+
if (data[field] !== undefined && data[field] !== null) {
|
|
61
|
+
findings.push({ status: 'pass', message: `Required field "${field}" present` });
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
findings.push({
|
|
65
|
+
status: 'fail',
|
|
66
|
+
message: `Required field "${field}" missing`,
|
|
67
|
+
hint: `Add the "${field}" field to your agent.json. This is required by the A2A protocol specification.`,
|
|
68
|
+
learnMoreUrl: guideUrl(meta.id, 'missing-field'),
|
|
69
|
+
});
|
|
70
|
+
score -= 15;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (typeof data.url === 'string' && data.url.length > 0) {
|
|
74
|
+
const sameOrigin = sameHost(data.url, ctx.url);
|
|
75
|
+
if (sameOrigin === false) {
|
|
76
|
+
findings.push({
|
|
77
|
+
status: 'warn',
|
|
78
|
+
message: `agent.json "url" points to a different origin: ${data.url}`,
|
|
79
|
+
hint: 'The url field should match the audited site origin. Pointing it elsewhere can confuse agents about the canonical agent endpoint.',
|
|
80
|
+
learnMoreUrl: guideUrl(meta.id, 'url-mismatch'),
|
|
81
|
+
});
|
|
82
|
+
score -= 5;
|
|
83
|
+
}
|
|
84
|
+
else if (sameOrigin === null) {
|
|
85
|
+
findings.push({
|
|
86
|
+
status: 'warn',
|
|
87
|
+
message: `agent.json "url" is not a valid absolute URL: ${data.url}`,
|
|
88
|
+
hint: 'Provide an absolute https:// URL for the url field.',
|
|
89
|
+
learnMoreUrl: guideUrl(meta.id, 'url-invalid'),
|
|
90
|
+
});
|
|
91
|
+
score -= 5;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (Array.isArray(data.skills) && data.skills.length > 0) {
|
|
95
|
+
findings.push({ status: 'pass', message: `${data.skills.length} skill(s) defined` });
|
|
96
|
+
const incomplete = data.skills.filter((s) => !s.id || !s.description);
|
|
97
|
+
if (incomplete.length === 0) {
|
|
98
|
+
findings.push({ status: 'pass', message: 'All skills have id + description' });
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
findings.push({
|
|
102
|
+
status: 'warn',
|
|
103
|
+
message: `${incomplete.length}/${data.skills.length} skill(s) missing id or description`,
|
|
104
|
+
hint: 'Each entry in skills[] should include both an id and a description so agents can address it and reason about its purpose.',
|
|
105
|
+
learnMoreUrl: guideUrl(meta.id, 'incomplete-skills'),
|
|
106
|
+
});
|
|
107
|
+
score -= 5;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else if (Array.isArray(data.skills)) {
|
|
111
|
+
findings.push({
|
|
112
|
+
status: 'warn',
|
|
113
|
+
message: 'Skills array is empty',
|
|
114
|
+
hint: 'Add at least one skill to the skills array describing what your agent/site can do.',
|
|
115
|
+
learnMoreUrl: guideUrl(meta.id, 'empty-skills'),
|
|
116
|
+
});
|
|
117
|
+
score -= 10;
|
|
118
|
+
}
|
|
119
|
+
if (data.protocolVersion) {
|
|
120
|
+
findings.push({ status: 'pass', message: `Protocol version: ${data.protocolVersion}` });
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
findings.push({
|
|
124
|
+
status: 'warn',
|
|
125
|
+
message: 'No protocolVersion field',
|
|
126
|
+
hint: 'Add "protocolVersion": "0.2.0" to your agent.json to declare A2A protocol compatibility.',
|
|
127
|
+
learnMoreUrl: guideUrl(meta.id, 'no-protocol-version'),
|
|
128
|
+
});
|
|
129
|
+
score -= 5;
|
|
130
|
+
}
|
|
131
|
+
const optionalFields = ['capabilities', 'authentication', 'documentationUrl'];
|
|
132
|
+
const presentOptional = optionalFields.filter((f) => data[f] !== undefined);
|
|
133
|
+
if (presentOptional.length === optionalFields.length) {
|
|
134
|
+
findings.push({
|
|
135
|
+
status: 'pass',
|
|
136
|
+
message: 'All optional fields present (capabilities, authentication, documentationUrl)',
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
else if (presentOptional.length > 0) {
|
|
140
|
+
findings.push({
|
|
141
|
+
status: 'pass',
|
|
142
|
+
message: `${presentOptional.length}/${optionalFields.length} optional fields present`,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
findings.push({
|
|
147
|
+
status: 'warn',
|
|
148
|
+
message: 'No optional fields (capabilities, authentication, documentationUrl)',
|
|
149
|
+
hint: 'Consider adding capabilities (what protocols you support), authentication (auth requirements), and documentationUrl (link to API docs).',
|
|
150
|
+
learnMoreUrl: guideUrl(meta.id, 'missing-optional'),
|
|
151
|
+
});
|
|
152
|
+
score -= 5;
|
|
153
|
+
}
|
|
154
|
+
return buildResult(meta, score, findings, start);
|
|
155
|
+
}
|
|
156
|
+
/** Returns `true` when the two URLs share host (case-insensitive), `false` if hosts differ, `null` on parse error. */
|
|
157
|
+
function sameHost(a, b) {
|
|
158
|
+
try {
|
|
159
|
+
const ua = new URL(a);
|
|
160
|
+
const ub = new URL(b);
|
|
161
|
+
return ua.host.toLowerCase() === ub.host.toLowerCase();
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=agent-json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-json.js","sourceRoot":"","sources":["../../src/checks/agent-json.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-discovery.d.ts","sourceRoot":"","sources":["../../src/checks/auth-discovery.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAW,aAAa,EAAE,MAAM,aAAa,CAAC;AAIhG;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,IAAI,EAAE,SAKlB,CAAC;
|
|
1
|
+
{"version":3,"file":"auth-discovery.d.ts","sourceRoot":"","sources":["../../src/checks/auth-discovery.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAW,aAAa,EAAE,MAAM,aAAa,CAAC;AAIhG;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,IAAI,EAAE,SAKlB,CAAC;AAmHF,oFAAoF;AACpF,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG3E;AAED,wBAA8B,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAkG3E;AA4FD,iEAAiE;AACjE,YAAY,EAAE,aAAa,EAAE,CAAC"}
|
|
@@ -32,12 +32,12 @@ const AUTHORIZATION_SERVER = '/.well-known/oauth-authorization-server';
|
|
|
32
32
|
const OPENID_CONFIGURATION = '/.well-known/openid-configuration';
|
|
33
33
|
/** Paths that indicate the site has something worth authorizing. */
|
|
34
34
|
const SURFACE_PROBES = [
|
|
35
|
-
{ path: '/openapi.json', label: 'an OpenAPI description' },
|
|
36
|
-
{ path: '/.well-known/openapi.json', label: 'an OpenAPI description' },
|
|
37
|
-
{ path: '/.well-known/api-catalog', label: 'an API catalog' },
|
|
38
|
-
{ path: '/.well-known/mcp/server-card.json', label: 'an MCP server card' },
|
|
39
|
-
{ path: '/mcp/server-card', label: 'an MCP server card' },
|
|
40
|
-
{ path: '/.well-known/ucp', label: 'a commerce profile' },
|
|
35
|
+
{ path: '/openapi.json', label: 'an OpenAPI description', kind: 'openapi' },
|
|
36
|
+
{ path: '/.well-known/openapi.json', label: 'an OpenAPI description', kind: 'openapi' },
|
|
37
|
+
{ path: '/.well-known/api-catalog', label: 'an API catalog', kind: 'other' },
|
|
38
|
+
{ path: '/.well-known/mcp/server-card.json', label: 'an MCP server card', kind: 'mcp-card' },
|
|
39
|
+
{ path: '/mcp/server-card', label: 'an MCP server card', kind: 'mcp-card' },
|
|
40
|
+
{ path: '/.well-known/ucp', label: 'a commerce profile', kind: 'other' },
|
|
41
41
|
];
|
|
42
42
|
async function fetchJson(ctx, url) {
|
|
43
43
|
const res = await ctx.fetch(url);
|
|
@@ -50,14 +50,86 @@ async function fetchJson(ctx, url) {
|
|
|
50
50
|
return null;
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Does an OpenAPI description say credentials exist anywhere in the API?
|
|
55
|
+
*
|
|
56
|
+
* A document that declares no security scheme has nothing an OAuth flow
|
|
57
|
+
* could attach to, and a security requirement cannot legally reference an
|
|
58
|
+
* undeclared scheme, so the absence of schemes is decisive on its own.
|
|
59
|
+
* Root-level `security: []` says the same thing more loudly. Either way,
|
|
60
|
+
* the API is stating "you do not authenticate", and demanding OAuth
|
|
61
|
+
* discovery metadata from it would penalize the honest answer.
|
|
62
|
+
*/
|
|
63
|
+
function declaresNoAuth(body) {
|
|
64
|
+
try {
|
|
65
|
+
const doc = JSON.parse(body);
|
|
66
|
+
const components = doc.components;
|
|
67
|
+
const schemes = components?.securitySchemes ??
|
|
68
|
+
doc.securityDefinitions;
|
|
69
|
+
return schemes === undefined || Object.keys(schemes).length === 0;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// Not JSON we can read; assume it could describe an authenticated API.
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Does the MCP server this card advertises actually demand credentials?
|
|
78
|
+
*
|
|
79
|
+
* The card format has no field that says "no authentication", so the
|
|
80
|
+
* remote endpoint is asked directly: a server that requires OAuth answers
|
|
81
|
+
* an unauthenticated request with 401 before anything else — that 401 is
|
|
82
|
+
* where the RFC 9728 chain is supposed to begin. Any other answer means
|
|
83
|
+
* the transport serves anonymous callers. A card with no remotes names a
|
|
84
|
+
* server an agent runs locally, which has no HTTP resource to protect.
|
|
85
|
+
*/
|
|
86
|
+
async function mcpRemoteNeedsAuth(ctx, body) {
|
|
87
|
+
try {
|
|
88
|
+
const card = JSON.parse(body);
|
|
89
|
+
const remotes = Array.isArray(card.remotes) ? card.remotes : [];
|
|
90
|
+
const urls = remotes
|
|
91
|
+
.map((r) => (r !== null && typeof r === 'object' ? r.url : undefined))
|
|
92
|
+
.filter((u) => typeof u === 'string')
|
|
93
|
+
.slice(0, 3);
|
|
94
|
+
if (urls.length === 0)
|
|
95
|
+
return false;
|
|
96
|
+
for (const url of urls) {
|
|
97
|
+
const res = await ctx.fetch(url);
|
|
98
|
+
if (res.status === 401)
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// Not a card we can read; keep treating it as a surface.
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
53
108
|
/** Does this site expose anything an agent would need credentials for? */
|
|
54
|
-
async function
|
|
109
|
+
async function scanSurfaces(ctx) {
|
|
110
|
+
let publicApi = null;
|
|
111
|
+
let anonymousMcp = null;
|
|
55
112
|
for (const probe of SURFACE_PROBES) {
|
|
56
113
|
const res = await ctx.fetch(`${ctx.url}${probe.path}`);
|
|
57
|
-
if (res.ok
|
|
58
|
-
|
|
114
|
+
if (!res.ok || res.body.trim().length === 0 || isHtmlDocument(res.body))
|
|
115
|
+
continue;
|
|
116
|
+
// A surface gets to answer the question itself where its format
|
|
117
|
+
// allows it: an OpenAPI description that declares no authentication,
|
|
118
|
+
// and an MCP card whose remote never answers 401, are not surfaces
|
|
119
|
+
// auth discovery applies to. Catalogs and commerce profiles stay
|
|
120
|
+
// surfaces — neither carries a machine-readable "no credentials"
|
|
121
|
+
// claim, and there is nothing to probe.
|
|
122
|
+
if (probe.kind === 'openapi' && declaresNoAuth(res.body)) {
|
|
123
|
+
publicApi = probe.path;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (probe.kind === 'mcp-card' && !(await mcpRemoteNeedsAuth(ctx, res.body))) {
|
|
127
|
+
anonymousMcp = probe.path;
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
return { surface: probe.label, publicApi, anonymousMcp };
|
|
59
131
|
}
|
|
60
|
-
return null;
|
|
132
|
+
return { surface: null, publicApi, anonymousMcp };
|
|
61
133
|
}
|
|
62
134
|
/** Read the `resource_metadata` parameter out of a `WWW-Authenticate` challenge. */
|
|
63
135
|
export function resourceMetadataFromChallenge(header) {
|
|
@@ -82,8 +154,25 @@ export default async function check(ctx) {
|
|
|
82
154
|
const resource = (metadataUrl !== null ? await fetchJson(ctx, metadataUrl) : null) ??
|
|
83
155
|
(await fetchJson(ctx, `${ctx.url}${PROTECTED_RESOURCE}`));
|
|
84
156
|
if (resource === null) {
|
|
85
|
-
const surface = await
|
|
157
|
+
const { surface, publicApi, anonymousMcp } = await scanSurfaces(ctx);
|
|
86
158
|
if (surface === null) {
|
|
159
|
+
if (publicApi !== null) {
|
|
160
|
+
findings.push({
|
|
161
|
+
status: 'pass',
|
|
162
|
+
message: 'The API description declares no authentication — auth discovery does not apply',
|
|
163
|
+
detail: `${publicApi} declares no security scheme, which in OpenAPI is the statement that every operation is anonymous. There is nothing here for an OAuth flow to attach to.`,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
if (anonymousMcp !== null) {
|
|
167
|
+
findings.push({
|
|
168
|
+
status: 'pass',
|
|
169
|
+
message: 'The MCP server serves anonymous callers — auth discovery does not apply',
|
|
170
|
+
detail: `The remote endpoint named by ${anonymousMcp} answers an unauthenticated request without a 401, so there is no challenge for the RFC 9728 chain to begin from.`,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
if (publicApi !== null || anonymousMcp !== null) {
|
|
174
|
+
return notApplicable(meta, findings, start);
|
|
175
|
+
}
|
|
87
176
|
findings.push({
|
|
88
177
|
status: 'pass',
|
|
89
178
|
message: 'Nothing on this site requires authorization — auth discovery does not apply',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-discovery.js","sourceRoot":"","sources":["../../src/checks/auth-discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,IAAI,GAAc;IAC7B,EAAE,EAAE,gBAAgB;IACpB,IAAI,EAAE,gBAAgB;IACtB,WAAW,EAAE,8FAA8F;IAC3G,QAAQ,EAAE,WAAW;CACtB,CAAC;AAEF,MAAM,kBAAkB,GAAG,uCAAuC,CAAC;AACnE,MAAM,oBAAoB,GAAG,yCAAyC,CAAC;AACvE,MAAM,oBAAoB,GAAG,mCAAmC,CAAC;AAEjE,oEAAoE;AACpE,MAAM,cAAc,GAAG;IACrB,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,wBAAwB,EAAE;
|
|
1
|
+
{"version":3,"file":"auth-discovery.js","sourceRoot":"","sources":["../../src/checks/auth-discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,7 +9,7 @@ import type { CheckContext, CheckResult, CheckMeta } from '../types.js';
|
|
|
9
9
|
*
|
|
10
10
|
* Signals (each contributes to the score):
|
|
11
11
|
* - Visible text length and word count (low → likely JS-rendered shell)
|
|
12
|
-
* - Text-to-markup ratio (high JS, no text → SPA)
|
|
12
|
+
* - Text-to-markup ratio against structural markup (high JS, no text → SPA)
|
|
13
13
|
* - Presence of semantic landmarks (`<main>`, `<article>`, `<header>`, `<footer>`, `<nav>`)
|
|
14
14
|
* - Single, meaningful `<h1>`
|
|
15
15
|
* - `<noscript>` fallback for JS-only frameworks
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-rendering.d.ts","sourceRoot":"","sources":["../../src/checks/html-rendering.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAW,MAAM,aAAa,CAAC;AAIjF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,IAAI,EAAE,SAIlB,CAAC;AAOF,wBAA8B,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"html-rendering.d.ts","sourceRoot":"","sources":["../../src/checks/html-rendering.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAW,MAAM,aAAa,CAAC;AAIjF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,IAAI,EAAE,SAIlB,CAAC;AAOF,wBAA8B,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CA6L3E"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { guideUrl } from '../guide-urls.js';
|
|
2
|
-
import { countExecutableScripts, extractVisibleText, findOpeningTag, getMetaContent } from './html-utils.js';
|
|
2
|
+
import { countExecutableScripts, extractVisibleText, findOpeningTag, getMetaContent, structuralMarkupLength } from './html-utils.js';
|
|
3
3
|
import { buildResult } from './utils.js';
|
|
4
4
|
/**
|
|
5
5
|
* "html-rendering" — does the HTML delivered to a non-JS agent actually contain content?
|
|
@@ -11,7 +11,7 @@ import { buildResult } from './utils.js';
|
|
|
11
11
|
*
|
|
12
12
|
* Signals (each contributes to the score):
|
|
13
13
|
* - Visible text length and word count (low → likely JS-rendered shell)
|
|
14
|
-
* - Text-to-markup ratio (high JS, no text → SPA)
|
|
14
|
+
* - Text-to-markup ratio against structural markup (high JS, no text → SPA)
|
|
15
15
|
* - Presence of semantic landmarks (`<main>`, `<article>`, `<header>`, `<footer>`, `<nav>`)
|
|
16
16
|
* - Single, meaningful `<h1>`
|
|
17
17
|
* - `<noscript>` fallback for JS-only frameworks
|
|
@@ -43,8 +43,12 @@ export default async function check(ctx) {
|
|
|
43
43
|
}
|
|
44
44
|
const visibleText = extractVisibleText(html);
|
|
45
45
|
const wordCount = visibleText ? visibleText.split(/\s+/).filter(Boolean).length : 0;
|
|
46
|
-
const
|
|
47
|
-
|
|
46
|
+
const textOk = visibleText.length >= MIN_TEXT_LENGTH && wordCount >= MIN_WORD_COUNT;
|
|
47
|
+
// Against the markup that could have carried text — script and style
|
|
48
|
+
// bodies, svg interiors and the head excluded (see structuralMarkupLength).
|
|
49
|
+
const markup = structuralMarkupLength(html);
|
|
50
|
+
const ratio = markup > 0 ? visibleText.length / markup : 0;
|
|
51
|
+
if (textOk) {
|
|
48
52
|
findings.push({
|
|
49
53
|
status: 'pass',
|
|
50
54
|
message: `Server-rendered content detected (${wordCount} words, ${visibleText.length} chars of visible text)`,
|
|
@@ -72,14 +76,28 @@ export default async function check(ctx) {
|
|
|
72
76
|
if (ratio >= MIN_TEXT_TO_HTML_RATIO) {
|
|
73
77
|
findings.push({
|
|
74
78
|
status: 'pass',
|
|
75
|
-
message: `Text-to-markup ratio is healthy (${(ratio * 100).toFixed(1)}%)`,
|
|
79
|
+
message: `Text-to-markup ratio is healthy (${(ratio * 100).toFixed(1)}% of structural markup)`,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
else if (textOk) {
|
|
83
|
+
// The ratio exists as a shell symptom, and the text thresholds just
|
|
84
|
+
// proved this page is not a shell: the words are demonstrably there.
|
|
85
|
+
// What a low ratio still says is that the structure around them is
|
|
86
|
+
// expensive for an agent consuming raw HTML — worth saying, not
|
|
87
|
+
// worth charging for twice.
|
|
88
|
+
findings.push({
|
|
89
|
+
status: 'warn',
|
|
90
|
+
message: `Markup-heavy page (text is ${(ratio * 100).toFixed(1)}% of structural markup)`,
|
|
91
|
+
detail: `Recommended minimum: ${(MIN_TEXT_TO_HTML_RATIO * 100).toFixed(0)}%. The content thresholds are met, so this does not move the score.`,
|
|
92
|
+
hint: 'The visible text clears the content thresholds, so agents can read this page. Trimming wrapper markup would still make it cheaper to consume.',
|
|
93
|
+
learnMoreUrl: guideUrl(meta.id, 'low-ratio'),
|
|
76
94
|
});
|
|
77
95
|
}
|
|
78
96
|
else {
|
|
79
97
|
findings.push({
|
|
80
98
|
status: 'warn',
|
|
81
99
|
message: `Low text-to-markup ratio (${(ratio * 100).toFixed(1)}%)`,
|
|
82
|
-
detail: `Recommended minimum: ${(MIN_TEXT_TO_HTML_RATIO * 100).toFixed(0)}
|
|
100
|
+
detail: `Recommended minimum: ${(MIN_TEXT_TO_HTML_RATIO * 100).toFixed(0)}% of structural markup (script/style bodies and svg interiors excluded)`,
|
|
83
101
|
hint: 'A very low text-to-markup ratio is a typical SPA-shell symptom. Inline more content directly into the HTML response.',
|
|
84
102
|
learnMoreUrl: guideUrl(meta.id, 'low-ratio'),
|
|
85
103
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-rendering.js","sourceRoot":"","sources":["../../src/checks/html-rendering.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"html-rendering.js","sourceRoot":"","sources":["../../src/checks/html-rendering.ts"],"names":[],"mappings":"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"}
|
|
@@ -44,4 +44,23 @@ export declare function extractVisibleText(html: string): string;
|
|
|
44
44
|
export declare function findJsonLdBlocks(html: string): string[];
|
|
45
45
|
/** Count `<script>` tags (excluding `type="application/ld+json"` data blocks). */
|
|
46
46
|
export declare function countExecutableScripts(html: string): number;
|
|
47
|
+
/**
|
|
48
|
+
* How much of the document is markup that could have carried visible text.
|
|
49
|
+
*
|
|
50
|
+
* The denominator for the text-to-markup ratio. Three element classes are
|
|
51
|
+
* emptied rather than counted, because their contents are not markup an
|
|
52
|
+
* agent parses for content: script bodies are code or serialized data (a
|
|
53
|
+
* framework's hydration payload alone can be ten times the page), style
|
|
54
|
+
* bodies are presentation, and svg interiors are drawing instructions —
|
|
55
|
+
* the inline twin of image bytes, which nobody would count against an
|
|
56
|
+
* `<img>`. Comments likewise. The head is metadata by definition — much
|
|
57
|
+
* of it demanded by other checks in this engine — so the measurement
|
|
58
|
+
* starts at `<body>` when one exists.
|
|
59
|
+
*
|
|
60
|
+
* Measured against the raw document instead, vercel.com, stripe.com and
|
|
61
|
+
* nextjs.org all sat under the 5% threshold while serving hundreds of
|
|
62
|
+
* words of visible text: the raw ratio graded framework choice, not
|
|
63
|
+
* agent experience.
|
|
64
|
+
*/
|
|
65
|
+
export declare function structuralMarkupLength(html: string): number;
|
|
47
66
|
//# sourceMappingURL=html-utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-utils.d.ts","sourceRoot":"","sources":["../../src/checks/html-utils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,mEAAmE;AACnE,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,6FAA6F;AAC7F,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CASlD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI3E;AAED,0FAA0F;AAC1F,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKlF;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG9F;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMvE;AAED,kGAAkG;AAClG,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAG3E;AAED,yEAAyE;AACzE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAGhE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAQvD;AAED,kFAAkF;AAClF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAS3D"}
|
|
1
|
+
{"version":3,"file":"html-utils.d.ts","sourceRoot":"","sources":["../../src/checks/html-utils.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,mEAAmE;AACnE,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,6FAA6F;AAC7F,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CASlD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI3E;AAED,0FAA0F;AAC1F,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKlF;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG9F;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMvE;AAED,kGAAkG;AAClG,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAG3E;AAED,yEAAyE;AACzE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAGhE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAQvD;AAED,kFAAkF;AAClF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAS3D;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ3D"}
|
|
@@ -109,4 +109,31 @@ export function countExecutableScripts(html) {
|
|
|
109
109
|
}
|
|
110
110
|
return count;
|
|
111
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* How much of the document is markup that could have carried visible text.
|
|
114
|
+
*
|
|
115
|
+
* The denominator for the text-to-markup ratio. Three element classes are
|
|
116
|
+
* emptied rather than counted, because their contents are not markup an
|
|
117
|
+
* agent parses for content: script bodies are code or serialized data (a
|
|
118
|
+
* framework's hydration payload alone can be ten times the page), style
|
|
119
|
+
* bodies are presentation, and svg interiors are drawing instructions —
|
|
120
|
+
* the inline twin of image bytes, which nobody would count against an
|
|
121
|
+
* `<img>`. Comments likewise. The head is metadata by definition — much
|
|
122
|
+
* of it demanded by other checks in this engine — so the measurement
|
|
123
|
+
* starts at `<body>` when one exists.
|
|
124
|
+
*
|
|
125
|
+
* Measured against the raw document instead, vercel.com, stripe.com and
|
|
126
|
+
* nextjs.org all sat under the 5% threshold while serving hundreds of
|
|
127
|
+
* words of visible text: the raw ratio graded framework choice, not
|
|
128
|
+
* agent experience.
|
|
129
|
+
*/
|
|
130
|
+
export function structuralMarkupLength(html) {
|
|
131
|
+
const stripped = html
|
|
132
|
+
.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, '<script></script>')
|
|
133
|
+
.replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, '<style></style>')
|
|
134
|
+
.replace(/<svg\b[\s\S]*?<\/svg>/gi, '<svg></svg>')
|
|
135
|
+
.replace(/<!--[\s\S]*?-->/g, '');
|
|
136
|
+
const body = stripped.match(/<body[\s\S]*<\/body>/i);
|
|
137
|
+
return (body ? body[0] : stripped).length;
|
|
138
|
+
}
|
|
112
139
|
//# sourceMappingURL=html-utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-utils.js","sourceRoot":"","sources":["../../src/checks/html-utils.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"html-utils.js","sourceRoot":"","sources":["../../src/checks/html-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/checks/mcp.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAW,MAAM,aAAa,CAAC;AAGjF,eAAO,MAAM,IAAI,EAAE,SAKlB,CAAC;AAEF,wBAA8B,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CA6J3E"}
|