106 lines
2.9 KiB
Python
106 lines
2.9 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
import stat
|
|
from pathlib import Path
|
|
|
|
from chguard.restore import apply_restore, plan_restore
|
|
|
|
|
|
def test_plan_restore_reports_mode_owner_missing_and_type_changes(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
root = tmp_path / "root"
|
|
root.mkdir()
|
|
config = root / "config.txt"
|
|
config.write_text("config", encoding="utf-8")
|
|
config.chmod(0o644)
|
|
logs = root / "logs"
|
|
logs.write_text("not a directory", encoding="utf-8")
|
|
|
|
current = config.lstat()
|
|
rows = [
|
|
("config.txt", "file", 0o600, current.st_uid + 1, current.st_gid),
|
|
("missing.txt", "file", 0o644, current.st_uid, current.st_gid),
|
|
("logs", "dir", 0o755, current.st_uid, current.st_gid),
|
|
]
|
|
|
|
changes = plan_restore(
|
|
root=root,
|
|
rows=rows,
|
|
restore_permissions=True,
|
|
restore_owner=True,
|
|
)
|
|
|
|
kinds_by_path = {(change.path.name, change.kind) for change in changes}
|
|
assert ("config.txt", "mode") in kinds_by_path
|
|
assert ("config.txt", "owner") in kinds_by_path
|
|
assert ("missing.txt", "missing") in kinds_by_path
|
|
assert ("logs", "type") in kinds_by_path
|
|
|
|
|
|
def test_plan_restore_marks_unselected_scope_as_not_applicable(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
root = tmp_path / "root"
|
|
root.mkdir()
|
|
config = root / "config.txt"
|
|
config.write_text("config", encoding="utf-8")
|
|
config.chmod(0o644)
|
|
st = config.lstat()
|
|
|
|
changes = plan_restore(
|
|
root=root,
|
|
rows=[("config.txt", "file", 0o600, st.st_uid, st.st_gid)],
|
|
restore_permissions=False,
|
|
restore_owner=True,
|
|
)
|
|
|
|
assert len(changes) == 1
|
|
assert changes[0].kind == "mode"
|
|
assert not changes[0].will_apply
|
|
|
|
|
|
def test_apply_restore_changes_mode_without_changing_contents(
|
|
tmp_path: Path,
|
|
) -> None:
|
|
root = tmp_path / "root"
|
|
root.mkdir()
|
|
config = root / "config.txt"
|
|
config.write_text("config", encoding="utf-8")
|
|
config.chmod(0o644)
|
|
st = config.lstat()
|
|
|
|
apply_restore(
|
|
root=root,
|
|
rows=[("config.txt", "file", 0o600, st.st_uid, st.st_gid)],
|
|
restore_permissions=True,
|
|
restore_owner=False,
|
|
)
|
|
|
|
assert stat.S_IMODE(config.lstat().st_mode) == 0o600
|
|
assert config.read_text(encoding="utf-8") == "config"
|
|
|
|
|
|
def test_apply_restore_skips_missing_and_type_mismatch(tmp_path: Path) -> None:
|
|
root = tmp_path / "root"
|
|
root.mkdir()
|
|
config = root / "config.txt"
|
|
config.write_text("config", encoding="utf-8")
|
|
config.chmod(0o644)
|
|
st = config.lstat()
|
|
|
|
apply_restore(
|
|
root=root,
|
|
rows=[
|
|
("missing.txt", "file", 0o600, st.st_uid, st.st_gid),
|
|
("config.txt", "dir", 0o600, st.st_uid, st.st_gid),
|
|
],
|
|
restore_permissions=True,
|
|
restore_owner=False,
|
|
)
|
|
|
|
assert not (root / "missing.txt").exists()
|
|
assert stat.S_IMODE(config.lstat().st_mode) == 0o644
|
|
assert os.listdir(root) == ["config.txt"]
|