107 lines
3.1 KiB
Python
107 lines
3.1 KiB
Python
# retoor <retoor@molodetz.nl>
|
|
import os
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
|
|
EXPECTED_KEYS = [
|
|
"SECRET_KEY",
|
|
"PLAYWRIGHT_HEADLESS",
|
|
"PLAYWRIGHT_SLOW_MO",
|
|
"MOLODETZ_ADMIN_USERNAME",
|
|
"MOLODETZ_ADMIN_EMAIL",
|
|
"MOLODETZ_ADMIN_PASSWORD",
|
|
"MOLODETZ_PORT",
|
|
"MOLODETZ_TEST_PORT",
|
|
"MOLODETZ_SITE_URL",
|
|
"MOLODETZ_DATA_DIR",
|
|
"MOLODETZ_DATABASE_URL",
|
|
"MOLODETZ_INTERNAL_BASE_URL",
|
|
"MOLODETZ_DISABLE_SERVICES",
|
|
"MOLODETZ_DISABLE_RATE_LIMIT",
|
|
"MOLODETZ_RATE_LIMIT",
|
|
"MOLODETZ_WEB_WORKERS",
|
|
"MOLODETZ_TEMPLATE_AUTO_RELOAD",
|
|
"MOLODETZ_STATIC_VERSION",
|
|
"MOLODETZ_LOG_LEVEL",
|
|
"MOLODETZ_PRESENCE_TIMEOUT_SECONDS",
|
|
"MOLODETZ_PRESENCE_ONLINE_LIMIT",
|
|
"MOLODETZ_PRESENCE_TRACK_LIMIT",
|
|
"MOLODETZ_PRESENCE_ONLINE_MARGIN_SECONDS",
|
|
"MOLODETZ_OUTBOUND_PROXY_URL",
|
|
"MOLODETZ_RCLONE_BIN",
|
|
"MOLODETZ_RCLONE_CONFIG",
|
|
"MOLODETZ_BACKUP_OFFLOAD_REMOTE",
|
|
"MOLODETZ_SITEMAP_TTL",
|
|
"MOLODETZ_LANDING_TTL",
|
|
"MOLODETZ_UNREAD_TTL",
|
|
]
|
|
|
|
NONEMPTY_PATH_KEYS = [
|
|
"MOLODETZ_DATA_DIR",
|
|
"MOLODETZ_DATABASE_URL",
|
|
"MOLODETZ_INTERNAL_BASE_URL",
|
|
"MOLODETZ_RCLONE_BIN",
|
|
"MOLODETZ_RCLONE_CONFIG",
|
|
]
|
|
|
|
|
|
def read_example():
|
|
values = {}
|
|
for line in (ROOT / ".env.example").read_text().splitlines():
|
|
match = re.match(r"^([A-Z][A-Z0-9_]*)=(.*)$", line)
|
|
if match:
|
|
values[match.group(1)] = match.group(2)
|
|
return values
|
|
|
|
|
|
def test_env_example_lists_every_key():
|
|
values = read_example()
|
|
assert sorted(values) == sorted(EXPECTED_KEYS)
|
|
|
|
|
|
def test_env_example_keeps_path_values_nonempty():
|
|
values = read_example()
|
|
for key in NONEMPTY_PATH_KEYS:
|
|
assert values[key].strip() != ""
|
|
|
|
|
|
def test_config_reads_no_unknown_keys():
|
|
source = (ROOT / "molodetz" / "config.py").read_text()
|
|
prefixed = set(re.findall(r'_env(?:_int)?\("([A-Z_]+)"', source))
|
|
assert set(re.findall(r'os\.environ\.get\("([A-Z_]+)"', source)) <= {"SECRET_KEY", "PLAYWRIGHT_HEADLESS", "PLAYWRIGHT_SLOW_MO"}
|
|
assert {f"MOLODETZ_{name}" for name in prefixed} <= set(EXPECTED_KEYS)
|
|
|
|
|
|
def run_config_import(data_dir, database_url):
|
|
env = {**os.environ, "MOLODETZ_DATA_DIR": data_dir, "MOLODETZ_DATABASE_URL": database_url}
|
|
return subprocess.run(
|
|
[sys.executable, "-c", "from molodetz import config"],
|
|
cwd=ROOT,
|
|
env=env,
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
|
|
|
|
def test_data_dir_outside_root_refused():
|
|
result = run_config_import("/tmp/evil", "sqlite:////tmp/evil/molodetz.db")
|
|
assert result.returncode != 0
|
|
assert "outside" in result.stderr
|
|
|
|
|
|
def test_data_dir_inside_root_allowed():
|
|
target = ROOT / "data" / ".tmp-guard-probe"
|
|
result = run_config_import(str(target), f"sqlite:///{target / 'molodetz.db'}")
|
|
assert result.returncode == 0
|
|
|
|
|
|
def test_database_url_outside_data_dir_refused():
|
|
target = ROOT / "data" / ".tmp-guard-probe"
|
|
result = run_config_import(str(target), "sqlite:////tmp/evil/molodetz.db")
|
|
assert result.returncode != 0
|
|
assert "outside" in result.stderr
|