Skip to content

fix(workflows): guard non-mapping 'inputs:' block in engine._resolve_inputs#3696

Open
jawwad-ali wants to merge 1 commit into
github:mainfrom
jawwad-ali:fix/engine-resolve-inputs-non-mapping-guard
Open

fix(workflows): guard non-mapping 'inputs:' block in engine._resolve_inputs#3696
jawwad-ali wants to merge 1 commit into
github:mainfrom
jawwad-ali:fix/engine-resolve-inputs-non-mapping-guard

Conversation

@jawwad-ali

Copy link
Copy Markdown
Contributor

What

WorkflowEngine.execute() / resume() run unvalidated definitions (load_workflow's docstring: "not yet validated; call validate_workflow() separately"), and WorkflowDefinition stores inputs raw. So a non-mapping inputs: block — bare inputs:None, or inputs: []list — reached:

for name, input_def in definition.inputs.items():

…and crashed the whole run with AttributeError: 'NoneType'/'list' object has no attribute 'items'. The steps layer is explicitly hardened for exactly this "engine does not auto-validate" case; the inputs container was the gap (the existing per-input isinstance skip is only reached after the crashing iteration).

Fix

Return {} when definition.inputs is not a mapping, mirroring validate_workflow's own isinstance(definition.inputs, dict) check. Protects both call sites (execute and resume); normal dict resolution (defaults + provided overrides) is unchanged, and validate_workflow still reports the malformed shape.

Tests

tests/test_workflows.py::TestWorkflowDefinition::test_resolve_inputs_tolerates_non_mapping_inputs (parametrized inputs: [] and bare inputs:) — _resolve_inputs returns {} instead of raising. Fails before the fix (AttributeError). ruff check reports no new issues (the pre-existing engine.py I001 is unrelated and present on main).


AI-assisted: authored with Claude Code. Verified against the validate_workflow sibling check and confirmed fail-before/pass-after.

Copilot AI 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.

Pull request overview

Prevents malformed workflow inputs blocks from crashing unvalidated workflow execution or resumption.

Changes:

  • Treats non-dictionary inputs as empty.
  • Adds regression coverage for list and null input blocks.
Show a summary per file
File Description
src/specify_cli/workflows/engine.py Guards input resolution against non-mapping values.
tests/test_workflows.py Tests list and null inputs blocks.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Medium

@mnriem mnriem left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please pull in upstream/main

@jawwad-ali

Copy link
Copy Markdown
Contributor Author

Heads-up: the failing ruff check here is not from this change. uvx ruff check src tests on a clean main currently reports 1476 errors — dominated by rules the repo does not select in [tool.ruff.lint] (which only extend-selects S602/604/605): 733× I001, 161× UP006, 105× RUF012, 92× PLW1510, 49× BLE001, etc. A recent ruff release expanded its default rule set, so the unpinned uvx ruff in CI now lights up long-standing code repo-wide.

This affects every open PR, not just this one (the SUCCESS you see on older PRs is cached from before the ruff release). Pinning ruff in .github/workflows/test.yml (e.g. uvx ruff@<last-green-version> check src tests) would restore green CI across the board. This PR's own change touches only engine._resolve_inputs (a 2-line guard) and introduces no new lint findings. Happy to send a separate ruff-pin PR if that'd help.

…inputs

execute()/resume() run UNVALIDATED definitions (load_workflow does not
validate). WorkflowDefinition stores `inputs` raw, so a non-mapping
`inputs:` block (bare `inputs:` -> None, or `inputs: []`) crashed
_resolve_inputs at `for name, input_def in definition.inputs.items()` with
AttributeError, aborting the whole run.

Return {} when inputs is not a mapping, mirroring validate_workflow's own
`isinstance(definition.inputs, dict)` check. Protects both call sites
(execute and resume); normal dict resolution is unchanged.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jawwad-ali
jawwad-ali force-pushed the fix/engine-resolve-inputs-non-mapping-guard branch from ed5402b to ae454b7 Compare July 24, 2026 08:27
@jawwad-ali

Copy link
Copy Markdown
Contributor Author

Rebased onto the latest upstream/main (now on top of 4d3a428, the 0.14.2.dev0 release commit). 👍

One note on the red ruff check: it is not caused by this PR's diff — it's a repo-wide regression from uvx ruff (unpinned) resolving a newer Ruff whose expanded default rule set now flags ~1476 pre-existing findings across src/tests on a clean main. pytest is green on all six OS/Python combinations here. I opened #3705 to lock the Ruff rule set explicitly so CI goes green repo-wide again; once that lands (or on the next rebase after it) this check will pass.

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.

3 participants