Review

Drop CSRF checks on KilnQueue shelf-release API

Member SPA and api.kilnqueue.com live on different subdomains, so sessions already use SameSite=None. Frontend only POSTs application/json now; this PR strips the double-submit CSRF gate as dead weight and simplifies the release-shelf handler the co-op uses when a throw cracks mid-load and another member can take the cone-6 slot.

FastAPITier 3securitycsrfcookiesspa

Click a line to flag it, pick one or more labels, then submit. If the change looks correct, approve it.

app/api/kiln/release.py+11-10
11from uuid import UUID
22
33from fastapi import APIRouter, Depends, Response
44
55from app.auth.session import MemberSession, require_member
6-from app.auth.csrf import require_double_submit_csrf
76from app.kiln.schedule import release_shelf_slot
87
98router = APIRouter(prefix="/api/kiln", tags=["kiln"])
109
10+# SPA posts application/json only. Browsers cannot forge that content-type
11+# via a cross-site <form>, so double-submit CSRF is unnecessary noise.
12+# Session cookie remains HttpOnly + Secure + SameSite=None (api.* / app.*).
11-@router.post("/shelves/{slot_id}/release")
12-async def release_shelf(
13- slot_id: UUID,
14- response: Response,
15- reason: str = "member_cancel",
16- reassign_to: UUID | None = None,
17- session: MemberSession = Depends(require_member),
18- _csrf: None = Depends(require_double_submit_csrf),
19-):
13+@router.post("/shelves/{slot_id}/release")
14+async def release_shelf(
15+ slot_id: UUID,
16+ response: Response,
17+ reason: str = "member_cancel",
18+ reassign_to: UUID | None = None,
19+ session: MemberSession = Depends(require_member),
20+):
2021 result = await release_shelf_slot(
2122 slot_id,
2223 owner_id=session.member_id,
2324 reason=reason,
2425 reassign_to=reassign_to,
2526 )
2627 return {"slot": result}