Address code review feedback - persistent dev secrets and fix empty auth header

Co-authored-by: Stalin-143 <161853795+Stalin-143@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-01-31 18:42:45 +00:00
parent f04fc76eb9
commit a343b17ab3
3 changed files with 48 additions and 9 deletions
+27 -4
View File
@@ -117,6 +117,28 @@ def get_required_secret(env_var: str, description: str) -> str:
raise ValueError(f"{description} ({env_var}) must be set in environment variables for security. Do not use default values for secrets.") raise ValueError(f"{description} ({env_var}) must be set in environment variables for security. Do not use default values for secrets.")
return value return value
def get_dev_fallback_secret(name: str) -> str:
"""
Generate a persistent random secret for development use only.
Stores the secret in a file to persist across restarts.
"""
import tempfile
secret_file = os.path.join(tempfile.gettempdir(), f'.openlearnx_dev_{name}')
try:
if os.path.exists(secret_file):
with open(secret_file, 'r') as f:
return f.read().strip()
except Exception:
pass
# Generate new secret and persist it
new_secret = os.urandom(32).hex()
try:
with open(secret_file, 'w') as f:
f.write(new_secret)
except Exception:
pass # If we can't persist, just return the generated secret
return new_secret
# Validate required secrets at startup # Validate required secrets at startup
try: try:
_secret_key = get_required_secret('SECRET_KEY', 'Flask secret key') _secret_key = get_required_secret('SECRET_KEY', 'Flask secret key')
@@ -124,10 +146,11 @@ try:
_admin_token = get_required_secret('ADMIN_TOKEN', 'Admin authentication token') _admin_token = get_required_secret('ADMIN_TOKEN', 'Admin authentication token')
except ValueError as e: except ValueError as e:
print(f"⚠️ SECURITY WARNING: {e}") print(f"⚠️ SECURITY WARNING: {e}")
print("⚠️ Using insecure defaults for development only. Set proper secrets in production!") print("⚠️ Using persistent development secrets. Set proper secrets in production!")
_secret_key = os.getenv('SECRET_KEY', os.urandom(32).hex()) _secret_key = os.getenv('SECRET_KEY') or get_dev_fallback_secret('secret_key')
_jwt_secret_key = os.getenv('JWT_SECRET_KEY', os.urandom(32).hex()) _jwt_secret_key = os.getenv('JWT_SECRET_KEY') or get_dev_fallback_secret('jwt_secret_key')
_admin_token = os.getenv('ADMIN_TOKEN', os.urandom(16).hex()) _admin_token = os.getenv('ADMIN_TOKEN') or get_dev_fallback_secret('admin_token')
print(f"⚠️ DEV ADMIN_TOKEN (first 8 chars): {_admin_token[:8]}...")
app.config.update( app.config.update(
SECRET_KEY=_secret_key, SECRET_KEY=_secret_key,
+14 -1
View File
@@ -20,7 +20,20 @@ db = client.openlearnx
JWT_SECRET = os.getenv('JWT_SECRET') JWT_SECRET = os.getenv('JWT_SECRET')
if not JWT_SECRET: if not JWT_SECRET:
import warnings import warnings
warnings.warn("JWT_SECRET environment variable not set. Using randomly generated secret.", UserWarning) import tempfile
warnings.warn("JWT_SECRET environment variable not set. Using persistent dev secret.", UserWarning)
# Use persistent file-based secret for development to avoid invalidating tokens on restart
_secret_file = os.path.join(tempfile.gettempdir(), '.openlearnx_dev_jwt_secret_auth')
try:
if os.path.exists(_secret_file):
with open(_secret_file, 'r') as f:
JWT_SECRET = f.read().strip()
if not JWT_SECRET:
import secrets as _secrets
JWT_SECRET = _secrets.token_hex(32)
with open(_secret_file, 'w') as f:
f.write(JWT_SECRET)
except Exception:
import secrets as _secrets import secrets as _secrets
JWT_SECRET = _secrets.token_hex(32) JWT_SECRET = _secrets.token_hex(32)
+5 -2
View File
@@ -73,10 +73,13 @@ export default function AdminDashboard() {
// Helper function to get authorization headers // Helper function to get authorization headers
const getAuthHeaders = (): Record<string, string> => { const getAuthHeaders = (): Record<string, string> => {
const token = getAdminToken() const token = getAdminToken()
return { const headers: Record<string, string> = {
'Authorization': token ? `Bearer ${token}` : '',
'Content-Type': 'application/json' 'Content-Type': 'application/json'
} }
if (token) {
headers['Authorization'] = `Bearer ${token}`
}
return headers
} }
useEffect(() => { useEffect(() => {