1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
"""Test the guarded sudoers.pacnew replacement.
Bug (Minor, hard consequence): the installer did
[ -f /etc/sudoers.pacnew ] && cp /etc/sudoers.pacnew /etc/sudoers
with no validation. A malformed pacnew replaces /etc/sudoers with a file sudo
refuses to parse, locking out privilege escalation right before the NOPASSWD
rule is appended. replace_sudoers_pacnew now runs `visudo -cf` on the pacnew
first and only copies a file that validates; a failure warns (non-fatal) and
leaves the working sudoers in place.
Method: sed-extract replace_sudoers_pacnew from the real `archsetup`, pass a
temp pacnew + temp target (the function's positional-arg testability seam), and
drive it with a fake visudo (controlled validation result) and a fake
error_warn recorder.
Run from repo root:
python3 -m unittest tests.installer-steps.test_replace_sudoers_pacnew
"""
import os
import subprocess
import tempfile
import textwrap
import unittest
REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
ARCHSETUP = os.path.join(REPO_ROOT, "archsetup")
def run(*, pacnew_exists, visudo_rc):
"""Run replace_sudoers_pacnew with a temp pacnew/target and fake visudo."""
with tempfile.TemporaryDirectory() as d:
pacnew = os.path.join(d, "sudoers.pacnew")
target = os.path.join(d, "sudoers")
with open(target, "w") as f:
f.write("ORIGINAL\n")
if pacnew_exists:
with open(pacnew, "w") as f:
f.write("NEW\n")
script = textwrap.dedent(f"""\
logfile=/dev/null
display() {{ :; }}
visudo() {{ return {visudo_rc}; }}
error_warn() {{ echo "WARN: $1"; return 1; }}
source <(sed -n '/^replace_sudoers_pacnew() {{/,/^}}/p' "{ARCHSETUP}")
replace_sudoers_pacnew "{pacnew}" "{target}"
echo "RC=$?"
echo "TARGET=[$(cat "{target}")]"
""")
return subprocess.run(
["bash", "-c", script], capture_output=True, text=True, timeout=10,
)
class ReplaceSudoersPacnew(unittest.TestCase):
def test_valid_pacnew_is_copied(self):
r = run(pacnew_exists=True, visudo_rc=0)
self.assertIn("TARGET=[NEW]", r.stdout)
self.assertNotIn("WARN", r.stdout)
def test_invalid_pacnew_warns_and_keeps_original(self):
r = run(pacnew_exists=True, visudo_rc=1)
self.assertIn("WARN", r.stdout,
"a pacnew that fails visudo must warn, not clobber sudoers")
self.assertIn("TARGET=[ORIGINAL]", r.stdout,
"the working sudoers must survive a malformed pacnew")
def test_no_pacnew_is_a_noop(self):
r = run(pacnew_exists=False, visudo_rc=0)
self.assertIn("RC=0", r.stdout)
self.assertIn("TARGET=[ORIGINAL]", r.stdout)
self.assertNotIn("WARN", r.stdout)
if __name__ == "__main__":
unittest.main()
|