fix(bounties): validate inputs, return pagination, log errors, expose updated_at/questions - #387
Conversation
Greptile SummaryThis PR improves the
Confidence Score: 4/5Safe to merge — all changes are additive or fix real silent failures; no regressions introduced in the happy path. The validation logic correctly rejects obviously bad inputs and the pagination math is sound. The one gap — float values like src/app/api/bounties/route.ts — the limit/page guards should also reject non-integer values to match the error message they return. Important Files Changed
Sequence DiagramsequenceDiagram
participant Client
participant GET_handler as GET /api/bounties
participant Supabase
Client->>GET_handler: "GET ?status=open&page=1&limit=50"
alt invalid status
GET_handler-->>Client: "400 { error: "Invalid status..." }"
else invalid limit
GET_handler-->>Client: "400 { error: "Invalid limit..." }"
else invalid page
GET_handler-->>Client: "400 { error: "Invalid page..." }"
else params valid
GET_handler->>Supabase: ".select(cols, { count: "exact" }).eq("status",...).range(...)"
alt Supabase error
Supabase-->>GET_handler: error
GET_handler-->>Client: "400 { error: message }"
else success
Supabase-->>GET_handler: "{ data, count }"
GET_handler-->>Client: "200 { data, pagination: { page, limit, total, total_pages } }"
end
end
Reviews (1): Last reviewed commit: "fix(bounties): add updated_at/questions ..." | Re-trigger Greptile |
| if (params.get("limit") !== null && (!Number.isFinite(limitRaw) || limitRaw <= 0)) { | ||
| return NextResponse.json( | ||
| { error: "Invalid limit. Must be a positive integer." }, | ||
| { status: 400 } | ||
| ); | ||
| } | ||
| const limitCandidate = | ||
| Number.isFinite(limitRaw) && limitRaw > 0 ? Math.floor(limitRaw) : defaultLimit; | ||
| const limit = Math.min(limitCandidate, 100); | ||
|
|
||
| const pageRaw = Number(params.get("page")); | ||
| if (params.get("page") !== null && (!Number.isFinite(pageRaw) || pageRaw <= 0)) { | ||
| return NextResponse.json( | ||
| { error: "Invalid page. Must be a positive integer." }, | ||
| { status: 400 } | ||
| ); |
There was a problem hiding this comment.
Float values bypass "positive integer" validation
The validation rejects non-finite and non-positive values but accepts fractional numbers — ?limit=1.5 and ?page=2.7 both pass the guard and are silently floored to 1 and 2 respectively. The error message says "Must be a positive integer" but the actual contract accepted is any positive finite number. A caller following the error message would not expect floats to succeed, so the guard should also reject limitRaw !== Math.floor(limitRaw) (and the same for pageRaw).
…tion issues (matches #387-#390) (#391) * fix(bounties): add updated_at/questions to select, validate inputs, return pagination * fix(gigs): validate status, page, limit query params (matches /api/bounties fix in #387) * fix(notifications): validate limit/offset query params (matches #387, #388) * chore: sync src/app/api/gigs/route.ts with upstream master * chore: sync src/app/api/notifications/route.ts with upstream master * fix(reviews): validate limit/offset/gig_id, log errors, expose validation issues (matches #387-#390)
…#389) (#390) * fix(bounties): add updated_at/questions to select, validate inputs, return pagination * fix(gigs): validate status, page, limit query params (matches /api/bounties fix in #387) * fix(notifications): validate limit/offset query params (matches #387, #388) * fix(activity): validate limit/offset query params (matches #387, #388, #389) * chore: restore src/app/api/gigs/route.ts to upstream (was: 4487, now: 8988) * chore: restore src/app/api/notifications/route.ts to upstream (was: 2955, now: 2180) * chore: restore src/app/api/activity/route.ts to upstream (was: 2258, now: 1650)
…388) (#389) * fix(bounties): add updated_at/questions to select, validate inputs, return pagination * fix(gigs): validate status, page, limit query params (matches /api/bounties fix in #387) * fix(notifications): validate limit/offset query params (matches #387, #388) * fix(notifications): validate limit/offset query params (matches #387, #388) * chore: restore src/app/api/gigs/route.ts to upstream (was: 4487, now: 8988) * chore: restore src/app/api/notifications/route.ts to upstream (was: 2658, now: 2180)
…unties fix in #387) (#388) * fix(bounties): add updated_at/questions to select, validate inputs, return pagination * fix(gigs): validate status, page, limit query params (matches /api/bounties fix in #387) * fix(notifications): validate limit/offset query params (matches #387, #388) * chore: sync src/app/api/gigs/route.ts with upstream master * chore: sync src/app/api/notifications/route.ts with upstream master
Bug Fix: /api/bounties endpoint improvements
Found while testing ugig.net as part of bug bounty
c3137a9d("I will pay for every bug fix found and PR submitted that fix").Bugs Found
Bug 1: Missing fields in GET response
The
select()clause omitsupdated_atandquestionscolumns that exist in thebountiestable. Frontend has no way to know when a bounty was last modified, and the questions metadata is unavailable for the public listing endpoint.Bug 2: Invalid
statusquery param silently returns[]?status=invalidreturns empty array instead of a 400 error. Clients can't tell if they made a typo or there are no results.Bug 3: No pagination metadata
Response only returns
dataarray. Clients can't tell if more pages exist or how many. Addingtotalandtotal_pagesis the standard fix.Bug 4: Generic 500 errors with no logging
Both GET and POST catch all exceptions and return
{"error":"Unexpected error"}with noconsole.error. Production debugging is impossible.Bug 5: No input validation feedback on POST
When
createBountySchema.safeParse()fails, only the first issue message is returned. The fullissuesarray is dropped, making client-side validation work harder.Changes
updated_atandquestionsto theselect()clause.statusparam against allowed values (open|paused|closed), return 400 for invalid.limitandpageparams, return 400 for non-positive integers.{ count: "exact" }to Supabase query to get total count.paginationobject to response:{ page, limit, total, total_pages }.console.errorlogging for both expected and unexpected errors.issuesarray in POST validation error response.Testing
After merging, verify:
Related
c3137a9don ugig.netsrc/app/api/bounties/route.ts)Looking forward to your review.