@@ -43,6 +43,10 @@ import {
4343 type StreamingExecution ,
4444} from '@/executor/types'
4545import { streamingResponseFormatProcessor } from '@/executor/utils'
46+ import {
47+ createEnvironmentSecretSanitizer ,
48+ type EnvironmentSecretSanitizer ,
49+ } from '@/executor/utils/environment-secret-sanitizer'
4650import { buildBlockExecutionError , normalizeError } from '@/executor/utils/errors'
4751import {
4852 buildUnifiedParentIterations ,
@@ -100,6 +104,10 @@ export class BlockExecutor {
100104
101105 const blockType = block . metadata ?. id ?? ''
102106 const isSentinel = isSentinelBlockType ( blockType )
107+ const sanitizeEnvironmentSecrets = createEnvironmentSecretSanitizer (
108+ block . config ,
109+ ctx . environmentVariables
110+ )
103111
104112 // Capture startedAt and startTime at the same synchronous instant so
105113 // blockLog.startedAt and performance.now()-derived durationMs share a
@@ -159,7 +167,11 @@ export class BlockExecutor {
159167 }
160168
161169 if ( blockLog ) {
162- blockLog . input = this . sanitizeInputsForLog ( inputsForLog , block . metadata ?. id )
170+ blockLog . input = this . sanitizeInputsForLog (
171+ inputsForLog ,
172+ sanitizeEnvironmentSecrets ,
173+ block . metadata ?. id
174+ )
163175 }
164176 } catch ( error ) {
165177 cleanupSelfReference ?.( )
@@ -173,6 +185,7 @@ export class BlockExecutor {
173185 blockLog ,
174186 inputsForLog ,
175187 isSentinel ,
188+ sanitizeEnvironmentSecrets ,
176189 'input_resolution'
177190 )
178191 }
@@ -277,9 +290,13 @@ export class BlockExecutor {
277290 blockLog . endedAt = endedAt
278291 blockLog . durationMs = duration
279292 blockLog . success = true
280- blockLog . output = filterOutputForLog ( block . metadata ?. id || '' , normalizedOutput , { block } )
293+ blockLog . output = this . sanitizeOutputForLog (
294+ block ,
295+ normalizedOutput ,
296+ sanitizeEnvironmentSecrets
297+ )
281298 if ( normalizedOutput . childTraceSpans && Array . isArray ( normalizedOutput . childTraceSpans ) ) {
282- blockLog . childTraceSpans = normalizedOutput . childTraceSpans
299+ blockLog . childTraceSpans = sanitizeEnvironmentSecrets ( normalizedOutput . childTraceSpans )
283300 }
284301 }
285302
@@ -291,15 +308,17 @@ export class BlockExecutor {
291308 typeof normalizedOutput . _childWorkflowInstanceId === 'string'
292309 ? normalizedOutput . _childWorkflowInstanceId
293310 : undefined
294- const displayOutput = filterOutputForLog ( block . metadata ?. id || '' , normalizedOutput , {
311+ const displayOutput = this . sanitizeOutputForLog (
295312 block ,
296- } )
313+ normalizedOutput ,
314+ sanitizeEnvironmentSecrets
315+ )
297316 this . fireBlockCompleteCallback (
298317 blockStartPromise ,
299318 ctx ,
300319 node ,
301320 block ,
302- this . sanitizeInputsForLog ( inputsForLog , block . metadata ?. id ) ,
321+ this . sanitizeInputsForLog ( inputsForLog , sanitizeEnvironmentSecrets , block . metadata ?. id ) ,
303322 displayOutput ,
304323 duration ,
305324 blockLog . startedAt ,
@@ -321,6 +340,7 @@ export class BlockExecutor {
321340 blockLog ,
322341 inputsForLog ,
323342 isSentinel ,
343+ sanitizeEnvironmentSecrets ,
324344 'execution' ,
325345 streamingPartialOutput
326346 )
@@ -379,12 +399,14 @@ export class BlockExecutor {
379399 blockLog : BlockLog | undefined ,
380400 inputsForLog : Record < string , any > ,
381401 isSentinel : boolean ,
402+ sanitizeEnvironmentSecrets : EnvironmentSecretSanitizer ,
382403 phase : 'input_resolution' | 'execution' ,
383404 streamingPartialOutput ?: Record < string , any >
384405 ) : Promise < NormalizedBlockOutput > {
385406 const endedAt = new Date ( ) . toISOString ( )
386407 const duration = performance . now ( ) - startTime
387408 const errorMessage = normalizeError ( error )
409+ const sanitizedErrorMessage = sanitizeEnvironmentSecrets ( errorMessage )
388410 const hasLogInputs =
389411 inputsForLog && typeof inputsForLog === 'object' && Object . keys ( inputsForLog ) . length > 0
390412 const input = hasLogInputs
@@ -412,8 +434,12 @@ export class BlockExecutor {
412434 blockLog . durationMs = duration
413435 blockLog . success = true
414436 blockLog . error = undefined
415- blockLog . input = this . sanitizeInputsForLog ( input , block . metadata ?. id )
416- blockLog . output = filterOutputForLog ( block . metadata ?. id || '' , softOutput , { block } )
437+ blockLog . input = this . sanitizeInputsForLog (
438+ input ,
439+ sanitizeEnvironmentSecrets ,
440+ block . metadata ?. id
441+ )
442+ blockLog . output = this . sanitizeOutputForLog ( block , softOutput , sanitizeEnvironmentSecrets )
417443 }
418444
419445 this . execLogger . info ( 'Block stream aborted by client; soft-completing' , {
@@ -427,8 +453,8 @@ export class BlockExecutor {
427453 ctx ,
428454 node ,
429455 block ,
430- this . sanitizeInputsForLog ( input , block . metadata ?. id ) ,
431- filterOutputForLog ( block . metadata ?. id || '' , softOutput , { block } ) ,
456+ this . sanitizeInputsForLog ( input , sanitizeEnvironmentSecrets , block . metadata ?. id ) ,
457+ this . sanitizeOutputForLog ( block , softOutput , sanitizeEnvironmentSecrets ) ,
432458 duration ,
433459 blockLog . startedAt ,
434460 blockLog . executionOrder ,
@@ -463,12 +489,16 @@ export class BlockExecutor {
463489 blockLog . endedAt = endedAt
464490 blockLog . durationMs = duration
465491 blockLog . success = false
466- blockLog . error = errorMessage
467- blockLog . input = this . sanitizeInputsForLog ( input , block . metadata ?. id )
468- blockLog . output = filterOutputForLog ( block . metadata ?. id || '' , errorOutput , { block } )
492+ blockLog . error = sanitizedErrorMessage
493+ blockLog . input = this . sanitizeInputsForLog (
494+ input ,
495+ sanitizeEnvironmentSecrets ,
496+ block . metadata ?. id
497+ )
498+ blockLog . output = this . sanitizeOutputForLog ( block , errorOutput , sanitizeEnvironmentSecrets )
469499
470500 if ( ChildWorkflowError . isChildWorkflowError ( error ) && error . childTraceSpans . length > 0 ) {
471- blockLog . childTraceSpans = error . childTraceSpans
501+ blockLog . childTraceSpans = sanitizeEnvironmentSecrets ( error . childTraceSpans )
472502 }
473503 }
474504
@@ -477,21 +507,25 @@ export class BlockExecutor {
477507 {
478508 blockId : node . id ,
479509 blockType : block . metadata ?. id ,
480- error : errorMessage ,
510+ error : sanitizedErrorMessage ,
481511 }
482512 )
483513
484514 if ( ! isSentinel && blockLog ) {
485515 const childWorkflowInstanceId = ChildWorkflowError . isChildWorkflowError ( error )
486516 ? error . childWorkflowInstanceId
487517 : undefined
488- const displayOutput = filterOutputForLog ( block . metadata ?. id || '' , errorOutput , { block } )
518+ const displayOutput = this . sanitizeOutputForLog (
519+ block ,
520+ errorOutput ,
521+ sanitizeEnvironmentSecrets
522+ )
489523 this . fireBlockCompleteCallback (
490524 blockStartPromise ,
491525 ctx ,
492526 node ,
493527 block ,
494- this . sanitizeInputsForLog ( input , block . metadata ?. id ) ,
528+ this . sanitizeInputsForLog ( input , sanitizeEnvironmentSecrets , block . metadata ?. id ) ,
495529 displayOutput ,
496530 duration ,
497531 blockLog . startedAt ,
@@ -508,7 +542,7 @@ export class BlockExecutor {
508542 }
509543 this . execLogger . info ( 'Block has error port - returning error output instead of throwing' , {
510544 blockId : node . id ,
511- error : errorMessage ,
545+ error : sanitizedErrorMessage ,
512546 } )
513547 return errorOutput
514548 }
@@ -615,6 +649,7 @@ export class BlockExecutor {
615649 */
616650 private sanitizeInputsForLog (
617651 inputs : Record < string , any > ,
652+ sanitizeEnvironmentSecrets : EnvironmentSecretSanitizer ,
618653 blockType ?: string
619654 ) : Record < string , any > {
620655 // Custom (deploy-as-block) blocks run via an internal `workflow_executor`; the
@@ -671,7 +706,20 @@ export class BlockExecutor {
671706 }
672707 }
673708
674- return redactApiKeys ( result )
709+ return sanitizeEnvironmentSecrets ( redactApiKeys ( result ) )
710+ }
711+
712+ /**
713+ * Builds the display-only output shared by persisted logs and live callbacks.
714+ * Runtime output remains untouched for state, handlers, retries, and resume.
715+ */
716+ private sanitizeOutputForLog (
717+ block : SerializedBlock ,
718+ output : NormalizedBlockOutput ,
719+ sanitizeEnvironmentSecrets : EnvironmentSecretSanitizer
720+ ) : NormalizedBlockOutput {
721+ const filteredOutput = filterOutputForLog ( block . metadata ?. id ?? '' , output , { block } )
722+ return sanitizeEnvironmentSecrets ( redactApiKeys ( filteredOutput ) ) as NormalizedBlockOutput
675723 }
676724
677725 /**
0 commit comments