87 lines
4.0 KiB
Python
87 lines
4.0 KiB
Python
"""Standalone Bash contract; subprocesses never install or change services."""
|
|
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import subprocess
|
|
import tempfile
|
|
import unittest
|
|
|
|
from install_support import entry_with_python, load_installer
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
|
|
|
|
class InstallEntryTests(unittest.TestCase):
|
|
def run_bash(self, script, *arguments, **kwargs):
|
|
return subprocess.run(["/bin/bash", "-s", "--", *arguments], input=script,
|
|
env={}, text=True, capture_output=True, timeout=10, **kwargs)
|
|
|
|
def test_root_entry_pins_the_independent_key_and_has_valid_shell_syntax(self):
|
|
installer = load_installer()
|
|
self.assertEqual(installer.DEFAULT_PUBLIC_KEY,
|
|
(ROOT / "skills/assets/release.pub").read_text().strip())
|
|
syntax = subprocess.run(["/bin/bash", "-n", str(ROOT / "install")], env={},
|
|
text=True, capture_output=True, timeout=10)
|
|
self.assertEqual(syntax.returncode, 0, syntax.stderr)
|
|
|
|
def test_file_and_pipe_help_do_not_need_a_checkout(self):
|
|
with tempfile.TemporaryDirectory(prefix="dever-entry-") as directory:
|
|
entry = Path(directory) / "install"
|
|
entry.write_bytes((ROOT / "install").read_bytes())
|
|
for command, contents in ((["/bin/bash", str(entry), "--help"], None),
|
|
(["/bin/bash", "-s", "--", "--help"], entry.read_text())):
|
|
result = subprocess.run(command, input=contents, cwd=directory, env={},
|
|
text=True, capture_output=True, timeout=10)
|
|
self.assertEqual(result.returncode, 0, result.stderr)
|
|
self.assertIn("--trusted-key", result.stdout)
|
|
self.assertIn("--system-root", result.stdout)
|
|
invalid = self.run_bash((ROOT / "install").read_text(), "--unknown-argument")
|
|
self.assertEqual(invalid.returncode, 2)
|
|
|
|
def test_arguments_python_isolation_and_exit_code_are_preserved(self):
|
|
source = '''import json
|
|
import sys
|
|
print(json.dumps([sys.argv[1:], sys.flags.isolated]))
|
|
raise SystemExit(37)
|
|
'''
|
|
script = entry_with_python(source)
|
|
arguments = ["--release", "/a path/with 'quotes'", "", "$(not executed)", "*", "--no-start"]
|
|
result = self.run_bash(script, *arguments)
|
|
self.assertEqual(result.returncode, 37, result.stderr)
|
|
self.assertEqual(json.loads(result.stdout), [arguments, 1])
|
|
|
|
def test_truncated_body_does_not_execute_python_or_sudo(self):
|
|
script = entry_with_python('print("EXECUTED")\n')
|
|
for end in (script.index("import sys"), script.index("DEVER_INSTALL_PYTHON\n}"),
|
|
script.index('\ndever_install "$@"')):
|
|
result = self.run_bash(script[:end])
|
|
self.assertNotIn("EXECUTED", result.stdout)
|
|
|
|
@unittest.skipUnless(os.geteuid() == 0 and Path("/usr/bin/sudo").is_file(),
|
|
"real nonroot UID fixture requires root and sudo executable")
|
|
def test_nonroot_help_skips_sudo_and_install_forwards_through_sudo(self):
|
|
# Replace only the sudo command in this owned Bash process. It records
|
|
# argv and returns without executing Python or attempting escalation.
|
|
intercept = '''function /usr/bin/sudo() {
|
|
printf '<%s>\\n' "$@"
|
|
return 43
|
|
}
|
|
'''
|
|
script = intercept + (ROOT / "install").read_text()
|
|
lowered = {"user": 65534, "group": 65534, "extra_groups": []}
|
|
help_result = self.run_bash(script, "--help", **lowered)
|
|
self.assertEqual(help_result.returncode, 0, help_result.stderr)
|
|
self.assertIn("--release", help_result.stdout)
|
|
install = self.run_bash(script, "--system-root", "/owned image", "--no-start", **lowered)
|
|
self.assertEqual(install.returncode, 43, install.stderr)
|
|
self.assertEqual(install.stdout.splitlines(), [
|
|
"<-->", "</usr/bin/python3>", "<-I>", "<->", "<--system-root>",
|
|
"</owned image>", "<--no-start>",
|
|
])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|