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_PASSWORD`
|
||||||
- `MAIL_DEFAULT_SENDER`
|
- `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
|
## Site Admin Access
|
||||||
|
|
||||||
|
|||||||
+5
-1
@@ -9,7 +9,7 @@ from flask import Flask, render_template, request
|
|||||||
from werkzeug.exceptions import HTTPException
|
from werkzeug.exceptions import HTTPException
|
||||||
|
|
||||||
from boker.auth import current_user_id, is_logged_in, is_site_admin, normalize_email
|
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.db import database_extensions_available, db, init_database
|
||||||
from boker.extensions import csrf, limiter, mail
|
from boker.extensions import csrf, limiter, mail
|
||||||
from boker.routes.account import account_bp
|
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:
|
if app.config["SESSION_COOKIE_SECURE"] and app.config["SECRET_KEY"] == DEFAULT_SECRET_KEY:
|
||||||
raise RuntimeError("Set SECRET_KEY before running in production.")
|
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"])
|
ensure_data_file(app.config["DATA_PATH"])
|
||||||
init_database(app)
|
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