Files
Fenris/tests/test_store_group_access.py
T
2026-10-05 17:28:15 +05:30

79 lines
3.0 KiB
Python

"""Group access to the observation store — regression coverage for issue #54.
Two defects: (1) a non-group user's stat() on the store directory raised
PermissionError straight through open_store_readonly(), crashing status/TUI
instead of degrading to the Store fault view; (2) even group members could
not open the WAL-mode store because root-created sidecars lacked group write
and the store directory lacked group execute-then-write.
"""
import sys
from pathlib import Path
import pytest
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
from fenris.store import init_store
from fenris.status import StoreFault, open_store_readonly
def test_stat_permission_error_becomes_store_fault(monkeypatch, tmp_path):
"""stat() denied (non-group user on a 2750 dir) → StoreFault, not crash."""
store = tmp_path / "observations.db"
store.write_bytes(b"")
import pathlib
def denied(self, follow_symlinks=True):
raise PermissionError(13, "Permission denied")
monkeypatch.setattr(pathlib.Path, "exists", denied)
with pytest.raises(StoreFault):
open_store_readonly(store)
def test_connect_failure_becomes_store_fault(tmp_path):
"""sqlite failures stay wrapped as StoreFault (existing contract)."""
garbage = tmp_path / "observations.db"
garbage.write_bytes(b"not a database" * 100)
with pytest.raises(StoreFault):
open_store_readonly(garbage)
def test_init_store_leaves_files_group_writable(tmp_path):
"""Root-created stores must stay readable by WAL readers: db and sidecars
need group write after init_store (issue #54)."""
store = tmp_path / "observations.db"
conn = init_store(store)
try:
assert (store.stat().st_mode & 0o060) == 0o060, "db not group rw"
wal = store.with_name(store.name + "-wal")
shm = store.with_name(store.name + "-shm")
if wal.exists():
assert (wal.stat().st_mode & 0o060) == 0o060, "wal not group rw"
if shm.exists():
assert (shm.stat().st_mode & 0o060) == 0o060, "shm not group rw"
finally:
conn.close()
def test_readonly_open_works_after_init_store(tmp_path):
"""The shipped read path opens a store created by init_store."""
store = tmp_path / "observations.db"
writer = init_store(store)
writer.execute("INSERT INTO monitoring_periods (started_at) VALUES ('2026-01-01T00:00:00+00:00')")
writer.commit()
conn = open_store_readonly(store)
assert conn is not None
conn.close()
writer.close()
def test_packaging_ships_group_access():
"""tmpfiles must create the store dir group-writable; collect unit must
keep the umask loose so root-created sidecars stay group-accessible."""
repo = Path(__file__).resolve().parent.parent
assert "2770" in (repo / "packaging" / "tmpfiles.d" / "fenris.conf").read_text()
assert "2750" not in (repo / "packaging" / "tmpfiles.d" / "fenris.conf").read_text()
assert "UMask=002" in (repo / "units" / "fenris-collect.service").read_text()