mirror of
https://github.com/github/spec-kit.git
synced 2026-08-03 06:26:30 +08:00
fix: escape workflow validation errors before Rich output
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -374,7 +374,7 @@ def workflow_run(
|
||||
if errors:
|
||||
err.print("[red]Workflow validation failed:[/red]")
|
||||
for verr in errors:
|
||||
err.print(f" • {verr}")
|
||||
err.print(f" • {_escape_markup(str(verr))}")
|
||||
raise typer.Exit(1)
|
||||
|
||||
# Parse inputs
|
||||
@@ -645,7 +645,7 @@ def workflow_add(
|
||||
if errors:
|
||||
console.print("[red]Error:[/red] Workflow validation failed:")
|
||||
for err in errors:
|
||||
console.print(f" \u2022 {err}")
|
||||
console.print(f" \u2022 {_escape_markup(str(err))}")
|
||||
raise typer.Exit(1)
|
||||
|
||||
if expected_id is not None and definition.id != expected_id:
|
||||
@@ -903,7 +903,7 @@ def _install_workflow_from_catalog(
|
||||
shutil.rmtree(workflow_dir, ignore_errors=True)
|
||||
console.print("[red]Error:[/red] Downloaded workflow validation failed:")
|
||||
for err in errors:
|
||||
console.print(f" \u2022 {err}")
|
||||
console.print(f" \u2022 {_escape_markup(str(err))}")
|
||||
raise typer.Exit(1)
|
||||
|
||||
# Enforce that the workflow's internal ID matches the catalog key
|
||||
|
||||
@@ -5905,6 +5905,34 @@ class TestWorkflowAddSymlinkGuard:
|
||||
assert result.exit_code != 0
|
||||
assert "symlinked .specify/workflows" in result.output
|
||||
|
||||
def test_add_escapes_rich_markup_in_validation_errors(self, temp_dir, monkeypatch):
|
||||
"""User-controlled YAML values in validation errors must not be parsed as Rich markup."""
|
||||
from typer.testing import CliRunner
|
||||
from specify_cli import app
|
||||
|
||||
(temp_dir / ".specify" / "workflows").mkdir(parents=True)
|
||||
src = temp_dir / "incoming.yml"
|
||||
src.write_text(
|
||||
"""
|
||||
schema_version: "1.0"
|
||||
workflow:
|
||||
id: "markup-wf"
|
||||
name: "Markup"
|
||||
version: "[bold]bad[/bold]"
|
||||
|
||||
steps:
|
||||
- id: step-one
|
||||
command: speckit.specify
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
monkeypatch.chdir(temp_dir)
|
||||
result = CliRunner().invoke(app, ["workflow", "add", str(src)])
|
||||
|
||||
assert result.exit_code != 0
|
||||
assert "[bold]bad[/bold]" in result.output
|
||||
|
||||
@pytest.mark.skipif(not hasattr(os, "symlink"), reason="symlinks are unavailable")
|
||||
def test_add_refuses_symlinked_id_dir(self, temp_dir, monkeypatch, sample_workflow_yaml):
|
||||
"""A symlinked <id> install dir must not let a copy escape the project root."""
|
||||
|
||||
Reference in New Issue
Block a user