@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,710 @@
|
|
|
1
|
+
# W3C Verifiable Credentials Delegation Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The `@kya-os/mcp-i-core` package provides a production-ready implementation of W3C Verifiable Credentials for delegation in MCP-I systems. This guide explains how to issue, verify, and revoke delegation credentials.
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
1. [Quick Start](#quick-start)
|
|
10
|
+
2. [Architecture](#architecture)
|
|
11
|
+
3. [Issuing Delegation Credentials](#issuing-delegation-credentials)
|
|
12
|
+
4. [Verifying Delegations](#verifying-delegations)
|
|
13
|
+
5. [Revocation with StatusList2021](#revocation-with-statuslist2021)
|
|
14
|
+
6. [Cascading Revocation](#cascading-revocation)
|
|
15
|
+
7. [Tool Protection](#tool-protection)
|
|
16
|
+
8. [Best Practices](#best-practices)
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import {
|
|
22
|
+
createDelegationIssuer,
|
|
23
|
+
createDelegationVerifier,
|
|
24
|
+
createStatusListManager,
|
|
25
|
+
} from '@kya-os/mcp-i-core';
|
|
26
|
+
|
|
27
|
+
// 1. Create issuer
|
|
28
|
+
const issuer = createDelegationIssuer({
|
|
29
|
+
identityProvider: {
|
|
30
|
+
getDID: async () => 'did:key:z6Mk...',
|
|
31
|
+
getKeyId: async () => 'did:key:z6Mk...#key-1',
|
|
32
|
+
getPrivateKey: async () => privateKeyBase64,
|
|
33
|
+
},
|
|
34
|
+
signVC: async (vc) => {
|
|
35
|
+
// Sign the VC using Ed25519Signature2020
|
|
36
|
+
return signedVC;
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// 2. Issue delegation
|
|
41
|
+
const delegation = await issuer.issue({
|
|
42
|
+
subjectDid: 'did:key:z6Mkp...',
|
|
43
|
+
constraints: {
|
|
44
|
+
scope: {
|
|
45
|
+
allowedTools: ['read_file', 'write_file'],
|
|
46
|
+
allowedResources: ['/documents/*'],
|
|
47
|
+
},
|
|
48
|
+
budget: {
|
|
49
|
+
maxCost: 100,
|
|
50
|
+
currency: 'USD',
|
|
51
|
+
},
|
|
52
|
+
time: {
|
|
53
|
+
notBefore: new Date().toISOString(),
|
|
54
|
+
notAfter: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
audience: 'https://api.example.com',
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// 3. Verify delegation
|
|
61
|
+
const verifier = createDelegationVerifier({
|
|
62
|
+
resolveDID: async (did) => {
|
|
63
|
+
// Resolve DID to DID Document
|
|
64
|
+
return didDocument;
|
|
65
|
+
},
|
|
66
|
+
verifySignature: async (vc, publicKey) => {
|
|
67
|
+
// Verify signature
|
|
68
|
+
return true;
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const result = await verifier.verify(delegation);
|
|
73
|
+
console.log(result.valid); // true
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Architecture
|
|
77
|
+
|
|
78
|
+
The delegation system consists of several key components:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
82
|
+
│ Delegation System │
|
|
83
|
+
├─────────────────────────────────────────────────────────────┤
|
|
84
|
+
│ │
|
|
85
|
+
│ ┌───────────────────┐ ┌────────────────────┐ │
|
|
86
|
+
│ │ Delegation │ │ Delegation │ │
|
|
87
|
+
│ │ Issuer │─────▶│ Credential (VC) │ │
|
|
88
|
+
│ │ (Ed25519) │ │ - Constraints │ │
|
|
89
|
+
│ └───────────────────┘ │ - Proof │ │
|
|
90
|
+
│ │ - Status │ │
|
|
91
|
+
│ └────────────────────┘ │
|
|
92
|
+
│ │ │
|
|
93
|
+
│ ▼ │
|
|
94
|
+
│ ┌───────────────────┐ ┌────────────────────┐ │
|
|
95
|
+
│ │ Delegation │◀─────│ StatusList2021 │ │
|
|
96
|
+
│ │ Verifier │ │ Manager │ │
|
|
97
|
+
│ │ (DID Resolution) │ │ (Revocation) │ │
|
|
98
|
+
│ └───────────────────┘ └────────────────────┘ │
|
|
99
|
+
│ │ │ │
|
|
100
|
+
│ ▼ ▼ │
|
|
101
|
+
│ ┌───────────────────┐ ┌────────────────────┐ │
|
|
102
|
+
│ │ Tool Protection │ │ Cascading │ │
|
|
103
|
+
│ │ Service │ │ Revocation │ │
|
|
104
|
+
│ │ (Access Control) │ │ (Graph-based) │ │
|
|
105
|
+
│ └───────────────────┘ └────────────────────┘ │
|
|
106
|
+
│ │
|
|
107
|
+
└─────────────────────────────────────────────────────────────┘
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Core Components
|
|
111
|
+
|
|
112
|
+
1. **DelegationCredentialIssuer**: Creates W3C VC delegation credentials
|
|
113
|
+
2. **DelegationCredentialVerifier**: Verifies delegation credentials
|
|
114
|
+
3. **StatusList2021Manager**: Manages revocation lists efficiently
|
|
115
|
+
4. **DelegationGraphManager**: Tracks delegation chains
|
|
116
|
+
5. **CascadingRevocationManager**: Handles chain revocation
|
|
117
|
+
6. **ToolProtectionService**: Enforces delegation requirements
|
|
118
|
+
|
|
119
|
+
## Issuing Delegation Credentials
|
|
120
|
+
|
|
121
|
+
### Basic Issuance
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
import { DelegationCredentialIssuer } from '@kya-os/mcp-i-core';
|
|
125
|
+
|
|
126
|
+
const issuer = new DelegationCredentialIssuer({
|
|
127
|
+
identityProvider: {
|
|
128
|
+
getDID: async () => 'did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK',
|
|
129
|
+
getKeyId: async () => 'did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK#key-1',
|
|
130
|
+
getPrivateKey: async () => privateKeyBase64,
|
|
131
|
+
},
|
|
132
|
+
signVC: async (vc) => {
|
|
133
|
+
// Implement Ed25519Signature2020 signing
|
|
134
|
+
const signature = await ed25519.sign(canonicalJson, privateKey);
|
|
135
|
+
return {
|
|
136
|
+
...vc,
|
|
137
|
+
proof: {
|
|
138
|
+
type: 'Ed25519Signature2020',
|
|
139
|
+
created: new Date().toISOString(),
|
|
140
|
+
verificationMethod: keyId,
|
|
141
|
+
proofPurpose: 'assertionMethod',
|
|
142
|
+
proofValue: `z${base58btc.encode(signature)}`,
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### CRISP Constraints
|
|
150
|
+
|
|
151
|
+
Delegation credentials use CRISP constraints (Cost, Resource, Identity, Scope, Purpose):
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
const constraints: DelegationConstraints = {
|
|
155
|
+
// Budget constraint (C - Cost)
|
|
156
|
+
budget: {
|
|
157
|
+
maxCost: 100,
|
|
158
|
+
currency: 'USD',
|
|
159
|
+
costPer: 'call', // or 'hour', 'day', 'month'
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
// Scope constraint (S - Scope)
|
|
163
|
+
scope: {
|
|
164
|
+
allowedTools: ['read_file', 'write_file', 'list_directory'],
|
|
165
|
+
allowedResources: [
|
|
166
|
+
'/documents/*',
|
|
167
|
+
'/public/data/*.json',
|
|
168
|
+
],
|
|
169
|
+
deniedTools: ['delete_all'], // Explicit denials
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
// Time constraint (implicit P - Purpose)
|
|
173
|
+
time: {
|
|
174
|
+
notBefore: '2025-10-17T00:00:00Z',
|
|
175
|
+
notAfter: '2025-10-18T00:00:00Z',
|
|
176
|
+
maxDuration: 3600, // seconds
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const delegation = await issuer.issue({
|
|
181
|
+
subjectDid: 'did:key:z6Mkp...',
|
|
182
|
+
constraints,
|
|
183
|
+
audience: 'https://api.example.com',
|
|
184
|
+
});
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### With Revocation Support
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
// First, create a status list
|
|
191
|
+
const statusListManager = createStatusListManager({
|
|
192
|
+
identityProvider,
|
|
193
|
+
storage: new MemoryStatusListStorage(), // or your storage backend
|
|
194
|
+
signVC,
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
const statusListId = await statusListManager.createStatusList('revocation');
|
|
198
|
+
const statusListUrl = `https://status.example.com/lists/${statusListId}`;
|
|
199
|
+
|
|
200
|
+
// Issue with revocation support
|
|
201
|
+
const delegation = await issuer.issue({
|
|
202
|
+
subjectDid: 'did:key:z6Mkp...',
|
|
203
|
+
constraints,
|
|
204
|
+
audience: 'https://api.example.com',
|
|
205
|
+
credentialStatus: {
|
|
206
|
+
id: `${statusListUrl}#0`,
|
|
207
|
+
type: 'StatusList2021Entry',
|
|
208
|
+
statusPurpose: 'revocation',
|
|
209
|
+
statusListIndex: '0',
|
|
210
|
+
statusListCredential: statusListUrl,
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Verifying Delegations
|
|
216
|
+
|
|
217
|
+
### Basic Verification
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
import { DelegationCredentialVerifier } from '@kya-os/mcp-i-core';
|
|
221
|
+
|
|
222
|
+
const verifier = new DelegationCredentialVerifier({
|
|
223
|
+
// DID resolution
|
|
224
|
+
resolveDID: async (did: string) => {
|
|
225
|
+
const response = await fetch(`https://did-resolver.example.com/${did}`);
|
|
226
|
+
return await response.json();
|
|
227
|
+
},
|
|
228
|
+
|
|
229
|
+
// Signature verification
|
|
230
|
+
verifySignature: async (vc: VerifiableCredential, publicKey: string) => {
|
|
231
|
+
const proof = vc.proof as Ed25519Signature2020Proof;
|
|
232
|
+
const payload = canonicalizeVC(vc);
|
|
233
|
+
const signature = base58btc.decode(proof.proofValue.slice(1)); // Remove 'z'
|
|
234
|
+
return await ed25519.verify(signature, payload, publicKey);
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
// Status list resolution (for revocation checks)
|
|
238
|
+
resolveStatusList: async (url: string) => {
|
|
239
|
+
const response = await fetch(url);
|
|
240
|
+
return await response.json();
|
|
241
|
+
},
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
const result = await verifier.verify(delegation);
|
|
245
|
+
|
|
246
|
+
if (result.valid) {
|
|
247
|
+
console.log('✅ Delegation is valid');
|
|
248
|
+
console.log('Subject:', delegation.credentialSubject.id);
|
|
249
|
+
console.log('Allowed tools:', delegation.credentialSubject.delegation.constraints.scope.allowedTools);
|
|
250
|
+
} else {
|
|
251
|
+
console.error('❌ Delegation is invalid');
|
|
252
|
+
console.error('Errors:', result.errors);
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Verification Result
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
interface DelegationVCVerificationResult {
|
|
260
|
+
valid: boolean;
|
|
261
|
+
checks: {
|
|
262
|
+
structure: boolean; // W3C VC structure valid
|
|
263
|
+
signature: boolean; // Cryptographic signature valid
|
|
264
|
+
expiration: boolean; // Not expired
|
|
265
|
+
notBefore: boolean; // Currently active
|
|
266
|
+
revocation?: boolean; // Not revoked (if status list present)
|
|
267
|
+
didResolution: boolean; // DID resolved successfully
|
|
268
|
+
};
|
|
269
|
+
errors: string[]; // List of errors if invalid
|
|
270
|
+
warnings: string[]; // Non-fatal warnings
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Constraint Validation
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
// Check if delegation allows specific tool
|
|
278
|
+
function canExecuteTool(delegation: DelegationCredential, toolName: string): boolean {
|
|
279
|
+
const constraints = delegation.credentialSubject.delegation.constraints;
|
|
280
|
+
|
|
281
|
+
// Check scope
|
|
282
|
+
if (constraints.scope.allowedTools && !constraints.scope.allowedTools.includes(toolName)) {
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (constraints.scope.deniedTools?.includes(toolName)) {
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Check budget remaining
|
|
294
|
+
function checkBudget(delegation: DelegationCredential, usedCost: number): boolean {
|
|
295
|
+
const budget = delegation.credentialSubject.delegation.constraints.budget;
|
|
296
|
+
if (!budget) return true;
|
|
297
|
+
|
|
298
|
+
return usedCost < budget.maxCost;
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## Revocation with StatusList2021
|
|
303
|
+
|
|
304
|
+
StatusList2021 provides efficient, privacy-preserving credential revocation using compressed bitstrings.
|
|
305
|
+
|
|
306
|
+
### Creating Status Lists
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
import { StatusList2021Manager } from '@kya-os/mcp-i-core';
|
|
310
|
+
|
|
311
|
+
const manager = createStatusListManager({
|
|
312
|
+
identityProvider,
|
|
313
|
+
storage, // Implement StatusListStorageProvider
|
|
314
|
+
signVC,
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
// Create revocation list
|
|
318
|
+
const revocationListId = await manager.createStatusList('revocation');
|
|
319
|
+
|
|
320
|
+
// Create suspension list (optional)
|
|
321
|
+
const suspensionListId = await manager.createStatusList('suspension');
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Revoking Credentials
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
// Revoke a specific credential by its status list index
|
|
328
|
+
await manager.setStatus(revocationListId, 42, true); // Index 42 is now revoked
|
|
329
|
+
|
|
330
|
+
// Check status
|
|
331
|
+
const isRevoked = await manager.getStatus(revocationListId, 42);
|
|
332
|
+
console.log('Revoked:', isRevoked); // true
|
|
333
|
+
|
|
334
|
+
// Un-revoke (rare, but possible)
|
|
335
|
+
await manager.setStatus(revocationListId, 42, false);
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### Bulk Operations
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
// Revoke multiple credentials efficiently
|
|
342
|
+
const indicesToRevoke = [0, 5, 10, 42, 100, 1000];
|
|
343
|
+
|
|
344
|
+
for (const index of indicesToRevoke) {
|
|
345
|
+
await manager.setStatus(revocationListId, index, true);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// The bitstring is automatically compressed (gzip + base64)
|
|
349
|
+
// Very efficient: 131,072 credentials = ~16KB compressed
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Status List Credentials
|
|
353
|
+
|
|
354
|
+
The status list itself is a W3C Verifiable Credential:
|
|
355
|
+
|
|
356
|
+
```json
|
|
357
|
+
{
|
|
358
|
+
"@context": [
|
|
359
|
+
"https://www.w3.org/2018/credentials/v1",
|
|
360
|
+
"https://w3id.org/vc/status-list/2021/v1"
|
|
361
|
+
],
|
|
362
|
+
"id": "https://status.example.com/lists/revocation-123",
|
|
363
|
+
"type": ["VerifiableCredential", "StatusList2021Credential"],
|
|
364
|
+
"issuer": "did:key:z6Mk...",
|
|
365
|
+
"issuanceDate": "2025-10-17T00:00:00Z",
|
|
366
|
+
"credentialSubject": {
|
|
367
|
+
"id": "https://status.example.com/lists/revocation-123#list",
|
|
368
|
+
"type": "StatusList2021",
|
|
369
|
+
"statusPurpose": "revocation",
|
|
370
|
+
"encodedList": "H4sIAAAAAAAAA-3BMQEAAADCoPVP..."
|
|
371
|
+
},
|
|
372
|
+
"proof": { ... }
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
## Cascading Revocation
|
|
377
|
+
|
|
378
|
+
When a delegation is revoked, all sub-delegations should also be revoked.
|
|
379
|
+
|
|
380
|
+
### Setting Up Delegation Graph
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
import {
|
|
384
|
+
DelegationGraphManager,
|
|
385
|
+
CascadingRevocationManager
|
|
386
|
+
} from '@kya-os/mcp-i-core';
|
|
387
|
+
|
|
388
|
+
// Create delegation graph
|
|
389
|
+
const graph = createDelegationGraph({
|
|
390
|
+
storage: new MemoryDelegationGraphStorage(), // or your storage
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// Track delegations
|
|
394
|
+
await graph.addDelegation({
|
|
395
|
+
id: 'delegation-root',
|
|
396
|
+
issuerDid: 'did:key:issuer',
|
|
397
|
+
subjectDid: 'did:key:delegate1',
|
|
398
|
+
parentId: null,
|
|
399
|
+
issuedAt: new Date().toISOString(),
|
|
400
|
+
expiresAt: new Date(Date.now() + 86400000).toISOString(),
|
|
401
|
+
statusListUrl: 'https://status.example.com/lists/123',
|
|
402
|
+
statusListIndex: 0,
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
await graph.addDelegation({
|
|
406
|
+
id: 'delegation-sub',
|
|
407
|
+
issuerDid: 'did:key:delegate1',
|
|
408
|
+
subjectDid: 'did:key:delegate2',
|
|
409
|
+
parentId: 'delegation-root', // Link to parent
|
|
410
|
+
issuedAt: new Date().toISOString(),
|
|
411
|
+
expiresAt: new Date(Date.now() + 43200000).toISOString(),
|
|
412
|
+
statusListUrl: 'https://status.example.com/lists/123',
|
|
413
|
+
statusListIndex: 1,
|
|
414
|
+
});
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Cascading Revocation
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
const cascadingRevocation = createCascadingRevocationManager({
|
|
421
|
+
delegationGraph: graph,
|
|
422
|
+
statusListManager: manager,
|
|
423
|
+
issuerIdentity: identityProvider,
|
|
424
|
+
signVC,
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
// Revoke with cascade
|
|
428
|
+
const revokedIds = await cascadingRevocation.revoke('delegation-root', {
|
|
429
|
+
cascade: true,
|
|
430
|
+
reason: 'Security incident',
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
console.log('Revoked delegations:', revokedIds);
|
|
434
|
+
// ['delegation-root', 'delegation-sub']
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### Revocation Hooks
|
|
438
|
+
|
|
439
|
+
```typescript
|
|
440
|
+
// Register hook for custom logic
|
|
441
|
+
cascadingRevocation.onRevoke(async (event) => {
|
|
442
|
+
console.log('Revoked:', event.credentialId);
|
|
443
|
+
console.log('Reason:', event.reason);
|
|
444
|
+
console.log('Cascade:', event.cascade);
|
|
445
|
+
|
|
446
|
+
// Send notification
|
|
447
|
+
await notifyUser(event.credentialId, event.reason);
|
|
448
|
+
|
|
449
|
+
// Log to audit trail
|
|
450
|
+
await auditLog.record({
|
|
451
|
+
action: 'delegation.revoke',
|
|
452
|
+
credentialId: event.credentialId,
|
|
453
|
+
timestamp: new Date(),
|
|
454
|
+
});
|
|
455
|
+
});
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
## Tool Protection
|
|
459
|
+
|
|
460
|
+
Enforce delegation requirements on sensitive tools:
|
|
461
|
+
|
|
462
|
+
```typescript
|
|
463
|
+
import {
|
|
464
|
+
ToolProtectionService,
|
|
465
|
+
InMemoryToolProtectionCache
|
|
466
|
+
} from '@kya-os/mcp-i-core';
|
|
467
|
+
|
|
468
|
+
const toolProtection = new ToolProtectionService({
|
|
469
|
+
cache: new InMemoryToolProtectionCache(),
|
|
470
|
+
delegationVerifier: verifier,
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
// Configure protection
|
|
474
|
+
await toolProtection.setProtection('delete_database', {
|
|
475
|
+
requiresDelegation: true,
|
|
476
|
+
requiredScopes: ['admin', 'delete'],
|
|
477
|
+
budgetLimit: 1000,
|
|
478
|
+
rateLimit: {
|
|
479
|
+
maxCalls: 10,
|
|
480
|
+
windowSeconds: 3600,
|
|
481
|
+
},
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
// Check access
|
|
485
|
+
try {
|
|
486
|
+
const hasAccess = await toolProtection.checkAccess(
|
|
487
|
+
'delete_database',
|
|
488
|
+
'did:key:z6Mkp...',
|
|
489
|
+
delegation
|
|
490
|
+
);
|
|
491
|
+
|
|
492
|
+
if (hasAccess) {
|
|
493
|
+
// Execute tool
|
|
494
|
+
await deleteDatabase();
|
|
495
|
+
|
|
496
|
+
// Track usage
|
|
497
|
+
await toolProtection.trackUsage('delete_database', 'did:key:z6Mkp...', {
|
|
498
|
+
cost: 100,
|
|
499
|
+
timestamp: Date.now(),
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
} catch (error) {
|
|
503
|
+
console.error('Access denied:', error.message);
|
|
504
|
+
}
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
## Best Practices
|
|
508
|
+
|
|
509
|
+
### 1. Key Management
|
|
510
|
+
|
|
511
|
+
```typescript
|
|
512
|
+
// ✅ DO: Use secure key storage
|
|
513
|
+
import { SecureKeyStore } from './secure-storage';
|
|
514
|
+
|
|
515
|
+
const identityProvider = {
|
|
516
|
+
getDID: async () => await keyStore.getDID(),
|
|
517
|
+
getPrivateKey: async () => await keyStore.getPrivateKey(),
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
// ❌ DON'T: Hardcode private keys
|
|
521
|
+
const identityProvider = {
|
|
522
|
+
getDID: async () => 'did:key:z6Mk...',
|
|
523
|
+
getPrivateKey: async () => 'my-private-key-123', // NEVER DO THIS
|
|
524
|
+
};
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
### 2. Principle of Least Privilege
|
|
528
|
+
|
|
529
|
+
```typescript
|
|
530
|
+
// ✅ DO: Minimal scope
|
|
531
|
+
const constraints = {
|
|
532
|
+
scope: {
|
|
533
|
+
allowedTools: ['read_public_data'], // Only what's needed
|
|
534
|
+
allowedResources: ['/public/*.json'], // Specific paths
|
|
535
|
+
},
|
|
536
|
+
time: {
|
|
537
|
+
notBefore: now,
|
|
538
|
+
notAfter: now + 3600000, // 1 hour only
|
|
539
|
+
},
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
// ❌ DON'T: Over-permission
|
|
543
|
+
const constraints = {
|
|
544
|
+
scope: {
|
|
545
|
+
allowedTools: ['*'], // Too broad
|
|
546
|
+
},
|
|
547
|
+
time: {
|
|
548
|
+
notAfter: now + 31536000000, // 1 year is too long
|
|
549
|
+
},
|
|
550
|
+
};
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### 3. Always Enable Revocation
|
|
554
|
+
|
|
555
|
+
```typescript
|
|
556
|
+
// ✅ DO: Include revocation support
|
|
557
|
+
const delegation = await issuer.issue({
|
|
558
|
+
subjectDid,
|
|
559
|
+
constraints,
|
|
560
|
+
credentialStatus: statusEntry, // Always include this
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
// ❌ DON'T: Skip revocation
|
|
564
|
+
const delegation = await issuer.issue({
|
|
565
|
+
subjectDid,
|
|
566
|
+
constraints,
|
|
567
|
+
// No credentialStatus = can't revoke!
|
|
568
|
+
});
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
### 4. Verify Before Use
|
|
572
|
+
|
|
573
|
+
```typescript
|
|
574
|
+
// ✅ DO: Always verify
|
|
575
|
+
async function executeTool(toolName: string, delegation: DelegationCredential) {
|
|
576
|
+
const result = await verifier.verify(delegation);
|
|
577
|
+
if (!result.valid) {
|
|
578
|
+
throw new Error(`Invalid delegation: ${result.errors.join(', ')}`);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// Now execute tool
|
|
582
|
+
return await tools[toolName]();
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// ❌ DON'T: Trust without verification
|
|
586
|
+
async function executeTool(toolName: string, delegation: DelegationCredential) {
|
|
587
|
+
// Skipping verification = security vulnerability
|
|
588
|
+
return await tools[toolName]();
|
|
589
|
+
}
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
### 5. Monitor Usage
|
|
593
|
+
|
|
594
|
+
```typescript
|
|
595
|
+
// ✅ DO: Track and alert
|
|
596
|
+
toolProtection.onUsage(async (event) => {
|
|
597
|
+
await metrics.record({
|
|
598
|
+
tool: event.toolName,
|
|
599
|
+
user: event.userDid,
|
|
600
|
+
cost: event.cost,
|
|
601
|
+
timestamp: event.timestamp,
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
// Alert on suspicious patterns
|
|
605
|
+
if (event.cost > 1000) {
|
|
606
|
+
await alerting.send(`High cost usage: ${event.cost}`);
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
## Complete Example
|
|
612
|
+
|
|
613
|
+
```typescript
|
|
614
|
+
import {
|
|
615
|
+
createDelegationIssuer,
|
|
616
|
+
createDelegationVerifier,
|
|
617
|
+
createStatusListManager,
|
|
618
|
+
createCascadingRevocationManager,
|
|
619
|
+
createDelegationGraph,
|
|
620
|
+
ToolProtectionService,
|
|
621
|
+
InMemoryToolProtectionCache,
|
|
622
|
+
MemoryStatusListStorage,
|
|
623
|
+
MemoryDelegationGraphStorage,
|
|
624
|
+
} from '@kya-os/mcp-i-core';
|
|
625
|
+
|
|
626
|
+
// Setup
|
|
627
|
+
const issuer = createDelegationIssuer({ identityProvider, signVC });
|
|
628
|
+
const verifier = createDelegationVerifier({ resolveDID, verifySignature, resolveStatusList });
|
|
629
|
+
const statusListManager = createStatusListManager({ identityProvider, storage: new MemoryStatusListStorage(), signVC });
|
|
630
|
+
const delegationGraph = createDelegationGraph({ storage: new MemoryDelegationGraphStorage() });
|
|
631
|
+
const cascadingRevocation = createCascadingRevocationManager({
|
|
632
|
+
delegationGraph,
|
|
633
|
+
statusListManager,
|
|
634
|
+
issuerIdentity: identityProvider,
|
|
635
|
+
signVC,
|
|
636
|
+
});
|
|
637
|
+
const toolProtection = new ToolProtectionService({
|
|
638
|
+
cache: new InMemoryToolProtectionCache(),
|
|
639
|
+
delegationVerifier: verifier,
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
// 1. Issue delegation
|
|
643
|
+
const statusListId = await statusListManager.createStatusList('revocation');
|
|
644
|
+
const delegation = await issuer.issue({
|
|
645
|
+
subjectDid: 'did:key:delegate',
|
|
646
|
+
constraints: {
|
|
647
|
+
scope: { allowedTools: ['read', 'write'] },
|
|
648
|
+
budget: { maxCost: 100, currency: 'USD' },
|
|
649
|
+
time: {
|
|
650
|
+
notBefore: new Date().toISOString(),
|
|
651
|
+
notAfter: new Date(Date.now() + 3600000).toISOString(),
|
|
652
|
+
},
|
|
653
|
+
},
|
|
654
|
+
audience: 'https://api.example.com',
|
|
655
|
+
credentialStatus: {
|
|
656
|
+
id: `https://status.example.com/lists/${statusListId}#0`,
|
|
657
|
+
type: 'StatusList2021Entry',
|
|
658
|
+
statusPurpose: 'revocation',
|
|
659
|
+
statusListIndex: '0',
|
|
660
|
+
statusListCredential: `https://status.example.com/lists/${statusListId}`,
|
|
661
|
+
},
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
// 2. Track in graph
|
|
665
|
+
await delegationGraph.addDelegation({
|
|
666
|
+
id: delegation.id!,
|
|
667
|
+
issuerDid: await identityProvider.getDID(),
|
|
668
|
+
subjectDid: 'did:key:delegate',
|
|
669
|
+
parentId: null,
|
|
670
|
+
issuedAt: delegation.issuanceDate,
|
|
671
|
+
expiresAt: delegation.expirationDate!,
|
|
672
|
+
statusListUrl: `https://status.example.com/lists/${statusListId}`,
|
|
673
|
+
statusListIndex: 0,
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
// 3. Configure tool protection
|
|
677
|
+
await toolProtection.setProtection('write', {
|
|
678
|
+
requiresDelegation: true,
|
|
679
|
+
requiredScopes: ['write'],
|
|
680
|
+
budgetLimit: 50,
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
// 4. Execute tool with delegation
|
|
684
|
+
const result = await verifier.verify(delegation);
|
|
685
|
+
if (result.valid) {
|
|
686
|
+
const hasAccess = await toolProtection.checkAccess('write', 'did:key:delegate', delegation);
|
|
687
|
+
if (hasAccess) {
|
|
688
|
+
// Execute tool
|
|
689
|
+
await executeWriteTool();
|
|
690
|
+
|
|
691
|
+
// Track usage
|
|
692
|
+
await toolProtection.trackUsage('write', 'did:key:delegate', {
|
|
693
|
+
cost: 10,
|
|
694
|
+
timestamp: Date.now(),
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// 5. Revoke if needed
|
|
700
|
+
await cascadingRevocation.revoke(delegation.id!, {
|
|
701
|
+
cascade: true,
|
|
702
|
+
reason: 'Project completed',
|
|
703
|
+
});
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
## Next Steps
|
|
707
|
+
|
|
708
|
+
- [StatusList2021 Guide](./STATUSLIST2021_GUIDE.md) - Deep dive into revocation
|
|
709
|
+
- [Compliance Matrix](./COMPLIANCE_MATRIX.md) - Schema compliance status
|
|
710
|
+
- [API Reference](./API_REFERENCE.md) - Complete API documentation
|