@adcp/sdk 14.0.0-beta.14 → 14.0.0-beta.15
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/dist/lib/auth/oauth/authorization-required.d.mts +25 -11
- package/dist/lib/auth/oauth/authorization-required.d.ts +25 -11
- package/dist/lib/auth/oauth/authorization-required.js +18 -4
- package/dist/lib/auth/oauth/authorization-required.mjs +17 -4
- package/dist/lib/auth/oauth/index.d.mts +1 -1
- package/dist/lib/auth/oauth/index.d.ts +1 -1
- package/dist/lib/auth/oauth/index.js +2 -0
- package/dist/lib/auth/oauth/index.mjs +2 -0
- package/dist/lib/auth/oauth/resource-url.d.mts +8 -0
- package/dist/lib/auth/oauth/resource-url.d.ts +8 -0
- package/dist/lib/auth/oauth/resource-url.js +42 -0
- package/dist/lib/auth/oauth/resource-url.mjs +40 -0
- package/dist/lib/core/ConversationTypes.d.mts +10 -0
- package/dist/lib/core/ConversationTypes.d.ts +10 -0
- package/dist/lib/core/SingleAgentClient.d.mts +5 -2
- package/dist/lib/core/SingleAgentClient.d.ts +5 -2
- package/dist/lib/core/SingleAgentClient.js +133 -28
- package/dist/lib/core/SingleAgentClient.mjs +138 -29
- package/dist/lib/core/TaskExecutor.d.mts +1 -0
- package/dist/lib/core/TaskExecutor.d.ts +1 -0
- package/dist/lib/core/TaskExecutor.js +7 -1
- package/dist/lib/core/TaskExecutor.mjs +7 -1
- package/dist/lib/core/webhook-registration.d.mts +8 -1
- package/dist/lib/core/webhook-registration.d.ts +8 -1
- package/dist/lib/core/webhook-registration.js +65 -5
- package/dist/lib/core/webhook-registration.mjs +61 -4
- package/dist/lib/errors/index.d.mts +9 -0
- package/dist/lib/errors/index.d.ts +9 -0
- package/dist/lib/errors/index.js +33 -0
- package/dist/lib/errors/index.mjs +32 -0
- package/dist/lib/index.d.mts +3 -2
- package/dist/lib/index.d.ts +3 -2
- package/dist/lib/index.js +4 -0
- package/dist/lib/index.mjs +4 -0
- package/dist/lib/media-buy/compatibility.js +14 -2
- package/dist/lib/media-buy/compatibility.mjs +14 -2
- package/dist/lib/protocols/index.js +23 -7
- package/dist/lib/protocols/index.mjs +24 -8
- package/dist/lib/protocols/mcp.js +8 -6
- package/dist/lib/protocols/mcp.mjs +9 -7
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/decisioning/async-outcome.d.mts +11 -0
- package/dist/lib/server/decisioning/async-outcome.d.ts +11 -0
- package/dist/lib/server/decisioning/context.d.mts +11 -1
- package/dist/lib/server/decisioning/context.d.ts +11 -1
- package/dist/lib/server/decisioning/index.d.mts +3 -2
- package/dist/lib/server/decisioning/index.d.ts +3 -2
- package/dist/lib/server/decisioning/index.js +9 -0
- package/dist/lib/server/decisioning/index.mjs +10 -0
- package/dist/lib/server/decisioning/runtime/from-platform.d.mts +5 -2
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts +5 -2
- package/dist/lib/server/decisioning/runtime/from-platform.js +40 -8
- package/dist/lib/server/decisioning/runtime/from-platform.mjs +40 -8
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.mts +8 -1
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.ts +8 -1
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.js +10 -1
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.mjs +9 -1
- package/dist/lib/server/decisioning/runtime/postgres-task-settlement.d.mts +79 -0
- package/dist/lib/server/decisioning/runtime/postgres-task-settlement.d.ts +79 -0
- package/dist/lib/server/decisioning/runtime/postgres-task-settlement.js +391 -0
- package/dist/lib/server/decisioning/runtime/postgres-task-settlement.mjs +369 -0
- package/dist/lib/server/decisioning/runtime/task-registry.d.mts +2 -0
- package/dist/lib/server/decisioning/runtime/task-registry.d.ts +2 -0
- package/dist/lib/server/decisioning/runtime/task-registry.js +2 -1
- package/dist/lib/server/decisioning/runtime/task-registry.mjs +2 -1
- package/dist/lib/server/decisioning/runtime/to-context.js +15 -11
- package/dist/lib/server/decisioning/runtime/to-context.mjs +15 -11
- package/dist/lib/server/index.d.mts +2 -2
- package/dist/lib/server/index.d.ts +2 -2
- package/dist/lib/server/index.js +4 -0
- package/dist/lib/server/index.mjs +4 -0
- package/dist/lib/server/webhook-delivery/index.d.mts +2 -2
- package/dist/lib/server/webhook-delivery/index.d.ts +2 -2
- package/dist/lib/server/webhook-delivery/index.js +4 -0
- package/dist/lib/server/webhook-delivery/index.mjs +5 -1
- package/dist/lib/server/webhook-delivery/pg.d.mts +3 -1
- package/dist/lib/server/webhook-delivery/pg.d.ts +3 -1
- package/dist/lib/server/webhook-delivery/pg.js +25 -2
- package/dist/lib/server/webhook-delivery/pg.mjs +25 -2
- package/dist/lib/server/webhook-delivery/recovery.d.mts +44 -0
- package/dist/lib/server/webhook-delivery/recovery.d.ts +44 -0
- package/dist/lib/server/webhook-delivery/recovery.js +146 -43
- package/dist/lib/server/webhook-delivery/recovery.mjs +144 -43
- package/dist/lib/signing/agent-resolver/index.d.mts +1 -1
- package/dist/lib/signing/agent-resolver/index.d.ts +1 -1
- package/dist/lib/signing/agent-resolver/resolve-agent.d.mts +9 -0
- package/dist/lib/signing/agent-resolver/resolve-agent.d.ts +9 -0
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.mts +4 -1
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.d.ts +4 -1
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.js +17 -4
- package/dist/lib/signing/agent-resolver/resolved-agent-jwks.mjs +17 -4
- package/dist/lib/signing/jwks.d.mts +7 -0
- package/dist/lib/signing/jwks.d.ts +7 -0
- package/dist/lib/signing/server.d.mts +2 -2
- package/dist/lib/signing/server.d.ts +2 -2
- package/dist/lib/signing/webhook-verifier.d.mts +6 -0
- package/dist/lib/signing/webhook-verifier.d.ts +6 -0
- package/dist/lib/signing/webhook-verifier.js +38 -4
- package/dist/lib/signing/webhook-verifier.mjs +38 -4
- package/dist/lib/testing/client.d.mts +1 -0
- package/dist/lib/testing/client.d.ts +1 -0
- package/dist/lib/testing/client.js +6 -2
- package/dist/lib/testing/client.mjs +6 -2
- package/dist/lib/testing/compliance/comply.d.mts +2 -2
- package/dist/lib/testing/compliance/comply.d.ts +2 -2
- package/dist/lib/testing/compliance/comply.js +41 -31
- package/dist/lib/testing/compliance/comply.mjs +44 -21
- package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.d.mts +1 -7
- package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.d.ts +1 -7
- package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.js +6 -42
- package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.mjs +10 -40
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/utils/adcp-version-config.d.mts +2 -0
- package/dist/lib/utils/adcp-version-config.d.ts +2 -0
- package/dist/lib/utils/adcp-version-config.js +5 -0
- package/dist/lib/utils/adcp-version-config.mjs +4 -0
- package/dist/lib/version.d.mts +3 -3
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.mjs +3 -3
- package/docs/llms.txt +3 -1
- package/docs/migration-12-to-14.md +6 -5
- package/docs/migration-13-to-14.md +48 -7
- package/docs/migration-task-registry-scoping.md +164 -11
- package/package.json +1 -1
- package/skills/build-decisioning-platform/advanced/REFERENCE.md +1 -1
|
@@ -15,7 +15,8 @@ const WEBHOOK_MANDATORY_COMPONENTS = [
|
|
|
15
15
|
"content-digest"
|
|
16
16
|
];
|
|
17
17
|
async function verifyWebhookSignature(request, options) {
|
|
18
|
-
const
|
|
18
|
+
const currentTime = options.now ?? (() => Date.now() / 1e3);
|
|
19
|
+
const now = currentTime();
|
|
19
20
|
const requiredTag = options.requiredTag ?? WEBHOOK_SIGNING_TAG;
|
|
20
21
|
const sigInputHeader = getHeaderValue(request.headers, "Signature-Input");
|
|
21
22
|
const sigHeader = getHeaderValue(request.headers, "Signature");
|
|
@@ -56,7 +57,8 @@ async function verifyWebhookSignature(request, options) {
|
|
|
56
57
|
validateWindow(parsedInput.params.created, parsedInput.params.expires, now);
|
|
57
58
|
validateCoveredComponents(parsedInput.components);
|
|
58
59
|
const canonicalWebhookTarget = validateTargetUri(request.url);
|
|
59
|
-
const
|
|
60
|
+
const keyResolution = options.jwks.resolveWithMetadata ? await options.jwks.resolveWithMetadata(parsedInput.params.keyid) : { jwk: await options.jwks.resolve(parsedInput.params.keyid) };
|
|
61
|
+
const jwk = keyResolution.jwk;
|
|
60
62
|
if (!jwk) {
|
|
61
63
|
throw new WebhookSignatureError(
|
|
62
64
|
"webhook_signature_key_unknown",
|
|
@@ -71,6 +73,9 @@ async function verifyWebhookSignature(request, options) {
|
|
|
71
73
|
`JWKS resolver returned a JWK whose kid "${jwk.kid}" does not match requested keyid "${parsedInput.params.keyid}".`
|
|
72
74
|
);
|
|
73
75
|
}
|
|
76
|
+
if (keyResolution.operatorAuthorizationValidUntil !== void 0) {
|
|
77
|
+
assertDelegatedOperatorAuthorizationActive(keyResolution.operatorAuthorizationValidUntil, currentTime());
|
|
78
|
+
}
|
|
74
79
|
if (jwk.adcp_use === void 0 || !jwk.key_ops?.includes("verify") || jwk.adcp_use !== "request-signing" && jwk.adcp_use !== "webhook-signing") {
|
|
75
80
|
throw new WebhookSignatureError(
|
|
76
81
|
"webhook_signature_key_purpose_invalid",
|
|
@@ -88,7 +93,7 @@ async function verifyWebhookSignature(request, options) {
|
|
|
88
93
|
}
|
|
89
94
|
throw err;
|
|
90
95
|
}
|
|
91
|
-
const replayScope = canonicalWebhookTarget;
|
|
96
|
+
const replayScope = replayScopeForWebhook(canonicalWebhookTarget, options.replayScopeBinding);
|
|
92
97
|
if (await options.replayStore.has(jwk.kid, replayScope, parsedInput.params.nonce, now)) {
|
|
93
98
|
throw new WebhookSignatureError(
|
|
94
99
|
"webhook_signature_replayed",
|
|
@@ -134,6 +139,9 @@ async function verifyWebhookSignature(request, options) {
|
|
|
134
139
|
"Content-Digest header does not match recomputed body hash."
|
|
135
140
|
);
|
|
136
141
|
}
|
|
142
|
+
if (keyResolution.operatorAuthorizationValidUntil !== void 0) {
|
|
143
|
+
assertDelegatedOperatorAuthorizationActive(keyResolution.operatorAuthorizationValidUntil, currentTime());
|
|
144
|
+
}
|
|
137
145
|
const remaining = parsedInput.params.expires - now + CLOCK_SKEW_TOLERANCE_SECONDS;
|
|
138
146
|
const ttl = Math.max(remaining, MAX_SIGNATURE_WINDOW_SECONDS + CLOCK_SKEW_TOLERANCE_SECONDS);
|
|
139
147
|
const insertResult = await options.replayStore.insert(jwk.kid, replayScope, parsedInput.params.nonce, ttl, now);
|
|
@@ -151,8 +159,34 @@ async function verifyWebhookSignature(request, options) {
|
|
|
151
159
|
`Per-keyid replay cache cap exceeded on commit for keyid=${jwk.kid}.`
|
|
152
160
|
);
|
|
153
161
|
}
|
|
162
|
+
if (keyResolution.operatorAuthorizationValidUntil !== void 0) {
|
|
163
|
+
assertDelegatedOperatorAuthorizationActive(keyResolution.operatorAuthorizationValidUntil, currentTime());
|
|
164
|
+
}
|
|
154
165
|
const agent_url = options.agentUrlForKeyid?.(jwk.kid);
|
|
155
|
-
return {
|
|
166
|
+
return {
|
|
167
|
+
status: "verified",
|
|
168
|
+
keyid: jwk.kid,
|
|
169
|
+
...agent_url !== void 0 && { agent_url },
|
|
170
|
+
// Keep the established whole-second credential timestamp while using the
|
|
171
|
+
// fractional clock above for exact authorization-expiry enforcement.
|
|
172
|
+
verified_at: Math.floor(now)
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
function assertDelegatedOperatorAuthorizationActive(validUntil, now) {
|
|
176
|
+
if (validUntil !== void 0 && (!Number.isFinite(validUntil) || now >= validUntil)) {
|
|
177
|
+
throw new WebhookSignatureError(
|
|
178
|
+
"webhook_signature_key_unknown",
|
|
179
|
+
7,
|
|
180
|
+
"The signing key is no longer authorized for this webhook registration."
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function replayScopeForWebhook(canonicalTarget, binding) {
|
|
185
|
+
if (binding === void 0) return canonicalTarget;
|
|
186
|
+
if (binding.length === 0 || binding.length > 1024 || binding.includes("\0")) {
|
|
187
|
+
throw new TypeError("replayScopeBinding must be a non-empty string of at most 1024 characters without NUL.");
|
|
188
|
+
}
|
|
189
|
+
return JSON.stringify([canonicalTarget, binding]);
|
|
156
190
|
}
|
|
157
191
|
function requireParams(parsed) {
|
|
158
192
|
const required = ["created", "expires", "nonce", "keyid", "alg", "tag"];
|
|
@@ -94,6 +94,7 @@ export declare function discoverAgentProfile(client: TestClient, signal?: AbortS
|
|
|
94
94
|
schemaAdcpVersion?: string): Promise<{
|
|
95
95
|
profile: AgentProfile;
|
|
96
96
|
step: TestStepResult;
|
|
97
|
+
caughtError?: unknown;
|
|
97
98
|
}>;
|
|
98
99
|
/**
|
|
99
100
|
* Discover what channels, pricing models, formats the agent supports
|
|
@@ -94,6 +94,7 @@ export declare function discoverAgentProfile(client: TestClient, signal?: AbortS
|
|
|
94
94
|
schemaAdcpVersion?: string): Promise<{
|
|
95
95
|
profile: AgentProfile;
|
|
96
96
|
step: TestStepResult;
|
|
97
|
+
caughtError?: unknown;
|
|
97
98
|
}>;
|
|
98
99
|
/**
|
|
99
100
|
* Discover what channels, pricing models, formats the agent supports
|
|
@@ -359,7 +359,11 @@ function describeVersionUnsupported(result, requestedVersion) {
|
|
|
359
359
|
return `VERSION_UNSUPPORTED: ${requestedText}${supportedText}`;
|
|
360
360
|
}
|
|
361
361
|
async function discoverAgentProfile(client, signal, schemaAdcpVersion) {
|
|
362
|
-
const {
|
|
362
|
+
const {
|
|
363
|
+
result: agentInfo,
|
|
364
|
+
step,
|
|
365
|
+
caughtError
|
|
366
|
+
} = await runStep(
|
|
363
367
|
"Discover agent capabilities",
|
|
364
368
|
"getAgentInfo",
|
|
365
369
|
() => raceWithSignal(client.getAgentInfo({ signal }), signal)
|
|
@@ -425,7 +429,7 @@ async function discoverAgentProfile(client, signal, schemaAdcpVersion) {
|
|
|
425
429
|
}
|
|
426
430
|
}
|
|
427
431
|
seedTestClientSigningCapability(client, profile, schemaAdcpVersion);
|
|
428
|
-
return { profile, step };
|
|
432
|
+
return { profile, step, ...caughtError !== void 0 && { caughtError } };
|
|
429
433
|
}
|
|
430
434
|
async function discoverAgentCapabilities(client, profile, options) {
|
|
431
435
|
const steps = [];
|
|
@@ -321,7 +321,11 @@ function describeVersionUnsupported(result, requestedVersion) {
|
|
|
321
321
|
return `VERSION_UNSUPPORTED: ${requestedText}${supportedText}`;
|
|
322
322
|
}
|
|
323
323
|
async function discoverAgentProfile(client, signal, schemaAdcpVersion) {
|
|
324
|
-
const {
|
|
324
|
+
const {
|
|
325
|
+
result: agentInfo,
|
|
326
|
+
step,
|
|
327
|
+
caughtError
|
|
328
|
+
} = await runStep(
|
|
325
329
|
"Discover agent capabilities",
|
|
326
330
|
"getAgentInfo",
|
|
327
331
|
() => raceWithSignal(client.getAgentInfo({ signal }), signal)
|
|
@@ -387,7 +391,7 @@ async function discoverAgentProfile(client, signal, schemaAdcpVersion) {
|
|
|
387
391
|
}
|
|
388
392
|
}
|
|
389
393
|
seedTestClientSigningCapability(client, profile, schemaAdcpVersion);
|
|
390
|
-
return { profile, step };
|
|
394
|
+
return { profile, step, ...caughtError !== void 0 && { caughtError } };
|
|
391
395
|
}
|
|
392
396
|
async function discoverAgentCapabilities(client, profile, options) {
|
|
393
397
|
const steps = [];
|
|
@@ -139,10 +139,10 @@ export declare function rotateStoryboardsForOffset<T>(items: readonly T[], offse
|
|
|
139
139
|
* Centralized so the "run security.yaml against 401-happy agents" path and
|
|
140
140
|
* the fallback "unreachable result" path share the same truth.
|
|
141
141
|
*
|
|
142
|
-
* Exported for direct unit tests of the
|
|
142
|
+
* Exported for direct unit tests of the auth classifier — callers inside
|
|
143
143
|
* the library should go through `comply()`, not this helper.
|
|
144
144
|
*/
|
|
145
|
-
export declare function detectAuthRejection(agentUrl: string, errorMsg: string | undefined, signal?: AbortSignal, fetchFn?: typeof fetch): Promise<{
|
|
145
|
+
export declare function detectAuthRejection(agentUrl: string, errorMsg: string | undefined, signal?: AbortSignal, fetchFn?: typeof fetch, caughtError?: unknown, allowPrivateIp?: boolean): Promise<{
|
|
146
146
|
isAuth: boolean;
|
|
147
147
|
observations: AdvisoryObservation[];
|
|
148
148
|
}>;
|
|
@@ -139,10 +139,10 @@ export declare function rotateStoryboardsForOffset<T>(items: readonly T[], offse
|
|
|
139
139
|
* Centralized so the "run security.yaml against 401-happy agents" path and
|
|
140
140
|
* the fallback "unreachable result" path share the same truth.
|
|
141
141
|
*
|
|
142
|
-
* Exported for direct unit tests of the
|
|
142
|
+
* Exported for direct unit tests of the auth classifier — callers inside
|
|
143
143
|
* the library should go through `comply()`, not this helper.
|
|
144
144
|
*/
|
|
145
|
-
export declare function detectAuthRejection(agentUrl: string, errorMsg: string | undefined, signal?: AbortSignal, fetchFn?: typeof fetch): Promise<{
|
|
145
|
+
export declare function detectAuthRejection(agentUrl: string, errorMsg: string | undefined, signal?: AbortSignal, fetchFn?: typeof fetch, caughtError?: unknown, allowPrivateIp?: boolean): Promise<{
|
|
146
146
|
isAuth: boolean;
|
|
147
147
|
observations: AdvisoryObservation[];
|
|
148
148
|
}>;
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
6
|
var __export = (target, all) => {
|
|
9
7
|
for (var name in all)
|
|
@@ -17,14 +15,6 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
15
|
}
|
|
18
16
|
return to;
|
|
19
17
|
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
19
|
var comply_exports = {};
|
|
30
20
|
__export(comply_exports, {
|
|
@@ -55,7 +45,8 @@ var import_schema_loader = require('../../validation/schema-loader.js');
|
|
|
55
45
|
var import_oauth_metadata_graph = require('../storyboard/oauth-metadata-graph/index.js');
|
|
56
46
|
var import_version = require('../../version.js');
|
|
57
47
|
var import_validations = require('../storyboard/validations.js');
|
|
58
|
-
var
|
|
48
|
+
var import_agent_transport_fetch = require('../../net/agent-transport-fetch.js');
|
|
49
|
+
var import_authorization_required = require('../../auth/oauth/authorization-required.js');
|
|
59
50
|
var import_functional_dispatch = require('../storyboard/request-signing/functional-dispatch.js');
|
|
60
51
|
(0, import_default_invariants.registerDefaultInvariants)();
|
|
61
52
|
const TRACK_ORDER = [
|
|
@@ -816,11 +807,11 @@ async function complyImpl(agentUrl, options) {
|
|
|
816
807
|
const allObservations = [];
|
|
817
808
|
let discoveryOptions = effectiveOptions;
|
|
818
809
|
let discoveryClient = (0, import_client.createTestClient)(agentUrl, effectiveOptions.protocol ?? "mcp", discoveryOptions);
|
|
819
|
-
let {
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
);
|
|
810
|
+
let {
|
|
811
|
+
profile,
|
|
812
|
+
step: profileStep,
|
|
813
|
+
caughtError: profileCaughtError
|
|
814
|
+
} = await (0, import_client.discoverAgentProfile)(discoveryClient, signal, complianceIndex.adcp_version);
|
|
824
815
|
if (testOptions.versionEnvelope === void 0 && profile.tools.includes("get_adcp_capabilities") && profile.raw_capabilities === void 0 && !profileStep.error?.startsWith("VERSION_UNSUPPORTED:")) {
|
|
825
816
|
const legacyDiscoveryOptions = { ...effectiveOptions, versionEnvelope: "major-only" };
|
|
826
817
|
const legacyDiscoveryClient = (0, import_client.createTestClient)(
|
|
@@ -834,6 +825,7 @@ async function complyImpl(agentUrl, options) {
|
|
|
834
825
|
discoveryClient = legacyDiscoveryClient;
|
|
835
826
|
profile = legacyDiscovery.profile;
|
|
836
827
|
profileStep = legacyDiscovery.step;
|
|
828
|
+
profileCaughtError = legacyDiscovery.caughtError;
|
|
837
829
|
}
|
|
838
830
|
}
|
|
839
831
|
effectiveOptions = applyNegotiatedComplianceVersionOptions(profile, effectiveOptions, {
|
|
@@ -889,7 +881,14 @@ async function complyImpl(agentUrl, options) {
|
|
|
889
881
|
}
|
|
890
882
|
if (!profileStep.passed) {
|
|
891
883
|
const isVersionUnsupported = profileStep.error?.startsWith("VERSION_UNSUPPORTED:") === true;
|
|
892
|
-
const authCheck = isVersionUnsupported ? { isAuth: false, observations: [] } : await detectAuthRejection(
|
|
884
|
+
const authCheck = isVersionUnsupported ? { isAuth: false, observations: [] } : await detectAuthRejection(
|
|
885
|
+
agentUrl,
|
|
886
|
+
profileStep.error,
|
|
887
|
+
signal,
|
|
888
|
+
effectiveOptions.transport?.trustedFetchFn,
|
|
889
|
+
profileCaughtError,
|
|
890
|
+
effectiveOptions.transport?.allowPrivateIp
|
|
891
|
+
);
|
|
893
892
|
if (authCheck.isAuth) {
|
|
894
893
|
const degraded = { name: profile.name || "Unknown (auth required)", tools: [] };
|
|
895
894
|
const candidate = explicitStoryboards?.length ? resolveExplicitStoryboards(explicitStoryboards, resolveOptions) : resolveFromCapabilities(degraded, resolveOptions).storyboards;
|
|
@@ -917,6 +916,7 @@ async function complyImpl(agentUrl, options) {
|
|
|
917
916
|
start,
|
|
918
917
|
effectiveOptions,
|
|
919
918
|
complianceIndex.adcp_version,
|
|
919
|
+
profileCaughtError,
|
|
920
920
|
signal
|
|
921
921
|
);
|
|
922
922
|
}
|
|
@@ -1106,17 +1106,22 @@ function buildComplyTimeoutBudgetObservation(timeout_ms, storyboardsExecuted, st
|
|
|
1106
1106
|
source: { kind: "profile", code: "timeout-budget-exceeded" }
|
|
1107
1107
|
};
|
|
1108
1108
|
}
|
|
1109
|
-
async function detectAuthRejection(agentUrl, errorMsg, signal, fetchFn) {
|
|
1109
|
+
async function detectAuthRejection(agentUrl, errorMsg, signal, fetchFn, caughtError, allowPrivateIp) {
|
|
1110
1110
|
const err = errorMsg || "Unknown error";
|
|
1111
1111
|
const observations = [];
|
|
1112
1112
|
const lower = err.toLowerCase();
|
|
1113
|
-
const
|
|
1114
|
-
const
|
|
1113
|
+
const hasLegacyAuthSignal = lower.includes("oauth authorization") || lower.includes("requires oauth") || lower.includes("requires authorization") || lower.includes("oauth flow") || lower.includes("oauthflowhandler") || lower.includes("needsauthorizationerror") || lower.includes("www-authenticate") || lower.includes("bearer realm");
|
|
1114
|
+
const hasValidatedOAuthSignal = caughtError instanceof import_authorization_required.NeedsAuthorizationError && (0, import_authorization_required.hasValidatedMcpAuthorizationRequirements)(caughtError.requirements, agentUrl);
|
|
1115
|
+
const isExplicitAuthError = lower.includes("401") || lower.includes("unauthorized") || lower.includes("authentication") || hasLegacyAuthSignal || hasValidatedOAuthSignal || lower.includes("jws") || lower.includes("jwt") || lower.includes("signature verification");
|
|
1115
1116
|
let isAuth = isExplicitAuthError;
|
|
1116
1117
|
if (!isAuth) {
|
|
1117
1118
|
try {
|
|
1118
1119
|
const probeSignal = signal ? AbortSignal.any([signal, AbortSignal.timeout(5e3)]) : AbortSignal.timeout(5e3);
|
|
1119
|
-
const
|
|
1120
|
+
const transportFetch = (0, import_agent_transport_fetch.createAgentTransportFetch)(agentUrl, {
|
|
1121
|
+
trustedFetchFn: fetchFn,
|
|
1122
|
+
allowPrivateIp: allowPrivateIp ?? false
|
|
1123
|
+
});
|
|
1124
|
+
const probe = await transportFetch(agentUrl, {
|
|
1120
1125
|
method: "POST",
|
|
1121
1126
|
headers: { "Content-Type": "application/json" },
|
|
1122
1127
|
redirect: "manual",
|
|
@@ -1127,20 +1132,18 @@ async function detectAuthRejection(agentUrl, errorMsg, signal, fetchFn) {
|
|
|
1127
1132
|
}
|
|
1128
1133
|
}
|
|
1129
1134
|
if (isAuth) {
|
|
1130
|
-
const
|
|
1131
|
-
const
|
|
1132
|
-
trustedFetchFn: fetchFn,
|
|
1133
|
-
allowPrivateIp: (0, import_address_guards.isLikelyPrivateUrl)(agentUrl)
|
|
1134
|
-
});
|
|
1135
|
-
const looksOAuth = oauthMeta !== null || hasOAuthSignal;
|
|
1135
|
+
const oauthRequirements = hasValidatedOAuthSignal ? caughtError.requirements : void 0;
|
|
1136
|
+
const looksOAuth = oauthRequirements !== void 0;
|
|
1136
1137
|
if (looksOAuth) {
|
|
1137
|
-
const issuer =
|
|
1138
|
+
const issuer = oauthRequirements?.authorizationServer ? fenceAgentText((0, import_oauth_metadata_graph.redactOAuthUrlForOutput)(oauthRequirements.authorizationServer), 200) : "(unknown)";
|
|
1138
1139
|
const safeAgentUrl = (0, import_oauth_metadata_graph.redactOAuthUrlForOutput)(agentUrl);
|
|
1139
1140
|
observations.push({
|
|
1140
1141
|
category: "auth",
|
|
1141
1142
|
severity: "error",
|
|
1142
1143
|
message: `Agent requires OAuth (issuer: ${issuer}). Inline: adcp storyboard run ${safeAgentUrl} --oauth (requires a saved alias). Save once: adcp --save-auth <alias> ${safeAgentUrl} --oauth.`,
|
|
1143
|
-
...
|
|
1144
|
+
...oauthRequirements?.authorizationServer && {
|
|
1145
|
+
evidence: { oauth_issuer: (0, import_oauth_metadata_graph.redactOAuthUrlForOutput)(oauthRequirements.authorizationServer) }
|
|
1146
|
+
},
|
|
1144
1147
|
source: { kind: "probe", code: "auth-oauth-required" }
|
|
1145
1148
|
});
|
|
1146
1149
|
} else {
|
|
@@ -1256,9 +1259,16 @@ async function runWithDegradedProfile(agentUrl, profile, storyboards, options, e
|
|
|
1256
1259
|
notices: []
|
|
1257
1260
|
};
|
|
1258
1261
|
}
|
|
1259
|
-
async function buildUnreachableResult(agentUrl, profile, errorMsg, start, effectiveOptions, adcpVersion, signal) {
|
|
1262
|
+
async function buildUnreachableResult(agentUrl, profile, errorMsg, start, effectiveOptions, adcpVersion, caughtError, signal) {
|
|
1260
1263
|
const isVersionUnsupported = errorMsg?.startsWith("VERSION_UNSUPPORTED:") === true;
|
|
1261
|
-
const { isAuth, observations } = isVersionUnsupported ? { isAuth: false, observations: [] } : await detectAuthRejection(
|
|
1264
|
+
const { isAuth, observations } = isVersionUnsupported ? { isAuth: false, observations: [] } : await detectAuthRejection(
|
|
1265
|
+
agentUrl,
|
|
1266
|
+
errorMsg,
|
|
1267
|
+
signal,
|
|
1268
|
+
effectiveOptions.transport?.trustedFetchFn,
|
|
1269
|
+
caughtError,
|
|
1270
|
+
effectiveOptions.transport?.allowPrivateIp
|
|
1271
|
+
);
|
|
1262
1272
|
const err = (0, import_oauth_metadata_graph.redactOAuthUrlsInText)(errorMsg || "Unknown error");
|
|
1263
1273
|
const headline = isAuth ? `Authentication required` : `Agent unreachable \u2014 ${err}`;
|
|
1264
1274
|
return {
|
|
@@ -21,7 +21,11 @@ import { withExternalSchemaRoot } from "../../validation/schema-loader.mjs";
|
|
|
21
21
|
import { redactOAuthUrlForOutput, redactOAuthUrlsInText } from "../storyboard/oauth-metadata-graph/index.mjs";
|
|
22
22
|
import { LIBRARY_VERSION } from "../../version.mjs";
|
|
23
23
|
import { validationFailsStep } from "../storyboard/validations.mjs";
|
|
24
|
-
import {
|
|
24
|
+
import { createAgentTransportFetch } from "../../net/agent-transport-fetch.mjs";
|
|
25
|
+
import {
|
|
26
|
+
hasValidatedMcpAuthorizationRequirements,
|
|
27
|
+
NeedsAuthorizationError
|
|
28
|
+
} from "../../auth/oauth/authorization-required.mjs";
|
|
25
29
|
import { applyFunctionalRequestSigning } from "../storyboard/request-signing/functional-dispatch.mjs";
|
|
26
30
|
const TRACK_ORDER = [
|
|
27
31
|
"core",
|
|
@@ -781,11 +785,11 @@ async function complyImpl(agentUrl, options) {
|
|
|
781
785
|
const allObservations = [];
|
|
782
786
|
let discoveryOptions = effectiveOptions;
|
|
783
787
|
let discoveryClient = createTestClient(agentUrl, effectiveOptions.protocol ?? "mcp", discoveryOptions);
|
|
784
|
-
let {
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
);
|
|
788
|
+
let {
|
|
789
|
+
profile,
|
|
790
|
+
step: profileStep,
|
|
791
|
+
caughtError: profileCaughtError
|
|
792
|
+
} = await discoverAgentProfile(discoveryClient, signal, complianceIndex.adcp_version);
|
|
789
793
|
if (testOptions.versionEnvelope === void 0 && profile.tools.includes("get_adcp_capabilities") && profile.raw_capabilities === void 0 && !profileStep.error?.startsWith("VERSION_UNSUPPORTED:")) {
|
|
790
794
|
const legacyDiscoveryOptions = { ...effectiveOptions, versionEnvelope: "major-only" };
|
|
791
795
|
const legacyDiscoveryClient = createTestClient(
|
|
@@ -799,6 +803,7 @@ async function complyImpl(agentUrl, options) {
|
|
|
799
803
|
discoveryClient = legacyDiscoveryClient;
|
|
800
804
|
profile = legacyDiscovery.profile;
|
|
801
805
|
profileStep = legacyDiscovery.step;
|
|
806
|
+
profileCaughtError = legacyDiscovery.caughtError;
|
|
802
807
|
}
|
|
803
808
|
}
|
|
804
809
|
effectiveOptions = applyNegotiatedComplianceVersionOptions(profile, effectiveOptions, {
|
|
@@ -854,7 +859,14 @@ async function complyImpl(agentUrl, options) {
|
|
|
854
859
|
}
|
|
855
860
|
if (!profileStep.passed) {
|
|
856
861
|
const isVersionUnsupported = profileStep.error?.startsWith("VERSION_UNSUPPORTED:") === true;
|
|
857
|
-
const authCheck = isVersionUnsupported ? { isAuth: false, observations: [] } : await detectAuthRejection(
|
|
862
|
+
const authCheck = isVersionUnsupported ? { isAuth: false, observations: [] } : await detectAuthRejection(
|
|
863
|
+
agentUrl,
|
|
864
|
+
profileStep.error,
|
|
865
|
+
signal,
|
|
866
|
+
effectiveOptions.transport?.trustedFetchFn,
|
|
867
|
+
profileCaughtError,
|
|
868
|
+
effectiveOptions.transport?.allowPrivateIp
|
|
869
|
+
);
|
|
858
870
|
if (authCheck.isAuth) {
|
|
859
871
|
const degraded = { name: profile.name || "Unknown (auth required)", tools: [] };
|
|
860
872
|
const candidate = explicitStoryboards?.length ? resolveExplicitStoryboards(explicitStoryboards, resolveOptions) : resolveFromCapabilities(degraded, resolveOptions).storyboards;
|
|
@@ -882,6 +894,7 @@ async function complyImpl(agentUrl, options) {
|
|
|
882
894
|
start,
|
|
883
895
|
effectiveOptions,
|
|
884
896
|
complianceIndex.adcp_version,
|
|
897
|
+
profileCaughtError,
|
|
885
898
|
signal
|
|
886
899
|
);
|
|
887
900
|
}
|
|
@@ -1071,17 +1084,22 @@ function buildComplyTimeoutBudgetObservation(timeout_ms, storyboardsExecuted, st
|
|
|
1071
1084
|
source: { kind: "profile", code: "timeout-budget-exceeded" }
|
|
1072
1085
|
};
|
|
1073
1086
|
}
|
|
1074
|
-
async function detectAuthRejection(agentUrl, errorMsg, signal, fetchFn) {
|
|
1087
|
+
async function detectAuthRejection(agentUrl, errorMsg, signal, fetchFn, caughtError, allowPrivateIp) {
|
|
1075
1088
|
const err = errorMsg || "Unknown error";
|
|
1076
1089
|
const observations = [];
|
|
1077
1090
|
const lower = err.toLowerCase();
|
|
1078
|
-
const
|
|
1079
|
-
const
|
|
1091
|
+
const hasLegacyAuthSignal = lower.includes("oauth authorization") || lower.includes("requires oauth") || lower.includes("requires authorization") || lower.includes("oauth flow") || lower.includes("oauthflowhandler") || lower.includes("needsauthorizationerror") || lower.includes("www-authenticate") || lower.includes("bearer realm");
|
|
1092
|
+
const hasValidatedOAuthSignal = caughtError instanceof NeedsAuthorizationError && hasValidatedMcpAuthorizationRequirements(caughtError.requirements, agentUrl);
|
|
1093
|
+
const isExplicitAuthError = lower.includes("401") || lower.includes("unauthorized") || lower.includes("authentication") || hasLegacyAuthSignal || hasValidatedOAuthSignal || lower.includes("jws") || lower.includes("jwt") || lower.includes("signature verification");
|
|
1080
1094
|
let isAuth = isExplicitAuthError;
|
|
1081
1095
|
if (!isAuth) {
|
|
1082
1096
|
try {
|
|
1083
1097
|
const probeSignal = signal ? AbortSignal.any([signal, AbortSignal.timeout(5e3)]) : AbortSignal.timeout(5e3);
|
|
1084
|
-
const
|
|
1098
|
+
const transportFetch = createAgentTransportFetch(agentUrl, {
|
|
1099
|
+
trustedFetchFn: fetchFn,
|
|
1100
|
+
allowPrivateIp: allowPrivateIp ?? false
|
|
1101
|
+
});
|
|
1102
|
+
const probe = await transportFetch(agentUrl, {
|
|
1085
1103
|
method: "POST",
|
|
1086
1104
|
headers: { "Content-Type": "application/json" },
|
|
1087
1105
|
redirect: "manual",
|
|
@@ -1092,20 +1110,18 @@ async function detectAuthRejection(agentUrl, errorMsg, signal, fetchFn) {
|
|
|
1092
1110
|
}
|
|
1093
1111
|
}
|
|
1094
1112
|
if (isAuth) {
|
|
1095
|
-
const
|
|
1096
|
-
const
|
|
1097
|
-
trustedFetchFn: fetchFn,
|
|
1098
|
-
allowPrivateIp: isLikelyPrivateUrl(agentUrl)
|
|
1099
|
-
});
|
|
1100
|
-
const looksOAuth = oauthMeta !== null || hasOAuthSignal;
|
|
1113
|
+
const oauthRequirements = hasValidatedOAuthSignal ? caughtError.requirements : void 0;
|
|
1114
|
+
const looksOAuth = oauthRequirements !== void 0;
|
|
1101
1115
|
if (looksOAuth) {
|
|
1102
|
-
const issuer =
|
|
1116
|
+
const issuer = oauthRequirements?.authorizationServer ? fenceAgentText(redactOAuthUrlForOutput(oauthRequirements.authorizationServer), 200) : "(unknown)";
|
|
1103
1117
|
const safeAgentUrl = redactOAuthUrlForOutput(agentUrl);
|
|
1104
1118
|
observations.push({
|
|
1105
1119
|
category: "auth",
|
|
1106
1120
|
severity: "error",
|
|
1107
1121
|
message: `Agent requires OAuth (issuer: ${issuer}). Inline: adcp storyboard run ${safeAgentUrl} --oauth (requires a saved alias). Save once: adcp --save-auth <alias> ${safeAgentUrl} --oauth.`,
|
|
1108
|
-
...
|
|
1122
|
+
...oauthRequirements?.authorizationServer && {
|
|
1123
|
+
evidence: { oauth_issuer: redactOAuthUrlForOutput(oauthRequirements.authorizationServer) }
|
|
1124
|
+
},
|
|
1109
1125
|
source: { kind: "probe", code: "auth-oauth-required" }
|
|
1110
1126
|
});
|
|
1111
1127
|
} else {
|
|
@@ -1221,9 +1237,16 @@ async function runWithDegradedProfile(agentUrl, profile, storyboards, options, e
|
|
|
1221
1237
|
notices: []
|
|
1222
1238
|
};
|
|
1223
1239
|
}
|
|
1224
|
-
async function buildUnreachableResult(agentUrl, profile, errorMsg, start, effectiveOptions, adcpVersion, signal) {
|
|
1240
|
+
async function buildUnreachableResult(agentUrl, profile, errorMsg, start, effectiveOptions, adcpVersion, caughtError, signal) {
|
|
1225
1241
|
const isVersionUnsupported = errorMsg?.startsWith("VERSION_UNSUPPORTED:") === true;
|
|
1226
|
-
const { isAuth, observations } = isVersionUnsupported ? { isAuth: false, observations: [] } : await detectAuthRejection(
|
|
1242
|
+
const { isAuth, observations } = isVersionUnsupported ? { isAuth: false, observations: [] } : await detectAuthRejection(
|
|
1243
|
+
agentUrl,
|
|
1244
|
+
errorMsg,
|
|
1245
|
+
signal,
|
|
1246
|
+
effectiveOptions.transport?.trustedFetchFn,
|
|
1247
|
+
caughtError,
|
|
1248
|
+
effectiveOptions.transport?.allowPrivateIp
|
|
1249
|
+
);
|
|
1227
1250
|
const err = redactOAuthUrlsInText(errorMsg || "Unknown error");
|
|
1228
1251
|
const headline = isAuth ? `Authentication required` : `Agent unreachable \u2014 ${err}`;
|
|
1229
1252
|
return {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { buildProtectedResourceMetadataUrl, normalizeOAuthResourceForComparison, } from '../../../auth/oauth/resource-url.mjs';
|
|
1
2
|
import type { OAuthMetadataGraphGrade } from './types.mjs';
|
|
2
3
|
export interface GradeOAuthMetadataGraphOptions {
|
|
3
4
|
/** Explicit local-development opt-in. Production grading remains HTTPS-only. */
|
|
@@ -6,16 +7,9 @@ export interface GradeOAuthMetadataGraphOptions {
|
|
|
6
7
|
/** Trusted scoped fetch supplied by a hosted runner; it must enforce peer-address binding. */
|
|
7
8
|
trustedFetchFn?: typeof fetch;
|
|
8
9
|
}
|
|
9
|
-
/**
|
|
10
|
-
* Shared RFC 9728 comparison semantics used by security.yaml and oauth_setup.
|
|
11
|
-
* Only scheme and host are case-folded and default ports are elided. The
|
|
12
|
-
* path, query, fragment, userinfo, and trailing slash remain significant.
|
|
13
|
-
*/
|
|
14
|
-
export declare function normalizeOAuthResourceForComparison(value: string): string;
|
|
15
10
|
/** Redact sensitive URL components before including a URL in a report. */
|
|
16
11
|
export declare function redactOAuthUrlForOutput(value: string): string;
|
|
17
12
|
/** Redact absolute URLs embedded in diagnostic text before report serialization. */
|
|
18
13
|
export declare function redactOAuthUrlsInText(value: string): string;
|
|
19
|
-
export declare function buildProtectedResourceMetadataUrl(agentUrl: string): string;
|
|
20
14
|
export declare function buildAuthorizationServerMetadataUrl(issuer: string): string;
|
|
21
15
|
export declare function gradeOAuthMetadataGraph(agentUrl: string, options?: GradeOAuthMetadataGraphOptions): Promise<OAuthMetadataGraphGrade>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { buildProtectedResourceMetadataUrl, normalizeOAuthResourceForComparison, } from '../../../auth/oauth/resource-url';
|
|
1
2
|
import type { OAuthMetadataGraphGrade } from './types';
|
|
2
3
|
export interface GradeOAuthMetadataGraphOptions {
|
|
3
4
|
/** Explicit local-development opt-in. Production grading remains HTTPS-only. */
|
|
@@ -6,16 +7,9 @@ export interface GradeOAuthMetadataGraphOptions {
|
|
|
6
7
|
/** Trusted scoped fetch supplied by a hosted runner; it must enforce peer-address binding. */
|
|
7
8
|
trustedFetchFn?: typeof fetch;
|
|
8
9
|
}
|
|
9
|
-
/**
|
|
10
|
-
* Shared RFC 9728 comparison semantics used by security.yaml and oauth_setup.
|
|
11
|
-
* Only scheme and host are case-folded and default ports are elided. The
|
|
12
|
-
* path, query, fragment, userinfo, and trailing slash remain significant.
|
|
13
|
-
*/
|
|
14
|
-
export declare function normalizeOAuthResourceForComparison(value: string): string;
|
|
15
10
|
/** Redact sensitive URL components before including a URL in a report. */
|
|
16
11
|
export declare function redactOAuthUrlForOutput(value: string): string;
|
|
17
12
|
/** Redact absolute URLs embedded in diagnostic text before report serialization. */
|
|
18
13
|
export declare function redactOAuthUrlsInText(value: string): string;
|
|
19
|
-
export declare function buildProtectedResourceMetadataUrl(agentUrl: string): string;
|
|
20
14
|
export declare function buildAuthorizationServerMetadataUrl(issuer: string): string;
|
|
21
15
|
export declare function gradeOAuthMetadataGraph(agentUrl: string, options?: GradeOAuthMetadataGraphOptions): Promise<OAuthMetadataGraphGrade>;
|
|
@@ -19,16 +19,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
var grader_exports = {};
|
|
20
20
|
__export(grader_exports, {
|
|
21
21
|
buildAuthorizationServerMetadataUrl: () => buildAuthorizationServerMetadataUrl,
|
|
22
|
-
buildProtectedResourceMetadataUrl: () => buildProtectedResourceMetadataUrl,
|
|
22
|
+
buildProtectedResourceMetadataUrl: () => import_resource_url.buildProtectedResourceMetadataUrl,
|
|
23
23
|
gradeOAuthMetadataGraph: () => gradeOAuthMetadataGraph,
|
|
24
24
|
gradeOAuthMetadataGraphWithTransport: () => gradeOAuthMetadataGraphWithTransport,
|
|
25
|
-
normalizeOAuthResourceForComparison: () => normalizeOAuthResourceForComparison,
|
|
25
|
+
normalizeOAuthResourceForComparison: () => import_resource_url.normalizeOAuthResourceForComparison,
|
|
26
26
|
redactOAuthUrlForOutput: () => redactOAuthUrlForOutput,
|
|
27
27
|
redactOAuthUrlsInText: () => redactOAuthUrlsInText
|
|
28
28
|
});
|
|
29
29
|
module.exports = __toCommonJS(grader_exports);
|
|
30
30
|
var import_address_guards = require('../../../net/address-guards.js');
|
|
31
31
|
var import_ssrf_fetch = require('../../../net/ssrf-fetch.js');
|
|
32
|
+
var import_resource_url = require('../../../auth/oauth/resource-url.js');
|
|
33
|
+
var import_resource_url2 = require('../../../auth/oauth/resource-url.js');
|
|
32
34
|
const LIMITS = Object.freeze({
|
|
33
35
|
authorizationServers: 16,
|
|
34
36
|
uniqueUrls: 64,
|
|
@@ -53,40 +55,6 @@ const DIAGNOSTIC_ORDER = Object.freeze([
|
|
|
53
55
|
"oauth_endpoint_unreachable",
|
|
54
56
|
"oauth_jwks_unavailable"
|
|
55
57
|
]);
|
|
56
|
-
function normalizeOAuthResourceForComparison(value) {
|
|
57
|
-
const match = /^([A-Za-z][A-Za-z\d+.-]*):\/\/([^/?#]*)([\s\S]*)$/.exec(value);
|
|
58
|
-
if (!match) return value;
|
|
59
|
-
const scheme = match[1].toLowerCase();
|
|
60
|
-
const authority = match[2];
|
|
61
|
-
const remainder = match[3];
|
|
62
|
-
const at = authority.lastIndexOf("@");
|
|
63
|
-
const userinfo = at >= 0 ? authority.slice(0, at + 1) : "";
|
|
64
|
-
const hostAndPort = at >= 0 ? authority.slice(at + 1) : authority;
|
|
65
|
-
let host;
|
|
66
|
-
let port = "";
|
|
67
|
-
if (hostAndPort.startsWith("[")) {
|
|
68
|
-
const bracket = hostAndPort.indexOf("]");
|
|
69
|
-
if (bracket < 0) return value;
|
|
70
|
-
host = hostAndPort.slice(0, bracket + 1).toLowerCase();
|
|
71
|
-
const suffix = hostAndPort.slice(bracket + 1);
|
|
72
|
-
if (suffix && !/^:\d+$/.test(suffix)) return value;
|
|
73
|
-
port = suffix.slice(1);
|
|
74
|
-
} else {
|
|
75
|
-
const colon = hostAndPort.lastIndexOf(":");
|
|
76
|
-
if (colon >= 0) {
|
|
77
|
-
const suffix = hostAndPort.slice(colon + 1);
|
|
78
|
-
if (!/^\d+$/.test(suffix)) return value;
|
|
79
|
-
host = hostAndPort.slice(0, colon).toLowerCase();
|
|
80
|
-
port = suffix;
|
|
81
|
-
} else {
|
|
82
|
-
host = hostAndPort.toLowerCase();
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
if (!host) return value;
|
|
86
|
-
const defaultPort = scheme === "https" ? "443" : scheme === "http" ? "80" : void 0;
|
|
87
|
-
const renderedPort = port && port !== defaultPort ? `:${port}` : "";
|
|
88
|
-
return `${scheme}://${userinfo}${host}${renderedPort}${remainder}`;
|
|
89
|
-
}
|
|
90
58
|
function redactOAuthUrlForOutput(value) {
|
|
91
59
|
try {
|
|
92
60
|
const u = new URL(value);
|
|
@@ -104,10 +72,6 @@ function redactOAuthUrlForOutput(value) {
|
|
|
104
72
|
function redactOAuthUrlsInText(value) {
|
|
105
73
|
return value.replace(/https?:\/\/[^\s"'<>]+/gi, (url) => redactOAuthUrlForOutput(url));
|
|
106
74
|
}
|
|
107
|
-
function buildProtectedResourceMetadataUrl(agentUrl) {
|
|
108
|
-
const u = new URL(agentUrl);
|
|
109
|
-
return `${u.origin}/.well-known/oauth-protected-resource${u.pathname}`;
|
|
110
|
-
}
|
|
111
75
|
function buildAuthorizationServerMetadataUrl(issuer) {
|
|
112
76
|
const u = new URL(issuer);
|
|
113
77
|
const issuerPath = u.pathname === "/" ? "" : u.pathname;
|
|
@@ -132,7 +96,7 @@ async function gradeOAuthMetadataGraphWithTransport(agentUrl, options = {}) {
|
|
|
132
96
|
const findings = [];
|
|
133
97
|
let protectedResourceUrl;
|
|
134
98
|
try {
|
|
135
|
-
protectedResourceUrl = buildProtectedResourceMetadataUrl(agentUrl);
|
|
99
|
+
protectedResourceUrl = (0, import_resource_url2.buildProtectedResourceMetadataUrl)(agentUrl);
|
|
136
100
|
} catch {
|
|
137
101
|
protectedResourceUrl = redactOAuthUrlForOutput(agentUrl);
|
|
138
102
|
findings.push(finding("oauth_protected_resource_metadata_invalid", "Agent URL is not an absolute URL."));
|
|
@@ -177,7 +141,7 @@ async function gradeOAuthMetadataGraphWithTransport(agentUrl, options = {}) {
|
|
|
177
141
|
"resource"
|
|
178
142
|
)
|
|
179
143
|
);
|
|
180
|
-
} else if (normalizeOAuthResourceForComparison(resource) !== normalizeOAuthResourceForComparison(agentUrl)) {
|
|
144
|
+
} else if ((0, import_resource_url2.normalizeOAuthResourceForComparison)(resource) !== (0, import_resource_url2.normalizeOAuthResourceForComparison)(agentUrl)) {
|
|
181
145
|
findings.push(
|
|
182
146
|
finding(
|
|
183
147
|
"oauth_resource_mismatch",
|