Skip to content

Commit 9c0e642

Browse files
committed
fix(api): withhold resolved pause input fields from viewers whose group hides execution data
1 parent 123a182 commit 9c0e642

5 files changed

Lines changed: 13 additions & 10 deletions

File tree

‎apps/docs/content/docs/workflows/deployment/api.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ A completed response includes the result when requested:
260260

261261
Stop polling on `completed`, `failed`, or `cancelled`. A paused Human run requires submitted input; a time pause can resume automatically. See [Human](/workflows/blocks/human-in-the-loop) and [Wait](/workflows/blocks/wait). Resuming an originally streaming run through the v2 resume endpoint returns an async receipt, not an SSE continuation.
262262

263-
A paused run lists every point it waits at in `paused.points`: the block, whether it is a `human` or `time` pause, its resume state, any parallel branch or loop iteration, its place in the resume queue, and the `inputFields` a Human pause asks for. With `includeOutput=true`, each point also carries the reviewer `display` content with resolved secrets redacted; organization permission groups that hide execution data withhold it. Resume a point by sending its `contextId` to `POST /api/v2/workflows/{workflow-id}/runs/{runId}/resume`.
263+
A paused run lists every point it waits at in `paused.points`: the block, whether it is a `human` or `time` pause, its resume state, any parallel branch or loop iteration, its place in the resume queue, and the `inputFields` a Human pause asks for. With `includeOutput=true`, each point also carries the reviewer `display` content with resolved secrets redacted; organization permission groups that hide execution data withhold it, along with `inputFields`, whose labels and descriptions are resolved from run data. Resume a point by sending its `contextId` to `POST /api/v2/workflows/{workflow-id}/runs/{runId}/resume`.
264264

265265
## Select outputs and handle large values [#oversized-outputs]
266266

‎apps/docs/openapi-v2-workflows.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15381,7 +15381,7 @@
1538115381
"type": "null"
1538215382
}
1538315383
],
15384-
"description": "Fields a human pause asks for, without default values. Null for a time pause, a pause with no declared form, fields over 64 KiB or not provably free of secrets, or one recorded before pause details were captured."
15384+
"description": "Fields a human pause asks for, without default values. Labels and descriptions are resolved, so they are withheld when organization permission groups hide execution data. Null then, for a time pause, a pause with no declared form, fields over 64 KiB or not provably free of secrets, or one recorded before pause details were captured."
1538515385
},
1538615386
"display": {
1538715387
"anyOf": [

‎apps/sim/lib/api/contracts/v2/workflows.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2096,7 +2096,7 @@ const v2WorkflowRunPausePointSchema = z
20962096
.array(v2PauseInputFieldSchema)
20972097
.nullable()
20982098
.describe(
2099-
'Fields a human pause asks for, without default values. Null for a time pause, a pause with no declared form, fields over 64 KiB or not provably free of secrets, or one recorded before pause details were captured.'
2099+
'Fields a human pause asks for, without default values. Labels and descriptions are resolved, so they are withheld when organization permission groups hide execution data. Null then, for a time pause, a pause with no declared form, fields over 64 KiB or not provably free of secrets, or one recorded before pause details were captured.'
21002100
),
21012101
display: z
21022102
.unknown()

‎apps/sim/lib/workflows/application/read-workflow-run-pause.integration.ts‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -279,12 +279,10 @@ describe('a deployed run paused at a human-in-the-loop block', () => {
279279
])
280280
})
281281

282-
it('withholds reviewer content from a viewer whose group hides execution data', async () => {
282+
it('withholds reviewer content and resolved input fields from a viewer whose group hides execution data', async () => {
283283
const runId = await pausedRun()
284284

285285
const run = await readRun(restricted, runId, { includeOutput: true })
286-
expect(run.pausePoints).toEqual([
287-
expect.objectContaining({ display: null, inputFields: INPUT_FIELDS }),
288-
])
286+
expect(run.pausePoints).toEqual([expect.objectContaining({ display: null, inputFields: null })])
289287
})
290288
})

‎apps/sim/lib/workflows/application/read-workflow-run.ts‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,9 @@ export const readWorkflowRun = defineAuthorizedWorkflowUseCase({
157157
*
158158
* A point's `display` is what the block rendered from upstream outputs, so it
159159
* follows `finalOutput`'s gating: withheld unless output was asked for and the
160-
* viewer's group shows execution data. `inputFields` are the block's own
161-
* configuration and stay.
160+
* viewer's group shows execution data. `inputFields` are resolved before the
161+
* pause is captured, so a label or description can carry upstream values too:
162+
* they are withheld from a viewer whose group hides execution data.
162163
*
163164
* permission-group-enforced: logs.trace_spans
164165
*/
@@ -169,7 +170,11 @@ export const readWorkflowRun = defineAuthorizedWorkflowUseCase({
169170
workflowId: context.workflowId,
170171
executionId: context.runId,
171172
})) ?? []
172-
).map((point) => (showsDisplay ? point : { ...point, display: null }))
173+
).map((point) => ({
174+
...point,
175+
display: showsDisplay ? point.display : null,
176+
inputFields: projection.hideTraceSpans ? null : point.inputFields,
177+
}))
173178
: null
174179

175180
return { ...status, files, pausePoints }

0 commit comments

Comments
 (0)