"""Run inside the configured source container. Export configuration, NEVER data. Usage: python prepare_production_settings.py /secure/new-directory Creates new files exclusively with mode 0600. No secrets go to stdout. """ import json import os from pathlib import Path import secrets import sys from app.runtime import get_runtime_settings def prepare(destination: Path) -> None: runtime = get_runtime_settings() keys = [ 'jellyfin_base_url', 'jellyfin_api_key', 'jellyfin_public_url', 'jellyseerr_base_url', 'jellyseerr_api_key', 'sonarr_base_url', 'sonarr_api_key', 'radarr_base_url', 'radarr_api_key', 'prowlarr_base_url', 'prowlarr_api_key', 'bazarr_base_url', 'bazarr_api_key', 'qbittorrent_base_url', 'qbittorrent_username', 'qbittorrent_password', 'magent_notify_enabled', 'magent_notify_email_enabled', 'magent_notify_email_smtp_host', 'magent_notify_email_smtp_port', 'magent_notify_email_smtp_username', 'magent_notify_email_smtp_password', 'magent_notify_email_from_address', 'magent_notify_email_from_name', 'magent_notify_email_use_tls', 'magent_notify_email_use_ssl', ] values = {key.upper(): getattr(runtime, key) for key in keys if getattr(runtime, key, None) is not None} password = secrets.token_urlsafe(30) values.update( APP_NAME='Magent', JWT_SECRET=secrets.token_urlsafe(48), ADMIN_USERNAME='admin', ADMIN_PASSWORD=password, AUTH_COOKIE_SECURE=True, AUTH_COOKIE_DOMAIN='magent.grizzlyflix.co.nz', AUTH_COOKIE_NAME='magent_auth', AUTH_STATE_COOKIE_NAME='magent_logged_in', CORS_ALLOW_ORIGIN='https://magent.grizzlyflix.co.nz', MAGENT_APPLICATION_URL='https://magent.grizzlyflix.co.nz', MAGENT_API_URL='https://magent.grizzlyflix.co.nz/api', SQLITE_PATH='/app/data/magent.db', LOG_FILE='/app/data/magent.log', SITE_BANNER_ENABLED=False, MAGENT_COMING_SOON=True, BACKGROUND_TASKS_ENABLED=False, ) destination.mkdir(mode=0o700, parents=True, exist_ok=False) def write_private(name, content): with os.fdopen(os.open(destination / name, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600), 'w') as stream: stream.write(content) # Compose single-quoted values preserve dollar signs in SMTP passwords. def encode(value): text = str(value).lower() if isinstance(value, bool) else str(value) if '\n' in text or '\r' in text: raise ValueError('Multiline configuration values require manual review') return "'" + text.replace('\\', '\\\\').replace("'", "\\'") + "'" write_private('.env', ''.join(f'{key}={encode(value)}\n' for key, value in values.items())) write_private('bootstrap-admin.json', json.dumps({'username': 'admin', 'password': password})) print(f'Prepared {len(keys)} allowlisted connection settings; fresh session and admin credentials. No client records copied.') if __name__ == '__main__': prepare(Path(sys.argv[1]))