fix(tui): reject absolute paths in persona export/import and propagate typer.Exit
CI / lint (pull_request) Successful in 39s
CI / typecheck (pull_request) Successful in 1m3s
CI / security (pull_request) Successful in 1m15s
CI / quality (pull_request) Successful in 56s
CI / e2e_tests (pull_request) Successful in 5m10s
CI / build (pull_request) Successful in 48s
CI / integration_tests (pull_request) Successful in 6m59s
CI / helm (pull_request) Successful in 39s
CI / push-validation (pull_request) Successful in 28s
CI / unit_tests (pull_request) Failing after 8m55s
CI / docker (pull_request) Has been skipped
CI / coverage (pull_request) Successful in 13m25s
CI / status-check (pull_request) Failing after 5s
CI / lint (pull_request) Successful in 39s
CI / typecheck (pull_request) Successful in 1m3s
CI / security (pull_request) Successful in 1m15s
CI / quality (pull_request) Successful in 56s
CI / e2e_tests (pull_request) Successful in 5m10s
CI / build (pull_request) Successful in 48s
CI / integration_tests (pull_request) Successful in 6m59s
CI / helm (pull_request) Successful in 39s
CI / push-validation (pull_request) Successful in 28s
CI / unit_tests (pull_request) Failing after 8m55s
CI / docker (pull_request) Has been skipped
CI / coverage (pull_request) Successful in 13m25s
CI / status-check (pull_request) Failing after 5s
- registry.py: resolve_export_path/resolve_import_path now raise ValueError
for absolute paths ("must be relative to current working directory"),
fixing the two failing BDD scenarios in repl_input_modes.feature
- actor_run.py, actor.py: catch (click.exceptions.Exit, typer.Exit) so
typer.Exit(code=2) from _resolve_config_files propagates with exit code 2
instead of being swallowed by except Exception and re-raised as code 3
- Apply ruff format to actor_run_signature_resolve_steps.py,
tui_persona_cycle_steps.py, state.py
ISSUES CLOSED: #10637
This commit is contained in:
@@ -28,6 +28,7 @@ with contextlib.suppress(ImportError, ModuleNotFoundError):
|
||||
resolve_config_files,
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@when("I call resolve_config_files with a config list")
|
||||
def step_resolve_with_config_list(context: Any) -> None:
|
||||
@@ -140,7 +141,9 @@ def step_resolve_with_no_config_data(context: Any) -> None:
|
||||
context.resolve_exit_code = 0
|
||||
except (SystemExit, click.exceptions.Exit) as exc:
|
||||
context.resolve_exit_code = getattr(
|
||||
exc, "exit_code", getattr(exc, "code", 1)
|
||||
exc,
|
||||
"exit_code",
|
||||
getattr(exc, "code", 1),
|
||||
)
|
||||
context.resolve_stderr = " ".join(captured_stderr)
|
||||
|
||||
@@ -184,7 +187,9 @@ def step_resolve_unknown_actor_directly(context: Any) -> None:
|
||||
context.resolve_exit_code = 0
|
||||
except (SystemExit, click.exceptions.Exit) as exc:
|
||||
context.resolve_exit_code = getattr(
|
||||
exc, "exit_code", getattr(exc, "code", 1)
|
||||
exc,
|
||||
"exit_code",
|
||||
getattr(exc, "code", 1),
|
||||
)
|
||||
context.resolve_stderr = " ".join(captured_stderr)
|
||||
|
||||
@@ -235,7 +240,9 @@ def step_resolve_with_empty_config_blob(context: Any) -> None:
|
||||
context.resolve_exit_code = 0
|
||||
except (SystemExit, click.exceptions.Exit) as exc:
|
||||
context.resolve_exit_code = getattr(
|
||||
exc, "exit_code", getattr(exc, "code", 1)
|
||||
exc,
|
||||
"exit_code",
|
||||
getattr(exc, "code", 1),
|
||||
)
|
||||
context.resolve_stderr = " ".join(captured_stderr)
|
||||
|
||||
@@ -277,7 +284,9 @@ def step_resolve_with_empty_name(context: Any) -> None:
|
||||
context.empty_name_exit_code = 0
|
||||
except (SystemExit, typer.Exit) as exc:
|
||||
context.empty_name_exit_code = getattr(
|
||||
exc, "exit_code", getattr(exc, "code", 1)
|
||||
exc,
|
||||
"exit_code",
|
||||
getattr(exc, "code", 1),
|
||||
)
|
||||
context.resolve_stderr = " ".join(captured_stderr)
|
||||
|
||||
@@ -331,7 +340,9 @@ def step_resolve_with_unserializable_config_blob(context: Any) -> None:
|
||||
context.resolve_exit_code = 0
|
||||
except (SystemExit, click.exceptions.Exit) as exc:
|
||||
context.resolve_exit_code = getattr(
|
||||
exc, "exit_code", getattr(exc, "code", 1)
|
||||
exc,
|
||||
"exit_code",
|
||||
getattr(exc, "code", 1),
|
||||
)
|
||||
context.resolve_stderr = " ".join(captured_stderr)
|
||||
|
||||
|
||||
@@ -21,9 +21,7 @@ def _registry_for_temp_dir(path: Path) -> PersonaRegistry:
|
||||
return PersonaRegistry(config_dir=path)
|
||||
|
||||
|
||||
@given(
|
||||
'I save TUI persona "{name}" with actor "{actor}" and cycle order {cycle:d}'
|
||||
)
|
||||
@given('I save TUI persona "{name}" with actor "{actor}" and cycle order {cycle:d}')
|
||||
def step_save_persona_cycle(
|
||||
context: Context, name: str, actor: str, cycle: int
|
||||
) -> None:
|
||||
|
||||
@@ -185,7 +185,7 @@ def run(
|
||||
except UnsafeConfigurationError as exc:
|
||||
typer.echo(f"Error: {exc}", err=True)
|
||||
raise typer.Exit(code=1) from exc
|
||||
except click.exceptions.Exit:
|
||||
except (click.exceptions.Exit, typer.Exit):
|
||||
raise
|
||||
except CleverAgentsError as exc:
|
||||
typer.echo(f"Error: {exc}", err=True)
|
||||
|
||||
@@ -159,7 +159,7 @@ def run(
|
||||
except UnsafeConfigurationError as exc:
|
||||
typer.echo(f"Error: {exc}", err=True)
|
||||
raise typer.Exit(code=1) from exc
|
||||
except click.exceptions.Exit:
|
||||
except (click.exceptions.Exit, typer.Exit):
|
||||
raise
|
||||
except CleverAgentsError as exc:
|
||||
typer.echo(f"Error: {exc}", err=True)
|
||||
|
||||
@@ -79,24 +79,24 @@ class PersonaRegistry:
|
||||
return result
|
||||
|
||||
def resolve_export_path(self, output_path: Path) -> Path:
|
||||
"""Resolve export path, accepting both absolute and relative paths."""
|
||||
resolved = output_path.resolve()
|
||||
# Allow absolute paths directly
|
||||
"""Resolve export path; only relative paths within cwd are accepted."""
|
||||
if output_path.is_absolute():
|
||||
return resolved
|
||||
# For relative paths, ensure they stay within working directory
|
||||
raise ValueError(
|
||||
"Export path must be relative to current working directory"
|
||||
)
|
||||
resolved = output_path.resolve()
|
||||
base = Path.cwd().resolve()
|
||||
if not resolved.is_relative_to(base):
|
||||
raise ValueError("Export path must stay within working directory")
|
||||
return resolved
|
||||
|
||||
def resolve_import_path(self, input_path: Path) -> Path:
|
||||
"""Resolve import path, accepting both absolute and relative paths."""
|
||||
resolved = input_path.resolve()
|
||||
# Allow absolute paths directly
|
||||
"""Resolve import path; only relative paths within cwd are accepted."""
|
||||
if input_path.is_absolute():
|
||||
return resolved
|
||||
# For relative paths, ensure they stay within working directory
|
||||
raise ValueError(
|
||||
"Import path must be relative to current working directory"
|
||||
)
|
||||
resolved = input_path.resolve()
|
||||
base = Path.cwd().resolve()
|
||||
if not resolved.is_relative_to(base):
|
||||
raise ValueError("Import path must stay within working directory")
|
||||
|
||||
@@ -72,7 +72,7 @@ class PersonaState:
|
||||
personas = self.registry.list_personas()
|
||||
cyclic = sorted(
|
||||
[p for p in personas if p.cycle_order > 0],
|
||||
key=lambda p: p.cycle_order
|
||||
key=lambda p: p.cycle_order,
|
||||
)
|
||||
|
||||
if not cyclic:
|
||||
|
||||
Reference in New Issue
Block a user