Skip to content

Commit e5e5599

Browse files
committed
fix: auto-generate JWT secret fallback, remove psycopg2-binary, harden startup
- config.py: replace ValueError crash with auto-generated ephemeral JWT key + warning (root cause of Azure infinite restart loop) - requirements.txt: remove unused psycopg2-binary (saves ~30s build time) - startup.sh: add timeout 180 to pip install fallback - deploy-azure.yml: pass JWT_SECRET_KEY from GitHub Secrets to Azure app settings
1 parent da8de99 commit e5e5599

4 files changed

Lines changed: 15 additions & 7 deletions

File tree

.github/workflows/deploy-azure.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ jobs:
6666
--name ${{ env.AZURE_WEBAPP_NAME }} \
6767
--settings \
6868
SCM_DO_BUILD_DURING_DEPLOYMENT=true \
69-
WEBSITE_STARTUP_TIME_LIMIT=600
69+
WEBSITE_STARTUP_TIME_LIMIT=600 \
70+
JWT_SECRET_KEY="${{ secrets.JWT_SECRET_KEY }}"
7071
7172
- name: Create deployment package
7273
run: |

requirements.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ aiosqlite>=0.19.0
2424
sqlalchemy[asyncio]>=2.0.25
2525
alembic>=1.13.1
2626
asyncpg>=0.29.0
27-
psycopg2-binary>=2.9.9
2827

2928
# Cache — Redis (prod, optional for dev)
3029
redis>=5.0.0

src/config.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,18 @@
1010
"""
1111
from __future__ import annotations
1212

13+
import logging
1314
import os
15+
import secrets
1416
from functools import lru_cache
1517
from pathlib import Path
1618
from typing import List, Optional
1719

1820
from pydantic import field_validator
1921
from pydantic_settings import BaseSettings
2022

23+
logger = logging.getLogger(__name__)
24+
2125

2226
class Settings(BaseSettings):
2327
"""Application settings — populated from environment variables."""
@@ -90,10 +94,14 @@ def _require_jwt_secret(cls, v: str) -> str:
9094
# Allow empty only when TESTING
9195
if os.getenv("TESTING", "").lower() in ("true", "1"):
9296
return "test-only-insecure-key"
93-
raise ValueError(
94-
"JWT_SECRET_KEY environment variable is required in production. "
95-
"Set it to a strong random string (e.g. `openssl rand -hex 32`)."
97+
# Auto-generate a secret so the app can boot, but warn loudly
98+
generated = secrets.token_hex(32)
99+
logger.warning(
100+
"⚠️ JWT_SECRET_KEY not set — auto-generated an ephemeral key. "
101+
"Sessions will NOT survive restarts. Set JWT_SECRET_KEY in your "
102+
"environment for production use."
96103
)
104+
return generated
97105

98106
@field_validator("cors_allowed_origins", mode="before")
99107
@classmethod

startup.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ cd /home/site/wwwroot
88

99
# Install dependencies if Oryx build didn't run (fallback)
1010
if ! python -c "import gunicorn" 2>/dev/null; then
11-
echo "Installing Python dependencies..."
12-
pip install --no-cache-dir -r requirements.txt 2>&1 | tail -5
11+
echo "Installing Python dependencies (timeout 180s)..."
12+
timeout 180 pip install --no-cache-dir -r requirements.txt 2>&1 | tail -5 || echo "⚠️ pip install timed out or failed (non-fatal)"
1313
fi
1414

1515
# Run database migrations (safe to run repeatedly — no-ops if up to date)

0 commit comments

Comments
 (0)