feat(#630): simplify SQL Browser authentication integration around @altinity/clickhouse-http (phase 6) - #648
Conversation
…s for the coming auth-owner move Adds the missing authedFetch characterization tests plan §14 Commit 1 calls for (fresh Authorization per retry, no second refresh after a retried auth failure, confirmed-401 counterpart to the existing confirmed-403 case, non-2xx never reports connected, onSignedOut receives the captured epoch, exact caller AbortSignal identity) so the coming ownership move (Commit 2) can retarget every one of them onto authenticatedRequest() unchanged rather than writing fresh proofs with nothing to compare against. Also extends build/check-boundaries.mjs with the not-yet-existing src/net/authenticated-clickhouse-request.ts: both #585 transport-leaf forbidden lists (clickhouse-http-transport.ts, clickhouse-transport.types.ts) and the #512 connectionAuthorityFiles lifecycle-authority list. The checker tolerates the not-yet-existing file, so the new auth owner is born inside its intended architecture boundary instead of landing temporarily unguarded. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwFPT465eDJqYcRa8HGNLz
…icated-clickhouse-request.ts Extracts the SQL Browser authenticated-request policy that used to live in src/net/ch-client.ts (authedFetch/transportFor: credential acquisition, epoch fencing, one-refresh retry, connect/offline/sign-out lifecycle classification) into a new module, src/net/authenticated-clickhouse-request.ts, which builds the @altinity/clickhouse-http package client directly (createClickHouseHttpClient(...).request()) instead of going through the compatibility transport adapter. authedFetch() and the ChCtx-based transportFor(ctx) are deleted outright — no forwarding alias, no second retry loop, no second Authorization constructor. ChCtx now extends the new module's narrower AuthenticatedRequestCtx instead of redeclaring its fields; it adds only dataLakeCatalogSettingUnsupported, the one field genuinely specific to this product client. AuthenticatedCancellationLease stays exported from ch-client.ts, and killQueryWithLease's frozen-lease bypass is untouched — it already built its own one-shot transport directly from the frozen lease, never through ChCtx, so it does not route through the new mutable-context auth loop. queryJson() now delegates to the new module's authenticatedJson(), the first real production consumer of the package's JSON response consumer (consumeJsonResponse); it translates the package's ClickHouseError back to queryJson's existing plain-Error compatibility shape, preserving the parsed exception message. runQuery()/exportQuery() switch only their authedFetch() call to the new raw authenticatedRequest() entrypoint, keeping their own result/error/body handling unchanged (their full package-consumer cutover is Phase 7). authenticatedText()/ authenticatedProgress() are added over the package's remaining response consumers as additive composition, not yet consumed by any src/** caller outside this module. Moves every low-level authedFetch test (plus the Commit-1 sensor additions) to the new tests/unit/authenticated-clickhouse-request.test.ts, retargeted onto authenticatedRequest, and adds package-consumer composition tests (authenticatedJson/Text/Progress each drive exactly one Fetch plus one matching package response consumer). ch-client.test.ts keeps only caller-level proofs: queryJson's existing JSON/error/ compatibility behavior and invocation-time settings/params capture, runQuery/exportQuery's unchanged result shapes and signal propagation. Reconciles now-stale authedFetch/transportFor(ctx) ownership comments in ch-client.ts, clickhouse-transport.types.ts, clickhouse-http-transport.ts, and connection-session.ts (+ its test) to name the new module as current owner while preserving historical Phase 1-5 narrative. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwFPT465eDJqYcRa8HGNLz
… (5-9) Adds authenticated-path variants of the existing post-header cancellation scenarios in tests/e2e/clickhouse-http-transport.html: Scenario 5 (native post-header body lifetime), 6 (no package streamLines() callbacks after cancellation), 7 (concurrent-request isolation sharing one ctx), 8 (abort after completion has no effect), and 9 (authenticatedProgress(), not the raw package client.queryProgress()) — each routed through the new src/net/authenticated-clickhouse-request.js module's authenticatedRequest()/authenticatedProgress() against a real, production-shaped AuthenticatedRequestCtx (synthetic test credentials, one deterministic epoch, refresh disabled) instead of the compatibility transport/package client with an already-resolved Authorization. Scenarios 1-4 (pre-header timing) and the existing raw 5-9/Extra stay unchanged as lower-layer coverage. Verified locally in both Chromium and WebKit: the new spec file's 15 scenarios (10 raw + 5 authenticated) and the full e2e suite (224 scenarios across both projects; WebKit's 4 environment-gated OAuth document-recovery specs skip as expected) are green. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwFPT465eDJqYcRa8HGNLz
…CHANGELOG for the auth-owner move
Repository-wide rg sweep for '\b(authedFetch|transportFor)\b' and
present-tense "ch-client owns auth" phrasing, classified per finding:
- current-owner comments retargeted to authenticated-clickhouse-request.ts
/ authenticatedRequest (already handled in the prior two commits for
src/net/**, src/application/connection-session.ts, and its test);
- spike fixtures (guarded-fetch.ts, official-adapter.ts, current-adapter.ts,
parity.test.ts) that compared against "the current production auth
owner" now say so explicitly ("at the time this spike was written,
ch-client.ts's authedFetch; since #630 Phase 6, authenticated-
clickhouse-request.ts's authenticatedRequest, unchanged in shape"),
preserving the historical comparison without asserting current
ownership;
- genuinely historical evidence (docs/evidence/585/**, CHANGELOG's #585
entries, ADR-0005's own historical citations/measurements, run-matrix.mjs/
support-minimum.mjs's evidence-generation classification tables pinned to
already-published numbers) is left byte-identical — none of it asserts
current ownership, and it must not be rewritten;
- one hit (clickhouse-http-package-policy.test.js's browser-root-literal
sabotage fixture) is an arbitrary import-name example unrelated to
authedFetch's own existence, left as-is.
Reconciliation artifacts required before certification:
- CHANGELOG.md [Unreleased] gains the #630 Phase 6 entry and reconciles
Phase 5's forward "Phase 6 auth composition ... deferred" statement;
- docs/ARCHITECTURE.md gains an "Authenticated request layer (#630 Phase 6)"
section and updates the Phase 2-5 narrative's now-superseded present-tense
claims to past tense;
- CLAUDE.md's hard rule 2 and repo-map table describe the new module and
its response-consumer adoption, keeping every other hard rule unchanged;
- .wiki/Architecture.md's Query path, .wiki/Source-Map.md's src/net table
rows, and .wiki/Decisions-and-Roadmap.md's #630 section advance through
Phase 6 while Phase 7 stays recorded as deferred;
- docs/ADR-0005-clickhouse-web-client.md gains a narrow "#630 Phase 6
authenticated-composition addendum," matching the existing Phase 2/4
addendum pattern, without touching any historical content, date, or
measurement recorded elsewhere in the ADR.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwFPT465eDJqYcRa8HGNLz
|
ChatGPT review pass 1 Reviewed head: FindingP2 —
At this head, What I verified
No other concrete defect found in the reviewed Phase-6 scope. VERDICT: REVISE |
docs/ARCHITECTURE.md's current-state "Route sessions and shells" section still attributed authConfirmed mutation and connected/offline transport classification to net/ch-client, contradicting the same commit's own new "Authenticated request layer (#630 Phase 6)" section, which correctly credits authenticatedRequest() in the new src/net/authenticated-clickhouse-request.ts module for both (authConfirmed/onTransportConnected on 2xx, onTransportOffline on a rejected non-aborted fetch). Retarget both sentences to net/authenticated-clickhouse-request; ch-client.ts no longer performs either mutation since Phase 6 moved authedFetch()/transportFor(ctx) out with no forwarding alias. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwFPT465eDJqYcRa8HGNLz
|
ChatGPT review pass 2 Previously reviewed head: Pass-1 finding statusRESOLVED. The one fix commit between the two SHAs changes only FindingP2 — two remaining current-path descriptions still call the compatibility transport the normal production query path.
Please rewrite those two descriptions so the ordinary path is Revalidation
No additional runtime/security/compatibility defect found. VERDICT: REVISE |
.wiki/Architecture.md's Query path step 2 and the e2e transport harness's Scenario 1-8 header comment still described the compatibility transport (createHttpTransport().send() -> package streamLines) as the ordinary production path. Since this phase, queryJson/runQuery/exportQuery reach authenticatedRequest()/authenticatedProgress() -> package request()/response consumers instead; createHttpTransport now remains live only as the frozen- lease killQueryWithLease bypass's compatibility route. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwFPT465eDJqYcRa8HGNLz
|
ChatGPT review pass 3 Previously reviewed baseline: Earlier finding status
FindingP2 — the E2E harness still contains older present-tense comments that contradict its newly corrected Phase-6 header.
Please retarget those older Scenario-6/Phase-3 comments to historical/lower-layer wording (and sweep the immediately adjacent raw-scenario wording for the same obsolete “production path” label). The authenticated Scenario-6 comment is already accurate: it identifies Revalidation
No runtime/security/compatibility defect found beyond the documentation/comment reconciliation issue above. VERDICT: REVISE |
Correct the remaining stale present-tense production-path claims in the raw Scenario 6 and Scenario 8 comments in tests/e2e/clickhouse-http-transport.html: they still said Scenario 6 exercises "the exact call path ch-client.ts's runQuery uses in production since Phase 3" via createHttpTransport().send() -> package streamLines, and Scenario 8 piggybacked on that same claim. Since Phase 6, runQuery()/queryJson()/exportQuery() go through authenticatedRequest()/authenticatedProgress() instead; createHttpTransport() is now only the frozen-lease killQueryWithLease compatibility route. Reword both comments to match the file's already- corrected top-level explanation: these raw scenarios are lower-layer package/transport regression coverage, not a claim about the current production path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwFPT465eDJqYcRa8HGNLz
Two more present-tense production-path claims survived the pass-3 fix in tests/e2e/clickhouse-http-transport.html: the Phase-3 top-of-file header still said Scenario 6/8's streamLines usage was "the SAME real production call path ch-client.ts's runQuery uses", and the Scenario 9 header called Scenario 6's path "the production compatibility path". Both predate Phase 6 (when runQuery/queryJson/exportQuery moved to authenticatedRequest()/ authenticatedProgress()) and are now worded to match the file's corrected top-level explanation. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwFPT465eDJqYcRa8HGNLz
ChatGPT review — final certification (manual continuation, same conversation)Session 226cff42's own Reviewed head:
|
Summary
Phase 6 of #630 ("Epic: extract the Fetch-native ClickHouse client"). Moves SQL Browser's
authenticated ClickHouse HTTP request composition — credential lookup, epoch capture/fencing,
refresh-retry, Authorization construction, lifecycle (connected/offline/sign-out) classification —
out of
src/net/ch-client.ts'sauthedFetch()/transportFor()and into a new,narrowly-scoped module,
src/net/authenticated-clickhouse-request.ts, which composesdirectly over
@altinity/clickhouse-http'srequest()and its Phase-4 response consumers(
consumeJsonResponse/consumeTextResponse/consumeProgressResponse). This is the firstreal production consumer of the Phase-4 response layer.
authedFetch()andtransportFor(ctx)are fully deleted — no forwarding alias, no secondretry loop, no second Authorization constructor.
queryJson(),runQuery(), andexportQuery()all now traverse the newauthenticatedRequest()/authenticatedJson()entrypoints.
ChCtxstays SQL-Browser-owned (nowextends AuthenticatedRequestCtx), and thefrozen-lease cancellation bypass (
killQueryWithLease) is untouched — it still never readsmutable credential/refresh/lifecycle state.
Query-result/export cutover to the package's convenience query APIs, and deletion of the
remaining generic transport mechanics, stay Phase 7's scope per the issue's own phase split —
not attempted here.
Claims A12 (authentication composed through one authenticated request layer over package
request()) and A13 (epoch/refresh/lifecycle/cancellation/frozen-lease invariants remainregression-tested and unchanged). A1–A11 already shipped; A14–A18 remain deferred to Phase 7/8.
Invariant map (plan §8) — all 13 behavioral invariants + architecture guards, sabotage-proven
await getToken()→ replacement epoch gained authority instead of AbortError. Failed as required.chUrlpreflight → token read became observable before the URIError. Failed.authHeader()→ a Fetch occurred despite the flip. Failed.onSignedOut→ call observed unlabeled. Failed.ChCtx→tscfailed with 9 type errors. Failed.Architecture sabotages (
build/check-boundaries.mjs): importing the new module fromclickhouse-http-transport.tsfailscheck:arch; type-only importing it fromclickhouse-transport.types.tsfailscheck:arch(proving the type-only leaf boundary too);introducing
serverVersionin the new module fails the #512 connection-authority guard. All16 sabotages: bytes saved → mutation introduced → smallest proof run and confirmed to fail for
the stated reason → exact bytes restored; verified clean afterward (
git status/git diffempty at HEAD).
Tests
tests/unit/authenticated-clickhouse-request.test.ts(new, 627 lines) — the movedlow-level auth/epoch/refresh/lifecycle characterization suite, retargeted to
authenticatedRequest()/authenticatedJson()/authenticatedText()/authenticatedProgress(),plus package-consumer composition proofs.
tests/unit/ch-client.test.ts— pared to caller-level proofs:queryJson()'sClickHouseError→plain-Error compatibility translation,
runQuery()/exportQuery()resultshapes, cancellation propagation.
tests/unit/connection-session.test.ts— unchanged behavior, still green (independentproof layer: refresh single-flight, replacement-epoch authority, immutable lease capture).
tests/e2e/clickhouse-http-transport.{html,spec.js}— added authenticated-path variants ofpost-header cancellation scenarios 5–9, run through the real
authenticatedRequest()/authenticatedProgress()composition (not just the raw package client). 30/30 passing onboth Chromium and WebKit locally.
Gate
Review
concrete defects found; confirmed the move is byte-for-byte algorithmically identical to
the deleted
authedFetch()apart from the client-construction line, confirmed no ownerremnants, confirmed the frozen-lease bypass untouched, confirmed the architecture-guard
change is a pure data extension.
security-reviewskill isn't installed inthe current environment, so an equivalent adversarial pass was run against its exact
checklist): no vulnerabilities found across all 10 checked items (epoch supersession,
Authorization reuse, missing fences, stale sign-out, credential observability, package
boundary, AbortSignal identity, frozen-lease isolation, misclassification of prep/abort/HTTP
failures).
Documentation reconciliation
CHANGELOG.md[Unreleased],docs/ARCHITECTURE.md,CLAUDE.md,.wiki/Architecture.md,.wiki/Source-Map.md,.wiki/Decisions-and-Roadmap.md, and a narrow current-state addendumto
docs/ADR-0005-clickhouse-web-client.md(preserving all historical content/datesunchanged) all updated. A repository-wide
authedFetch/transportForreference sweepreclassified every hit: current-owner comments updated, genuine historical references
preserved, executable references eliminated.
Part of #630.
Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01LwFPT465eDJqYcRa8HGNLz