fix: sanitize Prisma writes for control chars#1275
Conversation
Local Testing
Results: Lint ✅; Vitest 714 passed / 0 failed / 12 skipped (726 total). |
noa-lucent
left a comment
There was a problem hiding this comment.
Centralized sanitization is on the right track, but the middleware currently ignores the clause for actions such as /. Those lookups still carry the offending control characters, so Postgres continues to raise 22P05 and, in the upsert path, we now create sanitized keys but keep querying by the unsanitized key which causes duplicate-key failures. Please sanitize the filter objects alongside the payload and add regression coverage for the case.
Local Testing (update)
Results: Lint ✅; Vitest 715 passed / 0 failed / 12 skipped (727 total). |
noa-lucent
left a comment
There was a problem hiding this comment.
Looks good—middleware now sanitizes filters alongside the payload, so the lookups match the stored rows and the new tests cover the regression.
Local Testing (filters update)
Results: Typecheck ✅; Lint ✅; Vitest 716 passed / 0 failed / 12 skipped (728 total). |
|
Updated per stakeholder guidance: removed the global Prisma middleware, added localized sanitization in Local Testing
Results: Typecheck ✅; Lint ✅; Vitest 713 passed / 0 failed / 12 skipped (725 total). |
noa-lucent
left a comment
There was a problem hiding this comment.
Focused sanitizer at the ConversationState repository resolves the 22P05 regression and keeps serialization logic localized. Tests cover both the sanitizer helpers and the repository behavior. Looks good to merge.
Test & Lint Summary
|
noa-lucent
left a comment
There was a problem hiding this comment.
Ingress decoding/sanitization and LLM/run-event guards look good. Thanks for the thorough coverage.
|
Local verification:
|
|
CI update:
Next: once Test Server is green, we’ll proceed with merge and close Issue #1274. |
|
Tests & Lint Summary:
|
|
Requesting review: PR #1275 is updated and CI is green. Please review and approve if ready to merge. |
noa-lucent
left a comment
There was a problem hiding this comment.
Thanks for pushing the ingress decode/sanitize work through. There is still one blocker: sanitizeToolCallRecords now coerces Prisma.JsonNull/null arguments to plain null and then sends them to toPrismaJsonValue, which throws on top-level nulls. Any tool call that legitimately returns JSON null will trip this and fail to persist. Please preserve the sentinel (or convert back to Prisma.JsonNull) instead of normalizing to null before reserializing.
| } | ||
|
|
||
| private sanitizeToolCallRecords(records?: ToolCallRecord[]): ToolCallRecord[] | undefined { | ||
| if (!records || records.length === 0) return undefined; |
There was a problem hiding this comment.
[major] coerces any argument to and then immediately feeds that value into . The converter explicitly rejects top-level (it throws ), so the moment a caller supplies to represent a JSON tool-call payload, will now explode instead of persisting the event. Please either leave the sentinel untouched or convert it back to before calling so that JSON- arguments remain writable.
|
Local verification:\n- |
|
CI status: All checks are green. Requesting re-review. |
noa-lucent
left a comment
There was a problem hiding this comment.
Looks great. The tool-call argument sanitization now preserves Prisma.JsonNull and the new regression tests cover both sentinel and plain-null inputs.
|
Status: CI is green; re-review approved. Merge is currently blocked by branch protection/rules. Noted outstanding review request: Team |
Summary
Fixes #1274
Testing