Repository navigation
fix: fetch existing record in-process for transaction validation - #214
Merged
Merged
Conversation
Cql2ValidateTransactionMiddleware fetched the existing record for PUT/PATCH/ DELETE with its own httpx client pointed at upstream_url. When stac-auth-proxy is used as middleware around a STAC API, upstream_url points back at the same app, so that GET re-entered the auth middleware without credentials and failed (401 surfaced as 502). Issue the GET in-process to the downstream ASGI app instead. As middleware this hits the STAC API's routes directly; as a proxy it goes through ReverseProxyHandler to the upstream. Either way it never re-enters the auth layer, so no credentials need forwarding. Only host/accept are sent, so caller conditional (If-None-Match, Range) and Accept-Encoding headers can't produce a 304/206/undecodable body. Supersedes #201. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Claude finished @alukach's task in 23s —— View job ✅ No blocking issues — safe to merge. I read the diff and traced the sub-request through the middleware stack.
Non-blocking notes:
Simplify (ponytail)
💰 Estimated review cost: $0.16 · 0m22s · 6 turns |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #214 +/- ##
==========================================
+ Coverage 89.76% 90.22% +0.46%
==========================================
Files 30 30
Lines 1348 1361 +13
Branches 180 182 +2
==========================================
+ Hits 1210 1228 +18
+ Misses 97 92 -5
Partials 41 41
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Address review feedback on #214: - Copy scope state for the in-process GET so downstream writes to request.state can't leak into the caller's request. - Wrap the downstream call so a raised exception becomes UpstreamError (502) instead of an unhandled 500. - Cover raised-exception, non-JSON body, and state isolation in tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
alukach
marked this pull request as ready for review
October 3, 2026 03:21
alukach
pushed a commit
that referenced
this pull request
Oct 6, 2026
🤖 I have created a release *beep* *boop* --- ## [1.3.0](v1.2.0...v1.3.0) (2026-10-06) ### Features * add HTTPException handling in CQL2BuildFilter middleware ([#202](#202)) ([5aeee7c](5aeee7c)) * **helm:** add servicemonitor support. ([#209](#209)) ([979ceda](979ceda)) ### Bug Fixes * allow queryables endpoints for collections ([#204](#204)) ([8b3d3c9](8b3d3c9)) * allow text in json response for CQl2RewriteLinksFilterMiddleware ([#205](#205)) ([e55d85f](e55d85f)) * fetch existing record in-process for transaction validation ([#214](#214)) ([3ffdd1d](3ffdd1d)) * keep headers from HTTPException responses built by middleware ([#212](#212)) ([bd13264](bd13264)) * key OPA filter cache on full request context, not just Authorization (GHSA-rm58-963w-252r) ([2a1c989](2a1c989)) * normalize root_path_skip_prefixes in ProcessLinksMiddleware ([#199](#199)) ([1193600](1193600)) * reject ambiguous request paths before path-based checks (GHSA-c42p-7w4w-p877) ([2a1c989](2a1c989)) * update reverse_proxy.py to return correct status code for upstream request timeout ([#210](#210)) ([be008ba](be008ba)) * URL-encode query string values when injecting CQL2 filter (GHSA-c2p2-r6vx-2qc8) ([2a1c989](2a1c989)) ### Documentation * add security policy ([#218](#218)) ([ed3a6d7](ed3a6d7)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: ds-release-bot[bot] <116609932+ds-release-bot[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Cql2ValidateTransactionMiddlewarefetches the existing record for PUT/PATCH/DELETE with its ownhttpxclient pointed atupstream_url. When stac-auth-proxy is used as middleware around a STAC API,upstream_urlpoints back at the same app, so that GET re-entersEnforceAuthMiddlewarewithout credentials and fails (a 401 surfaced to the caller as a 502).#201 fixes this by forwarding the caller's headers onto the GET, but forwarding everything also carries
If-None-Match/Range(→ 304/206 with no JSON body → uncaught 500) andAccept-Encoding(e.g.zstd→ undecodable body).Change
Issue the GET in-process to the downstream ASGI app (
self.app) instead of over HTTP:ReverseProxyHandlerto the upstream exactly like any other request (same client, timeout,Forwardedheaders).hostandaccept: application/jsonare sent, which closes off the conditional and encoding problems above.httpx.AsyncClientand itsupstream_urlargument.UpstreamError, which is mapped to the existing 502UpstreamErrorresponse.Behavior note: in the full stack the sub-request passes through
Cql2ValidateResponseBodyMiddlewarewith the caller's filter, so a record the caller can't read is reported as 404, matching the existing "existing record doesn't match filter → 404" behavior.Tests
TestFetchExistingMiddlewareMode: an outer auth stand-in rejects requests withoutAuthorization. PUT/DELETE succeed, and the in-process GET arrives with noauthorization/if-none-match/accept-encoding. Also covers denied-existing → 404, missing → 404, and downstream 500 → 502.TestFetchExistingProxyMode: realReverseProxyHandleroverhttpx.MockTransport. The upstream sees a clean GET followed by the PUT (with the caller's auth). An upstream 503 on the GET → 502 and the PUT is never forwarded.Supersedes #201.
🤖 Generated with Claude Code