Skip to content

Commit 69c81f9

Browse files
review fixups: drop inert mocharc require, tighten casts, add CI guards, v2.0.0
Addresses code-review-squad findings from the self-review pass: - F1 (HIGH): drop `require: ['ts-node/register']` from both mocharc files. Verified locally that this option fires after mocha's import() resolution on Node 22+ and does NOT restore `__dirname`. The CJS-loader path on Node ≤20 is registered by nyc.config.js. Per-file path.resolve(...) fixes remain — they're what actually works. - F3 (MED): bump version 1.15.0 → 2.0.0 + CHANGELOG entry enumerating the three breaking signals (engines.node 14→16, uuid major, thrift major). Matches npm-ecosystem convention for runtime-dep majors + engine bumps. - F5 (MED): document the typescript 5.5.4 sandwich pin in CONTRIBUTING.md "Dependency Pins" section. Also documents the uuid override rationale and lockfile v2 pin policy. - F6 (MED): post-rewrite hard-check in setup-jfrog/action.yml. Fails CI loudly if a non-JFrog host slips into package-lock.json (rather than hanging npm ci for 8min like the regression we just fixed). - F7 (MED): timeout-minutes on unit-test (20) and e2e-test (30) jobs. Caps the blast radius of a wedged matrix entry — without these caps one hung e2e job could hold a runner + warehouse session for 6h. - F9 (LOW): add CWD invariant checks to the two tests that resolve from process.cwd(). Fails loudly with a clear error if mocha is ever invoked from a non-repo-root CWD, rather than producing an opaque ENOENT. - F10 (LOW): tighten the two as-any casts. FederationProvider's controller.signal cast now goes through `unknown as import('node-fetch') .RequestInit['signal']` to narrow the assertion. AuthorizationCode test uses `as unknown as (typeof authCode)['createHttpServer']` so the assertion is verifiable. - F12 (LOW): CI lint that fails if package-lock.json's lockfileVersion drifts from 2. Catches the silent v3 rewrite that modern npm performs by default on `npm install`. Verified locally: - npm test passes on Node 16 (904) and Node 22 (898 + 6 pending — the Node-22-only lz4 skip is unchanged from prior commits) - OSV-Scanner v2.3.8 reports zero findings on the lockfile - tsc --noEmit clean against tsconfig.build.json Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
1 parent 220ff59 commit 69c81f9

11 files changed

Lines changed: 81 additions & 17 deletions

File tree

.github/actions/setup-jfrog/action.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@ runs:
5959
echo "package-lock.json resolved: URLs rewritten to JFrog"
6060
echo "Resolved URL distribution after rewrite:"
6161
grep -oE '"resolved": "https://[^/]+' package-lock.json | sort | uniq -c
62+
# Fail loud if any non-JFrog host remains — a new registry hostname
63+
# added to the tree would otherwise silently hang `npm ci` for 8min.
64+
LEAKS=$(grep -oE '"resolved": "https://[^/]+' package-lock.json | grep -v 'databricks\.jfrog\.io' | sort -u || true)
65+
if [ -n "$LEAKS" ]; then
66+
echo "::error::JFrog rewrite incomplete; non-JFrog hosts remain: $LEAKS"
67+
exit 1
68+
fi
6269
else
6370
echo "no package-lock.json found; skipping rewrite"
6471
fi

.github/workflows/main.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@ jobs:
1919
labels: linux-ubuntu-latest
2020
steps:
2121
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
22+
- name: Pin lockfileVersion to 2
23+
# See CONTRIBUTING.md "Dependency Pins". Modern npm writes v3
24+
# by default; catching drift here prevents silent format upgrades
25+
# from sneaking in via `npm install`.
26+
run: |
27+
actual=$(jq -r '.lockfileVersion' package-lock.json)
28+
if [ "$actual" != "2" ]; then
29+
echo "::error::package-lock.json lockfileVersion is $actual; expected 2. Regenerate with 'npm install --lockfile-version=2'."
30+
exit 1
31+
fi
2232
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
2333
with:
2434
node-version: 20
@@ -44,6 +54,7 @@ jobs:
4454
runs-on:
4555
group: databricks-protected-runner-group
4656
labels: linux-ubuntu-latest
57+
timeout-minutes: 20
4758
strategy:
4859
matrix:
4960
# LTS versions: 16/18/20 are the currently-supported floor; 22
@@ -88,6 +99,10 @@ jobs:
8899
group: databricks-protected-runner-group
89100
labels: linux-ubuntu-latest
90101
environment: azure-prod
102+
# Cap job time so a wedged matrix entry doesn't hold a runner +
103+
# warehouse session for GitHub's 6-hour default. Tests historically
104+
# complete in <15min; 30min leaves room for warehouse cold-start.
105+
timeout-minutes: 30
91106
strategy:
92107
# Run all matrix entries even if one fails so a Node-version-specific
93108
# network/TLS regression doesn't hide other versions' results.

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
11
# Release History
22

3+
## 2.0.0
4+
5+
**Breaking changes:**
6+
7+
- **`engines.node` raised from `>=14.0.0` to `>=16.0.0`.** Node 14 is dropped. The modern npm ecosystem ships ES2021 syntax (`||=`) in widely-used transitive deps (e.g. `@dabh/diagnostics@2.0.7+` via `winston`) that Node 14's V8 cannot parse. Node 14 has been EOL upstream since April 2023.
8+
- **`uuid` runtime dep bumped from `^9.0.0` to `^11.1.1`.** uuid 11 is dual-published as ESM and CJS; this driver's CJS-compiled `dist/` continues to `require('uuid')` without changes. Customers whose code constructs uuids via this driver's transitive copy will see the v11 API surface (`v4`, `stringify`, `NIL` — the functions this driver uses — are API-stable across v9→v11).
9+
- **`thrift` runtime dep bumped from `^0.16.0` to `^0.23.0`.** Seven minor versions of the Apache Thrift Node.js client. Clears GHSA-r67j-r569-jrwp (HIGH) and GHSA-526f-jxpj-jmg2.
10+
11+
**Security:**
12+
13+
- Clear all OSV-Scanner HIGH/MED/LOW findings on the lockfile via dep bumps and an `overrides` block pinning 18 transitives to patched versions (databricks/databricks-sql-nodejs#390 by @vikrantpuppala)
14+
- Notably clears GHSA-w5hq-g745-h8pq (uuid v3/v5/v6 buffer-bounds, HIGH 7.5 — not reachable in this driver's usage but visible to customer-side scanners against our lockfile)
15+
16+
**Other:**
17+
18+
- Extend CI matrix to Node 16/18/20/22/24 for both unit and e2e tests (was 14/16/18/20 unit, single-version Node 20 e2e)
19+
- CI: rewrite lockfile `resolved:` URLs to JFrog mirror before `npm ci` so protected runners can fetch
20+
- TypeScript pinned to exact `5.5.4` (constraint: >=5.0 for uuid@11 d.ts, <5.6 to avoid Buffer-generic emit changing published declarations)
21+
322
## 1.15.0
423

524
- Add SPOG routing support: parse `?o=<workspaceId>` from `httpPath` and inject `x-databricks-org-id` on Thrift, telemetry, and feature-flag requests. Expose `customHeaders` on `ConnectionOptions` for caller-supplied headers (databricks/databricks-sql-nodejs#391 by @samikshya-db)

CONTRIBUTING.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,19 @@ npm run lint:fix
107107
npm run type-check
108108
```
109109

110+
## Dependency Pins
111+
112+
A few entries in `package.json` are pinned more tightly than usual. Don't relax these without understanding why.
113+
114+
- **`typescript: "5.5.4"`** (exact, no caret). This pin has both a floor and a ceiling:
115+
- Floor (TS >= 5.0) is required because `uuid@11`'s shipped `.d.ts` uses `export type * from './types.js'`, a TS 5.0+ feature.
116+
- Ceiling (TS < 5.6) is required because TS 5.6 changed how `@types/node`'s generic `Buffer<TArrayBuffer extends ArrayBufferLike>` declarations get emitted into our published `dist/*.d.ts`. Allowing TS 5.6+ would leak `Buffer<ArrayBufferLike>` into the published types, which fails to compile for consumers on stale `@types/node`.
117+
- If you bump TS, run `npm run build` and `git diff dist/` and verify no `Buffer<...>` generics appear in any `.d.ts`. If they do, you need to either roll back or also bump `@types/node` consumer expectations (a customer-facing change).
118+
119+
- **`overrides.uuid: "^11.1.1"`**. Forces `thrift@0.23.0`'s declared `uuid: ^13.0.0` (ESM-only) down to v11 (dual ESM+CJS). Without this override, the driver's CJS-compiled `dist/` would crash on `require('uuid')` at runtime. Remove this override only after migrating the driver to ESM or when `thrift` drops the uuid dep.
120+
121+
- **`package-lock.json` is pinned to `lockfileVersion: 2`.** Modern npm writes v3 by default. To regenerate the lockfile, run `npm install --lockfile-version=2` so CI's lint step doesn't reject your PR. v2 is kept for compat with older toolchains; revisit when the team is ready to drop them.
122+
110123
## Pull Request Process
111124

112125
1. Update the [CHANGELOG](CHANGELOG.md) with details of your changes, if applicable.

lib/connection/auth/tokenProvider/FederationProvider.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,9 @@ export default class FederationProvider implements ITokenProvider {
166166
// node-fetch ships its own AbortSignal shim that differs slightly
167167
// from the native AbortSignal (subtle `this`-typing mismatch on
168168
// onabort handler). TS 4 didn't catch this; TS 5+ does. The two
169-
// are runtime-compatible, so cast through any.
170-
signal: controller.signal as any,
169+
// are runtime-compatible, so cast through `unknown` (rather than
170+
// `any`) to keep the assertion narrow.
171+
signal: controller.signal as unknown as import('node-fetch').RequestInit['signal'],
171172
});
172173

173174
if (!response.ok) {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@databricks/sql",
3-
"version": "1.15.0",
3+
"version": "2.0.0",
44
"description": "Driver for connection to Databricks SQL via Thrift API.",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

tests/e2e/.mocharc.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,4 @@ const argvSpecs = process.argv.slice(4);
77
module.exports = {
88
spec: argvSpecs.length > 0 ? argvSpecs : allSpecs,
99
timeout: '300000',
10-
// Force the CommonJS loader path so .ts specs go through ts-node's
11-
// require hook. See tests/unit/.mocharc.js for context.
12-
require: ['ts-node/register'],
1310
};

tests/unit/.mocharc.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,4 @@ const argvSpecs = process.argv.slice(4);
66

77
module.exports = {
88
spec: argvSpecs.length > 0 ? argvSpecs : allSpecs,
9-
// Force the CommonJS loader path so .ts specs go through ts-node's
10-
// require hook. Mocha 10.5+ otherwise picks the ESM import() path
11-
// for .ts files on some Node versions (notably Node 22+), which
12-
// bypasses ts-node/register and breaks tests that rely on CJS
13-
// globals like `__dirname` and `require`.
14-
require: ['ts-node/register'],
159
};

tests/unit/connection/auth/DatabricksOAuth/AuthorizationCode.test.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,10 @@ function prepareTestInstances(options: Partial<AuthorizationCodeOptions>) {
9898
return httpServer;
9999
});
100100

101-
// Cast: createHttpServer's return type (OAuthCallbackServerStub) intentionally
102-
// omits some http.Server typing (e.g. Symbol.asyncDispose, listen overloads with
103-
// exact backlog typing). Relaxing the assignment keeps the stub minimal without
104-
// having to fully mirror the http.Server interface.
105-
authCode['createHttpServer'] = createHttpServer as any;
101+
// OAuthCallbackServerStub intentionally omits some http.Server typing
102+
// (e.g. Symbol.asyncDispose, listen overloads with exact backlog typing).
103+
// Cast through `unknown` to keep the assertion narrow rather than `any`.
104+
authCode['createHttpServer'] = createHttpServer as unknown as (typeof authCode)['createHttpServer'];
106105

107106
openAuthUrl.callsFake(async (authUrl) => {
108107
const params = JSON.parse(authUrl);

tests/unit/result/ArrowResultConverter.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@ const sampleArrowBatch = [
5757
// Resolve from CWD (always the repo root when mocha runs) rather than
5858
// __dirname. Node 22+'s ESM auto-detection loads .ts specs as ES modules,
5959
// where CJS globals like __dirname are unavailable.
60+
// Loud check for the CWD assumption: this file reads stub fixtures at
61+
// import time, so a wrong CWD must fail clearly rather than producing
62+
// an opaque ENOENT.
63+
if (!fs.existsSync('package.json')) {
64+
throw new Error(
65+
`Expected mocha to be invoked from repo root; CWD=${process.cwd()} has no package.json`,
66+
);
67+
}
6068
const ARROW_STUBS_DIR = path.resolve('tests/unit/result/.stubs');
6169
const arrowBatchAllNulls = [
6270
fs.readFileSync(path.join(ARROW_STUBS_DIR, 'arrowSchemaAllNulls.arrow')),

0 commit comments

Comments
 (0)