o2o-negosium-original/lps/config/server_configs.py
민헌 3a8d669970 feat(lps): P2 시크릿 env 주입 + Chrome 프로필 영속 볼륨
프로덕션에서 시크릿을 이미지에 굽지 않고 env 로 주입, 재시작 시 챌린지 쿠키 유지.

- server_configs: 시크릿 env override 추가(house 의 DB override 패턴 확장) —
  OPENAI_API_KEY/MODEL, DECODO_HOST/USERNAME/PASSWORD/COST_PER_GB, NAVER_KEYS="id:sec,...".
  로컬은 env 미설정 → config.local.toml 그대로.
- worker_main: Chrome 프로필 경로를 LPS_PROFILE_DIR(기본 /tmp)로 env 화 → 영속 볼륨 마운트 가능.
- docker-compose: lps-worker 에 lps-profiles 볼륨(/profiles) + 시크릿 env 주입 주석 예시.
- config.example: 프로덕션 env 주입 목록 문서화.

검증: env override 동작(OpenAI/DECODO/Naver), 프로필이 /profiles 볼륨에 Cookies 포함 저장(cf_clearance 유지). 89 tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 23:04:37 +09:00

66 lines
2.9 KiB
Python

import os
from config.config_loader import Configs
from config.config_models import (
WebServerConfig, LogConfig, MainDBConfig, NaverConfig, NaverKey, OpenAIConfig, DecodoConfig,
)
# 실행 환경 결정 (기본 local). 환경변수 APP_ENV 로 변경.
APP_ENV = os.environ.get("APP_ENV", "local")
_config_dir = os.path.dirname(__file__)
_config_file = os.path.join(_config_dir, f"config.{APP_ENV}.toml")
# 운영 전제: 항상 APP_ENV=local 로 띄운다 → config.local.toml 사용 (test/docker 도 local 로 실행).
if not os.path.exists(_config_file):
raise FileNotFoundError(f"설정 파일이 없습니다: {_config_file} (APP_ENV={APP_ENV}). APP_ENV=local 로 실행하세요.")
configs = Configs(_config_file)
web_server_config: WebServerConfig = configs.get(WebServerConfig)
log_config: LogConfig = configs.get(LogConfig)
main_db_config: MainDBConfig = configs.get(MainDBConfig)
# 시크릿 포함 설정도 TOML 로 통합. 섹션이 없으면 기본값(빈/비활성).
naver_config: NaverConfig = configs.get(NaverConfig) or NaverConfig()
openai_config: OpenAIConfig = configs.get(OpenAIConfig) or OpenAIConfig()
decodo_config: DecodoConfig = configs.get(DecodoConfig) or DecodoConfig()
# DB 접속 env override (config.local.toml 유지, 도커에서 host 만 교체). 로컬은 env 미설정 → toml 그대로.
def _apply_db_env_override(cfg: MainDBConfig):
h = os.environ.get("DB_HOST")
if h:
cfg.write_host = cfg.read_host = h
if os.environ.get("DB_PORT"):
cfg.write_port = cfg.read_port = int(os.environ["DB_PORT"])
if os.environ.get("DB_USER"):
cfg.write_id = cfg.read_id = os.environ["DB_USER"]
if os.environ.get("DB_PASSWORD"):
cfg.write_pw = cfg.read_pw = os.environ["DB_PASSWORD"]
if os.environ.get("DB_NAME"):
cfg.name = os.environ["DB_NAME"]
# 시크릿 env override — 프로덕션에선 API 키를 이미지에 굽지 않고 env(또는 시크릿매니저)로 주입한다.
# 로컬은 env 미설정 → config.local.toml 값 그대로. (배포 시 toml 의 시크릿은 비워두고 아래 env 로 주입 권장)
def _apply_secret_env_override():
if os.environ.get("OPENAI_API_KEY"):
openai_config.api_key = os.environ["OPENAI_API_KEY"]
if os.environ.get("OPENAI_MODEL"):
openai_config.model = os.environ["OPENAI_MODEL"]
for k in ("host", "username", "password"):
v = os.environ.get(f"DECODO_{k.upper()}")
if v:
setattr(decodo_config, k, v)
if os.environ.get("DECODO_COST_PER_GB"):
decodo_config.cost_per_gb = float(os.environ["DECODO_COST_PER_GB"])
# NAVER_KEYS="id1:secret1,id2:secret2" 형식으로 키 로테이션 주입
nk = os.environ.get("NAVER_KEYS")
if nk:
naver_config.keys = [NaverKey(id=i, secret=s)
for i, s in (p.split(":", 1) for p in nk.split(",") if ":" in p)]
_apply_db_env_override(main_db_config)
_apply_secret_env_override()