Skip to content

fix(core): reject unsupported dictionary unpacking in safe_expr - #939

Merged
elijahbenizzy merged 1 commit into
apache:mainfrom
tonghzhang:fix/safe-expr-reject-dict-unpacking
Oct 17, 2026
Merged

elijahbenizzy merged 1 commit into
apache:mainfrom
tonghzhang:fix/safe-expr-reject-dict-unpacking

Conversation

@tonghzhang

Copy link
Copy Markdown
Contributor

Condition.safe_expr("bool({**{}})") currently returns true: dictionary unpacking passes validation, but the interpreter treats its AST sentinel as a literal None key. Similarly, a membership condition such as 'allowed' in {**mapping} silently returns false even when mapping contains that key.

Changes

Reject unsupported dictionary unpacking when constructing the condition, matching the existing rejection of other unpacking forms. Document the restriction and cover plain, mixed, repeated, nested, and short-circuited unpacking, plus a valid literal None key.

How I tested this

  • The five new rejection cases fail on the original implementation and pass after the fix.
  • python -m pytest tests/core/test_action.py -q: 160 passed.
  • Broader tests/core run: 402 passed; four existing graph-rendering tests failed because the local Windows environment has no Graphviz dot executable.
  • Repository pre-commit hooks passed for both changed files (the frontend-only hook was skipped), including Black, isort, flake8, Python AST, whitespace, and ASF headers. git diff --check also passed.

Notes

Prepared with OpenAI Codex assistance; the regression and broader test results above were run locally. The commit includes a Generated-by trailer.

Checklist

  • PR has an informative and human-readable title
  • Changes are limited to a single goal
  • Any change in functionality is tested
  • The public API docstring describes the restriction

Reject ast.Dict unpacking at validation time so unsupported expressions do
not silently evaluate using a None key. Cover nested and short-circuited
unpacking, and preserve ordinary dictionary literals with None keys.

Generated-by: OpenAI Codex
@github-actions github-actions Bot added the area/core Application, State, Graph, Actions label Sep 27, 2026

@sivakumar-mahalingam sivakumar-mahalingam left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Could we include the original reported reproducer in the regression cases as well?

For example, bool({**{}}) is one of the concrete failures described in this PR, but the current parameterized test only exercises dictionary unpacking directly or through list/boolean nesting. Adding the exact reproducer would also verify that unpacking is rejected when the dictionary appears as an argument to an otherwise allowed builtin call.

It may also be worth including the membership case ('allowed' in {**mapping}) mentioned in the description, so both previously incorrect evaluation paths are explicitly protected against regression.

@elijahbenizzy elijahbenizzy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM, right place for the check. After #947 lands the k-is-not-None fallback in _eval_Dict becomes unreachable; I'll drop it there. Elijah

@elijahbenizzy
elijahbenizzy enabled auto-merge (squash) October 17, 2026 15:37
@elijahbenizzy
elijahbenizzy merged commit 918e323 into apache:main Oct 17, 2026
29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/core Application, State, Graph, Actions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants