Harden deployment, authentication, firewall and media storage failure paths
This commit is contained in:
parent
64ede7bd05
commit
7145a35927
35 changed files with 2529 additions and 499 deletions
61
scripts/media-storage-check.py
Normal file
61
scripts/media-storage-check.py
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
"""Test the generated storage readiness script in a private mount namespace.
|
||||
|
||||
Usage: sudo python3 scripts/media-storage-check.py <media-storage-ready-unit>
|
||||
Uses temporary tmpfs mounts and NSS fixtures; host media and mount state are untouched.
|
||||
"""
|
||||
|
||||
import os, re, subprocess as sp, sys, tempfile
|
||||
from pathlib import Path
|
||||
|
||||
original = os.environ.get("FRED_TEST_ORIGINAL_MNTNS")
|
||||
if not original:
|
||||
os.execvpe(
|
||||
"unshare",
|
||||
["unshare", "-m", sys.executable, *sys.argv],
|
||||
{**os.environ, "FRED_TEST_ORIGINAL_MNTNS": os.readlink("/proc/self/ns/mnt")},
|
||||
)
|
||||
assert original != os.readlink("/proc/self/ns/mnt")
|
||||
sp.run(["mount", "--make-rprivate", "/"], check=True)
|
||||
sp.run(["mount", "-t", "tmpfs", "tmpfs", "/mnt"], check=True)
|
||||
for name in ["storage", "disk1", "disk2", "disk3"]:
|
||||
Path("/mnt", name).mkdir()
|
||||
unit = (Path(sys.argv[1]) / "media-storage-ready.service").read_text()
|
||||
script = re.search(r"^ExecStart=(\S+)", unit, re.M)[1]
|
||||
|
||||
|
||||
def ready(expected):
|
||||
r = sp.run([script], capture_output=True, text=True)
|
||||
assert (r.returncode == 0) == expected, r.stderr
|
||||
print(r.stderr.strip() or "Readiness succeeded", flush=True)
|
||||
|
||||
|
||||
ready(False)
|
||||
assert list(Path("/mnt/storage").iterdir()) == []
|
||||
for name in ["storage", "disk1", "disk2"]:
|
||||
sp.run(["mount", "-t", "tmpfs", "tmpfs", "/mnt/" + name], check=True)
|
||||
ready(False)
|
||||
assert list(Path("/mnt/storage").iterdir()) == []
|
||||
# Isolated NSS fixtures let tmpfiles resolve the real configured names.
|
||||
root = Path(tempfile.mkdtemp(prefix="fred-storage-users."))
|
||||
(root / "passwd").write_text(
|
||||
"root:x:0:0:root:/root:/bin/sh\n"
|
||||
+ "".join(
|
||||
f"{name}:x:0:0::{root}:/bin/sh\n"
|
||||
for name in ["fred", "qbittorrent", "sonarr", "radarr", "sabnzbd"]
|
||||
)
|
||||
)
|
||||
(root / "group").write_text("root:x:0:\nmedia:x:0:\n")
|
||||
for name in ["passwd", "group"]:
|
||||
sp.run(["mount", "--bind", str(root / name), "/etc/" + name], check=True)
|
||||
sp.run(["mount", "-t", "tmpfs", "tmpfs", "/mnt/disk3"], check=True)
|
||||
ready(True)
|
||||
assert Path("/mnt/storage/torrents/shows").is_dir()
|
||||
sp.run(["umount", "/mnt/disk2"], check=True)
|
||||
ready(False)
|
||||
sp.run(["umount", "/mnt/storage"], check=True)
|
||||
assert list(Path("/mnt/storage").iterdir()) == [], (
|
||||
"wrote into underlying root directory"
|
||||
)
|
||||
print(
|
||||
"Storage guard: missing pool/branch and lost branch refused; mounted pool prepared; underlying directory untouched"
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue