Escape marketplace search filters#394
Conversation
Greptile SummaryThis PR centralises PostgREST filter escaping into a new
Confidence Score: 4/5Safe to merge; the escaping logic is correct and consistently applied across all four routes. The core change is straightforward and well-tested at the integration level. The only gaps are a copy-pasted test label in the skills test and a missing backslash case in the escapePostgrestSearchValue unit suite — neither affects runtime behaviour. src/lib/security/sanitize.test.ts could benefit from a backslash-input test case to fully document the escaping contract. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[User query string] --> B[escapePostgrestSearchValue]
B --> C[Single-pass regex replaces backslash percent underscore comma parens dot]
C --> D[safeSearch or escaped]
D --> E1[skills/mcp/affiliates .or filter]
D --> E2[search route pattern wrapped in wildcards]
E1 --> F[PostgREST HTTP API]
E2 --> F
F --> G[PostgreSQL ILIKE]
G --> H[Results]
Reviews (1): Last reviewed commit: "Escape marketplace search filters" | Re-trigger Greptile |
| describe("escapePostgrestSearchValue", () => { | ||
| it("escapes LIKE wildcards and PostgREST filter punctuation", () => { | ||
| expect(escapePostgrestSearchValue("100%_match,(v1.2)")).toBe( | ||
| "100\\%\\_match\\,\\(v1\\.2\\)" | ||
| ); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
The single test case doesn't exercise the backslash-escaping branch, which is the most sensitive part of the regex — an input of
\ must become \\ so that PostgREST and SQL LIKE each see the correct number of escape sequences. Adding a backslash-only case makes that explicit.
| describe("escapePostgrestSearchValue", () => { | |
| it("escapes LIKE wildcards and PostgREST filter punctuation", () => { | |
| expect(escapePostgrestSearchValue("100%_match,(v1.2)")).toBe( | |
| "100\\%\\_match\\,\\(v1\\.2\\)" | |
| ); | |
| }); | |
| }); | |
| describe("escapePostgrestSearchValue", () => { | |
| it("escapes LIKE wildcards and PostgREST filter punctuation", () => { | |
| expect(escapePostgrestSearchValue("100%_match,(v1.2)")).toBe( | |
| "100\\%\\_match\\,\\(v1\\.2\\)" | |
| ); | |
| }); | |
| it("escapes backslash so it does not act as a dangling LIKE escape character", () => { | |
| expect(escapePostgrestSearchValue("foo\\bar")).toBe("foo\\\\bar"); | |
| }); | |
| it("leaves plain alphanumeric strings unchanged", () => { | |
| expect(escapePostgrestSearchValue("hello world")).toBe("hello world"); | |
| }); | |
| }); |
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!
| const response = await GET(makeGetRequest({ search: "100%_mcp,(v1.2)" })); | ||
|
|
||
| expect(response.status).toBe(200); | ||
| expect(orSpy).toHaveBeenCalledWith( | ||
| "title.ilike.%100\\%\\_mcp\\,\\(v1\\.2\\)%,description.ilike.%100\\%\\_mcp\\,\\(v1\\.2\\)%,tagline.ilike.%100\\%\\_mcp\\,\\(v1\\.2\\)%" | ||
| ); |
There was a problem hiding this comment.
The search input uses
"100%_mcp,(v1.2)" — the mcp substring is copy-pasted from the MCP route test and is semantically confusing in a skills test. Renaming it to something skills-related keeps the test self-documenting.
| const response = await GET(makeGetRequest({ search: "100%_mcp,(v1.2)" })); | |
| expect(response.status).toBe(200); | |
| expect(orSpy).toHaveBeenCalledWith( | |
| "title.ilike.%100\\%\\_mcp\\,\\(v1\\.2\\)%,description.ilike.%100\\%\\_mcp\\,\\(v1\\.2\\)%,tagline.ilike.%100\\%\\_mcp\\,\\(v1\\.2\\)%" | |
| ); | |
| const response = await GET(makeGetRequest({ search: "100%_skill,(v1.2)" })); | |
| expect(response.status).toBe(200); | |
| expect(orSpy).toHaveBeenCalledWith( | |
| "title.ilike.%100\\%\\_skill\\,\\(v1\\.2\\)%,description.ilike.%100\\%\\_skill\\,\\(v1\\.2\\)%,tagline.ilike.%100\\%\\_skill\\,\\(v1\\.2\\)%" | |
| ); |
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!
Extends PostgREST search escaping to marketplace routes that interpolate user search text into .or(...) filters: skills, MCP listings, affiliate offers, and global search. This preserves literal %, _, comma, parentheses, and dot characters instead of letting them act as SQL/PostgREST filter syntax.
Validation: