75 lines
2.3 KiB
Python
75 lines
2.3 KiB
Python
from __future__ import annotations
|
|
|
|
import importlib
|
|
import stat
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
from backup_tool.config import Settings
|
|
|
|
snapshot = importlib.import_module("backup_tool.snapshot")
|
|
|
|
|
|
def settings_for(tmp_path: Path) -> Settings:
|
|
key = tmp_path / "master.key"
|
|
key.write_bytes(b"m6-restore-path-test-master-key-material")
|
|
key.chmod(0o600)
|
|
repositories = tmp_path / "repositories"
|
|
sources = tmp_path / "sources"
|
|
restores = tmp_path / "restores"
|
|
for directory in (repositories, sources, restores):
|
|
directory.mkdir()
|
|
return Settings(
|
|
data_dir=tmp_path,
|
|
database_url=f"sqlite+aiosqlite:///{tmp_path / 'metadata.db'}",
|
|
repository_roots=(repositories,),
|
|
local_source_roots=(sources,),
|
|
restore_roots=(restores,),
|
|
master_key_file=key,
|
|
min_free_bytes=1,
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("name", ["existing", "outside", "root"])
|
|
def test_restore_destination_rejects_existing_or_outside_paths(tmp_path: Path, name: str) -> None:
|
|
settings = settings_for(tmp_path)
|
|
root = settings.restore_roots[0]
|
|
outside = tmp_path / "outside"
|
|
outside.mkdir()
|
|
existing = root / "existing"
|
|
existing.mkdir()
|
|
destinations = {
|
|
"existing": existing,
|
|
"outside": outside / "restore",
|
|
"root": root,
|
|
}
|
|
|
|
with pytest.raises(snapshot.SnapshotError):
|
|
snapshot.validate_restore_destination(settings, str(destinations[name]))
|
|
|
|
|
|
def test_restore_strips_special_permission_bits(tmp_path: Path) -> None:
|
|
target = tmp_path / "restored"
|
|
target.write_bytes(b"content")
|
|
|
|
snapshot._apply_metadata(
|
|
target,
|
|
{"metadata_support": ["mode"], "mode": 0o7777},
|
|
)
|
|
|
|
mode = stat.S_IMODE(target.stat().st_mode)
|
|
assert mode == 0o777
|
|
assert mode & (stat.S_ISUID | stat.S_ISGID | stat.S_ISVTX) == 0
|
|
|
|
|
|
def test_restore_destination_rejects_a_symlinked_parent(tmp_path: Path) -> None:
|
|
settings = settings_for(tmp_path)
|
|
outside = tmp_path / "outside"
|
|
outside.mkdir()
|
|
(settings.restore_roots[0] / "linked").symlink_to(outside, target_is_directory=True)
|
|
|
|
with pytest.raises(snapshot.SnapshotError):
|
|
snapshot.validate_restore_destination(
|
|
settings, str(settings.restore_roots[0] / "linked" / "restore")
|
|
)
|