b56c824909
Three independent test-scaffold defects blocked the unit_tests and integration_tests gates on PR #6361's shell-safety wiring: - features/steps/_tui_helpers.py: the mocked-shell helper patched cleveragents.tui.input.shell_exec.run_shell_command, but modes.py binds the symbol into its own namespace via `from ... import`. The patch was inert, and only the CLEVERAGENTS_ALLOW_DANGEROUS_SHELL=1 gate kept the real `rm -rf /tmp` from running in the behave runner. Patch the use site (modes.run_shell_command) instead. - src/cleveragents/tui/widgets/prompt.py: _FallbackPromptInput (used whenever Textual is mocked or unavailable) had no add_class / remove_class / has_class, so the new "prompt should be marked as dangerous" assertions raised AttributeError and the three new scenarios errored. The production path (_TextualPromptInput) already inherits these from textual.containers.Horizontal; the fallback now mirrors that contract via a small self._classes set. - robot/tui_shell_safety.robot: Catenate's space-based argument separator collapses multi-space indentation, so the Python function bodies (warn_callback, deny) landed at column 0 and the helper scripts died with IndentationError before either assertion ran. Preserve the 4-space indent with ${SPACE * 4} markers. ISSUES CLOSED: #6361
63 lines
3.3 KiB
Plaintext
63 lines
3.3 KiB
Plaintext
*** Settings ***
|
|
Documentation Integration coverage for TUI shell safety wiring and safeguards.
|
|
Resource ${CURDIR}/common.resource
|
|
Suite Setup Setup Test Environment With Database Isolation
|
|
Suite Teardown Cleanup Test Environment
|
|
|
|
*** Variables ***
|
|
${TIMEOUT} 45s
|
|
|
|
*** Test Cases ***
|
|
Shell Safety Service Blocks Denied Command
|
|
[Documentation] ShellSafetyService verdict should block commands even when heuristics allow them.
|
|
[Tags] tui shell_safety regression
|
|
${script}= Catenate SEPARATOR=\n
|
|
... import os
|
|
... from cleveragents.tui.input.modes import InputModeRouter
|
|
... from cleveragents.tui.shell_safety import ShellSafetyService
|
|
... from cleveragents.tui.shell_safety.warning import DangerousCommandWarning
|
|
...
|
|
... warnings: list[DangerousCommandWarning] = []
|
|
...
|
|
... def warn_callback(warning: DangerousCommandWarning) -> bool:
|
|
... ${SPACE * 4}warnings.append(warning)
|
|
... ${SPACE * 4}return False
|
|
...
|
|
... router = InputModeRouter(lambda cmd: "handled", shell_safety=ShellSafetyService(warn_callback=warn_callback))
|
|
... os.environ.pop("CLEVERAGENTS_ALLOW_DANGEROUS_SHELL", None)
|
|
... result = router.process("!chmod -R 777 /tmp/test-shell-safety")
|
|
... assert result.shell_warning is not None, "Shell safety warning should be surfaced"
|
|
... assert warnings and warnings[0].command == "chmod -R 777 /tmp/test-shell-safety"
|
|
... assert result.shell_result is not None, "Shell result should be populated"
|
|
... assert result.shell_result.exit_code == 1, f"Expected blocked exit code, got {result.shell_result.exit_code}"
|
|
... assert "blocked" in result.shell_result.stderr.lower(), result.shell_result.stderr
|
|
... print("blocked-ok")
|
|
${result}= Run Process ${PYTHON} -c ${script}
|
|
... timeout=${TIMEOUT} on_timeout=kill
|
|
... env:PYTHONPATH=${CURDIR}/../src
|
|
Should Be Equal As Integers ${result.rc} 0 Shell safety blocking script failed: ${result.stderr}
|
|
Should Contain ${result.stdout} blocked-ok
|
|
|
|
Shell Confirm Callback Gates All Commands
|
|
[Documentation] run_shell_command must respect confirm callback regardless of built-in heuristics.
|
|
[Tags] tui shell_safety regression
|
|
${script}= Catenate SEPARATOR=\n
|
|
... from cleveragents.tui.input.shell_exec import run_shell_command
|
|
...
|
|
... counter = {"count": 0}
|
|
...
|
|
... def deny(command: str) -> bool:
|
|
... ${SPACE * 4}counter["count"] += 1
|
|
... ${SPACE * 4}return False
|
|
...
|
|
... result = run_shell_command("chmod -R 777 /tmp/test-shell-safety", confirm_dangerous=deny)
|
|
... assert counter["count"] == 1, f"Expected confirm to be invoked once, got {counter['count']}"
|
|
... assert result.exit_code == 1, f"Expected blocked exit code, got {result.exit_code}"
|
|
... assert "blocked" in result.stderr.lower(), result.stderr
|
|
... print("confirm-gate-ok")
|
|
${result}= Run Process ${PYTHON} -c ${script}
|
|
... timeout=${TIMEOUT} on_timeout=kill
|
|
... env:PYTHONPATH=${CURDIR}/../src
|
|
Should Be Equal As Integers ${result.rc} 0 Shell confirm gate script failed: ${result.stderr}
|
|
Should Contain ${result.stdout} confirm-gate-ok
|