@kya-os/mcp-i-core 1.3.13 → 1.3.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/dist/config/remote-config.js +9 -12
  2. package/dist/runtime/base.d.ts +2 -1
  3. package/dist/runtime/base.js +34 -6
  4. package/dist/services/access-control.service.js +5 -0
  5. package/dist/services/tool-protection.service.js +17 -8
  6. package/package.json +2 -2
  7. package/.turbo/turbo-build.log +0 -4
  8. package/.turbo/turbo-test$colon$coverage.log +0 -4586
  9. package/.turbo/turbo-test.log +0 -4631
  10. package/COMPLIANCE_IMPROVEMENT_REPORT.md +0 -483
  11. package/Composer 3.md +0 -615
  12. package/GPT-5.md +0 -1169
  13. package/OPUS-plan.md +0 -352
  14. package/PHASE_3_AND_4.1_SUMMARY.md +0 -585
  15. package/PHASE_3_SUMMARY.md +0 -317
  16. package/PHASE_4.1.3_SUMMARY.md +0 -428
  17. package/PHASE_4.1_COMPLETE.md +0 -525
  18. package/PHASE_4_USER_DID_IDENTITY_LINKING_PLAN.md +0 -1240
  19. package/SCHEMA_COMPLIANCE_REPORT.md +0 -275
  20. package/TEST_PLAN.md +0 -571
  21. package/coverage/coverage-final.json +0 -60
  22. package/dist/cache/oauth-config-cache.d.ts.map +0 -1
  23. package/dist/cache/oauth-config-cache.js.map +0 -1
  24. package/dist/cache/tool-protection-cache.d.ts.map +0 -1
  25. package/dist/cache/tool-protection-cache.js.map +0 -1
  26. package/dist/compliance/index.d.ts.map +0 -1
  27. package/dist/compliance/index.js.map +0 -1
  28. package/dist/compliance/schema-registry.d.ts.map +0 -1
  29. package/dist/compliance/schema-registry.js.map +0 -1
  30. package/dist/compliance/schema-verifier.d.ts.map +0 -1
  31. package/dist/compliance/schema-verifier.js.map +0 -1
  32. package/dist/config/remote-config.d.ts.map +0 -1
  33. package/dist/config/remote-config.js.map +0 -1
  34. package/dist/config.d.ts.map +0 -1
  35. package/dist/config.js.map +0 -1
  36. package/dist/delegation/audience-validator.d.ts.map +0 -1
  37. package/dist/delegation/audience-validator.js.map +0 -1
  38. package/dist/delegation/bitstring.d.ts.map +0 -1
  39. package/dist/delegation/bitstring.js.map +0 -1
  40. package/dist/delegation/cascading-revocation.d.ts.map +0 -1
  41. package/dist/delegation/cascading-revocation.js.map +0 -1
  42. package/dist/delegation/delegation-graph.d.ts.map +0 -1
  43. package/dist/delegation/delegation-graph.js.map +0 -1
  44. package/dist/delegation/did-key-resolver.d.ts.map +0 -1
  45. package/dist/delegation/did-key-resolver.js.map +0 -1
  46. package/dist/delegation/index.d.ts.map +0 -1
  47. package/dist/delegation/index.js.map +0 -1
  48. package/dist/delegation/statuslist-manager.d.ts.map +0 -1
  49. package/dist/delegation/statuslist-manager.js.map +0 -1
  50. package/dist/delegation/storage/index.d.ts.map +0 -1
  51. package/dist/delegation/storage/index.js.map +0 -1
  52. package/dist/delegation/storage/memory-graph-storage.d.ts.map +0 -1
  53. package/dist/delegation/storage/memory-graph-storage.js.map +0 -1
  54. package/dist/delegation/storage/memory-statuslist-storage.d.ts.map +0 -1
  55. package/dist/delegation/storage/memory-statuslist-storage.js.map +0 -1
  56. package/dist/delegation/utils.d.ts.map +0 -1
  57. package/dist/delegation/utils.js.map +0 -1
  58. package/dist/delegation/vc-issuer.d.ts.map +0 -1
  59. package/dist/delegation/vc-issuer.js.map +0 -1
  60. package/dist/delegation/vc-verifier.d.ts.map +0 -1
  61. package/dist/delegation/vc-verifier.js.map +0 -1
  62. package/dist/identity/idp-token-resolver.d.ts.map +0 -1
  63. package/dist/identity/idp-token-resolver.js.map +0 -1
  64. package/dist/identity/idp-token-storage.interface.d.ts.map +0 -1
  65. package/dist/identity/idp-token-storage.interface.js.map +0 -1
  66. package/dist/identity/user-did-manager.d.ts.map +0 -1
  67. package/dist/identity/user-did-manager.js.map +0 -1
  68. package/dist/index.d.ts.map +0 -1
  69. package/dist/index.js.map +0 -1
  70. package/dist/providers/base.d.ts.map +0 -1
  71. package/dist/providers/base.js.map +0 -1
  72. package/dist/providers/memory.d.ts.map +0 -1
  73. package/dist/providers/memory.js.map +0 -1
  74. package/dist/runtime/audit-logger.d.ts.map +0 -1
  75. package/dist/runtime/audit-logger.js.map +0 -1
  76. package/dist/runtime/base.d.ts.map +0 -1
  77. package/dist/runtime/base.js.map +0 -1
  78. package/dist/services/access-control.service.d.ts.map +0 -1
  79. package/dist/services/access-control.service.js.map +0 -1
  80. package/dist/services/authorization/authorization-registry.d.ts.map +0 -1
  81. package/dist/services/authorization/authorization-registry.js.map +0 -1
  82. package/dist/services/authorization/types.d.ts.map +0 -1
  83. package/dist/services/authorization/types.js.map +0 -1
  84. package/dist/services/batch-delegation.service.d.ts.map +0 -1
  85. package/dist/services/batch-delegation.service.js.map +0 -1
  86. package/dist/services/crypto.service.d.ts.map +0 -1
  87. package/dist/services/crypto.service.js.map +0 -1
  88. package/dist/services/errors.d.ts.map +0 -1
  89. package/dist/services/errors.js.map +0 -1
  90. package/dist/services/index.d.ts.map +0 -1
  91. package/dist/services/index.js.map +0 -1
  92. package/dist/services/oauth-config.service.d.ts.map +0 -1
  93. package/dist/services/oauth-config.service.js.map +0 -1
  94. package/dist/services/oauth-provider-registry.d.ts.map +0 -1
  95. package/dist/services/oauth-provider-registry.js.map +0 -1
  96. package/dist/services/oauth-service.d.ts.map +0 -1
  97. package/dist/services/oauth-service.js.map +0 -1
  98. package/dist/services/oauth-token-retrieval.service.d.ts.map +0 -1
  99. package/dist/services/oauth-token-retrieval.service.js.map +0 -1
  100. package/dist/services/proof-verifier.d.ts.map +0 -1
  101. package/dist/services/proof-verifier.js.map +0 -1
  102. package/dist/services/provider-resolver.d.ts.map +0 -1
  103. package/dist/services/provider-resolver.js.map +0 -1
  104. package/dist/services/provider-validator.d.ts.map +0 -1
  105. package/dist/services/provider-validator.js.map +0 -1
  106. package/dist/services/session-registration.service.d.ts.map +0 -1
  107. package/dist/services/session-registration.service.js.map +0 -1
  108. package/dist/services/storage.service.d.ts.map +0 -1
  109. package/dist/services/storage.service.js.map +0 -1
  110. package/dist/services/tool-context-builder.d.ts.map +0 -1
  111. package/dist/services/tool-context-builder.js.map +0 -1
  112. package/dist/services/tool-protection.service.d.ts.map +0 -1
  113. package/dist/services/tool-protection.service.js.map +0 -1
  114. package/dist/types/oauth-required-error.d.ts.map +0 -1
  115. package/dist/types/oauth-required-error.js.map +0 -1
  116. package/dist/types/tool-protection.d.ts.map +0 -1
  117. package/dist/types/tool-protection.js.map +0 -1
  118. package/dist/utils/base58.d.ts.map +0 -1
  119. package/dist/utils/base58.js.map +0 -1
  120. package/dist/utils/base64.d.ts.map +0 -1
  121. package/dist/utils/base64.js.map +0 -1
  122. package/dist/utils/cors.d.ts.map +0 -1
  123. package/dist/utils/cors.js.map +0 -1
  124. package/dist/utils/did-helpers.d.ts.map +0 -1
  125. package/dist/utils/did-helpers.js.map +0 -1
  126. package/dist/utils/index.d.ts.map +0 -1
  127. package/dist/utils/index.js.map +0 -1
  128. package/dist/utils/storage-keys.d.ts.map +0 -1
  129. package/dist/utils/storage-keys.js.map +0 -1
  130. package/docs/API_REFERENCE.md +0 -1362
  131. package/docs/COMPLIANCE_MATRIX.md +0 -691
  132. package/docs/STATUSLIST2021_GUIDE.md +0 -696
  133. package/docs/W3C_VC_DELEGATION_GUIDE.md +0 -710
  134. package/src/__tests__/cache/tool-protection-cache.test.ts +0 -640
  135. package/src/__tests__/config/provider-runtime-config.test.ts +0 -309
  136. package/src/__tests__/delegation-e2e.test.ts +0 -690
  137. package/src/__tests__/identity/user-did-manager.test.ts +0 -232
  138. package/src/__tests__/index.test.ts +0 -56
  139. package/src/__tests__/integration/full-flow.test.ts +0 -789
  140. package/src/__tests__/integration.test.ts +0 -281
  141. package/src/__tests__/providers/base.test.ts +0 -173
  142. package/src/__tests__/providers/memory.test.ts +0 -319
  143. package/src/__tests__/regression/phase2-regression.test.ts +0 -429
  144. package/src/__tests__/runtime/audit-logger.test.ts +0 -154
  145. package/src/__tests__/runtime/base-extensions.test.ts +0 -595
  146. package/src/__tests__/runtime/base.test.ts +0 -869
  147. package/src/__tests__/runtime/delegation-flow.test.ts +0 -164
  148. package/src/__tests__/runtime/proof-client-did.test.ts +0 -376
  149. package/src/__tests__/runtime/route-interception.test.ts +0 -686
  150. package/src/__tests__/runtime/tool-protection-enforcement.test.ts +0 -908
  151. package/src/__tests__/services/agentshield-integration.test.ts +0 -791
  152. package/src/__tests__/services/cache-busting.test.ts +0 -125
  153. package/src/__tests__/services/oauth-service-pkce.test.ts +0 -556
  154. package/src/__tests__/services/provider-resolver-edge-cases.test.ts +0 -591
  155. package/src/__tests__/services/tool-protection-merged-config.test.ts +0 -485
  156. package/src/__tests__/services/tool-protection-oauth-provider.test.ts +0 -480
  157. package/src/__tests__/services/tool-protection.service.test.ts +0 -1373
  158. package/src/__tests__/utils/mock-providers.ts +0 -340
  159. package/src/cache/oauth-config-cache.d.ts +0 -69
  160. package/src/cache/oauth-config-cache.d.ts.map +0 -1
  161. package/src/cache/oauth-config-cache.js.map +0 -1
  162. package/src/cache/oauth-config-cache.ts +0 -123
  163. package/src/cache/tool-protection-cache.ts +0 -171
  164. package/src/compliance/EXAMPLE.md +0 -412
  165. package/src/compliance/__tests__/schema-verifier.test.ts +0 -797
  166. package/src/compliance/index.ts +0 -8
  167. package/src/compliance/schema-registry.ts +0 -460
  168. package/src/compliance/schema-verifier.ts +0 -708
  169. package/src/config/__tests__/merged-config.spec.ts +0 -445
  170. package/src/config/__tests__/remote-config.spec.ts +0 -268
  171. package/src/config/remote-config.ts +0 -264
  172. package/src/config.ts +0 -312
  173. package/src/delegation/__tests__/audience-validator.test.ts +0 -112
  174. package/src/delegation/__tests__/bitstring.test.ts +0 -346
  175. package/src/delegation/__tests__/cascading-revocation.test.ts +0 -628
  176. package/src/delegation/__tests__/delegation-graph.test.ts +0 -584
  177. package/src/delegation/__tests__/did-key-resolver.test.ts +0 -265
  178. package/src/delegation/__tests__/utils.test.ts +0 -152
  179. package/src/delegation/__tests__/vc-issuer.test.ts +0 -442
  180. package/src/delegation/__tests__/vc-verifier.test.ts +0 -922
  181. package/src/delegation/audience-validator.ts +0 -52
  182. package/src/delegation/bitstring.ts +0 -278
  183. package/src/delegation/cascading-revocation.ts +0 -370
  184. package/src/delegation/delegation-graph.ts +0 -299
  185. package/src/delegation/did-key-resolver.ts +0 -179
  186. package/src/delegation/index.ts +0 -14
  187. package/src/delegation/statuslist-manager.ts +0 -353
  188. package/src/delegation/storage/__tests__/memory-graph-storage.test.ts +0 -366
  189. package/src/delegation/storage/__tests__/memory-statuslist-storage.test.ts +0 -228
  190. package/src/delegation/storage/index.ts +0 -9
  191. package/src/delegation/storage/memory-graph-storage.ts +0 -178
  192. package/src/delegation/storage/memory-statuslist-storage.ts +0 -77
  193. package/src/delegation/utils.ts +0 -221
  194. package/src/delegation/vc-issuer.ts +0 -232
  195. package/src/delegation/vc-verifier.ts +0 -568
  196. package/src/identity/idp-token-resolver.ts +0 -181
  197. package/src/identity/idp-token-storage.interface.ts +0 -94
  198. package/src/identity/user-did-manager.ts +0 -526
  199. package/src/index.ts +0 -310
  200. package/src/providers/base.d.ts +0 -91
  201. package/src/providers/base.d.ts.map +0 -1
  202. package/src/providers/base.js.map +0 -1
  203. package/src/providers/base.ts +0 -96
  204. package/src/providers/memory.ts +0 -142
  205. package/src/runtime/audit-logger.ts +0 -39
  206. package/src/runtime/base.ts +0 -1392
  207. package/src/services/__tests__/access-control.integration.test.ts +0 -443
  208. package/src/services/__tests__/access-control.proof-response-validation.test.ts +0 -578
  209. package/src/services/__tests__/access-control.service.test.ts +0 -970
  210. package/src/services/__tests__/batch-delegation.service.test.ts +0 -351
  211. package/src/services/__tests__/crypto.service.test.ts +0 -531
  212. package/src/services/__tests__/oauth-provider-registry.test.ts +0 -142
  213. package/src/services/__tests__/proof-verifier.integration.test.ts +0 -485
  214. package/src/services/__tests__/proof-verifier.test.ts +0 -489
  215. package/src/services/__tests__/provider-resolution.integration.test.ts +0 -202
  216. package/src/services/__tests__/provider-resolver.test.ts +0 -213
  217. package/src/services/__tests__/storage.service.test.ts +0 -358
  218. package/src/services/access-control.service.ts +0 -990
  219. package/src/services/authorization/authorization-registry.ts +0 -66
  220. package/src/services/authorization/types.ts +0 -71
  221. package/src/services/batch-delegation.service.ts +0 -137
  222. package/src/services/crypto.service.ts +0 -302
  223. package/src/services/errors.ts +0 -76
  224. package/src/services/index.ts +0 -18
  225. package/src/services/oauth-config.service.d.ts +0 -53
  226. package/src/services/oauth-config.service.d.ts.map +0 -1
  227. package/src/services/oauth-config.service.js.map +0 -1
  228. package/src/services/oauth-config.service.ts +0 -192
  229. package/src/services/oauth-provider-registry.d.ts +0 -57
  230. package/src/services/oauth-provider-registry.d.ts.map +0 -1
  231. package/src/services/oauth-provider-registry.js.map +0 -1
  232. package/src/services/oauth-provider-registry.ts +0 -141
  233. package/src/services/oauth-service.ts +0 -544
  234. package/src/services/oauth-token-retrieval.service.ts +0 -245
  235. package/src/services/proof-verifier.ts +0 -478
  236. package/src/services/provider-resolver.d.ts +0 -48
  237. package/src/services/provider-resolver.d.ts.map +0 -1
  238. package/src/services/provider-resolver.js.map +0 -1
  239. package/src/services/provider-resolver.ts +0 -146
  240. package/src/services/provider-validator.ts +0 -170
  241. package/src/services/session-registration.service.ts +0 -251
  242. package/src/services/storage.service.ts +0 -566
  243. package/src/services/tool-context-builder.ts +0 -237
  244. package/src/services/tool-protection.service.ts +0 -1070
  245. package/src/types/oauth-required-error.ts +0 -63
  246. package/src/types/tool-protection.ts +0 -155
  247. package/src/utils/__tests__/did-helpers.test.ts +0 -156
  248. package/src/utils/base58.ts +0 -109
  249. package/src/utils/base64.ts +0 -148
  250. package/src/utils/cors.ts +0 -83
  251. package/src/utils/did-helpers.ts +0 -210
  252. package/src/utils/index.ts +0 -8
  253. package/src/utils/storage-keys.ts +0 -278
  254. package/tsconfig.json +0 -21
  255. package/vitest.config.ts +0 -56
@@ -1,489 +0,0 @@
1
- /**
2
- * Tests for ProofVerifier
3
- *
4
- * Comprehensive security test coverage for proof verification service.
5
- * Tests nonce replay protection, timestamp skew validation, canonical payload reconstruction,
6
- * and various security attack scenarios.
7
- *
8
- * Test Coverage Requirements: 100% - All security-critical code paths
9
- */
10
-
11
- import { describe, it, expect, beforeEach, vi } from 'vitest';
12
- import { ProofVerifier } from '../proof-verifier.js';
13
- import { CryptoService, type Ed25519JWK } from '../crypto.service.js';
14
- import type {
15
- CryptoProvider,
16
- ClockProvider,
17
- NonceCacheProvider,
18
- FetchProvider,
19
- } from '../../providers/base.js';
20
- import type { DetachedProof } from '@kya-os/contracts/proof';
21
- import {
22
- ProofVerificationError,
23
- PROOF_VERIFICATION_ERROR_CODES,
24
- } from '../errors.js';
25
-
26
- describe('ProofVerifier Security', () => {
27
- let proofVerifier: ProofVerifier;
28
- let mockCryptoProvider: CryptoProvider;
29
- let mockClockProvider: ClockProvider;
30
- let mockNonceCache: NonceCacheProvider;
31
- let mockFetchProvider: FetchProvider;
32
- let cryptoService: CryptoService;
33
-
34
- const validJwk: Ed25519JWK = {
35
- kty: 'OKP',
36
- crv: 'Ed25519',
37
- x: 'VCpo2LMLhn6iWku8MKvSLg2ZAoC-nlOyPVQaO3FxVeQ',
38
- kid: 'did:key:z123#key-1',
39
- };
40
-
41
- const createValidProof = (): DetachedProof => {
42
- const header = { alg: 'EdDSA', typ: 'JWT' };
43
- // Create a proper JSON payload that matches the meta structure
44
- const payload = {
45
- aud: 'test-audience',
46
- sub: 'did:key:z123',
47
- iss: 'did:key:z123',
48
- nonce: 'nonce123',
49
- ts: Math.floor(Date.now() / 1000),
50
- sessionId: 'session123',
51
- requestHash: 'sha256:' + 'a'.repeat(64),
52
- responseHash: 'sha256:' + 'b'.repeat(64),
53
- };
54
- // Use btoa for base64 encoding (available in test environment via polyfill)
55
- const headerB64 = btoa(JSON.stringify(header))
56
- .replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
57
- const payloadB64 = btoa(JSON.stringify(payload))
58
- .replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
59
- const signatureB64 = btoa('signature')
60
- .replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
61
- const jws = `${headerB64}.${payloadB64}.${signatureB64}`;
62
-
63
- return {
64
- jws,
65
- meta: {
66
- did: 'did:key:z123',
67
- kid: 'did:key:z123#key-1',
68
- ts: Math.floor(Date.now() / 1000),
69
- nonce: 'nonce123',
70
- audience: 'test-audience',
71
- sessionId: 'session123',
72
- requestHash: 'sha256:' + 'a'.repeat(64),
73
- responseHash: 'sha256:' + 'b'.repeat(64),
74
- },
75
- };
76
- };
77
-
78
- beforeEach(() => {
79
- mockCryptoProvider = {
80
- sign: vi.fn(),
81
- verify: vi.fn().mockResolvedValue(true),
82
- generateKeyPair: vi.fn(),
83
- hash: vi.fn(),
84
- randomBytes: vi.fn(),
85
- };
86
-
87
- cryptoService = new CryptoService(mockCryptoProvider);
88
-
89
- mockClockProvider = {
90
- now: vi.fn().mockReturnValue(Date.now()), // Return milliseconds
91
- isWithinSkew: vi.fn().mockReturnValue(true),
92
- hasExpired: vi.fn(),
93
- calculateExpiry: vi.fn((ttlSeconds: number) => Date.now() + (ttlSeconds * 1000)), // Return milliseconds
94
- format: vi.fn(),
95
- };
96
-
97
- mockNonceCache = {
98
- has: vi.fn().mockResolvedValue(false),
99
- add: vi.fn().mockResolvedValue(undefined),
100
- cleanup: vi.fn().mockResolvedValue(undefined),
101
- destroy: vi.fn().mockResolvedValue(undefined),
102
- };
103
-
104
- mockFetchProvider = {
105
- resolveDID: vi.fn().mockResolvedValue({
106
- verificationMethod: [{
107
- id: 'did:key:z123#key-1',
108
- publicKeyJwk: validJwk,
109
- }],
110
- }),
111
- fetchStatusList: vi.fn(),
112
- fetchDelegationChain: vi.fn(),
113
- fetch: vi.fn(),
114
- };
115
-
116
- proofVerifier = new ProofVerifier({
117
- cryptoProvider: mockCryptoProvider,
118
- clockProvider: mockClockProvider,
119
- nonceCacheProvider: mockNonceCache,
120
- fetchProvider: mockFetchProvider,
121
- timestampSkewSeconds: 120,
122
- nonceTtlSeconds: 300,
123
- });
124
- });
125
-
126
- describe('Nonce Replay Protection', () => {
127
- it('should prevent nonce replay attacks', async () => {
128
- const proof = createValidProof();
129
-
130
- // First verification should succeed
131
- const result1 = await proofVerifier.verifyProof(proof, validJwk);
132
- expect(result1.valid).toBe(true);
133
- expect(mockNonceCache.has).toHaveBeenCalledWith('nonce123', 'did:key:z123');
134
- expect(mockNonceCache.add).toHaveBeenCalled();
135
-
136
- // Reset mock to simulate second attempt
137
- mockNonceCache.has = vi.fn().mockResolvedValue(true);
138
-
139
- // Second verification with same nonce should fail
140
- const result2 = await proofVerifier.verifyProof(proof, validJwk);
141
- expect(result2.valid).toBe(false);
142
- expect(result2.reason).toContain('replay');
143
- });
144
-
145
- it('should add nonce to cache after successful verification', async () => {
146
- const proof = createValidProof();
147
-
148
- await proofVerifier.verifyProof(proof, validJwk);
149
-
150
- expect(mockNonceCache.add).toHaveBeenCalledWith(
151
- 'nonce123',
152
- expect.any(Number),
153
- 'did:key:z123'
154
- );
155
- });
156
- });
157
-
158
- describe('Timestamp Skew Validation', () => {
159
- it('should enforce timestamp skew limits', async () => {
160
- const proof = createValidProof();
161
- const currentTime = Date.now(); // milliseconds
162
-
163
- // Set clock to 5 minutes in the future
164
- mockClockProvider.now = vi.fn().mockReturnValue(currentTime);
165
- mockClockProvider.isWithinSkew = vi.fn().mockReturnValue(false);
166
-
167
- const result = await proofVerifier.verifyProof(proof, validJwk);
168
-
169
- expect(result.valid).toBe(false);
170
- expect(result.reason).toContain('skew');
171
- // isWithinSkew is called with timestamp in milliseconds (converted from seconds)
172
- expect(mockClockProvider.isWithinSkew).toHaveBeenCalledWith(
173
- proof.meta.ts * 1000, // Convert seconds to milliseconds
174
- 120
175
- );
176
- });
177
-
178
- it('should accept timestamps within skew window', async () => {
179
- const proof = createValidProof();
180
- mockClockProvider.isWithinSkew = vi.fn().mockReturnValue(true);
181
-
182
- const result = await proofVerifier.verifyProof(proof, validJwk);
183
-
184
- expect(result.valid).toBe(true);
185
- });
186
-
187
- it('should use custom timestamp skew seconds', async () => {
188
- const customProofVerifier = new ProofVerifier({
189
- cryptoProvider: mockCryptoProvider,
190
- clockProvider: mockClockProvider,
191
- nonceCacheProvider: mockNonceCache,
192
- fetchProvider: mockFetchProvider,
193
- timestampSkewSeconds: 300, // 5 minutes
194
- nonceTtlSeconds: 300,
195
- });
196
-
197
- const proof = createValidProof();
198
- mockClockProvider.isWithinSkew = vi.fn().mockReturnValue(false);
199
-
200
- await customProofVerifier.verifyProof(proof, validJwk);
201
-
202
- // isWithinSkew is called with timestamp in milliseconds (converted from seconds)
203
- expect(mockClockProvider.isWithinSkew).toHaveBeenCalledWith(
204
- proof.meta.ts * 1000, // Convert seconds to milliseconds
205
- 300
206
- );
207
- });
208
- });
209
-
210
- describe('Canonical Payload Reconstruction', () => {
211
- it('should reconstruct canonical payload from meta', async () => {
212
- const proof = createValidProof();
213
-
214
- await proofVerifier.verifyProof(proof, validJwk);
215
-
216
- // Verify that verifyJWS was called with detached payload
217
- expect(mockCryptoProvider.verify).toHaveBeenCalled();
218
- });
219
-
220
- it('should validate canonical payload ordering determinism', () => {
221
- const meta1 = {
222
- z: 1,
223
- a: 2,
224
- m: 3,
225
- did: 'did:test',
226
- kid: 'kid',
227
- ts: 123,
228
- nonce: 'nonce',
229
- audience: 'aud',
230
- sessionId: 'session',
231
- requestHash: 'sha256:' + 'a'.repeat(64),
232
- responseHash: 'sha256:' + 'b'.repeat(64),
233
- };
234
- const meta2 = {
235
- a: 2,
236
- m: 3,
237
- z: 1,
238
- did: 'did:test',
239
- kid: 'kid',
240
- ts: 123,
241
- nonce: 'nonce',
242
- audience: 'aud',
243
- sessionId: 'session',
244
- requestHash: 'sha256:' + 'a'.repeat(64),
245
- responseHash: 'sha256:' + 'b'.repeat(64),
246
- };
247
-
248
- const canonical1 = proofVerifier.buildCanonicalPayload(meta1);
249
- const canonical2 = proofVerifier.buildCanonicalPayload(meta2);
250
-
251
- // Should be identical despite different key order
252
- expect(canonical1).toBe(canonical2);
253
- });
254
-
255
- it('should handle detached JWS reconstruction', async () => {
256
- const header = { alg: 'EdDSA' };
257
- const headerB64 = btoa(JSON.stringify(header))
258
- .replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
259
- const signatureB64 = btoa('signature')
260
- .replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
261
- const detachedJws = `${headerB64}..${signatureB64}`;
262
-
263
- const proof: DetachedProof = {
264
- jws: detachedJws,
265
- meta: createValidProof().meta,
266
- };
267
-
268
- const result = await proofVerifier.verifyProof(proof, validJwk);
269
-
270
- // Should call verifyJWS with detached payload
271
- expect(mockCryptoProvider.verify).toHaveBeenCalled();
272
- expect(result.valid).toBe(true);
273
- });
274
- });
275
-
276
- describe('Proof Structure Validation', () => {
277
- it('should reject invalid proof structure', async () => {
278
- const invalidProof = {
279
- jws: 'invalid',
280
- meta: {
281
- // Missing required fields
282
- did: 'did:test',
283
- },
284
- } as any;
285
-
286
- const result = await proofVerifier.verifyProof(invalidProof, validJwk);
287
-
288
- expect(result.valid).toBe(false);
289
- expect(result.reason).toContain('Invalid proof structure');
290
- });
291
-
292
- it('should reject proof with missing required meta fields', async () => {
293
- const invalidProof: DetachedProof = {
294
- jws: 'header.payload.signature',
295
- meta: {
296
- did: 'did:test',
297
- kid: 'kid',
298
- ts: 123,
299
- nonce: 'nonce',
300
- audience: 'aud',
301
- sessionId: 'session',
302
- // Missing requestHash and responseHash
303
- requestHash: '' as any,
304
- responseHash: '' as any,
305
- },
306
- };
307
-
308
- const result = await proofVerifier.verifyProof(invalidProof, validJwk);
309
-
310
- expect(result.valid).toBe(false);
311
- });
312
- });
313
-
314
- describe('Signature Verification', () => {
315
- it('should reject proof with invalid signature', async () => {
316
- const proof = createValidProof();
317
- mockCryptoProvider.verify = vi.fn().mockResolvedValue(false);
318
-
319
- const result = await proofVerifier.verifyProof(proof, validJwk);
320
-
321
- expect(result.valid).toBe(false);
322
- expect(result.reason).toContain('Invalid JWS signature');
323
- });
324
-
325
- it('should handle signature verification errors gracefully', async () => {
326
- const proof = createValidProof();
327
- mockCryptoProvider.verify = vi.fn().mockRejectedValue(
328
- new Error('Crypto error')
329
- );
330
-
331
- const result = await proofVerifier.verifyProof(proof, validJwk);
332
-
333
- expect(result.valid).toBe(false);
334
- expect(result.reason).toBeDefined();
335
- // Should not throw, should return error result
336
- });
337
- });
338
-
339
- describe('verifyProofDetached', () => {
340
- it('should verify proof with string canonical payload', async () => {
341
- const proof = createValidProof();
342
- const canonicalPayload = proofVerifier.buildCanonicalPayload(proof.meta);
343
-
344
- const result = await proofVerifier.verifyProofDetached(
345
- proof,
346
- canonicalPayload,
347
- validJwk
348
- );
349
-
350
- expect(result.valid).toBe(true);
351
- });
352
-
353
- it('should verify proof with Uint8Array canonical payload', async () => {
354
- const proof = createValidProof();
355
- const canonicalPayload = proofVerifier.buildCanonicalPayload(proof.meta);
356
- const canonicalPayloadBytes = new TextEncoder().encode(canonicalPayload);
357
-
358
- const result = await proofVerifier.verifyProofDetached(
359
- proof,
360
- canonicalPayloadBytes,
361
- validJwk
362
- );
363
-
364
- expect(result.valid).toBe(true);
365
- });
366
-
367
- it('should prevent nonce replay in verifyProofDetached', async () => {
368
- const proof = createValidProof();
369
- const canonicalPayload = proofVerifier.buildCanonicalPayload(proof.meta);
370
-
371
- // First verification
372
- const result1 = await proofVerifier.verifyProofDetached(
373
- proof,
374
- canonicalPayload,
375
- validJwk
376
- );
377
- expect(result1.valid).toBe(true);
378
-
379
- // Second verification should fail
380
- mockNonceCache.has = vi.fn().mockResolvedValue(true);
381
- const result2 = await proofVerifier.verifyProofDetached(
382
- proof,
383
- canonicalPayload,
384
- validJwk
385
- );
386
- expect(result2.valid).toBe(false);
387
- expect(result2.reason).toContain('replay');
388
- });
389
- });
390
-
391
- describe('Error Handling', () => {
392
- it('should never throw on verification errors', async () => {
393
- const proof = createValidProof();
394
-
395
- // Simulate various error conditions
396
- mockNonceCache.has = vi.fn().mockRejectedValue(new Error('Cache error'));
397
-
398
- const result = await proofVerifier.verifyProof(proof, validJwk);
399
-
400
- // Should return error result, not throw
401
- expect(result.valid).toBe(false);
402
- expect(result.reason).toBeDefined();
403
- });
404
-
405
- it('should handle clock provider errors gracefully', async () => {
406
- const proof = createValidProof();
407
- mockClockProvider.isWithinSkew = vi.fn().mockImplementation(() => {
408
- throw new Error('Clock error');
409
- });
410
-
411
- const result = await proofVerifier.verifyProof(proof, validJwk);
412
-
413
- expect(result.valid).toBe(false);
414
- expect(result.reason).toBeDefined();
415
- });
416
- });
417
-
418
- describe('fetchPublicKeyFromDID', () => {
419
- it('should fetch public key from DID document', async () => {
420
- const jwk = await proofVerifier.fetchPublicKeyFromDID('did:key:z123', 'key-1');
421
-
422
- expect(jwk).toEqual(validJwk);
423
- expect(mockFetchProvider.resolveDID).toHaveBeenCalledWith('did:key:z123');
424
- });
425
-
426
- it('should throw ProofVerificationError if DID document not found', async () => {
427
- mockFetchProvider.resolveDID = vi.fn().mockResolvedValue(null);
428
-
429
- await expect(
430
- proofVerifier.fetchPublicKeyFromDID('did:key:z123')
431
- ).rejects.toThrow(ProofVerificationError);
432
-
433
- try {
434
- await proofVerifier.fetchPublicKeyFromDID('did:key:z123');
435
- } catch (error) {
436
- expect(error).toBeInstanceOf(ProofVerificationError);
437
- expect((error as ProofVerificationError).code).toBe(
438
- PROOF_VERIFICATION_ERROR_CODES.DID_DOCUMENT_NOT_FOUND
439
- );
440
- }
441
- });
442
-
443
- it('should throw ProofVerificationError if verification method not found', async () => {
444
- mockFetchProvider.resolveDID = vi.fn().mockResolvedValue({
445
- verificationMethod: [],
446
- });
447
-
448
- await expect(
449
- proofVerifier.fetchPublicKeyFromDID('did:key:z123', 'key-1')
450
- ).rejects.toThrow(ProofVerificationError);
451
-
452
- try {
453
- await proofVerifier.fetchPublicKeyFromDID('did:key:z123', 'key-1');
454
- } catch (error) {
455
- expect(error).toBeInstanceOf(ProofVerificationError);
456
- expect((error as ProofVerificationError).code).toBe(
457
- PROOF_VERIFICATION_ERROR_CODES.VERIFICATION_METHOD_NOT_FOUND
458
- );
459
- }
460
- });
461
-
462
- it('should throw ProofVerificationError if JWK is not Ed25519', async () => {
463
- mockFetchProvider.resolveDID = vi.fn().mockResolvedValue({
464
- verificationMethod: [{
465
- id: 'did:key:z123#key-1',
466
- publicKeyJwk: {
467
- kty: 'RSA',
468
- crv: 'RS256',
469
- n: 'invalid',
470
- },
471
- }],
472
- });
473
-
474
- await expect(
475
- proofVerifier.fetchPublicKeyFromDID('did:key:z123')
476
- ).rejects.toThrow(ProofVerificationError);
477
-
478
- try {
479
- await proofVerifier.fetchPublicKeyFromDID('did:key:z123');
480
- } catch (error) {
481
- expect(error).toBeInstanceOf(ProofVerificationError);
482
- expect((error as ProofVerificationError).code).toBe(
483
- PROOF_VERIFICATION_ERROR_CODES.INVALID_JWK_FORMAT
484
- );
485
- }
486
- });
487
- });
488
- });
489
-
@@ -1,202 +0,0 @@
1
- /**
2
- * Provider Resolution Integration Tests
3
- *
4
- * Tests end-to-end provider resolution flow and backward compatibility.
5
- *
6
- * @package @kya-os/mcp-i-core
7
- */
8
-
9
- import { describe, it, expect, beforeEach, vi } from "vitest";
10
- import { OAuthProviderRegistry } from "../oauth-provider-registry.js";
11
- import { ProviderResolver } from "../provider-resolver.js";
12
- import { OAuthConfigService } from "../oauth-config.service.js";
13
- import { ToolProtectionService } from "../tool-protection.service.js";
14
- import type { ToolProtection } from "@kya-os/contracts/tool-protection";
15
- import type { OAuthConfig } from "@kya-os/contracts/config";
16
-
17
- describe("Provider Resolution Integration", () => {
18
- let mockConfigService: OAuthConfigService;
19
- let mockToolProtectionService: ToolProtectionService;
20
- let providerRegistry: OAuthProviderRegistry;
21
- let providerResolver: ProviderResolver;
22
-
23
- const mockOAuthConfig: OAuthConfig = {
24
- providers: {
25
- github: {
26
- clientId: "github_client_id",
27
- authorizationUrl: "https://github.com/login/oauth/authorize",
28
- tokenUrl: "https://github.com/login/oauth/access_token",
29
- supportsPKCE: true,
30
- requiresClientSecret: false,
31
- },
32
- google: {
33
- clientId: "google_client_id",
34
- authorizationUrl: "https://accounts.google.com/o/oauth2/v2/auth",
35
- tokenUrl: "https://oauth2.googleapis.com/token",
36
- supportsPKCE: true,
37
- requiresClientSecret: false,
38
- },
39
- },
40
- // Explicitly configured provider (Priority 3 fallback)
41
- configuredProvider: "github",
42
- };
43
-
44
- beforeEach(() => {
45
- mockConfigService = {
46
- getOAuthConfig: vi.fn().mockResolvedValue(mockOAuthConfig),
47
- } as any;
48
-
49
- mockToolProtectionService = {
50
- checkToolProtection: vi.fn(),
51
- getProjectId: vi.fn().mockReturnValue("test-project"),
52
- } as any;
53
-
54
- providerRegistry = new OAuthProviderRegistry(mockConfigService);
55
- providerResolver = new ProviderResolver(providerRegistry, mockConfigService);
56
- });
57
-
58
- describe("End-to-end provider resolution", () => {
59
- it("should resolve provider for tool with oauthProvider field", async () => {
60
- await providerRegistry.loadFromAgentShield("test-project");
61
-
62
- const toolProtection: ToolProtection = {
63
- requiresDelegation: true,
64
- requiredScopes: ["repo:read"],
65
- oauthProvider: "github",
66
- };
67
-
68
- const provider = await providerResolver.resolveProvider(
69
- toolProtection,
70
- "test-project"
71
- );
72
-
73
- expect(provider).toBe("github");
74
- });
75
-
76
- it("should resolve provider via scope inference when oauthProvider not specified", async () => {
77
- await providerRegistry.loadFromAgentShield("test-project");
78
-
79
- const toolProtection: ToolProtection = {
80
- requiresDelegation: true,
81
- requiredScopes: ["github:repo:read"],
82
- // No oauthProvider field (Phase 1 compatibility)
83
- };
84
-
85
- const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => {});
86
-
87
- const provider = await providerResolver.resolveProvider(
88
- toolProtection,
89
- "test-project"
90
- );
91
-
92
- expect(provider).toBe("github");
93
- expect(consoleSpy).toHaveBeenCalledWith(
94
- expect.stringContaining("Inferred provider")
95
- );
96
-
97
- consoleSpy.mockRestore();
98
- });
99
-
100
- it("should fall back to configuredProvider for Phase 1 compatibility", async () => {
101
- await providerRegistry.loadFromAgentShield("test-project");
102
-
103
- const toolProtection: ToolProtection = {
104
- requiresDelegation: true,
105
- requiredScopes: ["custom:scope"], // No recognizable prefix
106
- // No oauthProvider field
107
- };
108
-
109
- const consoleSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
110
-
111
- const provider = await providerResolver.resolveProvider(
112
- toolProtection,
113
- "test-project"
114
- );
115
-
116
- // Should use configuredProvider (github)
117
- expect(provider).toBe("github");
118
- expect(consoleSpy).toHaveBeenCalledWith(
119
- expect.stringContaining("project-configured provider")
120
- );
121
-
122
- consoleSpy.mockRestore();
123
- });
124
- });
125
-
126
- describe("Backward compatibility", () => {
127
- it("should work with Phase 1 tools (no oauthProvider field)", async () => {
128
- await providerRegistry.loadFromAgentShield("test-project");
129
-
130
- const toolProtection: ToolProtection = {
131
- requiresDelegation: true,
132
- requiredScopes: ["repo:read"],
133
- // No oauthProvider - Phase 1 style
134
- };
135
-
136
- // Should not throw - uses fallback resolution
137
- const provider = await providerResolver.resolveProvider(
138
- toolProtection,
139
- "test-project"
140
- );
141
-
142
- expect(provider).toBeDefined();
143
- expect(typeof provider).toBe("string");
144
- });
145
-
146
- it("should handle tools with empty requiredScopes", async () => {
147
- await providerRegistry.loadFromAgentShield("test-project");
148
-
149
- const toolProtection: ToolProtection = {
150
- requiresDelegation: true,
151
- requiredScopes: [],
152
- // No oauthProvider
153
- };
154
-
155
- const consoleSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
156
-
157
- const provider = await providerResolver.resolveProvider(
158
- toolProtection,
159
- "test-project"
160
- );
161
-
162
- // Should fall back to configuredProvider
163
- expect(provider).toBe("github");
164
- expect(consoleSpy).toHaveBeenCalledWith(
165
- expect.stringContaining("project-configured provider")
166
- );
167
-
168
- consoleSpy.mockRestore();
169
- });
170
- });
171
-
172
- describe("Multi-provider scenarios", () => {
173
- it("should resolve different providers for different tools", async () => {
174
- await providerRegistry.loadFromAgentShield("test-project");
175
-
176
- const githubTool: ToolProtection = {
177
- requiresDelegation: true,
178
- requiredScopes: ["repo:read"],
179
- oauthProvider: "github",
180
- };
181
-
182
- const googleTool: ToolProtection = {
183
- requiresDelegation: true,
184
- requiredScopes: ["calendar:read"],
185
- oauthProvider: "google",
186
- };
187
-
188
- const githubProvider = await providerResolver.resolveProvider(
189
- githubTool,
190
- "test-project"
191
- );
192
- const googleProvider = await providerResolver.resolveProvider(
193
- googleTool,
194
- "test-project"
195
- );
196
-
197
- expect(githubProvider).toBe("github");
198
- expect(googleProvider).toBe("google");
199
- });
200
- });
201
- });
202
-