feat: centralize L402 config, automate Metal install, fix watchdog cleanup

- config.py: add L402_HMAC_SECRET, L402_MACAROON_SECRET, LIGHTNING_BACKEND
  to pydantic-settings with startup warnings for default secrets
- l402_proxy.py, mock_backend.py, factory.py: migrate from os.environ.get()
  to `from config import settings` per project convention
- Makefile: `make install-creative` now auto-installs PyTorch nightly with
  Metal (MPS) support on Apple Silicon instead of just printing a note
- activate_self_tdd.sh: add PID file (.watchdog.pid) and EXIT trap so
  Ctrl-C cleanly stops both the dashboard and the watchdog process
- .gitignore: add .watchdog.pid

https://claude.ai/code/session_01A81E5HMxZEPxzv2acNo35u
This commit is contained in:
Claude
2026-02-25 18:19:22 +00:00
parent c0ca166d43
commit 2e7f3d1b29
7 changed files with 70 additions and 35 deletions

View File

@@ -59,6 +59,14 @@ class Settings(BaseSettings):
video_transition_duration: float = 1.0
default_video_codec: str = "libx264"
# ── L402 Lightning ───────────────────────────────────────────────────
# HMAC secrets for macaroon signing and invoice verification.
# MUST be changed from defaults before deploying to production.
# Generate with: python3 -c "import secrets; print(secrets.token_hex(32))"
l402_hmac_secret: str = "timmy-hmac-secret"
l402_macaroon_secret: str = "timmy-macaroon-secret"
lightning_backend: Literal["mock", "lnd"] = "mock"
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
@@ -67,3 +75,20 @@ class Settings(BaseSettings):
settings = Settings()
# ── Startup validation ───────────────────────────────────────────────────────
# Warn when security-sensitive settings are using defaults.
import logging as _logging
_startup_logger = _logging.getLogger("config")
if settings.l402_hmac_secret == "timmy-hmac-secret":
_startup_logger.warning(
"SEC: L402_HMAC_SECRET is using the default value — "
"set a unique secret in .env before deploying to production."
)
if settings.l402_macaroon_secret == "timmy-macaroon-secret":
_startup_logger.warning(
"SEC: L402_MACAROON_SECRET is using the default value — "
"set a unique secret in .env before deploying to production."
)

View File

@@ -12,6 +12,7 @@ import logging
import os
from typing import Optional
from config import settings
from lightning.base import LightningBackend
logger = logging.getLogger(__name__)
@@ -68,7 +69,7 @@ def get_backend(name: Optional[str] = None) -> LightningBackend:
"""
_register_backends()
backend_name = (name or os.environ.get("LIGHTNING_BACKEND", "mock")).lower()
backend_name = (name or settings.lightning_backend).lower()
if backend_name not in _BACKENDS:
available = ", ".join(_BACKENDS.keys())
@@ -100,8 +101,8 @@ def get_backend_info() -> dict:
Returns:
Dict with backend info for health/status endpoints
"""
backend_name = os.environ.get("LIGHTNING_BACKEND", "mock")
backend_name = settings.lightning_backend
return {
"configured_backend": backend_name,
"available_backends": list_backends(),

View File

@@ -12,20 +12,13 @@ import secrets
import time
from typing import Optional
from config import settings
from lightning.base import Invoice, LightningBackend, LightningError
logger = logging.getLogger(__name__)
# Secret for HMAC-based invoice verification (mock mode)
_HMAC_SECRET_DEFAULT = "timmy-sovereign-sats"
_HMAC_SECRET_RAW = os.environ.get("L402_HMAC_SECRET", _HMAC_SECRET_DEFAULT)
_HMAC_SECRET = _HMAC_SECRET_RAW.encode()
if _HMAC_SECRET_RAW == _HMAC_SECRET_DEFAULT:
logger.warning(
"SEC: L402_HMAC_SECRET is using the default value — set a unique "
"secret in .env before deploying to production."
)
# Read secret from centralised config (validated at startup in config.py)
_HMAC_SECRET = settings.l402_hmac_secret.encode()
class MockBackend(LightningBackend):

View File

@@ -13,29 +13,20 @@ import base64
import hashlib
import hmac
import logging
import os
import time
from dataclasses import dataclass
from typing import Optional
from config import settings
from timmy_serve.payment_handler import payment_handler
logger = logging.getLogger(__name__)
_MACAROON_SECRET_DEFAULT = "timmy-macaroon-secret"
_MACAROON_SECRET_RAW = os.environ.get("L402_MACAROON_SECRET", _MACAROON_SECRET_DEFAULT)
_MACAROON_SECRET = _MACAROON_SECRET_RAW.encode()
_HMAC_SECRET_DEFAULT = "timmy-hmac-secret"
_HMAC_SECRET_RAW = os.environ.get("L402_HMAC_SECRET", _HMAC_SECRET_DEFAULT)
# Read secrets from centralised config (validated at startup in config.py)
_MACAROON_SECRET = settings.l402_macaroon_secret.encode()
_HMAC_SECRET_RAW = settings.l402_hmac_secret
_HMAC_SECRET = _HMAC_SECRET_RAW.encode()
if _MACAROON_SECRET_RAW == _MACAROON_SECRET_DEFAULT or _HMAC_SECRET_RAW == _HMAC_SECRET_DEFAULT:
logger.warning(
"SEC: L402 secrets are using default values — set L402_MACAROON_SECRET "
"and L402_HMAC_SECRET in .env before deploying to production."
)
@dataclass
class Macaroon: