mirror of
https://github.com/github/spec-kit.git
synced 2026-07-03 12:28:06 +08:00
fix(workflows): reject infinite number-input default instead of raising OverflowError (#3199)
WorkflowEngine._coerce_input normalizes a whole-valued number to int via int(value). For an infinite float (e.g. a 'type: number' input with YAML 'default: .inf') int(inf) raises OverflowError, which is not in the except (ValueError, TypeError) tuple. validate_workflow eager-coerces declared defaults and is documented to RETURN a list of errors, but it only catches ValueError -- so the OverflowError escaped and validate_workflow raised instead of reporting, breaking its contract. (NaN already surfaced cleanly because int(nan) raises ValueError.) Add OverflowError to the except tuple so an infinite default surfaces as the same clean 'expected a number' ValueError as NaN, consistent with the function's existing fail-fast-on-authoring-mistakes design. Finite values (5.0 -> 5, 3.5 -> 3.5) are unaffected. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2846,6 +2846,47 @@ steps:
|
||||
errors = validate_workflow(definition)
|
||||
assert any("invalid default" in e for e in errors), errors
|
||||
|
||||
def test_coerce_number_input_rejects_infinity_cleanly(self):
|
||||
"""An infinite float must surface as a clean ValueError (like NaN), not
|
||||
let ``int(inf)``'s OverflowError escape: ``int()`` of an infinity raises
|
||||
OverflowError, which is not ValueError/TypeError.
|
||||
"""
|
||||
from specify_cli.workflows.engine import WorkflowEngine
|
||||
|
||||
for value in (float("inf"), float("-inf"), "inf", "Infinity", "-inf"):
|
||||
with pytest.raises(ValueError, match="expected a number"):
|
||||
WorkflowEngine._coerce_input("count", value, {"type": "number"})
|
||||
# Finite values still coerce (whole floats normalize to int).
|
||||
assert WorkflowEngine._coerce_input("count", 5.0, {"type": "number"}) == 5
|
||||
assert WorkflowEngine._coerce_input("count", 3.5, {"type": "number"}) == 3.5
|
||||
|
||||
def test_validate_workflow_rejects_infinite_default_for_number_type(self):
|
||||
"""``type: number`` with an infinite default (YAML ``.inf``) must be
|
||||
reported as an error, not raise. ``int(inf)`` raises OverflowError during
|
||||
coercion, which previously escaped validate_workflow's ValueError handler
|
||||
and broke its "return a list of errors" contract.
|
||||
"""
|
||||
from specify_cli.workflows.engine import WorkflowDefinition, validate_workflow
|
||||
|
||||
definition = WorkflowDefinition.from_string("""
|
||||
schema_version: "1.0"
|
||||
workflow:
|
||||
id: "inf-as-number"
|
||||
name: "Inf As Number"
|
||||
version: "1.0.0"
|
||||
inputs:
|
||||
count:
|
||||
type: number
|
||||
default: .inf
|
||||
steps:
|
||||
- id: noop
|
||||
type: gate
|
||||
message: "noop"
|
||||
options: [approve]
|
||||
""")
|
||||
errors = validate_workflow(definition)
|
||||
assert any("invalid default" in e for e in errors), errors
|
||||
|
||||
def test_validate_workflow_rejects_non_string_default_for_string_type(self):
|
||||
"""``type: string`` must require an actual string — a numeric YAML
|
||||
default like ``5`` would otherwise slip through unvalidated.
|
||||
|
||||
Reference in New Issue
Block a user