feat(seed): allow_private_ips opt-in for trusted internal API sources - #959
Conversation
|
ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing |
PR Summary by QodoSeedDataManager: opt-in allow_private_ips with shared SSRF guard for API seeds
AI Description
Diagram
High-Level Assessment
Files changed (2)
|
Code Review by Qodo
1.
|
|
Both findings addressed in
Full suite: 62/62 green across the seed + ssrf test modules. |
|
One thing of note: auth stripping fix from Qodo round only covers half the case it needs to. It compares Repro: Headers sent on downgraded hop: {'Authorization': 'Bearer secret-token'}
Given this PR's whole point is sending Fix should be a one liner: compare scheme too, or just check Everything else is good once this is in. |
|
Excellent catch @ZohaibHassan16 — you are right, the netloc-only comparison missed the https -> http downgrade on the same host, and the Authorization header would have been replayed in cleartext. That is exactly the kind of leak this PR must not ship with. Fixed in
Verified locally: 39/39 tests in Thanks again for the sharp review — exactly the kind of gap that is hard to see from the inside. |
0abea55 to
99ca5ec
Compare
026c5c4 to
2422863
Compare
…rces (Closes #943) SeedDataManager.load_from_api now delegates to the shared SSRF guard (semantica/ingest/ssrf.py, added in #906) instead of raw requests.get, gaining redirect validation and bounded DNS resolution for free. New config option allow_private_ips (parsed via the shared parse_bool helper) lets trusted internal deployments load from private APIs while the secure default (block private/loopback/link-local) is unchanged. Tests updated to mock request_with_ssrf_guard; new tests cover the block-by-default behavior and the opt-in flag reaching the guard. 19/19 green in test_seed_manager.py, 25/25 across both seed suites. Signed-off-by: Yunare Maia <yunare@gmail.com>
…ing) request_with_ssrf_guard reused the caller's headers on every redirect hop, so an Authorization bearer token from load_from_api could leak to a different redirect target host. Now strips Authorization and Proxy-Authorization when the redirect origin (netloc) changes, while keeping them for same-host hops (matching requests semantics). 2 new tests: cross-host redirect drops the credential; same-host keeps it. 37/37 green in test_ssrf_protection.py. load_from_api docstring now also documents cloud-metadata blocking and per-hop redirect validation. Signed-off-by: Yunare Maia <yunare@gmail.com>
…ew feedback) _should_strip_auth now mirrors requests' should_strip_auth semantics: strip on hostname change, port change, or scheme downgrade; keep the credential only for the safe http->https upgrade on default ports. Previously only netloc was compared, so an https->http redirect on the same host replayed the Authorization header in cleartext.
2422863 to
524a204
Compare
ZohaibHassan16
left a comment
There was a problem hiding this comment.
All tests passing. Approved.
Closes #943
Summary
Adds the documented opt-in for trusted internal deployments:
allow_private_ipsonSeedDataManager, without weakening the secure default.Changes (
semantica/seed/seed_manager.py):load_from_api()now delegates to the shared SSRF guard (semantica/ingest/ssrf.py, introduced in fix(ingest): SSRF protection for Web and API ingestors (#867) #906) viarequest_with_ssrf_guard()instead of rawrequests.get()— this also gains redirect-chain validation and bounded DNS resolution for freeallow_private_ips, parsed through the sharedparse_bool()helper (avoids thebool("false") == Truepitfall), defaulting to FalseTests (
tests/test_seed_manager.py):test_load_from_api_blocks_private_by_default—127.0.0.1rejected, no request madetest_load_from_api_allows_private_when_configured— withconfig={"allow_private_ips": True}the request proceeds and the flag reaches the guardtest_load_from_apiupdated to mockrequest_with_ssrf_guard(the call path changed)test_seed_manager.py, 25/25 across both seed suitesThe follow-up in #936 (SSRF guard for
load_from_api) is complementary: this PR plugs the same function into the repo's shared guard with the internal-deployment escape hatch requested here.