@vellumai/assistant 0.5.11 → 0.5.13
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/Dockerfile +42 -9
- package/docs/architecture/integrations.md +34 -32
- package/node_modules/@vellumai/ces-contracts/src/__tests__/grants.test.ts +7 -7
- package/node_modules/@vellumai/ces-contracts/src/handles.ts +5 -4
- package/node_modules/@vellumai/ces-contracts/src/index.ts +7 -0
- package/node_modules/@vellumai/ces-contracts/src/rpc.ts +5 -0
- package/node_modules/@vellumai/credential-storage/src/index.ts +1 -1
- package/openapi.yaml +87 -9
- package/package.json +1 -1
- package/src/__tests__/catalog-cache.test.ts +164 -0
- package/src/__tests__/catalog-search.test.ts +61 -0
- package/src/__tests__/cli-command-risk-guard.test.ts +181 -6
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +396 -0
- package/src/__tests__/conversation-error.test.ts +3 -2
- package/src/__tests__/credential-security-invariants.test.ts +9 -15
- package/src/__tests__/credential-vault-unit.test.ts +32 -34
- package/src/__tests__/credential-vault.test.ts +25 -33
- package/src/__tests__/credentials-cli.test.ts +3 -3
- package/src/__tests__/daemon-credential-client.test.ts +2 -2
- package/src/__tests__/first-greeting.test.ts +7 -0
- package/src/__tests__/host-bash-proxy.test.ts +79 -0
- package/src/__tests__/host-cu-proxy.test.ts +90 -0
- package/src/__tests__/host-file-proxy.test.ts +89 -0
- package/src/__tests__/integration-status.test.ts +5 -5
- package/src/__tests__/list-messages-attachments.test.ts +171 -0
- package/src/__tests__/mcp-abort-signal.test.ts +205 -0
- package/src/__tests__/messaging-send-tool.test.ts +5 -5
- package/src/__tests__/navigate-settings-tab.test.ts +6 -2
- package/src/__tests__/notification-telegram-adapter.test.ts +125 -0
- package/src/__tests__/oauth-cli.test.ts +126 -119
- package/src/__tests__/oauth-provider-profiles.test.ts +55 -20
- package/src/__tests__/oauth-scope-policy.test.ts +4 -6
- package/src/__tests__/onboarding-template-contract.test.ts +2 -2
- package/src/__tests__/platform.test.ts +3 -168
- package/src/__tests__/secret-routes-managed-proxy.test.ts +78 -0
- package/src/__tests__/secure-keys-managed-failover.test.ts +73 -0
- package/src/__tests__/skill-feature-flags.test.ts +8 -0
- package/src/__tests__/skill-secret-handling-guard.test.ts +212 -0
- package/src/__tests__/skills-uninstall.test.ts +2 -2
- package/src/__tests__/slack-messaging-token-resolution.test.ts +22 -24
- package/src/__tests__/slack-share-routes.test.ts +5 -5
- package/src/__tests__/system-prompt.test.ts +39 -0
- package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +1 -1
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +5 -4
- package/src/cli/AGENTS.md +47 -7
- package/src/cli/commands/browser-relay.ts +2 -17
- package/src/cli/commands/contacts.ts +6 -4
- package/src/cli/commands/conversations.ts +13 -1
- package/src/cli/commands/credential-execution.ts +16 -1
- package/src/cli/commands/credentials.ts +2 -8
- package/src/cli/commands/oauth/__tests__/connect.test.ts +29 -108
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +13 -87
- package/src/cli/commands/oauth/__tests__/mode.test.ts +22 -69
- package/src/cli/commands/oauth/__tests__/ping.test.ts +20 -79
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +574 -0
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +416 -0
- package/src/cli/commands/oauth/__tests__/status.test.ts +12 -40
- package/src/cli/commands/oauth/__tests__/token.test.ts +3 -50
- package/src/cli/commands/oauth/apps.ts +63 -44
- package/src/cli/commands/oauth/connect.ts +187 -155
- package/src/cli/commands/oauth/disconnect.ts +27 -75
- package/src/cli/commands/oauth/index.ts +36 -46
- package/src/cli/commands/oauth/mode.ts +22 -34
- package/src/cli/commands/oauth/ping.ts +19 -45
- package/src/cli/commands/oauth/providers.ts +569 -62
- package/src/cli/commands/oauth/request.ts +36 -48
- package/src/cli/commands/oauth/shared.ts +1 -19
- package/src/cli/commands/oauth/status.ts +14 -25
- package/src/cli/commands/oauth/token.ts +25 -34
- package/src/cli/commands/platform/__tests__/connect.test.ts +224 -0
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +237 -0
- package/src/cli/commands/platform/__tests__/status.test.ts +246 -0
- package/src/cli/commands/platform/connect.ts +104 -0
- package/src/cli/commands/platform/disconnect.ts +118 -0
- package/src/cli/commands/{platform.ts → platform/index.ts} +108 -38
- package/src/cli/commands/sequence.ts +5 -4
- package/src/cli/commands/shotgun.ts +16 -0
- package/src/cli/commands/skills.ts +173 -41
- package/src/cli/commands/usage.ts +5 -11
- package/src/cli/lib/daemon-credential-client.ts +22 -38
- package/src/cli/program.ts +1 -1
- package/src/config/assistant-feature-flags.ts +3 -7
- package/src/config/bundled-skills/contacts/tools/google-contacts.ts +1 -1
- package/src/config/bundled-skills/conversations/SKILL.md +20 -0
- package/src/config/bundled-skills/conversations/TOOLS.json +23 -0
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +66 -0
- package/src/config/bundled-skills/gmail/SKILL.md +13 -13
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +3 -3
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +2 -2
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +2 -2
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +1 -1
- package/src/config/bundled-skills/google-calendar/SKILL.md +10 -4
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +7 -7
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +5 -2
- package/src/config/bundled-skills/messaging/tools/shared.ts +5 -6
- package/src/config/bundled-skills/settings/TOOLS.json +5 -3
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +4 -2
- package/src/config/bundled-tool-registry.ts +5 -0
- package/src/config/feature-flag-registry.json +2 -2
- package/src/credential-execution/client.ts +15 -3
- package/src/daemon/conversation-agent-loop.ts +2 -0
- package/src/daemon/conversation-error.ts +36 -6
- package/src/daemon/conversation-messaging.ts +9 -0
- package/src/daemon/conversation-runtime-assembly.ts +33 -0
- package/src/daemon/conversation-surfaces.ts +120 -14
- package/src/daemon/conversation.ts +5 -0
- package/src/daemon/first-greeting.ts +6 -1
- package/src/daemon/handlers/skills.ts +148 -3
- package/src/daemon/host-bash-proxy.ts +16 -0
- package/src/daemon/host-cu-proxy.ts +16 -0
- package/src/daemon/host-file-proxy.ts +16 -0
- package/src/daemon/lifecycle.ts +56 -5
- package/src/daemon/message-types/conversations.ts +1 -0
- package/src/daemon/message-types/guardian-actions.ts +2 -0
- package/src/daemon/message-types/host-bash.ts +6 -1
- package/src/daemon/message-types/host-cu.ts +6 -1
- package/src/daemon/message-types/host-file.ts +6 -1
- package/src/daemon/message-types/integrations.ts +0 -1
- package/src/daemon/server.ts +29 -2
- package/src/hooks/cli.ts +74 -0
- package/src/inbound/platform-callback-registration.ts +7 -12
- package/src/index.ts +0 -12
- package/src/mcp/client.ts +6 -1
- package/src/mcp/manager.ts +2 -1
- package/src/memory/conversation-crud.ts +92 -3
- package/src/memory/conversation-key-store.ts +26 -0
- package/src/memory/conversation-queries.ts +6 -6
- package/src/memory/db-init.ts +16 -0
- package/src/memory/journal-memory.ts +8 -2
- package/src/memory/migrations/196-messages-conversation-created-at-index.ts +9 -0
- package/src/memory/migrations/196-strip-integration-prefix-from-provider-keys.ts +186 -0
- package/src/memory/migrations/197-oauth-providers-behavior-columns.ts +29 -0
- package/src/memory/migrations/198-drop-setup-skill-id-column.ts +11 -0
- package/src/memory/migrations/index.ts +4 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/schema/oauth.ts +11 -0
- package/src/messaging/provider.ts +13 -12
- package/src/messaging/providers/gmail/adapter.ts +44 -35
- package/src/messaging/providers/slack/adapter.ts +63 -33
- package/src/messaging/providers/telegram-bot/adapter.ts +6 -8
- package/src/messaging/providers/whatsapp/adapter.ts +6 -8
- package/src/notifications/adapters/telegram.ts +78 -2
- package/src/oauth/__tests__/identity-verifier.test.ts +464 -0
- package/src/oauth/byo-connection.test.ts +22 -24
- package/src/oauth/connect-orchestrator.ts +37 -76
- package/src/oauth/connect-types.ts +7 -65
- package/src/oauth/connection-resolver.test.ts +13 -13
- package/src/oauth/connection-resolver.ts +3 -4
- package/src/oauth/identity-verifier.ts +177 -0
- package/src/oauth/oauth-store.ts +228 -3
- package/src/oauth/platform-connection.test.ts +56 -6
- package/src/oauth/platform-connection.ts +8 -1
- package/src/oauth/seed-providers.ts +247 -34
- package/src/permissions/checker.ts +127 -1
- package/src/prompts/journal-context.ts +4 -1
- package/src/prompts/system-prompt.ts +54 -9
- package/src/prompts/templates/BOOTSTRAP.md +16 -5
- package/src/providers/anthropic/client.ts +2 -33
- package/src/runtime/guardian-action-service.ts +7 -2
- package/src/runtime/http-server.ts +12 -18
- package/src/runtime/http-types.ts +8 -1
- package/src/runtime/migrations/rebind-secrets-screen.ts +2 -2
- package/src/runtime/routes/conversation-management-routes.ts +31 -0
- package/src/runtime/routes/conversation-routes.ts +79 -4
- package/src/runtime/routes/guardian-action-routes.ts +15 -2
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -8
- package/src/runtime/routes/integrations/slack/share.ts +1 -1
- package/src/runtime/routes/oauth-apps.ts +2 -1
- package/src/runtime/routes/secret-routes.ts +45 -15
- package/src/runtime/routes/settings-routes.ts +12 -19
- package/src/runtime/routes/skills-routes.ts +45 -4
- package/src/schedule/integration-status.ts +2 -2
- package/src/security/ces-rpc-credential-backend.ts +19 -16
- package/src/security/oauth-completion-page.ts +153 -0
- package/src/security/oauth2.ts +3 -17
- package/src/security/secure-keys.ts +207 -7
- package/src/security/token-manager.ts +3 -6
- package/src/signals/bash.ts +6 -1
- package/src/skills/catalog-cache.ts +44 -0
- package/src/skills/catalog-search.ts +18 -0
- package/src/tools/browser/browser-manager.ts +2 -2
- package/src/tools/credentials/post-connect-hooks.ts +1 -1
- package/src/tools/credentials/vault.ts +34 -45
- package/src/tools/host-terminal/host-shell.ts +16 -3
- package/src/tools/mcp/mcp-tool-factory.ts +2 -1
- package/src/tools/skills/sandbox-runner.ts +16 -3
- package/src/tools/terminal/shell.ts +16 -3
- package/src/util/logger.ts +11 -1
- package/src/util/platform.ts +1 -91
- package/src/util/sentry-log-stream.ts +51 -0
- package/src/watcher/providers/github.ts +2 -2
- package/src/watcher/providers/gmail.ts +1 -1
- package/src/watcher/providers/google-calendar.ts +1 -1
- package/src/watcher/providers/linear.ts +2 -2
- package/src/workspace/migrations/011-backfill-installation-id.ts +5 -3
- package/src/workspace/migrations/020-rename-oauth-skill-dirs.ts +119 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/cli/commands/oauth/connections.ts +0 -255
- package/src/oauth/provider-behaviors.ts +0 -634
|
@@ -27,10 +27,6 @@ let mockOrchestrateOAuthConnect: (
|
|
|
27
27
|
grantedScopes: [],
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
let mockGetProviderBehavior: (
|
|
31
|
-
key: string,
|
|
32
|
-
) => Record<string, unknown> | undefined = () => undefined;
|
|
33
|
-
|
|
34
30
|
let mockGetSecureKeyViaDaemon: (
|
|
35
31
|
account: string,
|
|
36
32
|
) => Promise<string | undefined> = async () => undefined;
|
|
@@ -80,20 +76,6 @@ mock.module("../../../../oauth/oauth-store.js", () => ({
|
|
|
80
76
|
deleteConnection: () => false,
|
|
81
77
|
}));
|
|
82
78
|
|
|
83
|
-
mock.module("../../../../oauth/provider-behaviors.js", () => ({
|
|
84
|
-
resolveService: (service: string) => {
|
|
85
|
-
const aliases: Record<string, string> = {
|
|
86
|
-
gmail: "integration:google",
|
|
87
|
-
google: "integration:google",
|
|
88
|
-
slack: "integration:slack",
|
|
89
|
-
};
|
|
90
|
-
if (aliases[service]) return aliases[service];
|
|
91
|
-
if (!service.includes(":")) return `integration:${service}`;
|
|
92
|
-
return service;
|
|
93
|
-
},
|
|
94
|
-
getProviderBehavior: (key: string) => mockGetProviderBehavior(key),
|
|
95
|
-
}));
|
|
96
|
-
|
|
97
79
|
mock.module("../../../../oauth/connect-orchestrator.js", () => ({
|
|
98
80
|
orchestrateOAuthConnect: (opts: Record<string, unknown>) =>
|
|
99
81
|
mockOrchestrateOAuthConnect(opts),
|
|
@@ -134,16 +116,6 @@ mock.module("../../../lib/daemon-credential-client.js", () => ({
|
|
|
134
116
|
|
|
135
117
|
// Mock shared.js helpers to control managed vs BYO mode routing
|
|
136
118
|
mock.module("../shared.js", () => ({
|
|
137
|
-
resolveService: (service: string) => {
|
|
138
|
-
const aliases: Record<string, string> = {
|
|
139
|
-
gmail: "integration:google",
|
|
140
|
-
google: "integration:google",
|
|
141
|
-
slack: "integration:slack",
|
|
142
|
-
};
|
|
143
|
-
if (aliases[service]) return aliases[service];
|
|
144
|
-
if (!service.includes(":")) return `integration:${service}`;
|
|
145
|
-
return service;
|
|
146
|
-
},
|
|
147
119
|
isManagedMode: (key: string) => mockIsManagedMode(key),
|
|
148
120
|
requirePlatformClient: async (_cmd: Command) => {
|
|
149
121
|
if (
|
|
@@ -193,10 +165,6 @@ mock.module("../shared.js", () => ({
|
|
|
193
165
|
if (!result.ok) return null;
|
|
194
166
|
return result.body as Array<Record<string, unknown>>;
|
|
195
167
|
},
|
|
196
|
-
toBareProvider: (provider: string): string =>
|
|
197
|
-
provider.startsWith("integration:")
|
|
198
|
-
? provider.slice("integration:".length)
|
|
199
|
-
: provider,
|
|
200
168
|
}));
|
|
201
169
|
|
|
202
170
|
// ---------------------------------------------------------------------------
|
|
@@ -262,7 +230,6 @@ describe("assistant oauth connect", () => {
|
|
|
262
230
|
deferred: false,
|
|
263
231
|
grantedScopes: [],
|
|
264
232
|
});
|
|
265
|
-
mockGetProviderBehavior = () => undefined;
|
|
266
233
|
mockGetSecureKeyViaDaemon = async () => undefined;
|
|
267
234
|
mockOpenInBrowserCalls = [];
|
|
268
235
|
mockPlatformClientResult = null;
|
|
@@ -291,50 +258,13 @@ describe("assistant oauth connect", () => {
|
|
|
291
258
|
expect(parsed.error).toContain("providers list");
|
|
292
259
|
});
|
|
293
260
|
|
|
294
|
-
// -------------------------------------------------------------------------
|
|
295
|
-
// Provider alias resolution
|
|
296
|
-
// -------------------------------------------------------------------------
|
|
297
|
-
|
|
298
|
-
test("provider alias 'gmail' resolves to integration:google", async () => {
|
|
299
|
-
let capturedProviderKey: string | undefined;
|
|
300
|
-
|
|
301
|
-
mockGetProvider = (key: string) => {
|
|
302
|
-
capturedProviderKey = key;
|
|
303
|
-
return {
|
|
304
|
-
providerKey: key,
|
|
305
|
-
authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
306
|
-
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
307
|
-
managedServiceConfigKey: null,
|
|
308
|
-
};
|
|
309
|
-
};
|
|
310
|
-
|
|
311
|
-
mockGetMostRecentAppByProvider = () => ({
|
|
312
|
-
id: "app-1",
|
|
313
|
-
clientId: "test-id",
|
|
314
|
-
clientSecretCredentialPath: "oauth_app/app-1/client_secret",
|
|
315
|
-
providerKey: "integration:google",
|
|
316
|
-
createdAt: 0,
|
|
317
|
-
updatedAt: 0,
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
mockOrchestrateOAuthConnect = async () => ({
|
|
321
|
-
success: true,
|
|
322
|
-
deferred: false,
|
|
323
|
-
grantedScopes: ["read"],
|
|
324
|
-
accountInfo: "user@example.com",
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
await runCommand(["connect", "gmail", "--json"]);
|
|
328
|
-
expect(capturedProviderKey).toBe("integration:google");
|
|
329
|
-
});
|
|
330
|
-
|
|
331
261
|
// -------------------------------------------------------------------------
|
|
332
262
|
// Managed mode: prints connect URL without --open-browser
|
|
333
263
|
// -------------------------------------------------------------------------
|
|
334
264
|
|
|
335
265
|
test("managed mode: prints connect URL without --open-browser", async () => {
|
|
336
266
|
mockGetProvider = () => ({
|
|
337
|
-
providerKey: "
|
|
267
|
+
providerKey: "google",
|
|
338
268
|
authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
339
269
|
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
340
270
|
managedServiceConfigKey: "google-oauth",
|
|
@@ -361,7 +291,7 @@ describe("assistant oauth connect", () => {
|
|
|
361
291
|
expect(parsed.connectUrl).toBe(
|
|
362
292
|
"https://platform.example.com/oauth/connect",
|
|
363
293
|
);
|
|
364
|
-
expect(parsed.provider).toBe("
|
|
294
|
+
expect(parsed.provider).toBe("google");
|
|
365
295
|
});
|
|
366
296
|
|
|
367
297
|
// -------------------------------------------------------------------------
|
|
@@ -370,7 +300,7 @@ describe("assistant oauth connect", () => {
|
|
|
370
300
|
|
|
371
301
|
test("managed mode with --open-browser: opens browser and polls for new connection", async () => {
|
|
372
302
|
mockGetProvider = () => ({
|
|
373
|
-
providerKey: "
|
|
303
|
+
providerKey: "google",
|
|
374
304
|
authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
375
305
|
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
376
306
|
managedServiceConfigKey: "google-oauth",
|
|
@@ -427,7 +357,7 @@ describe("assistant oauth connect", () => {
|
|
|
427
357
|
|
|
428
358
|
test("BYO mode: prints auth URL without --open-browser", async () => {
|
|
429
359
|
mockGetProvider = () => ({
|
|
430
|
-
providerKey: "
|
|
360
|
+
providerKey: "google",
|
|
431
361
|
authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
432
362
|
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
433
363
|
managedServiceConfigKey: null,
|
|
@@ -438,7 +368,7 @@ describe("assistant oauth connect", () => {
|
|
|
438
368
|
id: "app-1",
|
|
439
369
|
clientId: "byo-client-id",
|
|
440
370
|
clientSecretCredentialPath: "oauth_app/app-1/client_secret",
|
|
441
|
-
providerKey: "
|
|
371
|
+
providerKey: "google",
|
|
442
372
|
createdAt: 0,
|
|
443
373
|
updatedAt: 0,
|
|
444
374
|
});
|
|
@@ -448,12 +378,12 @@ describe("assistant oauth connect", () => {
|
|
|
448
378
|
deferred: true,
|
|
449
379
|
authUrl: "https://accounts.google.com/o/oauth2/v2/auth?state=abc",
|
|
450
380
|
state: "abc",
|
|
451
|
-
service: "
|
|
381
|
+
service: "google",
|
|
452
382
|
});
|
|
453
383
|
|
|
454
384
|
const { exitCode, stdout } = await runCommand([
|
|
455
385
|
"connect",
|
|
456
|
-
"
|
|
386
|
+
"google",
|
|
457
387
|
"--json",
|
|
458
388
|
]);
|
|
459
389
|
expect(exitCode).toBe(0);
|
|
@@ -463,7 +393,7 @@ describe("assistant oauth connect", () => {
|
|
|
463
393
|
expect(parsed.authUrl).toBe(
|
|
464
394
|
"https://accounts.google.com/o/oauth2/v2/auth?state=abc",
|
|
465
395
|
);
|
|
466
|
-
expect(parsed.service).toBe("
|
|
396
|
+
expect(parsed.service).toBe("google");
|
|
467
397
|
});
|
|
468
398
|
|
|
469
399
|
// -------------------------------------------------------------------------
|
|
@@ -472,7 +402,7 @@ describe("assistant oauth connect", () => {
|
|
|
472
402
|
|
|
473
403
|
test("BYO mode with --open-browser calls orchestrator with isInteractive: true", async () => {
|
|
474
404
|
mockGetProvider = () => ({
|
|
475
|
-
providerKey: "
|
|
405
|
+
providerKey: "google",
|
|
476
406
|
authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
477
407
|
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
478
408
|
managedServiceConfigKey: null,
|
|
@@ -483,7 +413,7 @@ describe("assistant oauth connect", () => {
|
|
|
483
413
|
id: "app-1",
|
|
484
414
|
clientId: "test-id",
|
|
485
415
|
clientSecretCredentialPath: "oauth_app/app-1/client_secret",
|
|
486
|
-
providerKey: "
|
|
416
|
+
providerKey: "google",
|
|
487
417
|
createdAt: 0,
|
|
488
418
|
updatedAt: 0,
|
|
489
419
|
});
|
|
@@ -501,7 +431,7 @@ describe("assistant oauth connect", () => {
|
|
|
501
431
|
|
|
502
432
|
const { exitCode, stdout } = await runCommand([
|
|
503
433
|
"connect",
|
|
504
|
-
"
|
|
434
|
+
"google",
|
|
505
435
|
"--client-id",
|
|
506
436
|
"test-id",
|
|
507
437
|
"--open-browser",
|
|
@@ -525,7 +455,7 @@ describe("assistant oauth connect", () => {
|
|
|
525
455
|
|
|
526
456
|
test("BYO mode: missing app with --client-id returns error with hint", async () => {
|
|
527
457
|
mockGetProvider = () => ({
|
|
528
|
-
providerKey: "
|
|
458
|
+
providerKey: "google",
|
|
529
459
|
authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
530
460
|
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
531
461
|
managedServiceConfigKey: null,
|
|
@@ -535,7 +465,7 @@ describe("assistant oauth connect", () => {
|
|
|
535
465
|
|
|
536
466
|
const { exitCode, stdout } = await runCommand([
|
|
537
467
|
"connect",
|
|
538
|
-
"
|
|
468
|
+
"google",
|
|
539
469
|
"--client-id",
|
|
540
470
|
"nonexistent-id",
|
|
541
471
|
"--json",
|
|
@@ -553,7 +483,7 @@ describe("assistant oauth connect", () => {
|
|
|
553
483
|
|
|
554
484
|
test("BYO mode: no client_id found returns error with hint", async () => {
|
|
555
485
|
mockGetProvider = () => ({
|
|
556
|
-
providerKey: "
|
|
486
|
+
providerKey: "google",
|
|
557
487
|
authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
558
488
|
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
559
489
|
managedServiceConfigKey: null,
|
|
@@ -563,7 +493,7 @@ describe("assistant oauth connect", () => {
|
|
|
563
493
|
|
|
564
494
|
const { exitCode, stdout } = await runCommand([
|
|
565
495
|
"connect",
|
|
566
|
-
"
|
|
496
|
+
"google",
|
|
567
497
|
"--json",
|
|
568
498
|
]);
|
|
569
499
|
expect(exitCode).toBe(1);
|
|
@@ -579,7 +509,7 @@ describe("assistant oauth connect", () => {
|
|
|
579
509
|
|
|
580
510
|
test("--client-id is silently ignored in managed mode", async () => {
|
|
581
511
|
mockGetProvider = () => ({
|
|
582
|
-
providerKey: "
|
|
512
|
+
providerKey: "google",
|
|
583
513
|
authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
584
514
|
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
585
515
|
managedServiceConfigKey: "google-oauth",
|
|
@@ -616,7 +546,7 @@ describe("assistant oauth connect", () => {
|
|
|
616
546
|
|
|
617
547
|
test("JSON output for deferred case includes ok, deferred, authUrl, service", async () => {
|
|
618
548
|
mockGetProvider = () => ({
|
|
619
|
-
providerKey: "
|
|
549
|
+
providerKey: "slack",
|
|
620
550
|
authUrl: "https://slack.com/oauth/v2/authorize",
|
|
621
551
|
tokenUrl: "https://slack.com/api/oauth.v2.access",
|
|
622
552
|
managedServiceConfigKey: null,
|
|
@@ -627,7 +557,7 @@ describe("assistant oauth connect", () => {
|
|
|
627
557
|
id: "app-slack",
|
|
628
558
|
clientId: "slack-client-id",
|
|
629
559
|
clientSecretCredentialPath: "oauth_app/app-slack/client_secret",
|
|
630
|
-
providerKey: "
|
|
560
|
+
providerKey: "slack",
|
|
631
561
|
createdAt: 0,
|
|
632
562
|
updatedAt: 0,
|
|
633
563
|
});
|
|
@@ -637,7 +567,7 @@ describe("assistant oauth connect", () => {
|
|
|
637
567
|
deferred: true,
|
|
638
568
|
authUrl: "https://slack.com/oauth/v2/authorize?state=xyz",
|
|
639
569
|
state: "xyz",
|
|
640
|
-
service: "
|
|
570
|
+
service: "slack",
|
|
641
571
|
});
|
|
642
572
|
|
|
643
573
|
const { exitCode, stdout } = await runCommand([
|
|
@@ -650,7 +580,7 @@ describe("assistant oauth connect", () => {
|
|
|
650
580
|
expect(parsed).toHaveProperty("ok", true);
|
|
651
581
|
expect(parsed).toHaveProperty("deferred", true);
|
|
652
582
|
expect(parsed).toHaveProperty("authUrl");
|
|
653
|
-
expect(parsed).toHaveProperty("service", "
|
|
583
|
+
expect(parsed).toHaveProperty("service", "slack");
|
|
654
584
|
});
|
|
655
585
|
|
|
656
586
|
// -------------------------------------------------------------------------
|
|
@@ -659,7 +589,7 @@ describe("assistant oauth connect", () => {
|
|
|
659
589
|
|
|
660
590
|
test("JSON output for completed case includes ok, grantedScopes, accountInfo", async () => {
|
|
661
591
|
mockGetProvider = () => ({
|
|
662
|
-
providerKey: "
|
|
592
|
+
providerKey: "google",
|
|
663
593
|
authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
664
594
|
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
665
595
|
managedServiceConfigKey: null,
|
|
@@ -670,7 +600,7 @@ describe("assistant oauth connect", () => {
|
|
|
670
600
|
id: "app-1",
|
|
671
601
|
clientId: "completed-client-id",
|
|
672
602
|
clientSecretCredentialPath: "oauth_app/app-1/client_secret",
|
|
673
|
-
providerKey: "
|
|
603
|
+
providerKey: "google",
|
|
674
604
|
createdAt: 0,
|
|
675
605
|
updatedAt: 0,
|
|
676
606
|
});
|
|
@@ -703,11 +633,12 @@ describe("assistant oauth connect", () => {
|
|
|
703
633
|
|
|
704
634
|
test("BYO mode: client_secret required but missing returns error with hint", async () => {
|
|
705
635
|
mockGetProvider = () => ({
|
|
706
|
-
providerKey: "
|
|
636
|
+
providerKey: "google",
|
|
707
637
|
authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
708
638
|
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
709
639
|
tokenEndpointAuthMethod: "client_secret_post",
|
|
710
640
|
managedServiceConfigKey: null,
|
|
641
|
+
requiresClientSecret: 1,
|
|
711
642
|
});
|
|
712
643
|
mockIsManagedMode = () => false;
|
|
713
644
|
|
|
@@ -715,7 +646,7 @@ describe("assistant oauth connect", () => {
|
|
|
715
646
|
id: "app-1",
|
|
716
647
|
clientId: "test-id",
|
|
717
648
|
clientSecretCredentialPath: "oauth_app/app-1/client_secret",
|
|
718
|
-
providerKey: "
|
|
649
|
+
providerKey: "google",
|
|
719
650
|
createdAt: 0,
|
|
720
651
|
updatedAt: 0,
|
|
721
652
|
});
|
|
@@ -723,19 +654,9 @@ describe("assistant oauth connect", () => {
|
|
|
723
654
|
// No secret stored
|
|
724
655
|
mockGetSecureKeyViaDaemon = async () => undefined;
|
|
725
656
|
|
|
726
|
-
// Provider behavior says secret is required
|
|
727
|
-
mockGetProviderBehavior = () => ({
|
|
728
|
-
setup: {
|
|
729
|
-
requiresClientSecret: true,
|
|
730
|
-
displayName: "Google",
|
|
731
|
-
dashboardUrl: "https://console.cloud.google.com",
|
|
732
|
-
appType: "Desktop app",
|
|
733
|
-
},
|
|
734
|
-
});
|
|
735
|
-
|
|
736
657
|
const { exitCode, stdout } = await runCommand([
|
|
737
658
|
"connect",
|
|
738
|
-
"
|
|
659
|
+
"google",
|
|
739
660
|
"--json",
|
|
740
661
|
]);
|
|
741
662
|
expect(exitCode).toBe(1);
|
|
@@ -751,7 +672,7 @@ describe("assistant oauth connect", () => {
|
|
|
751
672
|
|
|
752
673
|
test("BYO mode: orchestrator error propagates correctly", async () => {
|
|
753
674
|
mockGetProvider = () => ({
|
|
754
|
-
providerKey: "
|
|
675
|
+
providerKey: "google",
|
|
755
676
|
authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
756
677
|
tokenUrl: "https://oauth2.googleapis.com/token",
|
|
757
678
|
managedServiceConfigKey: null,
|
|
@@ -762,7 +683,7 @@ describe("assistant oauth connect", () => {
|
|
|
762
683
|
id: "app-1",
|
|
763
684
|
clientId: "client-id",
|
|
764
685
|
clientSecretCredentialPath: "oauth_app/app-1/client_secret",
|
|
765
|
-
providerKey: "
|
|
686
|
+
providerKey: "google",
|
|
766
687
|
createdAt: 0,
|
|
767
688
|
updatedAt: 0,
|
|
768
689
|
});
|
|
@@ -774,7 +695,7 @@ describe("assistant oauth connect", () => {
|
|
|
774
695
|
|
|
775
696
|
const { exitCode, stdout } = await runCommand([
|
|
776
697
|
"connect",
|
|
777
|
-
"
|
|
698
|
+
"google",
|
|
778
699
|
"--json",
|
|
779
700
|
]);
|
|
780
701
|
expect(exitCode).toBe(1);
|
|
@@ -97,20 +97,6 @@ mock.module("../../../../oauth/oauth-store.js", () => ({
|
|
|
97
97
|
deleteConnection: () => false,
|
|
98
98
|
}));
|
|
99
99
|
|
|
100
|
-
mock.module("../../../../oauth/provider-behaviors.js", () => ({
|
|
101
|
-
resolveService: (service: string) => {
|
|
102
|
-
const aliases: Record<string, string> = {
|
|
103
|
-
gmail: "integration:google",
|
|
104
|
-
google: "integration:google",
|
|
105
|
-
slack: "integration:slack",
|
|
106
|
-
};
|
|
107
|
-
if (aliases[service]) return aliases[service];
|
|
108
|
-
if (!service.includes(":")) return `integration:${service}`;
|
|
109
|
-
return service;
|
|
110
|
-
},
|
|
111
|
-
getProviderBehavior: () => undefined,
|
|
112
|
-
}));
|
|
113
|
-
|
|
114
100
|
mock.module("../../../../oauth/connect-orchestrator.js", () => ({
|
|
115
101
|
orchestrateOAuthConnect: async () => ({
|
|
116
102
|
success: true,
|
|
@@ -165,16 +151,6 @@ mock.module("../../../lib/daemon-credential-client.js", () => ({
|
|
|
165
151
|
|
|
166
152
|
// Mock shared.js helpers to control managed vs BYO mode routing
|
|
167
153
|
mock.module("../shared.js", () => ({
|
|
168
|
-
resolveService: (service: string) => {
|
|
169
|
-
const aliases: Record<string, string> = {
|
|
170
|
-
gmail: "integration:google",
|
|
171
|
-
google: "integration:google",
|
|
172
|
-
slack: "integration:slack",
|
|
173
|
-
};
|
|
174
|
-
if (aliases[service]) return aliases[service];
|
|
175
|
-
if (!service.includes(":")) return `integration:${service}`;
|
|
176
|
-
return service;
|
|
177
|
-
},
|
|
178
154
|
isManagedMode: (key: string) => mockIsManagedMode(key),
|
|
179
155
|
requirePlatformClient: async (_cmd: Command) => {
|
|
180
156
|
if (
|
|
@@ -222,10 +198,6 @@ mock.module("../shared.js", () => ({
|
|
|
222
198
|
if (!result.ok) return null;
|
|
223
199
|
return result.body as Array<Record<string, unknown>>;
|
|
224
200
|
},
|
|
225
|
-
toBareProvider: (provider: string): string =>
|
|
226
|
-
provider.startsWith("integration:")
|
|
227
|
-
? provider.slice("integration:".length)
|
|
228
|
-
: provider,
|
|
229
201
|
}));
|
|
230
202
|
|
|
231
203
|
// ---------------------------------------------------------------------------
|
|
@@ -323,7 +295,7 @@ describe("assistant oauth disconnect", () => {
|
|
|
323
295
|
|
|
324
296
|
test("both --account and --connection-id returns error", async () => {
|
|
325
297
|
mockGetProvider = () => ({
|
|
326
|
-
providerKey: "
|
|
298
|
+
providerKey: "google",
|
|
327
299
|
managedServiceConfigKey: null,
|
|
328
300
|
});
|
|
329
301
|
|
|
@@ -351,7 +323,7 @@ describe("assistant oauth disconnect", () => {
|
|
|
351
323
|
describe("managed mode", () => {
|
|
352
324
|
beforeEach(() => {
|
|
353
325
|
mockGetProvider = () => ({
|
|
354
|
-
providerKey: "
|
|
326
|
+
providerKey: "google",
|
|
355
327
|
managedServiceConfigKey: "google-oauth",
|
|
356
328
|
});
|
|
357
329
|
mockIsManagedMode = () => true;
|
|
@@ -384,7 +356,7 @@ describe("assistant oauth disconnect", () => {
|
|
|
384
356
|
expect(exitCode).toBe(0);
|
|
385
357
|
const parsed = JSON.parse(stdout);
|
|
386
358
|
expect(parsed.ok).toBe(true);
|
|
387
|
-
expect(parsed.provider).toBe("
|
|
359
|
+
expect(parsed.provider).toBe("google");
|
|
388
360
|
expect(parsed.connectionId).toBe("conn-1");
|
|
389
361
|
expect(parsed.account).toBe("user@gmail.com");
|
|
390
362
|
});
|
|
@@ -512,7 +484,7 @@ describe("assistant oauth disconnect", () => {
|
|
|
512
484
|
describe("BYO mode", () => {
|
|
513
485
|
beforeEach(() => {
|
|
514
486
|
mockGetProvider = () => ({
|
|
515
|
-
providerKey: "
|
|
487
|
+
providerKey: "google",
|
|
516
488
|
managedServiceConfigKey: null,
|
|
517
489
|
});
|
|
518
490
|
mockIsManagedMode = () => false;
|
|
@@ -522,7 +494,7 @@ describe("assistant oauth disconnect", () => {
|
|
|
522
494
|
mockListActiveConnectionsByProvider = () => [
|
|
523
495
|
{
|
|
524
496
|
id: "conn-1",
|
|
525
|
-
providerKey: "
|
|
497
|
+
providerKey: "google",
|
|
526
498
|
accountInfo: "user@gmail.com",
|
|
527
499
|
status: "active",
|
|
528
500
|
},
|
|
@@ -536,68 +508,22 @@ describe("assistant oauth disconnect", () => {
|
|
|
536
508
|
expect(exitCode).toBe(0);
|
|
537
509
|
const parsed = JSON.parse(stdout);
|
|
538
510
|
expect(parsed.ok).toBe(true);
|
|
539
|
-
expect(parsed.provider).toBe("
|
|
511
|
+
expect(parsed.provider).toBe("google");
|
|
540
512
|
expect(parsed.connectionId).toBe("conn-1");
|
|
541
513
|
expect(parsed.account).toBe("user@gmail.com");
|
|
542
514
|
|
|
543
515
|
// Verify disconnectOAuthProvider was called
|
|
544
516
|
expect(mockDisconnectOAuthProviderCalls).toHaveLength(1);
|
|
545
|
-
expect(mockDisconnectOAuthProviderCalls[0].providerKey).toBe(
|
|
546
|
-
"integration:google",
|
|
547
|
-
);
|
|
517
|
+
expect(mockDisconnectOAuthProviderCalls[0].providerKey).toBe("google");
|
|
548
518
|
expect(mockDisconnectOAuthProviderCalls[0].connectionId).toBe("conn-1");
|
|
549
519
|
});
|
|
550
520
|
|
|
551
|
-
test("single connection also cleans up legacy credential keys", async () => {
|
|
552
|
-
mockListActiveConnectionsByProvider = () => [
|
|
553
|
-
{
|
|
554
|
-
id: "conn-1",
|
|
555
|
-
providerKey: "integration:google",
|
|
556
|
-
accountInfo: "user@gmail.com",
|
|
557
|
-
status: "active",
|
|
558
|
-
},
|
|
559
|
-
];
|
|
560
|
-
|
|
561
|
-
await runCommand(["disconnect", "google", "--json"]);
|
|
562
|
-
|
|
563
|
-
// Should have attempted to delete legacy keys
|
|
564
|
-
const expectedFields = [
|
|
565
|
-
"access_token",
|
|
566
|
-
"refresh_token",
|
|
567
|
-
"client_id",
|
|
568
|
-
"client_secret",
|
|
569
|
-
];
|
|
570
|
-
expect(mockDeleteSecureKeyViaDaemonCalls.length).toBe(
|
|
571
|
-
expectedFields.length,
|
|
572
|
-
);
|
|
573
|
-
for (const field of expectedFields) {
|
|
574
|
-
expect(
|
|
575
|
-
mockDeleteSecureKeyViaDaemonCalls.some(
|
|
576
|
-
(c) =>
|
|
577
|
-
c.type === "credential" &&
|
|
578
|
-
c.name === `integration:google:${field}`,
|
|
579
|
-
),
|
|
580
|
-
).toBe(true);
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
expect(mockDeleteCredentialMetadataCalls.length).toBe(
|
|
584
|
-
expectedFields.length,
|
|
585
|
-
);
|
|
586
|
-
for (const field of expectedFields) {
|
|
587
|
-
expect(
|
|
588
|
-
mockDeleteCredentialMetadataCalls.some(
|
|
589
|
-
(c) => c.service === "integration:google" && c.field === field,
|
|
590
|
-
),
|
|
591
|
-
).toBe(true);
|
|
592
|
-
}
|
|
593
|
-
});
|
|
594
|
-
|
|
595
521
|
test("--account matches accountInfo", async () => {
|
|
596
522
|
mockGetActiveConnection = (providerKey, opts) => {
|
|
597
523
|
if (opts?.account === "user@gmail.com") {
|
|
598
524
|
return {
|
|
599
525
|
id: "conn-1",
|
|
600
|
-
providerKey: "
|
|
526
|
+
providerKey: "google",
|
|
601
527
|
accountInfo: "user@gmail.com",
|
|
602
528
|
status: "active",
|
|
603
529
|
};
|
|
@@ -641,7 +567,7 @@ describe("assistant oauth disconnect", () => {
|
|
|
641
567
|
if (id === "conn-123") {
|
|
642
568
|
return {
|
|
643
569
|
id: "conn-123",
|
|
644
|
-
providerKey: "
|
|
570
|
+
providerKey: "google",
|
|
645
571
|
accountInfo: "user@gmail.com",
|
|
646
572
|
status: "active",
|
|
647
573
|
};
|
|
@@ -667,7 +593,7 @@ describe("assistant oauth disconnect", () => {
|
|
|
667
593
|
if (id === "conn-slack") {
|
|
668
594
|
return {
|
|
669
595
|
id: "conn-slack",
|
|
670
|
-
providerKey: "
|
|
596
|
+
providerKey: "slack",
|
|
671
597
|
accountInfo: null,
|
|
672
598
|
status: "active",
|
|
673
599
|
};
|
|
@@ -693,13 +619,13 @@ describe("assistant oauth disconnect", () => {
|
|
|
693
619
|
mockListActiveConnectionsByProvider = () => [
|
|
694
620
|
{
|
|
695
621
|
id: "conn-1",
|
|
696
|
-
providerKey: "
|
|
622
|
+
providerKey: "google",
|
|
697
623
|
accountInfo: "user1@gmail.com",
|
|
698
624
|
status: "active",
|
|
699
625
|
},
|
|
700
626
|
{
|
|
701
627
|
id: "conn-2",
|
|
702
|
-
providerKey: "
|
|
628
|
+
providerKey: "google",
|
|
703
629
|
accountInfo: "user2@gmail.com",
|
|
704
630
|
status: "active",
|
|
705
631
|
},
|
|
@@ -740,7 +666,7 @@ describe("assistant oauth disconnect", () => {
|
|
|
740
666
|
mockListActiveConnectionsByProvider = () => [
|
|
741
667
|
{
|
|
742
668
|
id: "conn-1",
|
|
743
|
-
providerKey: "
|
|
669
|
+
providerKey: "google",
|
|
744
670
|
accountInfo: null,
|
|
745
671
|
status: "active",
|
|
746
672
|
},
|