Skip to content

hotfix: KEEP-468 exclude condition fields from action-level post-scan#1192

Merged
joelorzet merged 1 commit into
stagingfrom
hotfix/KEEP-468-condition-scan-bypass
May 9, 2026
Merged

hotfix: KEEP-468 exclude condition fields from action-level post-scan#1192
joelorzet merged 1 commit into
stagingfrom
hotfix/KEEP-468-condition-scan-bypass

Conversation

@joelorzet
Copy link
Copy Markdown

Summary

Hotfix for a regression introduced by #1187 (KEEP-468 strict-mode template fail-closed) that landed in prod via #1191. Every workflow with a Condition node referencing upstream data — including the For Each + Condition cascades shipped for KEEP-520 — has been aborting every iteration with Reference left in rendered config since the release.

Root cause

processActionConfig ran the strict-mode post-scan (assertResolved) over processedConfig AFTER re-attaching condition and conditionConfig. Those fields intentionally keep their {{...}} tokens at the action level (they're substituted later by evaluateConditionExpression, which has its own leftover-token gate from commit b3d5d9eb), so the post-scan saw resolvable tokens like {{@fe:Each Item.currentItem}} and flagged them as unresolved leftover literals.

Fix

Reorder processActionConfig so assertResolved scans the rendered config before condition/conditionConfig are re-attached. The function still returns the same shape; downstream consumers (executeActionStep, condition step handler, true/false handle routing) see no change. Condition templates remain protected by evaluateConditionExpression's own leftover-scan.

Confirmed against prod data

Workflow befqn0fu66t7un1mqm8r2 (KEEP-520-C cascading-conditions test fixture):

  • gen_items correctly produced [1, 5, 8, 12, 18, 25]
  • fe (For Each) iterated 6 times
  • Every iteration's cond_outer aborted with the false-positive
  • done_collect aggregated 6 error rows
  • Zero iteration logs written

Verification

  • New regression test tests/unit/template-fail-closed-condition-bypass.test.ts captures the design contract: the action-level scan must not see condition fields.
  • Full suite: 4,413 unit + integration tests pass, 0 failed (40 skipped, all environment-dependent).
  • Type-check clean.

Notes

  • The KEEP-468 condition-expression gate in evaluateConditionExpression was already correct — this hotfix only fixes the action-level scan.
  • For Each iteration body persistence (the missing iteration logs) will recover automatically once iterations stop aborting on the false-positive.

… post-scan

The KEEP-468 strict gate ran `assertResolved` over `processedConfig` after
re-attaching `condition` and `conditionConfig`. Those fields intentionally
keep their `{{...}}` tokens at the action level (they're substituted later
by `evaluateConditionExpression`, which has its own leftover-token gate),
so the post-scan saw resolvable tokens like `{{@fe:Each Item.currentItem}}`
and false-tripped with "Reference left in rendered config" — aborting
every iteration of any For Each that contained a Condition node.

Confirmed in prod execution data on workflow `befqn0fu66t7un1mqm8r2`
(KEEP-520-C cascading-conditions test fixture): every iteration of the
For Each body returned `cond_outer` failure with the unresolved-leftover
message, the `done` Collect aggregated 6 failed-result rows, no iteration
logs were written.

Fix: reorder `processActionConfig` so `assertResolved` scans the rendered
config BEFORE `condition`/`conditionConfig` are re-attached. The function
still returns the same shape, downstream consumers (executeActionStep,
condition step handler, true/false handle routing) see no change.
Condition templates remain protected by `evaluateConditionExpression`'s
own leftover-scan added in commit b3d5d9e.

Regression test: `tests/unit/template-fail-closed-condition-bypass.test.ts`
captures the contract directly against `assertResolved`:
  - scanning a config with a Condition's templated expression trips the
    post-scan (regression baseline)
  - scanning the same config without `condition`/`conditionConfig` is
    clean (post-fix order)
  - leftover scans still catch genuinely unresolved action fields

Full suite: 4413 unit + integration tests pass, 0 failed.
@joelorzet joelorzet merged commit 34081ab into staging May 9, 2026
26 checks passed
@joelorzet joelorzet deleted the hotfix/KEEP-468-condition-scan-bypass branch May 9, 2026 11:23
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 9, 2026

🧹 PR Environment Cleaned Up

The PR environment has been successfully deleted.

Deleted Resources:

  • Namespace: pr-1192
  • All Helm releases (Keeperhub, Scheduler, Event services)
  • PostgreSQL Database (including data)
  • LocalStack, Redis
  • All associated secrets and configs

All resources have been cleaned up and will no longer incur costs.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 9, 2026

ℹ️ No PR Environment to Clean Up

No PR environment was found for this PR. This is expected if:

  • The PR never had the deploy-pr-environment label
  • The environment was already cleaned up
  • The deployment never completed successfully

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.

1 participant