Skip to content

feat(workflows): make shell step timeout configurable#3404

Open
marcelsafin wants to merge 3 commits into
github:mainfrom
marcelsafin:fix/3327-shell-timeout
Open

feat(workflows): make shell step timeout configurable#3404
marcelsafin wants to merge 3 commits into
github:mainfrom
marcelsafin:fix/3327-shell-timeout

Conversation

@marcelsafin

Copy link
Copy Markdown
Contributor

Description

Fixes #3327

The shell step hardcoded timeout=300 in its subprocess.run call, so any workflow gate longer than 5 minutes (full builds, linter aggregators, integration tests) died with TimeoutExpired regardless of whether the command would pass.

The step now reads an optional timeout field (seconds), defaulting to 300 for backward compatibility:

- id: qa
  type: shell
  timeout: 1800
  run: make code-qa

validate rejects non-integer, boolean, zero, negative, and null values, and the timeout error message reports the configured value instead of a hardcoded 300.

Testing

  • Tested locally with uv run specify --help
  • Ran existing tests with uv sync && uv run pytest (3819 passed)
  • Tested with a sample project (if applicable)

Six new tests in TestShellStep: override reaches subprocess.run, default stays 300, timeout error reports the configured value, validation rejects bad values (including True and YAML-null), and accepts a positive integer.

AI Disclosure

  • I did not use AI assistance for this contribution
  • I did use AI assistance (describe below)

Written with GitHub Copilot CLI; I reviewed the diff and test results.

The shell step hardcoded a 300s subprocess timeout, killing any
legitimate long-running QA command. Read an optional timeout field
(seconds, positive integer, default 300) and validate it.

Fixes github#3327

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 8, 2026 08:38
@marcelsafin marcelsafin requested a review from mnriem as a code owner July 8, 2026 08:38

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

This PR makes the workflow shell step’s execution timeout configurable via an optional timeout (seconds) field, defaulting to 300 seconds for backward compatibility, and updates validation and error reporting accordingly.

Changes:

  • Thread a per-step timeout value through ShellStep.execute() (default 300s) and report the configured timeout in TimeoutExpired errors.
  • Add ShellStep.validate() checks to reject invalid timeout values (non-int, bool, <= 0, null).
  • Add tests covering override/default behavior, timeout error messaging, and validation acceptance/rejection.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/specify_cli/workflows/steps/shell/__init__.py Reads timeout from step config, passes it to subprocess.run, updates timeout error text, and validates timeout values.
tests/test_workflows.py Adds TestShellStep coverage for configurable timeouts, defaults, error messaging, and validation rules.

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

Comment on lines +110 to +114
if "timeout" in config:
timeout = config["timeout"]
# bool is an int subclass, so reject it explicitly.
if isinstance(timeout, bool) or not isinstance(timeout, int) or timeout <= 0:
errors.append(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Reformatted to the multi-line conditional style.

Comment thread tests/test_workflows.py
Comment on lines +1316 to +1330
from specify_cli.workflows.steps.shell import ShellStep
from specify_cli.workflows.base import StepContext

seen = {}
real_run = sp.run

def spy_run(*args, **kwargs):
seen["timeout"] = kwargs.get("timeout")
return real_run(*args, **kwargs)

monkeypatch.setattr(
"specify_cli.workflows.steps.shell.subprocess.run", spy_run
)
ShellStep().execute({"id": "t", "run": "echo hi"}, StepContext())
assert seen["timeout"] == 300

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added the status assert, matching test_timeout_is_configurable.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 8, 2026 08:49

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

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

run_cmd = str(run_cmd)

cwd = context.project_root or "."
timeout = config.get("timeout", 300)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch. execute() now falls back to the 300s default for malformed timeout values (bool/non-int/non-positive), mirroring the engine's is True handling of unvalidated continue_on_error. Covered by test_execute_ignores_unvalidated_bad_timeout (parametrized over the same bad values as validate). 4b6e1fc

The engine does not auto-validate step config, so a string or null
timeout would reach subprocess.run() and crash the run with a
TypeError. Fall back to the 300s default for malformed values,
mirroring how the engine treats unvalidated continue_on_error.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 8, 2026 08:58

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

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

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.

Review details

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

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.

[Feature]: Make the shell step's execution timeout configurable (currently hardcoded to 300s)

3 participants