fix(tradein/devops): wire COOKIE_ENCRYPTION_KEY env to tradein-backend #543
No reviewers
Labels
No labels
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
Fable 5 ревью
feedback/max
generative
GG-форсайт
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
вторичка
ИРД
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#543
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "chore/tradein-cookie-encryption-key-env"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Root cause
Prod backend service
tradein-backendНЕ имеетCOOKIE_ENCRYPTION_KEYenv var вdocker-compose.prod.yml. Settings class имеет defaultcookie_encryption_key: str = "". Из-за этого:pgp_sym_encrypt(text, '')падаетpsycopg.errors.ExternalRoutineInvocationException: Illegal argument to function— попытка записать Cian cookies черезsave_sessionломается./estimategraceful'но возвращаетcian_valuation=None.verify_sessionон упал бы внутриsave_sessionна encrypt.Дисковерено при попытке локального backfill cian valuations — pgp_sym_encrypt SQL trace показал
'key': ''. Compose audit подтвердил: ни одного упоминанияCOOKIE_ENCRYPTION_KEYв backend env block.Fix
tradein-mvp/docker-compose.prod.yml— добавитьCOOKIE_ENCRYPTION_KEYвbackend.environment(послеGENDESIGN_FDW_PASSWORD). +4 lines с комментарием.tradein-mvp/DEPLOY.md— добавить в template.env.runtime+ новая секция «Обновление на существующем VPS» с командойup -d --force-recreate --no-deps backend(неrestart— она не re-читает env_file). +17 lines.Manual action on VPS after merge+deploy
openssl rand -hex 32/opt/gendesign/tradein-mvp/.env.runtime:COOKIE_ENCRYPTION_KEY=<64-char hex>cd /opt/gendesign/tradein-mvp && docker compose -p gendesign-tradein -f docker-compose.prod.yml up -d --force-recreate --no-deps backendПосле этого:
/scrapers/cian-cookiesUI ИЛИ через локальный скрипт.curl https://gendsgn.ru/trade-in/api/v1/admin/scrape/cian/test-authpython cian_backfill.py --no-listings --batch-size 30.Test plan
docker exec tradein-backend printenv COOKIE_ENCRYPTION_KEY≠ пустоFollows up 4-PR Cian activation series (#523/#525/#530/#535) + backfill task #539.
Deep Code Review — PR #543
(Posted as comment — Forgejo blocks self-PR formal Review.)
Summary
tradein-mvp/docker-compose.prod.yml+4,tradein-mvp/DEPLOY.md+17)Security verification (encryption-key sensitive)
${COOKIE_ENCRYPTION_KEY:-}shell substitution — value resolved at runtime from.env.runtime, never embedded in image / git.<64-char hex>— not a real key.openssl rand -hex 32(32 bytes = 256-bit) — sufficient for pgcrypto S2K-derived AES; far above any practical floor forpgp_sym_encrypt..forgejo/workflows/deploy-tradein.yml) sources viaset -a; source .env.runtime; set +a— noecho,cat, orprintenvof file content → no log leak (lessons from PR #510\o /dev/nullincident respected).chmod 600 .env.runtimeenforced in workflow line 145 → at-rest filesystem ACL OK.< "$sql_file"(not-c "$sql"), key is bound via psycopg parameters in app layer ({"key": settings.cookie_encryption_key}in cian_session.py:137/169), so the secret never appears in psql command line or postgres log_statement.SQLALCHEMY_ECHO/engine(echo=True)found in tradein backend → bound params not echoed to app logs.Correctness
GENDESIGN_FDW_PASSWORD) exactly: same indentation, same${VAR:-}empty default, same env block placement.--force-recreate --no-deps backendis the right rollout flag:docker compose restartdoes NOT re-readenv_file/environmentblock, only re-creates kernel namespaces. DEPLOY.md correctly documents this distinction.admin.py:269upload endpoint → 503 "COOKIE_ENCRYPTION_KEY not configured" (fail-closed)admin.py:305test-auth → returnsauthenticated=false reason=encryption_key_not_configured(graceful)cian_valuation.py:160no session → returnsNone,/estimatecontinues withcian_valuation=None(graceful, matches body claim)Settings.cookie_encryption_key: str = ""default inconfig.py:30is acceptable — app does NOT fail-fast on empty key, but every consumer call-site gates explicitly. Trade-off accepted (allows dev/test without key).Minor follow-ups (not blockers)
M1 — load_session has no try/except around pgp_sym_decrypt (
cian_session.py:157-170). If a key gets rotated OR if any stale row encrypted withkey=''(pre-deploy state) survives in prod, the nextload_sessionwill raisepsycopg.errors.ExternalRoutineInvocationExceptionand propagate as 500. Not introduced by this PR; flagging for the rotation workflow.M2 — Manual-action checklist should mention stale rows. Before setting
COOKIE_ENCRYPTION_KEYin prod, verifySELECT count(*) FROM cian_session_cookiesis 0 (it should be — Stage 9 was never functional per body), OR include aTRUNCATE cian_session_cookiesstep. Otherwise the firstload_sessionafter key wire-up could throw on legacykey=''blobs.M3 — No key-rotation runbook. DEPLOY.md documents one-time generation but not rotation. Suggested rotation: (1) TRUNCATE cian_session_cookies; (2) update .env.runtime; (3) up -d --force-recreate --no-deps backend; (4) re-upload cookies via /api/v1/cookies/upload. Add as a vault
runbooks/cian-key-rotation.mdfollow-up (out of scope for this PR).M4 —
chmod 600not in DEPLOY.md manual-action snippet. The deploy workflow chmod's.env.runtimeautomatically (line 145), but the manual-action snippet doesn't remind the operator. Suggested addition right after theecho ... >>line:Project conventions
# GlitchTip DSN — мониторинг ошибок ...) — bilingual + ticket-style. Good.:latesttag concerns — env var injection only, image pull untouched.Positive
--force-recreate --no-depscorrectly avoids postgres bounce.pgp_sym_encrypt(text, '')ExternalRoutineInvocationException → Stage 9 dead since ship).Blast radius
git revert+up -d --force-recreate --no-deps backend).cookie_encryption_key.Merge policy
Security-sensitive — human merge required after manual deploy diff audit. Do not auto-merge.
Approved logically; please address M2/M4 inline (or in follow-up) before triggering the prod key generation.