"""Graphical sudo prompts: command rewriting and helper resolution. Pure logic — no display, no sudo, no password.""" import sys from pathlib import Path import pytest sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from bolt_pet import sudo_askpass # ── rewriting ──────────────────────────────────────────────────────────────── @pytest.mark.parametrize( "command,expected", [ ("sudo apt update", "sudo -A apt update"), ("sudo apt update", "sudo -A apt update"), # spacing preserved ("apt update && sudo apt upgrade", "apt update && sudo -A apt upgrade"), ("ls; sudo reboot", "ls; sudo -A reboot"), ("echo hi | sudo tee /etc/motd", "echo hi | sudo -A tee /etc/motd"), ("sudo systemctl restart x\nsudo systemctl status x", "sudo -A systemctl restart x\nsudo -A systemctl status x"), ], ) def test_bare_sudo_gets_the_askpass_flag(command, expected): assert sudo_askpass.add_askpass_flag(command) == expected @pytest.mark.parametrize( "command", [ "sudo -n apt update", # explicitly non-interactive "sudo -A apt update", # already asking "sudo -u bob whoami", # the caller was explicit "ls -la", # no sudo at all "echo 'run sudo later'", # inside a quoted string "pseudo --version", # not the word sudo ], ) def test_commands_that_must_not_be_rewritten(command): assert sudo_askpass.add_askpass_flag(command) == command def test_blank_input(): assert sudo_askpass.add_askpass_flag("") == "" assert sudo_askpass.add_askpass_flag(None) == "" @pytest.mark.parametrize( "command,expected", [ ("sudo apt update", True), ("ls && sudo reboot", True), ("ls -la", False), ("echo 'sudo'", False), ("", False), ], ) def test_which_commands_get_the_longer_timeout(command, expected): assert sudo_askpass.needs_password_prompt(command) is expected # ── helper resolution ──────────────────────────────────────────────────────── def test_a_configured_helper_wins(): found = sudo_askpass.find_helper( configured="/opt/my-askpass", is_executable=lambda p: p == "/opt/my-askpass", ) assert found == "/opt/my-askpass" def test_a_configured_helper_that_is_not_executable_is_not_silently_replaced(): """Better to have sudo fail than to quietly prompt with something the user didn't choose.""" assert sudo_askpass.find_helper( configured="/opt/typo", is_executable=lambda p: False, which=lambda t: "/usr/bin/zenity", ) is None def test_a_real_askpass_binary_beats_a_generated_wrapper(): found = sudo_askpass.find_helper( configured="", is_executable=lambda p: p == "/usr/bin/ksshaskpass", which=lambda tool: "/usr/bin/zenity", ) assert found == "/usr/bin/ksshaskpass" def test_falls_back_to_wrapping_a_dialog_tool(tmp_path): found = sudo_askpass.find_helper( configured="", is_executable=lambda p: False, which=lambda tool: "/usr/bin/zenity" if tool == "zenity" else None, cache_dir=tmp_path, ) script = tmp_path / "askpass.sh" assert found == str(script) assert "zenity --password" in script.read_text() assert script.stat().st_mode & 0o777 == 0o700 # nobody else edits the password box def test_no_helper_available_at_all(): assert sudo_askpass.find_helper( configured="", is_executable=lambda p: False, which=lambda tool: None, ) is None def test_the_wrapper_passes_sudos_prompt_through(): """sudo hands the helper its prompt as $1 — it names the account the password is for, which is worth showing in the dialog.""" script = sudo_askpass.helper_script("/usr/bin/zenity") assert script.startswith("#!/bin/sh") assert '"$1"' in script def test_environment_points_sudo_at_the_helper(): env = sudo_askpass.environment("/tmp/askpass.sh", base={"PATH": "/usr/bin"}) assert env["SUDO_ASKPASS"] == "/tmp/askpass.sh" assert env["PATH"] == "/usr/bin" # the rest of the environment survives