@kya-os/mcp-i-core 1.2.3-canary.7 → 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.
Files changed (231) hide show
  1. package/.claude/settings.local.json +9 -0
  2. package/.turbo/turbo-build.log +4 -0
  3. package/.turbo/turbo-test$colon$coverage.log +4514 -0
  4. package/.turbo/turbo-test.log +2973 -0
  5. package/COMPLIANCE_IMPROVEMENT_REPORT.md +483 -0
  6. package/Composer 3.md +615 -0
  7. package/GPT-5.md +1169 -0
  8. package/OPUS-plan.md +352 -0
  9. package/PHASE_3_AND_4.1_SUMMARY.md +585 -0
  10. package/PHASE_3_SUMMARY.md +317 -0
  11. package/PHASE_4.1.3_SUMMARY.md +428 -0
  12. package/PHASE_4.1_COMPLETE.md +525 -0
  13. package/PHASE_4_USER_DID_IDENTITY_LINKING_PLAN.md +1240 -0
  14. package/SCHEMA_COMPLIANCE_REPORT.md +275 -0
  15. package/TEST_PLAN.md +571 -0
  16. package/coverage/coverage-final.json +57 -0
  17. package/dist/__tests__/utils/mock-providers.d.ts +1 -2
  18. package/dist/__tests__/utils/mock-providers.d.ts.map +1 -1
  19. package/dist/__tests__/utils/mock-providers.js.map +1 -1
  20. package/dist/cache/oauth-config-cache.d.ts +69 -0
  21. package/dist/cache/oauth-config-cache.d.ts.map +1 -0
  22. package/dist/cache/oauth-config-cache.js +76 -0
  23. package/dist/cache/oauth-config-cache.js.map +1 -0
  24. package/dist/identity/idp-token-resolver.d.ts +53 -0
  25. package/dist/identity/idp-token-resolver.d.ts.map +1 -0
  26. package/dist/identity/idp-token-resolver.js +108 -0
  27. package/dist/identity/idp-token-resolver.js.map +1 -0
  28. package/dist/identity/idp-token-storage.interface.d.ts +42 -0
  29. package/dist/identity/idp-token-storage.interface.d.ts.map +1 -0
  30. package/dist/identity/idp-token-storage.interface.js +12 -0
  31. package/dist/identity/idp-token-storage.interface.js.map +1 -0
  32. package/dist/identity/user-did-manager.d.ts +39 -1
  33. package/dist/identity/user-did-manager.d.ts.map +1 -1
  34. package/dist/identity/user-did-manager.js +69 -3
  35. package/dist/identity/user-did-manager.js.map +1 -1
  36. package/dist/index.d.ts +22 -0
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +39 -1
  39. package/dist/index.js.map +1 -1
  40. package/dist/runtime/audit-logger.d.ts +37 -0
  41. package/dist/runtime/audit-logger.d.ts.map +1 -0
  42. package/dist/runtime/audit-logger.js +9 -0
  43. package/dist/runtime/audit-logger.js.map +1 -0
  44. package/dist/runtime/base.d.ts +58 -2
  45. package/dist/runtime/base.d.ts.map +1 -1
  46. package/dist/runtime/base.js +266 -11
  47. package/dist/runtime/base.js.map +1 -1
  48. package/dist/services/access-control.service.d.ts.map +1 -1
  49. package/dist/services/access-control.service.js +200 -35
  50. package/dist/services/access-control.service.js.map +1 -1
  51. package/dist/services/authorization/authorization-registry.d.ts +29 -0
  52. package/dist/services/authorization/authorization-registry.d.ts.map +1 -0
  53. package/dist/services/authorization/authorization-registry.js +57 -0
  54. package/dist/services/authorization/authorization-registry.js.map +1 -0
  55. package/dist/services/authorization/types.d.ts +53 -0
  56. package/dist/services/authorization/types.d.ts.map +1 -0
  57. package/dist/services/authorization/types.js +10 -0
  58. package/dist/services/authorization/types.js.map +1 -0
  59. package/dist/services/batch-delegation.service.d.ts +53 -0
  60. package/dist/services/batch-delegation.service.d.ts.map +1 -0
  61. package/dist/services/batch-delegation.service.js +95 -0
  62. package/dist/services/batch-delegation.service.js.map +1 -0
  63. package/dist/services/oauth-config.service.d.ts +53 -0
  64. package/dist/services/oauth-config.service.d.ts.map +1 -0
  65. package/dist/services/oauth-config.service.js +117 -0
  66. package/dist/services/oauth-config.service.js.map +1 -0
  67. package/dist/services/oauth-provider-registry.d.ts +77 -0
  68. package/dist/services/oauth-provider-registry.d.ts.map +1 -0
  69. package/dist/services/oauth-provider-registry.js +112 -0
  70. package/dist/services/oauth-provider-registry.js.map +1 -0
  71. package/dist/services/oauth-service.d.ts +77 -0
  72. package/dist/services/oauth-service.d.ts.map +1 -0
  73. package/dist/services/oauth-service.js +348 -0
  74. package/dist/services/oauth-service.js.map +1 -0
  75. package/dist/services/oauth-token-retrieval.service.d.ts +49 -0
  76. package/dist/services/oauth-token-retrieval.service.d.ts.map +1 -0
  77. package/dist/services/oauth-token-retrieval.service.js +150 -0
  78. package/dist/services/oauth-token-retrieval.service.js.map +1 -0
  79. package/dist/services/provider-resolver.d.ts +48 -0
  80. package/dist/services/provider-resolver.d.ts.map +1 -0
  81. package/dist/services/provider-resolver.js +120 -0
  82. package/dist/services/provider-resolver.js.map +1 -0
  83. package/dist/services/provider-validator.d.ts +55 -0
  84. package/dist/services/provider-validator.d.ts.map +1 -0
  85. package/dist/services/provider-validator.js +135 -0
  86. package/dist/services/provider-validator.js.map +1 -0
  87. package/dist/services/tool-context-builder.d.ts +57 -0
  88. package/dist/services/tool-context-builder.d.ts.map +1 -0
  89. package/dist/services/tool-context-builder.js +125 -0
  90. package/dist/services/tool-context-builder.js.map +1 -0
  91. package/dist/services/tool-protection.service.d.ts +87 -10
  92. package/dist/services/tool-protection.service.d.ts.map +1 -1
  93. package/dist/services/tool-protection.service.js +282 -112
  94. package/dist/services/tool-protection.service.js.map +1 -1
  95. package/dist/types/oauth-required-error.d.ts +40 -0
  96. package/dist/types/oauth-required-error.d.ts.map +1 -0
  97. package/dist/types/oauth-required-error.js +40 -0
  98. package/dist/types/oauth-required-error.js.map +1 -0
  99. package/dist/utils/did-helpers.d.ts +33 -0
  100. package/dist/utils/did-helpers.d.ts.map +1 -1
  101. package/dist/utils/did-helpers.js +40 -0
  102. package/dist/utils/did-helpers.js.map +1 -1
  103. package/dist/utils/index.d.ts +1 -0
  104. package/dist/utils/index.d.ts.map +1 -1
  105. package/dist/utils/index.js +1 -0
  106. package/dist/utils/index.js.map +1 -1
  107. package/docs/API_REFERENCE.md +1362 -0
  108. package/docs/COMPLIANCE_MATRIX.md +691 -0
  109. package/docs/STATUSLIST2021_GUIDE.md +696 -0
  110. package/docs/W3C_VC_DELEGATION_GUIDE.md +710 -0
  111. package/package.json +24 -50
  112. package/scripts/audit-compliance.ts +724 -0
  113. package/src/__tests__/cache/tool-protection-cache.test.ts +640 -0
  114. package/src/__tests__/config/provider-runtime-config.test.ts +309 -0
  115. package/src/__tests__/delegation-e2e.test.ts +690 -0
  116. package/src/__tests__/identity/user-did-manager.test.ts +213 -0
  117. package/src/__tests__/index.test.ts +56 -0
  118. package/src/__tests__/integration/full-flow.test.ts +776 -0
  119. package/src/__tests__/integration.test.ts +281 -0
  120. package/src/__tests__/providers/base.test.ts +173 -0
  121. package/src/__tests__/providers/memory.test.ts +319 -0
  122. package/src/__tests__/regression/phase2-regression.test.ts +427 -0
  123. package/src/__tests__/runtime/audit-logger.test.ts +154 -0
  124. package/src/__tests__/runtime/base-extensions.test.ts +593 -0
  125. package/src/__tests__/runtime/base.test.ts +869 -0
  126. package/src/__tests__/runtime/delegation-flow.test.ts +164 -0
  127. package/src/__tests__/runtime/proof-client-did.test.ts +375 -0
  128. package/src/__tests__/runtime/route-interception.test.ts +686 -0
  129. package/src/__tests__/runtime/tool-protection-enforcement.test.ts +908 -0
  130. package/src/__tests__/services/agentshield-integration.test.ts +784 -0
  131. package/src/__tests__/services/provider-resolver-edge-cases.test.ts +487 -0
  132. package/src/__tests__/services/tool-protection-oauth-provider.test.ts +480 -0
  133. package/src/__tests__/services/tool-protection.service.test.ts +1366 -0
  134. package/src/__tests__/utils/mock-providers.ts +340 -0
  135. package/src/cache/oauth-config-cache.d.ts +69 -0
  136. package/src/cache/oauth-config-cache.d.ts.map +1 -0
  137. package/src/cache/oauth-config-cache.js +71 -0
  138. package/src/cache/oauth-config-cache.js.map +1 -0
  139. package/src/cache/oauth-config-cache.ts +123 -0
  140. package/src/cache/tool-protection-cache.ts +171 -0
  141. package/src/compliance/EXAMPLE.md +412 -0
  142. package/src/compliance/__tests__/schema-verifier.test.ts +797 -0
  143. package/src/compliance/index.ts +8 -0
  144. package/src/compliance/schema-registry.ts +460 -0
  145. package/src/compliance/schema-verifier.ts +708 -0
  146. package/src/config/__tests__/remote-config.spec.ts +268 -0
  147. package/src/config/remote-config.ts +174 -0
  148. package/src/config.ts +309 -0
  149. package/src/delegation/__tests__/audience-validator.test.ts +112 -0
  150. package/src/delegation/__tests__/bitstring.test.ts +346 -0
  151. package/src/delegation/__tests__/cascading-revocation.test.ts +628 -0
  152. package/src/delegation/__tests__/delegation-graph.test.ts +584 -0
  153. package/src/delegation/__tests__/utils.test.ts +152 -0
  154. package/src/delegation/__tests__/vc-issuer.test.ts +442 -0
  155. package/src/delegation/__tests__/vc-verifier.test.ts +922 -0
  156. package/src/delegation/audience-validator.ts +52 -0
  157. package/src/delegation/bitstring.ts +278 -0
  158. package/src/delegation/cascading-revocation.ts +370 -0
  159. package/src/delegation/delegation-graph.ts +299 -0
  160. package/src/delegation/index.ts +14 -0
  161. package/src/delegation/statuslist-manager.ts +353 -0
  162. package/src/delegation/storage/__tests__/memory-graph-storage.test.ts +366 -0
  163. package/src/delegation/storage/__tests__/memory-statuslist-storage.test.ts +228 -0
  164. package/src/delegation/storage/index.ts +9 -0
  165. package/src/delegation/storage/memory-graph-storage.ts +178 -0
  166. package/src/delegation/storage/memory-statuslist-storage.ts +77 -0
  167. package/src/delegation/utils.ts +42 -0
  168. package/src/delegation/vc-issuer.ts +232 -0
  169. package/src/delegation/vc-verifier.ts +568 -0
  170. package/src/identity/idp-token-resolver.ts +147 -0
  171. package/src/identity/idp-token-storage.interface.ts +59 -0
  172. package/src/identity/user-did-manager.ts +370 -0
  173. package/src/index.ts +260 -0
  174. package/src/providers/base.d.ts +91 -0
  175. package/src/providers/base.d.ts.map +1 -0
  176. package/src/providers/base.js +38 -0
  177. package/src/providers/base.js.map +1 -0
  178. package/src/providers/base.ts +96 -0
  179. package/src/providers/memory.ts +142 -0
  180. package/src/runtime/audit-logger.ts +39 -0
  181. package/src/runtime/base.ts +1329 -0
  182. package/src/services/__tests__/access-control.integration.test.ts +443 -0
  183. package/src/services/__tests__/access-control.proof-response-validation.test.ts +578 -0
  184. package/src/services/__tests__/access-control.service.test.ts +970 -0
  185. package/src/services/__tests__/batch-delegation.service.test.ts +351 -0
  186. package/src/services/__tests__/crypto.service.test.ts +531 -0
  187. package/src/services/__tests__/oauth-provider-registry.test.ts +142 -0
  188. package/src/services/__tests__/proof-verifier.integration.test.ts +485 -0
  189. package/src/services/__tests__/proof-verifier.test.ts +489 -0
  190. package/src/services/__tests__/provider-resolution.integration.test.ts +198 -0
  191. package/src/services/__tests__/provider-resolver.test.ts +217 -0
  192. package/src/services/__tests__/storage.service.test.ts +358 -0
  193. package/src/services/access-control.service.ts +990 -0
  194. package/src/services/authorization/authorization-registry.ts +66 -0
  195. package/src/services/authorization/types.ts +71 -0
  196. package/src/services/batch-delegation.service.ts +137 -0
  197. package/src/services/crypto.service.ts +302 -0
  198. package/src/services/errors.ts +76 -0
  199. package/src/services/index.ts +9 -0
  200. package/src/services/oauth-config.service.d.ts +53 -0
  201. package/src/services/oauth-config.service.d.ts.map +1 -0
  202. package/src/services/oauth-config.service.js +113 -0
  203. package/src/services/oauth-config.service.js.map +1 -0
  204. package/src/services/oauth-config.service.ts +166 -0
  205. package/src/services/oauth-provider-registry.d.ts +57 -0
  206. package/src/services/oauth-provider-registry.d.ts.map +1 -0
  207. package/src/services/oauth-provider-registry.js +73 -0
  208. package/src/services/oauth-provider-registry.js.map +1 -0
  209. package/src/services/oauth-provider-registry.ts +123 -0
  210. package/src/services/oauth-service.ts +510 -0
  211. package/src/services/oauth-token-retrieval.service.ts +245 -0
  212. package/src/services/proof-verifier.ts +478 -0
  213. package/src/services/provider-resolver.d.ts +48 -0
  214. package/src/services/provider-resolver.d.ts.map +1 -0
  215. package/src/services/provider-resolver.js +106 -0
  216. package/src/services/provider-resolver.js.map +1 -0
  217. package/src/services/provider-resolver.ts +144 -0
  218. package/src/services/provider-validator.ts +170 -0
  219. package/src/services/storage.service.ts +566 -0
  220. package/src/services/tool-context-builder.ts +172 -0
  221. package/src/services/tool-protection.service.ts +958 -0
  222. package/src/types/oauth-required-error.ts +63 -0
  223. package/src/types/tool-protection.ts +155 -0
  224. package/src/utils/__tests__/did-helpers.test.ts +101 -0
  225. package/src/utils/base64.ts +148 -0
  226. package/src/utils/cors.ts +83 -0
  227. package/src/utils/did-helpers.ts +150 -0
  228. package/src/utils/index.ts +8 -0
  229. package/src/utils/storage-keys.ts +278 -0
  230. package/tsconfig.json +21 -0
  231. package/vitest.config.ts +56 -0
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Provider Resolver
3
+ *
4
+ * Resolves OAuth provider for tools using priority-based resolution strategy.
5
+ * Supports Phase 2+ tool-specific providers with backward compatibility for Phase 1.
6
+ *
7
+ * @package @kya-os/mcp-i-core
8
+ */
9
+ import type { ToolProtection } from "@kya-os/contracts/tool-protection";
10
+ import type { OAuthProviderRegistry } from "./oauth-provider-registry.js";
11
+ import type { OAuthConfigService } from "./oauth-config.service.js";
12
+ /**
13
+ * Resolves OAuth provider for tools with priority-based fallback strategy
14
+ *
15
+ * Priority order:
16
+ * 1. Tool-specific oauthProvider field (Phase 2+ preferred)
17
+ * 2. Scope prefix inference (fallback)
18
+ * 3. First configured provider (Phase 1 compatibility fallback)
19
+ * 4. Error if no provider can be resolved
20
+ */
21
+ export declare class ProviderResolver {
22
+ private registry;
23
+ private configService;
24
+ constructor(registry: OAuthProviderRegistry, configService: OAuthConfigService);
25
+ /**
26
+ * Resolve OAuth provider for a tool
27
+ *
28
+ * @param toolProtection - Tool protection configuration
29
+ * @param projectId - Project ID for fetching provider config
30
+ * @returns Provider name (never null - throws if cannot resolve)
31
+ * @throws Error if provider cannot be resolved
32
+ */
33
+ resolveProvider(toolProtection: ToolProtection, projectId: string): Promise<string>;
34
+ /**
35
+ * Infer provider from scope prefixes
36
+ *
37
+ * Used as Priority 2 fallback when oauthProvider is not specified.
38
+ * Examples:
39
+ * - github:repo:read → github
40
+ * - gmail:read → google
41
+ * - microsoft:calendar:read → microsoft
42
+ *
43
+ * @param scopes - Required scopes for the tool
44
+ * @returns Provider name if uniquely inferred, null otherwise
45
+ */
46
+ private inferProviderFromScopes;
47
+ }
48
+ //# sourceMappingURL=provider-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-resolver.d.ts","sourceRoot":"","sources":["provider-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAEpE;;;;;;;;GAQG;AACH,qBAAa,gBAAgB;IAEzB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,aAAa;gBADb,QAAQ,EAAE,qBAAqB,EAC/B,aAAa,EAAE,kBAAkB;IAG3C;;;;;;;OAOG;IACG,eAAe,CACnB,cAAc,EAAE,cAAc,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC;IA6ClB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,uBAAuB;CAoChC"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Provider Resolver
3
+ *
4
+ * Resolves OAuth provider for tools using priority-based resolution strategy.
5
+ * Supports Phase 2+ tool-specific providers with backward compatibility for Phase 1.
6
+ *
7
+ * @package @kya-os/mcp-i-core
8
+ */
9
+ /**
10
+ * Resolves OAuth provider for tools with priority-based fallback strategy
11
+ *
12
+ * Priority order:
13
+ * 1. Tool-specific oauthProvider field (Phase 2+ preferred)
14
+ * 2. Scope prefix inference (fallback)
15
+ * 3. First configured provider (Phase 1 compatibility fallback)
16
+ * 4. Error if no provider can be resolved
17
+ */
18
+ export class ProviderResolver {
19
+ registry;
20
+ configService;
21
+ constructor(registry, configService) {
22
+ this.registry = registry;
23
+ this.configService = configService;
24
+ }
25
+ /**
26
+ * Resolve OAuth provider for a tool
27
+ *
28
+ * @param toolProtection - Tool protection configuration
29
+ * @param projectId - Project ID for fetching provider config
30
+ * @returns Provider name (never null - throws if cannot resolve)
31
+ * @throws Error if provider cannot be resolved
32
+ */
33
+ async resolveProvider(toolProtection, projectId) {
34
+ // Priority 1: Tool-specific provider (Phase 2+ preferred)
35
+ if (toolProtection.oauthProvider) {
36
+ if (!this.registry.hasProvider(toolProtection.oauthProvider)) {
37
+ throw new Error(`Provider "${toolProtection.oauthProvider}" not configured for project "${projectId}". ` +
38
+ `Add provider in project settings.`);
39
+ }
40
+ return toolProtection.oauthProvider;
41
+ }
42
+ // Priority 2: Scope prefix inference (fallback)
43
+ const inferredProvider = this.inferProviderFromScopes(toolProtection.requiredScopes || []);
44
+ if (inferredProvider && this.registry.hasProvider(inferredProvider)) {
45
+ console.log(`[ProviderResolver] Inferred provider "${inferredProvider}" from scopes`);
46
+ return inferredProvider;
47
+ }
48
+ // Priority 3: First configured provider (Phase 1 compatibility fallback)
49
+ // Ensure registry is loaded
50
+ await this.registry.loadFromAgentShield(projectId);
51
+ const providers = this.registry.getAllProviders();
52
+ if (providers.length > 0) {
53
+ // Log deprecation warning for Phase 1 tools
54
+ const firstProviderName = this.registry.getProviderNames()[0];
55
+ console.warn(`[ProviderResolver] Tool does not specify oauthProvider. ` +
56
+ `Using first configured provider "${firstProviderName}" as fallback. ` +
57
+ `This is deprecated - configure oauthProvider in AgentShield dashboard for Phase 2+.`);
58
+ return firstProviderName;
59
+ }
60
+ // Priority 4: Error if no provider can be resolved
61
+ throw new Error(`Tool requires OAuth but no provider could be resolved. ` +
62
+ `Either specify oauthProvider in tool protection config, or configure at least one provider for project "${projectId}".`);
63
+ }
64
+ /**
65
+ * Infer provider from scope prefixes
66
+ *
67
+ * Used as Priority 2 fallback when oauthProvider is not specified.
68
+ * Examples:
69
+ * - github:repo:read → github
70
+ * - gmail:read → google
71
+ * - microsoft:calendar:read → microsoft
72
+ *
73
+ * @param scopes - Required scopes for the tool
74
+ * @returns Provider name if uniquely inferred, null otherwise
75
+ */
76
+ inferProviderFromScopes(scopes) {
77
+ if (!scopes || scopes.length === 0) {
78
+ return null;
79
+ }
80
+ // Extract first part of scope (before first colon)
81
+ const scopePrefixes = scopes.map((scope) => {
82
+ const parts = scope.split(":");
83
+ return parts[0].toLowerCase();
84
+ });
85
+ // Provider mapping
86
+ const providerMap = {
87
+ github: "github",
88
+ google: "google",
89
+ gmail: "google", // gmail:read → google
90
+ calendar: "google", // calendar:read → google (if ambiguous, use project default)
91
+ microsoft: "microsoft",
92
+ outlook: "microsoft",
93
+ slack: "slack",
94
+ auth0: "auth0",
95
+ okta: "okta",
96
+ };
97
+ // Find unique provider
98
+ const providers = new Set(scopePrefixes.map((prefix) => providerMap[prefix]).filter(Boolean));
99
+ if (providers.size === 1) {
100
+ return Array.from(providers)[0];
101
+ }
102
+ // Ambiguous or no prefix → return null (use project-level provider)
103
+ return null;
104
+ }
105
+ }
106
+ //# sourceMappingURL=provider-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-resolver.js","sourceRoot":"","sources":["provider-resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Provider Resolver
3
+ *
4
+ * Resolves OAuth provider for tools using priority-based resolution strategy.
5
+ * Supports Phase 2+ tool-specific providers with backward compatibility for Phase 1.
6
+ *
7
+ * @package @kya-os/mcp-i-core
8
+ */
9
+
10
+ import type { ToolProtection } from "@kya-os/contracts/tool-protection";
11
+ import type { OAuthProviderRegistry } from "./oauth-provider-registry.js";
12
+ import type { OAuthConfigService } from "./oauth-config.service.js";
13
+
14
+ /**
15
+ * Resolves OAuth provider for tools with priority-based fallback strategy
16
+ *
17
+ * Priority order:
18
+ * 1. Tool-specific oauthProvider field (Phase 2+ preferred)
19
+ * 2. Scope prefix inference (fallback)
20
+ * 3. First configured provider (Phase 1 compatibility fallback)
21
+ * 4. Error if no provider can be resolved
22
+ */
23
+ export class ProviderResolver {
24
+ constructor(
25
+ private registry: OAuthProviderRegistry,
26
+ private configService: OAuthConfigService
27
+ ) {}
28
+
29
+ /**
30
+ * Resolve OAuth provider for a tool
31
+ *
32
+ * @param toolProtection - Tool protection configuration
33
+ * @param projectId - Project ID for fetching provider config
34
+ * @returns Provider name (never null - throws if cannot resolve)
35
+ * @throws Error if provider cannot be resolved
36
+ */
37
+ async resolveProvider(
38
+ toolProtection: ToolProtection,
39
+ projectId: string
40
+ ): Promise<string> {
41
+ // Priority 1: Tool-specific provider (Phase 2+ preferred)
42
+ if (toolProtection.oauthProvider) {
43
+ // Ensure registry is loaded before checking
44
+ if (this.registry.getProviderNames().length === 0) {
45
+ await this.registry.loadFromAgentShield(projectId);
46
+ }
47
+ if (!this.registry.hasProvider(toolProtection.oauthProvider)) {
48
+ throw new Error(
49
+ `Provider "${toolProtection.oauthProvider}" not configured for project "${projectId}". ` +
50
+ `Add provider in project settings.`
51
+ );
52
+ }
53
+ return toolProtection.oauthProvider;
54
+ }
55
+
56
+ // Priority 2: Scope prefix inference (fallback)
57
+ const inferredProvider = this.inferProviderFromScopes(
58
+ toolProtection.requiredScopes || []
59
+ );
60
+ if (inferredProvider) {
61
+ // Ensure registry is loaded before checking
62
+ if (this.registry.getProviderNames().length === 0) {
63
+ await this.registry.loadFromAgentShield(projectId);
64
+ }
65
+ if (this.registry.hasProvider(inferredProvider)) {
66
+ console.log(
67
+ `[ProviderResolver] Inferred provider "${inferredProvider}" from scopes`
68
+ );
69
+ return inferredProvider;
70
+ }
71
+ }
72
+
73
+ // Priority 3: First configured provider (Phase 1 compatibility fallback)
74
+ // Ensure registry is loaded
75
+ await this.registry.loadFromAgentShield(projectId);
76
+ const providers = this.registry.getAllProviders();
77
+ if (providers.length > 0) {
78
+ // Log deprecation warning for Phase 1 tools
79
+ const firstProviderName = this.registry.getProviderNames()[0];
80
+ console.warn(
81
+ `[ProviderResolver] Tool does not specify oauthProvider. ` +
82
+ `Using first configured provider "${firstProviderName}" as fallback. ` +
83
+ `This is deprecated - configure oauthProvider in AgentShield dashboard for Phase 2+.`
84
+ );
85
+ return firstProviderName;
86
+ }
87
+
88
+ // Priority 4: Error if no provider can be resolved
89
+ throw new Error(
90
+ `Tool requires OAuth but no provider could be resolved. ` +
91
+ `Either specify oauthProvider in tool protection config, or configure at least one provider for project "${projectId}".`
92
+ );
93
+ }
94
+
95
+ /**
96
+ * Infer provider from scope prefixes
97
+ *
98
+ * Used as Priority 2 fallback when oauthProvider is not specified.
99
+ * Examples:
100
+ * - github:repo:read → github
101
+ * - gmail:read → google
102
+ * - microsoft:calendar:read → microsoft
103
+ *
104
+ * @param scopes - Required scopes for the tool
105
+ * @returns Provider name if uniquely inferred, null otherwise
106
+ */
107
+ private inferProviderFromScopes(scopes: string[]): string | null {
108
+ if (!scopes || scopes.length === 0) {
109
+ return null;
110
+ }
111
+
112
+ // Extract first part of scope (before first colon)
113
+ const scopePrefixes = scopes.map((scope) => {
114
+ const parts = scope.split(":");
115
+ return parts[0].toLowerCase();
116
+ });
117
+
118
+ // Provider mapping
119
+ const providerMap: Record<string, string> = {
120
+ github: "github",
121
+ google: "google",
122
+ gmail: "google", // gmail:read → google
123
+ calendar: "google", // calendar:read → google (if ambiguous, use project default)
124
+ microsoft: "microsoft",
125
+ outlook: "microsoft",
126
+ slack: "slack",
127
+ auth0: "auth0",
128
+ okta: "okta",
129
+ };
130
+
131
+ // Find unique provider
132
+ const providers = new Set(
133
+ scopePrefixes.map((prefix) => providerMap[prefix]).filter(Boolean)
134
+ );
135
+
136
+ if (providers.size === 1) {
137
+ return Array.from(providers)[0];
138
+ }
139
+
140
+ // Ambiguous or no prefix → return null (use project-level provider)
141
+ return null;
142
+ }
143
+ }
144
+
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Provider Validator
3
+ *
4
+ * Validates OAuth provider configurations for custom IDP support.
5
+ * Ensures provider configurations are valid before registration.
6
+ *
7
+ * @package @kya-os/mcp-i-core
8
+ */
9
+
10
+ import type { OAuthProvider } from "@kya-os/contracts/config";
11
+
12
+ /**
13
+ * Reserved OAuth parameters that cannot be overridden by custom parameters
14
+ */
15
+ const RESERVED_PARAMETERS = [
16
+ "response_type",
17
+ "client_id",
18
+ "redirect_uri",
19
+ "scope",
20
+ "state",
21
+ "code_challenge",
22
+ "code_challenge_method",
23
+ ] as const;
24
+
25
+ /**
26
+ * Validation error for provider configuration issues
27
+ */
28
+ export class ProviderValidationError extends Error {
29
+ constructor(message: string, public readonly field?: string) {
30
+ super(message);
31
+ this.name = "ProviderValidationError";
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Service for validating OAuth provider configurations
37
+ */
38
+ export class ProviderValidator {
39
+ /**
40
+ * Validate provider configuration
41
+ *
42
+ * @param provider - Provider configuration to validate
43
+ * @param name - Provider name (for error messages)
44
+ * @throws ProviderValidationError if validation fails
45
+ */
46
+ validate(provider: OAuthProvider, name: string): void {
47
+ // Validate required fields
48
+ if (!provider.clientId || provider.clientId.trim().length === 0) {
49
+ throw new ProviderValidationError(
50
+ `Provider "${name}" must have a clientId`,
51
+ "clientId"
52
+ );
53
+ }
54
+
55
+ if (!provider.authorizationUrl || provider.authorizationUrl.trim().length === 0) {
56
+ throw new ProviderValidationError(
57
+ `Provider "${name}" must have an authorizationUrl`,
58
+ "authorizationUrl"
59
+ );
60
+ }
61
+
62
+ if (!provider.tokenUrl || provider.tokenUrl.trim().length === 0) {
63
+ throw new ProviderValidationError(
64
+ `Provider "${name}" must have a tokenUrl`,
65
+ "tokenUrl"
66
+ );
67
+ }
68
+
69
+ // Validate URL formats
70
+ this.validateUrl(provider.authorizationUrl, name, "authorizationUrl");
71
+ this.validateUrl(provider.tokenUrl, name, "tokenUrl");
72
+
73
+ if (provider.userInfoUrl) {
74
+ this.validateUrl(provider.userInfoUrl, name, "userInfoUrl");
75
+ }
76
+
77
+ // Validate proxy mode requirements
78
+ if (provider.proxyMode && !provider.requiresClientSecret) {
79
+ throw new ProviderValidationError(
80
+ `Provider "${name}" with proxyMode=true must have requiresClientSecret=true`,
81
+ "proxyMode"
82
+ );
83
+ }
84
+
85
+ // Validate custom parameters don't conflict with reserved parameters
86
+ if (provider.customParams) {
87
+ this.validateCustomParams(provider.customParams, name);
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Validate URL format
93
+ *
94
+ * @param url - URL to validate
95
+ * @param providerName - Provider name (for error messages)
96
+ * @param fieldName - Field name (for error messages)
97
+ * @throws ProviderValidationError if URL is invalid
98
+ */
99
+ private validateUrl(url: string, providerName: string, fieldName: string): void {
100
+ try {
101
+ const parsedUrl = new URL(url);
102
+ if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") {
103
+ throw new ProviderValidationError(
104
+ `Provider "${providerName}" ${fieldName} must use HTTP or HTTPS protocol`,
105
+ fieldName
106
+ );
107
+ }
108
+ } catch (error) {
109
+ if (error instanceof ProviderValidationError) {
110
+ throw error;
111
+ }
112
+ throw new ProviderValidationError(
113
+ `Provider "${providerName}" ${fieldName} is not a valid URL: ${error instanceof Error ? error.message : String(error)}`,
114
+ fieldName
115
+ );
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Validate custom parameters don't override reserved OAuth parameters
121
+ *
122
+ * @param customParams - Custom parameters to validate
123
+ * @param providerName - Provider name (for error messages)
124
+ * @throws ProviderValidationError if reserved parameter is overridden
125
+ */
126
+ private validateCustomParams(
127
+ customParams: Record<string, string>,
128
+ providerName: string
129
+ ): void {
130
+ for (const [key, value] of Object.entries(customParams)) {
131
+ const normalizedKey = key.toLowerCase();
132
+ if (RESERVED_PARAMETERS.includes(normalizedKey as any)) {
133
+ throw new ProviderValidationError(
134
+ `Provider "${providerName}" custom parameter "${key}" conflicts with reserved OAuth parameter. Reserved parameters: ${RESERVED_PARAMETERS.join(", ")}`,
135
+ `customParams.${key}`
136
+ );
137
+ }
138
+ if (!value || value.trim().length === 0) {
139
+ throw new ProviderValidationError(
140
+ `Provider "${providerName}" custom parameter "${key}" has empty value`,
141
+ `customParams.${key}`
142
+ );
143
+ }
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Test provider endpoint reachability (optional)
149
+ *
150
+ * @param provider - Provider configuration
151
+ * @param fetchProvider - Fetch implementation
152
+ * @returns True if endpoint is reachable, false otherwise
153
+ */
154
+ async testProvider(
155
+ provider: OAuthProvider,
156
+ fetchProvider: typeof fetch
157
+ ): Promise<boolean> {
158
+ try {
159
+ // Test authorization URL (HEAD request to avoid triggering OAuth flow)
160
+ const authResponse = await fetchProvider(provider.authorizationUrl, {
161
+ method: "HEAD",
162
+ signal: AbortSignal.timeout(5000), // 5 second timeout
163
+ });
164
+ return authResponse.ok || authResponse.status === 405; // 405 Method Not Allowed is OK
165
+ } catch (error) {
166
+ return false;
167
+ }
168
+ }
169
+ }
170
+