ax-audit 3.1.0 → 4.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.
- package/CHANGELOG.md +198 -0
- package/LICENSE +1 -1
- package/README.md +89 -231
- package/dist/baseline.d.ts +2 -0
- package/dist/baseline.d.ts.map +1 -1
- package/dist/baseline.js +42 -4
- package/dist/baseline.js.map +1 -1
- package/dist/check-ids.d.ts +19 -0
- package/dist/check-ids.d.ts.map +1 -0
- package/dist/check-ids.js +53 -0
- package/dist/check-ids.js.map +1 -0
- package/dist/checks/agent-access.d.ts +33 -0
- package/dist/checks/agent-access.d.ts.map +1 -0
- package/dist/checks/agent-access.js +256 -0
- package/dist/checks/agent-access.js.map +1 -0
- package/dist/checks/agent-card.d.ts +37 -0
- package/dist/checks/agent-card.d.ts.map +1 -0
- package/dist/checks/agent-card.js +352 -0
- package/dist/checks/agent-card.js.map +1 -0
- package/dist/checks/agent-operability.d.ts +66 -0
- package/dist/checks/agent-operability.d.ts.map +1 -0
- package/dist/checks/agent-operability.js +383 -0
- package/dist/checks/agent-operability.js.map +1 -0
- package/dist/checks/agent-skills.d.ts +24 -0
- package/dist/checks/agent-skills.d.ts.map +1 -0
- package/dist/checks/agent-skills.js +316 -0
- package/dist/checks/agent-skills.js.map +1 -0
- package/dist/checks/ai-catalog.d.ts +28 -0
- package/dist/checks/ai-catalog.d.ts.map +1 -0
- package/dist/checks/ai-catalog.js +254 -0
- package/dist/checks/ai-catalog.js.map +1 -0
- package/dist/checks/ai-directives.d.ts +57 -0
- package/dist/checks/ai-directives.d.ts.map +1 -0
- package/dist/checks/ai-directives.js +263 -0
- package/dist/checks/ai-directives.js.map +1 -0
- package/dist/checks/api-discovery.d.ts +26 -0
- package/dist/checks/api-discovery.d.ts.map +1 -0
- package/dist/checks/api-discovery.js +432 -0
- package/dist/checks/api-discovery.js.map +1 -0
- package/dist/checks/auth-discovery.d.ts +28 -0
- package/dist/checks/auth-discovery.d.ts.map +1 -0
- package/dist/checks/auth-discovery.js +213 -0
- package/dist/checks/auth-discovery.js.map +1 -0
- package/dist/checks/commerce-discovery.d.ts +40 -0
- package/dist/checks/commerce-discovery.d.ts.map +1 -0
- package/dist/checks/commerce-discovery.js +295 -0
- package/dist/checks/commerce-discovery.js.map +1 -0
- package/dist/checks/content-negotiation.d.ts.map +1 -1
- package/dist/checks/content-negotiation.js +135 -20
- package/dist/checks/content-negotiation.js.map +1 -1
- package/dist/checks/crawl-efficiency.d.ts +16 -0
- package/dist/checks/crawl-efficiency.d.ts.map +1 -0
- package/dist/checks/crawl-efficiency.js +186 -0
- package/dist/checks/crawl-efficiency.js.map +1 -0
- package/dist/checks/frontmatter.d.ts +34 -0
- package/dist/checks/frontmatter.d.ts.map +1 -0
- package/dist/checks/frontmatter.js +100 -0
- package/dist/checks/frontmatter.js.map +1 -0
- package/dist/checks/html-rendering.d.ts.map +1 -1
- package/dist/checks/html-rendering.js +0 -1
- package/dist/checks/html-rendering.js.map +1 -1
- package/dist/checks/html-utils.d.ts +10 -0
- package/dist/checks/html-utils.d.ts.map +1 -1
- package/dist/checks/html-utils.js +19 -0
- package/dist/checks/html-utils.js.map +1 -1
- package/dist/checks/http-headers.d.ts.map +1 -1
- package/dist/checks/http-headers.js +82 -10
- package/dist/checks/http-headers.js.map +1 -1
- package/dist/checks/http-hygiene.d.ts +26 -0
- package/dist/checks/http-hygiene.d.ts.map +1 -0
- package/dist/checks/http-hygiene.js +257 -0
- package/dist/checks/http-hygiene.js.map +1 -0
- package/dist/checks/index.d.ts.map +1 -1
- package/dist/checks/index.js +30 -8
- package/dist/checks/index.js.map +1 -1
- package/dist/checks/llms-txt.d.ts +15 -0
- package/dist/checks/llms-txt.d.ts.map +1 -1
- package/dist/checks/llms-txt.js +162 -2
- package/dist/checks/llms-txt.js.map +1 -1
- package/dist/checks/mcp-discovery.d.ts +30 -0
- package/dist/checks/mcp-discovery.d.ts.map +1 -0
- package/dist/checks/mcp-discovery.js +523 -0
- package/dist/checks/mcp-discovery.js.map +1 -0
- package/dist/checks/meta-tags.d.ts.map +1 -1
- package/dist/checks/meta-tags.js +6 -5
- package/dist/checks/meta-tags.js.map +1 -1
- package/dist/checks/robots-parser.d.ts +110 -0
- package/dist/checks/robots-parser.d.ts.map +1 -0
- package/dist/checks/robots-parser.js +277 -0
- package/dist/checks/robots-parser.js.map +1 -0
- package/dist/checks/robots-txt.d.ts +2 -0
- package/dist/checks/robots-txt.d.ts.map +1 -1
- package/dist/checks/robots-txt.js +252 -45
- package/dist/checks/robots-txt.js.map +1 -1
- package/dist/checks/{mcp.d.ts → rsl.d.ts} +1 -1
- package/dist/checks/rsl.d.ts.map +1 -0
- package/dist/checks/rsl.js +242 -0
- package/dist/checks/rsl.js.map +1 -0
- package/dist/checks/security-txt.d.ts.map +1 -1
- package/dist/checks/security-txt.js +0 -1
- package/dist/checks/security-txt.js.map +1 -1
- package/dist/checks/seo-basics.d.ts.map +1 -1
- package/dist/checks/seo-basics.js +0 -1
- package/dist/checks/seo-basics.js.map +1 -1
- package/dist/checks/sitemap.d.ts.map +1 -1
- package/dist/checks/sitemap.js +0 -1
- package/dist/checks/sitemap.js.map +1 -1
- package/dist/checks/structured-data.d.ts.map +1 -1
- package/dist/checks/structured-data.js +215 -4
- package/dist/checks/structured-data.js.map +1 -1
- package/dist/checks/structured-fields.d.ts +46 -0
- package/dist/checks/structured-fields.d.ts.map +1 -0
- package/dist/checks/structured-fields.js +112 -0
- package/dist/checks/structured-fields.js.map +1 -0
- package/dist/checks/surface.d.ts +59 -0
- package/dist/checks/surface.d.ts.map +1 -0
- package/dist/checks/surface.js +106 -0
- package/dist/checks/surface.js.map +1 -0
- package/dist/checks/tls-https.d.ts.map +1 -1
- package/dist/checks/tls-https.js +0 -1
- package/dist/checks/tls-https.js.map +1 -1
- package/dist/checks/usage-policy.d.ts +53 -0
- package/dist/checks/usage-policy.d.ts.map +1 -0
- package/dist/checks/usage-policy.js +339 -0
- package/dist/checks/usage-policy.js.map +1 -0
- package/dist/checks/utils.d.ts +25 -1
- package/dist/checks/utils.d.ts.map +1 -1
- package/dist/checks/utils.js +33 -1
- package/dist/checks/utils.js.map +1 -1
- package/dist/checks/waf.d.ts +75 -0
- package/dist/checks/waf.d.ts.map +1 -0
- package/dist/checks/waf.js +203 -0
- package/dist/checks/waf.js.map +1 -0
- package/dist/checks/webmcp.d.ts +55 -0
- package/dist/checks/webmcp.d.ts.map +1 -0
- package/dist/checks/webmcp.js +209 -0
- package/dist/checks/webmcp.js.map +1 -0
- package/dist/checks/well-known.d.ts +38 -0
- package/dist/checks/well-known.d.ts.map +1 -0
- package/dist/checks/well-known.js +202 -0
- package/dist/checks/well-known.js.map +1 -0
- package/dist/cli.d.ts +14 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +144 -6
- package/dist/cli.js.map +1 -1
- package/dist/constants.d.ts +212 -14
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +625 -59
- package/dist/constants.js.map +1 -1
- package/dist/fetcher.d.ts +5 -1
- package/dist/fetcher.d.ts.map +1 -1
- package/dist/fetcher.js +62 -27
- package/dist/fetcher.js.map +1 -1
- package/dist/guide-urls.js +1 -1
- package/dist/guide-urls.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/orchestrator.d.ts +2 -2
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +18 -7
- package/dist/orchestrator.js.map +1 -1
- package/dist/reporter/html.d.ts +9 -0
- package/dist/reporter/html.d.ts.map +1 -1
- package/dist/reporter/html.js +49 -11
- package/dist/reporter/html.js.map +1 -1
- package/dist/reporter/index.d.ts.map +1 -1
- package/dist/reporter/index.js +7 -0
- package/dist/reporter/index.js.map +1 -1
- package/dist/reporter/markdown.d.ts +8 -0
- package/dist/reporter/markdown.d.ts.map +1 -0
- package/dist/reporter/markdown.js +106 -0
- package/dist/reporter/markdown.js.map +1 -0
- package/dist/reporter/terminal.d.ts.map +1 -1
- package/dist/reporter/terminal.js +36 -1
- package/dist/reporter/terminal.js.map +1 -1
- package/dist/scorer.d.ts +10 -0
- package/dist/scorer.d.ts.map +1 -1
- package/dist/scorer.js +22 -5
- package/dist/scorer.js.map +1 -1
- package/dist/types.d.ts +96 -3
- package/dist/types.d.ts.map +1 -1
- package/docs/api.md +200 -0
- package/docs/architecture.md +104 -0
- package/docs/checks.md +555 -0
- package/docs/ci.md +89 -0
- package/docs/cli.md +103 -0
- package/docs/concepts.md +101 -0
- package/docs/faq.md +89 -0
- package/docs/getting-started.md +108 -0
- package/docs/roadmap.md +367 -0
- package/package.json +14 -5
- package/dist/checks/agent-json.d.ts +0 -14
- package/dist/checks/agent-json.d.ts.map +0 -1
- package/dist/checks/agent-json.js +0 -167
- package/dist/checks/agent-json.js.map +0 -1
- package/dist/checks/mcp.d.ts.map +0 -1
- package/dist/checks/mcp.js +0 -162
- package/dist/checks/mcp.js.map +0 -1
- package/dist/checks/openapi.d.ts +0 -4
- package/dist/checks/openapi.d.ts.map +0 -1
- package/dist/checks/openapi.js +0 -121
- package/dist/checks/openapi.js.map +0 -1
- package/dist/checks/well-known-ai.d.ts +0 -17
- package/dist/checks/well-known-ai.d.ts.map +0 -1
- package/dist/checks/well-known-ai.js +0 -123
- package/dist/checks/well-known-ai.js.map +0 -1
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
import { API_DESCRIPTION_PATHS, LINKSET_MEDIA_TYPE } from '../constants.js';
|
|
2
|
+
import { guideUrl } from '../guide-urls.js';
|
|
3
|
+
import { buildResult, checkContentType, isHtmlDocument, notApplicable } from './utils.js';
|
|
4
|
+
import { hasApiSurface } from './surface.js';
|
|
5
|
+
import { findLinkTags, getAttribute } from './html-utils.js';
|
|
6
|
+
import { parseLinkHeader } from './http-headers.js';
|
|
7
|
+
import { standingNote } from './well-known.js';
|
|
8
|
+
/**
|
|
9
|
+
* "api-discovery" — can an agent find, and read, this site's API description?
|
|
10
|
+
*
|
|
11
|
+
* The check used to probe exactly one path, `/.well-known/openapi.json`. That
|
|
12
|
+
* path is a folk convention: it is not in the IANA well-known registry, and the
|
|
13
|
+
* OpenAPI specification itself recommends the file be named `openapi.json` or
|
|
14
|
+
* `openapi.yaml` without prescribing a location. So a site doing everything
|
|
15
|
+
* right at `/openapi.json` scored zero.
|
|
16
|
+
*
|
|
17
|
+
* There *is* a registered mechanism: RFC 9727 defines `/.well-known/api-catalog`,
|
|
18
|
+
* a linkset of the APIs a publisher offers, each entry pointing at a
|
|
19
|
+
* machine-readable description via `service-desc` and human documentation via
|
|
20
|
+
* `service-doc` (RFC 8631). Adoption is tiny — a handful of publishers — but it
|
|
21
|
+
* is the only standards-track answer, and checking it costs one request.
|
|
22
|
+
*
|
|
23
|
+
* The check therefore walks discovery in order of authority: the registered
|
|
24
|
+
* catalog, then RFC 8631 link relations in headers and HTML, then the
|
|
25
|
+
* conventional file locations. Whatever it finds, it validates the same way, so
|
|
26
|
+
* broadening discovery can only raise a score, never lower one.
|
|
27
|
+
*/
|
|
28
|
+
export const meta = {
|
|
29
|
+
id: 'api-discovery',
|
|
30
|
+
name: 'API Discovery',
|
|
31
|
+
description: 'Checks how agents discover an API description (RFC 9727 catalog, service-desc links, OpenAPI)',
|
|
32
|
+
category: 'protocols',
|
|
33
|
+
aliases: ['openapi'],
|
|
34
|
+
};
|
|
35
|
+
const MECHANISM_LABEL = {
|
|
36
|
+
'api-catalog': '/.well-known/api-catalog (RFC 9727)',
|
|
37
|
+
'link-header': 'Link header rel="service-desc"',
|
|
38
|
+
'html-link': '<link rel="service-desc">',
|
|
39
|
+
'conventional-path': 'conventional file path',
|
|
40
|
+
};
|
|
41
|
+
function absolute(url, base) {
|
|
42
|
+
try {
|
|
43
|
+
return new URL(url, `${base}/`).toString();
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return url;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Follow the discovery chain. Returns the description document plus how it was
|
|
51
|
+
* found, and separately whether a catalog exists at all, since a catalog is
|
|
52
|
+
* worth reporting even when its entries lead nowhere.
|
|
53
|
+
*/
|
|
54
|
+
async function locate(ctx) {
|
|
55
|
+
// 1. RFC 9727 — the registered mechanism.
|
|
56
|
+
const catalogRes = await ctx.fetch(`${ctx.url}/.well-known/api-catalog`);
|
|
57
|
+
const catalog = catalogRes.ok && catalogRes.body.trim().length > 0 ? catalogRes : null;
|
|
58
|
+
if (catalog !== null) {
|
|
59
|
+
for (const href of serviceDescsFromLinkset(catalog.body)) {
|
|
60
|
+
const res = await ctx.fetch(absolute(href, ctx.url));
|
|
61
|
+
if (res.ok && res.body.trim().length > 0) {
|
|
62
|
+
return { found: { mechanism: 'api-catalog', path: href, res }, catalog };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// 2. RFC 8631 link relations, in the response header then the HTML head.
|
|
67
|
+
for (const entry of parseLinkHeader(ctx.headers['link'] ?? '')) {
|
|
68
|
+
if (entry.params['rel'] !== 'service-desc')
|
|
69
|
+
continue;
|
|
70
|
+
const res = await ctx.fetch(absolute(entry.url, ctx.url));
|
|
71
|
+
if (res.ok && res.body.trim().length > 0) {
|
|
72
|
+
return { found: { mechanism: 'link-header', path: entry.url, res }, catalog };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
for (const tag of findLinkTags(ctx.html, 'service-desc')) {
|
|
76
|
+
const href = getAttribute(tag, 'href');
|
|
77
|
+
if (href === null)
|
|
78
|
+
continue;
|
|
79
|
+
const res = await ctx.fetch(absolute(href, ctx.url));
|
|
80
|
+
if (res.ok && res.body.trim().length > 0) {
|
|
81
|
+
return { found: { mechanism: 'html-link', path: href, res }, catalog };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// 3. Conventional locations, registered path first.
|
|
85
|
+
for (const path of API_DESCRIPTION_PATHS) {
|
|
86
|
+
const res = await ctx.fetch(`${ctx.url}${path}`);
|
|
87
|
+
if (res.ok && res.body.trim().length > 0 && looksLikeApiDescription(res.body)) {
|
|
88
|
+
return { found: { mechanism: 'conventional-path', path, res }, catalog };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return { found: null, catalog };
|
|
92
|
+
}
|
|
93
|
+
/** Pull `service-desc` hrefs out of an RFC 9264 linkset document. */
|
|
94
|
+
export function serviceDescsFromLinkset(body) {
|
|
95
|
+
try {
|
|
96
|
+
const data = JSON.parse(body);
|
|
97
|
+
const linkset = Array.isArray(data.linkset) ? data.linkset : [];
|
|
98
|
+
return linkset.flatMap((entry) => {
|
|
99
|
+
const descs = Array.isArray(entry['service-desc']) ? entry['service-desc'] : [];
|
|
100
|
+
return descs.map((d) => String(d.href ?? '')).filter((h) => h !== '');
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* A 200 from `/api-docs` is usually a Swagger UI page, and on an SPA every
|
|
109
|
+
* unknown path returns the index shell. Either would turn "no API description"
|
|
110
|
+
* into a confusing validation failure, so pages are treated as absent.
|
|
111
|
+
*/
|
|
112
|
+
function looksLikeApiDescription(body) {
|
|
113
|
+
return !isHtmlDocument(body);
|
|
114
|
+
}
|
|
115
|
+
export default async function check(ctx) {
|
|
116
|
+
const start = performance.now();
|
|
117
|
+
const findings = [];
|
|
118
|
+
let score = 100;
|
|
119
|
+
const { found, catalog } = await locate(ctx);
|
|
120
|
+
if (catalog !== null) {
|
|
121
|
+
score = reportCatalog(catalog, findings, score);
|
|
122
|
+
}
|
|
123
|
+
if (found === null) {
|
|
124
|
+
const surface = await hasApiSurface(ctx);
|
|
125
|
+
if (!surface.found) {
|
|
126
|
+
findings.push({
|
|
127
|
+
status: 'pass',
|
|
128
|
+
message: 'No API surface — API discovery does not apply to this site',
|
|
129
|
+
detail: 'No description, catalog, service-desc relation or developer area was found. Run with --profile api to ' +
|
|
130
|
+
'audit as though the site offered one.',
|
|
131
|
+
});
|
|
132
|
+
return notApplicable(meta, findings, start);
|
|
133
|
+
}
|
|
134
|
+
findings.push({
|
|
135
|
+
status: 'fail',
|
|
136
|
+
message: 'API surface present but no machine-readable description found',
|
|
137
|
+
detail: `Evidence of an API: ${surface.reason}. Checked /.well-known/api-catalog, Link and <link> rel="service-desc", and ${API_DESCRIPTION_PATHS.join(', ')}`,
|
|
138
|
+
hint: 'The API exists; nothing describes it in a form an agent can read, so using it requires a human to read your ' +
|
|
139
|
+
'documentation first. Serve an OpenAPI description at /openapi.json and advertise it with ' +
|
|
140
|
+
'Link: </openapi.json>; rel="service-desc". For several APIs, publish an RFC 9727 catalog.',
|
|
141
|
+
learnMoreUrl: guideUrl(meta.id, 'not-found'),
|
|
142
|
+
});
|
|
143
|
+
return buildResult(meta, 0, findings, start);
|
|
144
|
+
}
|
|
145
|
+
findings.push({
|
|
146
|
+
status: 'pass',
|
|
147
|
+
message: `API description found at ${found.path} via ${MECHANISM_LABEL[found.mechanism]}`,
|
|
148
|
+
detail: standingNote(found.path),
|
|
149
|
+
});
|
|
150
|
+
if (found.mechanism === 'conventional-path' && catalog === null) {
|
|
151
|
+
findings.push({
|
|
152
|
+
status: 'warn',
|
|
153
|
+
message: 'API description is only discoverable by guessing its path',
|
|
154
|
+
hint: 'Nothing on the site points at it, so an agent has to try known filenames. Advertise it with a Link header ' +
|
|
155
|
+
'(Link: <…>; rel="service-desc") or a <link rel="service-desc"> tag, and for multiple APIs an RFC 9727 catalog.',
|
|
156
|
+
learnMoreUrl: guideUrl(meta.id, 'undiscoverable'),
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
return validateDescription(found, findings, score, start);
|
|
160
|
+
}
|
|
161
|
+
/** Report an RFC 9727 catalog: its media type, shape, and entry completeness. */
|
|
162
|
+
function reportCatalog(res, findings, score) {
|
|
163
|
+
const ct = (res.headers['content-type'] ?? '').toLowerCase();
|
|
164
|
+
if (!ct.includes(LINKSET_MEDIA_TYPE) && !ct.includes('application/json')) {
|
|
165
|
+
findings.push({
|
|
166
|
+
status: 'warn',
|
|
167
|
+
message: `/.well-known/api-catalog served as "${ct.split(';')[0] || 'no Content-Type'}"`,
|
|
168
|
+
detail: `RFC 9727 requires support for ${LINKSET_MEDIA_TYPE}.`,
|
|
169
|
+
hint: `Serve the catalog as ${LINKSET_MEDIA_TYPE}.`,
|
|
170
|
+
learnMoreUrl: guideUrl(meta.id, 'catalog-content-type'),
|
|
171
|
+
});
|
|
172
|
+
return score;
|
|
173
|
+
}
|
|
174
|
+
let data;
|
|
175
|
+
try {
|
|
176
|
+
data = JSON.parse(res.body);
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
findings.push({
|
|
180
|
+
status: 'warn',
|
|
181
|
+
message: '/.well-known/api-catalog is not valid JSON',
|
|
182
|
+
hint: 'The catalog must be a JSON linkset per RFC 9264.',
|
|
183
|
+
learnMoreUrl: guideUrl(meta.id, 'catalog-invalid'),
|
|
184
|
+
});
|
|
185
|
+
return score;
|
|
186
|
+
}
|
|
187
|
+
const linkset = Array.isArray(data.linkset) ? data.linkset : [];
|
|
188
|
+
if (linkset.length === 0) {
|
|
189
|
+
findings.push({
|
|
190
|
+
status: 'warn',
|
|
191
|
+
message: 'API catalog present but its linkset is empty',
|
|
192
|
+
hint: 'Each linkset entry needs an anchor and at least one service-desc or service-doc link.',
|
|
193
|
+
learnMoreUrl: guideUrl(meta.id, 'catalog-empty'),
|
|
194
|
+
});
|
|
195
|
+
return score;
|
|
196
|
+
}
|
|
197
|
+
findings.push({
|
|
198
|
+
status: 'pass',
|
|
199
|
+
message: `RFC 9727 API catalog lists ${linkset.length} API(s)`,
|
|
200
|
+
detail: standingNote('/.well-known/api-catalog'),
|
|
201
|
+
});
|
|
202
|
+
const noAnchor = linkset.filter((e) => typeof e.anchor !== 'string' || e.anchor === '').length;
|
|
203
|
+
if (noAnchor > 0) {
|
|
204
|
+
findings.push({
|
|
205
|
+
status: 'warn',
|
|
206
|
+
message: `${noAnchor} catalog entry(ies) missing an anchor`,
|
|
207
|
+
hint: 'Every linkset entry needs an "anchor" identifying the API it describes.',
|
|
208
|
+
learnMoreUrl: guideUrl(meta.id, 'catalog-anchor'),
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
const noDocs = linkset.filter((e) => !Array.isArray(e['service-doc'])).length;
|
|
212
|
+
if (noDocs > 0) {
|
|
213
|
+
findings.push({
|
|
214
|
+
status: 'warn',
|
|
215
|
+
message: `${noDocs} catalog entry(ies) have no service-doc link`,
|
|
216
|
+
hint: 'Pair each service-desc (machine-readable) with a service-doc (human-readable). Agents surface the latter to users.',
|
|
217
|
+
learnMoreUrl: guideUrl(meta.id, 'catalog-service-doc'),
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
return score;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Validate the description document. The deduction table is unchanged from the
|
|
224
|
+
* pre-3.7 OpenAPI check, so a site that scored under the old single-path check
|
|
225
|
+
* scores identically now.
|
|
226
|
+
*/
|
|
227
|
+
function validateDescription(located, findings, score, start) {
|
|
228
|
+
const { res, path } = located;
|
|
229
|
+
const isYaml = /\.ya?ml$/i.test(path) || /^\s*openapi\s*:/im.test(res.body);
|
|
230
|
+
if (!isYaml) {
|
|
231
|
+
const ctFinding = checkContentType(res, ['application/json'], {
|
|
232
|
+
checkId: meta.id,
|
|
233
|
+
resourceLabel: path,
|
|
234
|
+
anchor: 'wrong-content-type',
|
|
235
|
+
});
|
|
236
|
+
if (ctFinding) {
|
|
237
|
+
findings.push(ctFinding);
|
|
238
|
+
score -= 5;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (isYaml) {
|
|
242
|
+
// ax-audit carries no YAML parser (zero runtime dependencies beyond chalk
|
|
243
|
+
// and commander). Report what can be read from the surface and say plainly
|
|
244
|
+
// that the document was not fully validated, rather than guessing.
|
|
245
|
+
return reportYamlDescription(res.body, path, findings, score, start);
|
|
246
|
+
}
|
|
247
|
+
let data;
|
|
248
|
+
try {
|
|
249
|
+
data = JSON.parse(res.body);
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
findings.push({
|
|
253
|
+
status: 'fail',
|
|
254
|
+
message: `Invalid JSON in ${path}`,
|
|
255
|
+
hint: 'Fix the JSON syntax. Validate with a JSON linter or an OpenAPI validator.',
|
|
256
|
+
learnMoreUrl: guideUrl(meta.id, 'invalid-json'),
|
|
257
|
+
});
|
|
258
|
+
return buildResult(meta, 10, findings, start);
|
|
259
|
+
}
|
|
260
|
+
findings.push({ status: 'pass', message: 'Valid JSON' });
|
|
261
|
+
score = validateOpenApi(data, findings, score);
|
|
262
|
+
return buildResult(meta, score, findings, start);
|
|
263
|
+
}
|
|
264
|
+
/** Shared OpenAPI/Swagger field rules. */
|
|
265
|
+
function validateOpenApi(data, findings, score) {
|
|
266
|
+
const version = typeof data.openapi === 'string' ? data.openapi : typeof data.swagger === 'string' ? data.swagger : null;
|
|
267
|
+
if (version === null) {
|
|
268
|
+
findings.push({
|
|
269
|
+
status: 'fail',
|
|
270
|
+
message: 'No "openapi" or "swagger" version field',
|
|
271
|
+
hint: 'Add an "openapi" field naming the specification version, for example "3.1.0".',
|
|
272
|
+
learnMoreUrl: guideUrl(meta.id, 'no-version'),
|
|
273
|
+
});
|
|
274
|
+
score -= 20;
|
|
275
|
+
}
|
|
276
|
+
else if (typeof data.swagger === 'string') {
|
|
277
|
+
findings.push({
|
|
278
|
+
status: 'warn',
|
|
279
|
+
message: `Swagger ${version} rather than OpenAPI 3.x`,
|
|
280
|
+
hint: 'Convert to OpenAPI 3.1 or 3.2. Tooling support for Swagger 2.0 is fading, and 3.1 aligns with JSON Schema.',
|
|
281
|
+
learnMoreUrl: guideUrl(meta.id, 'swagger-2'),
|
|
282
|
+
});
|
|
283
|
+
score -= 10;
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
findings.push({ status: 'pass', message: `OpenAPI ${version}` });
|
|
287
|
+
if (version.startsWith('3.2') && data.$self !== undefined) {
|
|
288
|
+
findings.push({ status: 'pass', message: '$self declared (OpenAPI 3.2 self-identifying document)' });
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
const info = (data.info ?? {});
|
|
292
|
+
if (info.title) {
|
|
293
|
+
findings.push({ status: 'pass', message: `API title: "${String(info.title)}"` });
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
findings.push({
|
|
297
|
+
status: 'warn',
|
|
298
|
+
message: 'Missing info.title',
|
|
299
|
+
hint: 'Add info.title naming the API. Agents show it when choosing between tools.',
|
|
300
|
+
learnMoreUrl: guideUrl(meta.id, 'no-title'),
|
|
301
|
+
});
|
|
302
|
+
score -= 10;
|
|
303
|
+
}
|
|
304
|
+
if (info.description) {
|
|
305
|
+
findings.push({ status: 'pass', message: 'API description present' });
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
findings.push({
|
|
309
|
+
status: 'warn',
|
|
310
|
+
message: 'Missing info.description',
|
|
311
|
+
hint: 'Add info.description explaining what the API does. This is the text an agent reads to decide whether to use it.',
|
|
312
|
+
learnMoreUrl: guideUrl(meta.id, 'no-description'),
|
|
313
|
+
});
|
|
314
|
+
score -= 5;
|
|
315
|
+
}
|
|
316
|
+
const paths = (data.paths ?? {});
|
|
317
|
+
const pathCount = Object.keys(paths).length;
|
|
318
|
+
if (pathCount > 0) {
|
|
319
|
+
findings.push({ status: 'pass', message: `${pathCount} path(s) documented` });
|
|
320
|
+
reportOperationIds(paths, findings);
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
findings.push({
|
|
324
|
+
status: 'warn',
|
|
325
|
+
message: 'No paths documented',
|
|
326
|
+
hint: 'Document your endpoints under "paths". A description with no operations tells an agent nothing it can act on.',
|
|
327
|
+
learnMoreUrl: guideUrl(meta.id, 'no-paths'),
|
|
328
|
+
});
|
|
329
|
+
score -= 15;
|
|
330
|
+
}
|
|
331
|
+
if (Array.isArray(data.servers) && data.servers.length > 0) {
|
|
332
|
+
findings.push({ status: 'pass', message: `${data.servers.length} server URL(s) declared` });
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
findings.push({
|
|
336
|
+
status: 'warn',
|
|
337
|
+
message: 'No servers declared',
|
|
338
|
+
hint: 'Add a "servers" array with the base URL. Without it an agent has to guess where to send requests.',
|
|
339
|
+
learnMoreUrl: guideUrl(meta.id, 'no-servers'),
|
|
340
|
+
});
|
|
341
|
+
score -= 5;
|
|
342
|
+
}
|
|
343
|
+
const components = (data.components ?? {});
|
|
344
|
+
if (components.securitySchemes !== undefined || data.security !== undefined) {
|
|
345
|
+
findings.push({ status: 'pass', message: 'Authentication requirements declared' });
|
|
346
|
+
}
|
|
347
|
+
return score;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Operation ids are how an agent names a call. Informational in 3.x: this is a
|
|
351
|
+
* new finding inside a weighted check, so it must not deduct.
|
|
352
|
+
*/
|
|
353
|
+
function reportOperationIds(paths, findings) {
|
|
354
|
+
const methods = new Set(['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace']);
|
|
355
|
+
let total = 0;
|
|
356
|
+
let named = 0;
|
|
357
|
+
for (const item of Object.values(paths)) {
|
|
358
|
+
if (typeof item !== 'object' || item === null)
|
|
359
|
+
continue;
|
|
360
|
+
for (const [method, op] of Object.entries(item)) {
|
|
361
|
+
if (!methods.has(method.toLowerCase()))
|
|
362
|
+
continue;
|
|
363
|
+
total++;
|
|
364
|
+
if (typeof op?.operationId === 'string')
|
|
365
|
+
named++;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (total === 0)
|
|
369
|
+
return;
|
|
370
|
+
if (named === total) {
|
|
371
|
+
findings.push({ status: 'pass', message: `All ${total} operations have an operationId` });
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
findings.push({
|
|
375
|
+
status: 'warn',
|
|
376
|
+
message: `${named}/${total} operations have an operationId`,
|
|
377
|
+
hint: 'Give every operation a stable operationId. Agents and code generators use it as the function name; without one they invent one from the path and it changes under them.',
|
|
378
|
+
learnMoreUrl: guideUrl(meta.id, 'operation-ids'),
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
/** Surface-level reporting for a YAML description, clearly labelled as partial. */
|
|
383
|
+
function reportYamlDescription(body, path, findings, score, start) {
|
|
384
|
+
const version = body.match(/^\s*openapi\s*:\s*["']?([\d.]+)/im);
|
|
385
|
+
const hasTitle = /^\s{2,}title\s*:/im.test(body);
|
|
386
|
+
const hasPaths = /^paths\s*:/im.test(body);
|
|
387
|
+
const hasServers = /^servers\s*:/im.test(body);
|
|
388
|
+
findings.push({
|
|
389
|
+
status: 'pass',
|
|
390
|
+
message: version ? `OpenAPI ${version[1]} (YAML)` : 'YAML API description',
|
|
391
|
+
detail: 'ax-audit ships no YAML parser, so a YAML description is reported but not fully validated. Publish JSON alongside it for complete checking.',
|
|
392
|
+
});
|
|
393
|
+
if (!hasTitle) {
|
|
394
|
+
findings.push({
|
|
395
|
+
status: 'warn',
|
|
396
|
+
message: 'No info.title found in the YAML description',
|
|
397
|
+
hint: 'Add info.title naming the API.',
|
|
398
|
+
learnMoreUrl: guideUrl(meta.id, 'no-title'),
|
|
399
|
+
});
|
|
400
|
+
score -= 10;
|
|
401
|
+
}
|
|
402
|
+
if (!hasPaths) {
|
|
403
|
+
findings.push({
|
|
404
|
+
status: 'warn',
|
|
405
|
+
message: 'No paths section found in the YAML description',
|
|
406
|
+
hint: 'Document your endpoints under "paths".',
|
|
407
|
+
learnMoreUrl: guideUrl(meta.id, 'no-paths'),
|
|
408
|
+
});
|
|
409
|
+
score -= 15;
|
|
410
|
+
}
|
|
411
|
+
if (!hasServers) {
|
|
412
|
+
findings.push({
|
|
413
|
+
status: 'warn',
|
|
414
|
+
message: 'No servers section found in the YAML description',
|
|
415
|
+
hint: 'Add a "servers" list with the base URL.',
|
|
416
|
+
learnMoreUrl: guideUrl(meta.id, 'no-servers'),
|
|
417
|
+
});
|
|
418
|
+
score -= 5;
|
|
419
|
+
}
|
|
420
|
+
if (!version) {
|
|
421
|
+
findings.push({
|
|
422
|
+
status: 'warn',
|
|
423
|
+
message: 'No openapi version field found in the YAML description',
|
|
424
|
+
hint: 'Add an "openapi" field naming the specification version.',
|
|
425
|
+
learnMoreUrl: guideUrl(meta.id, 'no-version'),
|
|
426
|
+
});
|
|
427
|
+
score -= 20;
|
|
428
|
+
}
|
|
429
|
+
void path;
|
|
430
|
+
return buildResult(meta, score, findings, start);
|
|
431
|
+
}
|
|
432
|
+
//# sourceMappingURL=api-discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-discovery.js","sourceRoot":"","sources":["../../src/checks/api-discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { CheckContext, CheckResult, CheckMeta, FetchResponse } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* "auth-discovery" — if an agent needs credentials here, can it work out how to
|
|
4
|
+
* get them?
|
|
5
|
+
*
|
|
6
|
+
* A human hitting a 401 goes and reads the documentation. An agent cannot. It
|
|
7
|
+
* needs the answer in the response: which authorization server to talk to, what
|
|
8
|
+
* scopes exist, where to register. That is what RFC 9728 Protected Resource
|
|
9
|
+
* Metadata is for, and the MCP specification makes it mandatory for remote
|
|
10
|
+
* servers precisely because agents cannot read docs.
|
|
11
|
+
*
|
|
12
|
+
* The chain is: a `401` carrying `WWW-Authenticate` with a `resource_metadata`
|
|
13
|
+
* parameter, or `/.well-known/oauth-protected-resource`, naming one or more
|
|
14
|
+
* authorization servers; each of those exposing RFC 8414 metadata at
|
|
15
|
+
* `/.well-known/oauth-authorization-server` or OpenID discovery at
|
|
16
|
+
* `/.well-known/openid-configuration`.
|
|
17
|
+
*
|
|
18
|
+
* This check is conditional. A site with no API, no MCP server and no commerce
|
|
19
|
+
* profile has nothing to authorize, and demanding OAuth metadata from a blog
|
|
20
|
+
* would be noise. It reports N/A unless one of those surfaces exists.
|
|
21
|
+
*/
|
|
22
|
+
export declare const meta: CheckMeta;
|
|
23
|
+
/** Read the `resource_metadata` parameter out of a `WWW-Authenticate` challenge. */
|
|
24
|
+
export declare function resourceMetadataFromChallenge(header: string): string | null;
|
|
25
|
+
export default function check(ctx: CheckContext): Promise<CheckResult>;
|
|
26
|
+
/** Exposed for tests that build a metadata response directly. */
|
|
27
|
+
export type { FetchResponse };
|
|
28
|
+
//# sourceMappingURL=auth-discovery.d.ts.map
|
|
@@ -0,0 +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;AAmCF,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,CAiF3E;AA4FD,iEAAiE;AACjE,YAAY,EAAE,aAAa,EAAE,CAAC"}
|