@agent-native/dispatch 0.8.20 → 0.8.24
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/components/messaging-setup-panel.d.ts.map +1 -1
- package/dist/components/messaging-setup-panel.js +2 -3
- package/dist/components/messaging-setup-panel.js.map +1 -1
- package/dist/routes/pages/chat.d.ts +21 -2
- package/dist/routes/pages/chat.d.ts.map +1 -1
- package/dist/routes/pages/chat.js +12 -3
- package/dist/routes/pages/chat.js.map +1 -1
- package/dist/routes/pages/overview.d.ts +21 -2
- package/dist/routes/pages/overview.d.ts.map +1 -1
- package/dist/routes/pages/overview.js +13 -4
- package/dist/routes/pages/overview.js.map +1 -1
- package/dist/server/lib/dispatch-integrations.d.ts.map +1 -1
- package/dist/server/lib/dispatch-integrations.js +27 -3
- package/dist/server/lib/dispatch-integrations.js.map +1 -1
- package/dist/server/lib/mcp-gateway.d.ts.map +1 -1
- package/dist/server/lib/mcp-gateway.js +0 -6
- package/dist/server/lib/mcp-gateway.js.map +1 -1
- package/dist/server/lib/thread-link-preview.d.ts +24 -0
- package/dist/server/lib/thread-link-preview.d.ts.map +1 -0
- package/dist/server/lib/thread-link-preview.js +176 -0
- package/dist/server/lib/thread-link-preview.js.map +1 -0
- package/dist/server/lib/vault-store.d.ts +1 -0
- package/dist/server/lib/vault-store.d.ts.map +1 -1
- package/dist/server/lib/vault-store.js +67 -20
- package/dist/server/lib/vault-store.js.map +1 -1
- package/package.json +1 -1
- package/src/components/messaging-setup-panel.tsx +2 -3
- package/src/routes/pages/chat.tsx +20 -3
- package/src/routes/pages/overview.tsx +21 -8
- package/src/server/lib/dispatch-integrations.spec.ts +69 -0
- package/src/server/lib/dispatch-integrations.ts +26 -3
- package/src/server/lib/mcp-gateway.ts +0 -6
- package/src/server/lib/thread-link-preview.spec.ts +129 -0
- package/src/server/lib/thread-link-preview.ts +187 -0
- package/src/server/lib/vault-store.spec.ts +25 -0
- package/src/server/lib/vault-store.ts +75 -20
- package/src/server/lib/workspace-resource-approval-lifecycle.spec.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vault-store.js","sourceRoot":"","sources":["../../../src/server/lib/vault-store.ts"],"names":[],"mappings":"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","sourcesContent":["import crypto from \"node:crypto\";\nimport { and, desc, eq, isNull, or } from \"drizzle-orm\";\nimport { discoverAgents } from \"@agent-native/core/server/agent-discovery\";\nimport {\n deleteAppSecret,\n listAppSecretsForScope,\n writeAppSecret,\n type SecretScope,\n} from \"@agent-native/core/secrets\";\nimport {\n getOrgSetting,\n getUserSetting,\n putOrgSetting,\n putUserSetting,\n} from \"@agent-native/core/settings\";\nimport { getDb, schema } from \"../../db/index.js\";\nimport {\n currentOwnerEmail,\n currentOrgId,\n recordAudit,\n} from \"./dispatch-store.js\";\n\nconst VAULT_ACCESS_SETTINGS_KEY = \"dispatch-vault-access-settings\";\nconst VAULT_SYNC_DESCRIPTION_PREFIX = \"Synced from Dispatch vault:\";\n\nexport type VaultAccessMode = \"all-apps\" | \"manual\";\n\nexport interface VaultAccessSettings {\n mode: VaultAccessMode;\n scope: \"org\" | \"user\";\n scopeId: string;\n}\n\n/**\n * Caller-supplied access context for vault operations.\n *\n * Every getSecret / updateSecret / deleteSecret / createGrant call must\n * pass the ctx of the *current request* so the row is scoped to that\n * caller's tenant. Looking up a vault secret by id alone is unsafe — UUIDs\n * are not authorization. A row matches the ctx if either the caller owns\n * it or it lives in the caller's active org.\n */\nexport interface VaultCtx {\n ownerEmail: string;\n orgId: string | null;\n}\n\n/**\n * Build a VaultCtx from the current request. Throws if the request is\n * unauthenticated — the previous behavior of falling back to \"local@localhost\"\n * leaked rows across tenants when a misconfigured environment skipped auth.\n */\nexport function requireVaultCtx(): VaultCtx {\n const ownerEmail = currentOwnerEmail();\n if (!ownerEmail) {\n throw new Error(\"Vault operation requires an authenticated user\");\n }\n return { ownerEmail, orgId: currentOrgId() };\n}\n\n/** WHERE clause that limits a vault row to the caller's ownership scope. */\nfunction ctxScope<T extends { ownerEmail: any; orgId: any }>(\n table: T,\n ctx: VaultCtx,\n) {\n if (!ctx.orgId) {\n return and(eq(table.ownerEmail, ctx.ownerEmail), isNull(table.orgId));\n }\n return or(eq(table.ownerEmail, ctx.ownerEmail), eq(table.orgId, ctx.orgId));\n}\n\n/** Build a ctx that scopes to a specific row's owner/org (used when a\n * request approver acts on behalf of the original requester so the\n * created secret lands in the request's org). */\nfunction ctxForRow(row: {\n ownerEmail: string;\n orgId: string | null;\n}): VaultCtx {\n return { ownerEmail: row.ownerEmail, orgId: row.orgId };\n}\n\nfunction ctxForSecretRow(row: VaultSecretRow, fallback: VaultCtx): VaultCtx {\n return row.ownerEmail ? ctxForRow(row) : fallback;\n}\n\nfunction id() {\n return crypto.randomUUID();\n}\n\nfunction now() {\n return Date.now();\n}\n\nfunction safeJson(value: unknown) {\n return JSON.stringify(value ?? null);\n}\n\nfunction scopedFilter<T extends { ownerEmail: any; orgId: any }>(table: T) {\n return ctxScope(table, requireVaultCtx());\n}\n\nfunction normalizeCredentialKey(value: string) {\n return value.trim();\n}\n\nfunction vaultAccessScope() {\n const orgId = currentOrgId();\n if (orgId) return { scope: \"org\" as const, scopeId: orgId };\n return { scope: \"user\" as const, scopeId: currentOwnerEmail() };\n}\n\nfunction parseVaultAccessMode(value: unknown): VaultAccessMode {\n return value === \"manual\" ? \"manual\" : \"all-apps\";\n}\n\nexport async function getVaultAccessSettings(): Promise<VaultAccessSettings> {\n const scope = vaultAccessScope();\n const raw =\n scope.scope === \"org\"\n ? await getOrgSetting(scope.scopeId, VAULT_ACCESS_SETTINGS_KEY)\n : await getUserSetting(scope.scopeId, VAULT_ACCESS_SETTINGS_KEY);\n return {\n ...scope,\n mode: parseVaultAccessMode(raw?.mode),\n };\n}\n\nexport async function setVaultAccessSettings(input: {\n mode: VaultAccessMode;\n}): Promise<VaultAccessSettings> {\n const scope = vaultAccessScope();\n const next = { mode: parseVaultAccessMode(input.mode) };\n if (scope.scope === \"org\") {\n await putOrgSetting(scope.scopeId, VAULT_ACCESS_SETTINGS_KEY, next);\n } else {\n await putUserSetting(scope.scopeId, VAULT_ACCESS_SETTINGS_KEY, next);\n }\n await recordAudit({\n action: \"vault.access-settings.updated\",\n targetType: \"vault-settings\",\n targetId: VAULT_ACCESS_SETTINGS_KEY,\n summary:\n next.mode === \"all-apps\"\n ? \"Set vault access to all workspace apps\"\n : \"Set vault access to manual per-app grants\",\n metadata: next,\n });\n return getVaultAccessSettings();\n}\n\n// ─── Vault Audit ──────────────────────────────────────────────────\n\nexport async function recordVaultAudit(input: {\n action: string;\n secretId?: string | null;\n appId?: string | null;\n summary: string;\n metadata?: unknown;\n actor?: string;\n}) {\n const db = getDb();\n await db.insert(schema.vaultAuditLog).values({\n id: id(),\n ownerEmail: currentOwnerEmail(),\n orgId: currentOrgId(),\n secretId: input.secretId || null,\n appId: input.appId || null,\n action: input.action,\n actor: input.actor || currentOwnerEmail(),\n summary: input.summary,\n metadata: input.metadata ? safeJson(input.metadata) : null,\n createdAt: now(),\n });\n}\n\nexport async function listVaultAudit(limit = 50) {\n const db = getDb();\n return db\n .select()\n .from(schema.vaultAuditLog)\n .where(scopedFilter(schema.vaultAuditLog))\n .orderBy(desc(schema.vaultAuditLog.createdAt))\n .limit(limit);\n}\n\n// ─── Secrets ──────────────────────────────────────────────────────\n\nexport async function listSecrets() {\n const db = getDb();\n return db\n .select()\n .from(schema.vaultSecrets)\n .where(scopedFilter(schema.vaultSecrets))\n .orderBy(desc(schema.vaultSecrets.updatedAt));\n}\n\nexport async function getSecret(secretId: string, ctx: VaultCtx) {\n const db = getDb();\n const [row] = await db\n .select()\n .from(schema.vaultSecrets)\n .where(\n and(\n eq(schema.vaultSecrets.id, secretId),\n ctxScope(schema.vaultSecrets, ctx),\n ),\n )\n .limit(1);\n return row ?? null;\n}\n\nexport async function createSecret(\n input: {\n credentialKey: string;\n value: string;\n name: string;\n provider?: string | null;\n description?: string | null;\n },\n ctx: VaultCtx = requireVaultCtx(),\n) {\n const db = getDb();\n const timestamp = now();\n const credentialKey = normalizeCredentialKey(input.credentialKey);\n if (!credentialKey) throw new Error(\"Credential key is required\");\n const existing = await db\n .select()\n .from(schema.vaultSecrets)\n .where(\n and(\n eq(schema.vaultSecrets.credentialKey, credentialKey),\n ctxScope(schema.vaultSecrets, ctx),\n ),\n )\n .orderBy(desc(schema.vaultSecrets.updatedAt))\n .limit(1);\n\n if (existing[0]) {\n await db\n .update(schema.vaultSecrets)\n .set({\n name: input.name,\n credentialKey,\n value: input.value,\n provider: input.provider || null,\n description: input.description || null,\n updatedAt: timestamp,\n })\n .where(\n and(\n eq(schema.vaultSecrets.id, existing[0].id),\n ctxScope(schema.vaultSecrets, ctx),\n ),\n );\n\n await recordVaultAudit({\n action: \"secret.updated\",\n secretId: existing[0].id,\n summary: `Updated secret \"${input.name}\" (${credentialKey})`,\n metadata: { credentialKey, provider: input.provider },\n });\n\n await recordAudit({\n action: \"vault.secret.updated\",\n targetType: \"vault-secret\",\n targetId: existing[0].id,\n summary: `Updated vault secret \"${input.name}\" (${credentialKey})`,\n });\n\n const updated = await getSecret(existing[0].id, ctx);\n if (updated) {\n await syncSecretsToCredentialStore(\n [updated],\n ctxForSecretRow(updated, ctx),\n );\n }\n return updated;\n }\n\n const secretId = id();\n const actor = ctx.ownerEmail;\n\n await db.insert(schema.vaultSecrets).values({\n id: secretId,\n ownerEmail: actor,\n orgId: ctx.orgId,\n name: input.name,\n credentialKey,\n value: input.value,\n provider: input.provider || null,\n description: input.description || null,\n createdBy: actor,\n createdAt: timestamp,\n updatedAt: timestamp,\n });\n\n await recordVaultAudit({\n action: \"secret.created\",\n secretId,\n summary: `Created secret \"${input.name}\" (${credentialKey})`,\n metadata: { credentialKey, provider: input.provider },\n });\n\n await recordAudit({\n action: \"vault.secret.created\",\n targetType: \"vault-secret\",\n targetId: secretId,\n summary: `Created vault secret \"${input.name}\" (${credentialKey})`,\n });\n\n const created = await getSecret(secretId, ctx);\n if (created) {\n await syncSecretsToCredentialStore(\n [created],\n ctxForSecretRow(created, ctx),\n );\n }\n return created;\n}\n\nexport async function updateSecret(\n secretId: string,\n input:\n | string\n | {\n credentialKey?: string;\n value?: string;\n name?: string;\n provider?: string | null;\n description?: string | null;\n },\n ctx: VaultCtx = requireVaultCtx(),\n) {\n const db = getDb();\n const existing = await getSecret(secretId, ctx);\n if (!existing) throw new Error(\"Secret not found\");\n const patch = typeof input === \"string\" ? { value: input } : input;\n const credentialKey =\n patch.credentialKey !== undefined\n ? normalizeCredentialKey(patch.credentialKey)\n : existing.credentialKey;\n if (!credentialKey) throw new Error(\"Credential key is required\");\n const name = patch.name !== undefined ? patch.name.trim() : existing.name;\n if (!name) throw new Error(\"Secret name is required\");\n const value = patch.value !== undefined ? patch.value : existing.value;\n if (!value) throw new Error(\"Secret value is required\");\n const provider =\n patch.provider !== undefined ? patch.provider || null : existing.provider;\n const description =\n patch.description !== undefined\n ? patch.description || null\n : existing.description;\n\n if (credentialKey !== existing.credentialKey) {\n const conflict = await db\n .select({ id: schema.vaultSecrets.id })\n .from(schema.vaultSecrets)\n .where(\n and(\n eq(schema.vaultSecrets.credentialKey, credentialKey),\n ctxScope(schema.vaultSecrets, ctx),\n ),\n )\n .limit(1);\n if (conflict[0] && conflict[0].id !== secretId) {\n throw new Error(`Credential key \"${credentialKey}\" is already in use`);\n }\n }\n\n await db\n .update(schema.vaultSecrets)\n .set({\n name,\n credentialKey,\n value,\n provider,\n description,\n updatedAt: now(),\n })\n .where(\n and(\n eq(schema.vaultSecrets.id, secretId),\n ctxScope(schema.vaultSecrets, ctx),\n ),\n );\n\n const auditMetadata = {\n name,\n previousName: name !== existing.name ? existing.name : undefined,\n credentialKey,\n previousCredentialKey:\n credentialKey !== existing.credentialKey\n ? existing.credentialKey\n : undefined,\n provider,\n previousProvider:\n provider !== existing.provider ? existing.provider : undefined,\n description,\n previousDescription:\n description !== existing.description ? existing.description : undefined,\n valueChanged: value !== existing.value ? true : undefined,\n };\n\n await recordVaultAudit({\n action: \"secret.updated\",\n secretId,\n summary: `Updated secret \"${name}\" (${credentialKey})`,\n metadata: auditMetadata,\n });\n\n await recordAudit({\n action: \"vault.secret.updated\",\n targetType: \"vault-secret\",\n targetId: secretId,\n summary: `Updated vault secret \"${name}\" (${credentialKey})`,\n metadata: auditMetadata,\n });\n\n const updated = await getSecret(secretId, ctx);\n if (updated) {\n await syncSecretsToCredentialStore(\n [updated],\n ctxForSecretRow(updated, ctx),\n );\n }\n if (updated && credentialKey !== existing.credentialKey) {\n await cleanupSyncedCredentialKeysIfUnused(ctxForRow(existing), [\n existing.credentialKey,\n ]);\n } else if (updated && patch.credentialKey !== undefined) {\n await cleanupSyncedCredentialKeysIfUnused(ctxForSecretRow(updated, ctx));\n }\n return updated;\n}\n\nexport async function deleteSecret(\n secretId: string,\n ctx: VaultCtx = requireVaultCtx(),\n) {\n const db = getDb();\n const existing = await getSecret(secretId, ctx);\n if (!existing) throw new Error(\"Secret not found\");\n\n // Revoke all active grants first\n const grants = await listGrants({ secretId });\n for (const grant of grants) {\n if (grant.status === \"active\") {\n await revokeGrant(grant.id, ctx);\n }\n }\n\n await db\n .delete(schema.vaultSecrets)\n .where(\n and(\n eq(schema.vaultSecrets.id, secretId),\n ctxScope(schema.vaultSecrets, ctx),\n ),\n );\n await cleanupSyncedCredentialKeysIfUnused(ctxForRow(existing), [\n existing.credentialKey,\n ]);\n\n await recordVaultAudit({\n action: \"secret.deleted\",\n secretId,\n summary: `Deleted secret \"${existing.name}\" (${existing.credentialKey})`,\n });\n\n await recordAudit({\n action: \"vault.secret.deleted\",\n targetType: \"vault-secret\",\n targetId: secretId,\n summary: `Deleted vault secret \"${existing.name}\" (${existing.credentialKey})`,\n });\n\n return existing;\n}\n\n// ─── Grants ──────────────────────────────────────────────────────\n\nexport async function listGrants(filter?: {\n secretId?: string;\n appId?: string;\n}) {\n const db = getDb();\n const conditions = [scopedFilter(schema.vaultGrants)];\n if (filter?.secretId) {\n conditions.push(eq(schema.vaultGrants.secretId, filter.secretId) as any);\n }\n if (filter?.appId) {\n conditions.push(eq(schema.vaultGrants.appId, filter.appId) as any);\n }\n return db\n .select()\n .from(schema.vaultGrants)\n .where(and(...conditions))\n .orderBy(desc(schema.vaultGrants.updatedAt));\n}\n\nexport async function getGrant(\n grantId: string,\n ctx: VaultCtx = requireVaultCtx(),\n) {\n const db = getDb();\n const [row] = await db\n .select()\n .from(schema.vaultGrants)\n .where(\n and(\n eq(schema.vaultGrants.id, grantId),\n ctxScope(schema.vaultGrants, ctx),\n ),\n )\n .limit(1);\n return row ?? null;\n}\n\nexport async function createGrant(\n secretId: string,\n appId: string,\n ctx: VaultCtx = requireVaultCtx(),\n) {\n const db = getDb();\n const secret = await getSecret(secretId, ctx);\n if (!secret) throw new Error(\"Secret not found\");\n\n const timestamp = now();\n const grantId = id();\n const actor = ctx.ownerEmail;\n\n await db.insert(schema.vaultGrants).values({\n id: grantId,\n ownerEmail: actor,\n orgId: ctx.orgId,\n secretId,\n appId,\n grantedBy: actor,\n status: \"active\",\n syncedAt: null,\n createdAt: timestamp,\n updatedAt: timestamp,\n });\n\n await recordVaultAudit({\n action: \"grant.created\",\n secretId,\n appId,\n summary: `Granted \"${secret.name}\" (${secret.credentialKey}) to ${appId}`,\n metadata: { grantId },\n });\n\n await recordAudit({\n action: \"vault.grant.created\",\n targetType: \"vault-grant\",\n targetId: grantId,\n summary: `Granted vault secret \"${secret.name}\" to ${appId}`,\n });\n\n return getGrant(grantId);\n}\n\nexport async function grantSecretsToApp(\n secretIds: string[],\n appId: string,\n ctx: VaultCtx = requireVaultCtx(),\n) {\n const access = await getVaultAccessSettings();\n const uniqueSecretIds = Array.from(new Set(secretIds));\n if (access.mode === \"all-apps\") {\n return {\n appId,\n accessMode: access.mode,\n created: [],\n skipped: uniqueSecretIds,\n };\n }\n const existingActive = (await listGrants({ appId })).filter(\n (grant) => grant.status === \"active\",\n );\n const existingSecretIds = new Set(\n existingActive.map((grant) => grant.secretId),\n );\n const created = [];\n const skipped: string[] = [];\n\n for (const secretId of uniqueSecretIds) {\n if (existingSecretIds.has(secretId)) {\n skipped.push(secretId);\n continue;\n }\n const grant = await createGrant(secretId, appId, ctx);\n if (grant) {\n created.push(grant);\n existingSecretIds.add(secretId);\n }\n }\n\n return { appId, accessMode: access.mode, created, skipped };\n}\n\nexport async function revokeGrant(\n grantId: string,\n ctx: VaultCtx = requireVaultCtx(),\n) {\n const db = getDb();\n const grant = await getGrant(grantId, ctx);\n if (!grant) throw new Error(\"Grant not found\");\n\n const secret = await getSecret(grant.secretId, ctx);\n\n await db\n .update(schema.vaultGrants)\n .set({ status: \"revoked\", updatedAt: now() })\n .where(\n and(\n eq(schema.vaultGrants.id, grantId),\n ctxScope(schema.vaultGrants, ctx),\n ),\n );\n\n await recordVaultAudit({\n action: \"grant.revoked\",\n secretId: grant.secretId,\n appId: grant.appId,\n summary: `Revoked ${secret?.credentialKey || grant.secretId} from ${grant.appId}`,\n metadata: { grantId },\n });\n\n await recordAudit({\n action: \"vault.grant.revoked\",\n targetType: \"vault-grant\",\n targetId: grantId,\n summary: `Revoked vault secret \"${secret?.name || grant.secretId}\" from ${grant.appId}`,\n });\n\n return getGrant(grantId, ctx);\n}\n\n// ─── Shared Credential Store Sync ─────────────────────────────────\n\ntype VaultSecretRow = typeof schema.vaultSecrets.$inferSelect;\n\nexport function credentialStoreScopeForVaultCtx(ctx: VaultCtx): {\n scope: Extract<SecretScope, \"org\" | \"workspace\">;\n scopeId: string;\n} {\n if (ctx.orgId) return { scope: \"org\", scopeId: ctx.orgId };\n return { scope: \"workspace\", scopeId: `solo:${ctx.ownerEmail}` };\n}\n\nexport async function syncSecretsToCredentialStore(\n secrets: VaultSecretRow[],\n ctx: VaultCtx,\n) {\n const target = credentialStoreScopeForVaultCtx(ctx);\n const syncedKeys: string[] = [];\n\n for (const secret of secrets) {\n if (!secret.credentialKey || !secret.value) continue;\n await writeAppSecret({\n key: secret.credentialKey,\n value: secret.value,\n scope: target.scope,\n scopeId: target.scopeId,\n description: `${VAULT_SYNC_DESCRIPTION_PREFIX} ${secret.name}`,\n });\n syncedKeys.push(secret.credentialKey);\n }\n\n return { ...target, keys: syncedKeys };\n}\n\nexport async function cleanupSyncedCredentialKeysIfUnused(\n ctx: VaultCtx,\n candidateKeys?: string[],\n) {\n const db = getDb();\n const target = credentialStoreScopeForVaultCtx(ctx);\n const keys = candidateKeys\n ? candidateKeys\n : (await listAppSecretsForScope(target.scope, target.scopeId))\n .filter((secret) =>\n secret.description?.startsWith(VAULT_SYNC_DESCRIPTION_PREFIX),\n )\n .map((secret) => secret.key);\n\n for (const key of new Set(keys.filter(Boolean))) {\n const stillUsesKey = await db\n .select({ id: schema.vaultSecrets.id })\n .from(schema.vaultSecrets)\n .where(\n and(\n eq(schema.vaultSecrets.credentialKey, key),\n ctxScope(schema.vaultSecrets, ctx),\n ),\n )\n .limit(1);\n if (!stillUsesKey[0]) {\n await deleteAppSecret({\n key,\n scope: target.scope,\n scopeId: target.scopeId,\n });\n }\n }\n}\n\n// ─── Sync ──────────────────────────────────────────────────────\n\nexport async function syncGrantsToApp(\n appId: string,\n ctx: VaultCtx = requireVaultCtx(),\n) {\n const db = getDb();\n const access = await getVaultAccessSettings();\n const agents = await discoverAgents(\"dispatch\");\n const agent = agents.find((a) => a.id === appId);\n if (!agent) throw new Error(`App \"${appId}\" not found in agent registry`);\n\n const secretsToSync: VaultSecretRow[] = [];\n const activeGrants =\n access.mode === \"manual\"\n ? (await listGrants({ appId })).filter((g) => g.status === \"active\")\n : [];\n\n if (access.mode === \"all-apps\") {\n const secrets = await listSecrets();\n for (const secret of secrets) {\n secretsToSync.push(secret);\n }\n } else {\n for (const grant of activeGrants) {\n const secret = await getSecret(grant.secretId, ctx);\n if (secret) {\n secretsToSync.push(secret);\n }\n }\n }\n\n if (secretsToSync.length === 0) {\n return { appId, accessMode: access.mode, synced: 0, keys: [] };\n }\n\n const credentialStoreSync = await syncSecretsToCredentialStore(\n secretsToSync,\n ctx,\n );\n const vars = secretsToSync.map((secret) => ({\n key: secret.credentialKey,\n value: secret.value,\n }));\n let envVarSync:\n | { status: \"synced\"; keys: string[] }\n | { status: \"skipped\"; reason: string }\n | { status: \"failed\"; reason: string };\n\n // Best-effort push to the app's env-vars endpoint for local/dev apps that\n // still read process.env directly. Production/shared-DB apps intentionally\n // reject env writes; the encrypted app_secrets sync above is the canonical\n // path for request-scoped credentials.\n try {\n const res = await fetch(`${agent.url}/_agent-native/env-vars`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ vars }),\n });\n\n if (res.ok) {\n const result = await res.json();\n envVarSync = { status: \"synced\", keys: result.saved || [] };\n } else {\n const err = await res.text().catch(() => \"Unknown error\");\n envVarSync = { status: \"skipped\", reason: err };\n }\n } catch (err) {\n envVarSync = {\n status: \"failed\",\n reason: err instanceof Error ? err.message : String(err),\n };\n }\n\n const syncedKeys = credentialStoreSync.keys;\n const timestamp = now();\n\n // Update syncedAt on grants that were successfully pushed to the shared\n // credential store. All-apps mode has no explicit grant rows to update.\n for (const grant of activeGrants) {\n const secret = await getSecret(grant.secretId, ctx);\n if (secret && syncedKeys.includes(secret.credentialKey)) {\n await db\n .update(schema.vaultGrants)\n .set({ syncedAt: timestamp, updatedAt: timestamp })\n .where(eq(schema.vaultGrants.id, grant.id));\n }\n }\n\n await recordVaultAudit({\n action: \"secret.synced\",\n appId,\n summary: `Synced ${syncedKeys.length} secret(s) to ${appId}: ${syncedKeys.join(\", \")}`,\n metadata: {\n syncedKeys,\n accessMode: access.mode,\n credentialStore: {\n scope: credentialStoreSync.scope,\n scopeId: credentialStoreSync.scopeId,\n },\n envVars: envVarSync,\n },\n });\n\n return {\n appId,\n accessMode: access.mode,\n synced: syncedKeys.length,\n keys: syncedKeys,\n credentialStore: {\n scope: credentialStoreSync.scope,\n scopeId: credentialStoreSync.scopeId,\n synced: credentialStoreSync.keys.length,\n },\n envVars: envVarSync,\n };\n}\n\n// ─── Requests ──────────────────────────────────────────────────────\n\nexport async function listRequests(filter?: { status?: string }) {\n const db = getDb();\n const conditions = [scopedFilter(schema.vaultRequests)];\n if (filter?.status) {\n conditions.push(eq(schema.vaultRequests.status, filter.status) as any);\n }\n return db\n .select()\n .from(schema.vaultRequests)\n .where(and(...conditions))\n .orderBy(desc(schema.vaultRequests.updatedAt));\n}\n\nexport async function getRequest(\n requestId: string,\n ctx: VaultCtx = requireVaultCtx(),\n) {\n const db = getDb();\n const [row] = await db\n .select()\n .from(schema.vaultRequests)\n .where(\n and(\n eq(schema.vaultRequests.id, requestId),\n ctxScope(schema.vaultRequests, ctx),\n ),\n )\n .limit(1);\n return row ?? null;\n}\n\nexport async function createRequest(input: {\n credentialKey: string;\n appId: string;\n reason?: string | null;\n}) {\n const db = getDb();\n const timestamp = now();\n const requestId = id();\n const actor = currentOwnerEmail();\n\n await db.insert(schema.vaultRequests).values({\n id: requestId,\n ownerEmail: actor,\n orgId: currentOrgId(),\n credentialKey: input.credentialKey,\n appId: input.appId,\n reason: input.reason || null,\n requestedBy: actor,\n status: \"pending\",\n reviewedBy: null,\n reviewedAt: null,\n createdAt: timestamp,\n updatedAt: timestamp,\n });\n\n await recordVaultAudit({\n action: \"request.created\",\n appId: input.appId,\n summary: `${actor} requested ${input.credentialKey} for ${input.appId}`,\n metadata: { requestId, reason: input.reason },\n });\n\n await notifyAdminsOfRequest(requestId, input);\n\n return getRequest(requestId);\n}\n\nexport async function approveRequest(\n requestId: string,\n secretValue: string,\n secretName?: string,\n ctx: VaultCtx = requireVaultCtx(),\n) {\n const db = getDb();\n const request = await getRequest(requestId, ctx);\n if (!request) throw new Error(\"Request not found\");\n if (request.status !== \"pending\") {\n throw new Error(\"Only pending requests can be approved\");\n }\n\n const timestamp = now();\n const reviewer = ctx.ownerEmail;\n\n // Update request status — scoped to caller's tenant.\n await db\n .update(schema.vaultRequests)\n .set({\n status: \"approved\",\n reviewedBy: reviewer,\n reviewedAt: timestamp,\n updatedAt: timestamp,\n })\n .where(\n and(\n eq(schema.vaultRequests.id, requestId),\n ctxScope(schema.vaultRequests, ctx),\n ),\n );\n\n // Secret + grant must land in the REQUEST's tenant, not the approver's\n // (the approver may be acting on behalf of another user in the same org).\n const requestCtx = ctxForRow(request);\n\n // Check if secret already exists in the request's tenant for this key.\n const existingSecrets = await db\n .select()\n .from(schema.vaultSecrets)\n .where(\n and(\n eq(schema.vaultSecrets.credentialKey, request.credentialKey),\n ctxScope(schema.vaultSecrets, requestCtx),\n ),\n );\n let secret = existingSecrets[0] ?? null;\n\n if (!secret) {\n secret = await createSecret(\n {\n credentialKey: request.credentialKey,\n value: secretValue,\n name: secretName || request.credentialKey,\n },\n requestCtx,\n );\n }\n\n if (secret) {\n // Create the grant in the request's tenant as well.\n await createGrant(secret.id, request.appId, requestCtx);\n }\n\n await recordVaultAudit({\n action: \"request.approved\",\n appId: request.appId,\n summary: `Approved ${request.credentialKey} for ${request.appId} (requested by ${request.requestedBy})`,\n metadata: { requestId, reviewer },\n });\n\n return getRequest(requestId, ctx);\n}\n\nexport async function denyRequest(\n requestId: string,\n reason?: string | null,\n ctx: VaultCtx = requireVaultCtx(),\n) {\n const db = getDb();\n const request = await getRequest(requestId, ctx);\n if (!request) throw new Error(\"Request not found\");\n if (request.status !== \"pending\") {\n throw new Error(\"Only pending requests can be denied\");\n }\n\n const timestamp = now();\n const reviewer = ctx.ownerEmail;\n\n await db\n .update(schema.vaultRequests)\n .set({\n status: \"denied\",\n reviewedBy: reviewer,\n reviewedAt: timestamp,\n updatedAt: timestamp,\n })\n .where(\n and(\n eq(schema.vaultRequests.id, requestId),\n ctxScope(schema.vaultRequests, ctx),\n ),\n );\n\n await recordVaultAudit({\n action: \"request.denied\",\n appId: request.appId,\n summary: `Denied ${request.credentialKey} for ${request.appId} (requested by ${request.requestedBy})`,\n metadata: { requestId, reviewer, reason },\n });\n\n return getRequest(requestId, ctx);\n}\n\n// ─── Integrations Catalog ────────────────────────────────────────\n\nexport interface IntegrationEntry {\n key: string;\n label: string;\n required: boolean;\n configured: boolean;\n vaultGranted: boolean;\n vaultSecretId?: string;\n}\n\nexport interface AppIntegrations {\n appId: string;\n appName: string;\n url: string;\n color: string;\n integrations: IntegrationEntry[];\n vaultAccessMode: VaultAccessMode;\n reachable: boolean;\n}\n\nexport async function listIntegrationsCatalog(): Promise<AppIntegrations[]> {\n const access = await getVaultAccessSettings();\n const agents = await discoverAgents(\"dispatch\");\n const grants = await listGrants();\n const secrets = await listSecrets();\n\n const secretByKey = new Map(secrets.map((s) => [s.credentialKey, s]));\n\n const results: AppIntegrations[] = [];\n\n for (const agent of agents) {\n try {\n const res = await fetch(`${agent.url}/_agent-native/env-status`, {\n signal: AbortSignal.timeout(3000),\n });\n if (!res.ok) {\n results.push({\n appId: agent.id,\n appName: agent.name,\n url: agent.url,\n color: agent.color,\n integrations: [],\n vaultAccessMode: access.mode,\n reachable: false,\n });\n continue;\n }\n\n const envStatus: Array<{\n key: string;\n label: string;\n required: boolean;\n configured: boolean;\n }> = await res.json();\n\n const appGrants = grants.filter(\n (g) => g.appId === agent.id && g.status === \"active\",\n );\n const grantedSecretIds = new Set(appGrants.map((g) => g.secretId));\n\n const integrations: IntegrationEntry[] = envStatus.map((env) => {\n const matchingSecret = secretByKey.get(env.key);\n return {\n key: env.key,\n label: env.label,\n required: env.required,\n configured: env.configured,\n vaultGranted:\n !!matchingSecret &&\n (access.mode === \"all-apps\" ||\n grantedSecretIds.has(matchingSecret.id)),\n vaultSecretId: matchingSecret?.id,\n };\n });\n\n results.push({\n appId: agent.id,\n appName: agent.name,\n url: agent.url,\n color: agent.color,\n integrations,\n vaultAccessMode: access.mode,\n reachable: true,\n });\n } catch {\n results.push({\n appId: agent.id,\n appName: agent.name,\n url: agent.url,\n color: agent.color,\n integrations: [],\n vaultAccessMode: access.mode,\n reachable: false,\n });\n }\n }\n\n return results;\n}\n\n// ─── Vault Overview (for dashboard) ──────────────────────────────\n\nexport async function listVaultOverview() {\n const [secrets, grants, requests, access] = await Promise.all([\n listSecrets(),\n listGrants(),\n listRequests(),\n getVaultAccessSettings(),\n ]);\n const manualGrantCount = grants.filter((g) => g.status === \"active\").length;\n\n return {\n accessMode: access.mode,\n secretCount: secrets.length,\n activeGrantCount:\n access.mode === \"all-apps\" ? secrets.length : manualGrantCount,\n manualGrantCount,\n pendingRequestCount: requests.filter((r) => r.status === \"pending\").length,\n };\n}\n\n// ─── SendGrid Notifications ──────────────────────────────────────\n\nasync function notifyAdminsOfRequest(\n requestId: string,\n input: { credentialKey: string; appId: string; reason?: string | null },\n) {\n const apiKey = process.env.SENDGRID_API_KEY;\n const from = process.env.SENDGRID_FROM_EMAIL;\n const appUrl = process.env.APP_URL;\n if (!apiKey || !from || !appUrl) return;\n\n // Use approval policy approver emails as admin notification targets\n const { getApprovalPolicy } = await import(\"./dispatch-store.js\");\n const policy = await getApprovalPolicy();\n if (policy.approverEmails.length === 0) return;\n\n const body = [\n `Secret request: ${input.credentialKey} for ${input.appId}`,\n input.reason ? `Reason: ${input.reason}` : \"\",\n `Requested by: ${currentOwnerEmail()}`,\n \"\",\n `Review it here: ${appUrl}/vault`,\n ]\n .filter(Boolean)\n .join(\"\\n\");\n\n await fetch(\"https://api.sendgrid.com/v3/mail/send\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n personalizations: [\n {\n to: policy.approverEmails.map((email) => ({ email })),\n subject: `Vault request: ${input.credentialKey} for ${input.appId}`,\n },\n ],\n from: { email: from },\n content: [{ type: \"text/plain\", value: body }],\n custom_args: { requestId },\n }),\n }).catch(() => {});\n}\n"]}
|
|
1
|
+
{"version":3,"file":"vault-store.js","sourceRoot":"","sources":["../../../src/server/lib/vault-store.ts"],"names":[],"mappings":"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","sourcesContent":["import crypto from \"node:crypto\";\nimport { and, desc, eq, isNull, or } from \"drizzle-orm\";\nimport { discoverAgents } from \"@agent-native/core/server/agent-discovery\";\nimport { ssrfSafeFetch } from \"@agent-native/core/extensions/url-safety\";\nimport {\n deleteAppSecret,\n listAppSecretsForScope,\n writeAppSecret,\n type SecretScope,\n} from \"@agent-native/core/secrets\";\nimport {\n getOrgSetting,\n getUserSetting,\n putOrgSetting,\n putUserSetting,\n} from \"@agent-native/core/settings\";\nimport { getDb, schema } from \"../../db/index.js\";\nimport {\n currentOwnerEmail,\n currentOrgId,\n recordAudit,\n} from \"./dispatch-store.js\";\n\nconst VAULT_ACCESS_SETTINGS_KEY = \"dispatch-vault-access-settings\";\nconst VAULT_SYNC_DESCRIPTION_PREFIX = \"Synced from Dispatch vault:\";\n\nexport type VaultAccessMode = \"all-apps\" | \"manual\";\n\nexport interface VaultAccessSettings {\n mode: VaultAccessMode;\n scope: \"org\" | \"user\";\n scopeId: string;\n}\n\n/**\n * Caller-supplied access context for vault operations.\n *\n * Every getSecret / updateSecret / deleteSecret / createGrant call must\n * pass the ctx of the *current request* so the row is scoped to that\n * caller's tenant. Looking up a vault secret by id alone is unsafe — UUIDs\n * are not authorization. A row matches the ctx if either the caller owns\n * it or it lives in the caller's active org.\n */\nexport interface VaultCtx {\n ownerEmail: string;\n orgId: string | null;\n}\n\n/**\n * Build a VaultCtx from the current request. Throws if the request is\n * unauthenticated — the previous behavior of falling back to \"local@localhost\"\n * leaked rows across tenants when a misconfigured environment skipped auth.\n */\nexport function requireVaultCtx(): VaultCtx {\n const ownerEmail = currentOwnerEmail();\n if (!ownerEmail) {\n throw new Error(\"Vault operation requires an authenticated user\");\n }\n return { ownerEmail, orgId: currentOrgId() };\n}\n\n/** WHERE clause that limits a vault row to the caller's ownership scope. */\nfunction ctxScope<T extends { ownerEmail: any; orgId: any }>(\n table: T,\n ctx: VaultCtx,\n) {\n if (!ctx.orgId) {\n return and(eq(table.ownerEmail, ctx.ownerEmail), isNull(table.orgId));\n }\n return or(eq(table.ownerEmail, ctx.ownerEmail), eq(table.orgId, ctx.orgId));\n}\n\n/** Build a ctx that scopes to a specific row's owner/org (used when a\n * request approver acts on behalf of the original requester so the\n * created secret lands in the request's org). */\nfunction ctxForRow(row: {\n ownerEmail: string;\n orgId: string | null;\n}): VaultCtx {\n return { ownerEmail: row.ownerEmail, orgId: row.orgId };\n}\n\nfunction ctxForSecretRow(row: VaultSecretRow, fallback: VaultCtx): VaultCtx {\n return row.ownerEmail ? ctxForRow(row) : fallback;\n}\n\nfunction id() {\n return crypto.randomUUID();\n}\n\nfunction now() {\n return Date.now();\n}\n\nfunction safeJson(value: unknown) {\n return JSON.stringify(value ?? null);\n}\n\nfunction workspaceBaseOrigins(): Set<string> {\n const out = new Set<string>();\n for (const value of [\n process.env.WORKSPACE_GATEWAY_URL,\n process.env.APP_URL,\n process.env.URL,\n process.env.DEPLOY_URL,\n process.env.BETTER_AUTH_URL,\n ]) {\n if (!value) continue;\n try {\n out.add(new URL(value).origin);\n } catch {\n // Ignore malformed deploy metadata.\n }\n }\n return out;\n}\n\nexport function isTrustedEnvVarSyncAgentUrl(agentUrl: string): boolean {\n let parsed: URL;\n try {\n parsed = new URL(agentUrl);\n } catch {\n return false;\n }\n const hostname = parsed.hostname.toLowerCase();\n if (\n hostname === \"localhost\" ||\n hostname === \"127.0.0.1\" ||\n hostname === \"::1\" ||\n hostname.endsWith(\".localhost\")\n ) {\n return true;\n }\n return workspaceBaseOrigins().has(parsed.origin);\n}\n\nfunction scopedFilter<T extends { ownerEmail: any; orgId: any }>(table: T) {\n return ctxScope(table, requireVaultCtx());\n}\n\nfunction normalizeCredentialKey(value: string) {\n return value.trim();\n}\n\nfunction vaultAccessScope() {\n const orgId = currentOrgId();\n if (orgId) return { scope: \"org\" as const, scopeId: orgId };\n return { scope: \"user\" as const, scopeId: currentOwnerEmail() };\n}\n\nfunction parseVaultAccessMode(value: unknown): VaultAccessMode {\n return value === \"manual\" ? \"manual\" : \"all-apps\";\n}\n\nexport async function getVaultAccessSettings(): Promise<VaultAccessSettings> {\n const scope = vaultAccessScope();\n const raw =\n scope.scope === \"org\"\n ? await getOrgSetting(scope.scopeId, VAULT_ACCESS_SETTINGS_KEY)\n : await getUserSetting(scope.scopeId, VAULT_ACCESS_SETTINGS_KEY);\n return {\n ...scope,\n mode: parseVaultAccessMode(raw?.mode),\n };\n}\n\nexport async function setVaultAccessSettings(input: {\n mode: VaultAccessMode;\n}): Promise<VaultAccessSettings> {\n const scope = vaultAccessScope();\n const next = { mode: parseVaultAccessMode(input.mode) };\n if (scope.scope === \"org\") {\n await putOrgSetting(scope.scopeId, VAULT_ACCESS_SETTINGS_KEY, next);\n } else {\n await putUserSetting(scope.scopeId, VAULT_ACCESS_SETTINGS_KEY, next);\n }\n await recordAudit({\n action: \"vault.access-settings.updated\",\n targetType: \"vault-settings\",\n targetId: VAULT_ACCESS_SETTINGS_KEY,\n summary:\n next.mode === \"all-apps\"\n ? \"Set vault access to all workspace apps\"\n : \"Set vault access to manual per-app grants\",\n metadata: next,\n });\n return getVaultAccessSettings();\n}\n\n// ─── Vault Audit ──────────────────────────────────────────────────\n\nexport async function recordVaultAudit(input: {\n action: string;\n secretId?: string | null;\n appId?: string | null;\n summary: string;\n metadata?: unknown;\n actor?: string;\n}) {\n const db = getDb();\n await db.insert(schema.vaultAuditLog).values({\n id: id(),\n ownerEmail: currentOwnerEmail(),\n orgId: currentOrgId(),\n secretId: input.secretId || null,\n appId: input.appId || null,\n action: input.action,\n actor: input.actor || currentOwnerEmail(),\n summary: input.summary,\n metadata: input.metadata ? safeJson(input.metadata) : null,\n createdAt: now(),\n });\n}\n\nexport async function listVaultAudit(limit = 50) {\n const db = getDb();\n return db\n .select()\n .from(schema.vaultAuditLog)\n .where(scopedFilter(schema.vaultAuditLog))\n .orderBy(desc(schema.vaultAuditLog.createdAt))\n .limit(limit);\n}\n\n// ─── Secrets ──────────────────────────────────────────────────────\n\nexport async function listSecrets() {\n const db = getDb();\n return db\n .select()\n .from(schema.vaultSecrets)\n .where(scopedFilter(schema.vaultSecrets))\n .orderBy(desc(schema.vaultSecrets.updatedAt));\n}\n\nexport async function getSecret(secretId: string, ctx: VaultCtx) {\n const db = getDb();\n const [row] = await db\n .select()\n .from(schema.vaultSecrets)\n .where(\n and(\n eq(schema.vaultSecrets.id, secretId),\n ctxScope(schema.vaultSecrets, ctx),\n ),\n )\n .limit(1);\n return row ?? null;\n}\n\nexport async function createSecret(\n input: {\n credentialKey: string;\n value: string;\n name: string;\n provider?: string | null;\n description?: string | null;\n },\n ctx: VaultCtx = requireVaultCtx(),\n) {\n const db = getDb();\n const timestamp = now();\n const credentialKey = normalizeCredentialKey(input.credentialKey);\n if (!credentialKey) throw new Error(\"Credential key is required\");\n const existing = await db\n .select()\n .from(schema.vaultSecrets)\n .where(\n and(\n eq(schema.vaultSecrets.credentialKey, credentialKey),\n ctxScope(schema.vaultSecrets, ctx),\n ),\n )\n .orderBy(desc(schema.vaultSecrets.updatedAt))\n .limit(1);\n\n if (existing[0]) {\n await db\n .update(schema.vaultSecrets)\n .set({\n name: input.name,\n credentialKey,\n value: input.value,\n provider: input.provider || null,\n description: input.description || null,\n updatedAt: timestamp,\n })\n .where(\n and(\n eq(schema.vaultSecrets.id, existing[0].id),\n ctxScope(schema.vaultSecrets, ctx),\n ),\n );\n\n await recordVaultAudit({\n action: \"secret.updated\",\n secretId: existing[0].id,\n summary: `Updated secret \"${input.name}\" (${credentialKey})`,\n metadata: { credentialKey, provider: input.provider },\n });\n\n await recordAudit({\n action: \"vault.secret.updated\",\n targetType: \"vault-secret\",\n targetId: existing[0].id,\n summary: `Updated vault secret \"${input.name}\" (${credentialKey})`,\n });\n\n const updated = await getSecret(existing[0].id, ctx);\n if (updated) {\n await syncSecretsToCredentialStore(\n [updated],\n ctxForSecretRow(updated, ctx),\n );\n }\n return updated;\n }\n\n const secretId = id();\n const actor = ctx.ownerEmail;\n\n await db.insert(schema.vaultSecrets).values({\n id: secretId,\n ownerEmail: actor,\n orgId: ctx.orgId,\n name: input.name,\n credentialKey,\n value: input.value,\n provider: input.provider || null,\n description: input.description || null,\n createdBy: actor,\n createdAt: timestamp,\n updatedAt: timestamp,\n });\n\n await recordVaultAudit({\n action: \"secret.created\",\n secretId,\n summary: `Created secret \"${input.name}\" (${credentialKey})`,\n metadata: { credentialKey, provider: input.provider },\n });\n\n await recordAudit({\n action: \"vault.secret.created\",\n targetType: \"vault-secret\",\n targetId: secretId,\n summary: `Created vault secret \"${input.name}\" (${credentialKey})`,\n });\n\n const created = await getSecret(secretId, ctx);\n if (created) {\n await syncSecretsToCredentialStore(\n [created],\n ctxForSecretRow(created, ctx),\n );\n }\n return created;\n}\n\nexport async function updateSecret(\n secretId: string,\n input:\n | string\n | {\n credentialKey?: string;\n value?: string;\n name?: string;\n provider?: string | null;\n description?: string | null;\n },\n ctx: VaultCtx = requireVaultCtx(),\n) {\n const db = getDb();\n const existing = await getSecret(secretId, ctx);\n if (!existing) throw new Error(\"Secret not found\");\n const patch = typeof input === \"string\" ? { value: input } : input;\n const credentialKey =\n patch.credentialKey !== undefined\n ? normalizeCredentialKey(patch.credentialKey)\n : existing.credentialKey;\n if (!credentialKey) throw new Error(\"Credential key is required\");\n const name = patch.name !== undefined ? patch.name.trim() : existing.name;\n if (!name) throw new Error(\"Secret name is required\");\n const value = patch.value !== undefined ? patch.value : existing.value;\n if (!value) throw new Error(\"Secret value is required\");\n const provider =\n patch.provider !== undefined ? patch.provider || null : existing.provider;\n const description =\n patch.description !== undefined\n ? patch.description || null\n : existing.description;\n\n if (credentialKey !== existing.credentialKey) {\n const conflict = await db\n .select({ id: schema.vaultSecrets.id })\n .from(schema.vaultSecrets)\n .where(\n and(\n eq(schema.vaultSecrets.credentialKey, credentialKey),\n ctxScope(schema.vaultSecrets, ctx),\n ),\n )\n .limit(1);\n if (conflict[0] && conflict[0].id !== secretId) {\n throw new Error(`Credential key \"${credentialKey}\" is already in use`);\n }\n }\n\n await db\n .update(schema.vaultSecrets)\n .set({\n name,\n credentialKey,\n value,\n provider,\n description,\n updatedAt: now(),\n })\n .where(\n and(\n eq(schema.vaultSecrets.id, secretId),\n ctxScope(schema.vaultSecrets, ctx),\n ),\n );\n\n const auditMetadata = {\n name,\n previousName: name !== existing.name ? existing.name : undefined,\n credentialKey,\n previousCredentialKey:\n credentialKey !== existing.credentialKey\n ? existing.credentialKey\n : undefined,\n provider,\n previousProvider:\n provider !== existing.provider ? existing.provider : undefined,\n description,\n previousDescription:\n description !== existing.description ? existing.description : undefined,\n valueChanged: value !== existing.value ? true : undefined,\n };\n\n await recordVaultAudit({\n action: \"secret.updated\",\n secretId,\n summary: `Updated secret \"${name}\" (${credentialKey})`,\n metadata: auditMetadata,\n });\n\n await recordAudit({\n action: \"vault.secret.updated\",\n targetType: \"vault-secret\",\n targetId: secretId,\n summary: `Updated vault secret \"${name}\" (${credentialKey})`,\n metadata: auditMetadata,\n });\n\n const updated = await getSecret(secretId, ctx);\n if (updated) {\n await syncSecretsToCredentialStore(\n [updated],\n ctxForSecretRow(updated, ctx),\n );\n }\n if (updated && credentialKey !== existing.credentialKey) {\n await cleanupSyncedCredentialKeysIfUnused(ctxForRow(existing), [\n existing.credentialKey,\n ]);\n } else if (updated && patch.credentialKey !== undefined) {\n await cleanupSyncedCredentialKeysIfUnused(ctxForSecretRow(updated, ctx));\n }\n return updated;\n}\n\nexport async function deleteSecret(\n secretId: string,\n ctx: VaultCtx = requireVaultCtx(),\n) {\n const db = getDb();\n const existing = await getSecret(secretId, ctx);\n if (!existing) throw new Error(\"Secret not found\");\n\n // Revoke all active grants first\n const grants = await listGrants({ secretId });\n for (const grant of grants) {\n if (grant.status === \"active\") {\n await revokeGrant(grant.id, ctx);\n }\n }\n\n await db\n .delete(schema.vaultSecrets)\n .where(\n and(\n eq(schema.vaultSecrets.id, secretId),\n ctxScope(schema.vaultSecrets, ctx),\n ),\n );\n await cleanupSyncedCredentialKeysIfUnused(ctxForRow(existing), [\n existing.credentialKey,\n ]);\n\n await recordVaultAudit({\n action: \"secret.deleted\",\n secretId,\n summary: `Deleted secret \"${existing.name}\" (${existing.credentialKey})`,\n });\n\n await recordAudit({\n action: \"vault.secret.deleted\",\n targetType: \"vault-secret\",\n targetId: secretId,\n summary: `Deleted vault secret \"${existing.name}\" (${existing.credentialKey})`,\n });\n\n return existing;\n}\n\n// ─── Grants ──────────────────────────────────────────────────────\n\nexport async function listGrants(filter?: {\n secretId?: string;\n appId?: string;\n}) {\n const db = getDb();\n const conditions = [scopedFilter(schema.vaultGrants)];\n if (filter?.secretId) {\n conditions.push(eq(schema.vaultGrants.secretId, filter.secretId) as any);\n }\n if (filter?.appId) {\n conditions.push(eq(schema.vaultGrants.appId, filter.appId) as any);\n }\n return db\n .select()\n .from(schema.vaultGrants)\n .where(and(...conditions))\n .orderBy(desc(schema.vaultGrants.updatedAt));\n}\n\nexport async function getGrant(\n grantId: string,\n ctx: VaultCtx = requireVaultCtx(),\n) {\n const db = getDb();\n const [row] = await db\n .select()\n .from(schema.vaultGrants)\n .where(\n and(\n eq(schema.vaultGrants.id, grantId),\n ctxScope(schema.vaultGrants, ctx),\n ),\n )\n .limit(1);\n return row ?? null;\n}\n\nexport async function createGrant(\n secretId: string,\n appId: string,\n ctx: VaultCtx = requireVaultCtx(),\n) {\n const db = getDb();\n const secret = await getSecret(secretId, ctx);\n if (!secret) throw new Error(\"Secret not found\");\n\n const timestamp = now();\n const grantId = id();\n const actor = ctx.ownerEmail;\n\n await db.insert(schema.vaultGrants).values({\n id: grantId,\n ownerEmail: actor,\n orgId: ctx.orgId,\n secretId,\n appId,\n grantedBy: actor,\n status: \"active\",\n syncedAt: null,\n createdAt: timestamp,\n updatedAt: timestamp,\n });\n\n await recordVaultAudit({\n action: \"grant.created\",\n secretId,\n appId,\n summary: `Granted \"${secret.name}\" (${secret.credentialKey}) to ${appId}`,\n metadata: { grantId },\n });\n\n await recordAudit({\n action: \"vault.grant.created\",\n targetType: \"vault-grant\",\n targetId: grantId,\n summary: `Granted vault secret \"${secret.name}\" to ${appId}`,\n });\n\n return getGrant(grantId);\n}\n\nexport async function grantSecretsToApp(\n secretIds: string[],\n appId: string,\n ctx: VaultCtx = requireVaultCtx(),\n) {\n const access = await getVaultAccessSettings();\n const uniqueSecretIds = Array.from(new Set(secretIds));\n if (access.mode === \"all-apps\") {\n return {\n appId,\n accessMode: access.mode,\n created: [],\n skipped: uniqueSecretIds,\n };\n }\n const existingActive = (await listGrants({ appId })).filter(\n (grant) => grant.status === \"active\",\n );\n const existingSecretIds = new Set(\n existingActive.map((grant) => grant.secretId),\n );\n const created = [];\n const skipped: string[] = [];\n\n for (const secretId of uniqueSecretIds) {\n if (existingSecretIds.has(secretId)) {\n skipped.push(secretId);\n continue;\n }\n const grant = await createGrant(secretId, appId, ctx);\n if (grant) {\n created.push(grant);\n existingSecretIds.add(secretId);\n }\n }\n\n return { appId, accessMode: access.mode, created, skipped };\n}\n\nexport async function revokeGrant(\n grantId: string,\n ctx: VaultCtx = requireVaultCtx(),\n) {\n const db = getDb();\n const grant = await getGrant(grantId, ctx);\n if (!grant) throw new Error(\"Grant not found\");\n\n const secret = await getSecret(grant.secretId, ctx);\n\n await db\n .update(schema.vaultGrants)\n .set({ status: \"revoked\", updatedAt: now() })\n .where(\n and(\n eq(schema.vaultGrants.id, grantId),\n ctxScope(schema.vaultGrants, ctx),\n ),\n );\n\n await recordVaultAudit({\n action: \"grant.revoked\",\n secretId: grant.secretId,\n appId: grant.appId,\n summary: `Revoked ${secret?.credentialKey || grant.secretId} from ${grant.appId}`,\n metadata: { grantId },\n });\n\n await recordAudit({\n action: \"vault.grant.revoked\",\n targetType: \"vault-grant\",\n targetId: grantId,\n summary: `Revoked vault secret \"${secret?.name || grant.secretId}\" from ${grant.appId}`,\n });\n\n return getGrant(grantId, ctx);\n}\n\n// ─── Shared Credential Store Sync ─────────────────────────────────\n\ntype VaultSecretRow = typeof schema.vaultSecrets.$inferSelect;\n\nexport function credentialStoreScopeForVaultCtx(ctx: VaultCtx): {\n scope: Extract<SecretScope, \"org\" | \"workspace\">;\n scopeId: string;\n} {\n if (ctx.orgId) return { scope: \"org\", scopeId: ctx.orgId };\n return { scope: \"workspace\", scopeId: `solo:${ctx.ownerEmail}` };\n}\n\nexport async function syncSecretsToCredentialStore(\n secrets: VaultSecretRow[],\n ctx: VaultCtx,\n) {\n const target = credentialStoreScopeForVaultCtx(ctx);\n const syncedKeys: string[] = [];\n\n for (const secret of secrets) {\n if (!secret.credentialKey || !secret.value) continue;\n await writeAppSecret({\n key: secret.credentialKey,\n value: secret.value,\n scope: target.scope,\n scopeId: target.scopeId,\n description: `${VAULT_SYNC_DESCRIPTION_PREFIX} ${secret.name}`,\n });\n syncedKeys.push(secret.credentialKey);\n }\n\n return { ...target, keys: syncedKeys };\n}\n\nexport async function cleanupSyncedCredentialKeysIfUnused(\n ctx: VaultCtx,\n candidateKeys?: string[],\n) {\n const db = getDb();\n const target = credentialStoreScopeForVaultCtx(ctx);\n const keys = candidateKeys\n ? candidateKeys\n : (await listAppSecretsForScope(target.scope, target.scopeId))\n .filter((secret) =>\n secret.description?.startsWith(VAULT_SYNC_DESCRIPTION_PREFIX),\n )\n .map((secret) => secret.key);\n\n for (const key of new Set(keys.filter(Boolean))) {\n const stillUsesKey = await db\n .select({ id: schema.vaultSecrets.id })\n .from(schema.vaultSecrets)\n .where(\n and(\n eq(schema.vaultSecrets.credentialKey, key),\n ctxScope(schema.vaultSecrets, ctx),\n ),\n )\n .limit(1);\n if (!stillUsesKey[0]) {\n await deleteAppSecret({\n key,\n scope: target.scope,\n scopeId: target.scopeId,\n });\n }\n }\n}\n\n// ─── Sync ──────────────────────────────────────────────────────\n\nexport async function syncGrantsToApp(\n appId: string,\n ctx: VaultCtx = requireVaultCtx(),\n) {\n const db = getDb();\n const access = await getVaultAccessSettings();\n const agents = await discoverAgents(\"dispatch\");\n const agent = agents.find((a) => a.id === appId);\n if (!agent) throw new Error(`App \"${appId}\" not found in agent registry`);\n\n const secretsToSync: VaultSecretRow[] = [];\n const activeGrants =\n access.mode === \"manual\"\n ? (await listGrants({ appId })).filter((g) => g.status === \"active\")\n : [];\n\n if (access.mode === \"all-apps\") {\n const secrets = await listSecrets();\n for (const secret of secrets) {\n secretsToSync.push(secret);\n }\n } else {\n for (const grant of activeGrants) {\n const secret = await getSecret(grant.secretId, ctx);\n if (secret) {\n secretsToSync.push(secret);\n }\n }\n }\n\n if (secretsToSync.length === 0) {\n return { appId, accessMode: access.mode, synced: 0, keys: [] };\n }\n\n const credentialStoreSync = await syncSecretsToCredentialStore(\n secretsToSync,\n ctx,\n );\n const vars = secretsToSync.map((secret) => ({\n key: secret.credentialKey,\n value: secret.value,\n }));\n let envVarSync:\n | { status: \"synced\"; keys: string[] }\n | { status: \"skipped\"; reason: string }\n | { status: \"failed\"; reason: string };\n\n // Best-effort push to the app's env-vars endpoint for local/dev apps that\n // still read process.env directly. Production/shared-DB apps intentionally\n // reject env writes; the encrypted app_secrets sync above is the canonical\n // path for request-scoped credentials.\n if (!isTrustedEnvVarSyncAgentUrl(agent.url)) {\n envVarSync = {\n status: \"skipped\",\n reason: \"env-var sync is limited to localhost or workspace-owned apps\",\n };\n } else {\n try {\n const res = await ssrfSafeFetch(\n `${agent.url}/_agent-native/env-vars`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ vars }),\n signal: AbortSignal.timeout(10_000),\n },\n { maxRedirects: 3 },\n );\n\n if (res.ok) {\n const result = await res.json();\n envVarSync = { status: \"synced\", keys: result.saved || [] };\n } else {\n const err = await res.text().catch(() => \"Unknown error\");\n envVarSync = { status: \"skipped\", reason: err };\n }\n } catch (err) {\n envVarSync = {\n status: \"failed\",\n reason: err instanceof Error ? err.message : String(err),\n };\n }\n }\n\n const syncedKeys = credentialStoreSync.keys;\n const timestamp = now();\n\n // Update syncedAt on grants that were successfully pushed to the shared\n // credential store. All-apps mode has no explicit grant rows to update.\n for (const grant of activeGrants) {\n const secret = await getSecret(grant.secretId, ctx);\n if (secret && syncedKeys.includes(secret.credentialKey)) {\n await db\n .update(schema.vaultGrants)\n .set({ syncedAt: timestamp, updatedAt: timestamp })\n .where(eq(schema.vaultGrants.id, grant.id));\n }\n }\n\n await recordVaultAudit({\n action: \"secret.synced\",\n appId,\n summary: `Synced ${syncedKeys.length} secret(s) to ${appId}: ${syncedKeys.join(\", \")}`,\n metadata: {\n syncedKeys,\n accessMode: access.mode,\n credentialStore: {\n scope: credentialStoreSync.scope,\n scopeId: credentialStoreSync.scopeId,\n },\n envVars: envVarSync,\n },\n });\n\n return {\n appId,\n accessMode: access.mode,\n synced: syncedKeys.length,\n keys: syncedKeys,\n credentialStore: {\n scope: credentialStoreSync.scope,\n scopeId: credentialStoreSync.scopeId,\n synced: credentialStoreSync.keys.length,\n },\n envVars: envVarSync,\n };\n}\n\n// ─── Requests ──────────────────────────────────────────────────────\n\nexport async function listRequests(filter?: { status?: string }) {\n const db = getDb();\n const conditions = [scopedFilter(schema.vaultRequests)];\n if (filter?.status) {\n conditions.push(eq(schema.vaultRequests.status, filter.status) as any);\n }\n return db\n .select()\n .from(schema.vaultRequests)\n .where(and(...conditions))\n .orderBy(desc(schema.vaultRequests.updatedAt));\n}\n\nexport async function getRequest(\n requestId: string,\n ctx: VaultCtx = requireVaultCtx(),\n) {\n const db = getDb();\n const [row] = await db\n .select()\n .from(schema.vaultRequests)\n .where(\n and(\n eq(schema.vaultRequests.id, requestId),\n ctxScope(schema.vaultRequests, ctx),\n ),\n )\n .limit(1);\n return row ?? null;\n}\n\nexport async function createRequest(input: {\n credentialKey: string;\n appId: string;\n reason?: string | null;\n}) {\n const db = getDb();\n const timestamp = now();\n const requestId = id();\n const actor = currentOwnerEmail();\n\n await db.insert(schema.vaultRequests).values({\n id: requestId,\n ownerEmail: actor,\n orgId: currentOrgId(),\n credentialKey: input.credentialKey,\n appId: input.appId,\n reason: input.reason || null,\n requestedBy: actor,\n status: \"pending\",\n reviewedBy: null,\n reviewedAt: null,\n createdAt: timestamp,\n updatedAt: timestamp,\n });\n\n await recordVaultAudit({\n action: \"request.created\",\n appId: input.appId,\n summary: `${actor} requested ${input.credentialKey} for ${input.appId}`,\n metadata: { requestId, reason: input.reason },\n });\n\n await notifyAdminsOfRequest(requestId, input);\n\n return getRequest(requestId);\n}\n\nexport async function approveRequest(\n requestId: string,\n secretValue: string,\n secretName?: string,\n ctx: VaultCtx = requireVaultCtx(),\n) {\n const db = getDb();\n const request = await getRequest(requestId, ctx);\n if (!request) throw new Error(\"Request not found\");\n if (request.status !== \"pending\") {\n throw new Error(\"Only pending requests can be approved\");\n }\n\n const timestamp = now();\n const reviewer = ctx.ownerEmail;\n\n // Update request status — scoped to caller's tenant.\n await db\n .update(schema.vaultRequests)\n .set({\n status: \"approved\",\n reviewedBy: reviewer,\n reviewedAt: timestamp,\n updatedAt: timestamp,\n })\n .where(\n and(\n eq(schema.vaultRequests.id, requestId),\n ctxScope(schema.vaultRequests, ctx),\n ),\n );\n\n // Secret + grant must land in the REQUEST's tenant, not the approver's\n // (the approver may be acting on behalf of another user in the same org).\n const requestCtx = ctxForRow(request);\n\n // Check if secret already exists in the request's tenant for this key.\n const existingSecrets = await db\n .select()\n .from(schema.vaultSecrets)\n .where(\n and(\n eq(schema.vaultSecrets.credentialKey, request.credentialKey),\n ctxScope(schema.vaultSecrets, requestCtx),\n ),\n );\n let secret = existingSecrets[0] ?? null;\n\n if (!secret) {\n secret = await createSecret(\n {\n credentialKey: request.credentialKey,\n value: secretValue,\n name: secretName || request.credentialKey,\n },\n requestCtx,\n );\n }\n\n if (secret) {\n // Create the grant in the request's tenant as well.\n await createGrant(secret.id, request.appId, requestCtx);\n }\n\n await recordVaultAudit({\n action: \"request.approved\",\n appId: request.appId,\n summary: `Approved ${request.credentialKey} for ${request.appId} (requested by ${request.requestedBy})`,\n metadata: { requestId, reviewer },\n });\n\n return getRequest(requestId, ctx);\n}\n\nexport async function denyRequest(\n requestId: string,\n reason?: string | null,\n ctx: VaultCtx = requireVaultCtx(),\n) {\n const db = getDb();\n const request = await getRequest(requestId, ctx);\n if (!request) throw new Error(\"Request not found\");\n if (request.status !== \"pending\") {\n throw new Error(\"Only pending requests can be denied\");\n }\n\n const timestamp = now();\n const reviewer = ctx.ownerEmail;\n\n await db\n .update(schema.vaultRequests)\n .set({\n status: \"denied\",\n reviewedBy: reviewer,\n reviewedAt: timestamp,\n updatedAt: timestamp,\n })\n .where(\n and(\n eq(schema.vaultRequests.id, requestId),\n ctxScope(schema.vaultRequests, ctx),\n ),\n );\n\n await recordVaultAudit({\n action: \"request.denied\",\n appId: request.appId,\n summary: `Denied ${request.credentialKey} for ${request.appId} (requested by ${request.requestedBy})`,\n metadata: { requestId, reviewer, reason },\n });\n\n return getRequest(requestId, ctx);\n}\n\n// ─── Integrations Catalog ────────────────────────────────────────\n\nexport interface IntegrationEntry {\n key: string;\n label: string;\n required: boolean;\n configured: boolean;\n vaultGranted: boolean;\n vaultSecretId?: string;\n}\n\nexport interface AppIntegrations {\n appId: string;\n appName: string;\n url: string;\n color: string;\n integrations: IntegrationEntry[];\n vaultAccessMode: VaultAccessMode;\n reachable: boolean;\n}\n\nexport async function listIntegrationsCatalog(): Promise<AppIntegrations[]> {\n const access = await getVaultAccessSettings();\n const agents = await discoverAgents(\"dispatch\");\n const grants = await listGrants();\n const secrets = await listSecrets();\n\n const secretByKey = new Map(secrets.map((s) => [s.credentialKey, s]));\n\n const results: AppIntegrations[] = [];\n\n for (const agent of agents) {\n try {\n const res = await ssrfSafeFetch(\n `${agent.url}/_agent-native/env-status`,\n {\n signal: AbortSignal.timeout(3000),\n },\n { maxRedirects: 3 },\n );\n if (!res.ok) {\n results.push({\n appId: agent.id,\n appName: agent.name,\n url: agent.url,\n color: agent.color,\n integrations: [],\n vaultAccessMode: access.mode,\n reachable: false,\n });\n continue;\n }\n\n const envStatus: Array<{\n key: string;\n label: string;\n required: boolean;\n configured: boolean;\n }> = await res.json();\n\n const appGrants = grants.filter(\n (g) => g.appId === agent.id && g.status === \"active\",\n );\n const grantedSecretIds = new Set(appGrants.map((g) => g.secretId));\n\n const integrations: IntegrationEntry[] = envStatus.map((env) => {\n const matchingSecret = secretByKey.get(env.key);\n return {\n key: env.key,\n label: env.label,\n required: env.required,\n configured: env.configured,\n vaultGranted:\n !!matchingSecret &&\n (access.mode === \"all-apps\" ||\n grantedSecretIds.has(matchingSecret.id)),\n vaultSecretId: matchingSecret?.id,\n };\n });\n\n results.push({\n appId: agent.id,\n appName: agent.name,\n url: agent.url,\n color: agent.color,\n integrations,\n vaultAccessMode: access.mode,\n reachable: true,\n });\n } catch {\n results.push({\n appId: agent.id,\n appName: agent.name,\n url: agent.url,\n color: agent.color,\n integrations: [],\n vaultAccessMode: access.mode,\n reachable: false,\n });\n }\n }\n\n return results;\n}\n\n// ─── Vault Overview (for dashboard) ──────────────────────────────\n\nexport async function listVaultOverview() {\n const [secrets, grants, requests, access] = await Promise.all([\n listSecrets(),\n listGrants(),\n listRequests(),\n getVaultAccessSettings(),\n ]);\n const manualGrantCount = grants.filter((g) => g.status === \"active\").length;\n\n return {\n accessMode: access.mode,\n secretCount: secrets.length,\n activeGrantCount:\n access.mode === \"all-apps\" ? secrets.length : manualGrantCount,\n manualGrantCount,\n pendingRequestCount: requests.filter((r) => r.status === \"pending\").length,\n };\n}\n\n// ─── SendGrid Notifications ──────────────────────────────────────\n\nasync function notifyAdminsOfRequest(\n requestId: string,\n input: { credentialKey: string; appId: string; reason?: string | null },\n) {\n const apiKey = process.env.SENDGRID_API_KEY;\n const from = process.env.SENDGRID_FROM_EMAIL;\n const appUrl = process.env.APP_URL;\n if (!apiKey || !from || !appUrl) return;\n\n // Use approval policy approver emails as admin notification targets\n const { getApprovalPolicy } = await import(\"./dispatch-store.js\");\n const policy = await getApprovalPolicy();\n if (policy.approverEmails.length === 0) return;\n\n const body = [\n `Secret request: ${input.credentialKey} for ${input.appId}`,\n input.reason ? `Reason: ${input.reason}` : \"\",\n `Requested by: ${currentOwnerEmail()}`,\n \"\",\n `Review it here: ${appUrl}/vault`,\n ]\n .filter(Boolean)\n .join(\"\\n\");\n\n await fetch(\"https://api.sendgrid.com/v3/mail/send\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n personalizations: [\n {\n to: policy.approverEmails.map((email) => ({ email })),\n subject: `Vault request: ${input.credentialKey} for ${input.appId}`,\n },\n ],\n from: { email: from },\n content: [{ type: \"text/plain\", value: body }],\n custom_args: { requestId },\n }),\n }).catch(() => {});\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/dispatch",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.24",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Dispatch — workspace control plane for agent-native apps. Vault, integrations, destinations, scheduled jobs, and cross-app delegation, shipped as a single drop-in package.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -341,7 +341,7 @@ export function MessagingSetupPanel() {
|
|
|
341
341
|
try {
|
|
342
342
|
const action = enabled ? "disable" : "enable";
|
|
343
343
|
const res = await fetch(
|
|
344
|
-
`/_agent-native/integrations/${platform.id}/${action}
|
|
344
|
+
agentNativePath(`/_agent-native/integrations/${platform.id}/${action}`),
|
|
345
345
|
{
|
|
346
346
|
method: "POST",
|
|
347
347
|
},
|
|
@@ -371,7 +371,7 @@ export function MessagingSetupPanel() {
|
|
|
371
371
|
setSetupPlatform(platform.id);
|
|
372
372
|
try {
|
|
373
373
|
const res = await fetch(
|
|
374
|
-
`/_agent-native/integrations/${platform.id}/setup
|
|
374
|
+
agentNativePath(`/_agent-native/integrations/${platform.id}/setup`),
|
|
375
375
|
{
|
|
376
376
|
method: "POST",
|
|
377
377
|
},
|
|
@@ -422,7 +422,6 @@ export function MessagingSetupPanel() {
|
|
|
422
422
|
label: key,
|
|
423
423
|
required: true,
|
|
424
424
|
}));
|
|
425
|
-
const canEnable = configured;
|
|
426
425
|
|
|
427
426
|
return (
|
|
428
427
|
<section
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { useEffect, useRef } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
useLocation,
|
|
4
|
+
useNavigate,
|
|
5
|
+
type LoaderFunctionArgs,
|
|
6
|
+
} from "react-router";
|
|
3
7
|
import { AgentChatSurface } from "@agent-native/core/client";
|
|
4
8
|
import { submitOverviewPrompt } from "@/lib/overview-chat";
|
|
9
|
+
import {
|
|
10
|
+
buildThreadLinkPreviewMeta,
|
|
11
|
+
loadThreadLinkPreview,
|
|
12
|
+
} from "@/server/lib/thread-link-preview";
|
|
5
13
|
|
|
6
14
|
interface DispatchChatLocationState {
|
|
7
15
|
dispatchPrompt?: {
|
|
@@ -15,8 +23,17 @@ interface DispatchChatLocationState {
|
|
|
15
23
|
};
|
|
16
24
|
}
|
|
17
25
|
|
|
18
|
-
export function
|
|
19
|
-
|
|
26
|
+
export async function loader({ request }: LoaderFunctionArgs) {
|
|
27
|
+
const threadId = new URL(request.url).searchParams.get("thread");
|
|
28
|
+
return {
|
|
29
|
+
threadPreview: await loadThreadLinkPreview(threadId),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function meta({ data }: { data?: Awaited<ReturnType<typeof loader>> }) {
|
|
34
|
+
return data?.threadPreview
|
|
35
|
+
? buildThreadLinkPreviewMeta(data.threadPreview)
|
|
36
|
+
: [{ title: "Chat — Dispatch" }];
|
|
20
37
|
}
|
|
21
38
|
|
|
22
39
|
export default function ChatRoute() {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useEffect, useMemo, useState } from "react";
|
|
2
|
-
import { Link, useNavigate } from "react-router";
|
|
2
|
+
import { Link, useNavigate, type LoaderFunctionArgs } from "react-router";
|
|
3
3
|
import {
|
|
4
4
|
PromptComposer,
|
|
5
5
|
useActionQuery,
|
|
@@ -34,6 +34,10 @@ import {
|
|
|
34
34
|
TooltipTrigger,
|
|
35
35
|
} from "@/components/ui/tooltip";
|
|
36
36
|
import { submitOverviewPrompt } from "@/lib/overview-chat";
|
|
37
|
+
import {
|
|
38
|
+
buildThreadLinkPreviewMeta,
|
|
39
|
+
loadThreadLinkPreview,
|
|
40
|
+
} from "@/server/lib/thread-link-preview";
|
|
37
41
|
import type { WorkspaceAppSummary } from "@/lib/workspace-apps";
|
|
38
42
|
|
|
39
43
|
interface IntegrationStatus {
|
|
@@ -395,18 +399,18 @@ function StatCard({
|
|
|
395
399
|
cta?: React.ReactNode;
|
|
396
400
|
}) {
|
|
397
401
|
return (
|
|
398
|
-
<div className="rounded-2xl border bg-card p-5">
|
|
402
|
+
<div className="min-w-0 rounded-2xl border bg-card p-5">
|
|
399
403
|
<div className="flex items-start justify-between gap-3">
|
|
400
404
|
<div className="min-w-0">
|
|
401
|
-
<div className="flex items-center gap-1.5 text-sm font-medium text-foreground">
|
|
402
|
-
<span>{label}</span>
|
|
405
|
+
<div className="flex items-center gap-1.5 text-sm font-medium leading-snug text-foreground">
|
|
406
|
+
<span className="min-w-0">{label}</span>
|
|
403
407
|
<HelpTooltip content={help} />
|
|
404
408
|
</div>
|
|
405
409
|
<div className="mt-3 text-3xl font-semibold text-foreground">
|
|
406
410
|
{value}
|
|
407
411
|
</div>
|
|
408
412
|
</div>
|
|
409
|
-
<div className="rounded-xl border bg-muted/30 p-3 text-muted-foreground">
|
|
413
|
+
<div className="shrink-0 rounded-xl border bg-muted/30 p-3 text-muted-foreground">
|
|
410
414
|
<Icon size={18} />
|
|
411
415
|
</div>
|
|
412
416
|
</div>
|
|
@@ -471,8 +475,17 @@ function StepRow({ step }: { step: ChecklistStep }) {
|
|
|
471
475
|
);
|
|
472
476
|
}
|
|
473
477
|
|
|
474
|
-
export function
|
|
475
|
-
|
|
478
|
+
export async function loader({ request }: LoaderFunctionArgs) {
|
|
479
|
+
const threadId = new URL(request.url).searchParams.get("thread");
|
|
480
|
+
return {
|
|
481
|
+
threadPreview: await loadThreadLinkPreview(threadId),
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
export function meta({ data }: { data?: Awaited<ReturnType<typeof loader>> }) {
|
|
486
|
+
return data?.threadPreview
|
|
487
|
+
? buildThreadLinkPreviewMeta(data.threadPreview)
|
|
488
|
+
: [{ title: "Overview — Dispatch" }];
|
|
476
489
|
}
|
|
477
490
|
|
|
478
491
|
export default function OverviewRoute() {
|
|
@@ -636,7 +649,7 @@ export default function OverviewRoute() {
|
|
|
636
649
|
<IconActivity size={16} className="text-muted-foreground" />
|
|
637
650
|
<h2 className="text-sm font-semibold text-foreground">At a glance</h2>
|
|
638
651
|
</div>
|
|
639
|
-
<div className="grid
|
|
652
|
+
<div className="grid grid-cols-[repeat(auto-fit,minmax(min(100%,13rem),1fr))] gap-4">
|
|
640
653
|
<StatCard
|
|
641
654
|
label="Vault secrets"
|
|
642
655
|
help="Credentials stored in the workspace vault."
|
|
@@ -38,6 +38,21 @@ function slackIncoming(
|
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
function emailIncoming(
|
|
42
|
+
overrides: Partial<IncomingMessage> = {},
|
|
43
|
+
): IncomingMessage {
|
|
44
|
+
return {
|
|
45
|
+
platform: "email",
|
|
46
|
+
externalThreadId: "victim@member.test::<root@member.test>",
|
|
47
|
+
text: "transfer everything",
|
|
48
|
+
senderId: "victim@member.test",
|
|
49
|
+
senderName: "Victim",
|
|
50
|
+
platformContext: { from: "victim@member.test" },
|
|
51
|
+
timestamp: 1,
|
|
52
|
+
...overrides,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
41
56
|
beforeEach(() => {
|
|
42
57
|
mocks.resolveLinkedOwner.mockResolvedValue(null);
|
|
43
58
|
mocks.consumeLinkToken.mockResolvedValue("owner@example.test");
|
|
@@ -113,4 +128,58 @@ describe("resolveDispatchOwner", () => {
|
|
|
113
128
|
"default@example.test",
|
|
114
129
|
);
|
|
115
130
|
});
|
|
131
|
+
|
|
132
|
+
it("does NOT impersonate an org member from an unverified (spoofed) email From", async () => {
|
|
133
|
+
// Attacker spoofs From: victim@member.test, which IS a real org member —
|
|
134
|
+
// but the message is unverified (no DKIM/SPF pass). Must fall through to
|
|
135
|
+
// the synthetic, credential-less owner, NOT the victim's identity.
|
|
136
|
+
mocks.resolveOrgIdForEmail.mockResolvedValue("org_123");
|
|
137
|
+
|
|
138
|
+
const owner = await resolveDispatchOwner(
|
|
139
|
+
emailIncoming({ senderVerified: false }),
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
expect(owner).not.toBe("victim@member.test");
|
|
143
|
+
expect(owner).toMatch(/@integration\.local$/);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("does NOT impersonate when sender is verified but not an org member", async () => {
|
|
147
|
+
mocks.resolveOrgIdForEmail.mockResolvedValue(null);
|
|
148
|
+
|
|
149
|
+
const owner = await resolveDispatchOwner(
|
|
150
|
+
emailIncoming({
|
|
151
|
+
senderId: "stranger@outside.test",
|
|
152
|
+
platformContext: { from: "stranger@outside.test" },
|
|
153
|
+
senderVerified: true,
|
|
154
|
+
}),
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
expect(owner).not.toBe("stranger@outside.test");
|
|
158
|
+
expect(owner).toMatch(/@integration\.local$/);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("uses the email sender as owner when verified AND an org member", async () => {
|
|
162
|
+
mocks.resolveOrgIdForEmail.mockResolvedValue("org_123");
|
|
163
|
+
|
|
164
|
+
await expect(
|
|
165
|
+
resolveDispatchOwner(emailIncoming({ senderVerified: true })),
|
|
166
|
+
).resolves.toBe("victim@member.test");
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("honors a linked identity for email regardless of verification", async () => {
|
|
170
|
+
mocks.resolveLinkedOwner.mockResolvedValueOnce("linked@member.test");
|
|
171
|
+
|
|
172
|
+
await expect(
|
|
173
|
+
resolveDispatchOwner(emailIncoming({ senderVerified: false })),
|
|
174
|
+
).resolves.toBe("linked@member.test");
|
|
175
|
+
expect(mocks.resolveOrgIdForEmail).not.toHaveBeenCalled();
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it("restores legacy trust-From behavior under the escape hatch", async () => {
|
|
179
|
+
vi.stubEnv("DISPATCH_TRUST_UNVERIFIED_EMAIL_SENDER", "1");
|
|
180
|
+
|
|
181
|
+
await expect(
|
|
182
|
+
resolveDispatchOwner(emailIncoming({ senderVerified: false })),
|
|
183
|
+
).resolves.toBe("victim@member.test");
|
|
184
|
+
});
|
|
116
185
|
});
|
|
@@ -164,14 +164,37 @@ export async function resolveDispatchOwner(
|
|
|
164
164
|
});
|
|
165
165
|
if (owner) return owner;
|
|
166
166
|
|
|
167
|
-
// For email, the sender's
|
|
168
|
-
//
|
|
167
|
+
// For email, the sender's `From:` address is attacker-settable: SMTP lets
|
|
168
|
+
// anyone claim any From, and our inbound webhook secret only authenticates
|
|
169
|
+
// the provider→app hop, not the original sender. So we must NOT grant a
|
|
170
|
+
// real user's identity (their API keys, org secrets, personal
|
|
171
|
+
// instructions, ownable data) off the bare From. Mirror the Slack gate:
|
|
172
|
+
// only return the sender email as the acting owner when BOTH
|
|
173
|
+
// (a) the message is DKIM/SPF-verified for the From domain, AND
|
|
174
|
+
// (b) that email maps to a real org member.
|
|
175
|
+
// Otherwise fall through to the synthetic, credential-less fallback owner.
|
|
176
|
+
// (A linked identity, handled by resolveLinkedOwner above, remains an
|
|
177
|
+
// always-allowed way to bind an address regardless of verification.)
|
|
178
|
+
//
|
|
179
|
+
// Escape hatch: set DISPATCH_TRUST_UNVERIFIED_EMAIL_SENDER=1 to restore
|
|
180
|
+
// the legacy "trust the From header" behavior. OFF by default; only use
|
|
181
|
+
// this if you fully control the inbound mail path and accept that a
|
|
182
|
+
// spoofed From can act as any org member. See FINDING 3 (inbound-email
|
|
183
|
+
// impersonation) in the webhook security audit.
|
|
169
184
|
if (
|
|
170
185
|
incoming.platform === "email" &&
|
|
171
186
|
incoming.senderId &&
|
|
172
187
|
incoming.senderId.includes("@")
|
|
173
188
|
) {
|
|
174
|
-
|
|
189
|
+
if (process.env.DISPATCH_TRUST_UNVERIFIED_EMAIL_SENDER === "1") {
|
|
190
|
+
return incoming.senderId;
|
|
191
|
+
}
|
|
192
|
+
if (incoming.senderVerified) {
|
|
193
|
+
const orgId = await resolveOrgIdForEmail(incoming.senderId);
|
|
194
|
+
if (orgId) return incoming.senderId;
|
|
195
|
+
}
|
|
196
|
+
// Unverified or not an org member — do not impersonate. Fall through to
|
|
197
|
+
// the synthetic fallback owner below.
|
|
175
198
|
}
|
|
176
199
|
|
|
177
200
|
// Slack gives us a user id in the event payload. Resolve it to a verified
|
|
@@ -156,12 +156,6 @@ function safeAppOrigin(app: DispatchMcpAccessibleApp): string | null {
|
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
function appOrigin(app: DispatchMcpAccessibleApp): string {
|
|
160
|
-
const origin = safeAppOrigin(app);
|
|
161
|
-
if (!origin) throw new Error(`Invalid app URL for "${app.id}": ${app.url}`);
|
|
162
|
-
return origin;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
159
|
function appBaseUrl(app: DispatchMcpAccessibleApp): string {
|
|
166
160
|
return app.url.replace(/\/+$/, "");
|
|
167
161
|
}
|