ax-audit 2.4.0 → 3.1.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 +50 -0
- package/README.md +43 -17
- package/dist/checks/agent-json.d.ts +10 -0
- package/dist/checks/agent-json.d.ts.map +1 -1
- package/dist/checks/agent-json.js +66 -2
- package/dist/checks/agent-json.js.map +1 -1
- package/dist/checks/content-negotiation.d.ts +4 -0
- package/dist/checks/content-negotiation.d.ts.map +1 -0
- package/dist/checks/content-negotiation.js +138 -0
- package/dist/checks/content-negotiation.js.map +1 -0
- package/dist/checks/html-rendering.d.ts +21 -0
- package/dist/checks/html-rendering.d.ts.map +1 -0
- package/dist/checks/html-rendering.js +204 -0
- package/dist/checks/html-rendering.js.map +1 -0
- package/dist/checks/html-utils.d.ts +37 -0
- package/dist/checks/html-utils.d.ts.map +1 -0
- package/dist/checks/html-utils.js +93 -0
- package/dist/checks/html-utils.js.map +1 -0
- package/dist/checks/http-headers.js +1 -1
- package/dist/checks/http-headers.js.map +1 -1
- package/dist/checks/index.d.ts.map +1 -1
- package/dist/checks/index.js +12 -0
- package/dist/checks/index.js.map +1 -1
- package/dist/checks/llms-txt.d.ts.map +1 -1
- package/dist/checks/llms-txt.js +17 -2
- package/dist/checks/llms-txt.js.map +1 -1
- package/dist/checks/mcp.d.ts.map +1 -1
- package/dist/checks/mcp.js +11 -2
- package/dist/checks/mcp.js.map +1 -1
- package/dist/checks/meta-tags.d.ts +13 -0
- package/dist/checks/meta-tags.d.ts.map +1 -1
- package/dist/checks/meta-tags.js +104 -24
- package/dist/checks/meta-tags.js.map +1 -1
- package/dist/checks/openapi.d.ts.map +1 -1
- package/dist/checks/openapi.js +11 -2
- package/dist/checks/openapi.js.map +1 -1
- package/dist/checks/robots-txt.js +1 -1
- package/dist/checks/security-txt.js +1 -1
- package/dist/checks/seo-basics.d.ts +13 -0
- package/dist/checks/seo-basics.d.ts.map +1 -0
- package/dist/checks/seo-basics.js +222 -0
- package/dist/checks/seo-basics.js.map +1 -0
- package/dist/checks/sitemap.d.ts +12 -0
- package/dist/checks/sitemap.d.ts.map +1 -0
- package/dist/checks/sitemap.js +241 -0
- package/dist/checks/sitemap.js.map +1 -0
- package/dist/checks/structured-data.js +1 -1
- package/dist/checks/structured-data.js.map +1 -1
- package/dist/checks/tls-https.d.ts +13 -0
- package/dist/checks/tls-https.d.ts.map +1 -0
- package/dist/checks/tls-https.js +164 -0
- package/dist/checks/tls-https.js.map +1 -0
- package/dist/checks/utils.d.ts +13 -1
- package/dist/checks/utils.d.ts.map +1 -1
- package/dist/checks/utils.js +28 -0
- package/dist/checks/utils.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/constants.d.ts +19 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +50 -10
- package/dist/constants.js.map +1 -1
- package/dist/fetcher.d.ts +2 -2
- package/dist/fetcher.d.ts.map +1 -1
- package/dist/fetcher.js +42 -9
- package/dist/fetcher.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/scorer.d.ts.map +1 -1
- package/dist/scorer.js +8 -0
- package/dist/scorer.js.map +1 -1
- package/dist/types.d.ts +10 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { guideUrl } from '../guide-urls.js';
|
|
2
|
+
import { buildResult } from './utils.js';
|
|
3
|
+
/**
|
|
4
|
+
* "sitemap" — fetch and validate the XML sitemap so AI agents and search crawlers can discover
|
|
5
|
+
* the full URL surface. Sitemaps may be referenced from `robots.txt` (`Sitemap:` directive) or
|
|
6
|
+
* served at the conventional `/sitemap.xml` path. This check covers both, validates the XML
|
|
7
|
+
* shape, and respects sitemap-index files (which point to multiple child sitemaps).
|
|
8
|
+
*
|
|
9
|
+
* Reference: https://www.sitemaps.org/protocol.html
|
|
10
|
+
*/
|
|
11
|
+
export const meta = {
|
|
12
|
+
id: 'sitemap',
|
|
13
|
+
name: 'Sitemap',
|
|
14
|
+
description: 'Checks sitemap.xml presence, structure, and freshness',
|
|
15
|
+
weight: 4,
|
|
16
|
+
};
|
|
17
|
+
const MAX_URLS_PER_SITEMAP = 50_000;
|
|
18
|
+
const MAX_BYTES_PER_SITEMAP = 50 * 1024 * 1024;
|
|
19
|
+
const STALE_DAYS = 365;
|
|
20
|
+
export default async function check(ctx) {
|
|
21
|
+
const start = performance.now();
|
|
22
|
+
const findings = [];
|
|
23
|
+
let score = 100;
|
|
24
|
+
const sitemapUrl = await locateSitemap(ctx);
|
|
25
|
+
if (!sitemapUrl) {
|
|
26
|
+
findings.push({
|
|
27
|
+
status: 'fail',
|
|
28
|
+
message: 'No sitemap found',
|
|
29
|
+
detail: 'Tried robots.txt Sitemap: directive and /sitemap.xml',
|
|
30
|
+
hint: 'Publish an XML sitemap at /sitemap.xml and reference it from robots.txt with: Sitemap: https://your-site.com/sitemap.xml',
|
|
31
|
+
learnMoreUrl: guideUrl(meta.id, 'not-found'),
|
|
32
|
+
});
|
|
33
|
+
return buildResult(meta, 0, findings, start);
|
|
34
|
+
}
|
|
35
|
+
findings.push({ status: 'pass', message: `Sitemap located: ${sitemapUrl.url}` });
|
|
36
|
+
const res = sitemapUrl.response;
|
|
37
|
+
if (res.body.length > MAX_BYTES_PER_SITEMAP) {
|
|
38
|
+
findings.push({
|
|
39
|
+
status: 'warn',
|
|
40
|
+
message: `Sitemap exceeds 50 MB (${formatBytes(res.body.length)})`,
|
|
41
|
+
hint: 'Split the sitemap into a sitemap-index referencing multiple smaller sitemaps. The sitemaps.org spec caps individual sitemaps at 50 MB.',
|
|
42
|
+
learnMoreUrl: guideUrl(meta.id, 'too-large'),
|
|
43
|
+
});
|
|
44
|
+
score -= 10;
|
|
45
|
+
}
|
|
46
|
+
if (!isXml(res.body)) {
|
|
47
|
+
findings.push({
|
|
48
|
+
status: 'fail',
|
|
49
|
+
message: 'Sitemap response does not look like XML',
|
|
50
|
+
detail: snippet(res.body),
|
|
51
|
+
hint: 'Serve the sitemap with valid XML and Content-Type: application/xml. Confirm the file starts with <?xml ...?> and contains <urlset> or <sitemapindex>.',
|
|
52
|
+
learnMoreUrl: guideUrl(meta.id, 'not-xml'),
|
|
53
|
+
});
|
|
54
|
+
return buildResult(meta, 20, findings, start);
|
|
55
|
+
}
|
|
56
|
+
const contentType = res.headers['content-type'] ?? '';
|
|
57
|
+
if (/(application|text)\/xml/i.test(contentType)) {
|
|
58
|
+
findings.push({ status: 'pass', message: `Content-Type is XML (${contentType.split(';')[0]})` });
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
findings.push({
|
|
62
|
+
status: 'warn',
|
|
63
|
+
message: `Unexpected Content-Type: ${contentType || '(missing)'}`,
|
|
64
|
+
hint: 'Serve the sitemap with Content-Type: application/xml so AI agents and search crawlers parse it correctly.',
|
|
65
|
+
learnMoreUrl: guideUrl(meta.id, 'wrong-content-type'),
|
|
66
|
+
});
|
|
67
|
+
score -= 5;
|
|
68
|
+
}
|
|
69
|
+
const isIndex = /<sitemapindex\b/i.test(res.body);
|
|
70
|
+
if (isIndex) {
|
|
71
|
+
const childRefs = [...res.body.matchAll(/<sitemap>[\s\S]*?<loc>\s*([^<]+?)\s*<\/loc>[\s\S]*?<\/sitemap>/gi)].map((m) => m[1].trim());
|
|
72
|
+
if (childRefs.length === 0) {
|
|
73
|
+
findings.push({
|
|
74
|
+
status: 'fail',
|
|
75
|
+
message: '<sitemapindex> contains no <sitemap> entries',
|
|
76
|
+
hint: 'A sitemap-index must contain at least one <sitemap><loc>...</loc></sitemap> child entry.',
|
|
77
|
+
learnMoreUrl: guideUrl(meta.id, 'empty-index'),
|
|
78
|
+
});
|
|
79
|
+
score -= 20;
|
|
80
|
+
return buildResult(meta, score, findings, start);
|
|
81
|
+
}
|
|
82
|
+
findings.push({ status: 'pass', message: `Sitemap-index references ${childRefs.length} child sitemap(s)` });
|
|
83
|
+
const sample = childRefs.slice(0, 3);
|
|
84
|
+
const reachable = [];
|
|
85
|
+
let totalUrls = 0;
|
|
86
|
+
let newestLastmod = null;
|
|
87
|
+
for (const childUrl of sample) {
|
|
88
|
+
const child = await ctx.fetch(childUrl);
|
|
89
|
+
if (!child.ok || !isXml(child.body))
|
|
90
|
+
continue;
|
|
91
|
+
reachable.push(childUrl);
|
|
92
|
+
const stats = analyzeUrlset(child.body);
|
|
93
|
+
totalUrls += stats.urlCount;
|
|
94
|
+
if (stats.newestLastmod && (!newestLastmod || stats.newestLastmod > newestLastmod)) {
|
|
95
|
+
newestLastmod = stats.newestLastmod;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (reachable.length === sample.length) {
|
|
99
|
+
findings.push({
|
|
100
|
+
status: 'pass',
|
|
101
|
+
message: `${reachable.length}/${sample.length} sample child sitemap(s) reachable`,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
findings.push({
|
|
106
|
+
status: 'warn',
|
|
107
|
+
message: `${reachable.length}/${sample.length} sample child sitemap(s) reachable`,
|
|
108
|
+
detail: 'Some referenced child sitemaps could not be fetched.',
|
|
109
|
+
hint: 'Make sure every <loc> URL inside the sitemap-index returns 200 OK and is publicly accessible.',
|
|
110
|
+
learnMoreUrl: guideUrl(meta.id, 'unreachable-children'),
|
|
111
|
+
});
|
|
112
|
+
score -= 10;
|
|
113
|
+
}
|
|
114
|
+
findings.push({
|
|
115
|
+
status: 'pass',
|
|
116
|
+
message: `Sample yielded ${totalUrls} URL(s) across ${reachable.length} child(ren)`,
|
|
117
|
+
});
|
|
118
|
+
reportLastmod(newestLastmod, findings, () => {
|
|
119
|
+
score -= 5;
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
const stats = analyzeUrlset(res.body);
|
|
124
|
+
if (stats.urlCount === 0) {
|
|
125
|
+
findings.push({
|
|
126
|
+
status: 'fail',
|
|
127
|
+
message: '<urlset> contains no <url> entries',
|
|
128
|
+
hint: 'Populate the sitemap with at least one <url><loc>...</loc></url> entry per page you want crawlers to index.',
|
|
129
|
+
learnMoreUrl: guideUrl(meta.id, 'empty-urlset'),
|
|
130
|
+
});
|
|
131
|
+
score -= 30;
|
|
132
|
+
}
|
|
133
|
+
else if (stats.urlCount > MAX_URLS_PER_SITEMAP) {
|
|
134
|
+
findings.push({
|
|
135
|
+
status: 'warn',
|
|
136
|
+
message: `Sitemap declares ${stats.urlCount} URLs (above 50,000 limit)`,
|
|
137
|
+
hint: 'Split into a sitemap-index referencing multiple sitemaps, each below 50,000 URLs.',
|
|
138
|
+
learnMoreUrl: guideUrl(meta.id, 'too-many-urls'),
|
|
139
|
+
});
|
|
140
|
+
score -= 10;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
findings.push({ status: 'pass', message: `${stats.urlCount} URL(s) declared` });
|
|
144
|
+
}
|
|
145
|
+
if (stats.urlCount > 0) {
|
|
146
|
+
const lastmodCoverage = stats.lastmodCount / stats.urlCount;
|
|
147
|
+
if (lastmodCoverage >= 0.5) {
|
|
148
|
+
findings.push({
|
|
149
|
+
status: 'pass',
|
|
150
|
+
message: `${(lastmodCoverage * 100).toFixed(0)}% of URLs have <lastmod>`,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
findings.push({
|
|
155
|
+
status: 'warn',
|
|
156
|
+
message: `Only ${(lastmodCoverage * 100).toFixed(0)}% of URLs have <lastmod>`,
|
|
157
|
+
hint: 'Add a <lastmod>YYYY-MM-DD</lastmod> child to each <url>. AI agents use lastmod to prioritize re-fetching.',
|
|
158
|
+
learnMoreUrl: guideUrl(meta.id, 'low-lastmod'),
|
|
159
|
+
});
|
|
160
|
+
score -= 5;
|
|
161
|
+
}
|
|
162
|
+
reportLastmod(stats.newestLastmod, findings, () => {
|
|
163
|
+
score -= 5;
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return buildResult(meta, score, findings, start);
|
|
168
|
+
}
|
|
169
|
+
async function locateSitemap(ctx) {
|
|
170
|
+
const robots = await ctx.fetch(`${ctx.url}/robots.txt`);
|
|
171
|
+
if (robots.ok) {
|
|
172
|
+
const declared = [...robots.body.matchAll(/^Sitemap:\s*(\S+)\s*$/gim)].map((m) => m[1]);
|
|
173
|
+
for (const url of declared) {
|
|
174
|
+
const res = await ctx.fetch(url);
|
|
175
|
+
if (res.ok)
|
|
176
|
+
return { url, response: res };
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const fallback = `${ctx.url}/sitemap.xml`;
|
|
180
|
+
const res = await ctx.fetch(fallback);
|
|
181
|
+
if (res.ok)
|
|
182
|
+
return { url: fallback, response: res };
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
function analyzeUrlset(xml) {
|
|
186
|
+
let urlCount = 0;
|
|
187
|
+
let lastmodCount = 0;
|
|
188
|
+
let newestLastmod = null;
|
|
189
|
+
for (const m of xml.matchAll(/<url\b[\s\S]*?<\/url>/gi)) {
|
|
190
|
+
urlCount++;
|
|
191
|
+
const block = m[0];
|
|
192
|
+
const lastmod = block.match(/<lastmod>\s*([^<]+?)\s*<\/lastmod>/i);
|
|
193
|
+
if (lastmod) {
|
|
194
|
+
lastmodCount++;
|
|
195
|
+
const date = new Date(lastmod[1]);
|
|
196
|
+
if (!isNaN(date.getTime())) {
|
|
197
|
+
if (!newestLastmod || date > newestLastmod) {
|
|
198
|
+
newestLastmod = date;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return { urlCount, lastmodCount, newestLastmod };
|
|
204
|
+
}
|
|
205
|
+
function reportLastmod(newest, findings, onStale) {
|
|
206
|
+
if (!newest)
|
|
207
|
+
return;
|
|
208
|
+
const ageMs = Date.now() - newest.getTime();
|
|
209
|
+
const ageDays = Math.round(ageMs / (1000 * 60 * 60 * 24));
|
|
210
|
+
if (ageDays > STALE_DAYS) {
|
|
211
|
+
findings.push({
|
|
212
|
+
status: 'warn',
|
|
213
|
+
message: `Newest <lastmod> is ${ageDays} days old`,
|
|
214
|
+
hint: 'Refresh <lastmod> on URLs that have changed. A stale sitemap signals to crawlers that nothing on the site has updated.',
|
|
215
|
+
learnMoreUrl: guideUrl(meta.id, 'stale'),
|
|
216
|
+
});
|
|
217
|
+
onStale();
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
findings.push({
|
|
221
|
+
status: 'pass',
|
|
222
|
+
message: `Newest <lastmod> is recent (${ageDays} day(s) ago)`,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function isXml(body) {
|
|
227
|
+
const head = body.slice(0, 512).trim();
|
|
228
|
+
return /^<\?xml/i.test(head) || /^<(urlset|sitemapindex)\b/i.test(head);
|
|
229
|
+
}
|
|
230
|
+
function snippet(value) {
|
|
231
|
+
const trimmed = value.trim().slice(0, 80);
|
|
232
|
+
return trimmed.replace(/\s+/g, ' ');
|
|
233
|
+
}
|
|
234
|
+
function formatBytes(n) {
|
|
235
|
+
if (n < 1024)
|
|
236
|
+
return `${n} B`;
|
|
237
|
+
if (n < 1024 * 1024)
|
|
238
|
+
return `${(n / 1024).toFixed(1)} KB`;
|
|
239
|
+
return `${(n / 1024 / 1024).toFixed(1)} MB`;
|
|
240
|
+
}
|
|
241
|
+
//# sourceMappingURL=sitemap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sitemap.js","sourceRoot":"","sources":["../../src/checks/sitemap.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"structured-data.js","sourceRoot":"","sources":["../../src/checks/structured-data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,CAAC,MAAM,IAAI,GAAc;IAC7B,EAAE,EAAE,iBAAiB;IACrB,IAAI,EAAE,iBAAiB;IACvB,WAAW,EAAE,4CAA4C;IACzD,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"structured-data.js","sourceRoot":"","sources":["../../src/checks/structured-data.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CheckContext, CheckResult, CheckMeta } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* "tls-https" — verify the site is served over HTTPS, that bare HTTP redirects to HTTPS,
|
|
4
|
+
* and that HSTS is properly configured (with `preload` + `includeSubDomains` for full
|
|
5
|
+
* coverage). Many AI agents refuse to fetch plaintext HTTP and downgrade trust on
|
|
6
|
+
* misconfigured TLS.
|
|
7
|
+
*
|
|
8
|
+
* The check intentionally avoids verifying the certificate chain — Node's `fetch` already
|
|
9
|
+
* fails on invalid certificates, so a successful HTTPS fetch is itself a positive signal.
|
|
10
|
+
*/
|
|
11
|
+
export declare const meta: CheckMeta;
|
|
12
|
+
export default function check(ctx: CheckContext): Promise<CheckResult>;
|
|
13
|
+
//# sourceMappingURL=tls-https.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tls-https.d.ts","sourceRoot":"","sources":["../../src/checks/tls-https.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAW,MAAM,aAAa,CAAC;AAGjF;;;;;;;;GAQG;AACH,eAAO,MAAM,IAAI,EAAE,SAKlB,CAAC;AAKF,wBAA8B,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAqI3E"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { guideUrl } from '../guide-urls.js';
|
|
2
|
+
import { buildResult } from './utils.js';
|
|
3
|
+
/**
|
|
4
|
+
* "tls-https" — verify the site is served over HTTPS, that bare HTTP redirects to HTTPS,
|
|
5
|
+
* and that HSTS is properly configured (with `preload` + `includeSubDomains` for full
|
|
6
|
+
* coverage). Many AI agents refuse to fetch plaintext HTTP and downgrade trust on
|
|
7
|
+
* misconfigured TLS.
|
|
8
|
+
*
|
|
9
|
+
* The check intentionally avoids verifying the certificate chain — Node's `fetch` already
|
|
10
|
+
* fails on invalid certificates, so a successful HTTPS fetch is itself a positive signal.
|
|
11
|
+
*/
|
|
12
|
+
export const meta = {
|
|
13
|
+
id: 'tls-https',
|
|
14
|
+
name: 'TLS / HTTPS',
|
|
15
|
+
description: 'Checks HTTPS, HTTP→HTTPS redirect, and HSTS configuration',
|
|
16
|
+
weight: 5,
|
|
17
|
+
};
|
|
18
|
+
const HSTS_MIN_MAX_AGE = 15_768_000;
|
|
19
|
+
const HSTS_PRELOAD_MIN_MAX_AGE = 31_536_000;
|
|
20
|
+
export default async function check(ctx) {
|
|
21
|
+
const start = performance.now();
|
|
22
|
+
const findings = [];
|
|
23
|
+
let score = 100;
|
|
24
|
+
let parsed;
|
|
25
|
+
try {
|
|
26
|
+
parsed = new URL(ctx.url);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
findings.push({
|
|
30
|
+
status: 'fail',
|
|
31
|
+
message: `Invalid URL: ${ctx.url}`,
|
|
32
|
+
hint: 'Provide a fully qualified URL including scheme (https://...).',
|
|
33
|
+
learnMoreUrl: guideUrl(meta.id, 'invalid-url'),
|
|
34
|
+
});
|
|
35
|
+
return buildResult(meta, 0, findings, start);
|
|
36
|
+
}
|
|
37
|
+
if (parsed.protocol === 'https:') {
|
|
38
|
+
findings.push({ status: 'pass', message: 'Site is served over HTTPS' });
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
findings.push({
|
|
42
|
+
status: 'fail',
|
|
43
|
+
message: `Site is served over ${parsed.protocol.replace(':', '').toUpperCase()} (not HTTPS)`,
|
|
44
|
+
hint: 'Serve the site over HTTPS. Most AI crawlers refuse plaintext HTTP and downgrade trust on insecure origins.',
|
|
45
|
+
learnMoreUrl: guideUrl(meta.id, 'no-https'),
|
|
46
|
+
});
|
|
47
|
+
score -= 50;
|
|
48
|
+
}
|
|
49
|
+
if (parsed.protocol === 'https:') {
|
|
50
|
+
const httpUrl = `http://${parsed.host}${parsed.pathname || ''}`;
|
|
51
|
+
const httpRes = await ctx.fetch(httpUrl);
|
|
52
|
+
const finalUrl = httpRes.url || '';
|
|
53
|
+
if (httpRes.ok && /^https:\/\//i.test(finalUrl)) {
|
|
54
|
+
findings.push({ status: 'pass', message: 'HTTP requests redirect to HTTPS' });
|
|
55
|
+
}
|
|
56
|
+
else if (!httpRes.ok && httpRes.status === 0) {
|
|
57
|
+
findings.push({
|
|
58
|
+
status: 'pass',
|
|
59
|
+
message: 'HTTP endpoint not reachable (HTTPS-only — acceptable)',
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
else if (httpRes.ok && /^http:\/\//i.test(finalUrl)) {
|
|
63
|
+
findings.push({
|
|
64
|
+
status: 'fail',
|
|
65
|
+
message: 'HTTP request did not redirect to HTTPS',
|
|
66
|
+
detail: `Final URL: ${finalUrl}`,
|
|
67
|
+
hint: 'Configure your server to 301-redirect every http:// request to https://. Otherwise agents may cache the insecure variant.',
|
|
68
|
+
learnMoreUrl: guideUrl(meta.id, 'no-redirect'),
|
|
69
|
+
});
|
|
70
|
+
score -= 15;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
findings.push({
|
|
74
|
+
status: 'warn',
|
|
75
|
+
message: 'Could not verify HTTP→HTTPS redirect',
|
|
76
|
+
detail: `HTTP ${httpRes.status} on ${httpUrl}`,
|
|
77
|
+
hint: 'Test manually: a request to http://your-site.com should respond with 301 → https://your-site.com.',
|
|
78
|
+
learnMoreUrl: guideUrl(meta.id, 'redirect-unknown'),
|
|
79
|
+
});
|
|
80
|
+
score -= 5;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const hsts = ctx.headers['strict-transport-security'];
|
|
84
|
+
if (!hsts) {
|
|
85
|
+
findings.push({
|
|
86
|
+
status: 'warn',
|
|
87
|
+
message: 'No Strict-Transport-Security header',
|
|
88
|
+
hint: 'Add: Strict-Transport-Security: max-age=31536000; includeSubDomains; preload. This locks browsers and many agents to HTTPS for 1 year.',
|
|
89
|
+
learnMoreUrl: guideUrl(meta.id, 'no-hsts'),
|
|
90
|
+
});
|
|
91
|
+
score -= 15;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
const maxAge = parseHstsMaxAge(hsts);
|
|
95
|
+
const includesSubDomains = /includeSubDomains/i.test(hsts);
|
|
96
|
+
const preload = /preload/i.test(hsts);
|
|
97
|
+
if (maxAge === null) {
|
|
98
|
+
findings.push({
|
|
99
|
+
status: 'warn',
|
|
100
|
+
message: 'HSTS header has no max-age directive',
|
|
101
|
+
detail: hsts,
|
|
102
|
+
hint: 'Set a numeric max-age, e.g., max-age=31536000.',
|
|
103
|
+
learnMoreUrl: guideUrl(meta.id, 'hsts-no-maxage'),
|
|
104
|
+
});
|
|
105
|
+
score -= 10;
|
|
106
|
+
}
|
|
107
|
+
else if (maxAge < HSTS_MIN_MAX_AGE) {
|
|
108
|
+
findings.push({
|
|
109
|
+
status: 'warn',
|
|
110
|
+
message: `HSTS max-age is short (${maxAge}s = ~${Math.round(maxAge / 86400)} days)`,
|
|
111
|
+
hint: `Use at least max-age=${HSTS_MIN_MAX_AGE} (~6 months); preload list submission requires max-age=${HSTS_PRELOAD_MIN_MAX_AGE} (1 year).`,
|
|
112
|
+
learnMoreUrl: guideUrl(meta.id, 'hsts-short'),
|
|
113
|
+
});
|
|
114
|
+
score -= 5;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
findings.push({ status: 'pass', message: `HSTS max-age=${maxAge}` });
|
|
118
|
+
}
|
|
119
|
+
if (includesSubDomains) {
|
|
120
|
+
findings.push({ status: 'pass', message: 'HSTS includes subdomains' });
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
findings.push({
|
|
124
|
+
status: 'warn',
|
|
125
|
+
message: 'HSTS does not include subdomains',
|
|
126
|
+
hint: 'Add includeSubDomains to apply HSTS across api., docs., etc. Required for preload list submission.',
|
|
127
|
+
learnMoreUrl: guideUrl(meta.id, 'hsts-no-subdomains'),
|
|
128
|
+
});
|
|
129
|
+
score -= 5;
|
|
130
|
+
}
|
|
131
|
+
if (preload) {
|
|
132
|
+
if (maxAge !== null && maxAge >= HSTS_PRELOAD_MIN_MAX_AGE && includesSubDomains) {
|
|
133
|
+
findings.push({ status: 'pass', message: 'HSTS preload-eligible' });
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
findings.push({
|
|
137
|
+
status: 'warn',
|
|
138
|
+
message: 'HSTS has preload directive but does not satisfy preload-list requirements',
|
|
139
|
+
hint: `Preload requires max-age >= ${HSTS_PRELOAD_MIN_MAX_AGE} and includeSubDomains. See https://hstspreload.org.`,
|
|
140
|
+
learnMoreUrl: guideUrl(meta.id, 'hsts-preload-invalid'),
|
|
141
|
+
});
|
|
142
|
+
score -= 5;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
findings.push({
|
|
147
|
+
status: 'warn',
|
|
148
|
+
message: 'HSTS lacks the preload directive',
|
|
149
|
+
hint: 'Add preload (and ensure max-age >= 31536000 + includeSubDomains) and submit the domain at https://hstspreload.org for browser-built-in HTTPS enforcement.',
|
|
150
|
+
learnMoreUrl: guideUrl(meta.id, 'hsts-no-preload'),
|
|
151
|
+
});
|
|
152
|
+
score -= 3;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return buildResult(meta, score, findings, start);
|
|
156
|
+
}
|
|
157
|
+
function parseHstsMaxAge(value) {
|
|
158
|
+
const m = value.match(/max-age\s*=\s*"?(\d+)"?/i);
|
|
159
|
+
if (!m)
|
|
160
|
+
return null;
|
|
161
|
+
const n = Number(m[1]);
|
|
162
|
+
return Number.isFinite(n) ? n : null;
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=tls-https.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tls-https.js","sourceRoot":"","sources":["../../src/checks/tls-https.ts"],"names":[],"mappings":"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"}
|
package/dist/checks/utils.d.ts
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
import type { CheckMeta, CheckResult, Finding } from '../types.js';
|
|
1
|
+
import type { CheckMeta, CheckResult, FetchResponse, Finding } from '../types.js';
|
|
2
2
|
export declare function clampScore(score: number): number;
|
|
3
3
|
export declare function buildResult(meta: CheckMeta, score: number, findings: Finding[], start: number): CheckResult;
|
|
4
|
+
/**
|
|
5
|
+
* Validate the `Content-Type` of a fetched resource against a list of acceptable MIME types.
|
|
6
|
+
*
|
|
7
|
+
* Returns:
|
|
8
|
+
* - `null` when the content type is acceptable (no finding to add)
|
|
9
|
+
* - a `Finding` describing the mismatch otherwise (caller decides whether to apply a score penalty)
|
|
10
|
+
*/
|
|
11
|
+
export declare function checkContentType(res: FetchResponse, expected: string[], context: {
|
|
12
|
+
checkId: string;
|
|
13
|
+
resourceLabel: string;
|
|
14
|
+
anchor: string;
|
|
15
|
+
}): Finding | null;
|
|
4
16
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/checks/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/checks/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAElF,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW,CAS3G;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClE,OAAO,GAAG,IAAI,CAkBhB"}
|
package/dist/checks/utils.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { guideUrl } from '../guide-urls.js';
|
|
1
2
|
export function clampScore(score) {
|
|
2
3
|
return Math.max(0, Math.min(100, score));
|
|
3
4
|
}
|
|
@@ -11,4 +12,31 @@ export function buildResult(meta, score, findings, start) {
|
|
|
11
12
|
duration: Math.round(performance.now() - start),
|
|
12
13
|
};
|
|
13
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Validate the `Content-Type` of a fetched resource against a list of acceptable MIME types.
|
|
17
|
+
*
|
|
18
|
+
* Returns:
|
|
19
|
+
* - `null` when the content type is acceptable (no finding to add)
|
|
20
|
+
* - a `Finding` describing the mismatch otherwise (caller decides whether to apply a score penalty)
|
|
21
|
+
*/
|
|
22
|
+
export function checkContentType(res, expected, context) {
|
|
23
|
+
const ct = (res.headers['content-type'] ?? '').toLowerCase();
|
|
24
|
+
if (!ct) {
|
|
25
|
+
return {
|
|
26
|
+
status: 'warn',
|
|
27
|
+
message: `${context.resourceLabel} has no Content-Type header`,
|
|
28
|
+
hint: `Serve ${context.resourceLabel} with one of: ${expected.join(', ')}.`,
|
|
29
|
+
learnMoreUrl: guideUrl(context.checkId, context.anchor),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (expected.some((mime) => ct.includes(mime)))
|
|
33
|
+
return null;
|
|
34
|
+
return {
|
|
35
|
+
status: 'warn',
|
|
36
|
+
message: `${context.resourceLabel} Content-Type is "${ct.split(';')[0]}"`,
|
|
37
|
+
detail: `Expected one of: ${expected.join(', ')}`,
|
|
38
|
+
hint: `Configure your server to serve ${context.resourceLabel} as ${expected[0]} so AI agents parse it correctly.`,
|
|
39
|
+
learnMoreUrl: guideUrl(context.checkId, context.anchor),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
14
42
|
//# sourceMappingURL=utils.js.map
|
package/dist/checks/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/checks/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/checks/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAe,EAAE,KAAa,EAAE,QAAmB,EAAE,KAAa;IAC5F,OAAO;QACL,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,KAAK,EAAE,UAAU,CAAC,KAAK,CAAC;QACxB,QAAQ;QACR,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;KAChD,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAC9B,GAAkB,EAClB,QAAkB,EAClB,OAAmE;IAEnE,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IAC7D,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,OAAO;YACL,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,GAAG,OAAO,CAAC,aAAa,6BAA6B;YAC9D,IAAI,EAAE,SAAS,OAAO,CAAC,aAAa,iBAAiB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;YAC3E,YAAY,EAAE,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC;SACxD,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5D,OAAO;QACL,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,GAAG,OAAO,CAAC,aAAa,qBAAqB,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG;QACzE,MAAM,EAAE,oBAAoB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QACjD,IAAI,EAAE,kCAAkC,OAAO,CAAC,aAAa,OAAO,QAAQ,CAAC,CAAC,CAAC,mCAAmC;QAClH,YAAY,EAAE,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC;KACxD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { CheckContext, CheckResult, CheckMeta } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* "well-known-ai" — emerging AI-specific discovery files that don't have a settled spec yet
|
|
4
|
+
* but are already published by some sites and read by some agents. Each file present is a
|
|
5
|
+
* positive signal (bonus); none of them are individually required, so a site that publishes
|
|
6
|
+
* just one or two should not be punished. The score reflects coverage of this small bundle.
|
|
7
|
+
*
|
|
8
|
+
* Files probed:
|
|
9
|
+
* - `/.well-known/ai.txt` (Spawning AI — opt-in/opt-out for AI training)
|
|
10
|
+
* - `/.well-known/genai.txt` (proposed — generative AI policy)
|
|
11
|
+
* - `/ai-plugin.json` and `/.well-known/ai-plugin.json` (legacy ChatGPT plugin manifest)
|
|
12
|
+
* - `/agents.json` (Wildcard / OpenAgents — emerging agent capability manifest)
|
|
13
|
+
* - `/.well-known/nlweb.json` (Microsoft NLWeb — natural-language site interface)
|
|
14
|
+
*/
|
|
15
|
+
export declare const meta: CheckMeta;
|
|
16
|
+
export default function check(ctx: CheckContext): Promise<CheckResult>;
|
|
17
|
+
//# sourceMappingURL=well-known-ai.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"well-known-ai.d.ts","sourceRoot":"","sources":["../../src/checks/well-known-ai.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAA0B,MAAM,aAAa,CAAC;AAGhG;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,IAAI,EAAE,SAKlB,CAAC;AAmEF,wBAA8B,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CA+C3E"}
|