fix(#1): reject whitespace-only titles in POST and PATCH /tasks - #3
fix(#1): reject whitespace-only titles in POST and PATCH /tasks#3fullsend-ai-coder[bot] wants to merge 5 commits into
Conversation
The POST /tasks endpoint used `if (!title)` to validate titles, which only catches falsy values. Whitespace-only strings like " " are truthy in JavaScript and bypassed this check. The PATCH /tasks/:id endpoint had no title validation at all. Changes: - POST handler: add `.trim()` check so whitespace-only titles are rejected with 400. Trim accepted titles before storing. - PATCH handler: add title validation when `updates.title` is provided, rejecting empty/whitespace-only values with 400. Trim accepted title updates before storing. - Add integration tests covering both endpoints for empty, whitespace-only, null, and valid title inputs. Closes #1
ReviewFindingsMedium
Low
Info
Previous runReviewFindingsLow
Info
Previous run (2)ReviewFindingsLow
Info
Previous run (3)ReviewFindingsNo findings. Previous run (4)ReviewFindingsLow
Info
|
| try { | ||
| const { title, description } = JSON.parse(body); | ||
| if (!title) { | ||
| if (!title || !title.trim()) { |
There was a problem hiding this comment.
[low] correctness
Non-string title values (e.g., {title: 123}) will throw TypeError on .trim(), caught by catch block and returned as "invalid JSON". The error message is misleading. Pre-existing pattern, but consider adding explicit type check as follow-up.
Suggested fix: Add typeof title !== "string" guard before .trim() with error message "title must be a string".
|
/fs-fix |
Replace `!title` checks with `typeof title !== 'string'` guards in both POST and PATCH /tasks handlers so non-string values (numbers, booleans) return 400 with "title is required" instead of falling through to the catch block with a misleading "invalid JSON" error. Add tests for numeric and boolean title inputs in both endpoints. Addresses review feedback on #3 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: fullsend-fix <fullsend-code@users.noreply.github.com>
🔧 Fix agent — iteration 1 (human-triggered)Addressed review feedback: replaced falsy checks with typeof string guards in both POST and PATCH title validation to handle non-string inputs correctly. Added 3 new tests. Fixed (3):
Tests: passed Updated by fullsend fix agent |
|
/fs-fix Apply similar input validation hardening for the pattern described in #2 |
|
🤖 Finished Fix · ✅ Success · Started 1:41 PM UTC · Completed 1:45 PM UTC |
Wrap `new URL()` constructor in the request handler with try/catch so malformed URL paths return 400 Bad Request instead of crashing the server process. Add integration test for the malformed URL scenario. Addresses review feedback on #3
🔧 Fix agent — iteration 2 (human-triggered)Applied input validation hardening per issue #2: wrapped URL parsing in try/catch to prevent server crash on malformed URL paths. Added integration test. All 20 tests pass. Fixed (2):
Tests: passed Updated by fullsend fix agent |
|
🤖 Finished Review · ✅ Success · Started 1:46 PM UTC · Completed 1:55 PM UTC |
| res.writeHead(400); | ||
| res.end(JSON.stringify({ error: 'title is required' })); | ||
| return; | ||
| } |
There was a problem hiding this comment.
[low] logic-error
PATCH trim guard uses truthiness check instead of strict undefined check, inconsistent with validation gate on line 72. Functionally correct today but fragile if validation is relaxed.
Suggested fix: Change if (updates.title) to if (updates.title !== undefined) for consistency.
| @@ -5,7 +5,15 @@ const store = new TaskStore(); | |||
| const PORT = process.env.PORT || 3000; | |||
|
|
|||
| const server = http.createServer((req, res) => { | |||
There was a problem hiding this comment.
[low] scope-creep
URL parsing error handling added but not authorized by issue #1. Small defensive change with its own test, architecturally reasonable.
| const { title, description } = JSON.parse(body); | ||
| if (!title) { | ||
| if (typeof title !== 'string' || !title.trim()) { | ||
| res.writeHead(400); |
There was a problem hiding this comment.
[low] edge-case
Description field not trimmed in POST handler, asymmetric with title trimming. Pre-existing behavior, outside PR scope.
| req.on('end', () => { | ||
| try { | ||
| const updates = JSON.parse(body); | ||
| if (updates.title !== undefined && (typeof updates.title !== 'string' || !updates.title.trim())) { |
There was a problem hiding this comment.
[low] validation-pattern-consistency
PATCH uses two separate if-blocks for validation and trimming while POST combines them. Both correct; structural difference reflects conditional PATCH updates.
|
/fs-fix Follow the instructions at https://gist.github.com/ascerra/d77bba6af784edd4b4ca137086b6a37e |
|
🤖 Finished Fix · ✅ Success · Started 1:59 PM UTC · Completed 2:02 PM UTC |
- Change PATCH trim guard from truthiness check to strict undefined check for consistency with validation gate (logic-error finding) - Add missing test for PATCH with null title (test-inadequate finding) Addresses review feedback on #3
🔧 Fix agent — iteration 3 (human-triggered)Addressed 2 actionable review findings (logic-error: PATCH trim guard consistency, test-inadequate: missing null title test). Could not access the gist URL from the human instruction due to network restrictions. Recorded 4 disagreements for informational/out-of-scope findings. Fixed (2):
Disagreed (4):
Tests: passed Updated by fullsend fix agent |
|
🤖 Review · Started 2:04 PM UTC |
|
/fs-fix Follow the instructions at https://jsonblob.com/api/jsonBlob/019ed0c5-2f9c-7490-abc4-5fc2027ba46d |
| it('returns 400 for URL that triggers parsing failure instead of crashing', async () => { | ||
| const res = await rawRequest('GET', '///'); | ||
| assert.strictEqual(res.statusCode, 400); | ||
| assert.strictEqual(res.body.error, 'bad request'); |
There was a problem hiding this comment.
[low] edge-case
The malformed-URL test relies on new URL("///", base) throwing an error, which is Node-version-dependent. On older Node versions /// may parse successfully, causing the test to fail. The project has no engines field in package.json.
Suggested fix: Use a URL string that reliably triggers a parse error across all supported Node versions (e.g., /%ZZ), or add an engines field to package.json.
|
|
||
| const server = http.createServer((req, res) => { | ||
| const url = new URL(req.url, `http://${req.headers.host}`); | ||
| let url; |
There was a problem hiding this comment.
[low] scope-creep
The PR adds try/catch around URL parsing but Issue #1 only authorizes fixing whitespace-only title validation. This is a small, correct hardening change but undocumented scope expansion.
Suggested fix: Consider mentioning the URL hardening in the PR description, or splitting it into a separate PR.
|
🤖 Finished Review · ✅ Success · Started 2:04 PM UTC · Completed 2:13 PM UTC |
|
🤖 Finished Fix · ✅ Success · Started 2:15 PM UTC · Completed 2:19 PM UTC |
- Add engines field (node >=20) to package.json to document the minimum Node version, addressing the edge-case finding about the malformed URL test relying on Node-version-dependent behavior. - Add description passthrough tests for both POST and PATCH endpoints to guard against future regressions where description might be inadvertently trimmed. Addresses review feedback on #3
🔧 Fix agent — iteration 4 (human-triggered)Addressed 2 remaining actionable review findings: added engines field to package.json for Node >=20 (fixing the malformed URL test portability concern) and added description passthrough tests for both POST and PATCH endpoints. Could not access the jsonblob URL from the human instruction due to network restrictions. Disagreed with 4 informational/out-of-scope findings. Fixed (2):
Disagreed (5):
Tests: passed Updated by fullsend fix agent |
|
🤖 Finished Review · ✅ Success · Started 2:21 PM UTC · Completed 2:30 PM UTC |
The POST /tasks endpoint used
if (!title)to validate titles, which only catches falsy values. Whitespace-only strings like " " are truthy in JavaScript and bypassed this check. The PATCH /tasks/:id endpoint had no title validation at all.Changes:
.trim()check so whitespace-only titlesare rejected with 400. Trim accepted titles before storing.
updates.titleisprovided, rejecting empty/whitespace-only values with 400.
Trim accepted title updates before storing.
whitespace-only, null, and valid title inputs.
Closes #1
Post-script verification
agent/1-whitespace-title-validation)8165fcfe86e993b6f0e3c191e8c23ed4d2097643..HEAD)