2.0.0: breaking security bump — Node >=20, thrift 0.23, uuid 11, lz4→lz4-napi (0 OSV findings)#390
Merged
Merged
Conversation
This was referenced May 27, 2026
Closed
|
Thanks for your contribution! To satisfy the DCO policy in our contributing guide every commit message must include a sign-off message. One or more of your commits is missing this message. You can reword previous commit messages with an interactive rebase ( |
da4c50c to
439de47
Compare
b5b46b2 to
f4b11d3
Compare
… Node 24+ The previous commit added `node-option: [no-experimental-strip-types]`, but that flag doesn't exist before Node 22.6 — it's a "bad option" on Node 20, crashing the test process at startup and breaking a version that previously passed. `require: ts-node/register` alone is sufficient and version-agnostic: it registers ts-node's CommonJS require-hook so `.ts` resolves through ts-node on every supported Node, bypassing Node 24+'s built-in ESM strip-types path (whose strip-only mode rejects TS parameter properties). Verified locally: 34-test OAuth spec (uses parameter properties) passes on both Node 20 and Node 24 with require-only. Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
…t() path require:ts-node/register alone was insufficient: mocha loads some specs (e.g. tests/unit/kernel/execution.test.ts) via import() (ESM), not require (CJS). On Node 24+ those ESM-loaded .ts files are grabbed by Node's built-in --experimental-strip-types, whose strip-only mode rejects TS parameter properties. Adding `loader: ts-node/esm` covers the import() path; the existing `require: ts-node/register` covers the require() path. Verified locally on BOTH Node 20 and Node 24: the kernel spec (ESM-loaded, uses parameter properties) and the OAuth spec (CJS-loaded) both pass — 102 passing on each. No version-specific node flags (which would crash Node < 22.6). Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
… diagnosis Overrides review (per "why override instead of bumping the parent?"): main's dependency tree already resolves basic-ftp (5.3.1), @75lb/deep-merge (1.1.4), ip-address (10.2.0), and form-data (4.0.6) to PATCHED versions via their parents (get-uri, table-layout, socks, node-fetch types) — verified main's lock has 0 OSV findings with no overrides at all. So those four overrides were redundant. Removed them. The minimal necessary override set is 3, each with a specific reason: - uuid ^11.1.1 — thrift@0.23 declares uuid ^13 (ESM-only, breaks require()) - ws ^8.18.0 — thrift@0.23 pulls ws ^5.2.3 (vulnerable; <8.17.1) - serialize-javascript ^7.0.5 — dev; only patched line, needs Node >=20 Lock unchanged by the trim (the 4 removed overrides matched default resolution), OSV still 0 findings. Also set fail-fast:false on the unit-test matrix so each Node version reports independently — the lz4 install failure needs per-version signal (lz4@0.6.5 is a 2021 native addon with no prebuilds; suspect it fails to build on Node 22+, which main never tested — main only ran [14,16,18,20]). Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
…kfile The previous commit trimmed overrides to 3 but couldn't regenerate the lockfile to match (local npm proxy was failing tarball fetches), leaving package.json out of sync with package-lock.json → CI `npm ci` failed with EUSAGE "Missing: ip-address@9.0.5 from lock file". Also, the trim was partly wrong on the merits: ip-address's CVE fix (GHSA-v2v4-37r5-5v8g) is only in 10.1.1, but its parent `socks` caps it at `^9.0.5` — so without the override npm resolves the vulnerable 9.x. That override is genuinely required (parent won't allow the patched major), which is exactly when an override is the right tool. Restores the OSV-verified 7-override set matching the committed lock. `npm ci` clean, osv-scanner 0 findings. The fail-fast:false and ts-node strip-types fixes from earlier commits remain. Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
…patible)
Root cause of the Node 22+ CI failures: `lz4@0.6.5` (2021, unmaintained) is
a node-gyp native addon with NO prebuilt binaries. It fails to compile on
Node 22+, gets silently skipped as an optional dep, then tests that
require('lz4') crash with "Cannot find module 'lz4'". Node 20 passed; 22/24/26
failed — confirmed via fail-fast:false per-version run.
Replaces it with `lz4-napi@2.9.0` (maintained, napi-rs, ships prebuilds ->
no local toolchain build, works on all Node versions). Verified locally that
lz4-napi's compressFrameSync/decompressFrameSync are byte-compatible with the
LZ4 *frame* format (magic 0x184D2204) the old package used and the Databricks
server sends — round-trip and cross-decode both directions, incl. large
buffers. lib/utils/lz4.ts now wraps lz4-napi behind the same { encode, decode }
codec, so call sites are unchanged and the load-failure-tolerant contract is
kept. Also fixes #293 (deprecated Buffer() warning + xxhash build-resolution
error, both from the old lz4 package).
DIAGNOSTIC (this commit): CI temporarily uses `npm install` instead of
`npm ci` so the JFrog registry resolves lz4-napi + its @lz4-napi/* platform
packages (the dev npm proxy doesn't mirror those scoped packages, so the lock
couldn't be generated locally). If CI resolves them, I'll pin a proper lock
and restore `npm ci`.
Co-authored-by: Isaac
Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
The lz4-napi swap CI run proved green on all Node versions (unit + e2e 20/22/24/26), confirming the maintained fork resolves and decodes LZ4 frames correctly where the old node-gyp `lz4` addon failed to build on Node 22+. Finalize #390: - package-lock.json: regenerate against the dev proxy so the lz4-napi dependency tree is fully pinned (lz4-napi + 13 @antoniomuso/* platform packages + @node-rs/helper + @napi-rs/triples), with resolved: URLs the setup-jfrog action rewrites to JFrog. lockfileVersion stays 2. This makes the lock npm-ci-valid (the earlier stub was incomplete because @antoniomuso/* wasn't resolved). - main.yml: revert the diagnostic `npm install` back to `npm ci` in all three jobs (lint / unit-test / e2e-test) now that the lock is complete. - package.json: prettier — use the literal em-dash in the prepack message. Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
From the Code Review Squad pass on #390: - F1 (HIGH): package-lock.json — rewrite the 16 lz4-napi tree entries from the internal npm-proxy.dev.databricks.com back to registry.npmjs.org, matching the ~555 other lock entries so external forks/contributors can `npm ci`. CI's setup-jfrog step still rewrites npmjs.org → JFrog at install time. Integrity hashes are content-based, so the host swap is safe. - F2 (test): add a real, unmocked frame-compat suite (tests/unit/utils/lz4.test.ts) exercising the driver's codec against the actual lz4-napi — decodes a golden LZ4 frame produced by the independent `lz4` CLI (proving cross-encoder frame compat, not just self round-trip), plus binary round-trips incl. >single-block payloads. Runs on every Node version (import-based, no CJS-only skip). - F4 (HIGH): ArrowResultHandler / CloudFetchResultHandler error text said module `lz4` not installed — updated to `lz4-napi` so it no longer misdirects users to the removed package. - F6: README requirement Node.js 14 → 20, matching engines.node >=20. - F7 (perf): lz4-napi frame APIs already return owned Buffers; drop the redundant Buffer.from copy on the CloudFetch decode hot path. - F10: remove stale devDependency @types/uuid (uuid 11 is self-typed, unreferenced). F5 (matrix Node 26) is not applicable — Node 26 has GA'd (26.5.0 resolved and both unit+e2e legs passed), so the leg is real, not a permanently-red phantom. Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
Follow-up to N1 (devils-advocate, conf 85): the `is available` case asserted getLZ4() is always defined, which tests the environment rather than the code and breaks the module's deliberately-optional contract. lz4-napi ships prebuilds for mainstream platforms but not every arch (linux-ppc64le/s390x/…), and `npm ci --omit=optional` also yields undefined — on any of those the whole unit run would fail. Move the availability check into a `before()` that `this.skip()`s (with a visible console.warn) when the binding can't load, and drop the unconditional assertion. The frame-compat cases now test the codec when present and degrade gracefully when absent. CI's linux-x64 matrix always has a prebuild, so the golden-frame and round-trip coverage still runs there on every push. Co-authored-by: Isaac Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
|
Thanks for your contribution! To satisfy the DCO policy in our contributing guide every commit message must include a sign-off message. One or more of your commits is missing this message. You can reword previous commit messages with an interactive rebase ( |
Signed-off-by: Vikrant Puppala <vikrant.puppala@databricks.com>
This was referenced Jul 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Breaking security release (2.0.0) — completes the vulnerability cleanup, taking the lockfile to 0 OSV-Scanner findings. The non-breaking #446 (1.17.0) shipped first and cleared the criticals without breaking changes; this release rebases onto main and finishes the job with the breaking version-floor bumps.
Breaking changes
engines.node>=14→>=20>=20is also the floor for the patchedserialize-javascript(dev) and clears the kernel backend's Node 18 requirement.thrift^0.16.0→^0.23.0uuid^9.0.0→^11.1.1dist/stillrequire('uuid')unchanged. Anoverridespin holds thrift's transitive uuid at 11 (uuid 13 is ESM-only → would breakrequire()).lz4→lz4-napilz4@^0.6.5→lz4-napi@^2.9.0lz4package (unmaintained since 2021) is a node-gyp native addon with no prebuilt binaries — it fails to compile on Node 22+, so it was silently skipped as an optional dep and LZ4-compressed CloudFetch/Arrow results could not be decoded.lz4-napiis maintained, ships napi-rs prebuilds for every supported platform/Node version, and itscompressFrameSync/decompressFrameSyncare byte-compatible with the LZ4 frame format (magic0x184D2204) the server sends — verified by round-trip and cross-decode both directions, and confirmed green by the e2e matrix below.Supporting changes
typescriptpinned to exact 5.5.4 — uuid@11's.d.tsusesexport type(needs TS 5+);<5.6avoids@types/nodeBuffer-generic emit changing our published.d.ts.serialize-javascriptoverride^7.0.5(its only patched line requires Node ≥20 — now satisfied by the floor bump).@types/node-fetch^2.6.13; dropped@types/lz4(lz4-napi ships its own types).OAuth.tstest stub: castSymbol.asyncDisposethroughany(ES2018 target predates the symbol; Node 20+ runtime provides it).tests/unit+tests/e2e):require: ts-node/register+loader: ts-node/esmso Node 24+'s native--experimental-strip-typesdoesn't intercept.tsspecs ahead of ts-node (it can't handle TS parameter properties).[20, 22, 24, 26]for both unit and e2e (fail-fast: falseso a version-specific regression can't mask the others);setup-jfrogrewrites lockfileresolved:URLs to the JFrog mirror so protected runners cannpm ci.Net security result
OSV-Scanner v2.3.8 against the regenerated lockfile: No issues found (0 CRITICAL / 0 HIGH / 0 MED / 0 LOW).
Verification
npm run buildclean (TS 5.5.4)eslint+prettier --checkcleanosv-scanner= No issues found[20, 22, 24, 26]matrix (lint / unit-test / e2e-test / coverage / Kernel E2E / DCO)Closes #370
Closes #293
This pull request was AI-assisted by Isaac.