fix(cli): repair dangerous command approval UI
Move the dangerous-command header onto its own line inside the approval box so the panel border no longer cuts through it, and restore the long-command expand path in the active prompt_toolkit approval callback. The CLI already had a merged 'view full command' feature in fallback/gateway paths, but the live TUI callback was still using an older choice set and never exposed it. Add regression tests for long-command view state, in-place expansion, and panel rendering.
This commit is contained in:
100
tests/test_cli_approval_ui.py
Normal file
100
tests/test_cli_approval_ui.py
Normal file
@@ -0,0 +1,100 @@
|
||||
import queue
|
||||
import threading
|
||||
import time
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from cli import HermesCLI
|
||||
|
||||
|
||||
def _make_cli_stub():
|
||||
cli = HermesCLI.__new__(HermesCLI)
|
||||
cli._approval_state = None
|
||||
cli._approval_deadline = 0
|
||||
cli._approval_lock = threading.Lock()
|
||||
cli._invalidate = MagicMock()
|
||||
cli._app = SimpleNamespace(invalidate=MagicMock())
|
||||
return cli
|
||||
|
||||
|
||||
class TestCliApprovalUi:
|
||||
def test_approval_callback_includes_view_for_long_commands(self):
|
||||
cli = _make_cli_stub()
|
||||
command = "sudo dd if=/tmp/githubcli-keyring.gpg of=/usr/share/keyrings/githubcli-archive-keyring.gpg bs=4M status=progress"
|
||||
result = {}
|
||||
|
||||
def _run_callback():
|
||||
result["value"] = cli._approval_callback(command, "disk copy")
|
||||
|
||||
thread = threading.Thread(target=_run_callback, daemon=True)
|
||||
thread.start()
|
||||
|
||||
deadline = time.time() + 2
|
||||
while cli._approval_state is None and time.time() < deadline:
|
||||
time.sleep(0.01)
|
||||
|
||||
assert cli._approval_state is not None
|
||||
assert "view" in cli._approval_state["choices"]
|
||||
|
||||
cli._approval_state["response_queue"].put("deny")
|
||||
thread.join(timeout=2)
|
||||
assert result["value"] == "deny"
|
||||
|
||||
def test_handle_approval_selection_view_expands_in_place(self):
|
||||
cli = _make_cli_stub()
|
||||
cli._approval_state = {
|
||||
"command": "sudo dd if=/tmp/in of=/usr/share/keyrings/githubcli-archive-keyring.gpg bs=4M status=progress",
|
||||
"description": "disk copy",
|
||||
"choices": ["once", "session", "always", "deny", "view"],
|
||||
"selected": 4,
|
||||
"response_queue": queue.Queue(),
|
||||
}
|
||||
|
||||
cli._handle_approval_selection()
|
||||
|
||||
assert cli._approval_state is not None
|
||||
assert cli._approval_state["show_full"] is True
|
||||
assert "view" not in cli._approval_state["choices"]
|
||||
assert cli._approval_state["selected"] == 3
|
||||
assert cli._approval_state["response_queue"].empty()
|
||||
|
||||
def test_approval_display_places_title_inside_box_not_border(self):
|
||||
cli = _make_cli_stub()
|
||||
cli._approval_state = {
|
||||
"command": "sudo dd if=/tmp/in of=/usr/share/keyrings/githubcli-archive-keyring.gpg bs=4M status=progress",
|
||||
"description": "disk copy",
|
||||
"choices": ["once", "session", "always", "deny", "view"],
|
||||
"selected": 0,
|
||||
"response_queue": queue.Queue(),
|
||||
}
|
||||
|
||||
fragments = cli._get_approval_display_fragments()
|
||||
rendered = "".join(text for _style, text in fragments)
|
||||
lines = rendered.splitlines()
|
||||
|
||||
assert lines[0].startswith("╭")
|
||||
assert "Dangerous Command" not in lines[0]
|
||||
assert any("Dangerous Command" in line for line in lines[1:3])
|
||||
assert "Show full command" in rendered
|
||||
assert "githubcli-archive-keyring.gpg" not in rendered
|
||||
|
||||
def test_approval_display_shows_full_command_after_view(self):
|
||||
cli = _make_cli_stub()
|
||||
full_command = "sudo dd if=/tmp/in of=/usr/share/keyrings/githubcli-archive-keyring.gpg bs=4M status=progress"
|
||||
cli._approval_state = {
|
||||
"command": full_command,
|
||||
"description": "disk copy",
|
||||
"choices": ["once", "session", "always", "deny"],
|
||||
"selected": 0,
|
||||
"show_full": True,
|
||||
"response_queue": queue.Queue(),
|
||||
}
|
||||
|
||||
fragments = cli._get_approval_display_fragments()
|
||||
rendered = "".join(text for _style, text in fragments)
|
||||
|
||||
assert "..." not in rendered
|
||||
assert "githubcli-" in rendered
|
||||
assert "archive-" in rendered
|
||||
assert "keyring.gpg" in rendered
|
||||
assert "status=progress" in rendered
|
||||
Reference in New Issue
Block a user