d25d482dc2
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
152 lines
4.9 KiB
TypeScript
152 lines
4.9 KiB
TypeScript
import { createLogger } from '@sim/logger'
|
|
import { z } from 'zod'
|
|
import { SetEnvironmentVariables } from '@/lib/copilot/generated/tool-catalog-v1'
|
|
import {
|
|
ensureWorkflowAccess,
|
|
ensureWorkspaceAccess,
|
|
getDefaultWorkspaceId,
|
|
} from '@/lib/copilot/tools/handlers/access'
|
|
import type { BaseServerTool, ServerToolContext } from '@/lib/copilot/tools/server/base-tool'
|
|
import { upsertPersonalEnvVars, upsertWorkspaceEnvVars } from '@/lib/environment/utils'
|
|
|
|
type EnvironmentVariableInputValue = string | number | boolean | null | undefined
|
|
|
|
interface EnvironmentVariableInput {
|
|
name: string
|
|
value: EnvironmentVariableInputValue
|
|
}
|
|
|
|
interface SetEnvironmentVariablesParams {
|
|
variables: Record<string, EnvironmentVariableInputValue> | EnvironmentVariableInput[]
|
|
scope?: 'personal' | 'workspace'
|
|
workflowId?: string
|
|
workspaceId?: string
|
|
}
|
|
|
|
interface SetEnvironmentVariablesResult {
|
|
message: string
|
|
scope: 'personal' | 'workspace'
|
|
workspaceId?: string
|
|
variableCount: number
|
|
variableNames: string[]
|
|
addedVariables: string[]
|
|
updatedVariables: string[]
|
|
workspaceUpdatedVariables: string[]
|
|
}
|
|
|
|
const EnvVarSchema = z.object({ variables: z.record(z.string(), z.string()) })
|
|
|
|
function normalizeVariables(
|
|
input: Record<string, EnvironmentVariableInputValue> | EnvironmentVariableInput[]
|
|
): Record<string, string> {
|
|
if (Array.isArray(input)) {
|
|
return input.reduce(
|
|
(acc, item) => {
|
|
if (item && typeof item.name === 'string') {
|
|
acc[item.name] = String(item.value ?? '')
|
|
}
|
|
return acc
|
|
},
|
|
{} as Record<string, string>
|
|
)
|
|
}
|
|
return Object.fromEntries(
|
|
Object.entries(input || {}).map(([k, v]) => [k, String(v ?? '')])
|
|
) as Record<string, string>
|
|
}
|
|
|
|
async function resolveWorkspaceId(
|
|
params: SetEnvironmentVariablesParams,
|
|
context: ServerToolContext | undefined,
|
|
userId: string
|
|
): Promise<string> {
|
|
if (params.workflowId) {
|
|
const { workflow } = await ensureWorkflowAccess(params.workflowId, userId, 'write')
|
|
if (!workflow.workspaceId) {
|
|
throw new Error(`Workflow ${params.workflowId} is not associated with a workspace`)
|
|
}
|
|
return workflow.workspaceId
|
|
}
|
|
|
|
const workspaceId = params.workspaceId ?? context?.workspaceId
|
|
if (workspaceId) {
|
|
await ensureWorkspaceAccess(workspaceId, userId, 'write')
|
|
return workspaceId
|
|
}
|
|
|
|
return getDefaultWorkspaceId(userId)
|
|
}
|
|
|
|
export const setEnvironmentVariablesServerTool: BaseServerTool<
|
|
SetEnvironmentVariablesParams,
|
|
SetEnvironmentVariablesResult
|
|
> = {
|
|
name: SetEnvironmentVariables.id,
|
|
async execute(
|
|
params: SetEnvironmentVariablesParams,
|
|
context?: ServerToolContext
|
|
): Promise<SetEnvironmentVariablesResult> {
|
|
const logger = createLogger('SetEnvironmentVariablesServerTool')
|
|
|
|
if (!context?.userId) {
|
|
logger.error(
|
|
'Unauthorized attempt to set environment variables - no authenticated user context'
|
|
)
|
|
throw new Error('Authentication required')
|
|
}
|
|
|
|
const authenticatedUserId = context.userId
|
|
const { variables } = params || ({} as SetEnvironmentVariablesParams)
|
|
const scope = params.scope === 'personal' ? 'personal' : 'workspace'
|
|
|
|
const normalized = normalizeVariables(variables || {})
|
|
const { variables: validatedVariables } = EnvVarSchema.parse({ variables: normalized })
|
|
const variableNames = Object.keys(validatedVariables)
|
|
const added: string[] = []
|
|
const updated: string[] = []
|
|
let workspaceUpdated: string[] = []
|
|
|
|
let resolvedWorkspaceId: string | undefined
|
|
if (scope === 'workspace') {
|
|
resolvedWorkspaceId = await resolveWorkspaceId(params, context, authenticatedUserId)
|
|
workspaceUpdated = await upsertWorkspaceEnvVars(
|
|
resolvedWorkspaceId,
|
|
validatedVariables,
|
|
authenticatedUserId
|
|
)
|
|
} else {
|
|
const result = await upsertPersonalEnvVars(authenticatedUserId, validatedVariables)
|
|
added.push(...result.added)
|
|
updated.push(...result.updated)
|
|
}
|
|
|
|
const totalProcessed = added.length + updated.length + workspaceUpdated.length
|
|
|
|
logger.info('Saved environment variables', {
|
|
userId: authenticatedUserId,
|
|
scope,
|
|
addedCount: added.length,
|
|
updatedCount: updated.length,
|
|
workspaceUpdatedCount: workspaceUpdated.length,
|
|
workspaceId: resolvedWorkspaceId,
|
|
})
|
|
|
|
const parts: string[] = []
|
|
if (added.length > 0) parts.push(`${added.length} personal secret(s) added`)
|
|
if (updated.length > 0) parts.push(`${updated.length} personal secret(s) updated`)
|
|
if (workspaceUpdated.length > 0)
|
|
parts.push(`${workspaceUpdated.length} workspace secret(s) updated`)
|
|
|
|
return {
|
|
message: `Successfully processed ${totalProcessed} secret(s): ${parts.join(', ')}`,
|
|
scope,
|
|
workspaceId: resolvedWorkspaceId,
|
|
variableCount: variableNames.length,
|
|
variableNames,
|
|
addedVariables: added,
|
|
updatedVariables: updated,
|
|
workspaceUpdatedVariables: workspaceUpdated,
|
|
}
|
|
},
|
|
}
|