keep a precise failure precise, and state one redirect policy

Two problems of the same shape: information about *why* something failed being
replaced by something vaguer.

get_dataset_geojson wrapped the JSON parse, the metadata read, the CRS
resolution and the canonicalisation in one try and reported all of it as
"Stored dataset is not valid JSON" with a 500. An operator whose dataset had an
unusable CRS was sent to inspect a file that parses perfectly well, and the
canonicaliser's own AppError — with its code and its status — never reached
them. Only the parse is now inside that handler; everything after it keeps the
error it raised, and a genuine bug becomes a distinct 500 rather than a
mislabelled client error. A guard finds the same shape elsewhere: catching
Exception around a call into another component and relabelling what it
reported. Wrapping one's own private helper stays legitimate and the guard
says so.

The redirect policy was split without anyone saying so. Two acquisition
services rejected every redirect through a hand-rolled opener, while eight
allowed a same-origin one through the shared guard — and only the latter
checked where the response came from. Both live in the guard now, and the
strict path uses the rejecting handler rather than the guard's after-the-fact
check: objecting to response.url means urllib already opened the connection and
read the body, which for a metadata endpoint is the whole attack. That was a
weakening I introduced in this same commit's first draft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Jens
2026-08-22 23:35:59 +02:00
co-authored by Claude Opus 5
parent c6837ec1b2
commit 7c052a339e
8 changed files with 375 additions and 26 deletions
+6 -2
View File
@@ -62,8 +62,12 @@ runtime source of truth.
- An export states its own completeness in `geointel_provenance`. A capped
export is still a valid, usable file — it simply no longer implies it holds
everything the selection contains.
- Bounded acquisition refuses a redirect that leaves the configured origin, and
refuses any private, loopback or link-local destination. An official endpoint
- Bounded acquisition refuses any private, loopback or link-local destination,
resolving the host first so a DNS name cannot hide one. Two redirect policies
apply: the paged OGC feature readers refuse to follow a redirect at all,
because a page URL they built themselves should be answered by that URL; the
other readers allow a redirect within the configured origin, since providers
do version their endpoints. A refused redirect is never requested. An official endpoint
that legitimately moves to a new host therefore fails closed until the
operator updates the configured URL, which is the intended trade: bytes from
an unexpected host must never be persisted under an official provenance.