fix(trino): hold nextUri links to the connection's own origin - #1090
Conversation
A nextUri on another scheme, host or port is refused before any request is sent to it, the statement is cancelled on the configured coordinator, and the ConnectionError names only the two origins. Closes libredb#1087
The provider integration fixture advertised http://trino.test:8080 even when the statement was posted over https, which the origin rule now refuses. Mirror the real coordinator and derive the link from the request the way it builds it from the Host header.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
Thanks, this is good and I will merge it shortly. I removed the rejectForeignLink call from follow(). The host, port, scheme, both-origins, ftp and relative tests all failed, and the DELETE assertion shows the cancel still goes to the configured coordinator. One small gap, if you want to push it first. The IPv6 test cannot fail against a plain string compare. URL already rewrites http://[0:0:0:0:0:0:0:1]:8080 to [::1], so both sides are the same string before sameHost runs. Swapping the spellings fixes that: configure host 0:0:0:0:0:0:0:1 and send the link on http://[::1]:8080/.... I tried it, and it passes on your code and fails when sameHost is replaced by ===. Please keep the existing case next to it. If this does not land soon, I will merge as is and add the test myself. |
Closes #1087
What
TrinoHttpTransport.follow()requested everynextUriexactly as the coordinator sent it, with the connection'sAuthorizationheader attached. A page naming another host got the credential sent there. This holds eachnextUrito the connection's own origin.Change
src/lib/db/http/endpoint.ts: newrejectForeignLink(link, origin). Parses the link withURL, compares scheme, host (via the existingsameHost, so[::1]and[0:0:0:0:0:0:0:1]agree) and port (default port filled in from the scheme) against the transport'sHttpOrigin. A mismatch, a non-http(s) scheme or an unparsable link throws aConnectionErrorthat names only the two origins, never the path or query, and says a proxy that rewritesHostis the usual cause.src/lib/db/providers/sql/trino/http-transport.ts:follow()callsrejectForeignLink(next, this.origin)beforethis.request(next, ...). The throw happens insidequery()'s existingtry, soabandon()still sends theDELETEto the configured coordinator.tests/unit/db/trino/http-transport.test.ts(QUEUED_LINK_1,QUEUED_LINK_2,RUNNING_LINK,PARTIAL_CANCEL_LINK) were onhttp://localhost:8080whilemakeConnection()names127.0.0.1:8080. I changed the fixture side to127.0.0.1and leftmakeConnection()alone, with a note next to the constants.INFO_URIis untouched (it is never followed). The "sends the credential on every follow-up" test connects withssl: require, so its pages now advertisehttps://links to stay on-origin, and it additionally asserts every page was fetched.docs/providers/trino.md§4.4 describes the rule instead of the residual;docs/SECURITY.md0.6 note now lists two residuals (libSQL, Couchbase) instead of three.Tests
New
describe("TrinoHttpTransport nextUri origin"):test.eachover host / port / scheme mismatch:ConnectionError, message nameshttp://127.0.0.1:8080, does not contain the query id or the slug, the foreign link never appears incalls, every recorded call is on the configured origin, and the last call isDELETE /v1/query/<id>.::1vs[0:0:0:0:0:0:0:1]);httpslink with the default port left out againstport: 443.Testing
RED→GREEN: with the transport change stashed, the 6 refusal tests fail (the transport follows the foreign link); with it, all 119 tests in the file pass.
Not run locally: the full
bun run test(component/e2e lanes), the full-projecttsc --noEmitandeslint .— the host is memory-limited (7.6 GB) and those OOM; the unit lane fortests/unit/dbplus the coverage gate on the touched module ran as above. Please approve the workflow run so CI verifies the rest.