Skip to content

fix(workflows): fail gate step loudly on a malformed 'options'#3595

Merged
mnriem merged 1 commit into
github:mainfrom
Noor-ul-ain001:fix/gate-nonlist-options-crash
Jul 21, 2026
Merged

fix(workflows): fail gate step loudly on a malformed 'options'#3595
mnriem merged 1 commit into
github:mainfrom
Noor-ul-ain001:fix/gate-nonlist-options-crash

Conversation

@Noor-ul-ain001

Copy link
Copy Markdown
Contributor

Summary

GateStep.validate rejects a non-list (or empty) options and requires every option to be a string, but the workflow engine does not auto-validate a step before calling execute. On an unvalidated run a malformed options slipped straight through to the interactive prompt and took down the whole workflow:

  • scalar / dict / None options → raw TypeError (enumerate/len on a non-iterable) or KeyError (indexing a dict) inside _prompt
  • empty list []_prompt's while True: input loop can never satisfy 1 <= n <= 0, so it spins forever
  • non-string element (e.g. [123, 456]) → passes the shape check but crashes the reject test at choice.lower() with AttributeError

This mirrors an established bug class in this repo: validate() correctly rejects bad input, but execute() (reachable on an unvalidated run) crashes on it instead of failing the step cleanly — same shape as the switch cases (#3481) and command input guards.

Fix

Guard execute to return StepStatus.FAILED with a clear error when options is not a non-empty list of strings. The check runs before the non-TTY PAUSED short-circuit, so a misconfigured gate surfaces as FAILED in CI rather than pausing and only crashing later when an operator resumes on a real terminal.

Tests

Added regression tests under TestGateStep:

  • test_execute_non_list_options_fails_cleanly (parametrized over 5, {...}, None, [], "approve")
  • test_execute_non_string_options_element_fails_cleanly
  • test_execute_non_list_options_fails_in_non_tty_too

Verified test-the-test: with the source fix stashed, the scalar cases crash and the empty-list case hangs _prompt forever; with the fix all 21 TestGateStep tests pass.

🤖 Generated with Claude Code

`GateStep.validate` rejects a non-list (or empty) `options` and requires
every option to be a string, but the engine does not auto-validate before
`execute`. On an unvalidated run a scalar/dict/None `options` reached
`_prompt` and crashed the whole workflow with a raw `TypeError`
(`enumerate`/`len` on a non-iterable) or `KeyError` (indexing a dict); an
empty list spun `_prompt`'s input loop forever; a non-string option crashed
the reject check at `choice.lower()` with `AttributeError`.

Guard `execute` to FAIL the step cleanly instead, before the non-TTY
PAUSE short-circuit so the error surfaces in CI too rather than pausing
and only crashing later on interactive resume. Mirrors the switch 'cases'
and command 'input' unvalidated-execute guards.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

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

Adds runtime validation so malformed gate options fail cleanly instead of crashing or hanging workflows.

Changes:

  • Rejects options that are not non-empty lists of strings.
  • Adds interactive and non-TTY regression coverage.
Show a summary per file
File Description
src/specify_cli/workflows/steps/gate/__init__.py Adds the runtime options guard.
tests/test_workflows.py Tests malformed options handling.

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 merged commit 2f9e455 into github:main Jul 21, 2026
12 checks passed
@mnriem

mnriem commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Thank you!

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