c78862fe8b
ISSUES CLOSED: #6361
131 lines
4.4 KiB
Python
131 lines
4.4 KiB
Python
"""Shell safety-related step definitions for the TUI app coverage suite."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from types import SimpleNamespace
|
|
from unittest.mock import patch
|
|
|
|
from behave import given, then, when
|
|
|
|
from cleveragents.tui.input.modes import InputMode, ModeResult
|
|
from cleveragents.tui.shell_safety import (
|
|
DangerousCommandWarning,
|
|
DangerousPattern,
|
|
ShellDangerLevel,
|
|
)
|
|
|
|
from features.steps._tui_helpers import _submit_text, _submit_text_with_mocked_shell
|
|
|
|
|
|
@when('I submit "{text}" to the app')
|
|
def step_submit_text(context, text):
|
|
os.environ["CLEVERAGENTS_ALLOW_DANGEROUS_SHELL"] = "1"
|
|
|
|
def restore_env() -> None:
|
|
os.environ.pop("CLEVERAGENTS_ALLOW_DANGEROUS_SHELL", None)
|
|
|
|
context.add_cleanup(restore_env)
|
|
_submit_text(context, text)
|
|
|
|
|
|
@when('I submit "{text}" to the app with shell execution mocked')
|
|
def step_submit_text_mocked_shell(context, text):
|
|
os.environ["CLEVERAGENTS_ALLOW_DANGEROUS_SHELL"] = "1"
|
|
|
|
def restore_env() -> None:
|
|
os.environ.pop("CLEVERAGENTS_ALLOW_DANGEROUS_SHELL", None)
|
|
|
|
context.add_cleanup(restore_env)
|
|
_submit_text_with_mocked_shell(context, text)
|
|
|
|
|
|
@when("I submit shell text that produces a None shell result")
|
|
def step_submit_shell_none(context):
|
|
# Patch the mode router to emulate a shell submission returning None.
|
|
with patch(
|
|
"cleveragents.tui.app.InputModeRouter.process",
|
|
return_value=ModeResult(
|
|
mode=InputMode.SHELL,
|
|
expanded_text="!nothing",
|
|
references=[],
|
|
shell_result=None,
|
|
command_result=None,
|
|
shell_warning=None,
|
|
),
|
|
):
|
|
_submit_text(context, "!nothing")
|
|
|
|
|
|
@then("the shell warning indicator should be visible")
|
|
def step_shell_warning_visible(context):
|
|
MockStatic = context._tui_mock_static
|
|
banner = context._tui_app.query_one("#shell-warning", MockStatic)
|
|
assert banner.display is True, "Expected shell warning indicator to be visible"
|
|
assert banner._text, "Expected warning indicator text to be populated"
|
|
|
|
|
|
@then("the shell warning indicator should not be visible")
|
|
def step_shell_warning_hidden(context):
|
|
MockStatic = context._tui_mock_static
|
|
banner = context._tui_app.query_one("#shell-warning", MockStatic)
|
|
assert banner.display is False, "Expected shell warning indicator to be hidden"
|
|
assert banner._text == "", "Expected warning indicator text to be cleared"
|
|
|
|
|
|
@then("the prompt should be marked as dangerous")
|
|
def step_prompt_marked_dangerous(context):
|
|
from cleveragents.tui.widgets.prompt import PromptInput
|
|
|
|
prompt = context._tui_app.query_one("#prompt", PromptInput)
|
|
assert prompt.has_class("dangerous"), "Expected prompt to have dangerous class"
|
|
|
|
|
|
@then("the prompt should not be marked as dangerous")
|
|
def step_prompt_not_dangerous(context):
|
|
from cleveragents.tui.widgets.prompt import PromptInput
|
|
|
|
prompt = context._tui_app.query_one("#prompt", PromptInput)
|
|
assert not prompt.has_class("dangerous"), "Expected prompt to be safe"
|
|
|
|
|
|
@given("shell danger warnings are disabled in settings")
|
|
@when("shell danger warnings are disabled in settings")
|
|
def step_disable_shell_warnings(context):
|
|
stub = SimpleNamespace(shell_warn_dangerous=False)
|
|
app_patcher = patch("cleveragents.tui.app.get_settings", return_value=stub)
|
|
app_patcher.start()
|
|
context.add_cleanup(app_patcher.stop)
|
|
|
|
|
|
@when('I ask the app to confirm shell command "{command}"')
|
|
def step_confirm_shell_command(context, command):
|
|
context._tui_shell_confirmation = context._tui_app._confirm_dangerous_shell(command)
|
|
|
|
|
|
@then("the shell confirmation result should be allowed")
|
|
def step_shell_confirmation_allowed(context):
|
|
assert context._tui_shell_confirmation is True
|
|
|
|
|
|
@then("the shell confirmation result should be blocked")
|
|
def step_shell_confirmation_blocked(context):
|
|
assert context._tui_shell_confirmation is False
|
|
|
|
|
|
@when("I ask the app to handle a shell warning")
|
|
def step_handle_shell_warning(context):
|
|
pattern = DangerousPattern(
|
|
name="test_warning",
|
|
pattern=r"rm -rf",
|
|
level=ShellDangerLevel.CRITICAL,
|
|
description="test warning",
|
|
)
|
|
warning = DangerousCommandWarning.from_pattern("rm -rf /tmp", pattern)
|
|
context._tui_shell_warning_result = context._tui_app._handle_shell_warning(warning)
|
|
|
|
|
|
@then("the shell warning callback result should be allowed")
|
|
def step_shell_warning_callback_allowed(context):
|
|
assert context._tui_shell_warning_result is True
|