Skip to content

fix(dependencies): pin override for got to 11.8.5 / patch download for compat - #187

Open
ajaynes-godaddy wants to merge 2 commits into
masterfrom
fix/got-override
Open

ajaynes-godaddy wants to merge 2 commits into
masterfrom
fix/got-override

Conversation

@ajaynes-godaddy

@ajaynes-godaddy ajaynes-godaddy commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Pins got to 11.8.5, resolving Dependabot's security update that was otherwise stuck on an unpatchable got@7.1.0/8.3.2. Unlike the previous overrides in this series, a version pin alone isn't enough here — got's option API changed enough between these versions that the real consumer breaks outright, so this PR also patches that consumer's two call sites via patch-package.

Details

  • This was flagged by Dependabot's periodic update job, not a code-scanning alert — it's being fixed here manually, outside a Dependabot-authored PR, because that job couldn't produce one: no valid install resolves the constraint to a patched version, so Dependabot just logs the conflict and gives up rather than opening a PR.
  • gulp-imagemin's imagemin-gifsicle/imagemin-mozjpeg/imagemin-optipng plugins each wrap a native binary (gifsicle/mozjpeg/optipng-bin) that falls back to bin-build/bin-wrapper when no prebuilt binary is cached — both of which pull in download, which pulls in got. Two separate chains land on two different vulnerable versions: bin-build → download@6.2.5 → got@^7.0.0, and bin-wrapper → download@7.1.0 → got@^8.3.1. Neither range has a patched release; the fix landed in 11.8.5.
  • A blanket override alone breaks this. download's own code calls got.stream(uri, {encoding: null, agent, rejectUnauthorized, ...opts}) — a calling convention got dropped well before v11: encoding: null needs to be responseType: 'buffer', agent needs to be {http, https} instead of a bare Agent instance, rejectUnauthorized needs to move under https: {rejectUnauthorized}, and the redirect event's next-URL is now nextOptions.url (a URL instance) instead of a flat nextOptions.href string. Installed got@11.8.5 directly against the real download code and confirmed it throws immediately (TypeError: To get a Buffer, set 'options.responseType' to 'buffer' instead).
  • Patched both installed copies of download (node_modules/download@6.2.5 and the nested node_modules/bin-wrapper/node_modules/download@7.1.0) via patch-package, translating the four option shapes above without changing either package's own public API. Verified against real local HTTP/HTTPS servers: plain download, redirect-following download, the actual tar.gz extract-to-disk path (the real binary-fetch use case), and TLS certificate validation in both strict and rejectUnauthorized: false modes — all byte-identical to pre-patch behavior.
  • patch-package alone isn't sufficient either: npm runs a dependency's own lifecycle scripts before the root project's postinstall (scripts run bottom-up through the tree), so gifsicle/mozjpeg/optipng-bin's own install scripts — which is what actually calls into download — run and fail against the still-unpatched code on a fresh install, before patch-package gets a chance to fix it. Added scripts/ensure-imagemin-binaries.js, chained after patch-package in postinstall, which re-runs each of the three packages' own install step once download is guaranteed to be patched. This converts a slow/toolchain-dependent fallback build into the fast prebuilt-binary fetch, and is a no-op (just prints a success message) if the first attempt already landed on the primary path.
  • mozjpeg/optipng-bin are optionalDependencies of imagemin, so if their first (pre-patch) attempt fails outright rather than falling back gracefully, npm silently drops them from node_modules rather than failing the install — in which case there's nothing left for the retry script to re-run. This self-heals on the very next npm install (confirmed), since download is already patched by then and the normal dependency-reconciliation pass reinstalls whatever's missing.
  • This repo has one open Dependabot alert for got: alert 18 (medium, CVE-2022-33987, patched at 11.8.5) — this clears it and should auto-resolve once this merges.

QA

Steps

  1. Install dependencies on this branch and confirm the install succeeds, with both patches applying cleanly:
    npm install
    • Confirm the output includes:
      Applying patches...
      bin-wrapper/download@7.1.0 ✔
      download@6.2.5 ✔
      
  2. Confirm got resolved to the patched version:
    node -p "require('./node_modules/got/package.json').version"
    • Confirm the output is:
      11.8.5
      
  3. Confirm gifsicle/mozjpeg/optipng-bin all installed successfully (if any are missing after this first install on your machine, that's the optionalDependency/script-ordering race described above — run npm install a second time and they'll be there):
    for p in gifsicle mozjpeg optipng-bin; do [ -d "node_modules/$p" ] && echo "$p: present" || echo "$p: MISSING"; done
    • Confirm all three print present
  4. Confirm the real gulp-imagemin pipeline — the same one sake's minifyImagesTask runs — processes real PNG and GIF files end-to-end with no errors:
    node --input-type=module -e "
    import imagemin from 'gulp-imagemin';
    import Vinyl from 'vinyl';
    const png = Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==', 'base64');
    const gif = Buffer.from('R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=', 'base64');
    const stream = imagemin();
    let count = 0;
    stream.on('data', (file) => { count++; console.log(file.relative, 'ok'); });
    stream.on('end', () => { console.log('TOTAL:', count); process.exit(0); });
    stream.on('error', (err) => { console.error('FAILED:', err); process.exit(1); });
    stream.write(new (await import('vinyl')).default({path: '/tmp/test.png', contents: png}));
    stream.write(new (await import('vinyl')).default({path: '/tmp/test.gif', contents: gif}));
    stream.end();
    "
    • Confirm the output ends with TOTAL: 2 and no FAILED error
  5. Confirm the existing test suite still passes:
    npm test
    • Confirm all tests pass

Before merge

  • This PR makes the appropriate modifications to automated tests or explains why none are needed — the existing test suite (npm test) passes unchanged; the download call-site patch itself was verified manually via the QA steps above against real HTTP/HTTPS servers (not something the current test suite's scope covers).
  • This PR makes the appropriate modifications to documentation or explains why none are needed
  • This change does not impact usage or expected outputs of covered code — download's public API is unchanged, confirmed via the QA steps above.
  • I've bumped the AI Assistant framework version if one is available

🤖 Generated with Claude Code

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