You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
sea-auth-u2m: round-2 fixup — wrap close() in decodeNapiKernelError, raise on U2M+id, case-insensitive validation, preserve all error envelope fields
Addresses devils-advocate-auth-u2m-1 round-1 findings on commit
8e99b40. NF-1 is a HIGH continuation of DA-F1 — the previous fixup
wired `decodeNapiKernelError` at `SeaBackend.openSession` but missed
the second extant napi call site, `SeaSessionBackend.close()`. NF-2
through NF-4 are mediums.
## NF-1 (HIGH) — close() wrapped
`SeaSessionBackend.close()` calls `await this.connection.close()` on
the napi `Connection`. Kernel errors from there (e.g., a delete-
session RPC failure that the kernel chose to surface despite the
fire-and-forget pattern) were reaching JS callers as raw `Error`
with `__databricks_error__:` envelope. Wrapped in try/catch +
`throw decodeNapiKernelError(err)` — same 3-line shape as
openSession.
Per `grep -rn "await this\.native\.\|await this\.connection\." lib/sea/`,
these are the only two napi call sites on `sea-auth-u2m`. Future
napi call sites on sea-execution / sea-results / sea-operation
branches need the same wrap (Phase 2; tracked elsewhere).
## NF-2 (medium) — raise on U2M + oauthClientId
Previously, `oauthClientId` set without `oauthClientSecret` was
silently dropped (kernel uses built-in `databricks-cli`). A user
setting the field clearly expects it honored; silent-drop hid
intent. Flipped to throw HiveDriverError with explicit guidance
("kernel uses 'databricks-cli'; omit for U2M or supply
oauthClientSecret for M2M").
The matching unit test in `tests/unit/sea/auth-u2m.test.ts` flipped
from "drops the supplied oauthClientId" to "rejects oauthClientId
on the U2M path with a clear 'not supported' error".
## NF-3 (medium) — case-insensitive reserved-literal validation
`isBlankOrReserved` previously compared `trimmed === 'undefined'`
and `=== 'null'`, so `'UNDEFINED'`, `'Null'`, `'NULL'`, `'nUlL'`,
etc. slipped through. Changed to `trimmed.toLowerCase()` before
the comparison. New unit case in `auth-edge-cases.test.ts` iterates
five case variants and asserts each rejects.
## NF-4 (medium) — preserve all 7 kernel envelope fields
`decodeNapiKernelError` previously routed only `{code, message,
sqlState}` to the JS error class. The kernel envelope at
`native/sea/src/error.rs:50-89` actually carries 7 fields total
(`code`, `message`, `sqlState`, `errorCode`, `vendorCode`,
`httpStatus`, `retryable`, `queryId`). The remaining 5 were
silently dropped. Thrift parity demand: thrift errors carry these
fields.
Added `attachMetadata(error, meta)` helper that `Object.defineProperty`s
each non-undefined field as a non-enumerable own-property — matches
the way `attachSqlState` works and the way Node attaches `.code` to
system errors. Two new unit tests verify (a) all 5 fields round-trip
through a synthetic envelope, (b) they remain non-enumerable
(absent from `Object.keys(err)`) but accessible via direct property
read.
## Items DEFERRED to Phase 2 (recorded here for the curator)
- NF-5 (envelope versioning): `__databricks_error__:` payload has
no `version` field. A kernel refactor that renames a field would
silently break the JS decoder. Phase 2: add `version: 1` to the
kernel-side serialization, check + fallback on JS side. Not in
this commit because it requires coordinated kernel-side change.
- NF-6 (U2M e2e harness): `auth-u2m-e2e.test.ts` is fully
`it.skip` pending the Playwright/Puppeteer harness. Devils-
advocate noted that port-collision + headless-negative-path
subsets don't strictly need a browser. Phase 2: enable those
subsets when the harness lands. Not in this commit because the
work is mostly harness-wiring rather than test code.
Tests:
- Unit: 79/79 pass (was 74 before this commit: +5 — 1 case-insensitive
reserved literal sweep, 1 M2M oauthClientSecret reserved-literal
reject, 2 envelope-metadata preservation, 1 close() decode + 1
flipped from drop-to-reject which kept the count net same — but
the OAuthClientId test rewrite is on a different file).
- TypeScript build: clean.
- Native build: unchanged (no Rust changes this commit).
Co-authored-by: Isaac
0 commit comments