Skip to content

fix: #2359 render template tokens inside array-valued config - #2382

Open
bongbongcrypto wants to merge 1 commit into
KeeperHub:stagingfrom
bongbongcrypto:issue-2359
Open

fix: #2359 render template tokens inside array-valued config#2382
bongbongcrypto wants to merge 1 commit into
KeeperHub:stagingfrom
bongbongcrypto:issue-2359

Conversation

@bongbongcrypto

Copy link
Copy Markdown

Closes #2359

What this changes

processTemplates in lib/workflow/executor/executor.workflow.ts now recurses into arrays. The string, array and object cases go through one helper, renderTemplateValue, so the renderer and scanForLeftoverLiterals agree on what a container is. The doc comment that said "supports array paths like data.recipes[0]" is rewritten, since that was about an index inside a reference rather than array-valued config.

Per the amendment on the issue, web3/read-contract's functionArgs accepts string | unknown[], as web3/query-transactions already does for the same widget. A native array is taken as it is, a string is parsed as JSON, an empty string still means no arguments. Without this the renderer's change would have turned the guard's message into TypeError: functionArgs.trim is not a function.

What does not change

  • scanForLeftoverLiterals: correct as written.
  • condition, conditionConfig, dbQuery and code are lifted out before the renderer runs, so array recursion cannot reach the rules array under conditionConfig.
  • processCodeTemplates and extractTemplateParameters take a string, not a container; no array case exists for them.
  • valueContainsTemplate and walkNodeConfigStrings, the create-time and PATCH-time counterparts noted on the issue, are left for their own change.
  • Array recursion has no depth cap, matching the object recursion beside it; the scan is what is capped.

Tests

tests/unit/template-fail-closed.test.ts: a token as an array element, inside an object inside an array, and inside an array inside an object inside an array; non-string elements and order preserved; an unresolved token inside an array still recorded and still closing the gate; scalar and nested-object rendering unchanged; and the three step inputs that accept a native array end to end (calls on web3/batch-write-contract, functionArgs on web3/query-transactions, payouts on tempo/batch-payout).

tests/unit/read-contract-core.test.ts: the array shape produces the same contract call as its JSON-string shape; a non-array JSON string is still refused; an empty string still means no arguments.

Run against staging's own executor and step with the new tests in place, exactly the nine new cases fail and the TypeError reproduces. With this change, 95 of 95 pass across the two files. biome check is clean on the four changed files.

I could not run the full tests/unit suite or tsgo locally this round; those are on the CI jobs pending approval.

🤖 Generated with Claude Code

processTemplates recursed into plain objects and excluded arrays, so a token
stored inside an array in an action config was copied verbatim. The scan that
runs immediately after, scanForLeftoverLiterals, does walk arrays, found the
token, and aborted the run with a message naming a reference that was correct.
The container it sat in decided the outcome.

The renderer now recurses into arrays. The string, array and object cases go
through one helper, renderTemplateValue, so the renderer and the scan agree
on what a container is: a string is rendered, an array element by element, an
object through processTemplates, anything else passed through as it is. The
doc comment that said "supports array paths like data.recipes[0]" is
rewritten; that was about an index inside a reference, not array-valued
config, and read quickly it said the opposite of what the code did.

Per the amendment on the issue, web3/read-contract's functionArgs now accepts
string | unknown[], as web3/query-transactions already does for the same
widget. Without that, the renderer's change would have turned the guard's
message into an uncaught TypeError: the step declared the string only and
called .trim() on it. A native array is taken as it is; a string is parsed as
JSON; an empty string still means no arguments.

Nothing else moves. scanForLeftoverLiterals is correct as written. condition,
conditionConfig, dbQuery and code are lifted out before the renderer runs, so
array recursion cannot reach the rules array under conditionConfig.
processCodeTemplates and extractTemplateParameters take a string, not a
container, so no array case exists for them. valueContainsTemplate and
walkNodeConfigStrings are the create-time and PATCH-time counterparts the
issue thread noted and are left for their own change. Array recursion has no
depth cap, which matches the object recursion it sits beside; the scan is
what is capped.

Tests: a token as an array element, inside an object inside an array, and
inside an array inside an object inside an array; non-string elements and
order preserved; an unresolved token inside an array still recorded and still
closing the gate; scalar and nested-object rendering unchanged; and the three
step inputs that accept a native array end to end, calls on
web3/batch-write-contract, functionArgs on web3/query-transactions and
payouts on tempo/batch-payout. read-contract-core: the array shape produces
the same contract call as its JSON-string shape, a non-array JSON string is
still refused, and an empty string still means no arguments.

Against staging's own executor and step, exactly the nine new cases fail and
the TypeError reproduces; with this change 95 of 95 pass.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

About the build check on this pull request

This pull request comes from a fork, so GitHub does not pass it the credentials build normally uses for our image registry cache and staging build configuration. The build still runs and still compiles the image, so a red build here is real; it just takes longer than on team branches.

Every workflow run on a pull request from a fork also waits for a maintainer to approve it, so checks can sit at "awaiting approval" for a while after each push. Nothing is needed from you for either of these.

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.

Template tokens inside array config fields are never rendered but are always reported

1 participant