fix(das): validate cursor payload fields instead of returning 500#228
Open
rsnetworkinginc wants to merge 1 commit into
Open
fix(das): validate cursor payload fields instead of returning 500#228rsnetworkinginc wants to merge 1 commit into
rsnetworkinginc wants to merge 1 commit into
Conversation
… Postgres 500
decodeCursor type-checks the decoded payload but never checks that
created_at is actually a timestamp or that number is an integer. Both
values are bound to casts in the keyset pagination WHERE clause
((created_at, repo, number) < ($::timestamptz, $, $::int)), so a cursor
like {"created_at":"banana","repo_full_name":"a/b","number":1} — valid
base64url JSON with the right field types — sails through validation and
blows up in Postgres, returning 500 Internal Server Error for what is a
malformed client input. Clients that retry on 5xx will re-send a cursor
that can never work.
Tighten the malformed-cursor check: created_at must parse as a date and
number must be an integer. encodeCursor only ever emits toISOString()
timestamps and integer pr/issue numbers, so no server-issued cursor is
affected; only tampered or corrupted cursors now get the 400 they always
should have.
Adds unit tests for decodeCursor/parsePaginationQuery covering the
round-trip, both new rejection cases, and existing behavior.
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.
PR body — rsnetworkinginc — entrius/das-github-mirror
Branch:
fix-cursor-payload-validation(in WSL Ubuntu-22.04 clone/root/dgm, commit2c376e7, based onorigin/test@a188d3b)Base:
testTitle:
fix(miners): reject unparseable cursor payloads with 400 instead of a Postgres 500Bug
decodeCursor(pagination for/api/v1/miners/:githubId/pulls|issues) checks that the decoded payload's fields have the right types, but never thatcreated_atis actually a timestamp or thatnumberis an integer. Both values are bound to casts in the keyset WHERE clause:So a cursor that is valid base64url JSON with correctly-typed fields sails through validation and blows up inside Postgres, returning 500 Internal Server Error for malformed client input:
Base64url-decoded JSON that fails the shape check already gets a clean 400 ("cursor is malformed") — these two payloads are the gap. Since 5xx is conventionally retryable, a client holding a corrupted/truncated cursor will keep re-sending a request that can never succeed instead of restarting pagination.
Fix
Tighten the malformed-cursor check in
decodeCursor:created_atmust satisfy!Number.isNaN(Date.parse(...));numbermust satisfyNumber.isInteger(...)(subsumes the previousisFinitecheck).Both reuse the existing
BadRequestException("cursor is malformed"). No false rejections are possible:encodeCursoronly ever emitstoISOString()timestamps and integerpr_number/issue_numbervalues, so every server-issued cursor still decodes — only tampered or corrupted cursors are affected.Tests
New
pagination.spec.ts(unit):encodeCursor→decodeCursorround-trip (incl. repo lowercasing);created_atand non-integernumber(the two new cases);parsePaginationQuerypropagates cursor validation, still returnsnullwhen neither limit nor cursor is given, and accepts a valid limit+cursor pair.Written red-first against the current
testtip: the 3 new-validation cases fail before the fix, all 8 pass after.Local checks
npm test— 33 passed (4 suites)npm run lint— cleannpm run format:check— cleannpm run build— cleanNote on cap: rsnetworkinginc already has #221 open (fetch.processor ISSUE_CLOSURE guard). Cap is 2 per the triage bot, so this is the second and last slot — do not open anything else under this account until one of the two resolves.