Skip to content

fix(engine): redact sensitive workflow result logs#745

Merged
intel352 merged 2 commits into
mainfrom
fix/engine-result-log-redaction
May 20, 2026
Merged

fix(engine): redact sensitive workflow result logs#745
intel352 merged 2 commits into
mainfrom
fix/engine-result-log-redaction

Conversation

@intel352
Copy link
Copy Markdown
Contributor

Summary

  • redact workflow result values before debug logging in TriggerWorkflow
  • keep raw results available to PipelineResultHolder/event consumers
  • extend step-output redaction through arrays of result objects

Verification

  • GOWORK=off go test ./ -run 'TestEngineTriggerWorkflow|TestEngine_TriggerWorkflow|TestRedactStepOutput' -count=1\n- GOWORK=off go test ./... -count=1\n\n## Context\nStaging log capture showed token-shaped workflow outputs in app logs. This keeps log artifacts useful without leaking JWT/API-key/password-shaped values.

Copilot AI review requested due to automatic review settings May 20, 2026 16:24
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to prevent sensitive workflow result values from being written to application logs by redacting result maps before debug logging in StdEngine.TriggerWorkflow, while still preserving raw results for downstream consumers (e.g., PipelineResultHolder).

Changes:

  • Redact workflow execution results before emitting per-key debug logs in TriggerWorkflow.
  • Extend step-output redaction to recurse into nested []any values.
  • Add tests covering nested slice redaction and ensuring debug logs don’t leak sensitive result values.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
module/step_output_redactor.go Adds redactValue helper to recursively redact nested values, including []any.
module/step_output_redactor_test.go Adds a test to verify redaction works for nested slices of any.
engine.go Uses module.RedactStepOutput(results) before debug-logging workflow results.
engine_test.go Adds a test ensuring debug logs redact sensitive result values while PipelineResultHolder retains raw results.

Comment thread module/step_output_redactor.go
Comment thread module/step_output_redactor_test.go
Comment thread engine.go
@codecov
Copy link
Copy Markdown

codecov Bot commented May 20, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 20, 2026

⏱ Benchmark Results

No significant performance regressions detected.

benchstat comparison (baseline → PR)
## benchstat: baseline → PR
baseline-bench.txt:276: parsing iteration count: invalid syntax
baseline-bench.txt:311575: parsing iteration count: invalid syntax
baseline-bench.txt:548255: parsing iteration count: invalid syntax
baseline-bench.txt:831597: parsing iteration count: invalid syntax
baseline-bench.txt:1192189: parsing iteration count: invalid syntax
baseline-bench.txt:1525577: parsing iteration count: invalid syntax
benchmark-results.txt:276: parsing iteration count: invalid syntax
benchmark-results.txt:278365: parsing iteration count: invalid syntax
benchmark-results.txt:605714: parsing iteration count: invalid syntax
benchmark-results.txt:889137: parsing iteration count: invalid syntax
benchmark-results.txt:1239634: parsing iteration count: invalid syntax
benchmark-results.txt:1510232: parsing iteration count: invalid syntax
goos: linux
goarch: amd64
pkg: github.com/GoCodeAlone/workflow/dynamic
cpu: AMD EPYC 7763 64-Core Processor                
                            │ baseline-bench.txt │       benchmark-results.txt        │
                            │       sec/op       │    sec/op     vs base              │
InterpreterCreation-4               7.581m ± 59%   8.045m ± 62%       ~ (p=0.818 n=6)
ComponentLoad-4                     3.556m ±  1%   3.532m ±  1%  -0.69% (p=0.041 n=6)
ComponentExecute-4                  1.891µ ±  0%   1.897µ ±  4%       ~ (p=0.364 n=6)
PoolContention/workers-1-4          1.065µ ±  1%   1.063µ ±  2%       ~ (p=0.431 n=6)
PoolContention/workers-2-4          1.067µ ±  1%   1.066µ ±  0%       ~ (p=0.420 n=6)
PoolContention/workers-4-4          1.071µ ±  1%   1.068µ ±  1%       ~ (p=0.485 n=6)
PoolContention/workers-8-4          1.071µ ±  2%   1.072µ ±  1%       ~ (p=0.970 n=6)
PoolContention/workers-16-4         1.071µ ±  0%   1.075µ ±  1%       ~ (p=0.199 n=6)
ComponentLifecycle-4                3.567m ±  1%   3.564m ±  1%       ~ (p=0.589 n=6)
SourceValidation-4                  2.290µ ±  0%   2.276µ ±  1%  -0.59% (p=0.013 n=6)
RegistryConcurrent-4                767.6n ±  5%   802.4n ±  6%       ~ (p=0.240 n=6)
LoaderLoadFromString-4              3.578m ±  1%   3.576m ±  0%       ~ (p=0.818 n=6)
geomean                             18.49µ         18.63µ        +0.77%

                            │ baseline-bench.txt │        benchmark-results.txt         │
                            │        B/op        │     B/op      vs base                │
InterpreterCreation-4               2.027Mi ± 0%   2.027Mi ± 0%       ~ (p=0.937 n=6)
ComponentLoad-4                     2.180Mi ± 0%   2.180Mi ± 0%       ~ (p=0.422 n=6)
ComponentExecute-4                  1.203Ki ± 0%   1.203Ki ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-1-4          1.203Ki ± 0%   1.203Ki ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-2-4          1.203Ki ± 0%   1.203Ki ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-4-4          1.203Ki ± 0%   1.203Ki ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-8-4          1.203Ki ± 0%   1.203Ki ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-16-4         1.203Ki ± 0%   1.203Ki ± 0%       ~ (p=1.000 n=6) ¹
ComponentLifecycle-4                2.183Mi ± 0%   2.183Mi ± 0%       ~ (p=0.669 n=6)
SourceValidation-4                  1.984Ki ± 0%   1.984Ki ± 0%       ~ (p=1.000 n=6) ¹
RegistryConcurrent-4                1.133Ki ± 0%   1.133Ki ± 0%       ~ (p=1.000 n=6) ¹
LoaderLoadFromString-4              2.182Mi ± 0%   2.182Mi ± 0%  +0.00% (p=0.039 n=6)
geomean                             15.25Ki        15.25Ki       +0.00%
¹ all samples are equal

                            │ baseline-bench.txt │        benchmark-results.txt        │
                            │     allocs/op      │  allocs/op   vs base                │
InterpreterCreation-4                15.68k ± 0%   15.68k ± 0%       ~ (p=1.000 n=6)
ComponentLoad-4                      18.02k ± 0%   18.02k ± 0%       ~ (p=1.000 n=6)
ComponentExecute-4                    25.00 ± 0%    25.00 ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-1-4            25.00 ± 0%    25.00 ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-2-4            25.00 ± 0%    25.00 ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-4-4            25.00 ± 0%    25.00 ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-8-4            25.00 ± 0%    25.00 ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-16-4           25.00 ± 0%    25.00 ± 0%       ~ (p=1.000 n=6) ¹
ComponentLifecycle-4                 18.07k ± 0%   18.07k ± 0%       ~ (p=1.000 n=6) ¹
SourceValidation-4                    32.00 ± 0%    32.00 ± 0%       ~ (p=1.000 n=6) ¹
RegistryConcurrent-4                  2.000 ± 0%    2.000 ± 0%       ~ (p=1.000 n=6) ¹
LoaderLoadFromString-4               18.06k ± 0%   18.06k ± 0%       ~ (p=1.000 n=6) ¹
geomean                               183.3         183.3       +0.00%
¹ all samples are equal

pkg: github.com/GoCodeAlone/workflow/middleware
                                  │ baseline-bench.txt │       benchmark-results.txt       │
                                  │       sec/op       │   sec/op     vs base              │
CircuitBreakerDetection-4                 284.9n ± 12%   282.6n ± 4%       ~ (p=0.121 n=6)
CircuitBreakerExecution_Success-4         21.54n ±  2%   21.52n ± 0%       ~ (p=0.569 n=6)
CircuitBreakerExecution_Failure-4         66.33n ±  1%   66.12n ± 0%  -0.31% (p=0.011 n=6)
geomean                                   74.11n         73.81n       -0.40%

                                  │ baseline-bench.txt │       benchmark-results.txt        │
                                  │        B/op        │    B/op     vs base                │
CircuitBreakerDetection-4                 144.0 ± 0%     144.0 ± 0%       ~ (p=1.000 n=6) ¹
CircuitBreakerExecution_Success-4         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
CircuitBreakerExecution_Failure-4         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
geomean                                              ²               +0.00%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                  │ baseline-bench.txt │       benchmark-results.txt        │
                                  │     allocs/op      │ allocs/op   vs base                │
CircuitBreakerDetection-4                 1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=6) ¹
CircuitBreakerExecution_Success-4         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
CircuitBreakerExecution_Failure-4         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
geomean                                              ²               +0.00%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/module
                                 │ baseline-bench.txt │       benchmark-results.txt        │
                                 │       sec/op       │    sec/op     vs base              │
IaCStateBackend_InProcess-4              307.6n ± 28%   305.0n ± 21%       ~ (p=0.221 n=6)
IaCStateBackend_GRPC-4                   9.496m ±  6%   9.503m ±  3%       ~ (p=0.818 n=6)
JQTransform_Simple-4                     653.4n ± 35%   651.8n ± 37%       ~ (p=1.000 n=6)
JQTransform_ObjectConstruction-4         1.475µ ±  1%   1.478µ ±  1%       ~ (p=0.331 n=6)
JQTransform_ArraySelect-4                3.420µ ±  1%   3.555µ ±  4%       ~ (p=0.106 n=6)
JQTransform_Complex-4                    38.74µ ±  2%   41.20µ ±  7%       ~ (p=1.000 n=6)
JQTransform_Throughput-4                 1.807µ ±  0%   1.825µ ±  2%  +0.97% (p=0.002 n=6)
SSEPublishDelivery-4                     71.48n ±  1%   72.01n ±  1%       ~ (p=0.061 n=6)
geomean                                  3.849µ         3.902µ        +1.38%

                                 │ baseline-bench.txt │         benchmark-results.txt         │
                                 │        B/op        │     B/op       vs base                │
IaCStateBackend_InProcess-4              416.0 ± 0%       416.0 ±  0%       ~ (p=1.000 n=6) ¹
IaCStateBackend_GRPC-4                 5.958Mi ± 9%     5.949Mi ± 11%       ~ (p=0.589 n=6)
JQTransform_Simple-4                   1.273Ki ± 0%     1.273Ki ±  0%       ~ (p=1.000 n=6) ¹
JQTransform_ObjectConstruction-4       1.773Ki ± 0%     1.773Ki ±  0%       ~ (p=1.000 n=6) ¹
JQTransform_ArraySelect-4              2.625Ki ± 0%     2.625Ki ±  0%       ~ (p=1.000 n=6) ¹
JQTransform_Complex-4                  16.22Ki ± 0%     16.22Ki ±  0%       ~ (p=1.000 n=6) ¹
JQTransform_Throughput-4               1.984Ki ± 0%     1.984Ki ±  0%       ~ (p=1.000 n=6) ¹
SSEPublishDelivery-4                     0.000 ± 0%       0.000 ±  0%       ~ (p=1.000 n=6) ¹
geomean                                             ²                  -0.02%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                 │ baseline-bench.txt │        benchmark-results.txt        │
                                 │     allocs/op      │  allocs/op   vs base                │
IaCStateBackend_InProcess-4              2.000 ± 0%      2.000 ± 0%       ~ (p=1.000 n=6) ¹
IaCStateBackend_GRPC-4                  6.833k ± 0%     6.838k ± 0%       ~ (p=0.970 n=6)
JQTransform_Simple-4                     10.00 ± 0%      10.00 ± 0%       ~ (p=1.000 n=6) ¹
JQTransform_ObjectConstruction-4         15.00 ± 0%      15.00 ± 0%       ~ (p=1.000 n=6) ¹
JQTransform_ArraySelect-4                30.00 ± 0%      30.00 ± 0%       ~ (p=1.000 n=6) ¹
JQTransform_Complex-4                    324.0 ± 0%      324.0 ± 0%       ~ (p=1.000 n=6) ¹
JQTransform_Throughput-4                 17.00 ± 0%      17.00 ± 0%       ~ (p=1.000 n=6) ¹
SSEPublishDelivery-4                     0.000 ± 0%      0.000 ± 0%       ~ (p=1.000 n=6) ¹
geomean                                             ²                +0.01%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/schema
                                    │ baseline-bench.txt │       benchmark-results.txt       │
                                    │       sec/op       │   sec/op     vs base              │
SchemaValidation_Simple-4                   1.121µ ± 32%   1.107µ ± 2%  -1.16% (p=0.009 n=6)
SchemaValidation_AllFields-4                1.671µ ±  2%   1.660µ ± 2%       ~ (p=0.554 n=6)
SchemaValidation_FormatValidation-4         1.592µ ±  1%   1.593µ ± 1%       ~ (p=0.816 n=6)
SchemaValidation_ManySchemas-4              1.825µ ±  5%   1.841µ ± 2%       ~ (p=0.900 n=6)
geomean                                     1.527µ         1.524µ       -0.22%

                                    │ baseline-bench.txt │       benchmark-results.txt        │
                                    │        B/op        │    B/op     vs base                │
SchemaValidation_Simple-4                   0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SchemaValidation_AllFields-4                0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SchemaValidation_FormatValidation-4         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SchemaValidation_ManySchemas-4              0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
geomean                                                ²               +0.00%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                    │ baseline-bench.txt │       benchmark-results.txt        │
                                    │     allocs/op      │ allocs/op   vs base                │
SchemaValidation_Simple-4                   0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SchemaValidation_AllFields-4                0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SchemaValidation_FormatValidation-4         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SchemaValidation_ManySchemas-4              0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
geomean                                                ²               +0.00%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/store
                                   │ baseline-bench.txt │        benchmark-results.txt        │
                                   │       sec/op       │    sec/op     vs base               │
EventStoreAppend_InMemory-4                1.175µ ± 13%   1.146µ ± 10%        ~ (p=0.455 n=6)
EventStoreAppend_SQLite-4                  1.505m ±  6%   1.434m ±  2%   -4.71% (p=0.041 n=6)
GetTimeline_InMemory/events-10-4           14.36µ ±  4%   13.09µ ±  5%   -8.82% (p=0.002 n=6)
GetTimeline_InMemory/events-50-4           79.35µ ±  4%   60.04µ ± 25%  -24.33% (p=0.002 n=6)
GetTimeline_InMemory/events-100-4          132.4µ ±  2%   119.9µ ±  0%   -9.45% (p=0.002 n=6)
GetTimeline_InMemory/events-500-4          668.2µ ±  1%   618.0µ ±  2%   -7.51% (p=0.002 n=6)
GetTimeline_InMemory/events-1000-4         1.384m ±  1%   1.262m ±  1%   -8.82% (p=0.002 n=6)
GetTimeline_SQLite/events-10-4             110.4µ ±  1%   104.1µ ±  1%   -5.68% (p=0.002 n=6)
GetTimeline_SQLite/events-50-4             262.0µ ±  1%   241.4µ ±  0%   -7.88% (p=0.002 n=6)
GetTimeline_SQLite/events-100-4            445.3µ ±  1%   410.0µ ±  1%   -7.91% (p=0.002 n=6)
GetTimeline_SQLite/events-500-4            1.882m ±  2%   1.749m ±  0%   -7.07% (p=0.002 n=6)
GetTimeline_SQLite/events-1000-4           3.647m ±  1%   3.441m ±  1%   -5.66% (p=0.002 n=6)
geomean                                    229.9µ         210.3µ         -8.52%

                                   │ baseline-bench.txt │        benchmark-results.txt         │
                                   │        B/op        │     B/op      vs base                │
EventStoreAppend_InMemory-4                 766.0 ± 12%     780.0 ± 8%       ~ (p=0.617 n=6)
EventStoreAppend_SQLite-4                 1.986Ki ±  2%   1.987Ki ± 2%       ~ (p=1.000 n=6)
GetTimeline_InMemory/events-10-4          7.953Ki ±  0%   7.953Ki ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-50-4          46.62Ki ±  0%   46.62Ki ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-100-4         94.48Ki ±  0%   94.48Ki ± 0%       ~ (p=1.000 n=6)
GetTimeline_InMemory/events-500-4         472.8Ki ±  0%   472.8Ki ± 0%       ~ (p=1.000 n=6)
GetTimeline_InMemory/events-1000-4        944.3Ki ±  0%   944.3Ki ± 0%       ~ (p=0.121 n=6)
GetTimeline_SQLite/events-10-4            16.74Ki ±  0%   16.74Ki ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-50-4            87.14Ki ±  0%   87.14Ki ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-100-4           175.4Ki ±  0%   175.4Ki ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-500-4           846.1Ki ±  0%   846.1Ki ± 0%  -0.00% (p=0.002 n=6)
GetTimeline_SQLite/events-1000-4          1.639Mi ±  0%   1.639Mi ± 0%  +0.00% (p=0.024 n=6)
geomean                                   67.18Ki         67.28Ki       +0.15%
¹ all samples are equal

                                   │ baseline-bench.txt │        benchmark-results.txt        │
                                   │     allocs/op      │  allocs/op   vs base                │
EventStoreAppend_InMemory-4                  7.000 ± 0%    7.000 ± 0%       ~ (p=1.000 n=6) ¹
EventStoreAppend_SQLite-4                    53.00 ± 0%    53.00 ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-10-4             125.0 ± 0%    125.0 ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-50-4             653.0 ± 0%    653.0 ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-100-4           1.306k ± 0%   1.306k ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-500-4           6.514k ± 0%   6.514k ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-1000-4          13.02k ± 0%   13.02k ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-10-4               382.0 ± 0%    382.0 ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-50-4              1.852k ± 0%   1.852k ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-100-4             3.681k ± 0%   3.681k ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-500-4             18.54k ± 0%   18.54k ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-1000-4            37.29k ± 0%   37.29k ± 0%       ~ (p=1.000 n=6) ¹
geomean                                     1.162k        1.162k       +0.00%
¹ all samples are equal

Benchmarks run with go test -bench=. -benchmem -count=6.
Regressions ≥ 20% are flagged. Results compared via benchstat.

@intel352 intel352 merged commit 9792944 into main May 20, 2026
22 checks passed
@intel352 intel352 deleted the fix/engine-result-log-redaction branch May 20, 2026 16:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants