Skip to content

feat(db2): add an IBM Db2 LUW provider over db2-node - #1238

Merged
cevheri merged 49 commits into
mainfrom
feat/786-db2-provider
Oct 3, 2026
Merged

cevheri merged 49 commits into
mainfrom
feat/786-db2-provider

Conversation

@cevheri

@cevheri cevheri commented Oct 3, 2026

Copy link
Copy Markdown
Member

Adds IBM Db2 LUW as a provider (type id db2) over the npm driver db2-node 1.0.22, a native Rust DRDA client that needs no IBM client install and ships Linux arm64 and musl binaries.

Closes #786. Supersedes #787, which was written against the provider interface main has since replaced; thanks to @nycjay, much of the dialect and catalog know-how here comes from that PR.

What v1 does

  • Connects with host, port, database, user and password, or a pasted db2:// URL. TLS supports verify-full and verify-ca (verify-ca needs a CA certificate).
  • Refuses to send a password over a connection without TLS unless the connection sets allowInsecureAuth, because the driver silently falls back to sending it in cleartext.
  • Object browser over schemas: tables, views, MQTs, aliases, sequences, modules, procedures, functions and triggers, with columns, keys, indexes and definition text.
  • Runs queries with server-side paging and result metadata.
  • RUNSTATS and REORG on tables through ADMIN_CMD, from the operations page.
  • Agent and MCP take the Oracle posture: plan mode and inspect_schema only.
  • Every channel ships db2-node pruned to the one addon it loads, with the crate notices in THIRD_PARTY_NOTICES.txt. winget and Chocolatey declare the VC++ runtime the Windows addon needs.

Left out on purpose

Db2 for z/OS and IBM i, EXPLAIN, transactions and sandbox, cancel and streaming, read-only query, inline row edit, data import, Create Table, object edit (#789), monitoring beyond version, counts and the table list, and column-change DDL in schema diff (the schema diff limits a Db2 connection meets are backlog D145).

Known driver issues

db2-node 1.0.22 has defects we cannot fix from the provider, listed as K1 to K22 in docs/providers/db2.md and reported upstream in gurungabit/db2-node#12. The ones that matter most: non-ASCII text is decoded as EBCDIC, BIGINT loses precision, LOB fetches fail, CALL fails, and a bound DECIMAL that does not fit is stored as a wrong value without an error.
We forked the driver to libredb/database-provider-db2-node and will take the fixes over if upstream does not respond.

What the provider contains:

  • Parameters are normalised: an unsafe bigint, a Date, an array or an object is refused before the driver sees it (a bigint aborts the process).
  • Leading comments are stripped, the negative changed-row count is read as 0.
  • No catalog query reads a LOB, definitions are read in chunks, catalog names are read as HEX on UTF-8 databases.
  • The table preview names and casts its columns instead of SELECT *, and results with a lossy column or a duplicate column name carry a warning.
  • Maintenance wraps its call in a compound block, and runs on tables only.
  • Every write path the UI offers (inline edit, import, Create Table) is off, so a garbled read cannot be written back.

Two shared changes come with this: data import now refuses an engine that declares nothing to write into, and providers can declare a preview projection and the kinds a maintenance operation runs on.

Verification

  • Every required gate locally: format, lint, typecheck, knip, the four drift guards, the full suite (763 files), build, build:lib with attw, and 100% line coverage.
  • Live against Db2 12.1.0.0, plain and TLS, with a hand-run script (tests/live/) that checks the provider and probes every known issue.
  • In the browser: connect from the form and from a pasted URL, the TLS opt-in refusal, the object tree including non-ASCII names, describe, view source, paging, an error, RUNSTATS and REORG, and that edit, import and Create Table are not offered.
  • The Docker amd64 image against the same server through the API, with only the linux-x64-gnu addon in the image.

Not verified: the arm64 runtime, the Windows VC++ runtime on a clean machine, Db2 11.5 through the app (the driver spike ran on 11.5.9.0), the standalone server.js outside Docker, and e2e/login.spec.ts with the 21st showcase entry.

cevheri added 30 commits October 3, 2026 05:25
Adds db2 to DatabaseType and wires the factory, compatibility maps, UI config,
icon, showcase, connection form and modal, db2:// parsing with TLS query
parameters, seed types, SQL grammar, value literals (BX'..' binary hex),
fence tags, result export and the migration generator (Oracle and Db2 share a
no DROP ... IF EXISTS set). The provider itself is a stub that the next
commit replaces.
The provider doc covers the connection, TLS on both ends, the db2-node
1.0.22 known issues with the upstream report, capabilities, the object
surface, query execution, maintenance, monitoring, agent and MCP
posture, the Object edit (#789) absence, schema diff, packaging and
testing. The providers index gains the Db2 LUW row and its compose
service.
READMEs and their seven translations, Docker Hub, the marketplace and
catalog listings, the desktop and Linux package metadata and CLAUDE.md
now name Db2 LUW and count the twenty external engines
EXTERNAL_DATABASE_TYPES holds.
The chart description, keywords and README name the new engine, which
costs a chart version under #167; the operator mirror follows byte for
byte and the bundle is regenerated with make -C operator bundle.
Type-id counts move from twenty to twenty-one where they count the
DatabaseType union, the grammar tables record DB2_GRAMMAR, the provider
guide fixes its stale form and union examples, and the backlog gains
D140 to D144 for what the first Db2 version leaves out.
Catalog text is read as hex chunks rather than a CAST, a default past
254 bytes is left out, maintenance takes materialized query tables and
refuses views by name, and the integrity warning, the no-row DML count
and the code page rule are described as the code implements them.
db2-node carries eight prebuilt N-API addons in one package, and file tracing copies all of them into the standalone output. Externalize it for Next and tsup, prune the traced tree to the loadable addon in every image, the standalone payload (scripts/lib/prune-db2-node.sh, both libcs on Linux) and the AppImage, and load-probe the survivor in each Dockerfile (the alpine-slim runner), the payload smoke, the Windows zip and the engine smoke.

The addons statically link 62 Rust crates whose notices the npm tarball does not carry. THIRD_PARTY_NOTICES.txt, written by scripts/generate-db2-node-notices.sh from the upstream Cargo.lock at gitHead 68264e06, now travels in every image and payload, and docs/THIRD_PARTY_LICENSES.md summarises it.
db2-node's win32-x64-msvc addon imports VCRUNTIME140.dll, which a clean Windows machine lacks. The winget installer manifest now depends on Microsoft.VCRedist.2015+.x64 and the Chocolatey package on vcredist140, and the "nothing else to install" copy says what is pulled in and what a Scoop user installs by hand.
The db2 compose service runs IBM's Db2 Community image unprivileged, with only IPC_LOCK and IPC_OWNER, and loads the object-browser fixture once through /var/custom, which the image executes on every start; the SQL itself is mounted outside that directory.

tests/live/db2-known-issues.ts reports, one line each, whether the seventeen db2-node defects the provider contains are still present. tests/live/db2-live-check.ts drives Db2Provider over connect, catalog, source, paging, maintenance, the bigint refusal and verify-ca, and exits non-zero on any failure.
…eration runs on

A provider may now declare how the object browser's preview reads each
column, so an engine whose driver misreads some column types previews a
named projection rather than SELECT *. A maintenance operation spec may
name the kinds it runs on, and both row menus offer it on those kinds only.
Both are needed by the Db2 provider (#786).
The dialog refuses up front when no kind accepts row writes and no
create-table is declared, hides New Table where create-table is not
declared, and generateImportSQL refuses the same targets on its own (#786).
Db2 refuses TEXT (SQL0204N, measured on 12.1.0.0) (#786).
…s sent

Without TLS db2-node 1.0.22 sends the password in cleartext whatever
security mechanism is asked for. A new allowInsecureAuth field records the
consent; the form draws it as a warning checkbox while SSL Mode is disable,
the seed schema accepts it and the provider cache key frames it. A db2://
?ssl=true or ?security=SSL now asks for verified TLS (#786).
Replaces the registration stub. Schemas and nine kinds read from SYSCAT
with every name read as HEX and decoded, no LOB selected, definitions read
one chunk per row; RUNSTATS and REORG inside a compound block on tables and
MQTs only; bigint parameters checked before the driver; leading comments
stripped; TLS that fails closed and a tunnel never dialled around; a
projected preview and an integrity warning for the column types the driver
misreads; neutral monitoring (#786).
… reachable

The object tree's Run Statistics and Reorganize Table items deep-link to
the admin Operations list, whose per-table controls render on a row of
getTableStats. Db2 answered an empty list, so the page said it had no
row for the table and neither command could be run from the UI.

getTableStats now reads every user table and materialized query table
from SYSCAT.TABLES, names as HEX for K1, with CARD as the row count and
no size. A refused read is thrown, mapped, and lands on that panel.
@gitguardian

gitguardian Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

️✅ There are no secrets present in this pull request anymore.

If these secrets were true positive and are still valid, we highly recommend you to revoke them.
While these secrets were previously flagged, we no longer have a reference to the
specific commits where they were detected. Once a secret has been leaked into a git
repository, you should consider it compromised, even if it was deleted immediately.
Find here more information about risks.


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

@socket-security

socket-security Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​db2-node@​1.0.227510010095100

View full report

@codecov

codecov Bot commented Oct 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

… Windows

The CA file tests built the expected path with a literal "/" while the
provider uses path.join, and the seam guard compared a relative path with
native separators against a POSIX one. Assert the exact tmpdir-based paths
instead, normalise the seam guard the way the other boundary guards do, and
move the 0600/0700 mode check into a POSIX-only test, since Node on Windows
reports 0o666 for any writable file.
The mode bits do not apply there; the per-user ACL on the temp directory
under the user profile keeps it private.
Brings in the Neo4j provider (#1239), the dialect and dialect editor
registries (#1241, #1243), the node HTTP transport (#1242), host-box
addresses and credential warnings (#1244) and the Oracle UROWID fix.

Adapted to main:
- engine counts re-derived for 21 external engines (22 type-ids) in
  every listing, README, chart, operator CSV and package description,
  naming both Db2 LUW and Neo4j; showcase ranks renumbered
- Db2 needs no registry entry: it declares no queryDialect and opens
  sql tabs; the dialect golden file gains its db2 record
- census counts, fingerprint line references and field-copy tests
  updated for both providers
- Db2 backlog entries D140-D145 renumbered to D145-D150 behind
  Neo4j's D140-D144
- chart stays 0.1.74 (unreleased) with both changes in its metadata;
  operator bundle regenerated
…n census

The Azure short description and DOCKERHUB.md went over their byte limits
once both Db2 LUW and Neo4j were named; each is trimmed back inside.

engine-support.test.ts ended the DatabaseType declaration at the first
line-end semicolon, which the neo4j arm's comment carries, so with the
[a-z0-9]+ id class the factory scan found neo4j while the union parse
never reached it. The declaration now ends at the semicolon after a
quoted arm. On main the [a-z]+ class dropped neo4j from both sides, so
the parity test passed without checking it.
0.1.74 was released with Neo4j while this branch was open, so the Db2
LUW metadata change needs its own chart version (#167).
…ro padding

Db2 LUW is the twenty-second showcase entry and wrapped the engine list into a fourth row at 1366x768, which scrolled the page by 7px and failed the no-scroll check in e2e/login.spec.ts.
The hero column's vertical padding goes from 48px to 40px, which leaves 9px of slack at 1366x768 and 25px at 1280x800 with four rows at both.
A narrower column gap was measured and rejected: 8px restores three rows but leaves 38px on the last one, so the next entry would reopen the overflow.
@sonarqubecloud

sonarqubecloud Bot commented Oct 3, 2026

Copy link
Copy Markdown

@cevheri
cevheri merged commit 224e798 into main Oct 3, 2026
39 checks passed
cevheri added a commit that referenced this pull request Oct 3, 2026
The census holds one row per shipped type-id, so rebasing onto main with
the Db2 provider (#1238) made the record miss a member. Db2 offers analyze
and optimize per row, on both tabs and both row menus, and declares no
operation outside MaintenanceType: 11 of 22 type-ids now offer per-row
controls on the tabs and 10 on the row menus.
cevheri added a commit that referenced this pull request Oct 3, 2026
…he engine principal (#1246)

* test(maintenance): pin every shipped provider's per-row maintenance controls

* feat(maintenance): declare typed-target, preview and the engine principal on the provider contract

* test(maintenance): hold a typed-target confirmation to a per-row control

* feat(audit): carry the engine principal as engine_user on the audit line

* feat(maintenance): write the engine principal on every maintenance audit row

* feat(maintenance): serve a per-object preview at POST /api/db/maintenance/preview

* feat(monitoring): read a maintenance preview from the monitoring hook

* feat(maintenance): the typed-target and preview dialog for a per-row operation

* feat(operations): offer declared per-row operations with their typed target and preview

* feat(monitoring): offer declared per-row operations on the Tables tab

* feat(object-tree): offer declared per-row operations in the row menu

* feat(schema-explorer): offer declared per-row operations in the mobile row menu

* docs: document typed-target, the maintenance preview and engine_user

* test(maintenance): drop unused mock parameters from the per-row surface tests

* docs(security): re-derive the role-denial sites from the source

The table and its count missed the two account-administration routes,
and the preview route was added on top of that stale base. Seven
handler sites call auditRoleDenial, plus the proxy; a unit test now
derives the set from src/app and holds the table and the numerals to it.

Fixes review findings SC-1 and R1.

* fix(maintenance): answer no preview for an operation no row offers

The preview route served a preview for a spec declaring preview: true
with both placements false, which no surface draws. It now answers the
no-preview 400 unless the per-row placement is offered, and the
capability test holds every shipped spec that declares a preview to
perEntity: true and a provider that implements previewMaintenance.

Fixes review finding B1.

* fix(maintenance): key preview facts so a repeated label draws cleanly

Facts were keyed by label alone, and a preview that names each vector
field under one label logged a duplicate-key warning. Each fact is now
keyed by its label and how many facts before it share that label.

Fixes review finding B2.

* fix(maintenance): answer 400 to a body that is not a JSON object

Both maintenance routes destructured the parsed body directly, so null
answered 500 with the raw TypeError message and text that is not JSON
answered 500 as well. A body that is not a JSON object now answers 400
"Invalid request body" before any provider is opened, on the existing
route and on the preview route that copies its checks.

Fixes review finding B3.

* docs(rate-limit): re-count the query bucket's call sites

The comment said seventeen direct call sites while its own grep already
answered twenty-one on main, and the preview route made it twenty-two.
It now names all twenty-two files, the two that hold two call sites
each, and the thirty-two route files in total.

Fixes review findings B4 and R2.

* test(exports): say that the packed-tarball check is not tracked

The docblock described a tarball type check as if the repository ran
it. It was a one-off pre-merge measurement in a gitignored folder, so
the docblock now says what this file covers and what it does not.

Addresses review findings SC-2 and R3; a tracked tarball check in CI
is deferred.

* docs(maintenance): one sentence per line, and name the failed row

Split two sentences that shared a line, and call the engine_user rows
completed, failed (success: false) and thrown, since "refused" read as
the route's own 400 refusals, which write no maintenance row.

Fixes review findings R4 and R5.

* test(maintenance): spread the real auth module in the preview route test

The new route test copied the five-key auth stub that BACKLOG D85 records as debt, which also missed two of
the module's seven exports. It now spreads the real module and replaces getSession alone, the form D85
prefers, and D85 is re-measured: 40 files mock the module, eight of them by spreading it.

* test(maintenance): pin neo4j's per-row maintenance surface in the census

The census holds one row per shipped type-id, so rebasing onto main with
the Neo4j provider (#1239) made the record miss a member: a type error and
two failing cases. Neo4j offers no per-row maintenance control and declares
no extension of spec 3.11, so its row is the empty one.

* test(maintenance): pin db2 in the census of per-row maintenance controls

The census holds one row per shipped type-id, so rebasing onto main with
the Db2 provider (#1238) made the record miss a member. Db2 offers analyze
and optimize per row, on both tabs and both row menus, and declares no
operation outside MaintenanceType: 11 of 22 type-ids now offer per-row
controls on the tabs and 10 on the row menus.

* fix(maintenance): hold a declared per-row operation to the kinds its spec names

Main gained MaintenanceOperationSpec.kinds with the Db2 provider (#786):
a per-row control is offered only on the object kinds its operation names.
The two row menus pass the row kind for analyze and vacuum, and now pass
it for the declared operations outside MaintenanceType as well, so a
declared operation that names its kinds is not offered on a view. The
Operations and Tables tabs list tables and name no kind, as before.
cevheri added a commit that referenced this pull request Oct 5, 2026
…d three security fixes (#1531)

Carries eight connection types for seven engines: etcd (#1228), IBM Db2 LUW
(#1238), Neo4j with the Graph tab (#1239, #1289), Qdrant (#1270), Milvus
(#1283), InfluxDB and InfluxDB 3 (#1309) and Oxia (#1310). Also CapRover and
DigitalOcean discovery (#1502, #1378, #1528), launch sign-in for hosting
platforms (#1516), and any number of local accounts with passkeys (#1122,
#1195).

Three security fixes: the OIDC state cookie is no longer accepted as a
session (#1380), a non-admin role's DuckDB connection opens with file and
network access off (#1519), and SQLite, DuckDB and LibreDB connections refuse
Studio's own storage and credential files, with SQLite open to admins only in
the editor, agent runs and MCP alike (#1523, #1529). Chart 0.1.78 is flagged
containsSecurityUpdates, and its description calls Trino by its own name, the
rename #1158 left for this bump.
@cevheri
cevheri deleted the feat/786-db2-provider branch October 9, 2026 00:45
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.

[FEATURE] Add IBM Db2 LUW provider

1 participant