harden: low-severity bundle (rate-limit, TOCTOU, erasure order, outbox)#60
Merged
Conversation
Bundled low-severity findings from the review: - Rate-limit the self-service export endpoint (10/min/IP) for parity with withdraw/delete — the submission UUID is the only credential. - Withdraw is now race-safe: read + guarded `updateMany (status = current)` in one transaction; terminal statuses (incl. an existing withdrawal) return 409. - Erasure (DELETE) removes the row first (cascade) so it's durable even if object storage is down, then best-effort purges the stored objects. - `GET /api/files/[id]`: set Content-Length on `contentLength !== undefined` (0-byte files were silently dropping the header). - Outbox delivery: deliver each row under its own try/catch (one bad row no longer aborts the batch) and mark the delivered rows read in a single `updateMany`. Add a partial index on `notifications(created_at) WHERE read_at IS NULL` (hand-written migration) to keep the poller scan cheap. - Cap `maxFileSizeMb` at a hard server ceiling (`MAX_FILE_SIZE_MB = 25`) in the spec schema and clamp it again in the upload route; document the bounded in-memory buffering. - Move a misplaced doc comment onto the function it describes (deliverOne).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bundled low-severity findings from the multi-agent review (PR C — final of the cluster).
Changes
GET /api/submissions/[id]/exportnow rate-limited (10/min/IP) for parity with withdraw/delete (the UUID is the only credential).updateMany (status = current)in one transaction; terminal statuses (incl. an existing withdrawal) return 409 instead of racing.Content-Lengthis set oncontentLength !== undefinedrather than truthy.updateMany. New partial indexnotifications(created_at) WHERE read_at IS NULL(hand-written migration) keeps the scan cheap as the table grows.maxFileSizeMbcapped at a hard server ceiling (MAX_FILE_SIZE_MB = 25) in the spec schema and clamped again in the upload route; bounded in-memory buffering documented.deliverOne).Migration
20260620180000_notification_pending_index— rawCREATE INDEX ... WHERE read_at IS NULL(partial indexes aren't expressible in the Prisma schema). Applied byprisma migrate deployon deploy.Validation
pnpm typecheck,pnpm lint,pnpm test,pnpm build— all green.