Validate auto_update_query when a custom list is saved (PP-4506)#3551
Validate auto_update_query when a custom list is saved (PP-4506)#3551dbernstein wants to merge 1 commit into
Conversation
A custom list's auto_update_query was only checked for JSON serializability before being stored, never for whether the search layer could actually parse it. A query with an unknown key, a bad operator, or a malformed `published` value (e.g. `2025>01>01`) was accepted and persisted, and the list then silently stopped updating: the entry-update task can do nothing with such a list but log and skip it. Creating a list incidentally exercised its query through populate_query_pages, but editing one never parsed the query at all, so the bad value could only ever be introduced -- and never surfaced -- via an edit. Both paths are now validated, returning INVALID_INPUT with the parser's own explanation of what is wrong. Also corrects the auto_update_query annotation, which claimed dict[str, str] even though a query's value is a nested dict. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Claude finished @dbernstein's task in 4m 59s —— View job Code review — PR #3551
SummaryThe approach is sound — parsing the query at save time (for both create and edit) is the right place to turn a silently-stalled list into an immediate error, and the parametrized tests are a good illustration of the gap being closed. The annotation fix ( Details
|
Greptile SummaryThis PR validates custom list auto-update queries before saving them. The main changes are:
Confidence Score: 4/5The changed save path needs a contained fix for malformed nested query values.
src/palace/manager/api/admin/controller/custom_lists.py Important Files Changed
Reviews (1): Last reviewed commit: "Validate auto_update_query when a custom..." | Re-trigger Greptile |
| _ = JSONQuery(auto_update_query).search_query | ||
| except QueryParseException as exc: |
There was a problem hiding this comment.
Malformed Values Escape Validation
When a librarian submits a JSON-serializable query with the right keys but a wrong nested value type, such as a numeric title value, this new validation can raise a plain parser runtime error instead of QueryParseException. The admin save path then returns a 500 instead of the intended invalid-input response, so malformed auto_update_query payloads are still not handled safely at save time.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## bugfix/custom-list-sweep-query-parse-error #3551 +/- ##
==============================================================================
- Coverage 93.46% 93.46% -0.01%
==============================================================================
Files 512 512
Lines 46614 46623 +9
Branches 6352 6352
==============================================================================
+ Hits 43570 43578 +8
- Misses 1968 1969 +1
Partials 1076 1076 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Description
Note
Stacked on #3550 — its base is
bugfix/custom-list-sweep-query-parse-error, so the diff shown here is only this commit. Held in draft until #3550 merges; the base will then be retargeted tomain.A custom list's
auto_update_querywas only checked for JSON serializability before being stored — never for whether the search layer could actually parse it.CustomListsController._create_or_update_listnow builds aJSONQueryfrom the submitted query and returnsINVALID_INPUT(400) if it can't be parsed, passing along the parser's own explanation of what's wrong.Also corrects the
auto_update_queryparameter annotation, which claimeddict[str, str]even though a query'svalueis a nested dict. That's why the existing tests were able to pass placeholders like{"query": "foo"}without mypy complaining.Motivation and Context
Follow-up to #3550, which fixed the symptom: a list whose stored query contained a
publishedvalue of2025>01>01failed its Celery task every sweep and (before that PR) wedged the sweep lock for every library.This PR fixes how the bad value got in. Two gaps combined:
populate_query_pagescall on theis_newpath — but aQueryParseExceptionthere surfaced as an unhandled 500, not a validation error.Either way the result was a list that silently stopped updating, since the entry-update task can do nothing with an unparseable query but log it and skip. Rejecting the query at save time turns a silent, indefinitely-stalled list into an immediate 400 for the librarian who fat-fingered the date.
Behavior change worth flagging in review: a librarian editing an existing list whose stored query is already invalid will now get a 400 rather than a successful save, even if they only meant to change the list's name — the admin UI resubmits
auto_update_queryunchanged. That seems right to me (it forces the broken query to be fixed), but it is a real change, and it means any already-corrupted rows in production should be corrected before this ships.How Has This Been Tested?
tox -e py312-docker -- tests/manager/api/admin/controller/test_custom_lists.py tests/manager/core/test_customlist_queries.py tests/manager/celery/tasks/test_custom_lists.py(64 passed).test_auto_update_query_must_be_a_valid_search_queryis parametrized over four ways to be invalid — the2025>01>01value from production, an unknown key, an unknown operator, and a missingqueryroot — and asserts the parser's reason is surfaced in the problem detail and that nothing is persisted.test_auto_update_query_validated_on_editcovers the gap specifically: an existing list rejects a bad query on edit and keeps its previous good one.{"query": "foo"},{"query": "...changed"}) that the new validation correctly rejects. They test facets serialization, entry handling, and the repopulate-on-query-change path, so they now pass a valid query. That they needed changing at all is a decent illustration of how little the old code cared what was in this column.Checklist
🤖 Generated with Claude Code