fix: escape SQL wildcards in tag search autocomplete

The % and _ characters in user search input are now escaped before
the LIKE query, preventing unintended wildcard matching in tag search.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
chihlasm
2026-02-06 00:26:35 -05:00
parent 94ec19cf07
commit 1e57aa8323
2 changed files with 33 additions and 1 deletions

View File

@@ -62,8 +62,9 @@ async def search_tags(
Searches tag names for the query string.
Returns matching tags ordered by usage count.
"""
escaped_q = q.replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_")
query = select(TreeTag).where(
TreeTag.name.ilike(f"%{q}%")
TreeTag.name.ilike(f"%{escaped_q}%", escape="\\")
)
# Filter by visibility

View File

@@ -275,6 +275,37 @@ class TestTrees:
)
assert len(tag_rows_after.fetchall()) == 0
@pytest.mark.asyncio
async def test_tag_search_escapes_wildcards(
self, client: AsyncClient, admin_auth_headers: dict
):
"""Test that SQL wildcards in tag search are escaped, not interpreted."""
# Create tags as admin (can create global tags)
resp1 = await client.post(
"/api/v1/tags",
json={"name": "test_underscore"},
headers=admin_auth_headers
)
assert resp1.status_code == 201
resp2 = await client.post(
"/api/v1/tags",
json={"name": "testXunderscore"},
headers=admin_auth_headers
)
assert resp2.status_code == 201
# Search for literal underscore — should only match the first tag
response = await client.get(
"/api/v1/tags/search",
params={"q": "test_under"},
headers=admin_auth_headers
)
assert response.status_code == 200
names = [t["name"] for t in response.json()]
assert "test_underscore" in names
assert "testXunderscore" not in names
@pytest.mark.asyncio
async def test_create_tree_unauthorized(self, client: AsyncClient):
"""Test that creating a tree without auth fails."""