import pytest from unittest.mock import patch, MagicMock from rook.shell import run_shell, PolicyError def test_run_shell_in_approved_dir(): with patch('rook.shell.is_approved_dir', return_value=True): with patch('rook.shell.subprocess.run', return_value=MagicMock(stdout='hello\n', returncode=0)): result = run_shell('echo hello', cwd='/fake/dir') assert result == 'hello\n' def test_run_shell_denied_raises_policy_error(): with patch('rook.shell.is_approved_dir', return_value=False): with patch('rook.shell.confirm_spawn', return_value=False): with pytest.raises(PolicyError): run_shell('ls', cwd='/tmp') def test_run_shell_confirmed_outside_approved(): mock_confirm = MagicMock(return_value=True) with patch('rook.shell.is_approved_dir', return_value=False): with patch('rook.shell.confirm_spawn', mock_confirm): with patch('rook.shell.subprocess.run', return_value=MagicMock(stdout='ok', returncode=0)): result = run_shell('ls', cwd='/tmp') assert result == 'ok' mock_confirm.assert_called_once() def test_run_shell_logs_call(): with patch('rook.shell.is_approved_dir', return_value=True): with patch('rook.shell.subprocess.run', return_value=MagicMock(stdout='hi\n', returncode=0)): with patch('logging.Logger.info') as mock_log: run_shell('echo hi', cwd='/fake') assert mock_log.called def test_run_shell_nonzero_returncode_raises(): with patch('rook.shell.is_approved_dir', return_value=True): with patch('rook.shell.subprocess.run', return_value=MagicMock(stdout='', stderr='err', returncode=1)): with pytest.raises(RuntimeError): run_shell('bad', cwd='/fake')