@kya-os/mcp-i-core 1.2.3-canary.6 → 1.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/.claude/settings.local.json +9 -0
- package/.turbo/turbo-build.log +4 -0
- package/.turbo/turbo-test$colon$coverage.log +4514 -0
- package/.turbo/turbo-test.log +2973 -0
- package/COMPLIANCE_IMPROVEMENT_REPORT.md +483 -0
- package/Composer 3.md +615 -0
- package/GPT-5.md +1169 -0
- package/OPUS-plan.md +352 -0
- package/PHASE_3_AND_4.1_SUMMARY.md +585 -0
- package/PHASE_3_SUMMARY.md +317 -0
- package/PHASE_4.1.3_SUMMARY.md +428 -0
- package/PHASE_4.1_COMPLETE.md +525 -0
- package/PHASE_4_USER_DID_IDENTITY_LINKING_PLAN.md +1240 -0
- package/SCHEMA_COMPLIANCE_REPORT.md +275 -0
- package/TEST_PLAN.md +571 -0
- package/coverage/coverage-final.json +57 -0
- package/dist/__tests__/utils/mock-providers.d.ts +1 -2
- package/dist/__tests__/utils/mock-providers.d.ts.map +1 -1
- package/dist/__tests__/utils/mock-providers.js.map +1 -1
- package/dist/cache/oauth-config-cache.d.ts +69 -0
- package/dist/cache/oauth-config-cache.d.ts.map +1 -0
- package/dist/cache/oauth-config-cache.js +76 -0
- package/dist/cache/oauth-config-cache.js.map +1 -0
- package/dist/identity/idp-token-resolver.d.ts +53 -0
- package/dist/identity/idp-token-resolver.d.ts.map +1 -0
- package/dist/identity/idp-token-resolver.js +108 -0
- package/dist/identity/idp-token-resolver.js.map +1 -0
- package/dist/identity/idp-token-storage.interface.d.ts +42 -0
- package/dist/identity/idp-token-storage.interface.d.ts.map +1 -0
- package/dist/identity/idp-token-storage.interface.js +12 -0
- package/dist/identity/idp-token-storage.interface.js.map +1 -0
- package/dist/identity/user-did-manager.d.ts +39 -1
- package/dist/identity/user-did-manager.d.ts.map +1 -1
- package/dist/identity/user-did-manager.js +69 -3
- package/dist/identity/user-did-manager.js.map +1 -1
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +39 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime/audit-logger.d.ts +37 -0
- package/dist/runtime/audit-logger.d.ts.map +1 -0
- package/dist/runtime/audit-logger.js +9 -0
- package/dist/runtime/audit-logger.js.map +1 -0
- package/dist/runtime/base.d.ts +58 -2
- package/dist/runtime/base.d.ts.map +1 -1
- package/dist/runtime/base.js +266 -11
- package/dist/runtime/base.js.map +1 -1
- package/dist/services/access-control.service.d.ts.map +1 -1
- package/dist/services/access-control.service.js +200 -35
- package/dist/services/access-control.service.js.map +1 -1
- package/dist/services/authorization/authorization-registry.d.ts +29 -0
- package/dist/services/authorization/authorization-registry.d.ts.map +1 -0
- package/dist/services/authorization/authorization-registry.js +57 -0
- package/dist/services/authorization/authorization-registry.js.map +1 -0
- package/dist/services/authorization/types.d.ts +53 -0
- package/dist/services/authorization/types.d.ts.map +1 -0
- package/dist/services/authorization/types.js +10 -0
- package/dist/services/authorization/types.js.map +1 -0
- package/dist/services/batch-delegation.service.d.ts +53 -0
- package/dist/services/batch-delegation.service.d.ts.map +1 -0
- package/dist/services/batch-delegation.service.js +95 -0
- package/dist/services/batch-delegation.service.js.map +1 -0
- package/dist/services/oauth-config.service.d.ts +53 -0
- package/dist/services/oauth-config.service.d.ts.map +1 -0
- package/dist/services/oauth-config.service.js +117 -0
- package/dist/services/oauth-config.service.js.map +1 -0
- package/dist/services/oauth-provider-registry.d.ts +77 -0
- package/dist/services/oauth-provider-registry.d.ts.map +1 -0
- package/dist/services/oauth-provider-registry.js +112 -0
- package/dist/services/oauth-provider-registry.js.map +1 -0
- package/dist/services/oauth-service.d.ts +77 -0
- package/dist/services/oauth-service.d.ts.map +1 -0
- package/dist/services/oauth-service.js +348 -0
- package/dist/services/oauth-service.js.map +1 -0
- package/dist/services/oauth-token-retrieval.service.d.ts +49 -0
- package/dist/services/oauth-token-retrieval.service.d.ts.map +1 -0
- package/dist/services/oauth-token-retrieval.service.js +150 -0
- package/dist/services/oauth-token-retrieval.service.js.map +1 -0
- package/dist/services/provider-resolver.d.ts +48 -0
- package/dist/services/provider-resolver.d.ts.map +1 -0
- package/dist/services/provider-resolver.js +120 -0
- package/dist/services/provider-resolver.js.map +1 -0
- package/dist/services/provider-validator.d.ts +55 -0
- package/dist/services/provider-validator.d.ts.map +1 -0
- package/dist/services/provider-validator.js +135 -0
- package/dist/services/provider-validator.js.map +1 -0
- package/dist/services/tool-context-builder.d.ts +57 -0
- package/dist/services/tool-context-builder.d.ts.map +1 -0
- package/dist/services/tool-context-builder.js +125 -0
- package/dist/services/tool-context-builder.js.map +1 -0
- package/dist/services/tool-protection.service.d.ts +87 -10
- package/dist/services/tool-protection.service.d.ts.map +1 -1
- package/dist/services/tool-protection.service.js +282 -112
- package/dist/services/tool-protection.service.js.map +1 -1
- package/dist/types/oauth-required-error.d.ts +40 -0
- package/dist/types/oauth-required-error.d.ts.map +1 -0
- package/dist/types/oauth-required-error.js +40 -0
- package/dist/types/oauth-required-error.js.map +1 -0
- package/dist/utils/did-helpers.d.ts +33 -0
- package/dist/utils/did-helpers.d.ts.map +1 -1
- package/dist/utils/did-helpers.js +40 -0
- package/dist/utils/did-helpers.js.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/docs/API_REFERENCE.md +1362 -0
- package/docs/COMPLIANCE_MATRIX.md +691 -0
- package/docs/STATUSLIST2021_GUIDE.md +696 -0
- package/docs/W3C_VC_DELEGATION_GUIDE.md +710 -0
- package/package.json +24 -50
- package/scripts/audit-compliance.ts +724 -0
- package/src/__tests__/cache/tool-protection-cache.test.ts +640 -0
- package/src/__tests__/config/provider-runtime-config.test.ts +309 -0
- package/src/__tests__/delegation-e2e.test.ts +690 -0
- package/src/__tests__/identity/user-did-manager.test.ts +213 -0
- package/src/__tests__/index.test.ts +56 -0
- package/src/__tests__/integration/full-flow.test.ts +776 -0
- package/src/__tests__/integration.test.ts +281 -0
- package/src/__tests__/providers/base.test.ts +173 -0
- package/src/__tests__/providers/memory.test.ts +319 -0
- package/src/__tests__/regression/phase2-regression.test.ts +427 -0
- package/src/__tests__/runtime/audit-logger.test.ts +154 -0
- package/src/__tests__/runtime/base-extensions.test.ts +593 -0
- package/src/__tests__/runtime/base.test.ts +869 -0
- package/src/__tests__/runtime/delegation-flow.test.ts +164 -0
- package/src/__tests__/runtime/proof-client-did.test.ts +375 -0
- package/src/__tests__/runtime/route-interception.test.ts +686 -0
- package/src/__tests__/runtime/tool-protection-enforcement.test.ts +908 -0
- package/src/__tests__/services/agentshield-integration.test.ts +784 -0
- package/src/__tests__/services/provider-resolver-edge-cases.test.ts +487 -0
- package/src/__tests__/services/tool-protection-oauth-provider.test.ts +480 -0
- package/src/__tests__/services/tool-protection.service.test.ts +1366 -0
- package/src/__tests__/utils/mock-providers.ts +340 -0
- package/src/cache/oauth-config-cache.d.ts +69 -0
- package/src/cache/oauth-config-cache.d.ts.map +1 -0
- package/src/cache/oauth-config-cache.js +71 -0
- package/src/cache/oauth-config-cache.js.map +1 -0
- package/src/cache/oauth-config-cache.ts +123 -0
- package/src/cache/tool-protection-cache.ts +171 -0
- package/src/compliance/EXAMPLE.md +412 -0
- package/src/compliance/__tests__/schema-verifier.test.ts +797 -0
- package/src/compliance/index.ts +8 -0
- package/src/compliance/schema-registry.ts +460 -0
- package/src/compliance/schema-verifier.ts +708 -0
- package/src/config/__tests__/remote-config.spec.ts +268 -0
- package/src/config/remote-config.ts +174 -0
- package/src/config.ts +309 -0
- package/src/delegation/__tests__/audience-validator.test.ts +112 -0
- package/src/delegation/__tests__/bitstring.test.ts +346 -0
- package/src/delegation/__tests__/cascading-revocation.test.ts +628 -0
- package/src/delegation/__tests__/delegation-graph.test.ts +584 -0
- package/src/delegation/__tests__/utils.test.ts +152 -0
- package/src/delegation/__tests__/vc-issuer.test.ts +442 -0
- package/src/delegation/__tests__/vc-verifier.test.ts +922 -0
- package/src/delegation/audience-validator.ts +52 -0
- package/src/delegation/bitstring.ts +278 -0
- package/src/delegation/cascading-revocation.ts +370 -0
- package/src/delegation/delegation-graph.ts +299 -0
- package/src/delegation/index.ts +14 -0
- package/src/delegation/statuslist-manager.ts +353 -0
- package/src/delegation/storage/__tests__/memory-graph-storage.test.ts +366 -0
- package/src/delegation/storage/__tests__/memory-statuslist-storage.test.ts +228 -0
- package/src/delegation/storage/index.ts +9 -0
- package/src/delegation/storage/memory-graph-storage.ts +178 -0
- package/src/delegation/storage/memory-statuslist-storage.ts +77 -0
- package/src/delegation/utils.ts +42 -0
- package/src/delegation/vc-issuer.ts +232 -0
- package/src/delegation/vc-verifier.ts +568 -0
- package/src/identity/idp-token-resolver.ts +147 -0
- package/src/identity/idp-token-storage.interface.ts +59 -0
- package/src/identity/user-did-manager.ts +370 -0
- package/src/index.ts +260 -0
- package/src/providers/base.d.ts +91 -0
- package/src/providers/base.d.ts.map +1 -0
- package/src/providers/base.js +38 -0
- package/src/providers/base.js.map +1 -0
- package/src/providers/base.ts +96 -0
- package/src/providers/memory.ts +142 -0
- package/src/runtime/audit-logger.ts +39 -0
- package/src/runtime/base.ts +1329 -0
- package/src/services/__tests__/access-control.integration.test.ts +443 -0
- package/src/services/__tests__/access-control.proof-response-validation.test.ts +578 -0
- package/src/services/__tests__/access-control.service.test.ts +970 -0
- package/src/services/__tests__/batch-delegation.service.test.ts +351 -0
- package/src/services/__tests__/crypto.service.test.ts +531 -0
- package/src/services/__tests__/oauth-provider-registry.test.ts +142 -0
- package/src/services/__tests__/proof-verifier.integration.test.ts +485 -0
- package/src/services/__tests__/proof-verifier.test.ts +489 -0
- package/src/services/__tests__/provider-resolution.integration.test.ts +198 -0
- package/src/services/__tests__/provider-resolver.test.ts +217 -0
- package/src/services/__tests__/storage.service.test.ts +358 -0
- package/src/services/access-control.service.ts +990 -0
- package/src/services/authorization/authorization-registry.ts +66 -0
- package/src/services/authorization/types.ts +71 -0
- package/src/services/batch-delegation.service.ts +137 -0
- package/src/services/crypto.service.ts +302 -0
- package/src/services/errors.ts +76 -0
- package/src/services/index.ts +9 -0
- package/src/services/oauth-config.service.d.ts +53 -0
- package/src/services/oauth-config.service.d.ts.map +1 -0
- package/src/services/oauth-config.service.js +113 -0
- package/src/services/oauth-config.service.js.map +1 -0
- package/src/services/oauth-config.service.ts +166 -0
- package/src/services/oauth-provider-registry.d.ts +57 -0
- package/src/services/oauth-provider-registry.d.ts.map +1 -0
- package/src/services/oauth-provider-registry.js +73 -0
- package/src/services/oauth-provider-registry.js.map +1 -0
- package/src/services/oauth-provider-registry.ts +123 -0
- package/src/services/oauth-service.ts +510 -0
- package/src/services/oauth-token-retrieval.service.ts +245 -0
- package/src/services/proof-verifier.ts +478 -0
- package/src/services/provider-resolver.d.ts +48 -0
- package/src/services/provider-resolver.d.ts.map +1 -0
- package/src/services/provider-resolver.js +106 -0
- package/src/services/provider-resolver.js.map +1 -0
- package/src/services/provider-resolver.ts +144 -0
- package/src/services/provider-validator.ts +170 -0
- package/src/services/storage.service.ts +566 -0
- package/src/services/tool-context-builder.ts +172 -0
- package/src/services/tool-protection.service.ts +958 -0
- package/src/types/oauth-required-error.ts +63 -0
- package/src/types/tool-protection.ts +155 -0
- package/src/utils/__tests__/did-helpers.test.ts +101 -0
- package/src/utils/base64.ts +148 -0
- package/src/utils/cors.ts +83 -0
- package/src/utils/did-helpers.ts +150 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/storage-keys.ts +278 -0
- package/tsconfig.json +21 -0
- package/vitest.config.ts +56 -0
|
@@ -0,0 +1,690 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-End Integration Tests for W3C VC-Based Delegation System
|
|
3
|
+
*
|
|
4
|
+
* Tests the complete delegation lifecycle:
|
|
5
|
+
* - Delegation credential issuance
|
|
6
|
+
* - Delegation verification with DID resolution
|
|
7
|
+
* - StatusList2021 revocation
|
|
8
|
+
* - Cascading revocation through delegation chains
|
|
9
|
+
* - Tool protection integration
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
13
|
+
import {
|
|
14
|
+
DelegationCredentialIssuer,
|
|
15
|
+
DelegationCredentialVerifier,
|
|
16
|
+
StatusList2021Manager,
|
|
17
|
+
DelegationGraphManager,
|
|
18
|
+
CascadingRevocationManager,
|
|
19
|
+
ToolProtectionService,
|
|
20
|
+
InMemoryToolProtectionCache,
|
|
21
|
+
MemoryStatusListStorage,
|
|
22
|
+
MemoryDelegationGraphStorage
|
|
23
|
+
} from '../index';
|
|
24
|
+
import type {
|
|
25
|
+
DelegationCredential,
|
|
26
|
+
VerifiableCredential,
|
|
27
|
+
DelegationConstraints
|
|
28
|
+
} from '@kya-os/contracts';
|
|
29
|
+
|
|
30
|
+
// TODO: These tests are for W3C VC-based delegation features that are not yet implemented.
|
|
31
|
+
// The following classes are missing:
|
|
32
|
+
// - DelegationCredentialIssuer
|
|
33
|
+
// - DelegationCredentialVerifier
|
|
34
|
+
// - StatusList2021Manager
|
|
35
|
+
// - DelegationGraphManager
|
|
36
|
+
// - CascadingRevocationManager
|
|
37
|
+
// - ToolProtectionService (with setProtection method)
|
|
38
|
+
// Once these are implemented, remove the .skip and ensure proper mocks are set up.
|
|
39
|
+
describe.skip('Delegation E2E Tests', () => {
|
|
40
|
+
// Test identities
|
|
41
|
+
const issuerDID = 'did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK';
|
|
42
|
+
const issuerKid = `${issuerDID}#z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK`;
|
|
43
|
+
const issuerPrivateKey = 'mock-private-key-issuer';
|
|
44
|
+
const issuerPublicKey = 'mock-public-key-issuer';
|
|
45
|
+
|
|
46
|
+
const delegateDID = 'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH';
|
|
47
|
+
const delegateKid = `${delegateDID}#z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH`;
|
|
48
|
+
const delegatePrivateKey = 'mock-private-key-delegate';
|
|
49
|
+
const delegatePublicKey = 'mock-public-key-delegate';
|
|
50
|
+
|
|
51
|
+
const subDelegateDID = 'did:key:z6Mkfriq1MqLBoPWecGoDLjguo1sB9brj6wT3qZ5BxkKpuP6';
|
|
52
|
+
|
|
53
|
+
// Mock signing function
|
|
54
|
+
const mockSignVC = async (vc: VerifiableCredential): Promise<VerifiableCredential> => {
|
|
55
|
+
return {
|
|
56
|
+
...vc,
|
|
57
|
+
proof: {
|
|
58
|
+
type: 'Ed25519Signature2020',
|
|
59
|
+
created: new Date().toISOString(),
|
|
60
|
+
verificationMethod: issuerKid,
|
|
61
|
+
proofPurpose: 'assertionMethod',
|
|
62
|
+
proofValue: 'z58DAdFfa9SkqZMVPxAQpic7ndSayn1PzZs6ZjWp1CktyGesjuTSwRdoWhAfGFCF5bppETSTojQCrfFPP2oumHKtz',
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Mock signature verification
|
|
68
|
+
const mockVerifySignature = async (
|
|
69
|
+
vc: VerifiableCredential,
|
|
70
|
+
publicKey: string
|
|
71
|
+
): Promise<boolean> => {
|
|
72
|
+
// In real implementation, would verify the actual signature
|
|
73
|
+
return vc.proof?.type === 'Ed25519Signature2020';
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// Mock DID resolver
|
|
77
|
+
const mockResolveDID = async (did: string) => {
|
|
78
|
+
const keyMap: Record<string, string> = {
|
|
79
|
+
[issuerDID]: issuerPublicKey,
|
|
80
|
+
[delegateDID]: delegatePublicKey,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
'@context': ['https://www.w3.org/ns/did/v1'],
|
|
85
|
+
id: did,
|
|
86
|
+
verificationMethod: [
|
|
87
|
+
{
|
|
88
|
+
id: `${did}#key-1`,
|
|
89
|
+
type: 'Ed25519VerificationKey2020',
|
|
90
|
+
controller: did,
|
|
91
|
+
publicKeyBase64: keyMap[did] || 'unknown',
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
authentication: [`${did}#key-1`],
|
|
95
|
+
assertionMethod: [`${did}#key-1`],
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
let issuer: DelegationCredentialIssuer;
|
|
100
|
+
let verifier: DelegationCredentialVerifier;
|
|
101
|
+
let statusListManager: StatusList2021Manager;
|
|
102
|
+
let delegationGraph: DelegationGraphManager;
|
|
103
|
+
let cascadingRevocation: CascadingRevocationManager;
|
|
104
|
+
|
|
105
|
+
beforeEach(() => {
|
|
106
|
+
// Set up issuer
|
|
107
|
+
issuer = new DelegationCredentialIssuer({
|
|
108
|
+
identityProvider: {
|
|
109
|
+
getDID: async () => issuerDID,
|
|
110
|
+
getKeyId: async () => issuerKid,
|
|
111
|
+
getPrivateKey: async () => issuerPrivateKey,
|
|
112
|
+
},
|
|
113
|
+
signVC: mockSignVC,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Set up status list manager
|
|
117
|
+
const statusListStorage = new MemoryStatusListStorage();
|
|
118
|
+
statusListManager = new StatusList2021Manager({
|
|
119
|
+
identityProvider: {
|
|
120
|
+
getDID: async () => issuerDID,
|
|
121
|
+
getKeyId: async () => issuerKid,
|
|
122
|
+
getPrivateKey: async () => issuerPrivateKey,
|
|
123
|
+
},
|
|
124
|
+
storage: statusListStorage,
|
|
125
|
+
signVC: mockSignVC,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// Set up verifier
|
|
129
|
+
verifier = new DelegationCredentialVerifier({
|
|
130
|
+
resolveDID: mockResolveDID,
|
|
131
|
+
resolveStatusList: async (url: string) => {
|
|
132
|
+
const listId = url.split('/').pop()!;
|
|
133
|
+
return await statusListManager.getStatusListCredential(listId);
|
|
134
|
+
},
|
|
135
|
+
verifySignature: mockVerifySignature,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Set up delegation graph
|
|
139
|
+
const graphStorage = new MemoryDelegationGraphStorage();
|
|
140
|
+
delegationGraph = new DelegationGraphManager({
|
|
141
|
+
storage: graphStorage,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Set up cascading revocation
|
|
145
|
+
cascadingRevocation = new CascadingRevocationManager({
|
|
146
|
+
delegationGraph,
|
|
147
|
+
statusListManager,
|
|
148
|
+
issuerIdentity: {
|
|
149
|
+
getDID: async () => issuerDID,
|
|
150
|
+
getKeyId: async () => issuerKid,
|
|
151
|
+
getPrivateKey: async () => issuerPrivateKey,
|
|
152
|
+
},
|
|
153
|
+
signVC: mockSignVC,
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('Delegation Issuance', () => {
|
|
158
|
+
it('should issue a valid delegation credential', async () => {
|
|
159
|
+
const constraints: DelegationConstraints = {
|
|
160
|
+
budget: {
|
|
161
|
+
maxCost: 100,
|
|
162
|
+
currency: 'USD',
|
|
163
|
+
},
|
|
164
|
+
scope: {
|
|
165
|
+
allowedTools: ['read_file', 'write_file'],
|
|
166
|
+
allowedResources: ['/documents/*'],
|
|
167
|
+
},
|
|
168
|
+
time: {
|
|
169
|
+
notBefore: new Date().toISOString(),
|
|
170
|
+
notAfter: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const delegation = await issuer.issue({
|
|
175
|
+
subjectDid: delegateDID,
|
|
176
|
+
constraints,
|
|
177
|
+
audience: 'https://api.example.com',
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Verify credential structure
|
|
181
|
+
expect(delegation).toBeDefined();
|
|
182
|
+
expect(delegation['@context']).toContain('https://www.w3.org/2018/credentials/v1');
|
|
183
|
+
expect(delegation.type).toContain('VerifiableCredential');
|
|
184
|
+
expect(delegation.type).toContain('DelegationCredential');
|
|
185
|
+
expect(delegation.issuer).toBe(issuerDID);
|
|
186
|
+
expect(delegation.credentialSubject.id).toBe(delegateDID);
|
|
187
|
+
expect(delegation.proof).toBeDefined();
|
|
188
|
+
expect(delegation.proof?.type).toBe('Ed25519Signature2020');
|
|
189
|
+
|
|
190
|
+
// Verify constraints are embedded
|
|
191
|
+
expect(delegation.credentialSubject).toHaveProperty('delegation');
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('should issue delegation with status list revocation', async () => {
|
|
195
|
+
// Create status list
|
|
196
|
+
const statusListId = await statusListManager.createStatusList('revocation');
|
|
197
|
+
const statusListUrl = `https://status.example.com/lists/${statusListId}`;
|
|
198
|
+
|
|
199
|
+
const constraints: DelegationConstraints = {
|
|
200
|
+
scope: {
|
|
201
|
+
allowedTools: ['execute_command'],
|
|
202
|
+
},
|
|
203
|
+
time: {
|
|
204
|
+
notBefore: new Date().toISOString(),
|
|
205
|
+
notAfter: new Date(Date.now() + 3600000).toISOString(),
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
const delegation = await issuer.issue({
|
|
210
|
+
subjectDid: delegateDID,
|
|
211
|
+
constraints,
|
|
212
|
+
audience: 'https://api.example.com',
|
|
213
|
+
credentialStatus: {
|
|
214
|
+
id: `${statusListUrl}#0`,
|
|
215
|
+
type: 'StatusList2021Entry',
|
|
216
|
+
statusPurpose: 'revocation',
|
|
217
|
+
statusListIndex: '0',
|
|
218
|
+
statusListCredential: statusListUrl,
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
expect(delegation.credentialStatus).toBeDefined();
|
|
223
|
+
expect(delegation.credentialStatus?.type).toBe('StatusList2021Entry');
|
|
224
|
+
expect(delegation.credentialStatus?.statusPurpose).toBe('revocation');
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
describe('Delegation Verification', () => {
|
|
229
|
+
it('should verify a valid delegation credential', async () => {
|
|
230
|
+
const constraints: DelegationConstraints = {
|
|
231
|
+
scope: {
|
|
232
|
+
allowedTools: ['read_data'],
|
|
233
|
+
},
|
|
234
|
+
time: {
|
|
235
|
+
notBefore: new Date(Date.now() - 1000).toISOString(),
|
|
236
|
+
notAfter: new Date(Date.now() + 3600000).toISOString(),
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
const delegation = await issuer.issue({
|
|
241
|
+
subjectDid: delegateDID,
|
|
242
|
+
constraints,
|
|
243
|
+
audience: 'https://api.example.com',
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
const result = await verifier.verify(delegation);
|
|
247
|
+
|
|
248
|
+
expect(result.valid).toBe(true);
|
|
249
|
+
expect(result.checks.signature).toBe(true);
|
|
250
|
+
expect(result.checks.expiration).toBe(true);
|
|
251
|
+
expect(result.checks.notBefore).toBe(true);
|
|
252
|
+
expect(result.errors).toHaveLength(0);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it('should reject expired delegation', async () => {
|
|
256
|
+
const constraints: DelegationConstraints = {
|
|
257
|
+
scope: {
|
|
258
|
+
allowedTools: ['read_data'],
|
|
259
|
+
},
|
|
260
|
+
time: {
|
|
261
|
+
notBefore: new Date(Date.now() - 3600000).toISOString(),
|
|
262
|
+
notAfter: new Date(Date.now() - 1000).toISOString(), // Already expired
|
|
263
|
+
},
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
const delegation = await issuer.issue({
|
|
267
|
+
subjectDid: delegateDID,
|
|
268
|
+
constraints,
|
|
269
|
+
audience: 'https://api.example.com',
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
const result = await verifier.verify(delegation);
|
|
273
|
+
|
|
274
|
+
expect(result.valid).toBe(false);
|
|
275
|
+
expect(result.checks.expiration).toBe(false);
|
|
276
|
+
expect(result.errors).toContain('Credential has expired');
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('should reject delegation not yet valid', async () => {
|
|
280
|
+
const constraints: DelegationConstraints = {
|
|
281
|
+
scope: {
|
|
282
|
+
allowedTools: ['read_data'],
|
|
283
|
+
},
|
|
284
|
+
time: {
|
|
285
|
+
notBefore: new Date(Date.now() + 3600000).toISOString(), // Future
|
|
286
|
+
notAfter: new Date(Date.now() + 7200000).toISOString(),
|
|
287
|
+
},
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
const delegation = await issuer.issue({
|
|
291
|
+
subjectDid: delegateDID,
|
|
292
|
+
constraints,
|
|
293
|
+
audience: 'https://api.example.com',
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
const result = await verifier.verify(delegation);
|
|
297
|
+
|
|
298
|
+
expect(result.valid).toBe(false);
|
|
299
|
+
expect(result.checks.notBefore).toBe(false);
|
|
300
|
+
expect(result.errors).toContain('Credential is not yet valid');
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
describe('StatusList2021 Revocation', () => {
|
|
305
|
+
it('should create and manage status lists', async () => {
|
|
306
|
+
const statusListId = await statusListManager.createStatusList('revocation');
|
|
307
|
+
expect(statusListId).toBeDefined();
|
|
308
|
+
|
|
309
|
+
const statusListVC = await statusListManager.getStatusListCredential(statusListId);
|
|
310
|
+
expect(statusListVC).toBeDefined();
|
|
311
|
+
expect(statusListVC.type).toContain('StatusList2021Credential');
|
|
312
|
+
expect(statusListVC.credentialSubject.statusPurpose).toBe('revocation');
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it('should revoke delegation and verify revocation status', async () => {
|
|
316
|
+
// Create status list
|
|
317
|
+
const statusListId = await statusListManager.createStatusList('revocation');
|
|
318
|
+
const statusListUrl = `https://status.example.com/lists/${statusListId}`;
|
|
319
|
+
|
|
320
|
+
// Issue delegation with status
|
|
321
|
+
const constraints: DelegationConstraints = {
|
|
322
|
+
scope: { allowedTools: ['test'] },
|
|
323
|
+
time: {
|
|
324
|
+
notBefore: new Date().toISOString(),
|
|
325
|
+
notAfter: new Date(Date.now() + 3600000).toISOString(),
|
|
326
|
+
},
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
const delegation = await issuer.issue({
|
|
330
|
+
subjectDid: delegateDID,
|
|
331
|
+
constraints,
|
|
332
|
+
audience: 'https://api.example.com',
|
|
333
|
+
credentialStatus: {
|
|
334
|
+
id: `${statusListUrl}#5`,
|
|
335
|
+
type: 'StatusList2021Entry',
|
|
336
|
+
statusPurpose: 'revocation',
|
|
337
|
+
statusListIndex: '5',
|
|
338
|
+
statusListCredential: statusListUrl,
|
|
339
|
+
},
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
// Initially not revoked
|
|
343
|
+
let result = await verifier.verify(delegation);
|
|
344
|
+
expect(result.valid).toBe(true);
|
|
345
|
+
expect(result.checks.revocation).toBe(true);
|
|
346
|
+
|
|
347
|
+
// Revoke the credential
|
|
348
|
+
await statusListManager.setStatus(statusListId, 5, true);
|
|
349
|
+
|
|
350
|
+
// Now should be revoked
|
|
351
|
+
result = await verifier.verify(delegation);
|
|
352
|
+
expect(result.valid).toBe(false);
|
|
353
|
+
expect(result.checks.revocation).toBe(false);
|
|
354
|
+
expect(result.errors).toContain('Credential has been revoked');
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it('should handle bulk revocations efficiently', async () => {
|
|
358
|
+
const statusListId = await statusListManager.createStatusList('revocation');
|
|
359
|
+
|
|
360
|
+
// Set multiple indices as revoked
|
|
361
|
+
const indices = [0, 5, 10, 100, 1000];
|
|
362
|
+
for (const index of indices) {
|
|
363
|
+
await statusListManager.setStatus(statusListId, index, true);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Verify all are revoked
|
|
367
|
+
for (const index of indices) {
|
|
368
|
+
const isRevoked = await statusListManager.getStatus(statusListId, index);
|
|
369
|
+
expect(isRevoked).toBe(true);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Verify others are not revoked
|
|
373
|
+
const unrevoked = [1, 6, 11, 99, 999];
|
|
374
|
+
for (const index of unrevoked) {
|
|
375
|
+
const isRevoked = await statusListManager.getStatus(statusListId, index);
|
|
376
|
+
expect(isRevoked).toBe(false);
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
describe('Delegation Chains', () => {
|
|
382
|
+
it('should create and track delegation chains', async () => {
|
|
383
|
+
// Root delegation: issuer → delegate
|
|
384
|
+
const rootConstraints: DelegationConstraints = {
|
|
385
|
+
scope: {
|
|
386
|
+
allowedTools: ['read', 'write', 'execute'],
|
|
387
|
+
allowedResources: ['/*'],
|
|
388
|
+
},
|
|
389
|
+
time: {
|
|
390
|
+
notBefore: new Date().toISOString(),
|
|
391
|
+
notAfter: new Date(Date.now() + 3600000).toISOString(),
|
|
392
|
+
},
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
const rootDelegation = await issuer.issue({
|
|
396
|
+
subjectDid: delegateDID,
|
|
397
|
+
constraints: rootConstraints,
|
|
398
|
+
audience: 'https://api.example.com',
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
// Add to graph
|
|
402
|
+
await delegationGraph.addDelegation({
|
|
403
|
+
id: rootDelegation.id!,
|
|
404
|
+
issuerDid: issuerDID,
|
|
405
|
+
subjectDid: delegateDID,
|
|
406
|
+
parentId: null,
|
|
407
|
+
issuedAt: rootDelegation.issuanceDate,
|
|
408
|
+
expiresAt: rootDelegation.expirationDate!,
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
// Sub-delegation: delegate → sub-delegate
|
|
412
|
+
const subConstraints: DelegationConstraints = {
|
|
413
|
+
scope: {
|
|
414
|
+
allowedTools: ['read'], // Subset of root
|
|
415
|
+
allowedResources: ['/documents/*'], // Subset of root
|
|
416
|
+
},
|
|
417
|
+
time: {
|
|
418
|
+
notBefore: new Date().toISOString(),
|
|
419
|
+
notAfter: new Date(Date.now() + 1800000).toISOString(), // Shorter than root
|
|
420
|
+
},
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
const subDelegation: DelegationCredential = {
|
|
424
|
+
'@context': ['https://www.w3.org/2018/credentials/v1'],
|
|
425
|
+
id: 'urn:uuid:sub-delegation-456',
|
|
426
|
+
type: ['VerifiableCredential', 'DelegationCredential'],
|
|
427
|
+
issuer: delegateDID,
|
|
428
|
+
issuanceDate: new Date().toISOString(),
|
|
429
|
+
expirationDate: new Date(Date.now() + 1800000).toISOString(),
|
|
430
|
+
credentialSubject: {
|
|
431
|
+
id: subDelegateDID,
|
|
432
|
+
delegation: {
|
|
433
|
+
id: 'sub-delegation-456',
|
|
434
|
+
issuerDid: delegateDID,
|
|
435
|
+
subjectDid: subDelegateDID,
|
|
436
|
+
constraints: subConstraints,
|
|
437
|
+
issuedAt: new Date().toISOString(),
|
|
438
|
+
expiresAt: new Date(Date.now() + 1800000).toISOString(),
|
|
439
|
+
},
|
|
440
|
+
},
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
await delegationGraph.addDelegation({
|
|
444
|
+
id: subDelegation.id!,
|
|
445
|
+
issuerDid: delegateDID,
|
|
446
|
+
subjectDid: subDelegateDID,
|
|
447
|
+
parentId: rootDelegation.id!,
|
|
448
|
+
issuedAt: subDelegation.issuanceDate,
|
|
449
|
+
expiresAt: subDelegation.expirationDate!,
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
// Verify chain
|
|
453
|
+
const chain = await delegationGraph.getChain(subDelegation.id!);
|
|
454
|
+
expect(chain).toHaveLength(2);
|
|
455
|
+
expect(chain[0].id).toBe(rootDelegation.id);
|
|
456
|
+
expect(chain[1].id).toBe(subDelegation.id);
|
|
457
|
+
|
|
458
|
+
// Verify descendants
|
|
459
|
+
const descendants = await delegationGraph.getDescendants(rootDelegation.id!);
|
|
460
|
+
expect(descendants).toHaveLength(1);
|
|
461
|
+
expect(descendants[0].id).toBe(subDelegation.id);
|
|
462
|
+
});
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
describe('Cascading Revocation', () => {
|
|
466
|
+
it('should revoke entire delegation chain', async () => {
|
|
467
|
+
// Create status list
|
|
468
|
+
const statusListId = await statusListManager.createStatusList('revocation');
|
|
469
|
+
const statusListUrl = `https://status.example.com/lists/${statusListId}`;
|
|
470
|
+
|
|
471
|
+
// Root delegation
|
|
472
|
+
const rootDelegation = await issuer.issue({
|
|
473
|
+
subjectDid: delegateDID,
|
|
474
|
+
constraints: {
|
|
475
|
+
scope: { allowedTools: ['all'] },
|
|
476
|
+
time: {
|
|
477
|
+
notBefore: new Date().toISOString(),
|
|
478
|
+
notAfter: new Date(Date.now() + 3600000).toISOString(),
|
|
479
|
+
},
|
|
480
|
+
},
|
|
481
|
+
audience: 'https://api.example.com',
|
|
482
|
+
credentialStatus: {
|
|
483
|
+
id: `${statusListUrl}#0`,
|
|
484
|
+
type: 'StatusList2021Entry',
|
|
485
|
+
statusPurpose: 'revocation',
|
|
486
|
+
statusListIndex: '0',
|
|
487
|
+
statusListCredential: statusListUrl,
|
|
488
|
+
},
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
await delegationGraph.addDelegation({
|
|
492
|
+
id: rootDelegation.id!,
|
|
493
|
+
issuerDid: issuerDID,
|
|
494
|
+
subjectDid: delegateDID,
|
|
495
|
+
parentId: null,
|
|
496
|
+
issuedAt: rootDelegation.issuanceDate,
|
|
497
|
+
expiresAt: rootDelegation.expirationDate!,
|
|
498
|
+
statusListUrl,
|
|
499
|
+
statusListIndex: 0,
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
// Sub-delegation
|
|
503
|
+
const subDelegationId = 'urn:uuid:sub-456';
|
|
504
|
+
await delegationGraph.addDelegation({
|
|
505
|
+
id: subDelegationId,
|
|
506
|
+
issuerDid: delegateDID,
|
|
507
|
+
subjectDid: subDelegateDID,
|
|
508
|
+
parentId: rootDelegation.id!,
|
|
509
|
+
issuedAt: new Date().toISOString(),
|
|
510
|
+
expiresAt: new Date(Date.now() + 1800000).toISOString(),
|
|
511
|
+
statusListUrl,
|
|
512
|
+
statusListIndex: 1,
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
// Revoke root with cascading
|
|
516
|
+
const revoked = await cascadingRevocation.revoke(rootDelegation.id!, {
|
|
517
|
+
cascade: true,
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
expect(revoked).toHaveLength(2); // Root + sub-delegation
|
|
521
|
+
expect(revoked).toContain(rootDelegation.id);
|
|
522
|
+
expect(revoked).toContain(subDelegationId);
|
|
523
|
+
|
|
524
|
+
// Verify both are revoked in status list
|
|
525
|
+
expect(await statusListManager.getStatus(statusListId, 0)).toBe(true);
|
|
526
|
+
expect(await statusListManager.getStatus(statusListId, 1)).toBe(true);
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
it('should trigger revocation hooks', async () => {
|
|
530
|
+
const statusListId = await statusListManager.createStatusList('revocation');
|
|
531
|
+
const statusListUrl = `https://status.example.com/lists/${statusListId}`;
|
|
532
|
+
|
|
533
|
+
const delegation = await issuer.issue({
|
|
534
|
+
subjectDid: delegateDID,
|
|
535
|
+
constraints: {
|
|
536
|
+
scope: { allowedTools: ['test'] },
|
|
537
|
+
time: {
|
|
538
|
+
notBefore: new Date().toISOString(),
|
|
539
|
+
notAfter: new Date(Date.now() + 3600000).toISOString(),
|
|
540
|
+
},
|
|
541
|
+
},
|
|
542
|
+
audience: 'https://api.example.com',
|
|
543
|
+
credentialStatus: {
|
|
544
|
+
id: `${statusListUrl}#0`,
|
|
545
|
+
type: 'StatusList2021Entry',
|
|
546
|
+
statusPurpose: 'revocation',
|
|
547
|
+
statusListIndex: '0',
|
|
548
|
+
statusListCredential: statusListUrl,
|
|
549
|
+
},
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
await delegationGraph.addDelegation({
|
|
553
|
+
id: delegation.id!,
|
|
554
|
+
issuerDid: issuerDID,
|
|
555
|
+
subjectDid: delegateDID,
|
|
556
|
+
parentId: null,
|
|
557
|
+
issuedAt: delegation.issuanceDate,
|
|
558
|
+
expiresAt: delegation.expirationDate!,
|
|
559
|
+
statusListUrl,
|
|
560
|
+
statusListIndex: 0,
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
// Register hook
|
|
564
|
+
const revokedIds: string[] = [];
|
|
565
|
+
cascadingRevocation.onRevoke(async (event) => {
|
|
566
|
+
revokedIds.push(event.credentialId);
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
// Revoke
|
|
570
|
+
await cascadingRevocation.revoke(delegation.id!);
|
|
571
|
+
|
|
572
|
+
expect(revokedIds).toContain(delegation.id);
|
|
573
|
+
});
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
describe('Tool Protection Integration', () => {
|
|
577
|
+
it('should enforce delegation requirements for protected tools', async () => {
|
|
578
|
+
const toolProtection = new ToolProtectionService({
|
|
579
|
+
cache: new InMemoryToolProtectionCache(),
|
|
580
|
+
delegationVerifier: verifier,
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
// Configure tool protection
|
|
584
|
+
await toolProtection.setProtection('sensitive_operation', {
|
|
585
|
+
requiresDelegation: true,
|
|
586
|
+
requiredScopes: ['execute'],
|
|
587
|
+
budgetLimit: 50,
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
// Create valid delegation
|
|
591
|
+
const delegation = await issuer.issue({
|
|
592
|
+
subjectDid: delegateDID,
|
|
593
|
+
constraints: {
|
|
594
|
+
scope: {
|
|
595
|
+
allowedTools: ['sensitive_operation'],
|
|
596
|
+
},
|
|
597
|
+
budget: {
|
|
598
|
+
maxCost: 50,
|
|
599
|
+
currency: 'USD',
|
|
600
|
+
},
|
|
601
|
+
time: {
|
|
602
|
+
notBefore: new Date().toISOString(),
|
|
603
|
+
notAfter: new Date(Date.now() + 3600000).toISOString(),
|
|
604
|
+
},
|
|
605
|
+
},
|
|
606
|
+
audience: 'https://api.example.com',
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
// Check access - should succeed
|
|
610
|
+
const hasAccess = await toolProtection.checkAccess(
|
|
611
|
+
'sensitive_operation',
|
|
612
|
+
delegateDID,
|
|
613
|
+
delegation
|
|
614
|
+
);
|
|
615
|
+
expect(hasAccess).toBe(true);
|
|
616
|
+
|
|
617
|
+
// Track usage
|
|
618
|
+
await toolProtection.trackUsage('sensitive_operation', delegateDID, {
|
|
619
|
+
cost: 10,
|
|
620
|
+
timestamp: Date.now(),
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
const usage = await toolProtection.getUsage('sensitive_operation', delegateDID);
|
|
624
|
+
expect(usage.totalCost).toBe(10);
|
|
625
|
+
expect(usage.callCount).toBe(1);
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
it('should reject access without valid delegation', async () => {
|
|
629
|
+
const toolProtection = new ToolProtectionService({
|
|
630
|
+
cache: new InMemoryToolProtectionCache(),
|
|
631
|
+
delegationVerifier: verifier,
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
await toolProtection.setProtection('protected_tool', {
|
|
635
|
+
requiresDelegation: true,
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
// Attempt access without delegation
|
|
639
|
+
await expect(
|
|
640
|
+
toolProtection.checkAccess('protected_tool', delegateDID)
|
|
641
|
+
).rejects.toThrow('Delegation required');
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
it('should enforce budget constraints', async () => {
|
|
645
|
+
const toolProtection = new ToolProtectionService({
|
|
646
|
+
cache: new InMemoryToolProtectionCache(),
|
|
647
|
+
delegationVerifier: verifier,
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
await toolProtection.setProtection('expensive_operation', {
|
|
651
|
+
requiresDelegation: true,
|
|
652
|
+
budgetLimit: 100,
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
const delegation = await issuer.issue({
|
|
656
|
+
subjectDid: delegateDID,
|
|
657
|
+
constraints: {
|
|
658
|
+
scope: {
|
|
659
|
+
allowedTools: ['expensive_operation'],
|
|
660
|
+
},
|
|
661
|
+
budget: {
|
|
662
|
+
maxCost: 100,
|
|
663
|
+
currency: 'USD',
|
|
664
|
+
},
|
|
665
|
+
time: {
|
|
666
|
+
notBefore: new Date().toISOString(),
|
|
667
|
+
notAfter: new Date(Date.now() + 3600000).toISOString(),
|
|
668
|
+
},
|
|
669
|
+
},
|
|
670
|
+
audience: 'https://api.example.com',
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
await toolProtection.checkAccess('expensive_operation', delegateDID, delegation);
|
|
674
|
+
|
|
675
|
+
// Use up 90 of budget
|
|
676
|
+
await toolProtection.trackUsage('expensive_operation', delegateDID, {
|
|
677
|
+
cost: 90,
|
|
678
|
+
timestamp: Date.now(),
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
// Try to use 20 more (would exceed budget)
|
|
682
|
+
await expect(
|
|
683
|
+
toolProtection.trackUsage('expensive_operation', delegateDID, {
|
|
684
|
+
cost: 20,
|
|
685
|
+
timestamp: Date.now(),
|
|
686
|
+
})
|
|
687
|
+
).rejects.toThrow('Budget limit exceeded');
|
|
688
|
+
});
|
|
689
|
+
});
|
|
690
|
+
});
|