Skip to content

chore(deps): clear every remaining SDK-side advisory via resolutions - #429

Merged
JosephSamirL merged 1 commit into
mainfrom
chore/dependabot-sdk-resolutions
Aug 9, 2026
Merged

chore(deps): clear every remaining SDK-side advisory via resolutions#429
JosephSamirL merged 1 commit into
mainfrom
chore/dependabot-sdk-resolutions

Conversation

@abbaseya

@abbaseya abbaseya commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Follow-up to #427. Takes the repo from 41 open advisories (11 high) to 28 (6 high) — and more
usefully, advisories reachable from packages/* go from 8 to zero. Everything still open is
inside a demo/* app, which no CI job builds or tests.

Correcting the previous PR

#427 said these remaining advisories "sit behind a parent already at its latest published version
— these need the tool replaced, not upgraded". That was wrong, and worth stating plainly because
it would have closed off the cheap fix.

Checking all 42 alerts: none can be fixed by re-resolution (#427 already harvested those), but 38
of 42 do have a patched version published upstream. It simply falls outside the range the
parent declares — which is exactly what resolutions is for. This repo already used that
mechanism 14 times (tar, nth-check, braces, path-to-regexp, …). This adds 7 more.

What changed

Seven resolutions entries, and two dead devDependencies deleted. No published package moves:
peerDependencies are byte-identical to main in all 11 packages, and no dependencies change.

Four of the advisories had no upstream fix at all. They are gone because the thing that pulled
them is gone, not because they were patched:

why it works
jsdoc^4.0.5 jsdoc 4 dropped taffydb — the only high in the SDK's own tree — and brings markdown-it 14 / linkify-it 5 with it
vue-docgen-api^4.79.2 drops vue-template-compiler (Vue 2, EOL, no fix will ever ship)
remove browserify + watchify no script in the repo references either; they were the only path to elliptic (no upstream fix) and bn.js

The rest are ordinary forced bumps: serialize-javascript >=7.0.5, diff >=8.0.3,
pug / pug-code-gen >=3.0.3, underscore >=1.13.8.

Verification at 5cb9797

  • yarn install --immutable — passes
  • yarn build at the repo root — 50 bundles, exit 0
  • yarn lint in packages/js-sdk — clean
  • yarn test:mocha across all 10 test packages — 546 passing, 0 failing
  • yarn test:browser in packages/js-sdk47 passed

The 28 that remain — a separate decision

All demo-only: react-scripts (webpack-dev-server, postcss, svgo, uuid, @tootallnate/once),
Remix (react-router, turbo-stream, vite, esbuild, estree-util-value-to-estree), wrangler
(undici). Three options, none of them "replace the tool":

  1. Force them too. This is where the original claim has some truth — react-router 6→7 under
    Remix and webpack-dev-server 4→5 under react-scripts will very likely break those apps, and
    since no CI job builds demo/, nothing would catch it until someone runs a demo.
  2. Drop demo/* from the root workspaces. Their trees leave the lockfile entirely and all 28
    disappear with nothing forced; the demos then install standalone and resolve
    @convertcom/js-sdk from npm — arguably what a demo should demonstrate. Not measured — this
    number is a projection.
  3. Dismiss them in Dependabot as dev-only, since none of it ships.

Two pre-existing issues, still not fixed here

Repo-root yarn lint is red in packages/types (src/config/index.ts, generated
src/config/types.gen.ts). Pre-existing on main, untouched here, and pass-qa only lints
packages/js-sdk so CI has never exercised it.

yarn build leaves a dirty tree. generate-rollup-config.mjs rewrites each package's source
package.json, pinning peerDependencies to the current sibling workspace versions — not just the
generated lib/package.json. That churn was stripped before committing here; it bit #427 twice.

Commit is deliberately chore(...) with no feat/fix prefix, so release-please does not cut a
release. This is tooling only.

🤖 Generated with Claude Code

Takes the repo from 41 open advisories (11 high) to 28 (6 high). More
usefully: advisories reachable from `packages/*` go from 8 to **zero**.
Everything still open is inside a `demo/*` app, which no CI job builds or
tests.

These were previously written off as needing the parent tool replaced.
That was wrong - the patched versions exist, they just fall outside the
range the parent declares, which is exactly what `resolutions` is for.
This repo already used it 14 times; this adds 7 more.

Four of them had no upstream fix at all, and are gone because the thing
that pulled them is gone:

- `jsdoc` ^4.0.5 - jsdoc 4 dropped `taffydb` (the only high in the SDK's
  own tree) and brings `markdown-it` 14 / `linkify-it` 5 with it
- `vue-docgen-api` ^4.79.2 - drops `vue-template-compiler` (Vue 2, EOL,
  no fix will ever ship)
- `browserify` + `watchify` removed from packages/js-sdk - no script in
  the repo references either, and they were the only path to `elliptic`
  (no upstream fix) and `bn.js`

The rest are straightforward forced bumps: `serialize-javascript` >=7.0.5,
`diff` >=8.0.3, `pug` / `pug-code-gen` >=3.0.3, `underscore` >=1.13.8.

Deliberately no `feat`/`fix` prefix - this is tooling only and must not
cut a release. No published package changes: `peerDependencies` are
byte-identical to `main` in all 11 packages, and no `dependencies` move.

Verified at this commit:
- `yarn install --immutable` - passes
- `yarn build` at the repo root - 50 bundles, exit 0
- `yarn lint` in packages/js-sdk - clean
- 546 mocha tests across 10 packages - passing
- 47 browser tests - passing

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@abbaseya abbaseya self-assigned this Aug 9, 2026
@abbaseya
abbaseya requested a review from JosephSamirL August 9, 2026 18:05
@sonarqubecloud

sonarqubecloud Bot commented Aug 9, 2026

Copy link
Copy Markdown

@JosephSamirL

Copy link
Copy Markdown
Contributor

Independent code review via /convert:review at 5cb979758460c9c23665e0e6ecea9dfc9cf7a107. Verdict: APPROVED — 0 blocking, 5 non-blocking. B-G4 review marker written; human approval is a separate step via /convert:approve.

The load-bearing check was whether anything left the runtime closure of a published package. It did not: all 13 packages/* declare dependencies: {} except packages/utils (murmurhash: ^2.0.1), identical at both revisions — so bucketing/rule parity, the cross-SDK oracle role, is untouched. browserify and watchify have zero references anywhere in the tracked tree outside yarn.lock.

One methodology note worth recording: seeding the dependency walk from the lockfile workspace entry gives a false result, because Yarn Berry merges devDependencies into that entry's dependencies field (visible at yarn.lock:2347). The walk was re-derived from the real manifests instead.

The title's word "SDK-side" is load-bearing and accurate: 19 advisories remain vulnerable at HEAD, and all 19 are reachable only from demo/* — zero from any packages/*.


Review — convertcom/javascript-sdk PR #429

  • HEAD sha: 5cb979758460c9c23665e0e6ecea9dfc9cf7a107
  • Base (merge-base with main): c0c93c56114f00132c4533c6f0f95b0b70a145e7 (verified: git merge-base HEAD origin/main)
  • Title: chore(deps): clear every remaining SDK-side advisory via resolutions
  • Diff: 3 files, +248/-1648 (package.json, packages/js-sdk/package.json, yarn.lock)
  • Reviewed: 2026-08-10, read-only. No file in the repo was modified.
  • Verdict: APPROVE — 0 blocking findings, 5 non-blocking observations.

What I verified clean

V1. No runtime dependency of any published package changed — verified exhaustively

The single highest-stakes question. Method: read each workspace's real package.json
(dependencies + peerDependencies only) at both revisions, expand @convertcom/* workspace
peers transitively, then walk the Berry lockfile graph applying resolutions overrides.

Methodology note: seeding the walk from the lockfile workspace entry is wrong — Yarn Berry
merges devDependencies into the workspace entry's dependencies field (verified at
yarn.lock:2347 HEAD, where @babel/cli, eslint, @playwright/test — all devDeps in
packages/js-sdk/package.json — appear under dependencies). Seeds must come from the manifests.

Result — the entire third-party runtime surface of all 13 published packages is one package:

Package 3rd-party runtime closure (base) (head)
api, bucketing, cloudflare, data, experience, js-sdk, rules, segments, utils murmurhash@2.0.1 murmurhash@2.0.1
enums, event, logger, types (empty) (empty)

PUBLISHED_RUNTIME_CHANGED = False. Every published package declares "dependencies": {} except
packages/utils (murmurhash: ^2.0.1); all other inter-package links are peerDependencies on
sibling @convertcom/js-sdk-* workspaces. None of the 7 new resolutions touches murmurhash,
and the runtime manifests are byte-identical between base and HEAD for all 20 workspaces.
Bucketing/rule parity semantics are therefore untouched by this PR.

V2. browserify / watchify are genuinely unused — zero references

git grep -n -I -E 'browserify|watchify|babelify|tsify|esmify|envify|brfs' \
  5cb97975 -- . ':(exclude)yarn.lock'     ->  exit 1, no output

Grep form sanity-checked with the same invocation against a known-present token (webpack),
which returned hits in 8+ files — so the empty result is a real absence, not a broken pathspec.
This covers every workspace scripts block, rollup/webpack/karma configs, .github/workflows,
and docs in the tracked tree. Removing the two devDeps breaks no call site.

V3. The title's claim — "every remaining SDK-side advisory" — is accurate

41 open Dependabot alerts. Cross-checked every one against the resolved versions in the HEAD
lockfile, then attributed each still-vulnerable version to the workspaces that reach it
(full dev+runtime closure):

  • 3 packages removed from the tree entirely: taffydb (high), vue-template-compiler, elliptic
  • 19 alerts cleared by version movement (incl. underscore high, serialize-javascript high+medium, linkify-it 2x high, diff, pug, pug-code-gen, markdown-it)
  • 19 alerts still vulnerable at HEAD — all of them reachable only from demo/*:
Package Vuln version at HEAD Reachable from
undici 7.28.0 demo/cloudflare-workers
react-router, react-router-dom 6.30.4 demo/remixjs-*
esbuild 0.17.6, 0.21.5 demo/remixjs-*
estree-util-value-to-estree 1.3.0 demo/remixjs-*
postcss 7.0.39 demo/reactjs
svgo 1.3.2 demo/reactjs
webpack-dev-server 4.15.2 demo/reactjs

Zero still-vulnerable package is reachable from any packages/* workspace. The scoping word
"SDK-side" in the title is doing real work and is correct.

V4. All 7 resolutions are honored; none is a dead no-op entry

Resolution Base descriptors HEAD resolved Satisfies
jsdoc: ^4.0.5 ^3.6.2 4.0.5 yes
vue-docgen-api: ^4.79.2 ^3.26.0 4.79.2 yes
serialize-javascript: >=7.0.5 ^4.0.0, ^6.0.0/6.0.1/6.0.2 7.0.7 yes
diff: >=8.0.3 ^4.0.1, ^5.0.0, ^7.0.0 9.0.0 yes
pug: >=3.0.3 ^2.0.3, ^3.0.4 3.0.4 yes
pug-code-gen: >=3.0.3 ^2.0.2, ^3.0.4 3.0.4 yes
underscore: >=1.13.8 1.13.6, ^1.13.2/~1.13.2 1.13.8 yes

V5. Every forced major bump traced to its consumer and cleared

resolutions are blunt — each one overrides a declared range. I enumerated every consumer at base
and checked each SDK-side one:

Consumer (declared range) Forced to SDK-side? Verdict
mocha@11.8.0 (diff@^7.0.0) 9.0.0 yes (test:mocha) safe — see below
mocha@11.8.0 (serialize-javascript@^6.0.2) 7.0.7 yes parallel-mode only, not used
rollup-plugin-jsdoc@0.1.2 (jsdoc@^3.6.2) 4.0.5 yes (yarn build) exercised by green CI
better-docs@2.7.3 (vue-docgen-api@^3.26.0) 4.79.2 yes (jsdoc template) zero exposure — see below
ts-node@10.9.2 (diff@^4.0.1) 9.0.0 yes diff is a lazy require inside dist/repl.js only; tests use -r ts-node/register, never the REPL
tslint@6.1.3 (diff@^4.0.1) 9.0.0 yes (devDep) lint script is eslint src; tslint is never invoked
jsonpath@1.3.0 (underscore@1.13.6 exact) 1.13.8 no patch bump
uvu@0.5.6, rollup-plugin-terser@7.0.2, css-minimizer-webpack-plugin@3.4.1 no demo-side

mocha + diff@9 — the one that needed real proof. mocha/lib/reporters/base.js:16 does
var diff = require('diff') and line 518 calls diff.createPatch('string', actual, expected).
That is the failure-diff path — it only executes when a test fails, so a green CI run does not
exercise it. Verified directly against the published artifact instead:

curl https://registry.npmjs.org/diff/-/diff-9.0.0.tgz | tar xz
node -e "const d=require('./package/libcjs/index.js');
         console.log(typeof d.createPatch);
         console.log(d.createPatch('string','foo\nbar\n','foo\nbaz\n'))"
->  function
->  Index: string / --- string / +++ string / @@ -1,2 +1,2 @@ / foo / -bar / +baz

diff@9.0.0 still ships CJS (main: ./libcjs/index.js) and exports createPatch with the same
3-arg signature. Mocha's failure reporter is safe.

better-docs + vue-docgen-api@4 — zero functional exposure. vue-docgen-api is consumed only
by node_modules/better-docs/component.js. packages/js-sdk/jsdoc.config.json loads only
better-docs/typescript and better-docs/category as plugins — not component — and the repo
contains 0 .vue files. That resolution exists purely to evict vue-template-compiler
(GHSA-g3ch-rx76-35fx) from the tree; no code path changes.

V6. Lockfile is internally consistent

  • Dangling descriptors: 0. Every dependencies edge in all 2353 entries resolves.
  • Semver integrity: all 3021 npm: descriptors checked with semver.satisfies0 entries
    resolve outside their own declared range. (One apparent hit, node-gyp@npm:latest -> 13.0.1, is a
    dist-tag not a range, and is present identically at base: base.lock:18892, head.lock:18110.)
  • Resolution sources: 2326 npm:, 21 workspace:, 6 patch:. All 6 patches are Yarn builtin
    compat patches (#optional!builtin<compat/fsevents|resolve|typescript>), not custom patch files.
    No git:, http:, file:, or portal: sources — clean for a published SDK.
  • Metadata version: 8, cacheKey: 10c0; packageManager: yarn@4.10.3.

V7. CI has an immutable-install gate, and it passed on this exact sha

.github/workflows/qa.yml runs yarn install --immutable, then in packages/js-sdk:
yarn lint && yarn build && yarn test:mocha && yarn test:browser.
All check runs are bound to head_sha 5cb979758460c9c23665e0e6ecea9dfc9cf7a107 (verified via
/commits/<sha>/check-runs), and pass-qa (22) = success. The immutable install succeeding at
this sha is direct proof the lockfile matches the manifests with no drift — stronger evidence than a
local install would give here (see Coverage gaps). publish-package.yml and pages.yml also use
yarn install --immutable.


Blocking findings

None.


Non-blocking observations

N1. Five of the seven new resolutions have an unbounded upper bound

serialize-javascript: >=7.0.5, diff: >=8.0.3, pug: >=3.0.3, pug-code-gen: >=3.0.3,
underscore: >=1.13.8 accept any future major. The lockfile pins exact versions and CI is
--immutable, so nothing floats today — but the next deliberate re-resolution can jump a major of
dev tooling with no range guard. The two caret entries (jsdoc: ^4.0.5, vue-docgen-api: ^4.79.2)
are the safer form.

To be fair to the author: this mixed style is pre-existing, not introduced here — the 14 prior
resolutions are 13x >= and 1x caret (path-to-regexp: ^0.1.12). So the caret/>= inconsistency
flagged in the brief is consistent with existing repo practice rather than an oversight in this PR.
Worth a follow-up to settle on one form (>=X <Y+1 would keep the security floor and add a ceiling).

N2. pug / pug-code-gen resolutions are defensive no-ops at present

The pug advisories came from pug@2.0.4, pulled in by vue-docgen-api@3.26.0 (pug@^2.0.3).
Bumping vue-docgen-api to 4.79.2 removes that edge entirely. The only remaining pug consumer is
demo/nodejs (pug@^3.0.4), which already resolves to 3.0.4 — satisfying >=3.0.3 with or without
the resolution. Harmless as a floor; just note they are belt-and-braces, not the active fix.

N3. resolutions do not protect published consumers — fine here, worth knowing

Yarn resolutions in the root (private: true) manifest apply only to this repo's install tree;
they are not published. Anyone npm installing @convertcom/js-sdk gets none of them. That is
harmless in this case precisely because V1 holds — no resolved package is in any published
package's runtime closure. It does mean these entries fix CI/dev-tree advisories only.

N4. The "SDK-side" safety argument leans on demos never being published

demo/nodejs (@convertcom/js-sdk-demo-nodejs) and demo/reactjs (@convertcom/js-sdk-demo-react)
omit private: true. They are not publishable in practice — publish-package.yml publishes only
explicit packages/* directories gated on js-sdk-*-v tags, and release-please-config.json lists
only packages/*. Pre-existing and untouched by this PR; adding "private": true to both would make
the SDK-vs-demo boundary that this PR's scoping relies on structural rather than incidental.

N5. SonarCloud check is attributed to PR #426

gh pr checks 429 reports the SonarCloud check at
https://sonarcloud.io/dashboard?id=convertcom_javascript-sdk&pullRequest=426, and the workflow-run
list for this sha contains both a PR #426 and a PR #429 dynamic run. The check is bound to the
correct head_sha, so the code analyzed is this code; only the PR-number attribution looks off.
Cosmetic, but if SonarCloud decorations land on the wrong PR it is worth a glance.


Coverage gaps

  1. No local install performed. corepack is not installed in this environment
    (which corepack -> not found) and the global yarn is 4.5.3 vs the repo's pinned
    packageManager: yarn@4.10.3. Per the brief I did not force it — running 4.5.3 against a
    4.10.3-written lockfile risks rewriting it. The green yarn install --immutable in CI at this
    exact sha covers this question better than a mismatched local install would.
  2. Docs content is unverified. yarn build runs jsdoc only for the main package
    (generate-rollup-config.mjs:217 isMainPackage), and pages.yml copies
    packages/js-sdk/docs to gh-pages on push to main. A green build proves jsdoc 4.0.5 +
    better-docs ran; it does not prove the generated HTML is equivalent to what jsdoc 3.6.11
    produced. Recommend eyeballing the gh-pages output after merge — this is the one user-visible
    surface the major bumps touch.
  3. test:browser / Playwright ran in CI; I did not re-run it locally.
  4. Dependabot alert state is a snapshot of the default branch taken during this review
    (41 open). Alert closure after merge is inferred from lockfile versions, not observed.

Verdict

APPROVE — 0 blocking findings.

The two claims that carried real risk both hold under direct verification: no published package's
runtime dependency closure changes (it is murmurhash@2.0.1 and nothing else, identical at both
revisions), and browserify/watchify have zero references anywhere in the tracked tree. The
advisory bookkeeping in the title is precise — all 19 surviving advisories are demo-only. The one
genuinely non-obvious hazard, mocha's failure-only diff.createPatch path being force-bumped two
majors, was checked against the published diff@9.0.0 artifact rather than assumed safe from green CI.

@JosephSamirL JosephSamirL left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved via /convert:approve. An independent code review ran through /convert:review, and this issues the B-G4 human marker at 5cb9797.

@JosephSamirL
JosephSamirL merged commit fe46798 into main Aug 9, 2026
9 checks passed
@JosephSamirL
JosephSamirL deleted the chore/dependabot-sdk-resolutions branch August 9, 2026 23:32
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.

2 participants