Skip to content

Merge changes from internal repo - 2026-08-14 - #319

Merged
linjun-he-sap merged 13 commits into
masterfrom
mirroring/2.29.6
Aug 14, 2026
Merged

Merge changes from internal repo - 2026-08-14#319
linjun-he-sap merged 13 commits into
masterfrom
mirroring/2.29.6

Conversation

@linjun-he-sap

Copy link
Copy Markdown
Contributor

No description provided.

linjun-he-sap and others added 13 commits July 7, 2026 13:53
- add `diff: 8.0.4` to overrides in package.json; pulls in the patched
  diff release in place of the 7.0.0 version that mocha 11.7.6 transitively
  requests via `^7.0.0`
- regenerate package-lock.json via `npm install`; `npm audit` now reports 0 vulnerabilities

- vulnerability: GHSA-73rr-hh4g-fpgx ("jsdiff has a Denial of Service vulnerability in parsePatch
  and applyPatch"). diff versions >=6.0.0 <8.0.3 enter an infinite loop / O(n^3) ReDoS when parsing
  patches whose filename or patch headers contain `\r`, `
`, or `
`, exhausting memory or CPU. Fixed
  upstream in diff 8.0.3; pinned here to the latest 8.x patch (8.0.4)
- affected dependency: diff is a dev-only transitive dependency pulled in exclusively by mocha (used
  for pretty-printing assertion diffs in failing test output). it is not shipped to consumers of `hdb`
  and not reachable with attacker-controlled input in our test setup, so real-world exposure is minimal
  -- the override silences the npm audit alert and aligns with our existing pattern of pinning patched
  majors via `overrides` (see safer-buffer, serialize-javascript)
- mocha 11.7.6 (latest stable) still declares `diff: ^7.0.0`; the fix has only landed in mocha 12 betas,
  which we do not adopt. The override is the appropriate stable path until a fixed mocha stable releases
- change readable handler to loop read() until null so buffered
  chunks are not stranded when Node 26 emits one readable event
  per push instead of coalescing multiple pushes
- switch assertion from 'finish' to 'end' event so it runs after
  the readable side has fully drained, not just after writable done
- convert nearby var to let/const per project style

Background: how a Transform stream signals completion
=====================================================

A Transform stream is both a Writable (input side) and a Readable
(output side). Each side has its own "done" event:

  - 'finish' — writable side done: no more write() calls, and all
    buffered writes have been processed by _transform / _flush.
  - 'end'    — readable side done: consumer has read every chunk
    the stream will ever produce, and the buffer is now empty.

'finish' always fires first; 'end' fires only after the readable
buffer is fully drained by the consumer.

  Producer side                              Consumer side
  (writable)                                 (readable)
  -----------                                ----------

  write(0) --> _transform --push('[0')-->  +--------+
                                           | buffer |
  write(1) --> _transform --push(',1')-->  |  [0    |
                                           |  ,1    |
  write(2) --> _transform --push(',2')-->  |  ,2    |
                                           |  ]     |
  end()    --> _flush     --push( ']')-->  +--------+
                   |                            |
                   v                            |
              +--------+                        |
              | finish |  <-- writable done     |
              +--------+      (no more input)   |
                                                |
                       consumer drains buffer   |
                       via read() loop          |
                                                v
                                           +----------+
                                           | buffer   |
                                           | drained  |
                                           | + EOF    |
                                           +----------+
                                                |
                                                v
                                           +--------+
                                           |  end   |  <-- readable done
                                           +--------+

How 'readable' events are scheduled: Node < 26 vs Node 26
---------------------------------------------------------

Node < 26 — pushes coalesce into one 'readable':

  push('[0')  ┐
  push(',1')  |
  push(',2')  |  all 4 pushes land in buffer
  push(']')   ┘  before microtasks flush
                 |
                 v
      +----------------------+
      | ONE 'readable' fires |
      +----------------------+
                 |
                 v
      read() --> "[0,1,2]"    (all 4 concatenated)
      read() --> null         (buffer empty)
                 |
                 v
             'finish'          data == "[0,1,2]"  ✓

  The buggy single-read-per-event handler happened to work
  because one read() call retrieved everything.

Node 26 — each push tends to fire its own 'readable':

  push('[0')  --> 'readable' no.1  --> read() --> "[0"
  push(',1')  --> 'readable' no.2  --> read() --> ",1"
  push(',2')  --> 'readable' no.3  --> (queued, not yet delivered)
  push(']')   --> 'readable' no.4  --> (queued, not yet delivered)
                                             |
                                             v
                                       'finish' fires here
                                             |
                                             v
                          handler runs assertion: data == "[0,1"  ✗
                                             |
                                             v
                     (later) events no.3, no.4 deliver — too late

  Only two chunks reach the accumulator; the remaining two are
  still in the readable buffer when 'finish' fires. JSON.parse
  sees a truncated string and throws.

The fix
-------

Draining with \`while ((chunk = read()) !== null)\` empties the
buffer per event regardless of how many chunks it holds, and
asserting on 'end' waits until the readable side is fully done.
Both align with the documented stream contract and work on all
Node versions.
… to 3s

- add this.timeout(3000) to the REAL_VECTOR (dynamic length) 'should
  raise input type error' test to accommodate accumulated latency from
  6 invalid-input round-trips via async.each on far HANA cloud servers
- leave other DataType tests at Mocha's 2s default
- delete test/mocha.opts, which has been silently ignored since the
  repo upgraded to Mocha 8+ (mocha.opts was deprecated in v6, removed
  in v8; current version is 11)
- --require should was already redundant: several test files
  (lib.Writer.js, lib.Reader.js, hdb.Client.js, util.bignum.js,
  rep.part.js, acceptance/db.Authentication.js) require('should')
  directly, and once any of them runs the Object.prototype mutation
  covers the whole process
- --growl referenced growlnotify (dead since ~2016) and was removed
  from Mocha in v7; would be a hard error if the file were parsed
Co-authored-by: Michal Majewski <michal.majewski@sap.com>
- add .github/workflows/backport.yml that uses korthout/backport-action
  to auto-cherry-pick merged PRs to rel/* branches when labeled with
  `backport rel/<version>`
- fires on pull_request_target (closed, labeled); creates a backport PR
  for each matching label; conflicts leave conflict markers in the PR
  for manual resolution
- restricts label pattern to `^backport (rel/[^ ]+)$` so only rel/*
  branches can be targeted
- pin actions/checkout to df4cb1c (v6.0.3) and korthout/backport-action
  to 2e830a1 (v4.6.0) to make the audited action code immutable — a
  moved tag on pull_request_target with write permissions would
  otherwise be a supply-chain foothold
…tHub

- change runs-on from `ubuntu-latest` to `[self-hosted, solinas]`; SAP's
  internal GitHub has no GitHub-hosted runners, so `ubuntu-latest` jobs
  queue forever with no runner to pick them up
- align with the SUGAR runner label already used by integration-test.yml
* Update Client.js

* Update Connection.js

* Create ConnectOptionFlagSet1.js

* Update ConnectOption.js

* Update ConnectOptionType.js

* Update MessageType.js

* Update index.js

* Update index.js

* Update ConnectOptionFlagSet1.js

* Update Connection.js

* Update ConnectOptions.js

* Update index.js

* Update index.js

* Update db.Lifecycle.js

* Update Connection.js

* Update PartKind.js

* Update Connection.js

* Update Connection.js
* Keep space for potential client info updates

* [FIX] keep space for potential client info update segments

- fix getUpdatedPropertiesSize to compute exact wire size of the
  CLIENT_INFO part, accounting for per-field length indicators,
  8-byte alignment, PART_HEADER_LENGTH, and useCesu8 encoding
- return 0 when no properties are pending, removing the need for
  a message-type gate in getAvailableSize

* [TEST] add acceptance test for LOB exec with pending client info

- verify that setting client info between prepare and exec does not
  cause Packet size limit exceeded when writing a LOB stream

---------

Co-authored-by: Bob den Os <bob.den.os@sap.com>
@linjun-he-sap
linjun-he-sap merged commit f26df55 into master Aug 14, 2026
1 check passed
@linjun-he-sap
linjun-he-sap deleted the mirroring/2.29.6 branch August 14, 2026 17:09
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.

4 participants