Skip to content

Commit dfe5c6f

Browse files
feat(custom-block): run child under source owner's identity, workspace, and env
1 parent 3be6122 commit dfe5c6f

1 file changed

Lines changed: 26 additions & 3 deletions

File tree

apps/sim/executor/handlers/workflow/workflow-handler.ts

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { createLogger } from '@sim/logger'
22
import { getErrorMessage } from '@sim/utils/errors'
33
import { generateId } from '@sim/utils/id'
4+
import { getPersonalAndWorkspaceEnv } from '@/lib/environment/utils'
45
import { buildNextCallChain, validateCallChain } from '@/lib/execution/call-chain'
56
import { snapshotService } from '@/lib/logs/execution/snapshot/service'
67
import { buildTraceSpans } from '@/lib/logs/execution/trace-spans/trace-spans'
@@ -239,10 +240,32 @@ export class WorkflowBlockHandler implements BlockHandler {
239240
)
240241
}
241242

243+
// A custom block is an invocation boundary: the child runs under the SOURCE
244+
// workflow owner's identity, workspace, and environment — not the consumer's —
245+
// so it resolves credentials/integrations/env exactly as published and the
246+
// consumer needs no access to any of them. (Billing still lands on the
247+
// consumer's org, aggregated onto the block above.) Regular workflow blocks
248+
// keep running in the parent's context.
249+
let childUserId = ctx.userId
250+
let childWorkspaceId = ctx.workspaceId
251+
let childEnvVarValues = ctx.environmentVariables
252+
if (isCustomBlock) {
253+
if (!loadUserId) {
254+
throw new Error('Custom block source workflow has no owner')
255+
}
256+
if (!childWorkflow.workspaceId) {
257+
throw new Error('Custom block source workflow has no workspace')
258+
}
259+
childUserId = loadUserId
260+
childWorkspaceId = childWorkflow.workspaceId
261+
const ownerEnv = await getPersonalAndWorkspaceEnv(loadUserId, childWorkflow.workspaceId)
262+
childEnvVarValues = { ...ownerEnv.personalDecrypted, ...ownerEnv.workspaceDecrypted }
263+
}
264+
242265
const subExecutor = new Executor({
243266
workflow: childWorkflow.serializedState,
244267
workflowInput: childWorkflowInput,
245-
envVarValues: ctx.environmentVariables,
268+
envVarValues: childEnvVarValues,
246269
workflowVariables: childWorkflow.variables || {},
247270
contextExtensions: {
248271
isChildExecution: true,
@@ -251,8 +274,8 @@ export class WorkflowBlockHandler implements BlockHandler {
251274
// deployed graph as draft. `useDeployed` folds in the custom-block case.
252275
isDeployedContext: useDeployed,
253276
enforceCredentialAccess: ctx.enforceCredentialAccess,
254-
workspaceId: ctx.workspaceId,
255-
userId: ctx.userId,
277+
workspaceId: childWorkspaceId,
278+
userId: childUserId,
256279
executionId: ctx.executionId,
257280
abortSignal: ctx.abortSignal,
258281
// Propagate in-flight block-output redaction into child workflows so

0 commit comments

Comments
 (0)