teecup/app/config.py

53 lines
1.8 KiB
Python
Raw Normal View History

2026-07-16 07:26:04 +02:00
"""
Konfigurasjon for TeeCup-API-et.
ADR (åpent spørsmål 1): TeeCup bruker EGNE, uavhengige secrets den skal ikke
falle tilbake teeoff sine. Manglende variabel skal feile høyt ved oppstart,
ikke stille bruke en usikker standard.
"""
import os
def _required(name: str) -> str:
value = os.environ.get(name, "").strip()
if not value:
raise RuntimeError(
f"Miljøvariabelen {name} mangler. TeeCup starter ikke uten den "
f"(ingen fallback til teeoff sine verdier — se ADR)."
)
return value
class Settings:
# Peker på teecup_db, og bruker RUNTIME-rollen teecup_app (ikke teeoff_admin).
# Format: postgresql://teecup_app:<passord>@<host>:<port>/teecup_db
DATABASE_URL: str = _required("TEECUP_DATABASE_URL")
# Egen sesjons-secret, uavhengig av teeoff.
SESSION_SECRET: str = _required("TEECUP_SESSION_SECRET")
DB_POOL_MIN: int = int(os.getenv("TEECUP_DB_POOL_MIN", "2"))
DB_POOL_MAX: int = int(os.getenv("TEECUP_DB_POOL_MAX", "10"))
Ekte autentisering er bygget og verifisert. X-Debug-User-Id-stubben er helt fjernet, ingen fallback beholdt. Ny flyt: magic-link (POST /auth/request-link → POST /auth/verify-link) + JWT-sesjon i HttpOnly/SameSite=Lax/dynamisk-Secure-cookie (30 dager), pluss /auth/logout og /auth/me. Ny migrasjon 004_auth.sql (unik e-post-indeks + magic_link_token-tabell). Sikkerhetsdesignet fra Plan-agent-gjennomgangen holdt gjennom testing: Token: secrets.token_urlsafe(32), kun SHA-256-hash lagres Atomisk forbruk (UPDATE...RETURNING, ikke les-sjekk-skriv) — hindrer replay Generisk respons uansett om e-posten finnes — hindrer enumerering app_user opprettes først ved vellykket verifisering, ikke ved forespørsel — hindrer massopprettelse Gamle uforbrukte lenker ugyldiggjøres når en ny utstedes PyJWT (byttet fra python-jose pga. bredere sårbarhetsflate) med eksplisitt algorithms=["HS256"] Ekte eksistens-sjekk mot app_user på hvert kall — en slettet bruker mister tilgang umiddelbart, ikke etter 30 dager Alle 12 planlagte tester bestått, inkludert cooldown, token-ugyldiggjøring, utløp, tuklet JWT, slettet bruker, og at debug-headeren nå er helt uten effekt. To ting funnet og fikset/dokumentert underveis: ON CONFLICT (email) matchet ikke den nye partielle unike indeksen uten eksplisitt WHERE-klausul — fikset. En reell, dypere RLS-bug (dokumentert i FEATURE_BACKLOG.md, ikke fikset her): organization-tabellens RLS-policy kaster en 500 i stedet for "se ingenting" når app.current_org leses tilbake som tomstreng (ikke NULL) på en gjenbrukt pool-tilkobling. Berører trolig alle 15 RLS-policyer i skjemaet — for stort og sensitivt (ADR-003-grunnmuren) til å hastefikse her, så jeg mitigerte det lokalt i /auth/me og satte det som punkt 1 i neste-steg-listen.
2026-07-16 15:16:53 +02:00
# Ekte autentisering (magic-link + JWT-sesjon). Ikke hemmeligheter --
# sane defaults, ikke _required.
SESSION_MAX_AGE_SECONDS: int = int(
os.getenv("TEECUP_SESSION_MAX_AGE_SECONDS", str(30 * 24 * 3600))
)
MAGIC_LINK_MAX_AGE_MINUTES: int = int(os.getenv("TEECUP_MAGIC_LINK_MAX_AGE_MINUTES", "20"))
MAGIC_LINK_COOLDOWN_SECONDS: int = int(os.getenv("TEECUP_MAGIC_LINK_COOLDOWN_SECONDS", "60"))
# Logger rå magic-link-token server-side i stedet for å sende e-post.
# ALDRI på som standard -- må settes eksplisitt, kun for dev/scratch-
# testing (samme klasse feil som denne runden finnes for å lukke for
# X-Debug-User-Id-headeren).
DEV_LOG_MAGIC_LINKS: bool = os.getenv("TEECUP_DEV_LOG_MAGIC_LINKS", "").strip().lower() in (
"1",
"true",
"yes",
)
2026-07-16 07:26:04 +02:00
settings = Settings()