fix: CORS headers missing on photo static files #208
No reviewers
Labels
No labels
domain:backend
domain:devops
domain:frontend
status:approved
status:in-progress
status:needs-fix
status:qa
type:bug
type:devops
type:feature
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
forgejo_admin/basketball-api!208
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "207-fix-cors-headers-missing-on-photo-static"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
/uploads/photos/*responses to lackAccess-Control-Allow-Originheaders, triggering Chrome ORB blocks when westside-app loaded player photos cross-originChanges
src/basketball_api/main.py: Movedapp.mount("/uploads/photos", StaticFiles(...))from inside thelifespanasync context manager to module level, afterCORSMiddlewareis registered. Addedos.makedirsat module level sinceStaticFilesrequires the directory to exist at mount time. Kept the lifespanos.makedirsas a belt-and-suspenders safeguard.Test Plan
curl -I https://basketball-api.tail5b443a.ts.net/uploads/photos/<any-file>includesaccess-control-allow-originheaderReview Checklist
Related Notes
westside-app— the project whose coach dashboard is blocked by missing CORS headersQA Review -- PR #208
Scope Check
src/basketball_api/main.py), 9 additions, 4 deletionsCorrectness
lifespancontext manager are not wrapped by middleware, so responses from/uploads/photos/*lackedAccess-Control-Allow-Originheaders.app.mount(...)to module level (afterapp.add_middleware(CORSMiddleware, ...)) ensures the middleware stack wraps static file responses.os.makedirs(settings.upload_dir, exist_ok=True)at module level is necessary becauseStaticFilesvalidates the directory exists at mount time. The duplicate call in lifespan is idempotent (exist_ok=True) and harmless.Testing
Nits
VERDICT: APPROVE
PR #208 Review
DOMAIN REVIEW
Tech stack: Python / FastAPI / SQLAlchemy / Pydantic Settings
Analysis of the fix:
The root cause is correct. FastAPI's
StaticFilesmounted inside alifespanasync context manager does not pass through the middleware stack --CORSMiddlewarenever wraps those responses. Movingapp.mount("/uploads/photos", ...)to module level (afterCORSMiddlewareis registered) is the canonical fix.The module-level
os.makedirs(settings.upload_dir, exist_ok=True)at line 96 is necessary becauseStaticFilesvalidates directory existence at mount time. The duplicate call insidelifespan(line 45) serves as a startup safeguard. Both useexist_ok=True, so there is no conflict. The "belt-and-suspenders" rationale documented in the PR body and code comments is sound.Placement: The mount is placed after all
include_routercalls and beforeif __name__, which is correct --app.mountfor static files should come last so it does not shadow API routes.BLOCKERS
None.
This is a 1-file, 9-addition/4-deletion bugfix that moves existing code from lifespan scope to module scope. No new functionality is introduced -- the static file mount and directory creation existed before. The change is a code relocation, not a feature addition, so the "new functionality with zero test coverage" blocker does not apply.
NITS
No automated CORS verification test. There are zero tests in the suite that assert
access-control-allow-originheaders on/uploads/photos/*responses. The PR test plan covers this via manualcurl -I, which is acceptable for a bugfix. However, aTestClienttest that sends a request with anOriginheader and asserts the CORS response header would prevent regression. Worth a follow-up ticket.Hardcoded CORS origins (lines 54-59 in
main.py) are a pre-existing concern, not introduced by this PR. Out of scope, but worth noting for a future cleanup ticket to move them tosettings.SOP COMPLIANCE
207-fix-cors-headers-missing-on-photo-staticreferences #207)Closes #207)PROCESS OBSERVATIONS
VERDICT: APPROVED