@kya-os/mcp-i-core 1.3.7-canary.0 → 1.3.7-canary.clientinfo.20251126041014
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/.turbo/turbo-build.log +4 -0
- package/.turbo/turbo-test$colon$coverage.log +4239 -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 +24 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +43 -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 +19 -2
- package/dist/runtime/base.d.ts.map +1 -1
- package/dist/runtime/base.js +227 -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 +199 -15
- 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/index.d.ts +2 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +4 -1
- package/dist/services/index.js.map +1 -1
- 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 +141 -0
- package/dist/services/oauth-config.service.js.map +1 -0
- package/dist/services/oauth-provider-registry.d.ts +88 -0
- package/dist/services/oauth-provider-registry.d.ts.map +1 -0
- package/dist/services/oauth-provider-registry.js +128 -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 +373 -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 +121 -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/session-registration.service.d.ts +80 -0
- package/dist/services/session-registration.service.d.ts.map +1 -0
- package/dist/services/session-registration.service.js +228 -0
- package/dist/services/session-registration.service.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 +27 -0
- package/dist/services/tool-protection.service.d.ts.map +1 -1
- package/dist/services/tool-protection.service.js +194 -4
- 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 +23 -54
- 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 +429 -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/cache-busting.test.ts +125 -0
- package/src/__tests__/services/oauth-service-pkce.test.ts +556 -0
- package/src/__tests__/services/provider-resolver-edge-cases.test.ts +591 -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.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 +271 -0
- package/src/providers/base.d.ts +91 -0
- package/src/providers/base.d.ts.map +1 -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 +202 -0
- package/src/services/__tests__/provider-resolver.test.ts +213 -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 +18 -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.map +1 -0
- package/src/services/oauth-config.service.ts +192 -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.map +1 -0
- package/src/services/oauth-provider-registry.ts +141 -0
- package/src/services/oauth-service.ts +544 -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.map +1 -0
- package/src/services/provider-resolver.ts +146 -0
- package/src/services/provider-validator.ts +170 -0
- package/src/services/session-registration.service.ts +317 -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 +982 -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,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delegation Verification Flow Integration Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests the complete flow: handshake → session creation → tool call → delegation verification
|
|
5
|
+
* Ensures that session.agentDid is correctly used in delegation verification.
|
|
6
|
+
*
|
|
7
|
+
* @package @kya-os/mcp-i-core/__tests__/runtime
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { describe, it, expect, beforeEach } from "vitest";
|
|
11
|
+
import { MCPIRuntimeBase } from "../../runtime/base";
|
|
12
|
+
import { ProviderRuntimeConfig } from "../../config";
|
|
13
|
+
import {
|
|
14
|
+
createMockProviders,
|
|
15
|
+
MockClockProvider,
|
|
16
|
+
MockIdentityProvider,
|
|
17
|
+
MockNonceCacheProvider,
|
|
18
|
+
} from "../utils/mock-providers";
|
|
19
|
+
import type { DelegationRecord } from "@kya-os/contracts/delegation";
|
|
20
|
+
|
|
21
|
+
describe("Delegation Verification Flow", () => {
|
|
22
|
+
let runtime: MCPIRuntimeBase;
|
|
23
|
+
let config: ProviderRuntimeConfig;
|
|
24
|
+
let mockProviders: ReturnType<typeof createMockProviders>;
|
|
25
|
+
|
|
26
|
+
beforeEach(async () => {
|
|
27
|
+
mockProviders = createMockProviders();
|
|
28
|
+
config = {
|
|
29
|
+
...mockProviders,
|
|
30
|
+
environment: "development",
|
|
31
|
+
session: {
|
|
32
|
+
timestampSkewSeconds: 120,
|
|
33
|
+
ttlMinutes: 30,
|
|
34
|
+
},
|
|
35
|
+
audit: {
|
|
36
|
+
enabled: false, // Disable audit for cleaner test output
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
runtime = new MCPIRuntimeBase(config);
|
|
40
|
+
await runtime.initialize();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("should verify delegation using session.agentDid", async () => {
|
|
44
|
+
const agentDid = "did:key:zagent123";
|
|
45
|
+
const userDid = "did:web:user.example.com";
|
|
46
|
+
|
|
47
|
+
// 1. Perform handshake with agentDid
|
|
48
|
+
const handshakeRequest = {
|
|
49
|
+
nonce: "test-nonce-123",
|
|
50
|
+
audience: "https://server.example.com",
|
|
51
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
52
|
+
agentDid,
|
|
53
|
+
clientDid: userDid,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const handshakeResponse = await runtime.handleHandshake(handshakeRequest);
|
|
57
|
+
expect(handshakeResponse.sessionId).toBeDefined();
|
|
58
|
+
|
|
59
|
+
// 2. Get session and verify agentDid is correct
|
|
60
|
+
const session = await runtime.getCurrentSession();
|
|
61
|
+
expect(session).toBeDefined();
|
|
62
|
+
expect(session?.agentDid).toBe(agentDid); // ✅ Should be client's agent DID, not server DID
|
|
63
|
+
expect(session?.serverDid).toBe("did:key:zmock123"); // ✅ Should be server's DID
|
|
64
|
+
|
|
65
|
+
// 3. Create a delegation with subjectDid matching agentDid
|
|
66
|
+
// (In real scenario, this would be verified via delegation verifier)
|
|
67
|
+
const delegation: DelegationRecord = {
|
|
68
|
+
id: "del_test_001",
|
|
69
|
+
issuerDid: userDid,
|
|
70
|
+
subjectDid: agentDid, // ✅ Matches session.agentDid
|
|
71
|
+
controller: "user_alice",
|
|
72
|
+
vcId: "vc_test_001",
|
|
73
|
+
constraints: {
|
|
74
|
+
scopes: ["tool:execute"],
|
|
75
|
+
},
|
|
76
|
+
createdAt: Date.now(),
|
|
77
|
+
expiresAt: Date.now() + 3600000, // 1 hour
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// 4. Verify that delegation.subjectDid matches session.agentDid
|
|
81
|
+
expect(delegation.subjectDid).toBe(session?.agentDid);
|
|
82
|
+
expect(delegation.subjectDid).not.toBe(session?.serverDid); // ✅ Should NOT match server DID
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("should fail when session.agentDid does not match delegation.subjectDid", async () => {
|
|
86
|
+
const agentDid = "did:key:zagent123";
|
|
87
|
+
const wrongAgentDid = "did:key:zwrong456";
|
|
88
|
+
const userDid = "did:web:user.example.com";
|
|
89
|
+
|
|
90
|
+
// 1. Perform handshake with agentDid
|
|
91
|
+
const handshakeRequest = {
|
|
92
|
+
nonce: "test-nonce-456",
|
|
93
|
+
audience: "https://server.example.com",
|
|
94
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
95
|
+
agentDid,
|
|
96
|
+
clientDid: userDid,
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
await runtime.handleHandshake(handshakeRequest);
|
|
100
|
+
|
|
101
|
+
// 2. Get session
|
|
102
|
+
const session = await runtime.getCurrentSession();
|
|
103
|
+
expect(session?.agentDid).toBe(agentDid);
|
|
104
|
+
|
|
105
|
+
// 3. Create delegation with wrong subjectDid
|
|
106
|
+
const delegation: DelegationRecord = {
|
|
107
|
+
id: "del_test_002",
|
|
108
|
+
issuerDid: userDid,
|
|
109
|
+
subjectDid: wrongAgentDid, // ❌ Does NOT match session.agentDid
|
|
110
|
+
controller: "user_bob",
|
|
111
|
+
vcId: "vc_test_002",
|
|
112
|
+
constraints: {
|
|
113
|
+
scopes: ["tool:execute"],
|
|
114
|
+
},
|
|
115
|
+
createdAt: Date.now(),
|
|
116
|
+
expiresAt: Date.now() + 3600000,
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// 4. Verify mismatch
|
|
120
|
+
expect(delegation.subjectDid).not.toBe(session?.agentDid);
|
|
121
|
+
expect(delegation.subjectDid).toBe(wrongAgentDid);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("should handle session without agentDid gracefully", async () => {
|
|
125
|
+
const userDid = "did:web:user.example.com";
|
|
126
|
+
|
|
127
|
+
// 1. Perform handshake WITHOUT agentDid
|
|
128
|
+
const handshakeRequest = {
|
|
129
|
+
nonce: "test-nonce-789",
|
|
130
|
+
audience: "https://server.example.com",
|
|
131
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
132
|
+
// agentDid not provided
|
|
133
|
+
clientDid: userDid,
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
await runtime.handleHandshake(handshakeRequest);
|
|
137
|
+
|
|
138
|
+
// 2. Get session
|
|
139
|
+
const session = await runtime.getCurrentSession();
|
|
140
|
+
expect(session?.agentDid).toBeUndefined(); // ✅ Should be undefined, not fallback to clientDid
|
|
141
|
+
expect(session?.serverDid).toBe("did:key:zmock123"); // ✅ Server DID should still be set
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("should verify serverDid is set correctly in session", async () => {
|
|
145
|
+
const agentDid = "did:key:zagent789";
|
|
146
|
+
const identity = await runtime.getIdentity();
|
|
147
|
+
|
|
148
|
+
// 1. Perform handshake
|
|
149
|
+
const handshakeRequest = {
|
|
150
|
+
nonce: "test-nonce-server",
|
|
151
|
+
audience: "https://server.example.com",
|
|
152
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
153
|
+
agentDid,
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
await runtime.handleHandshake(handshakeRequest);
|
|
157
|
+
|
|
158
|
+
// 2. Verify serverDid matches identity.did
|
|
159
|
+
const session = await runtime.getCurrentSession();
|
|
160
|
+
expect(session?.serverDid).toBe(identity.did);
|
|
161
|
+
expect(session?.serverDid).not.toBe(agentDid); // ✅ Should NOT match agent DID
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Proof Client DID Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for proof generation with clientDid tracking and extraction.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
8
|
+
import { MCPIRuntimeBase } from '../../runtime/base';
|
|
9
|
+
import { ProviderRuntimeConfig } from '../../config';
|
|
10
|
+
import { createMockProviders, MockClockProvider } from '../utils/mock-providers';
|
|
11
|
+
|
|
12
|
+
describe('MCPIRuntimeBase - Proof Client DID', () => {
|
|
13
|
+
let runtime: MCPIRuntimeBase;
|
|
14
|
+
let config: ProviderRuntimeConfig;
|
|
15
|
+
let mockProviders: ReturnType<typeof createMockProviders>;
|
|
16
|
+
|
|
17
|
+
beforeEach(async () => {
|
|
18
|
+
vi.clearAllMocks();
|
|
19
|
+
mockProviders = createMockProviders();
|
|
20
|
+
config = {
|
|
21
|
+
...mockProviders,
|
|
22
|
+
environment: 'development',
|
|
23
|
+
session: {
|
|
24
|
+
timestampSkewSeconds: 120,
|
|
25
|
+
ttlMinutes: 30
|
|
26
|
+
},
|
|
27
|
+
audit: {
|
|
28
|
+
enabled: false
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
runtime = new MCPIRuntimeBase(config);
|
|
32
|
+
await runtime.initialize();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('createProof with clientDid', () => {
|
|
36
|
+
it('should include clientDid in proof when provided in session', async () => {
|
|
37
|
+
const testData = { result: 'success' };
|
|
38
|
+
const session = {
|
|
39
|
+
id: 'session123',
|
|
40
|
+
audience: 'https://client.example.com',
|
|
41
|
+
nonce: 'test-nonce',
|
|
42
|
+
clientDid: 'did:key:zclient123'
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const proof = await runtime.createProof(testData, session);
|
|
46
|
+
|
|
47
|
+
expect(proof).toBeDefined();
|
|
48
|
+
expect(proof.did).toBe('did:key:zmock123'); // Agent DID
|
|
49
|
+
expect(proof.sessionId).toBe('session123');
|
|
50
|
+
expect(proof.audience).toBe('https://client.example.com');
|
|
51
|
+
// Note: clientDid is stored in proofData but not directly in proof object
|
|
52
|
+
// The proof structure includes sessionId which can be used to retrieve clientDid
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should include userDid in proof when provided in session', async () => {
|
|
56
|
+
const testData = { result: 'success' };
|
|
57
|
+
const session = {
|
|
58
|
+
id: 'session123',
|
|
59
|
+
audience: 'https://client.example.com',
|
|
60
|
+
nonce: 'test-nonce',
|
|
61
|
+
userDid: 'did:key:zuser456'
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const proof = await runtime.createProof(testData, session);
|
|
65
|
+
|
|
66
|
+
expect(proof).toBeDefined();
|
|
67
|
+
expect(proof.sessionId).toBe('session123');
|
|
68
|
+
// userDid is stored in session context
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should work without clientDid or userDid (backward compatibility)', async () => {
|
|
72
|
+
const testData = { result: 'success' };
|
|
73
|
+
const session = {
|
|
74
|
+
id: 'session123',
|
|
75
|
+
audience: 'https://client.example.com',
|
|
76
|
+
nonce: 'test-nonce'
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const proof = await runtime.createProof(testData, session);
|
|
80
|
+
|
|
81
|
+
expect(proof).toBeDefined();
|
|
82
|
+
expect(proof.did).toBe('did:key:zmock123');
|
|
83
|
+
expect(proof.sessionId).toBe('session123');
|
|
84
|
+
expect(proof.audience).toBe('https://client.example.com');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should prioritize clientDid over userDid when both provided', async () => {
|
|
88
|
+
const testData = { result: 'success' };
|
|
89
|
+
const session = {
|
|
90
|
+
id: 'session123',
|
|
91
|
+
audience: 'https://client.example.com',
|
|
92
|
+
nonce: 'test-nonce',
|
|
93
|
+
clientDid: 'did:key:zclient123',
|
|
94
|
+
userDid: 'did:key:zuser456'
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const proof = await runtime.createProof(testData, session);
|
|
98
|
+
|
|
99
|
+
expect(proof).toBeDefined();
|
|
100
|
+
expect(proof.sessionId).toBe('session123');
|
|
101
|
+
// clientDid takes precedence in session context
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe('processToolCall with clientDid', () => {
|
|
106
|
+
const mockHandler = vi.fn().mockResolvedValue({ result: 'success' });
|
|
107
|
+
|
|
108
|
+
it('should include clientDid in proof when session has clientDid', async () => {
|
|
109
|
+
const session = {
|
|
110
|
+
id: 'session123',
|
|
111
|
+
audience: 'https://client.example.com',
|
|
112
|
+
nonce: 'test-nonce',
|
|
113
|
+
clientDid: 'did:key:zclient123'
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
await runtime.processToolCall(
|
|
117
|
+
'testTool',
|
|
118
|
+
{ arg: 'value' },
|
|
119
|
+
mockHandler,
|
|
120
|
+
session
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
const proof = runtime.getLastProof();
|
|
124
|
+
expect(proof).toBeDefined();
|
|
125
|
+
expect(proof.sessionId).toBe('session123');
|
|
126
|
+
expect(proof.audience).toBe('https://client.example.com');
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('should extract clientDid from handshake session', async () => {
|
|
130
|
+
// Create session via handshake
|
|
131
|
+
const handshakeResponse = await runtime.handleHandshake({
|
|
132
|
+
clientDid: 'did:key:zhandshake123',
|
|
133
|
+
audience: 'https://client.example.com'
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const session = await runtime.getCurrentSession();
|
|
137
|
+
const proof = await runtime.createProof(
|
|
138
|
+
{ test: 'data' },
|
|
139
|
+
session
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
expect(proof.sessionId).toBe(handshakeResponse.sessionId);
|
|
143
|
+
expect(session.clientDid).toBe('did:key:zhandshake123');
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('should handle userDid from handshake session', async () => {
|
|
147
|
+
// Initialize runtime with user DID generation enabled
|
|
148
|
+
const configWithUserDid = {
|
|
149
|
+
...config,
|
|
150
|
+
identity: {
|
|
151
|
+
enabled: true,
|
|
152
|
+
generateUserDids: true,
|
|
153
|
+
environment: 'development'
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
const runtimeWithUserDid = new MCPIRuntimeBase(configWithUserDid);
|
|
157
|
+
await runtimeWithUserDid.initialize();
|
|
158
|
+
|
|
159
|
+
const handshakeResponse = await runtimeWithUserDid.handleHandshake({
|
|
160
|
+
audience: 'https://client.example.com'
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const session = await runtimeWithUserDid.getCurrentSession();
|
|
164
|
+
expect(session).toBeDefined();
|
|
165
|
+
|
|
166
|
+
// When userDid generation is enabled, it should be generated and available
|
|
167
|
+
// This is a critical assertion - if userDid is missing, the test should fail
|
|
168
|
+
expect(session.userDid).toBeDefined();
|
|
169
|
+
expect(session.userDid).toMatch(/^did:key:z/);
|
|
170
|
+
|
|
171
|
+
const proof = await runtimeWithUserDid.createProof(
|
|
172
|
+
{ test: 'data' },
|
|
173
|
+
session
|
|
174
|
+
);
|
|
175
|
+
expect(proof.sessionId).toBe(handshakeResponse.sessionId);
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
describe('verifyProof with clientDid context', () => {
|
|
180
|
+
let validProof: any;
|
|
181
|
+
const testData = { foo: 'bar' };
|
|
182
|
+
|
|
183
|
+
beforeEach(async () => {
|
|
184
|
+
// Set up DID document for verification
|
|
185
|
+
const fetchProvider = mockProviders.fetchProvider as any;
|
|
186
|
+
fetchProvider.setDIDDocument('did:key:zmock123', {
|
|
187
|
+
verificationMethod: [{
|
|
188
|
+
publicKeyBase64: 'mock-public-key'
|
|
189
|
+
}]
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
const session = {
|
|
193
|
+
id: 'session123',
|
|
194
|
+
audience: 'https://client.example.com',
|
|
195
|
+
nonce: 'test-nonce',
|
|
196
|
+
clientDid: 'did:key:zclient123'
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
validProof = await runtime.createProof(testData, session);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('should verify proof with clientDid in session context', async () => {
|
|
203
|
+
const nonceCache = mockProviders.nonceCacheProvider as any;
|
|
204
|
+
nonceCache.clear();
|
|
205
|
+
|
|
206
|
+
const isValid = await runtime.verifyProof(testData, validProof);
|
|
207
|
+
expect(isValid).toBe(true);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('should verify proof independently of clientDid presence', async () => {
|
|
211
|
+
// Create proof without clientDid
|
|
212
|
+
const proofWithoutClientDid = await runtime.createProof(testData, {
|
|
213
|
+
id: 'session456',
|
|
214
|
+
audience: 'https://client.example.com',
|
|
215
|
+
nonce: 'other-nonce'
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
const nonceCache = mockProviders.nonceCacheProvider as any;
|
|
219
|
+
nonceCache.clear();
|
|
220
|
+
|
|
221
|
+
const isValid = await runtime.verifyProof(testData, proofWithoutClientDid);
|
|
222
|
+
expect(isValid).toBe(true);
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
describe('clientDid extraction from session', () => {
|
|
227
|
+
it('should retrieve clientDid from active session', async () => {
|
|
228
|
+
const handshakeResponse = await runtime.handleHandshake({
|
|
229
|
+
clientDid: 'did:key:zclient789',
|
|
230
|
+
audience: 'https://client.example.com'
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
const session = await runtime.getCurrentSession();
|
|
234
|
+
expect(session.clientDid).toBe('did:key:zclient789');
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('should use generated userDid as clientDid when no clientDid provided', async () => {
|
|
238
|
+
const configWithUserDid = {
|
|
239
|
+
...config,
|
|
240
|
+
identity: {
|
|
241
|
+
enabled: true,
|
|
242
|
+
generateUserDids: true,
|
|
243
|
+
environment: 'development'
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
const runtimeWithUserDid = new MCPIRuntimeBase(configWithUserDid);
|
|
247
|
+
await runtimeWithUserDid.initialize();
|
|
248
|
+
|
|
249
|
+
const handshakeResponse = await runtimeWithUserDid.handleHandshake({
|
|
250
|
+
audience: 'https://client.example.com'
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
const session = await runtimeWithUserDid.getCurrentSession();
|
|
254
|
+
expect(session).toBeDefined();
|
|
255
|
+
|
|
256
|
+
// When userDid generation is enabled, it should be generated and available
|
|
257
|
+
// This is a critical assertion - if userDid is missing, the test should fail
|
|
258
|
+
expect(session.userDid).toBeDefined();
|
|
259
|
+
expect(session.userDid).toMatch(/^did:key:z/);
|
|
260
|
+
|
|
261
|
+
// clientDid should be set to userDid if no explicit clientDid provided
|
|
262
|
+
expect(session.clientDid || session.userDid).toBeDefined();
|
|
263
|
+
|
|
264
|
+
// Verify proof includes the session
|
|
265
|
+
const proof = await runtimeWithUserDid.createProof(
|
|
266
|
+
{ test: 'data' },
|
|
267
|
+
session
|
|
268
|
+
);
|
|
269
|
+
expect(proof.sessionId).toBe(handshakeResponse.sessionId);
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
describe('edge cases', () => {
|
|
274
|
+
it('should handle empty clientDid string gracefully', async () => {
|
|
275
|
+
const session = {
|
|
276
|
+
id: 'session123',
|
|
277
|
+
audience: 'https://client.example.com',
|
|
278
|
+
nonce: 'test-nonce',
|
|
279
|
+
clientDid: ''
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
const proof = await runtime.createProof({ test: 'data' }, session);
|
|
283
|
+
expect(proof).toBeDefined();
|
|
284
|
+
expect(proof.sessionId).toBe('session123');
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it('should handle null clientDid gracefully', async () => {
|
|
288
|
+
const session = {
|
|
289
|
+
id: 'session123',
|
|
290
|
+
audience: 'https://client.example.com',
|
|
291
|
+
nonce: 'test-nonce',
|
|
292
|
+
clientDid: null as any
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
const proof = await runtime.createProof({ test: 'data' }, session);
|
|
296
|
+
expect(proof).toBeDefined();
|
|
297
|
+
expect(proof.sessionId).toBe('session123');
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it('should handle undefined clientDid gracefully', async () => {
|
|
301
|
+
const session = {
|
|
302
|
+
id: 'session123',
|
|
303
|
+
audience: 'https://client.example.com',
|
|
304
|
+
nonce: 'test-nonce'
|
|
305
|
+
// clientDid is undefined
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
const proof = await runtime.createProof({ test: 'data' }, session);
|
|
309
|
+
expect(proof).toBeDefined();
|
|
310
|
+
expect(proof.sessionId).toBe('session123');
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it('should handle invalid DID format in clientDid', async () => {
|
|
314
|
+
const session = {
|
|
315
|
+
id: 'session123',
|
|
316
|
+
audience: 'https://client.example.com',
|
|
317
|
+
nonce: 'test-nonce',
|
|
318
|
+
clientDid: 'invalid-did-format'
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const proof = await runtime.createProof({ test: 'data' }, session);
|
|
322
|
+
expect(proof).toBeDefined();
|
|
323
|
+
// Proof should still be created even with invalid DID format
|
|
324
|
+
expect(proof.sessionId).toBe('session123');
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
describe('proof metadata consistency', () => {
|
|
329
|
+
it('should maintain consistent proof structure with clientDid', async () => {
|
|
330
|
+
const session = {
|
|
331
|
+
id: 'session123',
|
|
332
|
+
audience: 'https://client.example.com',
|
|
333
|
+
nonce: 'test-nonce',
|
|
334
|
+
clientDid: 'did:key:zclient123'
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
const proof1 = await runtime.createProof({ test: 'data1' }, session);
|
|
338
|
+
const proof2 = await runtime.createProof({ test: 'data2' }, session);
|
|
339
|
+
|
|
340
|
+
// Both proofs should have same sessionId and audience
|
|
341
|
+
expect(proof1.sessionId).toBe(proof2.sessionId);
|
|
342
|
+
expect(proof1.audience).toBe(proof2.audience);
|
|
343
|
+
|
|
344
|
+
// But different nonces (if not pre-provided)
|
|
345
|
+
// Since we're using same nonce, they should be same
|
|
346
|
+
expect(proof1.nonce).toBe(proof2.nonce);
|
|
347
|
+
|
|
348
|
+
// Different timestamps
|
|
349
|
+
expect(proof1.timestamp).toBeLessThanOrEqual(proof2.timestamp);
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it('should use different proofs for different sessions', async () => {
|
|
353
|
+
const session1 = {
|
|
354
|
+
id: 'session1',
|
|
355
|
+
audience: 'https://client.example.com',
|
|
356
|
+
nonce: 'nonce1',
|
|
357
|
+
clientDid: 'did:key:zclient1'
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
const session2 = {
|
|
361
|
+
id: 'session2',
|
|
362
|
+
audience: 'https://client.example.com',
|
|
363
|
+
nonce: 'nonce2',
|
|
364
|
+
clientDid: 'did:key:zclient2'
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
const proof1 = await runtime.createProof({ test: 'data' }, session1);
|
|
368
|
+
const proof2 = await runtime.createProof({ test: 'data' }, session2);
|
|
369
|
+
|
|
370
|
+
expect(proof1.sessionId).not.toBe(proof2.sessionId);
|
|
371
|
+
expect(proof1.nonce).not.toBe(proof2.nonce);
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
});
|
|
375
|
+
|