@kya-os/mcp-i-core 1.3.12 → 1.3.14
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/dist/config/remote-config.js +9 -12
- package/dist/runtime/base.js +11 -0
- package/dist/services/access-control.service.js +5 -0
- package/dist/services/tool-protection.service.js +17 -8
- package/package.json +2 -2
- package/.turbo/turbo-build.log +0 -4
- package/.turbo/turbo-test$colon$coverage.log +0 -4586
- package/.turbo/turbo-test.log +0 -3169
- package/COMPLIANCE_IMPROVEMENT_REPORT.md +0 -483
- package/Composer 3.md +0 -615
- package/GPT-5.md +0 -1169
- package/OPUS-plan.md +0 -352
- package/PHASE_3_AND_4.1_SUMMARY.md +0 -585
- package/PHASE_3_SUMMARY.md +0 -317
- package/PHASE_4.1.3_SUMMARY.md +0 -428
- package/PHASE_4.1_COMPLETE.md +0 -525
- package/PHASE_4_USER_DID_IDENTITY_LINKING_PLAN.md +0 -1240
- package/SCHEMA_COMPLIANCE_REPORT.md +0 -275
- package/TEST_PLAN.md +0 -571
- package/coverage/coverage-final.json +0 -60
- package/dist/cache/oauth-config-cache.d.ts.map +0 -1
- package/dist/cache/oauth-config-cache.js.map +0 -1
- package/dist/cache/tool-protection-cache.d.ts.map +0 -1
- package/dist/cache/tool-protection-cache.js.map +0 -1
- package/dist/compliance/index.d.ts.map +0 -1
- package/dist/compliance/index.js.map +0 -1
- package/dist/compliance/schema-registry.d.ts.map +0 -1
- package/dist/compliance/schema-registry.js.map +0 -1
- package/dist/compliance/schema-verifier.d.ts.map +0 -1
- package/dist/compliance/schema-verifier.js.map +0 -1
- package/dist/config/remote-config.d.ts.map +0 -1
- package/dist/config/remote-config.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/delegation/audience-validator.d.ts.map +0 -1
- package/dist/delegation/audience-validator.js.map +0 -1
- package/dist/delegation/bitstring.d.ts.map +0 -1
- package/dist/delegation/bitstring.js.map +0 -1
- package/dist/delegation/cascading-revocation.d.ts.map +0 -1
- package/dist/delegation/cascading-revocation.js.map +0 -1
- package/dist/delegation/delegation-graph.d.ts.map +0 -1
- package/dist/delegation/delegation-graph.js.map +0 -1
- package/dist/delegation/did-key-resolver.d.ts.map +0 -1
- package/dist/delegation/did-key-resolver.js.map +0 -1
- package/dist/delegation/index.d.ts.map +0 -1
- package/dist/delegation/index.js.map +0 -1
- package/dist/delegation/statuslist-manager.d.ts.map +0 -1
- package/dist/delegation/statuslist-manager.js.map +0 -1
- package/dist/delegation/storage/index.d.ts.map +0 -1
- package/dist/delegation/storage/index.js.map +0 -1
- package/dist/delegation/storage/memory-graph-storage.d.ts.map +0 -1
- package/dist/delegation/storage/memory-graph-storage.js.map +0 -1
- package/dist/delegation/storage/memory-statuslist-storage.d.ts.map +0 -1
- package/dist/delegation/storage/memory-statuslist-storage.js.map +0 -1
- package/dist/delegation/utils.d.ts.map +0 -1
- package/dist/delegation/utils.js.map +0 -1
- package/dist/delegation/vc-issuer.d.ts.map +0 -1
- package/dist/delegation/vc-issuer.js.map +0 -1
- package/dist/delegation/vc-verifier.d.ts.map +0 -1
- package/dist/delegation/vc-verifier.js.map +0 -1
- package/dist/identity/idp-token-resolver.d.ts.map +0 -1
- package/dist/identity/idp-token-resolver.js.map +0 -1
- package/dist/identity/idp-token-storage.interface.d.ts.map +0 -1
- package/dist/identity/idp-token-storage.interface.js.map +0 -1
- package/dist/identity/user-did-manager.d.ts.map +0 -1
- package/dist/identity/user-did-manager.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/providers/base.d.ts.map +0 -1
- package/dist/providers/base.js.map +0 -1
- package/dist/providers/memory.d.ts.map +0 -1
- package/dist/providers/memory.js.map +0 -1
- package/dist/runtime/audit-logger.d.ts.map +0 -1
- package/dist/runtime/audit-logger.js.map +0 -1
- package/dist/runtime/base.d.ts.map +0 -1
- package/dist/runtime/base.js.map +0 -1
- package/dist/services/access-control.service.d.ts.map +0 -1
- package/dist/services/access-control.service.js.map +0 -1
- package/dist/services/authorization/authorization-registry.d.ts.map +0 -1
- package/dist/services/authorization/authorization-registry.js.map +0 -1
- package/dist/services/authorization/types.d.ts.map +0 -1
- package/dist/services/authorization/types.js.map +0 -1
- package/dist/services/batch-delegation.service.d.ts.map +0 -1
- package/dist/services/batch-delegation.service.js.map +0 -1
- package/dist/services/crypto.service.d.ts.map +0 -1
- package/dist/services/crypto.service.js.map +0 -1
- package/dist/services/errors.d.ts.map +0 -1
- package/dist/services/errors.js.map +0 -1
- package/dist/services/index.d.ts.map +0 -1
- package/dist/services/index.js.map +0 -1
- package/dist/services/oauth-config.service.d.ts.map +0 -1
- package/dist/services/oauth-config.service.js.map +0 -1
- package/dist/services/oauth-provider-registry.d.ts.map +0 -1
- package/dist/services/oauth-provider-registry.js.map +0 -1
- package/dist/services/oauth-service.d.ts.map +0 -1
- package/dist/services/oauth-service.js.map +0 -1
- package/dist/services/oauth-token-retrieval.service.d.ts.map +0 -1
- package/dist/services/oauth-token-retrieval.service.js.map +0 -1
- package/dist/services/proof-verifier.d.ts.map +0 -1
- package/dist/services/proof-verifier.js.map +0 -1
- package/dist/services/provider-resolver.d.ts.map +0 -1
- package/dist/services/provider-resolver.js.map +0 -1
- package/dist/services/provider-validator.d.ts.map +0 -1
- package/dist/services/provider-validator.js.map +0 -1
- package/dist/services/session-registration.service.d.ts.map +0 -1
- package/dist/services/session-registration.service.js.map +0 -1
- package/dist/services/storage.service.d.ts.map +0 -1
- package/dist/services/storage.service.js.map +0 -1
- package/dist/services/tool-context-builder.d.ts.map +0 -1
- package/dist/services/tool-context-builder.js.map +0 -1
- package/dist/services/tool-protection.service.d.ts.map +0 -1
- package/dist/services/tool-protection.service.js.map +0 -1
- package/dist/types/oauth-required-error.d.ts.map +0 -1
- package/dist/types/oauth-required-error.js.map +0 -1
- package/dist/types/tool-protection.d.ts.map +0 -1
- package/dist/types/tool-protection.js.map +0 -1
- package/dist/utils/base58.d.ts.map +0 -1
- package/dist/utils/base58.js.map +0 -1
- package/dist/utils/base64.d.ts.map +0 -1
- package/dist/utils/base64.js.map +0 -1
- package/dist/utils/cors.d.ts.map +0 -1
- package/dist/utils/cors.js.map +0 -1
- package/dist/utils/did-helpers.d.ts.map +0 -1
- package/dist/utils/did-helpers.js.map +0 -1
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/storage-keys.d.ts.map +0 -1
- package/dist/utils/storage-keys.js.map +0 -1
- package/docs/API_REFERENCE.md +0 -1362
- package/docs/COMPLIANCE_MATRIX.md +0 -691
- package/docs/STATUSLIST2021_GUIDE.md +0 -696
- package/docs/W3C_VC_DELEGATION_GUIDE.md +0 -710
- package/src/__tests__/cache/tool-protection-cache.test.ts +0 -640
- package/src/__tests__/config/provider-runtime-config.test.ts +0 -309
- package/src/__tests__/delegation-e2e.test.ts +0 -690
- package/src/__tests__/identity/user-did-manager.test.ts +0 -232
- package/src/__tests__/index.test.ts +0 -56
- package/src/__tests__/integration/full-flow.test.ts +0 -789
- package/src/__tests__/integration.test.ts +0 -281
- package/src/__tests__/providers/base.test.ts +0 -173
- package/src/__tests__/providers/memory.test.ts +0 -319
- package/src/__tests__/regression/phase2-regression.test.ts +0 -429
- package/src/__tests__/runtime/audit-logger.test.ts +0 -154
- package/src/__tests__/runtime/base-extensions.test.ts +0 -595
- package/src/__tests__/runtime/base.test.ts +0 -869
- package/src/__tests__/runtime/delegation-flow.test.ts +0 -164
- package/src/__tests__/runtime/proof-client-did.test.ts +0 -376
- package/src/__tests__/runtime/route-interception.test.ts +0 -686
- package/src/__tests__/runtime/tool-protection-enforcement.test.ts +0 -908
- package/src/__tests__/services/agentshield-integration.test.ts +0 -791
- package/src/__tests__/services/cache-busting.test.ts +0 -125
- package/src/__tests__/services/oauth-service-pkce.test.ts +0 -556
- package/src/__tests__/services/provider-resolver-edge-cases.test.ts +0 -591
- package/src/__tests__/services/tool-protection-merged-config.test.ts +0 -485
- package/src/__tests__/services/tool-protection-oauth-provider.test.ts +0 -480
- package/src/__tests__/services/tool-protection.service.test.ts +0 -1373
- package/src/__tests__/utils/mock-providers.ts +0 -340
- package/src/cache/oauth-config-cache.d.ts +0 -69
- package/src/cache/oauth-config-cache.d.ts.map +0 -1
- package/src/cache/oauth-config-cache.js.map +0 -1
- package/src/cache/oauth-config-cache.ts +0 -123
- package/src/cache/tool-protection-cache.ts +0 -171
- package/src/compliance/EXAMPLE.md +0 -412
- package/src/compliance/__tests__/schema-verifier.test.ts +0 -797
- package/src/compliance/index.ts +0 -8
- package/src/compliance/schema-registry.ts +0 -460
- package/src/compliance/schema-verifier.ts +0 -708
- package/src/config/__tests__/merged-config.spec.ts +0 -445
- package/src/config/__tests__/remote-config.spec.ts +0 -268
- package/src/config/remote-config.ts +0 -264
- package/src/config.ts +0 -312
- package/src/delegation/__tests__/audience-validator.test.ts +0 -112
- package/src/delegation/__tests__/bitstring.test.ts +0 -346
- package/src/delegation/__tests__/cascading-revocation.test.ts +0 -628
- package/src/delegation/__tests__/delegation-graph.test.ts +0 -584
- package/src/delegation/__tests__/did-key-resolver.test.ts +0 -265
- package/src/delegation/__tests__/utils.test.ts +0 -152
- package/src/delegation/__tests__/vc-issuer.test.ts +0 -442
- package/src/delegation/__tests__/vc-verifier.test.ts +0 -922
- package/src/delegation/audience-validator.ts +0 -52
- package/src/delegation/bitstring.ts +0 -278
- package/src/delegation/cascading-revocation.ts +0 -370
- package/src/delegation/delegation-graph.ts +0 -299
- package/src/delegation/did-key-resolver.ts +0 -179
- package/src/delegation/index.ts +0 -14
- package/src/delegation/statuslist-manager.ts +0 -353
- package/src/delegation/storage/__tests__/memory-graph-storage.test.ts +0 -366
- package/src/delegation/storage/__tests__/memory-statuslist-storage.test.ts +0 -228
- package/src/delegation/storage/index.ts +0 -9
- package/src/delegation/storage/memory-graph-storage.ts +0 -178
- package/src/delegation/storage/memory-statuslist-storage.ts +0 -77
- package/src/delegation/utils.ts +0 -221
- package/src/delegation/vc-issuer.ts +0 -232
- package/src/delegation/vc-verifier.ts +0 -568
- package/src/identity/idp-token-resolver.ts +0 -181
- package/src/identity/idp-token-storage.interface.ts +0 -94
- package/src/identity/user-did-manager.ts +0 -526
- package/src/index.ts +0 -310
- package/src/providers/base.d.ts +0 -91
- package/src/providers/base.d.ts.map +0 -1
- package/src/providers/base.js.map +0 -1
- package/src/providers/base.ts +0 -96
- package/src/providers/memory.ts +0 -142
- package/src/runtime/audit-logger.ts +0 -39
- package/src/runtime/base.ts +0 -1392
- package/src/services/__tests__/access-control.integration.test.ts +0 -443
- package/src/services/__tests__/access-control.proof-response-validation.test.ts +0 -578
- package/src/services/__tests__/access-control.service.test.ts +0 -970
- package/src/services/__tests__/batch-delegation.service.test.ts +0 -351
- package/src/services/__tests__/crypto.service.test.ts +0 -531
- package/src/services/__tests__/oauth-provider-registry.test.ts +0 -142
- package/src/services/__tests__/proof-verifier.integration.test.ts +0 -485
- package/src/services/__tests__/proof-verifier.test.ts +0 -489
- package/src/services/__tests__/provider-resolution.integration.test.ts +0 -202
- package/src/services/__tests__/provider-resolver.test.ts +0 -213
- package/src/services/__tests__/storage.service.test.ts +0 -358
- package/src/services/access-control.service.ts +0 -990
- package/src/services/authorization/authorization-registry.ts +0 -66
- package/src/services/authorization/types.ts +0 -71
- package/src/services/batch-delegation.service.ts +0 -137
- package/src/services/crypto.service.ts +0 -302
- package/src/services/errors.ts +0 -76
- package/src/services/index.ts +0 -18
- package/src/services/oauth-config.service.d.ts +0 -53
- package/src/services/oauth-config.service.d.ts.map +0 -1
- package/src/services/oauth-config.service.js.map +0 -1
- package/src/services/oauth-config.service.ts +0 -192
- package/src/services/oauth-provider-registry.d.ts +0 -57
- package/src/services/oauth-provider-registry.d.ts.map +0 -1
- package/src/services/oauth-provider-registry.js.map +0 -1
- package/src/services/oauth-provider-registry.ts +0 -141
- package/src/services/oauth-service.ts +0 -544
- package/src/services/oauth-token-retrieval.service.ts +0 -245
- package/src/services/proof-verifier.ts +0 -478
- package/src/services/provider-resolver.d.ts +0 -48
- package/src/services/provider-resolver.d.ts.map +0 -1
- package/src/services/provider-resolver.js.map +0 -1
- package/src/services/provider-resolver.ts +0 -146
- package/src/services/provider-validator.ts +0 -170
- package/src/services/session-registration.service.ts +0 -251
- package/src/services/storage.service.ts +0 -566
- package/src/services/tool-context-builder.ts +0 -237
- package/src/services/tool-protection.service.ts +0 -1070
- package/src/types/oauth-required-error.ts +0 -63
- package/src/types/tool-protection.ts +0 -155
- package/src/utils/__tests__/did-helpers.test.ts +0 -156
- package/src/utils/base58.ts +0 -109
- package/src/utils/base64.ts +0 -148
- package/src/utils/cors.ts +0 -83
- package/src/utils/did-helpers.ts +0 -210
- package/src/utils/index.ts +0 -8
- package/src/utils/storage-keys.ts +0 -278
- package/tsconfig.json +0 -21
- package/vitest.config.ts +0 -56
|
@@ -1,591 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Provider Resolver - Edge Cases Tests
|
|
3
|
-
*
|
|
4
|
-
* Tests for edge cases and error scenarios in provider resolution
|
|
5
|
-
* (Phase 2: Dynamic Providers)
|
|
6
|
-
*
|
|
7
|
-
* @package @kya-os/mcp-i-core
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
11
|
-
import { ProviderResolver } from "../../services/provider-resolver.js";
|
|
12
|
-
import { OAuthProviderRegistry } from "../../services/oauth-provider-registry.js";
|
|
13
|
-
import { OAuthConfigService } from "../../services/oauth-config.service.js";
|
|
14
|
-
import type { ToolProtection } from "@kya-os/contracts/tool-protection";
|
|
15
|
-
import type { OAuthConfig } from "@kya-os/contracts/config";
|
|
16
|
-
|
|
17
|
-
describe("ProviderResolver - Edge Cases", () => {
|
|
18
|
-
let mockConfigService: OAuthConfigService;
|
|
19
|
-
let mockRegistry: OAuthProviderRegistry;
|
|
20
|
-
let resolver: ProviderResolver;
|
|
21
|
-
|
|
22
|
-
const mockOAuthConfig: OAuthConfig = {
|
|
23
|
-
providers: {
|
|
24
|
-
github: {
|
|
25
|
-
clientId: "github_client_id",
|
|
26
|
-
authorizationUrl: "https://github.com/login/oauth/authorize",
|
|
27
|
-
tokenUrl: "https://github.com/login/oauth/access_token",
|
|
28
|
-
supportsPKCE: true,
|
|
29
|
-
requiresClientSecret: false,
|
|
30
|
-
},
|
|
31
|
-
google: {
|
|
32
|
-
clientId: "google_client_id",
|
|
33
|
-
authorizationUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
34
|
-
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
35
|
-
supportsPKCE: true,
|
|
36
|
-
requiresClientSecret: false,
|
|
37
|
-
},
|
|
38
|
-
microsoft: {
|
|
39
|
-
clientId: "microsoft_client_id",
|
|
40
|
-
authorizationUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
|
|
41
|
-
tokenUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
|
|
42
|
-
supportsPKCE: true,
|
|
43
|
-
requiresClientSecret: false,
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
beforeEach(() => {
|
|
49
|
-
// Don't clear mocks here - it might interfere with mock return values
|
|
50
|
-
// Instead, create fresh mocks for each test
|
|
51
|
-
|
|
52
|
-
mockConfigService = {
|
|
53
|
-
getOAuthConfig: vi.fn().mockResolvedValue(mockOAuthConfig),
|
|
54
|
-
} as any;
|
|
55
|
-
|
|
56
|
-
// Create fresh mocks for each test
|
|
57
|
-
const getProviderNamesMock = vi.fn().mockReturnValue([]);
|
|
58
|
-
const loadFromAgentShieldMock = vi.fn().mockResolvedValue(undefined);
|
|
59
|
-
const hasProviderMock = vi.fn().mockReturnValue(false);
|
|
60
|
-
const getConfiguredProviderMock = vi.fn().mockReturnValue(null);
|
|
61
|
-
|
|
62
|
-
mockRegistry = {
|
|
63
|
-
hasProvider: hasProviderMock,
|
|
64
|
-
getAllProviders: vi.fn().mockReturnValue([]),
|
|
65
|
-
getProviderNames: getProviderNamesMock,
|
|
66
|
-
loadFromAgentShield: loadFromAgentShieldMock,
|
|
67
|
-
getConfiguredProvider: getConfiguredProviderMock,
|
|
68
|
-
} as any;
|
|
69
|
-
|
|
70
|
-
resolver = new ProviderResolver(mockRegistry, mockConfigService);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
describe("Provider validation (Priority 1)", () => {
|
|
74
|
-
it("should validate provider exists before returning", async () => {
|
|
75
|
-
const toolProtection: ToolProtection = {
|
|
76
|
-
requiresDelegation: true,
|
|
77
|
-
requiredScopes: ["repo:read"],
|
|
78
|
-
oauthProvider: "github",
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
// Mock registry that simulates loaded state
|
|
82
|
-
const testRegistry = {
|
|
83
|
-
getProviderNames: vi.fn().mockReturnValue(["github", "google"]),
|
|
84
|
-
hasProvider: vi.fn((provider: string) => provider === "github" || provider === "google"),
|
|
85
|
-
loadFromAgentShield: vi.fn().mockResolvedValue(undefined),
|
|
86
|
-
getAllProviders: vi.fn().mockReturnValue([]),
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
const testResolver = new ProviderResolver(testRegistry as any, mockConfigService);
|
|
90
|
-
|
|
91
|
-
const provider = await testResolver.resolveProvider(
|
|
92
|
-
toolProtection,
|
|
93
|
-
"test-project"
|
|
94
|
-
);
|
|
95
|
-
|
|
96
|
-
expect(provider).toBe("github");
|
|
97
|
-
expect(testRegistry.hasProvider).toHaveBeenCalledWith("github");
|
|
98
|
-
// Should not need to load since registry already has providers
|
|
99
|
-
expect(testRegistry.loadFromAgentShield).not.toHaveBeenCalled();
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
// TODO: Fix this test - it's trying to verify that the registry automatically loads
|
|
103
|
-
// when empty, but the mock state transitions are complex due to async timing.
|
|
104
|
-
// The test needs to properly simulate the registry state changing from empty to
|
|
105
|
-
// populated after loadFromAgentShield completes, but before hasProvider is called.
|
|
106
|
-
// Consider using a more integration-style test or rethinking the test approach.
|
|
107
|
-
it.skip("should load registry if empty before checking provider existence", async () => {
|
|
108
|
-
const toolProtection: ToolProtection = {
|
|
109
|
-
requiresDelegation: true,
|
|
110
|
-
requiredScopes: ["repo:read"],
|
|
111
|
-
oauthProvider: "github",
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
// Create a mock registry that starts empty
|
|
115
|
-
const mockEmptyRegistry = {
|
|
116
|
-
getProviderNames: vi.fn().mockReturnValue([]), // Empty initially
|
|
117
|
-
hasProvider: vi.fn().mockReturnValue(false), // No providers initially
|
|
118
|
-
loadFromAgentShield: vi.fn().mockResolvedValue(undefined),
|
|
119
|
-
getAllProviders: vi.fn().mockReturnValue([]),
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
const testResolver = new ProviderResolver(mockEmptyRegistry as any, mockConfigService);
|
|
123
|
-
|
|
124
|
-
// Since the registry starts empty and hasProvider returns false,
|
|
125
|
-
// the resolver will throw an error about the provider not being configured
|
|
126
|
-
await expect(
|
|
127
|
-
testResolver.resolveProvider(toolProtection, "test-project")
|
|
128
|
-
).rejects.toThrow(/not configured for project/);
|
|
129
|
-
|
|
130
|
-
// Verify that loadFromAgentShield was called
|
|
131
|
-
expect(mockEmptyRegistry.loadFromAgentShield).toHaveBeenCalledWith("test-project");
|
|
132
|
-
expect(mockEmptyRegistry.getProviderNames).toHaveBeenCalled();
|
|
133
|
-
expect(mockEmptyRegistry.hasProvider).toHaveBeenCalledWith("github");
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it("should throw error if tool-specific provider not configured", async () => {
|
|
137
|
-
const toolProtection: ToolProtection = {
|
|
138
|
-
requiresDelegation: true,
|
|
139
|
-
requiredScopes: ["repo:read"],
|
|
140
|
-
oauthProvider: "nonexistent",
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
(mockRegistry.getProviderNames as any).mockReturnValue(["github", "google"]);
|
|
144
|
-
(mockRegistry.hasProvider as any).mockReturnValue(false);
|
|
145
|
-
|
|
146
|
-
await expect(
|
|
147
|
-
resolver.resolveProvider(toolProtection, "test-project")
|
|
148
|
-
).rejects.toThrow(/not configured for project/);
|
|
149
|
-
});
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
describe("Scope inference edge cases (Priority 2)", () => {
|
|
153
|
-
it("should handle empty scopes array", async () => {
|
|
154
|
-
const toolProtection: ToolProtection = {
|
|
155
|
-
requiresDelegation: true,
|
|
156
|
-
requiredScopes: [],
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
// Should fall through to Priority 3 (configuredProvider)
|
|
160
|
-
(mockRegistry.hasProvider as any).mockImplementation((name: string) => name === "github");
|
|
161
|
-
(mockRegistry.getConfiguredProvider as any).mockReturnValue("github");
|
|
162
|
-
|
|
163
|
-
const provider = await resolver.resolveProvider(
|
|
164
|
-
toolProtection,
|
|
165
|
-
"test-project"
|
|
166
|
-
);
|
|
167
|
-
|
|
168
|
-
// Should use configured provider (Priority 3)
|
|
169
|
-
expect(provider).toBe("github");
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
it("should handle ambiguous scopes (multiple providers inferred)", async () => {
|
|
173
|
-
const toolProtection: ToolProtection = {
|
|
174
|
-
requiresDelegation: true,
|
|
175
|
-
requiredScopes: ["github:repo:read", "google:calendar:read"],
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
// Ambiguous scopes should fall through to Priority 3 (configuredProvider)
|
|
179
|
-
(mockRegistry.hasProvider as any).mockImplementation((name: string) => name === "github");
|
|
180
|
-
(mockRegistry.getConfiguredProvider as any).mockReturnValue("github");
|
|
181
|
-
|
|
182
|
-
const provider = await resolver.resolveProvider(
|
|
183
|
-
toolProtection,
|
|
184
|
-
"test-project"
|
|
185
|
-
);
|
|
186
|
-
|
|
187
|
-
// Should use configured provider (Priority 3)
|
|
188
|
-
expect(provider).toBe("github");
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
it("should handle unknown scope prefixes", async () => {
|
|
192
|
-
const toolProtection: ToolProtection = {
|
|
193
|
-
requiresDelegation: true,
|
|
194
|
-
requiredScopes: ["custom:unknown:scope"],
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
// Unknown prefix should fall through to Priority 3 (configuredProvider)
|
|
198
|
-
(mockRegistry.hasProvider as any).mockImplementation((name: string) => name === "github");
|
|
199
|
-
(mockRegistry.getConfiguredProvider as any).mockReturnValue("github");
|
|
200
|
-
|
|
201
|
-
const provider = await resolver.resolveProvider(
|
|
202
|
-
toolProtection,
|
|
203
|
-
"test-project"
|
|
204
|
-
);
|
|
205
|
-
|
|
206
|
-
// Should use configured provider (Priority 3)
|
|
207
|
-
expect(provider).toBe("github");
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
it("should verify gmail → google mapping works", async () => {
|
|
211
|
-
const toolProtection: ToolProtection = {
|
|
212
|
-
requiresDelegation: true,
|
|
213
|
-
requiredScopes: ["gmail:read"],
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
(mockRegistry.getProviderNames as any).mockReturnValue(["google"]);
|
|
217
|
-
(mockRegistry.hasProvider as any).mockImplementation((name: string) => {
|
|
218
|
-
return name === "google";
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
const provider = await resolver.resolveProvider(
|
|
222
|
-
toolProtection,
|
|
223
|
-
"test-project"
|
|
224
|
-
);
|
|
225
|
-
|
|
226
|
-
expect(provider).toBe("google");
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
it("should verify calendar → google mapping works", async () => {
|
|
230
|
-
const toolProtection: ToolProtection = {
|
|
231
|
-
requiresDelegation: true,
|
|
232
|
-
requiredScopes: ["calendar:read"],
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
(mockRegistry.getProviderNames as any).mockReturnValue(["google"]);
|
|
236
|
-
(mockRegistry.hasProvider as any).mockImplementation((name: string) => {
|
|
237
|
-
return name === "google";
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
const provider = await resolver.resolveProvider(
|
|
241
|
-
toolProtection,
|
|
242
|
-
"test-project"
|
|
243
|
-
);
|
|
244
|
-
|
|
245
|
-
expect(provider).toBe("google");
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
it("should verify outlook → microsoft mapping works", async () => {
|
|
249
|
-
const toolProtection: ToolProtection = {
|
|
250
|
-
requiresDelegation: true,
|
|
251
|
-
requiredScopes: ["outlook:read"],
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
(mockRegistry.getProviderNames as any).mockReturnValue(["microsoft"]);
|
|
255
|
-
(mockRegistry.hasProvider as any).mockImplementation((name: string) => {
|
|
256
|
-
return name === "microsoft";
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
const provider = await resolver.resolveProvider(
|
|
260
|
-
toolProtection,
|
|
261
|
-
"test-project"
|
|
262
|
-
);
|
|
263
|
-
|
|
264
|
-
expect(provider).toBe("microsoft");
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
it("should handle scopes without colons", async () => {
|
|
268
|
-
const toolProtection: ToolProtection = {
|
|
269
|
-
requiresDelegation: true,
|
|
270
|
-
requiredScopes: ["read", "write"], // No colons
|
|
271
|
-
};
|
|
272
|
-
|
|
273
|
-
// Should fall through to Priority 3 (configuredProvider)
|
|
274
|
-
(mockRegistry.hasProvider as any).mockImplementation((name: string) => name === "github");
|
|
275
|
-
(mockRegistry.getConfiguredProvider as any).mockReturnValue("github");
|
|
276
|
-
|
|
277
|
-
const provider = await resolver.resolveProvider(
|
|
278
|
-
toolProtection,
|
|
279
|
-
"test-project"
|
|
280
|
-
);
|
|
281
|
-
|
|
282
|
-
// Should use configured provider (Priority 3)
|
|
283
|
-
expect(provider).toBe("github");
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
it("should handle inferred provider not in registry", async () => {
|
|
287
|
-
const toolProtection: ToolProtection = {
|
|
288
|
-
requiresDelegation: true,
|
|
289
|
-
requiredScopes: ["github:repo:read"],
|
|
290
|
-
};
|
|
291
|
-
|
|
292
|
-
// Inferred provider (github) exists but not in registry
|
|
293
|
-
// configuredProvider is google
|
|
294
|
-
(mockRegistry.getProviderNames as any).mockReturnValue(["google"]);
|
|
295
|
-
(mockRegistry.hasProvider as any).mockImplementation((name: string) => name === "google");
|
|
296
|
-
(mockRegistry.getConfiguredProvider as any).mockReturnValue("google");
|
|
297
|
-
|
|
298
|
-
const provider = await resolver.resolveProvider(
|
|
299
|
-
toolProtection,
|
|
300
|
-
"test-project"
|
|
301
|
-
);
|
|
302
|
-
|
|
303
|
-
// Should use configured provider (Priority 3)
|
|
304
|
-
expect(provider).toBe("google");
|
|
305
|
-
});
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
describe("Fallback behavior (Priority 3 - configuredProvider)", () => {
|
|
309
|
-
it("should log warning when using configuredProvider fallback", async () => {
|
|
310
|
-
const toolProtection: ToolProtection = {
|
|
311
|
-
requiresDelegation: true,
|
|
312
|
-
requiredScopes: ["custom:scope"],
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
(mockRegistry.hasProvider as any).mockImplementation((name: string) => name === "github");
|
|
316
|
-
(mockRegistry.getConfiguredProvider as any).mockReturnValue("github");
|
|
317
|
-
|
|
318
|
-
const consoleSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
319
|
-
|
|
320
|
-
await resolver.resolveProvider(toolProtection, "test-project");
|
|
321
|
-
|
|
322
|
-
expect(consoleSpy).toHaveBeenCalledWith(
|
|
323
|
-
expect.stringContaining("project-configured provider")
|
|
324
|
-
);
|
|
325
|
-
expect(consoleSpy).toHaveBeenCalledWith(
|
|
326
|
-
expect.stringContaining("github")
|
|
327
|
-
);
|
|
328
|
-
|
|
329
|
-
consoleSpy.mockRestore();
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
it("should use configuredProvider when oauthProvider not specified", async () => {
|
|
333
|
-
const toolProtection: ToolProtection = {
|
|
334
|
-
requiresDelegation: true,
|
|
335
|
-
requiredScopes: ["custom:scope"],
|
|
336
|
-
};
|
|
337
|
-
|
|
338
|
-
// Multiple providers available, but configuredProvider is google
|
|
339
|
-
(mockRegistry.hasProvider as any).mockImplementation((name: string) =>
|
|
340
|
-
name === "github" || name === "google"
|
|
341
|
-
);
|
|
342
|
-
(mockRegistry.getConfiguredProvider as any).mockReturnValue("google");
|
|
343
|
-
|
|
344
|
-
const provider = await resolver.resolveProvider(
|
|
345
|
-
toolProtection,
|
|
346
|
-
"test-project"
|
|
347
|
-
);
|
|
348
|
-
|
|
349
|
-
// Should use configuredProvider, not first alphabetically
|
|
350
|
-
expect(provider).toBe("google");
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
it("should NOT fall back to first provider alphabetically", async () => {
|
|
354
|
-
const toolProtection: ToolProtection = {
|
|
355
|
-
requiresDelegation: true,
|
|
356
|
-
requiredScopes: ["custom:scope"],
|
|
357
|
-
};
|
|
358
|
-
|
|
359
|
-
// Multiple providers in registry, but NO configuredProvider
|
|
360
|
-
(mockRegistry.hasProvider as any).mockReturnValue(false);
|
|
361
|
-
(mockRegistry.getConfiguredProvider as any).mockReturnValue(null);
|
|
362
|
-
(mockRegistry.getAllProviders as any).mockReturnValue([
|
|
363
|
-
{ clientId: "github_client_id" },
|
|
364
|
-
{ clientId: "google_client_id" },
|
|
365
|
-
]);
|
|
366
|
-
(mockRegistry.getProviderNames as any).mockReturnValue(["github", "google"]);
|
|
367
|
-
|
|
368
|
-
// Should throw error, NOT pick first provider
|
|
369
|
-
await expect(
|
|
370
|
-
resolver.resolveProvider(toolProtection, "test-project")
|
|
371
|
-
).rejects.toThrow(/no provider is configured/);
|
|
372
|
-
});
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
describe("Error scenarios (Priority 4)", () => {
|
|
376
|
-
it("should throw error if no provider is configured", async () => {
|
|
377
|
-
const toolProtection: ToolProtection = {
|
|
378
|
-
requiresDelegation: true,
|
|
379
|
-
requiredScopes: [],
|
|
380
|
-
};
|
|
381
|
-
|
|
382
|
-
(mockRegistry.hasProvider as any).mockReturnValue(false);
|
|
383
|
-
(mockRegistry.getConfiguredProvider as any).mockReturnValue(null);
|
|
384
|
-
|
|
385
|
-
await expect(
|
|
386
|
-
resolver.resolveProvider(toolProtection, "test-project")
|
|
387
|
-
).rejects.toThrow(/no provider is configured/);
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
it("should include project ID in error message", async () => {
|
|
391
|
-
const toolProtection: ToolProtection = {
|
|
392
|
-
requiresDelegation: true,
|
|
393
|
-
requiredScopes: [],
|
|
394
|
-
};
|
|
395
|
-
|
|
396
|
-
(mockRegistry.hasProvider as any).mockReturnValue(false);
|
|
397
|
-
(mockRegistry.getConfiguredProvider as any).mockReturnValue(null);
|
|
398
|
-
|
|
399
|
-
try {
|
|
400
|
-
await resolver.resolveProvider(toolProtection, "test-project-123");
|
|
401
|
-
} catch (error) {
|
|
402
|
-
expect((error as Error).message).toContain("test-project-123");
|
|
403
|
-
}
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
it("should provide helpful error message with resolution steps", async () => {
|
|
407
|
-
const toolProtection: ToolProtection = {
|
|
408
|
-
requiresDelegation: true,
|
|
409
|
-
requiredScopes: [],
|
|
410
|
-
};
|
|
411
|
-
|
|
412
|
-
(mockRegistry.hasProvider as any).mockReturnValue(false);
|
|
413
|
-
(mockRegistry.getConfiguredProvider as any).mockReturnValue(null);
|
|
414
|
-
|
|
415
|
-
try {
|
|
416
|
-
await resolver.resolveProvider(toolProtection, "test-project");
|
|
417
|
-
} catch (error) {
|
|
418
|
-
const message = (error as Error).message;
|
|
419
|
-
expect(message).toContain("AgentShield dashboard");
|
|
420
|
-
expect(message).toContain("Configure");
|
|
421
|
-
}
|
|
422
|
-
});
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
describe("Registry load failures", () => {
|
|
426
|
-
it("should propagate registry load errors", async () => {
|
|
427
|
-
const toolProtection: ToolProtection = {
|
|
428
|
-
requiresDelegation: true,
|
|
429
|
-
requiredScopes: [],
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
(mockRegistry.hasProvider as any).mockReturnValue(false);
|
|
433
|
-
(mockRegistry.loadFromAgentShield as any).mockRejectedValueOnce(
|
|
434
|
-
new Error("Network error")
|
|
435
|
-
);
|
|
436
|
-
|
|
437
|
-
await expect(
|
|
438
|
-
resolver.resolveProvider(toolProtection, "test-project")
|
|
439
|
-
).rejects.toThrow("Network error");
|
|
440
|
-
});
|
|
441
|
-
});
|
|
442
|
-
|
|
443
|
-
describe("Provider name case sensitivity", () => {
|
|
444
|
-
it("should handle provider names case-insensitively in inference", async () => {
|
|
445
|
-
const toolProtection: ToolProtection = {
|
|
446
|
-
requiresDelegation: true,
|
|
447
|
-
requiredScopes: ["GITHUB:repo:read"], // Uppercase prefix
|
|
448
|
-
};
|
|
449
|
-
|
|
450
|
-
(mockRegistry.getProviderNames as any).mockReturnValue(["github"]);
|
|
451
|
-
(mockRegistry.hasProvider as any).mockImplementation((name: string) => {
|
|
452
|
-
return name.toLowerCase() === "github";
|
|
453
|
-
});
|
|
454
|
-
|
|
455
|
-
const provider = await resolver.resolveProvider(
|
|
456
|
-
toolProtection,
|
|
457
|
-
"test-project"
|
|
458
|
-
);
|
|
459
|
-
|
|
460
|
-
expect(provider).toBe("github");
|
|
461
|
-
});
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
describe("Multiple scopes with same provider", () => {
|
|
465
|
-
it("should handle multiple scopes from same provider", async () => {
|
|
466
|
-
const toolProtection: ToolProtection = {
|
|
467
|
-
requiresDelegation: true,
|
|
468
|
-
requiredScopes: [
|
|
469
|
-
"github:repo:read",
|
|
470
|
-
"github:repo:write",
|
|
471
|
-
"github:user:read",
|
|
472
|
-
],
|
|
473
|
-
};
|
|
474
|
-
|
|
475
|
-
(mockRegistry.getProviderNames as any).mockReturnValue(["github"]);
|
|
476
|
-
(mockRegistry.hasProvider as any).mockReturnValue(true);
|
|
477
|
-
|
|
478
|
-
const provider = await resolver.resolveProvider(
|
|
479
|
-
toolProtection,
|
|
480
|
-
"test-project"
|
|
481
|
-
);
|
|
482
|
-
|
|
483
|
-
expect(provider).toBe("github");
|
|
484
|
-
});
|
|
485
|
-
});
|
|
486
|
-
|
|
487
|
-
describe("configuredProvider behavior (Priority 3)", () => {
|
|
488
|
-
it("should use configuredProvider when tool has no oauthProvider", async () => {
|
|
489
|
-
const toolProtection: ToolProtection = {
|
|
490
|
-
requiresDelegation: true,
|
|
491
|
-
requiredScopes: ["greet:execute"], // No scope inference match
|
|
492
|
-
};
|
|
493
|
-
|
|
494
|
-
// configuredProvider is github
|
|
495
|
-
(mockRegistry.hasProvider as any).mockImplementation((name: string) => name === "github");
|
|
496
|
-
(mockRegistry.getConfiguredProvider as any).mockReturnValue("github");
|
|
497
|
-
|
|
498
|
-
const provider = await resolver.resolveProvider(
|
|
499
|
-
toolProtection,
|
|
500
|
-
"test-project"
|
|
501
|
-
);
|
|
502
|
-
|
|
503
|
-
expect(provider).toBe("github");
|
|
504
|
-
expect(mockRegistry.getConfiguredProvider).toHaveBeenCalled();
|
|
505
|
-
});
|
|
506
|
-
|
|
507
|
-
it("should throw when configuredProvider is null and tool needs OAuth", async () => {
|
|
508
|
-
const toolProtection: ToolProtection = {
|
|
509
|
-
requiresDelegation: true,
|
|
510
|
-
requiredScopes: ["greet:execute"],
|
|
511
|
-
};
|
|
512
|
-
|
|
513
|
-
// No configuredProvider set
|
|
514
|
-
(mockRegistry.hasProvider as any).mockReturnValue(false);
|
|
515
|
-
(mockRegistry.getConfiguredProvider as any).mockReturnValue(null);
|
|
516
|
-
|
|
517
|
-
await expect(
|
|
518
|
-
resolver.resolveProvider(toolProtection, "test-project")
|
|
519
|
-
).rejects.toThrow(/no provider is configured/);
|
|
520
|
-
});
|
|
521
|
-
|
|
522
|
-
it("should NOT use unconfigured providers as fallback", async () => {
|
|
523
|
-
const toolProtection: ToolProtection = {
|
|
524
|
-
requiresDelegation: true,
|
|
525
|
-
requiredScopes: ["greet:execute"],
|
|
526
|
-
};
|
|
527
|
-
|
|
528
|
-
// Registry has providers but configuredProvider is null
|
|
529
|
-
// This simulates AgentShield returning all providers but none configured
|
|
530
|
-
(mockRegistry.hasProvider as any).mockReturnValue(false);
|
|
531
|
-
(mockRegistry.getConfiguredProvider as any).mockReturnValue(null);
|
|
532
|
-
(mockRegistry.getAllProviders as any).mockReturnValue([
|
|
533
|
-
{ clientId: "github_client_id" },
|
|
534
|
-
{ clientId: "google_client_id" },
|
|
535
|
-
{ clientId: "microsoft_client_id" },
|
|
536
|
-
]);
|
|
537
|
-
(mockRegistry.getProviderNames as any).mockReturnValue(["github", "google", "microsoft"]);
|
|
538
|
-
|
|
539
|
-
// Should NOT pick "github" alphabetically - should throw
|
|
540
|
-
await expect(
|
|
541
|
-
resolver.resolveProvider(toolProtection, "test-project")
|
|
542
|
-
).rejects.toThrow(/no provider is configured/);
|
|
543
|
-
});
|
|
544
|
-
|
|
545
|
-
it("should prefer tool-specific oauthProvider over configuredProvider", async () => {
|
|
546
|
-
const toolProtection: ToolProtection = {
|
|
547
|
-
requiresDelegation: true,
|
|
548
|
-
requiredScopes: [],
|
|
549
|
-
oauthProvider: "google", // Tool specifies google
|
|
550
|
-
};
|
|
551
|
-
|
|
552
|
-
// configuredProvider is github, but tool wants google
|
|
553
|
-
(mockRegistry.hasProvider as any).mockImplementation((name: string) =>
|
|
554
|
-
name === "github" || name === "google"
|
|
555
|
-
);
|
|
556
|
-
(mockRegistry.getConfiguredProvider as any).mockReturnValue("github");
|
|
557
|
-
(mockRegistry.getProviderNames as any).mockReturnValue(["github", "google"]);
|
|
558
|
-
|
|
559
|
-
const provider = await resolver.resolveProvider(
|
|
560
|
-
toolProtection,
|
|
561
|
-
"test-project"
|
|
562
|
-
);
|
|
563
|
-
|
|
564
|
-
// Priority 1 (tool-specific) should win over Priority 3 (configuredProvider)
|
|
565
|
-
expect(provider).toBe("google");
|
|
566
|
-
});
|
|
567
|
-
|
|
568
|
-
it("should prefer scope-inferred provider over configuredProvider", async () => {
|
|
569
|
-
const toolProtection: ToolProtection = {
|
|
570
|
-
requiresDelegation: true,
|
|
571
|
-
requiredScopes: ["google:calendar:read"], // Infers google
|
|
572
|
-
};
|
|
573
|
-
|
|
574
|
-
// configuredProvider is github, but scopes infer google
|
|
575
|
-
(mockRegistry.hasProvider as any).mockImplementation((name: string) =>
|
|
576
|
-
name === "github" || name === "google"
|
|
577
|
-
);
|
|
578
|
-
(mockRegistry.getConfiguredProvider as any).mockReturnValue("github");
|
|
579
|
-
(mockRegistry.getProviderNames as any).mockReturnValue(["github", "google"]);
|
|
580
|
-
|
|
581
|
-
const provider = await resolver.resolveProvider(
|
|
582
|
-
toolProtection,
|
|
583
|
-
"test-project"
|
|
584
|
-
);
|
|
585
|
-
|
|
586
|
-
// Priority 2 (scope inference) should win over Priority 3 (configuredProvider)
|
|
587
|
-
expect(provider).toBe("google");
|
|
588
|
-
});
|
|
589
|
-
});
|
|
590
|
-
});
|
|
591
|
-
|