diff --git a/src/rook/policy.py b/src/rook/policy.py new file mode 100644 index 0000000..0664f86 --- /dev/null +++ b/src/rook/policy.py @@ -0,0 +1,34 @@ +import os +import shutil + +APPROVED_DIRS: list[str] = [ + os.path.abspath(os.path.expanduser('~/dev')), + os.path.abspath(os.path.expanduser('~/logs')), + os.path.abspath(os.path.expanduser('~/ModernCoSy')), +] + +CAPABILITY_ALLOWLISTS: dict[str, list[str]] = { + 'file': ['read', 'write', 'edit'], + 'shell': ['run'], + 'git': ['status', 'log', 'diff', 'add', 'commit'], +} + + +def is_approved_dir(path: str) -> bool: + resolved = os.path.abspath(path) + return any(resolved.startswith(d) for d in APPROVED_DIRS) + + +def confirm_spawn(action: str, details: str) -> bool: + response = input(f"Allow '{action}' with '{details}'? [y/n]: ") + return response.strip().lower() == 'y' + + +def backup_before_edit(file_path: str) -> str: + backup_path = file_path + '.bak' + shutil.copy2(file_path, backup_path) + return backup_path + + +def check_allowlist(capability: str, operation: str) -> bool: + return operation in CAPABILITY_ALLOWLISTS.get(capability, []) diff --git a/tests/test_policy.py b/tests/test_policy.py new file mode 100644 index 0000000..ebbc65f --- /dev/null +++ b/tests/test_policy.py @@ -0,0 +1,42 @@ +import os +from unittest.mock import patch +import pytest + +from rook.policy import is_approved_dir, confirm_spawn, backup_before_edit, check_allowlist + + +def test_is_approved_dir_true(): + assert is_approved_dir(os.path.expanduser('~/dev/myproject')) == True + + +def test_is_approved_dir_false(): + assert is_approved_dir('/tmp/evil') == False + + +def test_is_approved_dir_subpath(): + assert is_approved_dir(os.path.expanduser('~/logs/app.log')) == True + + +def test_confirm_spawn_yes(): + with patch('builtins.input', return_value='y'): + assert confirm_spawn('git push', 'origin main') == True + + +def test_confirm_spawn_no(): + with patch('builtins.input', return_value='n'): + assert confirm_spawn('rm file', 'myfile.txt') == False + + +def test_backup_before_edit(tmp_path): + tmp_file = tmp_path / 'sample.txt' + tmp_file.write_text('hello') + backup_path = backup_before_edit(str(tmp_file)) + assert os.path.exists(backup_path) + assert open(backup_path).read() == 'hello' + + +def test_check_allowlist(): + assert check_allowlist('file', 'read') == True + assert check_allowlist('file', 'delete') == False + assert check_allowlist('git', 'push') == False + assert check_allowlist('git', 'commit') == True