import logging from typing import Any log = logging.getLogger('root') def validate_critical_config(settings: Any): """ Validates that essential settings are populated and not using placeholders. Logs warnings or errors for missing critical infrastructure. """ log.info("Checking critical system configuration...") # 1. Database Check db = getattr(settings, 'DB', {}) if not db.get('server') or db.get('server') == 'mariadb': # 'mariadb' is the default in .env, usually fine, but worth noting log.info(f"Database server: {db.get('server')}") # 2. SMTP Check smtp = getattr(settings, 'SMTP', {}) if not smtp.get('server'): log.warning("CRITICAL: SMTP server not configured. Email features will fail.") if smtp.get('password') == 'set-in-ae-sql-db-cnf-tbl': log.error("CRITICAL: SMTP password is still set to placeholder. Email authentication will fail.") # 3. Security Check jwt_key = getattr(settings, 'JWT_KEY', '') if not jwt_key or jwt_key == 'fake-super-secret-token': log.error("SECURITY: JWT_KEY is missing or using a known fake token!") log.info("Aether configuration validation complete.") def bootstrap_db_config(settings: Any) -> bool: """ Loads dynamic settings from the 'cfg' table and updates the settings object. Uses deferred import of sql_select to avoid circular dependencies. """ # CRITICAL: Deferred import to prevent boot-time circular dependencies from app.db_sql import sql_select # log.setLevel(logging.DEBUG) cfg_id = settings.AETHER_CFG.get('id', 0) log.info(f"Bootstrapping Aether system configuration from DB (cfg_id={cfg_id})...") try: # Fetch the config record aether_cfg_sql = sql_select( table_name='cfg', record_id=int(cfg_id), as_list=False, max_count=1, ) log.debug(f"Raw config record from DB: {aether_cfg_sql}") # In some cases sql_select might return a single-item list even with as_list=False if isinstance(aether_cfg_sql, list): if len(aether_cfg_sql) > 0: aether_cfg_sql = aether_cfg_sql[0] else: aether_cfg_sql = None if not aether_cfg_sql or not isinstance(aether_cfg_sql, dict): log.error(f"FAILED to load system config from DB for ID {cfg_id}. Table 'cfg' might be empty or ID missing.") return False # --- Update Database settings --- # ID Vision: Prioritize Environment Variables for core infrastructure. # We only overwrite if the DB value is present AND the environment value is empty OR changed. db_smtp_server = aether_cfg_sql.get('db_server') if db_smtp_server and (not settings.DB_SERVER or settings.DB_SERVER != db_smtp_server): settings.DB_SERVER = db_smtp_server db_smtp_port = aether_cfg_sql.get('db_port') if db_smtp_port and (not settings.DB_PORT or settings.DB_PORT != str(db_smtp_port)): settings.DB_PORT = str(db_smtp_port) db_smtp_name = aether_cfg_sql.get('db_name') if db_smtp_name and (not settings.DB_NAME or settings.DB_NAME != db_smtp_name): settings.DB_NAME = db_smtp_name db_smtp_username = aether_cfg_sql.get('db_username') if db_smtp_username and (not settings.DB_USER or settings.DB_USER != db_smtp_username): settings.DB_USER = db_smtp_username db_smtp_password = aether_cfg_sql.get('db_password') if db_smtp_password and (not settings.DB_PASS or settings.DB_PASS != db_smtp_password): settings.DB_PASS = db_smtp_password # --- Update SMTP Settings --- # ID Vision: Prioritize Environment Variables for core infrastructure. # We overwrite ONLY if: # 1. The environment value is a known placeholder ('set-in-ae-sql-db-cnf-tbl') # 2. OR the database value has explicitly changed (dynamic refresh) placeholder = 'set-in-ae-sql-db-cnf-tbl' db_smtp_server = aether_cfg_sql.get('smtp_server') if db_smtp_server and (settings.SMTP.get('server') in [placeholder, '', None] or settings.SMTP.get('server') != db_smtp_server): log.info(f"Updating SMTP server to {db_smtp_server}") settings.SMTP['server'] = db_smtp_server db_smtp_port = aether_cfg_sql.get('smtp_port') if db_smtp_port and (settings.SMTP.get('port') in [placeholder, '', None] or settings.SMTP.get('port') != str(db_smtp_port)): settings.SMTP['port'] = str(db_smtp_port) db_smtp_username = aether_cfg_sql.get('smtp_username') if db_smtp_username and (settings.SMTP.get('username') in [placeholder, '', None] or settings.SMTP.get('username') != db_smtp_username): settings.SMTP['username'] = db_smtp_username db_smtp_password = aether_cfg_sql.get('smtp_password') if db_smtp_password and (settings.SMTP.get('password') in [placeholder, '', None] or settings.SMTP.get('password') != db_smtp_password): log.info("Updating SMTP password from database (dynamic refresh).") settings.SMTP['password'] = db_smtp_password # --- Update File Paths --- # DEPRECATED: Filesystem paths should be controlled by the Environment/Docker, not the DB. # if aether_cfg_sql.get('path_hosted_files_root'): settings.FILES_PATH['hosted_files_root'] = aether_cfg_sql.get('path_hosted_files_root') # if aether_cfg_sql.get('path_hosted_tmp_root'): settings.FILES_PATH['hosted_tmp_root'] = aether_cfg_sql.get('path_hosted_tmp_root') # log.setLevel(logging.DEBUG) log.info("Aether API system configuration successfully synchronized with DB.") log.debug(f"Current Database settings after bootstrap: DB_SERVER={settings.DB_SERVER} DB_PORT={settings.DB_PORT} DB_NAME={settings.DB_NAME} DB_USER={settings.DB_USER} DB_PASS={'****' if settings.DB_PASS else ''}") log.debug(f"Current SMTP settings after bootstrap: {settings.SMTP}") return True except Exception as e: log.exception(f"Unexpected error during system bootstrap: {e}") return False