Files
openswarm/backend/tests/test_router_data_dir_permissions.py

57 lines
2.0 KiB
Python

"""9Router's state dir must be owner-only.
Its db.json carries live subscription access AND refresh tokens in plaintext, and 9Router writes
that file 0644. On a shared machine every other local account could read them. We tighten the
directory rather than the file because 9Router rewrites db.json on every token refresh, so a chmod
on the file itself would be undone within the hour.
Run:
cd backend && .venv/bin/python -m pytest tests/test_router_data_dir_permissions.py -v
"""
import os
import stat
import pytest
import backend.apps.nine_router.process as process
@pytest.fixture
def p_data_dir(tmp_path, monkeypatch):
d = tmp_path / "9router"
d.mkdir()
monkeypatch.setenv("DATA_DIR", str(d))
return d
@pytest.mark.skipif(os.name == "nt", reason="POSIX mode bits only")
def test_group_and_world_readable_dir_is_tightened(p_data_dir):
os.chmod(p_data_dir, 0o755)
process.harden_data_dir_permissions()
assert stat.S_IMODE(os.stat(p_data_dir).st_mode) == 0o700
@pytest.mark.skipif(os.name == "nt", reason="POSIX mode bits only")
def test_tokens_are_unreadable_by_others_afterwards(p_data_dir):
"""The property that actually matters, stated as the attacker sees it: no bit outside the owner."""
os.chmod(p_data_dir, 0o755)
(p_data_dir / "db.json").write_text('{"providerConnections":[]}')
process.harden_data_dir_permissions()
assert stat.S_IMODE(os.stat(p_data_dir).st_mode) & 0o077 == 0
@pytest.mark.skipif(os.name == "nt", reason="POSIX mode bits only")
def test_already_tight_dir_is_left_alone(p_data_dir):
os.chmod(p_data_dir, 0o700)
before = os.stat(p_data_dir).st_mtime_ns
process.harden_data_dir_permissions()
assert stat.S_IMODE(os.stat(p_data_dir).st_mode) == 0o700
assert os.stat(p_data_dir).st_mtime_ns == before
def test_missing_dir_does_not_raise(tmp_path, monkeypatch):
"""Runs before 9Router has ever started, so the dir legitimately may not exist yet."""
monkeypatch.setenv("DATA_DIR", str(tmp_path / "nope"))
process.harden_data_dir_permissions()