Skip to content

[SEA-NodeJS] (1/3) SEA connect + auth (PAT + OAuth M2M/U2M)#409

Open
msrathore-db wants to merge 2 commits into
mainfrom
msrathore/sea-connect-auth
Open

[SEA-NodeJS] (1/3) SEA connect + auth (PAT + OAuth M2M/U2M)#409
msrathore-db wants to merge 2 commits into
mainfrom
msrathore/sea-connect-auth

Conversation

@msrathore-db
Copy link
Copy Markdown
Contributor

@msrathore-db msrathore-db commented Jun 1, 2026

First of three stacked PRs splitting the SEA foundation (replaces the single 8/8 #383). Establishes a SEA-backed connection + session.

  • SeaBackendconnect() validates auth + captures napi ConnectionOptions; openSession() folds catalog/schema/sessionConf and opens a kernel session.
  • SeaAuth — PAT + OAuth M2M + OAuth U2M validation/routing.
  • SeaErrorMapping — kernel ErrorCode → JS error-class mapping.
  • SeaSessionBackend — open/close; executeStatement + metadata throw a clear deferred error (wired in 2/3).
  • DBSQLClient — routes useSEA: true to the real SeaBackend.
  • native/sea — napi-rs binding surface (.d.ts + router); .node stays gitignored (loader/version tests skip when absent).

Tests: PAT/M2M/U2M/edge-case auth, kernel error mapping, DBSQLClient SEA routing + partial-init guard.

Stack: 1/3#410#411

This pull request and its description were written by Isaac.

First of three stacked PRs splitting the SEA foundation (was the single
8/8 PR #383). This PR establishes a SEA-backed connection and session:

- SeaBackend: connect() validates auth + captures the napi ConnectionOptions;
  openSession() folds catalog/schema/sessionConf and opens a kernel session.
- SeaAuth: PAT + OAuth M2M + OAuth U2M validation/routing (mirrors the
  DBSQLClient auth-validation pattern; slash-prepended httpPath via prependSlash).
- SeaErrorMapping: kernel ErrorCode → JS error-class mapping.
- SeaSessionBackend: session open/close. executeStatement + metadata methods
  throw a clear deferred error — wired in [2/3] SEA execution + results.
- DBSQLClient: route `useSEA: true` to the real SeaBackend (with IClientContext).
- native/sea: the napi-rs binding surface (.d.ts + router); the .node stays
  gitignored (CI does not build it, loader/version tests skip when absent).

Tests: PAT / M2M / U2M / edge-case auth suites, kernel error mapping, and the
DBSQLClient SEA-routing + partial-init guard. Drops the obsolete stub
SeaBackend.test (real backend is covered by the auth suites).

Co-authored-by: Isaac
Signed-off-by: Madhavendra Rathore <madhavendra.rathore@databricks.com>
@gopalldb
Copy link
Copy Markdown
Collaborator

gopalldb commented Jun 1, 2026

🔴 P0 (Critical) — verified at source, must fix

SEA is non-functional on a clean install: the generated loader requires package names that are garbled AND undeclared in optionalDependencies.
native/sea/index.js (all platform branches) + package.json

I confirmed both halves:

  • Every npm fallback in the loader is @databricks/sea-native-linux-x64-gnu- — e.g. ...-gnu-darwin-arm64, ...-gnu-win32-x64-msvc, and even the real linux target resolves to
    @databricks/sea-native-linux-x64-gnu-linux-x64-gnu. The M0 triple linux-x64-gnu got baked into the package prefix for every platform — a napi-rs npmName misconfiguration when index.js was regenerated.
  • optionalDependencies contains only lz4 and @napi-rs/cli — none of the per-platform native packages. So npm install never fetches a .node, and a useSEA:true caller always hits MODULE_NOT_FOUND, on every
    platform including the supported one.

→ Fix: regenerate native/sea/index.js with the correct npmName, declare the real per-platform packages in optionalDependencies, and align the loader hint / .npmignore comments to that name. Add a test
asserting the require name in index.js matches an optionalDependencies key. (Also: @napi-rs/cli is a build tool sitting in optionalDependencies — it'll be pulled into consumer installs; belongs in
devDependencies.)

🟠 P1 (Important)

  1. M2M-vs-U2M flow selection diverges from Thrift and breaks a valid config (carryover Simplify basic usage (hide Thrift details) #1 from [SEA-NodeJS] (8/8) M1 Phase 1 — OAuth M2M + OAuth U2M (5 review rounds, ZERO HIGH at close) #383 — PERSISTS, and it's a real trap, not just a comment) — SeaAuth.ts:270-316. Thrift keys off the secret
    (oauthClientSecret === undefined ? U2M : M2M, DBSQLClient.ts:216); SEA selects M2M whenever oauthClientId is present. A valid oauthClientId + no secret → Thrift runs U2M, SEA throws AuthenticationError. The
    comment still claims it "mirrors thrift's DBSQLClient.createAuthProvider (DBSQLClient.ts:143)" — wrong line (:216) and wrong claim. And SEA's U2M arm hardcodes databricks-cli and rejects any client id, so
    this is a genuine capability gap, not just routing. → fix the comment and document the divergence + the U2M-no-custom-id limitation honestly.
  2. Stale source line ref DBSQLOperation.ts:209 (carryover Setup E2E tests with GitHub Actions #2 from [SEA-NodeJS] (8/8) M1 Phase 1 — OAuth M2M + OAuth U2M (5 review rounds, ZERO HIGH at close) #383 — PERSISTS) — SeaErrorMapping.ts:54 and the :702-region comment. The actual errorCode === OperationStateErrorCode.Canceled switch is now
    at :374/:376; :209 is unrelated. The namespacing design is correct — only the ref drifted. → update or drop the line number.

🟡 P2 (Minor)

  • SeaBackendOptions.context optional + blind as IClientContext (carryover Update CHANGELOG #3 — PERSISTS, unreachable today) — SeaBackend.ts:415 can store undefined; the only prod caller always passes {context: this}, and
    session methods throw before derefing it. Latent NPE when M1 wires executeStatement to use context. → make required + stub in tests, or guard.
  • prependSlash not actually shared — the new lib/utils/prependSlash.ts docstring claims it's shared by DBSQLClient and SeaAuth "so the two can't drift," but neither imports it; both keep private copies (now
    3 identical impls). No correctness impact. → import it at both sites or drop the file.
  • Cancelled/Timeout mapping discards the default state message — SeaErrorMapping.ts:626-635 overwrites the enum's canonical message with kernel text. Intentional; flagged only for consumers relying on the
    canonical message.

- P0 packaging: the napi router's per-platform npm names were garbled — the
  M0 triple was baked into the prefix for every platform
  (@databricks/sea-native-linux-x64-gnu-<triple>, and the doubled
  ...-gnu-linux-x64-gnu). Corrected to the canonical @databricks/sql-kernel-<triple>
  (matches the loader hint + native/sea/README). Added native-packaging.test
  to lock the naming. The per-platform packages are unpublished, so they remain
  undeclared in optionalDependencies (npm ci can't resolve an unpublished pin);
  README documents the M0 build:native load path.
- Moved @napi-rs/cli out of optionalDependencies (a build tool should not land
  in consumer installs); build:native now fetches it on demand via npx --yes.
- P1 auth-flow: documented honestly that SEA's OAuth flow selection DIVERGES
  from Thrift — Thrift keys off the secret (DBSQLClient.ts:216), SEA keys off
  oauthClientId presence — including the two real gaps (id+no-secret throws;
  U2M has no custom client id). Fixed the stale DBSQLClient.ts:143 ref.
- P1 stale ref: SeaErrorMapping pointed at DBSQLOperation.ts:209; the Canceled
  switch is now ~:374. Updated.
- P2 context: SeaBackendOptions.context is now required (was an `as IClientContext`
  downcast of undefined → latent NPE). Tests pass a shared makeFakeContext().
- P2 prependSlash: dropped the dead lib/utils/prependSlash.ts (nothing imported
  it; SeaAuth and DBSQLClient each keep their own inline copy).

Co-authored-by: Isaac
Signed-off-by: Madhavendra Rathore <madhavendra.rathore@databricks.com>
@msrathore-db msrathore-db deployed to azure-prod June 1, 2026 13:42 — with GitHub Actions Active
@msrathore-db
Copy link
Copy Markdown
Contributor Author

Thanks @gopalldb — validated all of these against the source; addressed in the latest push (f6418e0, plus the rebased stack). Summary:

🔴 P0 — packaging

  • Garbled npm names: confirmed — the M0 triple was baked into the prefix for every platform (@databricks/sea-native-linux-x64-gnu-darwin-arm64, and the doubled …-gnu-linux-x64-gnu). Corrected the router to the canonical @databricks/sql-kernel-<triple> (matches the loader hint + native/sea/README.md). Added tests/unit/sea/native-packaging.test.ts asserting every @databricks/* require matches @databricks/sql-kernel-<triple> and that the garbled/doubled prefixes never reappear. (The root cause is the kernel's napi package.name; this fixes the committed/shipped router, and the kernel config needs the matching change so a future build:native doesn't regress it.)
  • @napi-rs/cli in optionalDependencies: agreed — a build tool shouldn't land in consumer installs. Removed it from optionalDependencies; build:native now fetches it on demand via npx --yes @napi-rs/cli@2.18.4.
  • Per-platform packages not declared: these aren't published yet, and npm ci hard-fails on a pinned dependency it can't resolve from the registry — so declaring them now would break every install. Left undeclared for M0; native/sea/README.md now documents that the binding comes from build:native locally until the packages publish (at which point they go back into optionalDependencies). Could not write the "require-name matches an optionalDependencies key" test for the same reason; the naming-regression test above is the M0 stand-in.

🟠 P1

  1. M2M/U2M flow selection: confirmed the divergence and rewrote the docs honestly — Thrift keys off the secret (DBSQLClient.ts:216), SEA keys off oauthClientId presence, with both real gaps spelled out (id + no secret throws where Thrift runs U2M; SEA U2M has no custom client id). Fixed the wrong :143 ref and dropped the misleading "mirrors thrift" claim.
  2. Stale DBSQLOperation.ts:209: updated to ~:374 (the actual errorCode === OperationStateErrorCode.Canceled switch) in both spots.

🟡 P2

  • SeaBackendOptions.context: made required (removed the as IClientContext downcast of undefined) so a missing context is a compile error, not a latent NPE. Tests pass a shared makeFakeContext().
  • prependSlash: dropped the dead lib/utils/prependSlash.ts — nothing imported it; SeaAuth and DBSQLClient each keep their own inline copy.
  • Cancelled/Timeout canonical message: intentional, leaving as-is per your note.

None of these were already fixed downstream; the fixes live in #409 and propagate through the rebased #410/#411.

This pull request and its description were written by Isaac.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants