- C1: drop module-level app singleton in app/main.py so importing the package no longer validates Settings or creates DATA_DIR; run uvicorn with --factory in the Dockerfile. pytest now collects and passes with no ambient env vars. - I2: add missing app/auth, app/security, app/web __init__.py so setuptools discovers all five packages. - I3: resolve the Jinja2 template directory relative to __file__ instead of the process CWD. - I4: add .gitignore covering .env, data/, .venv/, caches and build artifacts so example deployment secrets cannot be committed. - I5: assert UserRepository.list_enabled() excludes disabled users. - M6: encode both operands before hmac.compare_digest in validate_csrf so a non-ASCII token yields 403 instead of an unhandled 500. - M9: remove unused relationship / HealthState imports. - M11: make session cookie https_only configurable via SESSION_HTTPS_ONLY (default unchanged: false). - M13: dispose SQLAlchemy engines in the db_session and client fixtures. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
36 lines
1.1 KiB
Python
36 lines
1.1 KiB
Python
from fastapi import FastAPI
|
|
from starlette.middleware.sessions import SessionMiddleware
|
|
|
|
from app.config import Settings, get_settings
|
|
from app.db.session import create_db_engine, create_session_factory, initialize_schema
|
|
from app.web.routes import router as web_router
|
|
|
|
|
|
def create_app(settings: Settings | None = None) -> FastAPI:
|
|
resolved = settings or get_settings()
|
|
resolved.data_dir.mkdir(parents=True, exist_ok=True)
|
|
resolved.tokens_dir.mkdir(parents=True, exist_ok=True)
|
|
resolved.activities_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
app = FastAPI(title="MyWhoosh Garmin Sync")
|
|
app.state.settings = resolved
|
|
|
|
engine = create_db_engine(resolved.database_url)
|
|
initialize_schema(engine)
|
|
app.state.db_engine = engine
|
|
app.state.session_factory = create_session_factory(engine)
|
|
|
|
app.add_middleware(
|
|
SessionMiddleware,
|
|
secret_key=resolved.secret_key,
|
|
same_site="lax",
|
|
https_only=resolved.session_https_only,
|
|
)
|
|
app.include_router(web_router)
|
|
|
|
@app.get("/healthz")
|
|
def healthz() -> dict[str, str]:
|
|
return {"status": "ok"}
|
|
|
|
return app
|