From 3492c441ee6a909d3d8a8f22c930fe06abac82e3 Mon Sep 17 00:00:00 2001 From: Niranjan Date: Tue, 7 Apr 2026 03:35:32 +0530 Subject: [PATCH] Updated feature / fix --- YakPanel-server/backend/.env.example | 4 +-- YakPanel-server/backend/app/core/config.py | 19 ++++++++----- YakPanel-server/backend/app/core/database.py | 28 +++++++++++++++++--- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/YakPanel-server/backend/.env.example b/YakPanel-server/backend/.env.example index 66a68fbe..d585dd28 100644 --- a/YakPanel-server/backend/.env.example +++ b/YakPanel-server/backend/.env.example @@ -1,6 +1,6 @@ -# YakPanel - Environment +# YakPanel - Environment (this file lives next to app/ — loaded from backend/ always, not shell CWD) SECRET_KEY=change-this-in-production -# Resolved against backend directory (see app/core/database.py), safe when CWD is not backend/ +# Resolved to backend/data/default.db (see app/core/database.py) DATABASE_URL=sqlite+aiosqlite:///./data/default.db REDIS_URL=redis://localhost:6379/0 DEBUG=false diff --git a/YakPanel-server/backend/app/core/config.py b/YakPanel-server/backend/app/core/config.py index 2b6c45fa..64b3e9bd 100644 --- a/YakPanel-server/backend/app/core/config.py +++ b/YakPanel-server/backend/app/core/config.py @@ -1,15 +1,26 @@ """YakPanel - Configuration""" import os -from typing import Any -from pydantic_settings import BaseSettings from functools import lru_cache +from pathlib import Path +from typing import Any + +from pydantic_settings import BaseSettings, SettingsConfigDict # Runtime config loaded from DB on startup (overrides Settings) _runtime_config: dict[str, Any] = {} +_BACKEND_ROOT = Path(__file__).resolve().parent.parent + class Settings(BaseSettings): """Application settings""" + + model_config = SettingsConfigDict( + env_file=str(_BACKEND_ROOT / ".env"), + env_file_encoding="utf-8", + extra="ignore", + ) + app_name: str = "YakPanel" app_version: str = "1.0.0" debug: bool = False @@ -47,10 +58,6 @@ class Settings(BaseSettings): # Comma-separated CIDRs; empty = no restriction (e.g. "10.0.0.0/8,192.168.0.0/16") remote_install_allowed_target_cidrs: str = "" - class Config: - env_file = ".env" - env_file_encoding = "utf-8" - @lru_cache def get_settings() -> Settings: diff --git a/YakPanel-server/backend/app/core/database.py b/YakPanel-server/backend/app/core/database.py index ddddce48..d5da952c 100644 --- a/YakPanel-server/backend/app/core/database.py +++ b/YakPanel-server/backend/app/core/database.py @@ -1,4 +1,6 @@ """YakPanel - Database configuration""" +import os +import sqlite3 from pathlib import Path from sqlalchemy.engine.url import make_url @@ -22,10 +24,28 @@ def _resolve_database_url(raw_url: str) -> str: path = (backend_dir / path).resolve() else: path = path.resolve() - path.parent.mkdir(parents=True, exist_ok=True) - # POSIX path for SQLite URL (backslashes break aiosqlite on unexpected setups) - posix = path.as_posix() - return str(url.set(database=posix)) + data_dir = path.parent + data_dir.mkdir(parents=True, exist_ok=True) + try: + os.chmod(data_dir, 0o755) + except OSError: + pass + if not os.access(data_dir, os.W_OK): + raise RuntimeError( + f"SQLite directory not writable: {data_dir} " + f"(fix ownership or permissions; check SELinux if enabled)." + ) + abs_path = path.as_posix() + try: + test = sqlite3.connect(abs_path) + test.close() + except sqlite3.Error as e: + raise RuntimeError( + f"SQLite refused to open {abs_path} (from DATABASE_URL). {e}. " + f"Parent dir: {data_dir} writable={os.access(data_dir, os.W_OK)}." + ) from e + # Unix absolute file: sqlite+aiosqlite:////abs/path (four slashes total after the colon) + return f"sqlite+aiosqlite:///{abs_path}" settings = get_settings()