Files
SecureCheck/securecheck/config.py
2026-04-05 18:56:26 +02:00

97 lines
2.8 KiB
Python

from __future__ import annotations
import os
import pwd
import tempfile
from dataclasses import dataclass
from pathlib import Path
@dataclass(frozen=True)
class AppPaths:
config_dir: Path
state_dir: Path
log_dir: Path
report_dir: Path
scenario_file: Path
app_log_file: Path
def _invoking_user() -> tuple[str, Path]:
sudo_user = os.environ.get("SUDO_USER")
if sudo_user:
user_info = pwd.getpwnam(sudo_user)
return sudo_user, Path(user_info.pw_dir)
user = os.environ.get("USER", "root")
home = Path.home()
return user, home
def build_paths() -> AppPaths:
_, user_home = _invoking_user()
config_home = Path(os.environ.get("XDG_CONFIG_HOME", user_home / ".config"))
state_home = Path(os.environ.get("XDG_STATE_HOME", user_home / ".local" / "state"))
config_dir = _select_writable_dir(
[
config_home / "securecheck",
Path.cwd() / ".securecheck-runtime" / "config",
Path(tempfile.gettempdir()) / "securecheck" / "config",
]
)
state_dir = _select_writable_dir(
[
state_home / "securecheck",
Path.cwd() / ".securecheck-runtime" / "state",
Path(tempfile.gettempdir()) / "securecheck" / "state",
]
)
if os.geteuid() == 0 and _is_path_writable(Path("/var/log")):
log_dir = Path("/var/log/securecheck")
else:
log_dir = _select_writable_dir(
[
state_dir / "logs",
Path.cwd() / ".securecheck-runtime" / "logs",
Path(tempfile.gettempdir()) / "securecheck" / "logs",
]
)
report_dir = log_dir / "reports"
scenario_file = config_dir / "scenarios.json"
app_log_file = log_dir / "securecheck.log"
return AppPaths(
config_dir=config_dir,
state_dir=state_dir,
log_dir=log_dir,
report_dir=report_dir,
scenario_file=scenario_file,
app_log_file=app_log_file,
)
def ensure_app_dirs(paths: AppPaths) -> None:
for directory in (paths.config_dir, paths.state_dir, paths.log_dir, paths.report_dir):
directory.mkdir(parents=True, exist_ok=True)
def _is_path_writable(path: Path) -> bool:
target = path if path.exists() else path.parent
return os.access(target, os.W_OK)
def _select_writable_dir(candidates: list[Path]) -> Path:
for candidate in candidates:
try:
candidate.mkdir(parents=True, exist_ok=True)
probe = candidate / ".write-test"
with probe.open("w", encoding="utf-8") as handle:
handle.write("ok")
probe.unlink()
return candidate
except OSError:
continue
raise OSError("Aucun emplacement inscriptible disponible pour SecureCheck")