fix(workflows): stop list-literal-then-index expressions silently corrupting - #4572
Open
Noor-ul-ain001 wants to merge 1 commit into
Open
Conversation
…rupting
_evaluate_simple_expression's list-literal detection was
`expr.startswith("[") and expr.endswith("]")` -- true not only for a
genuine literal like `[1, 2, 3]` but also for a list literal immediately
followed by an index suffix, e.g. `[1,2,3][1]` (read as "index 1 of
[1,2,3]", i.e. 2). Naively stripping the outer brackets from that string
produces the garbage `1,2,3][1`, which the comma-splitter then breaks
into `["1", "2", "3][1"]`; the last segment resolves to None via the
dot-path fallback, so `{{ [1,2,3][1] }}` silently evaluated to
`[1, 2, None]` instead of raising or resolving the index -- no error, no
warning, just wrong data.
This is the same "grabs the wrong span" failure mode the adjacent
string-literal check already guards against (verifying the matching
quote is the last character, not just present), just never given the
same treatment for brackets.
Added _is_single_list_literal: a quote/bracket-depth scan (mirroring
_split_top_level_commas's existing tracking in this same file) that
confirms the opening `[` closes exactly at the final character before
treating the expression as one literal. A misclassified expression now
falls through to the existing dot-path resolution and evaluates to None
-- consistent with how every other unresolvable expression in this
module already behaves, not a new failure mode.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U74yBbvVQCPwB7Ed8Dzeu6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
_evaluate_simple_expression's list-literal detection (workflows/expressions.py) isexpr.startswith("[") and expr.endswith("]"). This is true not only for a genuine literal like[1, 2, 3]but also for a list literal immediately followed by an index suffix, e.g.[1,2,3][1]— which reads as "index 1 of[1,2,3]" (i.e.2).Naively stripping the outer brackets from
"[1,2,3][1]"produces"1,2,3][1", which the comma-splitter then breaks into["1", "2", "3][1"]. The malformed last segment resolves toNonevia the existing dot-path fallback, so the whole expression silently evaluates to[1, 2, None]— no error, no warning, just wrong data.This is the exact "grabs the wrong span" failure mode the adjacent string-literal check already guards against a few lines above (verifying the matching quote is the last character, not just present anywhere) — the list-literal branch never got the same rigor.
Fix
Added
_is_single_list_literal: a quote/bracket-depth scan (mirroring_split_top_level_commas's existing tracking style in the same file) that confirms the opening[closes exactly at the final character before treating the expression as one literal. A misclassified expression now falls through to the existing dot-path resolution and evaluates toNone— consistent with how every other unresolvable expression in this module already behaves, not a new failure mode. This does not add support for indexing directly into a literal list (an author would still writesteps.x.output.list[0], which the dot-path resolver already supports); it only stops the misclassification from silently corrupting the result.Test plan
ruff check .cleanassert [1, 2, None] is None→ confirmed via test-the-test) and passes with the fixtest_workflows.pysuite (985 tests) passes