Conversation
Co-authored-by: Radhey Kalra <radheykalra901@gmail.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedBot user detected. To trigger a single review, invoke the ⚙️ Run configurationConfiguration used: Repository UI Review profile: ASSERTIVE Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| if (typeof jobId !== 'string' || !isJobState(state) || typeof progress !== 'number') { | ||
| return null; | ||
| } |
There was a problem hiding this comment.
Invalid progress passes validation. Job progress is defined as 0–100, but this check accepts any number. If a malformed frame names an existing job, the jobs store writes values such as
-1 or 5000 directly. Validate the range before accepting the update.
| if (typeof jobId !== 'string' || !isJobState(state) || typeof progress !== 'number') { | |
| return null; | |
| } | |
| if ( | |
| typeof jobId !== 'string' || | |
| !isJobState(state) || | |
| typeof progress !== 'number' || | |
| !Number.isInteger(progress) || | |
| progress < 0 || | |
| progress > 100 | |
| ) { | |
| return null; | |
| } |
| } | ||
|
|
||
| /** Returns null for malformed JSON, an unknown type, or a payload of the wrong shape. */ | ||
| export function parseServerMessage(text: string): WSServerMessage | null { |
There was a problem hiding this comment.
Parser lacks persistent tests. This parser now decides which WebSocket frames can update job state, but its valid and invalid cases have no committed regression tests. The described 12-frame check was a throwaway script. Persistent tests would catch changes that accept malformed updates or discard valid server messages.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| if (message) { | ||
| handleServerMessage(message); | ||
| } else { | ||
| console.warn('Ignoring unrecognised WebSocket message:', text); |
There was a problem hiding this comment.
Rejected frames logged verbatim. Every malformed or unrecognised frame is now printed in full. An unexpected job message could contain user paths or a large payload, making browser diagnostics noisy and retaining data the previous parse-error log did not print. Log a bounded description instead of the raw frame.
| console.warn('Ignoring unrecognised WebSocket message:', text); | |
| console.warn('Ignoring unrecognised WebSocket message'); |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
…esperides-d9702ac5--parse-boundary Co-authored-by: Radhey Kalra <radheykalra901@gmail.com>
…iefly Co-authored-by: Radhey Kalra <radheykalra901@gmail.com>
* Fix auto_discover mounts being dropped at startup (#131) * Fix auto_discover mounts being dropped at startup Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> * Make the auto_discover test pick a mounted directory and check it is returned Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> --------- Co-authored-by: usehoplite[bot] <288093033+usehoplite[bot]@users.noreply.github.com> Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> * Make chunk_size_mb control browser upload chunks (#132) * Make chunk_size_mb control browser upload chunks Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> * Share one chunk size request across upload workers and respect cancel Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> --------- Co-authored-by: usehoplite[bot] <288093033+usehoplite[bot]@users.noreply.github.com> Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> * Resolve virtual paths in one place (#133) Co-authored-by: usehoplite[bot] <288093033+usehoplite[bot]@users.noreply.github.com> Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> * Parse WebSocket and job data at the boundary (#134) * Parse WebSocket and job data at the boundary Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> * Validate job progress range, add parser tests, log rejected frames briefly Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> --------- Co-authored-by: usehoplite[bot] <288093033+usehoplite[bot]@users.noreply.github.com> Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> * Move frontend state to runes and split the browse page (#136) * Migrate jobs and websocket stores to runes Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> * Migrate settings store to runes and split out appearance helpers Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> * Migrate auth store to runes Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> * Split the browse page into composables Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> * Keep the WebSocket reconnect backoff when connect runs in an effect Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> --------- Co-authored-by: usehoplite[bot] <288093033+usehoplite[bot]@users.noreply.github.com> Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> * Fix the auth API docs, drop stale comments, add AGENTS.md (#137) * Fix the auth API docs, drop stale spec comments, add AGENTS.md Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> * Add the frontend test command to AGENTS.md Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> * Correct the logout docs and scope the path rule Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> --------- Co-authored-by: usehoplite[bot] <288093033+usehoplite[bot]@users.noreply.github.com> Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> * Fix --dev failing config validation (#139) * Fix --dev failing config validation Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> * Isolate the dev credentials test from inherited BoxBox settings Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> --------- Co-authored-by: usehoplite[bot] <288093033+usehoplite[bot]@users.noreply.github.com> Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> * Test the WebSocket reconnect backoff (#138) * Test the WebSocket reconnect backoff Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> * Keep the connection mode on WebSocket retries and test the attempt limit Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> --------- Co-authored-by: usehoplite[bot] <288093033+usehoplite[bot]@users.noreply.github.com> Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> * Fix browsing discovered mount points Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> * Skip inaccessible auto-discovered mounts Co-authored-by: Radhey Kalra <radheykalra901@gmail.com> --------- Co-authored-by: usehoplite[bot] <288093033+usehoplite[bot]@users.noreply.github.com> Co-authored-by: Radhey Kalra <radheykalra901@gmail.com>
Problem
The browser trusted data it had not checked. WebSocket frames were read with
JSON.parse(text) as WSServerMessage, and the payload was then cast again in each branch. An unexpected frame could put a wrong shape into the jobs store. The API client also returned{} as Tfor any success response that was not JSON, so a proxy error page or the SPA fallback looked like a successful call. On the Go side,JobResponsecopied every field ofmodel.Jobby hand and re-formatted the dates for no reason.Change
parseServerMessage, which turns a raw frame into a discriminated union (job_update | job_complete | error | pong) ornull. The store switches on the union with an exhaustiveness check (satisfies never), and logs and ignores frames it does not recognise. Noasremains in that path. Progress must be an integer from 0 to 100, and the log line for a rejected frame does not include the frame.frontend/src/lib/api/websocket.test.ts(runs withbun run test, usingnode:testso no new dependency) and a CI step for it.JobUpdatetoapi/jobs.tswithisJobState, so the job state values are listed once.ApiRequestError(INVALID_RESPONSE) when a success response is not JSON. Every handler already returns JSON, so no working call changes. Drive-name calls declaredvoidfor a JSON reply and now sayunknown.icon: anyand its eslint-disable inSettingsSectionwithtypeof ChevronDown.JobResponseandtoJobResponseand serialisemodel.Jobdirectly. It already hidesOwnerand the resolved paths withjson:"-". Job times now include fractional seconds (RFC 3339 with nanoseconds), the same format asmodTimeon files, which the browser already parses. An empty job list is still[].Left alone: the 40 or so
event.target as HTMLInputElementcasts in components, and thenull as string | nullinsettings.ts, which goes away when that store is migrated in unit 5. REST payload shapes are still trusted, not validated.Verification
{"jobs":[]}. A job response contains no owner or resolved paths, omits a zerostartedAt, and has acreatedAtthat parses as RFC 3339 with nanoseconds.bun run testpasses.bun run check,lintandbuildpass.go vetand the handler tests pass.202and the page received newline-batchedjob_updateframes (running, progress 0 to 100, then completed). The parser split them correctly and the copied file matched.job_completeorerrorframe from a real server, and a proxy that returns HTML with status 200 (the newINVALID_RESPONSEpath).Stack: 4 of 6. Targets the branch of the PR below it.
Written by anthropic/claude-sonnet-5-5 in the Hoplite agent harness.