fix(workflows): make expression operator/literal parsing quote-aware#3197
Open
jawwad-ali wants to merge 1 commit into
Open
fix(workflows): make expression operator/literal parsing quote-aware#3197jawwad-ali wants to merge 1 commit into
jawwad-ali wants to merge 1 commit into
Conversation
_evaluate_simple_expression split on operator keywords using naive str.find/split, so a keyword INSIDE a quoted operand was treated as an operator: `inputs.mode == 'read and write'` split on the inner ' and ' and evaluated as `(inputs.mode == 'read) and (write')`. The literal short-circuit was also too greedy -- `'a' == 'b'` matched startswith("'")/endswith("'") and was stripped to the garbage truthy string `a' == 'b`, so `'done' == 'failed'` evaluated truthy and gated the wrong branch.
Add a quote/bracket-aware _find_top_level helper (mirroring the existing _split_top_level_commas) and use it for the and/or/comparison/in/not-in splits; tighten the literal short-circuit to fire only when the opening quote's match is the final char. The docstring already lists comparisons + and/or/not + in/not-in + string literals as supported, so this restores the documented contract.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Description
The workflow expression evaluator (
_evaluate_simple_expression) split on operator keywords with naivestr.find/split, so a keyword inside a quoted operand was mistaken for an operator. Two concrete bugs:{{ inputs.mode == 'read and write' }}split on the innerandand evaluated as(inputs.mode == 'read) and (write')-> wrong result.'a' == 'b'matchedstartswith("'") and endswith("'")and was stripped to the garbage truthy stringa' == 'b. So{{ 'done' == 'failed' }}evaluated truthy and gated the wrong branch inif/switch/while/fan-out steps.The docstring already lists comparisons,
and/or/not,in/not in, and string literals as supported, so silent mis-parsing of common human-readable strings ("approve or reject", "read and write", "in progress") contradicts the contract.Fix
_find_top_level(text, token)helper — a direct sibling of the existing_split_top_level_commas(added in fix(workflows): preserve commas inside quoted list-literal elements #3134) — and use it for theor/and/comparison/in/not insplits, so operators inside quoted operands are skipped.Pipe-filter handling is untouched (it runs first and already worked for single filters).
Testing
uvx ruff checkclean.TestExpressions::test_operator_splitting_is_quote_aware— fails before / passes after; covers keyword-in-literal (both operand sides), membership, literal-vs-literal equality, single-literal preservation, plus regression guards (plain comparisons, realand/or,| default('a and b')).tests/test_workflows.py: 305 passed, 1 skipped. (5 pre-existingsymlinktests fail only on Windows due to theSeCreateSymbolicLinkprivilege — identical on cleanmainwith this change stashed; they pass on CI Linux.)main(b7e67f5).AI Disclosure
Found and fixed with Claude Code (Claude Opus 4.8) under my direction. AI located the quote-naive splitting + greedy literal short-circuit, mirrored the existing
_split_top_level_commaspattern, and drafted the regression tests; I reproduced every mis-parse against the real evaluator, confirmed the regression guards (filter args, real boolean operators, list literals) still pass, and reviewed the diff before submitting.