@adcp/sdk 16.1.0 → 16.3.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/AGENTS.md +2 -0
- package/dist/lib/core/AgentClient.js +17 -1
- package/dist/lib/core/AgentClient.mjs +17 -1
- package/dist/lib/core/SingleAgentClient.js +13 -0
- package/dist/lib/core/SingleAgentClient.mjs +13 -0
- package/dist/lib/core/TaskExecutor.js +88 -13
- package/dist/lib/core/TaskExecutor.mjs +89 -14
- package/dist/lib/errors/index.d.mts +34 -0
- package/dist/lib/errors/index.d.ts +34 -0
- package/dist/lib/errors/index.js +11 -0
- package/dist/lib/errors/index.mjs +10 -0
- package/dist/lib/governance/authorization.d.mts +66 -0
- package/dist/lib/governance/authorization.d.ts +66 -0
- package/dist/lib/governance/authorization.js +181 -37
- package/dist/lib/governance/authorization.mjs +183 -36
- package/dist/lib/governance/index.d.mts +2 -2
- package/dist/lib/governance/index.d.ts +2 -2
- package/dist/lib/governance/index.js +4 -2
- package/dist/lib/governance/index.mjs +3 -1
- package/dist/lib/identity-3.3/index.d.mts +1 -0
- package/dist/lib/identity-3.3/index.d.ts +1 -0
- package/dist/lib/identity-3.3/index.js +3 -1
- package/dist/lib/identity-3.3/index.mjs +1 -0
- package/dist/lib/identity-3.3/jws-artifacts.d.mts +147 -0
- package/dist/lib/identity-3.3/jws-artifacts.d.ts +147 -0
- package/dist/lib/identity-3.3/jws-artifacts.js +258 -0
- package/dist/lib/identity-3.3/jws-artifacts.mjs +234 -0
- package/dist/lib/identity-3.3/revocation.d.mts +7 -0
- package/dist/lib/identity-3.3/revocation.d.ts +7 -0
- package/dist/lib/identity-3.3/revocation.js +13 -0
- package/dist/lib/identity-3.3/revocation.mjs +13 -0
- package/dist/lib/index.d.mts +3 -3
- package/dist/lib/index.d.ts +3 -3
- package/dist/lib/index.js +4 -0
- package/dist/lib/index.mjs +4 -0
- package/dist/lib/media-buy/compatibility.d.mts +1 -0
- package/dist/lib/media-buy/compatibility.d.ts +1 -0
- package/dist/lib/media-buy/compatibility.js +33 -10
- package/dist/lib/media-buy/compatibility.mjs +32 -14
- package/dist/lib/negotiation/buyer.js +11 -5
- package/dist/lib/negotiation/buyer.mjs +11 -5
- package/dist/lib/negotiation/types.d.mts +4 -2
- package/dist/lib/negotiation/types.d.ts +4 -2
- package/dist/lib/negotiation/verification.d.mts +15 -6
- package/dist/lib/negotiation/verification.d.ts +15 -6
- package/dist/lib/negotiation/verification.js +146 -27
- package/dist/lib/negotiation/verification.mjs +146 -28
- package/dist/lib/negotiation/version.d.mts +6 -0
- package/dist/lib/negotiation/version.d.ts +6 -0
- package/dist/lib/negotiation/version.js +60 -0
- package/dist/lib/negotiation/version.mjs +33 -0
- package/dist/lib/registry/types.generated.d.mts +24 -1
- package/dist/lib/registry/types.generated.d.ts +24 -1
- package/dist/lib/server/create-adcp-server.js +1 -1
- package/dist/lib/server/create-adcp-server.mjs +1 -1
- package/dist/lib/server/error-arm-tools.d.mts +10 -10
- package/dist/lib/server/error-arm-tools.d.ts +10 -10
- package/dist/lib/server/error-arm-tools.js +22 -58
- package/dist/lib/server/error-arm-tools.mjs +30 -65
- package/dist/lib/server/index.d.mts +2 -2
- package/dist/lib/server/index.d.ts +2 -2
- package/dist/lib/server/index.js +2 -0
- package/dist/lib/server/index.mjs +2 -0
- package/dist/lib/signing/web-bot-auth.js +5 -0
- package/dist/lib/signing/web-bot-auth.mjs +4 -0
- package/dist/lib/testing/compliance/comply.js +17 -0
- package/dist/lib/testing/compliance/comply.mjs +17 -0
- package/dist/lib/testing/index.d.mts +3 -0
- package/dist/lib/testing/index.d.ts +3 -0
- package/dist/lib/testing/index.js +44 -2
- package/dist/lib/testing/index.mjs +42 -0
- package/dist/lib/testing/storyboard/collection-selection.d.mts +259 -0
- package/dist/lib/testing/storyboard/collection-selection.d.ts +259 -0
- package/dist/lib/testing/storyboard/collection-selection.js +384 -0
- package/dist/lib/testing/storyboard/collection-selection.mjs +348 -0
- package/dist/lib/testing/storyboard/context.js +12 -6
- package/dist/lib/testing/storyboard/context.mjs +12 -6
- package/dist/lib/testing/storyboard/fixture-resolution.d.mts +39 -1
- package/dist/lib/testing/storyboard/fixture-resolution.d.ts +39 -1
- package/dist/lib/testing/storyboard/fixture-resolution.js +216 -12
- package/dist/lib/testing/storyboard/fixture-resolution.mjs +218 -12
- package/dist/lib/testing/storyboard/index.d.mts +9 -2
- package/dist/lib/testing/storyboard/index.d.ts +9 -2
- package/dist/lib/testing/storyboard/index.js +51 -2
- package/dist/lib/testing/storyboard/index.mjs +49 -1
- package/dist/lib/testing/storyboard/prepared-fixtures.d.mts +471 -0
- package/dist/lib/testing/storyboard/prepared-fixtures.d.ts +471 -0
- package/dist/lib/testing/storyboard/prepared-fixtures.js +434 -0
- package/dist/lib/testing/storyboard/prepared-fixtures.mjs +389 -0
- package/dist/lib/testing/storyboard/protected-context.d.mts +127 -0
- package/dist/lib/testing/storyboard/protected-context.d.ts +127 -0
- package/dist/lib/testing/storyboard/protected-context.js +301 -0
- package/dist/lib/testing/storyboard/protected-context.mjs +267 -0
- package/dist/lib/testing/storyboard/rejection-hints.js +13 -4
- package/dist/lib/testing/storyboard/rejection-hints.mjs +13 -4
- package/dist/lib/testing/storyboard/runner.d.mts +24 -0
- package/dist/lib/testing/storyboard/runner.d.ts +24 -0
- package/dist/lib/testing/storyboard/runner.js +1061 -105
- package/dist/lib/testing/storyboard/runner.mjs +1075 -106
- package/dist/lib/testing/storyboard/seeding.d.mts +15 -1
- package/dist/lib/testing/storyboard/seeding.d.ts +15 -1
- package/dist/lib/testing/storyboard/seeding.js +272 -12
- package/dist/lib/testing/storyboard/seeding.mjs +274 -13
- package/dist/lib/testing/storyboard/types.d.mts +207 -10
- package/dist/lib/testing/storyboard/types.d.ts +207 -10
- package/dist/lib/testing/storyboard/types.js +1 -1
- package/dist/lib/testing/storyboard/types.mjs +1 -1
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/testing/storyboard/validations.js +95 -0
- package/dist/lib/testing/storyboard/validations.mjs +95 -0
- package/dist/lib/validation/bundled-schema-store.js +5 -0
- package/dist/lib/validation/bundled-schema-store.mjs +4 -0
- package/dist/lib/validation/schema-loader.js +19 -2
- package/dist/lib/validation/schema-loader.mjs +22 -3
- 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/TYPE-SUMMARY.md +2 -2
- package/docs/guides/COLLECTION-FIXTURE-FOUNDATION.md +850 -0
- package/docs/guides/PROPOSAL-TERMS-VERIFICATION.md +66 -0
- package/docs/llms.txt +4 -3
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/docs/migration-agent-identity-3.3.md +51 -6
- package/package.json +6 -4
|
@@ -537,3 +537,37 @@ export declare function extractErrorInfo(error: unknown): {
|
|
|
537
537
|
details?: unknown;
|
|
538
538
|
stack?: string;
|
|
539
539
|
};
|
|
540
|
+
/**
|
|
541
|
+
* Prepared fixture state was refused by the host authorizer.
|
|
542
|
+
*
|
|
543
|
+
* An authorization failure is an ACCESS-CONTROL error, not a grading
|
|
544
|
+
* outcome, so the refused caller gets this and no `StoryboardResult` —
|
|
545
|
+
* not a partial one, not a redacted one. It carries the machine refusal
|
|
546
|
+
* code and nothing else: no fixture identities, no `seller_ids`, no
|
|
547
|
+
* captures, no binding values, no request/response records, and no
|
|
548
|
+
* results from steps that ran before the grant was revoked.
|
|
549
|
+
*
|
|
550
|
+
* The complete, unredacted record — including the synthesized
|
|
551
|
+
* `prepared_fixtures_authorization` check, `fixture_resolutions` with
|
|
552
|
+
* `seller_ids`, and exact request/response records — is handed to the
|
|
553
|
+
* host's `prepared_fixtures_audit_sink` before this is thrown. Where no
|
|
554
|
+
* sink is configured the record is simply not produced to anyone.
|
|
555
|
+
*
|
|
556
|
+
* Hosted entry points should surface this as a 403-style denial.
|
|
557
|
+
*/
|
|
558
|
+
export declare class PreparedFixturesDeniedError extends ADCPError {
|
|
559
|
+
/**
|
|
560
|
+
* Machine refusal code: `authorizer_required` | `untrusted_state` |
|
|
561
|
+
* `contract_version_mismatch` | `authorizer_denied` |
|
|
562
|
+
* `binding_mismatch` | `unauthorized_metadata`.
|
|
563
|
+
*/
|
|
564
|
+
readonly refusalCode: string;
|
|
565
|
+
readonly code = "PREPARED_FIXTURES_DENIED";
|
|
566
|
+
constructor(
|
|
567
|
+
/**
|
|
568
|
+
* Machine refusal code: `authorizer_required` | `untrusted_state` |
|
|
569
|
+
* `contract_version_mismatch` | `authorizer_denied` |
|
|
570
|
+
* `binding_mismatch` | `unauthorized_metadata`.
|
|
571
|
+
*/
|
|
572
|
+
refusalCode: string);
|
|
573
|
+
}
|
package/dist/lib/errors/index.js
CHANGED
|
@@ -39,6 +39,7 @@ __export(errors_exports, {
|
|
|
39
39
|
InvalidContextError: () => InvalidContextError,
|
|
40
40
|
MaxClarificationError: () => MaxClarificationError,
|
|
41
41
|
MissingInputHandlerError: () => MissingInputHandlerError,
|
|
42
|
+
PreparedFixturesDeniedError: () => PreparedFixturesDeniedError,
|
|
42
43
|
ProtocolError: () => ProtocolError,
|
|
43
44
|
ProtocolFeatureUnsupportedError: () => ProtocolFeatureUnsupportedError,
|
|
44
45
|
ResponseTooLargeError: () => ResponseTooLargeError,
|
|
@@ -655,6 +656,15 @@ function extractErrorInfo(error) {
|
|
|
655
656
|
message: String(error)
|
|
656
657
|
};
|
|
657
658
|
}
|
|
659
|
+
class PreparedFixturesDeniedError extends ADCPError {
|
|
660
|
+
constructor(refusalCode) {
|
|
661
|
+
super(`prepared fixture state was refused by the configured authorizer (${refusalCode})`);
|
|
662
|
+
this.refusalCode = refusalCode;
|
|
663
|
+
this.details = { refusal_code: refusalCode };
|
|
664
|
+
}
|
|
665
|
+
refusalCode;
|
|
666
|
+
code = "PREPARED_FIXTURES_DENIED";
|
|
667
|
+
}
|
|
658
668
|
// Annotate the CommonJS export names for ESM import in node:
|
|
659
669
|
0 && (module.exports = {
|
|
660
670
|
ADCPError,
|
|
@@ -678,6 +688,7 @@ function extractErrorInfo(error) {
|
|
|
678
688
|
InvalidContextError,
|
|
679
689
|
MaxClarificationError,
|
|
680
690
|
MissingInputHandlerError,
|
|
691
|
+
PreparedFixturesDeniedError,
|
|
681
692
|
ProtocolError,
|
|
682
693
|
ProtocolFeatureUnsupportedError,
|
|
683
694
|
ResponseTooLargeError,
|
|
@@ -595,6 +595,15 @@ function extractErrorInfo(error) {
|
|
|
595
595
|
message: String(error)
|
|
596
596
|
};
|
|
597
597
|
}
|
|
598
|
+
class PreparedFixturesDeniedError extends ADCPError {
|
|
599
|
+
constructor(refusalCode) {
|
|
600
|
+
super(`prepared fixture state was refused by the configured authorizer (${refusalCode})`);
|
|
601
|
+
this.refusalCode = refusalCode;
|
|
602
|
+
this.details = { refusal_code: refusalCode };
|
|
603
|
+
}
|
|
604
|
+
refusalCode;
|
|
605
|
+
code = "PREPARED_FIXTURES_DENIED";
|
|
606
|
+
}
|
|
598
607
|
export {
|
|
599
608
|
ADCPError,
|
|
600
609
|
AccountAmbiguousError,
|
|
@@ -617,6 +626,7 @@ export {
|
|
|
617
626
|
InvalidContextError,
|
|
618
627
|
MaxClarificationError,
|
|
619
628
|
MissingInputHandlerError,
|
|
629
|
+
PreparedFixturesDeniedError,
|
|
620
630
|
ProtocolError,
|
|
621
631
|
ProtocolFeatureUnsupportedError,
|
|
622
632
|
ResponseTooLargeError,
|
|
@@ -12,7 +12,9 @@ import type { CheckGovernanceRequest, GovernancePhase, PlannedDelivery } from '.
|
|
|
12
12
|
import type { JwksResolver } from '../signing/jwks.mjs';
|
|
13
13
|
import type { ReplayStore } from '../signing/replay.mjs';
|
|
14
14
|
import type { RevocationStore } from '../signing/revocation.mjs';
|
|
15
|
+
import type { RevocationDetail } from '../identity-3.3/types.mjs';
|
|
15
16
|
import { type HttpsJwksResolverOptions } from '../signing/jwks-https.mjs';
|
|
17
|
+
import { type GovernanceKeyArchiveResolver, type JwsArtifactWebBotAuthOptions } from '../identity-3.3/jws-artifacts.mjs';
|
|
16
18
|
export declare const GOVERNANCE_AUTHORIZATION_CRITICAL_CLAIMS: readonly ["authorized_commitment", "authorized_task", "authorized_payload_hash"];
|
|
17
19
|
export type GovernanceAuthorizationCriticalClaim = (typeof GOVERNANCE_AUTHORIZATION_CRITICAL_CLAIMS)[number];
|
|
18
20
|
export type GovernanceEnforcementMode = 'signed_context' | 'online_execution_check';
|
|
@@ -51,6 +53,12 @@ export interface GovernanceAuthorizationFailure {
|
|
|
51
53
|
ok: false;
|
|
52
54
|
error: GovernanceAuthorizationErrorCode;
|
|
53
55
|
message: string;
|
|
56
|
+
/**
|
|
57
|
+
* Set when the failure is an outage (an issuer trust record, key directory,
|
|
58
|
+
* archive or revocation list could not be read), not a verdict on the
|
|
59
|
+
* token: the same token may verify on retry.
|
|
60
|
+
*/
|
|
61
|
+
retryable?: true;
|
|
54
62
|
}
|
|
55
63
|
export type GovernanceAuthorizationResult = GovernanceAuthorizationSuccess | GovernanceAuthorizationFailure;
|
|
56
64
|
export interface GovernanceReplayStore {
|
|
@@ -127,6 +135,18 @@ export interface VerifyGovernanceAuthorizationOptions {
|
|
|
127
135
|
jwks?: JwksResolver;
|
|
128
136
|
/** When supplied, discover keys from this exact authenticated buyer record. */
|
|
129
137
|
buyerIdentity?: GovernanceBuyerIdentity;
|
|
138
|
+
/**
|
|
139
|
+
* AdCP 3.3 (`specs/agent-identity-3-3.md` R4): when the trust record derived
|
|
140
|
+
* from the issuer's origin lists that origin, verify the token with a key
|
|
141
|
+
* from the origin's Web Bot Auth key directory (`alg` `EdDSA`, `kid` the
|
|
142
|
+
* key's JWK thumbprint, no `use`/`key_ops`/`adcp_use` checks) and check
|
|
143
|
+
* revocation against the origin's list, never under the 3.2 profile. A
|
|
144
|
+
* trust-record fetch failure rejects the token; it never falls back to 3.2.
|
|
145
|
+
* An issuer no trust record lists stays on the 3.2 profile (`jwks` or
|
|
146
|
+
* `buyerIdentity`). Every other check is unchanged, including the
|
|
147
|
+
* `buyerIdentity` cross-check that the issuer is the buyer's governance agent.
|
|
148
|
+
*/
|
|
149
|
+
webBotAuth?: JwsArtifactWebBotAuthOptions;
|
|
130
150
|
replayStore: GovernanceReplayStore;
|
|
131
151
|
/** Optional governance-key revocation source. */
|
|
132
152
|
revocationStore?: RevocationStore;
|
|
@@ -187,6 +207,52 @@ export declare function targetDeclaresGovernanceEnforcement(capabilities: unknow
|
|
|
187
207
|
export declare function targetDeclaresLegacyGovernanceAwareness(capabilities: unknown, task: string): boolean;
|
|
188
208
|
/** Verify the published compact-JWS authorization profile and all service bindings. */
|
|
189
209
|
export declare function verifyGovernanceAuthorization(options: VerifyGovernanceAuthorizationOptions): Promise<GovernanceAuthorizationResult>;
|
|
210
|
+
export interface VerifyHistoricalGovernanceContextOptions {
|
|
211
|
+
token: unknown;
|
|
212
|
+
/** The governance agent the verifier expected to sign, from its own records. */
|
|
213
|
+
expectedIssuer: string;
|
|
214
|
+
/**
|
|
215
|
+
* The WBA components plus the governance key archive at the issuer's
|
|
216
|
+
* origin (`{origin}/.well-known/jwks-archive.json`, `security.mdx`
|
|
217
|
+
* §Revocation), which holds keys rotated out of the directory.
|
|
218
|
+
*/
|
|
219
|
+
webBotAuth: JwsArtifactWebBotAuthOptions & {
|
|
220
|
+
archive: GovernanceKeyArchiveResolver;
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
export type HistoricalGovernanceContextResult = {
|
|
224
|
+
ok: true;
|
|
225
|
+
claims: GovernanceAuthorizationClaims;
|
|
226
|
+
protectedHeader: Record<string, unknown>;
|
|
227
|
+
/** The key was in the issuer's current directory, or only in its archive. */
|
|
228
|
+
keySource: 'directory' | 'archive';
|
|
229
|
+
/**
|
|
230
|
+
* The issuer origin's revocation status for the signing key: `current`
|
|
231
|
+
* (listed, not revoked), `absent` (the origin serves no list) or
|
|
232
|
+
* `revoked`. Online verification rejects every token a revoked key
|
|
233
|
+
* signed; an audit decides what a revocation means for a retained token
|
|
234
|
+
* from its detail (R9: only `keyCompromise` exposes, from its
|
|
235
|
+
* `invalidity_date`).
|
|
236
|
+
*/
|
|
237
|
+
revocation: 'current' | 'absent' | 'revoked';
|
|
238
|
+
revocationDetail?: RevocationDetail;
|
|
239
|
+
} | (GovernanceAuthorizationFailure & {
|
|
240
|
+
/** Set when the issuer is on the 3.2 profile, which this function does not verify. */
|
|
241
|
+
profile?: '3.2';
|
|
242
|
+
});
|
|
243
|
+
/**
|
|
244
|
+
* Historical (audit) verification of a retained governance context from a
|
|
245
|
+
* Web Bot Auth identity (R4): the key comes from the issuer origin's key
|
|
246
|
+
* directory or, once rotated out, from its governance key archive. Checks the
|
|
247
|
+
* token's shape, `typ`, `crit`, issuer, `alg` `EdDSA`, `kid` thumbprint and
|
|
248
|
+
* signature, and reports the origin's revocation status and detail for the
|
|
249
|
+
* key instead of rejecting a revoked one. It does not check expiry, audience,
|
|
250
|
+
* replay or the request binding, which only an online verification can.
|
|
251
|
+
*
|
|
252
|
+
* Profile selection is the same as online: an issuer whose origin no trust
|
|
253
|
+
* record lists is on the 3.2 profile, reported as `profile: '3.2'`.
|
|
254
|
+
*/
|
|
255
|
+
export declare function verifyHistoricalGovernanceContext(options: VerifyHistoricalGovernanceContextOptions): Promise<HistoricalGovernanceContextResult>;
|
|
190
256
|
export declare class GovernanceAuthorizationError extends Error {
|
|
191
257
|
readonly code: GovernanceAuthorizationErrorCode;
|
|
192
258
|
constructor(result: GovernanceAuthorizationFailure);
|
|
@@ -12,7 +12,9 @@ import type { CheckGovernanceRequest, GovernancePhase, PlannedDelivery } from '.
|
|
|
12
12
|
import type { JwksResolver } from '../signing/jwks';
|
|
13
13
|
import type { ReplayStore } from '../signing/replay';
|
|
14
14
|
import type { RevocationStore } from '../signing/revocation';
|
|
15
|
+
import type { RevocationDetail } from '../identity-3.3/types';
|
|
15
16
|
import { type HttpsJwksResolverOptions } from '../signing/jwks-https';
|
|
17
|
+
import { type GovernanceKeyArchiveResolver, type JwsArtifactWebBotAuthOptions } from '../identity-3.3/jws-artifacts';
|
|
16
18
|
export declare const GOVERNANCE_AUTHORIZATION_CRITICAL_CLAIMS: readonly ["authorized_commitment", "authorized_task", "authorized_payload_hash"];
|
|
17
19
|
export type GovernanceAuthorizationCriticalClaim = (typeof GOVERNANCE_AUTHORIZATION_CRITICAL_CLAIMS)[number];
|
|
18
20
|
export type GovernanceEnforcementMode = 'signed_context' | 'online_execution_check';
|
|
@@ -51,6 +53,12 @@ export interface GovernanceAuthorizationFailure {
|
|
|
51
53
|
ok: false;
|
|
52
54
|
error: GovernanceAuthorizationErrorCode;
|
|
53
55
|
message: string;
|
|
56
|
+
/**
|
|
57
|
+
* Set when the failure is an outage (an issuer trust record, key directory,
|
|
58
|
+
* archive or revocation list could not be read), not a verdict on the
|
|
59
|
+
* token: the same token may verify on retry.
|
|
60
|
+
*/
|
|
61
|
+
retryable?: true;
|
|
54
62
|
}
|
|
55
63
|
export type GovernanceAuthorizationResult = GovernanceAuthorizationSuccess | GovernanceAuthorizationFailure;
|
|
56
64
|
export interface GovernanceReplayStore {
|
|
@@ -127,6 +135,18 @@ export interface VerifyGovernanceAuthorizationOptions {
|
|
|
127
135
|
jwks?: JwksResolver;
|
|
128
136
|
/** When supplied, discover keys from this exact authenticated buyer record. */
|
|
129
137
|
buyerIdentity?: GovernanceBuyerIdentity;
|
|
138
|
+
/**
|
|
139
|
+
* AdCP 3.3 (`specs/agent-identity-3-3.md` R4): when the trust record derived
|
|
140
|
+
* from the issuer's origin lists that origin, verify the token with a key
|
|
141
|
+
* from the origin's Web Bot Auth key directory (`alg` `EdDSA`, `kid` the
|
|
142
|
+
* key's JWK thumbprint, no `use`/`key_ops`/`adcp_use` checks) and check
|
|
143
|
+
* revocation against the origin's list, never under the 3.2 profile. A
|
|
144
|
+
* trust-record fetch failure rejects the token; it never falls back to 3.2.
|
|
145
|
+
* An issuer no trust record lists stays on the 3.2 profile (`jwks` or
|
|
146
|
+
* `buyerIdentity`). Every other check is unchanged, including the
|
|
147
|
+
* `buyerIdentity` cross-check that the issuer is the buyer's governance agent.
|
|
148
|
+
*/
|
|
149
|
+
webBotAuth?: JwsArtifactWebBotAuthOptions;
|
|
130
150
|
replayStore: GovernanceReplayStore;
|
|
131
151
|
/** Optional governance-key revocation source. */
|
|
132
152
|
revocationStore?: RevocationStore;
|
|
@@ -187,6 +207,52 @@ export declare function targetDeclaresGovernanceEnforcement(capabilities: unknow
|
|
|
187
207
|
export declare function targetDeclaresLegacyGovernanceAwareness(capabilities: unknown, task: string): boolean;
|
|
188
208
|
/** Verify the published compact-JWS authorization profile and all service bindings. */
|
|
189
209
|
export declare function verifyGovernanceAuthorization(options: VerifyGovernanceAuthorizationOptions): Promise<GovernanceAuthorizationResult>;
|
|
210
|
+
export interface VerifyHistoricalGovernanceContextOptions {
|
|
211
|
+
token: unknown;
|
|
212
|
+
/** The governance agent the verifier expected to sign, from its own records. */
|
|
213
|
+
expectedIssuer: string;
|
|
214
|
+
/**
|
|
215
|
+
* The WBA components plus the governance key archive at the issuer's
|
|
216
|
+
* origin (`{origin}/.well-known/jwks-archive.json`, `security.mdx`
|
|
217
|
+
* §Revocation), which holds keys rotated out of the directory.
|
|
218
|
+
*/
|
|
219
|
+
webBotAuth: JwsArtifactWebBotAuthOptions & {
|
|
220
|
+
archive: GovernanceKeyArchiveResolver;
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
export type HistoricalGovernanceContextResult = {
|
|
224
|
+
ok: true;
|
|
225
|
+
claims: GovernanceAuthorizationClaims;
|
|
226
|
+
protectedHeader: Record<string, unknown>;
|
|
227
|
+
/** The key was in the issuer's current directory, or only in its archive. */
|
|
228
|
+
keySource: 'directory' | 'archive';
|
|
229
|
+
/**
|
|
230
|
+
* The issuer origin's revocation status for the signing key: `current`
|
|
231
|
+
* (listed, not revoked), `absent` (the origin serves no list) or
|
|
232
|
+
* `revoked`. Online verification rejects every token a revoked key
|
|
233
|
+
* signed; an audit decides what a revocation means for a retained token
|
|
234
|
+
* from its detail (R9: only `keyCompromise` exposes, from its
|
|
235
|
+
* `invalidity_date`).
|
|
236
|
+
*/
|
|
237
|
+
revocation: 'current' | 'absent' | 'revoked';
|
|
238
|
+
revocationDetail?: RevocationDetail;
|
|
239
|
+
} | (GovernanceAuthorizationFailure & {
|
|
240
|
+
/** Set when the issuer is on the 3.2 profile, which this function does not verify. */
|
|
241
|
+
profile?: '3.2';
|
|
242
|
+
});
|
|
243
|
+
/**
|
|
244
|
+
* Historical (audit) verification of a retained governance context from a
|
|
245
|
+
* Web Bot Auth identity (R4): the key comes from the issuer origin's key
|
|
246
|
+
* directory or, once rotated out, from its governance key archive. Checks the
|
|
247
|
+
* token's shape, `typ`, `crit`, issuer, `alg` `EdDSA`, `kid` thumbprint and
|
|
248
|
+
* signature, and reports the origin's revocation status and detail for the
|
|
249
|
+
* key instead of rejecting a revoked one. It does not check expiry, audience,
|
|
250
|
+
* replay or the request binding, which only an online verification can.
|
|
251
|
+
*
|
|
252
|
+
* Profile selection is the same as online: an issuer whose origin no trust
|
|
253
|
+
* record lists is on the 3.2 profile, reported as `profile: '3.2'`.
|
|
254
|
+
*/
|
|
255
|
+
export declare function verifyHistoricalGovernanceContext(options: VerifyHistoricalGovernanceContextOptions): Promise<HistoricalGovernanceContextResult>;
|
|
190
256
|
export declare class GovernanceAuthorizationError extends Error {
|
|
191
257
|
readonly code: GovernanceAuthorizationErrorCode;
|
|
192
258
|
constructor(result: GovernanceAuthorizationFailure);
|
|
@@ -35,7 +35,8 @@ __export(authorization_exports, {
|
|
|
35
35
|
governanceTaskRequiresProposedCommitment: () => governanceTaskRequiresProposedCommitment,
|
|
36
36
|
targetDeclaresGovernanceEnforcement: () => targetDeclaresGovernanceEnforcement,
|
|
37
37
|
targetDeclaresLegacyGovernanceAwareness: () => targetDeclaresLegacyGovernanceAwareness,
|
|
38
|
-
verifyGovernanceAuthorization: () => verifyGovernanceAuthorization
|
|
38
|
+
verifyGovernanceAuthorization: () => verifyGovernanceAuthorization,
|
|
39
|
+
verifyHistoricalGovernanceContext: () => verifyHistoricalGovernanceContext
|
|
39
40
|
});
|
|
40
41
|
module.exports = __toCommonJS(authorization_exports);
|
|
41
42
|
var import_node_crypto = require("node:crypto");
|
|
@@ -44,11 +45,18 @@ var import_jcs = require('../utils/jcs.js');
|
|
|
44
45
|
var import_jwks_https = require('../signing/jwks-https.js');
|
|
45
46
|
var import_select_agent = require('../signing/agent-resolver/select-agent.js');
|
|
46
47
|
var import_strict_json = require('../signing/agent-resolver/strict-json.js');
|
|
48
|
+
var import_jws_artifacts = require('../identity-3.3/jws-artifacts.js');
|
|
47
49
|
const GOVERNANCE_AUTHORIZATION_CRITICAL_CLAIMS = Object.freeze([
|
|
48
50
|
"authorized_commitment",
|
|
49
51
|
"authorized_task",
|
|
50
52
|
"authorized_payload_hash"
|
|
51
53
|
]);
|
|
54
|
+
const GOVERNANCE_JWS_TYP = "adcp-gov+jws";
|
|
55
|
+
const GOVERNANCE_CRIT = {
|
|
56
|
+
authorized_commitment: true,
|
|
57
|
+
authorized_task: true,
|
|
58
|
+
authorized_payload_hash: true
|
|
59
|
+
};
|
|
52
60
|
class GovernanceReplayStoreAdapter {
|
|
53
61
|
constructor(replayStore) {
|
|
54
62
|
this.replayStore = replayStore;
|
|
@@ -282,27 +290,19 @@ function targetDeclaresLegacyGovernanceAwareness(capabilities, task) {
|
|
|
282
290
|
const mediaBuy = isRecord(root?.media_buy) ? root.media_buy : void 0;
|
|
283
291
|
return mediaBuy?.governance_aware === true;
|
|
284
292
|
}
|
|
285
|
-
|
|
293
|
+
function parseGovernanceJws(token, expectedIssuer) {
|
|
286
294
|
const reject = (error, message) => ({
|
|
287
295
|
ok: false,
|
|
288
296
|
error,
|
|
289
297
|
message
|
|
290
298
|
});
|
|
291
|
-
if (
|
|
292
|
-
return reject("governance_token_invalid", "Authenticated caller is required");
|
|
293
|
-
}
|
|
294
|
-
try {
|
|
295
|
-
buildGovernanceCommitment(options.actualCommitment.amount, options.actualCommitment.currency);
|
|
296
|
-
} catch (error) {
|
|
297
|
-
return reject("governance_token_invalid", error.message);
|
|
298
|
-
}
|
|
299
|
-
if (typeof options.token !== "string" || options.token.length === 0) {
|
|
299
|
+
if (typeof token !== "string" || token.length === 0) {
|
|
300
300
|
return reject("governance_token_invalid", "governance_context is required");
|
|
301
301
|
}
|
|
302
|
-
if (
|
|
302
|
+
if (token.length > 4096) {
|
|
303
303
|
return reject("governance_token_invalid", "governance_context exceeds the protocol size limit");
|
|
304
304
|
}
|
|
305
|
-
const parts =
|
|
305
|
+
const parts = token.split(".");
|
|
306
306
|
if (parts.length !== 3 || parts.some((part) => !part || !/^[A-Za-z0-9_-]+$/.test(part))) {
|
|
307
307
|
return reject("governance_token_invalid", "governance_context is not a compact JWS");
|
|
308
308
|
}
|
|
@@ -315,7 +315,7 @@ async function verifyGovernanceAuthorization(options) {
|
|
|
315
315
|
if (alg !== "EdDSA" && alg !== "ES256") {
|
|
316
316
|
return reject("governance_token_invalid", "Unsupported governance JWS algorithm");
|
|
317
317
|
}
|
|
318
|
-
if (protectedHeader.typ !==
|
|
318
|
+
if (protectedHeader.typ !== GOVERNANCE_JWS_TYP) {
|
|
319
319
|
return reject("governance_token_invalid", "Invalid governance JWS typ");
|
|
320
320
|
}
|
|
321
321
|
const critical = protectedHeader.crit;
|
|
@@ -343,35 +343,71 @@ async function verifyGovernanceAuthorization(options) {
|
|
|
343
343
|
try {
|
|
344
344
|
if (typeof decodedClaims.iss !== "string") throw new TypeError("Missing issuer");
|
|
345
345
|
canonicalIssuer = (0, import_select_agent.canonicalAgentUrl)(decodedClaims.iss);
|
|
346
|
-
if (canonicalIssuer !== (0, import_select_agent.canonicalAgentUrl)(
|
|
346
|
+
if (canonicalIssuer !== (0, import_select_agent.canonicalAgentUrl)(expectedIssuer)) throw new TypeError("Issuer mismatch");
|
|
347
347
|
} catch {
|
|
348
348
|
return reject("governance_token_invalid", "Governance token issuer mismatch");
|
|
349
349
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
350
|
+
return { ok: true, token, protectedHeader, decodedClaims, canonicalIssuer, alg };
|
|
351
|
+
}
|
|
352
|
+
async function verifyGovernanceAuthorization(options) {
|
|
353
|
+
const reject = (error, message) => ({
|
|
354
|
+
ok: false,
|
|
355
|
+
error,
|
|
356
|
+
message
|
|
357
|
+
});
|
|
358
|
+
if (!options.authenticatedCaller) {
|
|
359
|
+
return reject("governance_token_invalid", "Authenticated caller is required");
|
|
360
|
+
}
|
|
353
361
|
try {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
} catch {
|
|
358
|
-
return reject("governance_key_unknown", "Governance signing key could not be resolved");
|
|
362
|
+
buildGovernanceCommitment(options.actualCommitment.amount, options.actualCommitment.currency);
|
|
363
|
+
} catch (error) {
|
|
364
|
+
return reject("governance_token_invalid", error.message);
|
|
359
365
|
}
|
|
360
|
-
|
|
361
|
-
|
|
366
|
+
const parsed = parseGovernanceJws(options.token, options.expectedIssuer);
|
|
367
|
+
if (!parsed.ok) return parsed;
|
|
368
|
+
const { protectedHeader, decodedClaims, canonicalIssuer, alg } = parsed;
|
|
369
|
+
const kid = typeof protectedHeader.kid === "string" ? protectedHeader.kid : "";
|
|
370
|
+
if (!kid) return reject("governance_key_unknown", "Governance signing kid is missing");
|
|
371
|
+
let profile;
|
|
372
|
+
if (options.webBotAuth) {
|
|
373
|
+
try {
|
|
374
|
+
profile = await (0, import_jws_artifacts.selectJwsArtifactProfile)(options.expectedIssuer, options.webBotAuth.trust);
|
|
375
|
+
} catch {
|
|
376
|
+
return { ...reject("governance_key_unknown", "Governance issuer trust record is unavailable"), retryable: true };
|
|
377
|
+
}
|
|
362
378
|
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
authorized_payload_hash: true
|
|
379
|
+
if (profile?.profile === "web-bot-auth") {
|
|
380
|
+
if (options.buyerIdentity) {
|
|
381
|
+
try {
|
|
382
|
+
const record = (0, import_select_agent.relyingPartyAgentRecord)(options.buyerIdentity.brandJson, options.buyerIdentity.brandDomain);
|
|
383
|
+
(0, import_select_agent.selectAgentByUrl)(record, canonicalIssuer, { agentType: "governance" });
|
|
384
|
+
} catch {
|
|
385
|
+
return reject("governance_key_unknown", "Governance issuer is not the buyer's governance agent");
|
|
371
386
|
}
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
|
|
387
|
+
}
|
|
388
|
+
const failure = await verifyGovernanceJwsOnWebBotAuth(options.token, profile.origin, options.webBotAuth);
|
|
389
|
+
if (failure) return failure;
|
|
390
|
+
} else {
|
|
391
|
+
let jwk;
|
|
392
|
+
try {
|
|
393
|
+
const resolver = options.buyerIdentity ? createGovernanceAgentJwksResolver(canonicalIssuer, options.buyerIdentity) : options.jwks;
|
|
394
|
+
if (!resolver) return reject("governance_key_unknown", "No governance key resolver or buyer identity configured");
|
|
395
|
+
jwk = await resolver.resolve(kid);
|
|
396
|
+
} catch {
|
|
397
|
+
return reject("governance_key_unknown", "Governance signing key could not be resolved");
|
|
398
|
+
}
|
|
399
|
+
if (!jwk || jwk.adcp_use !== "governance-signing" || jwk.use !== "sig" || !jwk.key_ops?.includes("verify") || jwk.alg !== void 0 && jwk.alg !== alg) {
|
|
400
|
+
return reject("governance_key_unknown", "Governance signing key is unknown or not authorized");
|
|
401
|
+
}
|
|
402
|
+
try {
|
|
403
|
+
const key = await (0, import_jose.importJWK)(jwk, alg);
|
|
404
|
+
await (0, import_jose.compactVerify)(options.token, key, {
|
|
405
|
+
algorithms: [alg],
|
|
406
|
+
crit: GOVERNANCE_CRIT
|
|
407
|
+
});
|
|
408
|
+
} catch {
|
|
409
|
+
return reject("governance_token_invalid", "Governance token signature verification failed");
|
|
410
|
+
}
|
|
375
411
|
}
|
|
376
412
|
try {
|
|
377
413
|
if (options.revocationStore && await options.revocationStore.isRevoked(kid)) {
|
|
@@ -529,6 +565,113 @@ async function verifyGovernanceAuthorization(options) {
|
|
|
529
565
|
payloadHash
|
|
530
566
|
};
|
|
531
567
|
}
|
|
568
|
+
function governanceFailureFromJwsArtifact(error) {
|
|
569
|
+
if (!(error instanceof import_jws_artifacts.JwsArtifactError))
|
|
570
|
+
return {
|
|
571
|
+
ok: false,
|
|
572
|
+
error: "governance_key_unknown",
|
|
573
|
+
message: "Governance signing key could not be resolved",
|
|
574
|
+
retryable: true
|
|
575
|
+
};
|
|
576
|
+
switch (error.code) {
|
|
577
|
+
case "jws_key_revoked":
|
|
578
|
+
return { ok: false, error: "governance_token_revoked", message: "Governance signing key is revoked" };
|
|
579
|
+
case "jws_revocation_unavailable":
|
|
580
|
+
return {
|
|
581
|
+
ok: false,
|
|
582
|
+
error: "governance_token_revoked",
|
|
583
|
+
message: "Governance revocation status could not be established",
|
|
584
|
+
retryable: true
|
|
585
|
+
};
|
|
586
|
+
case "jws_invalid":
|
|
587
|
+
return {
|
|
588
|
+
ok: false,
|
|
589
|
+
error: "governance_token_invalid",
|
|
590
|
+
message: `Governance token verification failed: ${error.message}`
|
|
591
|
+
};
|
|
592
|
+
case "jws_key_unavailable":
|
|
593
|
+
return {
|
|
594
|
+
ok: false,
|
|
595
|
+
error: "governance_key_unknown",
|
|
596
|
+
message: "Governance signing key could not be resolved",
|
|
597
|
+
retryable: true
|
|
598
|
+
};
|
|
599
|
+
default:
|
|
600
|
+
return { ok: false, error: "governance_key_unknown", message: "Governance signing key could not be resolved" };
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
const NO_ORIGIN_REVOCATION = Object.freeze({
|
|
604
|
+
ok: false,
|
|
605
|
+
error: "governance_token_revoked",
|
|
606
|
+
message: "No origin revocation source is configured for the Web Bot Auth path"
|
|
607
|
+
});
|
|
608
|
+
async function verifyGovernanceJwsOnWebBotAuth(token, origin, webBotAuth) {
|
|
609
|
+
if (!webBotAuth.revocation) return { ...NO_ORIGIN_REVOCATION };
|
|
610
|
+
try {
|
|
611
|
+
await (0, import_jws_artifacts.verifyWebBotAuthJwsArtifact)(token, origin, {
|
|
612
|
+
typ: GOVERNANCE_JWS_TYP,
|
|
613
|
+
directory: webBotAuth.directory,
|
|
614
|
+
revocation: webBotAuth.revocation,
|
|
615
|
+
// A governance context authorizes spend: an origin that serves no list fails closed.
|
|
616
|
+
revocationAbsent: "reject",
|
|
617
|
+
crit: GOVERNANCE_CRIT
|
|
618
|
+
});
|
|
619
|
+
return void 0;
|
|
620
|
+
} catch (error) {
|
|
621
|
+
return governanceFailureFromJwsArtifact(error);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
async function verifyHistoricalGovernanceContext(options) {
|
|
625
|
+
const parsed = parseGovernanceJws(options.token, options.expectedIssuer);
|
|
626
|
+
if (!parsed.ok) return parsed;
|
|
627
|
+
if (parsed.alg !== "EdDSA")
|
|
628
|
+
return {
|
|
629
|
+
ok: false,
|
|
630
|
+
error: "governance_token_invalid",
|
|
631
|
+
message: "A Web Bot Auth governance context uses alg EdDSA"
|
|
632
|
+
};
|
|
633
|
+
if (!options.webBotAuth.revocation) return { ...NO_ORIGIN_REVOCATION };
|
|
634
|
+
let profile;
|
|
635
|
+
try {
|
|
636
|
+
profile = await (0, import_jws_artifacts.selectJwsArtifactProfile)(options.expectedIssuer, options.webBotAuth.trust);
|
|
637
|
+
} catch {
|
|
638
|
+
return {
|
|
639
|
+
ok: false,
|
|
640
|
+
error: "governance_key_unknown",
|
|
641
|
+
message: "Governance issuer trust record is unavailable",
|
|
642
|
+
retryable: true
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
if (profile.profile !== "web-bot-auth")
|
|
646
|
+
return {
|
|
647
|
+
ok: false,
|
|
648
|
+
error: "governance_key_unknown",
|
|
649
|
+
message: "Governance issuer is on the 3.2 profile; its trust record does not list its origin",
|
|
650
|
+
profile: "3.2"
|
|
651
|
+
};
|
|
652
|
+
try {
|
|
653
|
+
const verified = await (0, import_jws_artifacts.verifyWebBotAuthJwsArtifact)(parsed.token, profile.origin, {
|
|
654
|
+
typ: GOVERNANCE_JWS_TYP,
|
|
655
|
+
directory: options.webBotAuth.directory,
|
|
656
|
+
archive: options.webBotAuth.archive,
|
|
657
|
+
revocation: options.webBotAuth.revocation,
|
|
658
|
+
// No spend rides on an audit: an origin that serves no list has revoked nothing.
|
|
659
|
+
revocationAbsent: "accept",
|
|
660
|
+
revokedKey: "report",
|
|
661
|
+
crit: GOVERNANCE_CRIT
|
|
662
|
+
});
|
|
663
|
+
return {
|
|
664
|
+
ok: true,
|
|
665
|
+
claims: parsed.decodedClaims,
|
|
666
|
+
protectedHeader: parsed.protectedHeader,
|
|
667
|
+
keySource: verified.keySource,
|
|
668
|
+
revocation: verified.revocation,
|
|
669
|
+
...verified.revocationDetail ? { revocationDetail: verified.revocationDetail } : {}
|
|
670
|
+
};
|
|
671
|
+
} catch (error) {
|
|
672
|
+
return governanceFailureFromJwsArtifact(error);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
532
675
|
class GovernanceAuthorizationError extends Error {
|
|
533
676
|
code;
|
|
534
677
|
constructor(result) {
|
|
@@ -585,5 +728,6 @@ function decodeJsonObject(segment) {
|
|
|
585
728
|
governanceTaskRequiresProposedCommitment,
|
|
586
729
|
targetDeclaresGovernanceEnforcement,
|
|
587
730
|
targetDeclaresLegacyGovernanceAwareness,
|
|
588
|
-
verifyGovernanceAuthorization
|
|
731
|
+
verifyGovernanceAuthorization,
|
|
732
|
+
verifyHistoricalGovernanceContext
|
|
589
733
|
});
|