Require production database configuration
This commit is contained in:
3 files changed
+43
-2
No files matched your search
@@ -94,7 +94,7 @@ The app reads these from `.env`:
|
||||
- `MAIL_PASSWORD`
|
||||
- `MAIL_DEFAULT_SENDER`
|
||||
|
||||
For public deployments, set `APP_ENV=production`. Production mode enables secure cookies and refuses to start with the development `SECRET_KEY`. Set `RATELIMIT_STORAGE_URI` to a shared backend such as Redis so login and signup limits are enforced across processes.
|
||||
For public deployments, set `APP_ENV=production`. Production mode enables secure cookies and refuses to start with the development `SECRET_KEY` or the local SQLite database. Use PostgreSQL for `DATABASE_URL`, then run `flask --app app db upgrade` during deploy. Set `RATELIMIT_STORAGE_URI` to a shared backend such as Redis so login and signup limits are enforced across processes.
|
||||
|
||||
## Site Admin Access
|
||||
|
||||
|
||||
+5
-1
@@ -9,7 +9,7 @@ from flask import Flask, render_template, request
|
||||
from werkzeug.exceptions import HTTPException
|
||||
|
||||
from boker.auth import current_user_id, is_logged_in, is_site_admin, normalize_email
|
||||
from boker.config import DEFAULT_SECRET_KEY, Config, ProductionConfig
|
||||
from boker.config import DEFAULT_DATABASE_URL, DEFAULT_SECRET_KEY, Config, ProductionConfig
|
||||
from boker.db import database_extensions_available, db, init_database
|
||||
from boker.extensions import csrf, limiter, mail
|
||||
from boker.routes.account import account_bp
|
||||
@@ -35,6 +35,10 @@ def create_app(config_overrides: dict | None = None) -> Flask:
|
||||
|
||||
if app.config["SESSION_COOKIE_SECURE"] and app.config["SECRET_KEY"] == DEFAULT_SECRET_KEY:
|
||||
raise RuntimeError("Set SECRET_KEY before running in production.")
|
||||
if app.config["SESSION_COOKIE_SECURE"]:
|
||||
database_url = app.config["SQLALCHEMY_DATABASE_URI"]
|
||||
if database_url == DEFAULT_DATABASE_URL or database_url.startswith("sqlite:"):
|
||||
raise RuntimeError("Set DATABASE_URL to a production PostgreSQL database before running in production.")
|
||||
|
||||
ensure_data_file(app.config["DATA_PATH"])
|
||||
init_database(app)
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import os
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
from app import create_app
|
||||
|
||||
|
||||
class ProductionConfigTests(unittest.TestCase):
|
||||
def test_production_refuses_default_sqlite_database(self):
|
||||
with patch.dict(
|
||||
os.environ,
|
||||
{"APP_ENV": "production"},
|
||||
clear=False,
|
||||
):
|
||||
with self.assertRaisesRegex(RuntimeError, "DATABASE_URL"):
|
||||
create_app({"SECRET_KEY": "test-production-secret"})
|
||||
|
||||
def test_production_accepts_postgresql_database_url(self):
|
||||
with patch.dict(
|
||||
os.environ,
|
||||
{"APP_ENV": "production"},
|
||||
clear=False,
|
||||
):
|
||||
app = create_app(
|
||||
{
|
||||
"SECRET_KEY": "test-production-secret",
|
||||
"SQLALCHEMY_DATABASE_URI": "postgresql+psycopg://user:password@example.com/dbname",
|
||||
}
|
||||
)
|
||||
|
||||
self.assertTrue(app.config["SESSION_COOKIE_SECURE"])
|
||||
self.assertEqual(app.config["SESSION_COOKIE_SAMESITE"], "Strict")
|
||||
self.assertTrue(app.config["SQLALCHEMY_DATABASE_URI"].startswith("postgresql+psycopg://"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user