ax-audit 4.2.1 → 6.0.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 (188) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +39 -4
  3. package/dist/baseline.js +1 -1
  4. package/dist/baseline.js.map +1 -1
  5. package/dist/check-ids.js +1 -1
  6. package/dist/check-ids.js.map +1 -1
  7. package/dist/cli.js +1 -1
  8. package/dist/cli.js.map +1 -1
  9. package/dist/constants.d.ts +1 -85
  10. package/dist/constants.d.ts.map +1 -1
  11. package/dist/constants.js +0 -135
  12. package/dist/constants.js.map +1 -1
  13. package/dist/index.d.ts +3 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +2 -1
  16. package/dist/index.js.map +1 -1
  17. package/dist/license.d.ts +8 -0
  18. package/dist/license.d.ts.map +1 -0
  19. package/dist/license.js +18 -0
  20. package/dist/license.js.map +1 -0
  21. package/dist/metadata.d.ts +6 -0
  22. package/dist/metadata.d.ts.map +1 -0
  23. package/dist/metadata.js +205 -0
  24. package/dist/metadata.js.map +1 -0
  25. package/dist/orchestrator.d.ts +1 -0
  26. package/dist/orchestrator.d.ts.map +1 -1
  27. package/dist/orchestrator.js +134 -56
  28. package/dist/orchestrator.js.map +1 -1
  29. package/dist/scorer.js +2 -2
  30. package/dist/scorer.js.map +1 -1
  31. package/dist/types.d.ts +4 -0
  32. package/dist/types.d.ts.map +1 -1
  33. package/docs/api.md +14 -3
  34. package/docs/architecture.md +9 -98
  35. package/docs/ci.md +19 -0
  36. package/docs/cli.md +11 -0
  37. package/docs/faq.md +18 -0
  38. package/docs/getting-started.md +33 -1
  39. package/package.json +5 -5
  40. package/dist/checks/agent-access.d.ts +0 -33
  41. package/dist/checks/agent-access.d.ts.map +0 -1
  42. package/dist/checks/agent-access.js +0 -256
  43. package/dist/checks/agent-access.js.map +0 -1
  44. package/dist/checks/agent-card.d.ts +0 -37
  45. package/dist/checks/agent-card.d.ts.map +0 -1
  46. package/dist/checks/agent-card.js +0 -352
  47. package/dist/checks/agent-card.js.map +0 -1
  48. package/dist/checks/agent-operability.d.ts +0 -66
  49. package/dist/checks/agent-operability.d.ts.map +0 -1
  50. package/dist/checks/agent-operability.js +0 -383
  51. package/dist/checks/agent-operability.js.map +0 -1
  52. package/dist/checks/agent-skills.d.ts +0 -24
  53. package/dist/checks/agent-skills.d.ts.map +0 -1
  54. package/dist/checks/agent-skills.js +0 -316
  55. package/dist/checks/agent-skills.js.map +0 -1
  56. package/dist/checks/ai-catalog.d.ts +0 -28
  57. package/dist/checks/ai-catalog.d.ts.map +0 -1
  58. package/dist/checks/ai-catalog.js +0 -254
  59. package/dist/checks/ai-catalog.js.map +0 -1
  60. package/dist/checks/ai-directives.d.ts +0 -57
  61. package/dist/checks/ai-directives.d.ts.map +0 -1
  62. package/dist/checks/ai-directives.js +0 -263
  63. package/dist/checks/ai-directives.js.map +0 -1
  64. package/dist/checks/api-discovery.d.ts +0 -26
  65. package/dist/checks/api-discovery.d.ts.map +0 -1
  66. package/dist/checks/api-discovery.js +0 -432
  67. package/dist/checks/api-discovery.js.map +0 -1
  68. package/dist/checks/auth-discovery.d.ts +0 -28
  69. package/dist/checks/auth-discovery.d.ts.map +0 -1
  70. package/dist/checks/auth-discovery.js +0 -302
  71. package/dist/checks/auth-discovery.js.map +0 -1
  72. package/dist/checks/commerce-discovery.d.ts +0 -40
  73. package/dist/checks/commerce-discovery.d.ts.map +0 -1
  74. package/dist/checks/commerce-discovery.js +0 -295
  75. package/dist/checks/commerce-discovery.js.map +0 -1
  76. package/dist/checks/content-negotiation.d.ts +0 -4
  77. package/dist/checks/content-negotiation.d.ts.map +0 -1
  78. package/dist/checks/content-negotiation.js +0 -253
  79. package/dist/checks/content-negotiation.js.map +0 -1
  80. package/dist/checks/crawl-efficiency.d.ts +0 -16
  81. package/dist/checks/crawl-efficiency.d.ts.map +0 -1
  82. package/dist/checks/crawl-efficiency.js +0 -186
  83. package/dist/checks/crawl-efficiency.js.map +0 -1
  84. package/dist/checks/frontmatter.d.ts +0 -34
  85. package/dist/checks/frontmatter.d.ts.map +0 -1
  86. package/dist/checks/frontmatter.js +0 -100
  87. package/dist/checks/frontmatter.js.map +0 -1
  88. package/dist/checks/html-rendering.d.ts +0 -21
  89. package/dist/checks/html-rendering.d.ts.map +0 -1
  90. package/dist/checks/html-rendering.js +0 -221
  91. package/dist/checks/html-rendering.js.map +0 -1
  92. package/dist/checks/html-utils.d.ts +0 -66
  93. package/dist/checks/html-utils.d.ts.map +0 -1
  94. package/dist/checks/html-utils.js +0 -139
  95. package/dist/checks/html-utils.js.map +0 -1
  96. package/dist/checks/http-headers.d.ts +0 -11
  97. package/dist/checks/http-headers.d.ts.map +0 -1
  98. package/dist/checks/http-headers.js +0 -249
  99. package/dist/checks/http-headers.js.map +0 -1
  100. package/dist/checks/http-hygiene.d.ts +0 -26
  101. package/dist/checks/http-hygiene.d.ts.map +0 -1
  102. package/dist/checks/http-hygiene.js +0 -257
  103. package/dist/checks/http-hygiene.js.map +0 -1
  104. package/dist/checks/index.d.ts +0 -3
  105. package/dist/checks/index.d.ts.map +0 -1
  106. package/dist/checks/index.js +0 -55
  107. package/dist/checks/index.js.map +0 -1
  108. package/dist/checks/llms-txt.d.ts +0 -19
  109. package/dist/checks/llms-txt.d.ts.map +0 -1
  110. package/dist/checks/llms-txt.js +0 -281
  111. package/dist/checks/llms-txt.js.map +0 -1
  112. package/dist/checks/mcp-discovery.d.ts +0 -30
  113. package/dist/checks/mcp-discovery.d.ts.map +0 -1
  114. package/dist/checks/mcp-discovery.js +0 -523
  115. package/dist/checks/mcp-discovery.js.map +0 -1
  116. package/dist/checks/meta-tags.d.ts +0 -17
  117. package/dist/checks/meta-tags.d.ts.map +0 -1
  118. package/dist/checks/meta-tags.js +0 -188
  119. package/dist/checks/meta-tags.js.map +0 -1
  120. package/dist/checks/robots-parser.d.ts +0 -110
  121. package/dist/checks/robots-parser.d.ts.map +0 -1
  122. package/dist/checks/robots-parser.js +0 -277
  123. package/dist/checks/robots-parser.js.map +0 -1
  124. package/dist/checks/robots-txt.d.ts +0 -6
  125. package/dist/checks/robots-txt.d.ts.map +0 -1
  126. package/dist/checks/robots-txt.js +0 -367
  127. package/dist/checks/robots-txt.js.map +0 -1
  128. package/dist/checks/rsl.d.ts +0 -4
  129. package/dist/checks/rsl.d.ts.map +0 -1
  130. package/dist/checks/rsl.js +0 -242
  131. package/dist/checks/rsl.js.map +0 -1
  132. package/dist/checks/security-txt.d.ts +0 -4
  133. package/dist/checks/security-txt.d.ts.map +0 -1
  134. package/dist/checks/security-txt.js +0 -81
  135. package/dist/checks/security-txt.js.map +0 -1
  136. package/dist/checks/seo-basics.d.ts +0 -13
  137. package/dist/checks/seo-basics.d.ts.map +0 -1
  138. package/dist/checks/seo-basics.js +0 -221
  139. package/dist/checks/seo-basics.js.map +0 -1
  140. package/dist/checks/sitemap.d.ts +0 -12
  141. package/dist/checks/sitemap.d.ts.map +0 -1
  142. package/dist/checks/sitemap.js +0 -240
  143. package/dist/checks/sitemap.js.map +0 -1
  144. package/dist/checks/structured-data.d.ts +0 -4
  145. package/dist/checks/structured-data.d.ts.map +0 -1
  146. package/dist/checks/structured-data.js +0 -408
  147. package/dist/checks/structured-data.js.map +0 -1
  148. package/dist/checks/structured-fields.d.ts +0 -46
  149. package/dist/checks/structured-fields.d.ts.map +0 -1
  150. package/dist/checks/structured-fields.js +0 -112
  151. package/dist/checks/structured-fields.js.map +0 -1
  152. package/dist/checks/surface.d.ts +0 -59
  153. package/dist/checks/surface.d.ts.map +0 -1
  154. package/dist/checks/surface.js +0 -106
  155. package/dist/checks/surface.js.map +0 -1
  156. package/dist/checks/tls-https.d.ts +0 -13
  157. package/dist/checks/tls-https.d.ts.map +0 -1
  158. package/dist/checks/tls-https.js +0 -163
  159. package/dist/checks/tls-https.js.map +0 -1
  160. package/dist/checks/usage-policy.d.ts +0 -53
  161. package/dist/checks/usage-policy.d.ts.map +0 -1
  162. package/dist/checks/usage-policy.js +0 -339
  163. package/dist/checks/usage-policy.js.map +0 -1
  164. package/dist/checks/utils.d.ts +0 -40
  165. package/dist/checks/utils.d.ts.map +0 -1
  166. package/dist/checks/utils.js +0 -74
  167. package/dist/checks/utils.js.map +0 -1
  168. package/dist/checks/waf.d.ts +0 -75
  169. package/dist/checks/waf.d.ts.map +0 -1
  170. package/dist/checks/waf.js +0 -203
  171. package/dist/checks/waf.js.map +0 -1
  172. package/dist/checks/webmcp.d.ts +0 -55
  173. package/dist/checks/webmcp.d.ts.map +0 -1
  174. package/dist/checks/webmcp.js +0 -209
  175. package/dist/checks/webmcp.js.map +0 -1
  176. package/dist/checks/well-known.d.ts +0 -38
  177. package/dist/checks/well-known.d.ts.map +0 -1
  178. package/dist/checks/well-known.js +0 -202
  179. package/dist/checks/well-known.js.map +0 -1
  180. package/dist/fetcher.d.ts +0 -15
  181. package/dist/fetcher.d.ts.map +0 -1
  182. package/dist/fetcher.js +0 -127
  183. package/dist/fetcher.js.map +0 -1
  184. package/dist/guide-urls.d.ts +0 -2
  185. package/dist/guide-urls.d.ts.map +0 -1
  186. package/dist/guide-urls.js +0 -5
  187. package/dist/guide-urls.js.map +0 -1
  188. package/docs/roadmap.md +0 -367
@@ -1,249 +0,0 @@
1
- import { SECURITY_HEADERS } from '../constants.js';
2
- import { guideUrl } from '../guide-urls.js';
3
- import { buildResult } from './utils.js';
4
- /** Parse an RFC 5988 Link header into structured entries. */
5
- export function parseLinkHeader(header) {
6
- if (!header)
7
- return [];
8
- const entries = [];
9
- const parts = splitLinkHeader(header);
10
- for (const part of parts) {
11
- const trimmed = part.trim();
12
- if (!trimmed)
13
- continue;
14
- const urlMatch = trimmed.match(/^<([^>]*)>/);
15
- if (!urlMatch)
16
- continue;
17
- const url = urlMatch[1];
18
- const rest = trimmed.slice(urlMatch[0].length);
19
- const params = {};
20
- const paramRegex = /;\s*([^=\s]+)\s*=\s*(?:"([^"]*)"|([^\s;,]*))/g;
21
- let match;
22
- while ((match = paramRegex.exec(rest)) !== null) {
23
- params[match[1].toLowerCase()] = match[2] ?? match[3];
24
- }
25
- entries.push({ url, params });
26
- }
27
- return entries;
28
- }
29
- /**
30
- * Report the discovery relations a site advertises beyond llms.txt and the
31
- * Agent Card. Each one saves an agent a round of path guessing, and several
32
- * point at resources no amount of guessing would find.
33
- */
34
- function reportDiscoveryRelations(links, headers, findings) {
35
- const present = [];
36
- const missing = [];
37
- for (const { rel, label, note } of DISCOVERY_RELATIONS) {
38
- const found = links.some((l) => (l.params['rel'] ?? '').split(/\s+/).includes(rel));
39
- if (found)
40
- present.push(label);
41
- else
42
- missing.push({ label, note });
43
- }
44
- const markdownAlternate = links.some((l) => (l.params['rel'] ?? '').split(/\s+/).includes('alternate') && (l.params['type'] ?? '').includes('text/markdown'));
45
- if (markdownAlternate)
46
- present.push('alternate (text/markdown)');
47
- if (headers['x-llms-txt'] !== undefined) {
48
- findings.push({
49
- status: 'pass',
50
- message: 'X-Llms-Txt header advertises the llms.txt location',
51
- detail: headers['x-llms-txt'],
52
- });
53
- }
54
- if (present.length > 0) {
55
- findings.push({
56
- status: 'pass',
57
- message: `${present.length} additional discovery relation(s) advertised: ${present.join(', ')}`,
58
- });
59
- }
60
- if (missing.length === DISCOVERY_RELATIONS.length && !markdownAlternate) {
61
- findings.push({
62
- status: 'warn',
63
- message: 'No machine-readable discovery relations beyond llms.txt and the Agent Card',
64
- detail: DISCOVERY_RELATIONS.map((r) => `${r.label} — ${r.note}`).join('\n'),
65
- hint: 'Advertise what you publish with Link relations so agents stop guessing paths. Add the ones that apply, ' +
66
- 'for example: Link: </llms.txt>; rel="describedby", </.well-known/api-catalog>; rel="api-catalog". ' +
67
- 'Informational in 3.x: this does not affect your score.',
68
- learnMoreUrl: guideUrl(meta.id, 'discovery-relations'),
69
- });
70
- }
71
- }
72
- /** Split a Link header value by commas, respecting angle brackets. */
73
- function splitLinkHeader(header) {
74
- const parts = [];
75
- let current = '';
76
- let inAngle = false;
77
- let inQuote = false;
78
- for (let i = 0; i < header.length; i++) {
79
- const ch = header[i];
80
- if (ch === '"' && !inAngle) {
81
- inQuote = !inQuote;
82
- current += ch;
83
- }
84
- else if (ch === '<' && !inQuote) {
85
- inAngle = true;
86
- current += ch;
87
- }
88
- else if (ch === '>' && !inQuote) {
89
- inAngle = false;
90
- current += ch;
91
- }
92
- else if (ch === ',' && !inAngle && !inQuote) {
93
- parts.push(current);
94
- current = '';
95
- }
96
- else {
97
- current += ch;
98
- }
99
- }
100
- if (current.trim()) {
101
- parts.push(current);
102
- }
103
- return parts;
104
- }
105
- export const meta = {
106
- id: 'http-headers',
107
- name: 'HTTP Headers',
108
- description: 'Checks security headers, AI discovery Link headers, and CORS',
109
- category: 'discovery',
110
- };
111
- /**
112
- * Link relations that tell an agent where a site's machine-readable resources
113
- * live. Discovery by link beats discovery by guessing: an agent that has to try
114
- * known filenames finds only the ones it already knows to look for.
115
- *
116
- * Reported, never required — several of these relations come from drafts, and
117
- * a site that publishes none of them is not doing anything wrong.
118
- */
119
- const DISCOVERY_RELATIONS = [
120
- {
121
- rel: 'describedby',
122
- label: 'describedby',
123
- note: 'llms.txt v2 uses this relation to point a page at the llms.txt that covers it.',
124
- },
125
- { rel: 'api-catalog', label: 'api-catalog', note: 'RFC 9727: the catalog of APIs this publisher offers.' },
126
- { rel: 'service-desc', label: 'service-desc', note: 'RFC 8631: a machine-readable API description.' },
127
- { rel: 'service-doc', label: 'service-doc', note: 'RFC 8631: human documentation for the API.' },
128
- { rel: 'ai-catalog', label: 'ai-catalog', note: 'Draft: the AI catalog listing agent cards and MCP server cards.' },
129
- { rel: 'c2pa-manifest', label: 'c2pa-manifest', note: 'C2PA 2.4: content provenance for media on the page.' },
130
- { rel: 'license', label: 'license', note: 'RSL and other machine-readable licensing terms.' },
131
- ];
132
- export default async function check(ctx) {
133
- const start = performance.now();
134
- const findings = [];
135
- let score = 100;
136
- const headers = ctx.headers;
137
- if (!headers || Object.keys(headers).length === 0) {
138
- findings.push({ status: 'fail', message: 'Could not fetch homepage headers' });
139
- return buildResult(meta, 0, findings, start);
140
- }
141
- let securityCount = 0;
142
- for (const header of SECURITY_HEADERS) {
143
- if (headers[header.name]) {
144
- securityCount++;
145
- }
146
- else if (header.critical) {
147
- findings.push({
148
- status: 'fail',
149
- message: `Missing critical header: ${header.label}`,
150
- hint: `Add the ${header.label} response header to your server configuration. This is a critical security header.`,
151
- learnMoreUrl: guideUrl(meta.id, 'missing-critical-header'),
152
- });
153
- score -= 10;
154
- }
155
- }
156
- if (securityCount === SECURITY_HEADERS.length) {
157
- findings.push({ status: 'pass', message: `All ${SECURITY_HEADERS.length} security headers present` });
158
- }
159
- else if (securityCount >= 4) {
160
- findings.push({ status: 'pass', message: `${securityCount}/${SECURITY_HEADERS.length} security headers present` });
161
- }
162
- else {
163
- findings.push({
164
- status: 'warn',
165
- message: `Only ${securityCount}/${SECURITY_HEADERS.length} security headers present`,
166
- hint: 'Add security headers like Strict-Transport-Security, X-Content-Type-Options, X-Frame-Options, and Referrer-Policy to your server response.',
167
- learnMoreUrl: guideUrl(meta.id, 'low-security-headers'),
168
- });
169
- score -= 5;
170
- }
171
- const linkHeader = headers['link'] ?? '';
172
- const links = parseLinkHeader(linkHeader);
173
- const hasLlmsLink = links.some((l) => /llms\.txt/i.test(l.url));
174
- // A2A moved the card to agent-card.json in v0.3.0; both paths count as a
175
- // discovery link so a site that upgraded is not marked down for it.
176
- const hasAgentLink = links.some((l) => /agent(-card)?\.json/i.test(l.url));
177
- if (hasLlmsLink && hasAgentLink) {
178
- findings.push({ status: 'pass', message: 'Link header references both llms.txt and the Agent Card' });
179
- }
180
- else if (hasLlmsLink) {
181
- findings.push({ status: 'pass', message: 'Link header references llms.txt' });
182
- findings.push({
183
- status: 'warn',
184
- message: 'Link header does not reference the Agent Card',
185
- hint: 'Add the Agent Card to your Link header: Link: </.well-known/agent-card.json>; rel="alternate"; type="application/json"',
186
- learnMoreUrl: guideUrl(meta.id, 'missing-agent-link'),
187
- });
188
- score -= 5;
189
- }
190
- else if (hasAgentLink) {
191
- findings.push({ status: 'pass', message: 'Link header references the Agent Card' });
192
- findings.push({
193
- status: 'warn',
194
- message: 'Link header does not reference llms.txt',
195
- hint: 'Add llms.txt to your Link header: Link: </llms.txt>; rel="alternate"; type="text/plain"',
196
- learnMoreUrl: guideUrl(meta.id, 'missing-llms-link'),
197
- });
198
- score -= 5;
199
- }
200
- else if (linkHeader) {
201
- findings.push({
202
- status: 'warn',
203
- message: 'Link header present but does not reference AI discovery files',
204
- hint: 'Add AI discovery entries to your Link header: Link: </llms.txt>; rel="alternate"; type="text/plain", </.well-known/agent-card.json>; rel="alternate"; type="application/json"',
205
- learnMoreUrl: guideUrl(meta.id, 'no-ai-discovery'),
206
- });
207
- score -= 15;
208
- }
209
- else {
210
- findings.push({
211
- status: 'warn',
212
- message: 'No Link header for AI discovery (llms.txt, Agent Card)',
213
- hint: 'Add a Link response header pointing to your AI discovery files: Link: </llms.txt>; rel="alternate"; type="text/plain", </.well-known/agent-card.json>; rel="alternate"; type="application/json"',
214
- learnMoreUrl: guideUrl(meta.id, 'no-link-header'),
215
- });
216
- score -= 15;
217
- }
218
- // Probe the registered path first, falling back to the pre-0.3 one, so CORS
219
- // is evaluated against whichever card the site actually serves.
220
- let wellKnownRes = await ctx.fetch(`${ctx.url}/.well-known/agent-card.json`);
221
- if (!wellKnownRes.ok)
222
- wellKnownRes = await ctx.fetch(`${ctx.url}/.well-known/agent.json`);
223
- if (wellKnownRes.ok) {
224
- const cors = wellKnownRes.headers['access-control-allow-origin'];
225
- if (cors) {
226
- findings.push({ status: 'pass', message: 'CORS enabled on .well-known resources' });
227
- }
228
- else {
229
- findings.push({
230
- status: 'warn',
231
- message: 'No CORS headers on .well-known resources',
232
- hint: 'Add Access-Control-Allow-Origin: * to responses from /.well-known/* so AI agents from other domains can fetch your discovery files.',
233
- learnMoreUrl: guideUrl(meta.id, 'no-cors'),
234
- });
235
- score -= 10;
236
- }
237
- }
238
- const llmsRes = await ctx.fetch(`${ctx.url}/llms.txt`);
239
- if (llmsRes.ok && llmsRes.headers['x-robots-tag']?.includes('noindex')) {
240
- findings.push({
241
- status: 'pass',
242
- message: 'X-Robots-Tag: noindex on /llms.txt (prevents search indexing of raw text)',
243
- });
244
- }
245
- // Informational in 3.x: new findings inside a weighted check must not deduct.
246
- reportDiscoveryRelations(links, headers, findings);
247
- return buildResult(meta, score, findings, start);
248
- }
249
- //# sourceMappingURL=http-headers.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"http-headers.js","sourceRoot":"","sources":["../../src/checks/http-headers.ts"],"names":[],"mappings":"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"}
@@ -1,26 +0,0 @@
1
- import type { CheckContext, CheckResult, CheckMeta } from '../types.js';
2
- /**
3
- * "http-hygiene" — does this site answer honestly at the protocol level?
4
- *
5
- * An agent has no eyes. It decides what happened from the status code, and it
6
- * has no way to notice that the 200 it just received is a "page not found"
7
- * screen. A human seeing that page moves on; an agent stores the apology as the
8
- * answer, or retries forever, or reports it to the user as content.
9
- *
10
- * The failures here are unglamorous and common:
11
- *
12
- * - **Soft 404s.** A missing page answering `200 OK`, or redirecting to the
13
- * homepage. Every "not found" an agent cannot detect becomes a fabricated
14
- * fact or a wasted retry.
15
- * - **Rate limits without `Retry-After`.** A `429` with no header tells a
16
- * well-behaved crawler nothing about when to come back, so it either gives up
17
- * or hammers. The header is how backoff is negotiated.
18
- * - **Long redirect chains.** Each hop is a round trip an agent pays for, and
19
- * some clients cap their hops well below what browsers allow.
20
- * - **`HEAD` refused.** A cheap existence check turned into a full download.
21
- * - **Missing charset**, which turns non-ASCII text into replacement characters
22
- * in whatever the agent quotes.
23
- */
24
- export declare const meta: CheckMeta;
25
- export default function check(ctx: CheckContext): Promise<CheckResult>;
26
- //# sourceMappingURL=http-hygiene.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"http-hygiene.d.ts","sourceRoot":"","sources":["../../src/checks/http-hygiene.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAW,MAAM,aAAa,CAAC;AAKjF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,IAAI,EAAE,SAKlB,CAAC;AAiBF,wBAA8B,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAW3E"}
@@ -1,257 +0,0 @@
1
- import { guideUrl } from '../guide-urls.js';
2
- import { buildResult } from './utils.js';
3
- import { extractVisibleText, getTagAttribute } from './html-utils.js';
4
- import { classifyResponse } from './waf.js';
5
- /**
6
- * "http-hygiene" — does this site answer honestly at the protocol level?
7
- *
8
- * An agent has no eyes. It decides what happened from the status code, and it
9
- * has no way to notice that the 200 it just received is a "page not found"
10
- * screen. A human seeing that page moves on; an agent stores the apology as the
11
- * answer, or retries forever, or reports it to the user as content.
12
- *
13
- * The failures here are unglamorous and common:
14
- *
15
- * - **Soft 404s.** A missing page answering `200 OK`, or redirecting to the
16
- * homepage. Every "not found" an agent cannot detect becomes a fabricated
17
- * fact or a wasted retry.
18
- * - **Rate limits without `Retry-After`.** A `429` with no header tells a
19
- * well-behaved crawler nothing about when to come back, so it either gives up
20
- * or hammers. The header is how backoff is negotiated.
21
- * - **Long redirect chains.** Each hop is a round trip an agent pays for, and
22
- * some clients cap their hops well below what browsers allow.
23
- * - **`HEAD` refused.** A cheap existence check turned into a full download.
24
- * - **Missing charset**, which turns non-ASCII text into replacement characters
25
- * in whatever the agent quotes.
26
- */
27
- export const meta = {
28
- id: 'http-hygiene',
29
- name: 'HTTP Hygiene',
30
- description: 'Checks status-code honesty, redirect depth, rate-limit headers and content typing',
31
- category: 'access',
32
- };
33
- /** Redirect hops tolerated on the homepage before it costs an agent real time. */
34
- const MAX_REDIRECT_HOPS = 1;
35
- /** Phrases a soft-404 body uses. Matched only against short bodies, to avoid false hits on articles about 404s. */
36
- const NOT_FOUND_PHRASES = /\b(404|page not found|not found|no longer exists|doesn'?t exist|does not exist|couldn'?t find|could not find)\b/i;
37
- /** Body shorter than this is treated as an error page rather than content. */
38
- const SHORT_BODY_CHARS = 600;
39
- /** Build a path that cannot plausibly exist, so a 200 proves the site invents pages. */
40
- function improbablePath() {
41
- return `/ax-audit-probe-${Math.random().toString(36).slice(2, 10)}`;
42
- }
43
- export default async function check(ctx) {
44
- const start = performance.now();
45
- const findings = [];
46
- let score = 100;
47
- score = await checkSoft404(ctx, findings, score);
48
- score = await checkRedirects(ctx, findings, score);
49
- score = await checkHeadSupport(ctx, findings, score);
50
- score = checkContentTyping(ctx, findings, score);
51
- return buildResult(meta, score, findings, start);
52
- }
53
- /**
54
- * Request a path that cannot exist and insist the server say so. A `200`, a
55
- * redirect to the homepage, or an error page dressed as content all break the
56
- * one signal an agent can rely on.
57
- */
58
- async function checkSoft404(ctx, findings, score) {
59
- const path = improbablePath();
60
- const res = await ctx.fetch(`${ctx.url}${path}`, { redirect: 'manual' });
61
- const cls = classifyResponse(res);
62
- if (cls.kind === 'challenge' || cls.kind === 'needs-signature') {
63
- findings.push({
64
- status: 'warn',
65
- message: 'Could not test 404 handling — the probe was challenged',
66
- detail: cls.evidence.join('; '),
67
- hint: 'Bot management answered a plain GET with an interstitial, so status-code honesty could not be verified from outside.',
68
- learnMoreUrl: guideUrl(meta.id, 'probe-challenged'),
69
- });
70
- return score;
71
- }
72
- if (res.status === 404 || res.status === 410) {
73
- findings.push({ status: 'pass', message: `Missing pages return ${res.status}` });
74
- return checkErrorBody(res.body, findings, score);
75
- }
76
- if (res.status >= 300 && res.status < 400) {
77
- const target = res.redirectLocation ?? '';
78
- const toRoot = target === '/' || target === ctx.url || target === `${ctx.url}/`;
79
- findings.push({
80
- status: 'warn',
81
- message: `A missing page redirects (${res.status}) instead of returning 404`,
82
- detail: `Location: ${target || '(none)'}`,
83
- hint: toRoot
84
- ? 'Redirecting every unknown URL to the homepage means an agent following a stale link believes it arrived. Return 404 or 410.'
85
- : 'A redirect on a nonexistent path hides the error. Return 404 or 410 so a client can tell the difference.',
86
- learnMoreUrl: guideUrl(meta.id, 'soft-404-redirect'),
87
- });
88
- return score - 20;
89
- }
90
- if (res.status === 200) {
91
- const text = extractVisibleText(res.body);
92
- const looksLikeError = text.length < SHORT_BODY_CHARS && NOT_FOUND_PHRASES.test(text);
93
- findings.push({
94
- status: 'fail',
95
- message: looksLikeError
96
- ? 'A "page not found" screen is served with HTTP 200'
97
- : 'A nonexistent path returns HTTP 200',
98
- detail: `${path} → 200 (${text.length} chars of visible text)`,
99
- hint: 'An agent has no way to see that this page is an apology. It stores the text as the answer, or retries a URL ' +
100
- 'that will never work. Return 404 for missing pages and 410 for removed ones.',
101
- learnMoreUrl: guideUrl(meta.id, 'soft-404'),
102
- });
103
- return score - 30;
104
- }
105
- if (res.status === 403 || res.status === 401) {
106
- findings.push({
107
- status: 'warn',
108
- message: `A nonexistent path returns ${res.status} rather than 404`,
109
- hint: 'Answering unknown paths with 403 is a defensible hardening choice, but it stops a client distinguishing "missing" from "forbidden".',
110
- learnMoreUrl: guideUrl(meta.id, 'not-found-403'),
111
- });
112
- return score - 5;
113
- }
114
- findings.push({
115
- status: 'warn',
116
- message: `A nonexistent path returns ${res.status || 'a network error'}`,
117
- hint: 'Missing pages should return 404 or 410.',
118
- learnMoreUrl: guideUrl(meta.id, 'soft-404'),
119
- });
120
- return score - 10;
121
- }
122
- /** A correct 404 can still ship an unhelpful body. */
123
- function checkErrorBody(body, findings, score) {
124
- if (body.trim().length === 0) {
125
- findings.push({
126
- status: 'warn',
127
- message: '404 responses have an empty body',
128
- hint: 'Send a short explanation and a link back into the site. An agent that hits a dead link can then recover instead of stopping.',
129
- learnMoreUrl: guideUrl(meta.id, 'empty-error-body'),
130
- });
131
- return score - 5;
132
- }
133
- return score;
134
- }
135
- /** Count redirect hops from the audited URL to the page that finally answers. */
136
- async function checkRedirects(ctx, findings, score) {
137
- let url = ctx.url;
138
- const chain = [];
139
- for (let hop = 0; hop <= 5; hop++) {
140
- const res = await ctx.fetch(url, { redirect: 'manual' });
141
- if (res.status < 300 || res.status >= 400 || !res.redirectLocation)
142
- break;
143
- let next;
144
- try {
145
- next = new URL(res.redirectLocation, url).toString();
146
- }
147
- catch {
148
- break;
149
- }
150
- chain.push(`${res.status} → ${next}`);
151
- if (next === url)
152
- break;
153
- url = next;
154
- }
155
- if (chain.length === 0) {
156
- findings.push({ status: 'pass', message: 'Homepage answers without a redirect' });
157
- return score;
158
- }
159
- if (chain.length <= MAX_REDIRECT_HOPS) {
160
- findings.push({
161
- status: 'pass',
162
- message: `Homepage answers after ${chain.length} redirect`,
163
- detail: chain.join('\n'),
164
- });
165
- return score;
166
- }
167
- findings.push({
168
- status: 'warn',
169
- message: `Homepage takes ${chain.length} redirects to answer`,
170
- detail: chain.join('\n'),
171
- hint: 'Every hop is a round trip the agent pays for, and some clients cap redirects well below a browser. ' +
172
- 'Collapse the chain: point the first URL straight at the final one.',
173
- learnMoreUrl: guideUrl(meta.id, 'redirect-chain'),
174
- });
175
- return score - 10;
176
- }
177
- /** `HEAD` is how a client checks existence without paying for the body. */
178
- async function checkHeadSupport(ctx, findings, score) {
179
- const res = await ctx.fetch(ctx.url, { method: 'HEAD' });
180
- if (res.status === 405 || res.status === 501) {
181
- findings.push({
182
- status: 'warn',
183
- message: `HEAD requests are refused (${res.status})`,
184
- hint: 'HEAD lets a client confirm a URL exists, or check Last-Modified, without downloading the page. Refusing it turns every existence check into a full transfer.',
185
- learnMoreUrl: guideUrl(meta.id, 'head-refused'),
186
- });
187
- return score - 10;
188
- }
189
- if (res.ok) {
190
- findings.push({ status: 'pass', message: 'HEAD requests are supported' });
191
- }
192
- // A rate limit on the second request of an audit is a real finding: nothing
193
- // here resembles a crawl.
194
- if (res.status === 429) {
195
- const retryAfter = res.headers['retry-after'];
196
- findings.push({
197
- status: retryAfter === undefined ? 'fail' : 'warn',
198
- message: retryAfter === undefined
199
- ? 'Rate limited with no Retry-After header'
200
- : `Rate limited after two requests (Retry-After: ${retryAfter})`,
201
- hint: retryAfter === undefined
202
- ? 'A 429 without Retry-After tells a well-behaved crawler nothing about when to return, so it either gives up or keeps hammering. Always send the header.'
203
- : 'A limit this tight will stall any crawl. Consider a higher allowance for identified AI crawlers.',
204
- learnMoreUrl: guideUrl(meta.id, 'rate-limit'),
205
- });
206
- return score - (retryAfter === undefined ? 20 : 10);
207
- }
208
- return score;
209
- }
210
- /** Character encoding and language declarations, which decide what an agent quotes. */
211
- function checkContentTyping(ctx, findings, score) {
212
- const headers = ctx.headers ?? {};
213
- const contentType = headers['content-type'] ?? '';
214
- if (contentType === '') {
215
- findings.push({
216
- status: 'warn',
217
- message: 'Homepage has no Content-Type header',
218
- hint: 'Send Content-Type: text/html; charset=utf-8 so a client does not have to guess the encoding.',
219
- learnMoreUrl: guideUrl(meta.id, 'no-content-type'),
220
- });
221
- return score - 10;
222
- }
223
- const hasCharset = /charset=/i.test(contentType);
224
- const hasMetaCharset = /<meta[^>]+charset\s*=/i.test(ctx.html ?? '');
225
- if (!hasCharset && !hasMetaCharset) {
226
- findings.push({
227
- status: 'warn',
228
- message: 'No character encoding declared in the header or the document',
229
- hint: 'Without a charset, non-ASCII text is decoded by guesswork and quoted back with replacement characters. Add charset=utf-8.',
230
- learnMoreUrl: guideUrl(meta.id, 'no-charset'),
231
- });
232
- score -= 10;
233
- }
234
- else if (!hasCharset) {
235
- findings.push({
236
- status: 'pass',
237
- message: 'Character encoding declared in the document (not in the Content-Type header)',
238
- });
239
- }
240
- else {
241
- findings.push({ status: 'pass', message: `Content-Type: ${contentType.split(';')[0]} with charset` });
242
- }
243
- // `Content-Language` and `<html lang>` should not contradict each other.
244
- const htmlLang = (getTagAttribute(ctx.html ?? '', 'html', 'lang') ?? '').toLowerCase();
245
- const contentLanguage = (headers['content-language'] ?? '').toLowerCase().split(',')[0].trim();
246
- if (htmlLang !== '' && contentLanguage !== '' && htmlLang.split('-')[0] !== contentLanguage.split('-')[0]) {
247
- findings.push({
248
- status: 'warn',
249
- message: `<html lang="${htmlLang}"> disagrees with Content-Language: ${contentLanguage}`,
250
- hint: 'Agents pick a language signal and translate or route on it. Make the two agree.',
251
- learnMoreUrl: guideUrl(meta.id, 'language-mismatch'),
252
- });
253
- score -= 5;
254
- }
255
- return score;
256
- }
257
- //# sourceMappingURL=http-hygiene.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"http-hygiene.js","sourceRoot":"","sources":["../../src/checks/http-hygiene.ts"],"names":[],"mappings":"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"}
@@ -1,3 +0,0 @@
1
- import type { CheckModule } from '../types.js';
2
- export declare const checks: CheckModule[];
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/checks/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AA6B/C,eAAO,MAAM,MAAM,EAAE,WAAW,EA2B/B,CAAC"}
@@ -1,55 +0,0 @@
1
- import llmsTxt, { meta as llmsTxtMeta } from './llms-txt.js';
2
- import robotsTxt, { meta as robotsTxtMeta } from './robots-txt.js';
3
- import agentCard, { meta as agentCardMeta } from './agent-card.js';
4
- import securityTxt, { meta as securityTxtMeta } from './security-txt.js';
5
- import structuredData, { meta as structuredDataMeta } from './structured-data.js';
6
- import metaTags, { meta as metaTagsMeta } from './meta-tags.js';
7
- import apiDiscovery, { meta as apiDiscoveryMeta } from './api-discovery.js';
8
- import httpHeaders, { meta as httpHeadersMeta } from './http-headers.js';
9
- import mcpDiscovery, { meta as mcpDiscoveryMeta } from './mcp-discovery.js';
10
- import htmlRendering, { meta as htmlRenderingMeta } from './html-rendering.js';
11
- import sitemap, { meta as sitemapMeta } from './sitemap.js';
12
- import seoBasics, { meta as seoBasicsMeta } from './seo-basics.js';
13
- import tlsHttps, { meta as tlsHttpsMeta } from './tls-https.js';
14
- import contentNegotiation, { meta as contentNegotiationMeta } from './content-negotiation.js';
15
- import rsl, { meta as rslMeta } from './rsl.js';
16
- import agentAccess, { meta as agentAccessMeta } from './agent-access.js';
17
- import crawlEfficiency, { meta as crawlEfficiencyMeta } from './crawl-efficiency.js';
18
- import aiDirectives, { meta as aiDirectivesMeta } from './ai-directives.js';
19
- import usagePolicy, { meta as usagePolicyMeta } from './usage-policy.js';
20
- import httpHygiene, { meta as httpHygieneMeta } from './http-hygiene.js';
21
- import aiCatalog, { meta as aiCatalogMeta } from './ai-catalog.js';
22
- import agentSkills, { meta as agentSkillsMeta } from './agent-skills.js';
23
- import webmcp, { meta as webmcpMeta } from './webmcp.js';
24
- import commerceDiscovery, { meta as commerceDiscoveryMeta } from './commerce-discovery.js';
25
- import authDiscovery, { meta as authDiscoveryMeta } from './auth-discovery.js';
26
- import agentOperability, { meta as agentOperabilityMeta } from './agent-operability.js';
27
- export const checks = [
28
- { run: llmsTxt, meta: llmsTxtMeta },
29
- { run: robotsTxt, meta: robotsTxtMeta },
30
- { run: agentCard, meta: agentCardMeta },
31
- { run: securityTxt, meta: securityTxtMeta },
32
- { run: structuredData, meta: structuredDataMeta },
33
- { run: metaTags, meta: metaTagsMeta },
34
- { run: apiDiscovery, meta: apiDiscoveryMeta },
35
- { run: httpHeaders, meta: httpHeadersMeta },
36
- { run: mcpDiscovery, meta: mcpDiscoveryMeta },
37
- { run: htmlRendering, meta: htmlRenderingMeta },
38
- { run: sitemap, meta: sitemapMeta },
39
- { run: seoBasics, meta: seoBasicsMeta },
40
- { run: tlsHttps, meta: tlsHttpsMeta },
41
- { run: contentNegotiation, meta: contentNegotiationMeta },
42
- { run: rsl, meta: rslMeta },
43
- { run: agentAccess, meta: agentAccessMeta },
44
- { run: crawlEfficiency, meta: crawlEfficiencyMeta },
45
- { run: aiDirectives, meta: aiDirectivesMeta },
46
- { run: usagePolicy, meta: usagePolicyMeta },
47
- { run: httpHygiene, meta: httpHygieneMeta },
48
- { run: aiCatalog, meta: aiCatalogMeta },
49
- { run: agentSkills, meta: agentSkillsMeta },
50
- { run: webmcp, meta: webmcpMeta },
51
- { run: commerceDiscovery, meta: commerceDiscoveryMeta },
52
- { run: authDiscovery, meta: authDiscoveryMeta },
53
- { run: agentOperability, meta: agentOperabilityMeta },
54
- ];
55
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/checks/index.ts"],"names":[],"mappings":"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"}