Use yauzl directly instead of extract-zip#639
Conversation
Swaps the unmaintained `extract-zip` (no release since 2020) for `yauzl` directly. extract-zip is a thin wrapper around yauzl, so the swap is small. The motivation is that yauzl's built-in `AssertByteCountStream` overrides its own `destroy` in a way that silently swallows errors when an entry's actual decompressed bytes exceed its declared uncompressed size. extract-zip pipes that stream into a `pipeline()` and waits on the error that never arrives, hanging the extraction promise forever on any zip whose central directory understates the payload — including the metadata-pre-flight checks from #632. By opening yauzl with `validateEntrySizes: false` and running our own counting Transform, the per-entry size limit is enforced against actual decompressed bytes and errors propagate cleanly through `pipeline()`. All existing pre-flight checks, error shapes, helpers, and the `onEntry` hook contract are preserved. Path traversal, `__MACOSX/` skip, symlink/dir/mode detection are ported verbatim from extract-zip. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (3)
WalkthroughThis PR replaces the Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint skipped: no ESLint configuration detected in root package.json. To enable, add Comment |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #639 +/- ##
==========================================
- Coverage 98.12% 97.87% -0.25%
==========================================
Files 84 84
Lines 2771 2830 +59
Branches 510 524 +14
==========================================
+ Hits 2719 2770 +51
- Misses 11 12 +1
- Partials 41 48 +7 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Summary
Swaps the unmaintained
extract-zip(no release since 2020) foryauzldirectly. Closes the lying-header hang in #632's size-limit checks: a zip whose central directory understates an entry's size currently bypasses the metadata pre-flight check and then hangsextract()indefinitely.Why the swap matters
yauzl's built-in
AssertByteCountStreamis supposed to error when actual decompressed bytes exceed declareduncompressedSize. But it overrides its owndestroywith a closure that silently discards the error, soextract-zip'spipeline()waits on an error that never arrives. The fix is to open yauzl withvalidateEntrySizes: falseand run our own countingTransformwhose errors propagate cleanly.Scope
Minimum-viable swap:
lib/extract.js— existing helpers (normalizeLimit,getLimits,getEntryUncompressedSize,throwOn*, etc.) and theonEntrywrapper are untouched. The only change is removing therequire('extract-zip')line and replacing the singleawait extract(zipToExtract, opts)call with a localextractZip()function that uses yauzl. Path-traversal guard,__MACOSX/skip, symlink/dir/mode handling are ported verbatim.test/zip.test.js— three existing tests that mockedextract-zipviaModule._loadare updated to mockyauzlvia a small helper. One new regression test for the lying-header case.package.json—extract-zip→yauzl.Total diff: ~130 net new lines in
extract.js(the local yauzl-based extractor) plus the test refactor and the one new regression test.What's deliberately out of scope
The streaming counter currently only enforces
perEntryUncompressedBytesagainst actual decompressed bytes.totalUncompressedBytesstill uses the existing metadata pre-flight (same as today). A future change could extend streaming to the total — left out here to keep the diff focused.Test plan
pnpm --filter @tryghost/zip test— 16/16 pass, coverage above thresholds, lint clean🤖 Generated with Claude Code