| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
The metadata pre-flight check from #632 only inspects an entry's declared `uncompressedSize`. An archive whose central directory lies about that size slips past the check, and (worse) hangs `extract()` indefinitely because yauzl's built-in `AssertByteCountStream` overrides its own `destroy` so the mid-stream error never surfaces to extract-zip's `pipeline()`. In `onEntry`, switch off yauzl's broken counter (`validateEntrySizes = false`) and monkey-patch `zipfile.openReadStream` to pipe each read stream through our own counting Transform — whose errors propagate cleanly through extract-zip's pipeline. No dependency changes; existing pre-flight checks, error shapes, and the `onEntry` hook contract are preserved. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
WalkthroughThis PR adds streaming byte counting to enforce per-entry uncompressed size limits during ZIP decompression. Previously, size validation relied only on central-directory metadata. The changes introduce a new entryTooLargeError helper, monkey-patch yauzl's openReadStream within an installStreamingCounter function to wrap reads with a Transform stream that counts decompressed bytes, and integrate this into the extraction onEntry handler. Test coverage includes a helper that forges central-directory uncompressedSize fields and a test case verifying extract() rejects when streamed payload exceeds limits despite understated metadata. Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
❌ Failed checks (1 warning)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches 📝 Generate docstrings
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 eslint to devDependencies. Comment @coderabbitai help to get the list of available commands and usage tips. |
Sorry, something went wrong.
Codecov Report❌ Patch coverage is 85.71429% with 4 lines in your changes missing coverage. Please review.
@@ Coverage Diff @@
## main #641 +/- ##
==========================================
- Coverage 98.12% 95.95% -2.17%
==========================================
Files 84 2 -82
Lines 2771 99 -2672
Branches 510 17 -493
==========================================
- Hits 2719 95 -2624
+ Misses 11 2 -9
+ Partials 41 2 -39 ☔ View full report in Codecov by Sentry.
|
Sorry, something went wrong.
There was a problem hiding this comment.
packages/zip/lib/extract.js (1)🤖 Prompt for all review comments with AI agents191-192: 💤 Low value
Consider skipping streaming counter when per-entry limit is Infinity.
The counter is installed even when limits.perEntryUncompressedBytes === Infinity, adding Transform overhead for every entry without any enforcement benefit. The comparison observedBytes > Infinity is always false, so it's correct but wasteful.
♻️ Optional: skip counter when no limit is configuredfunction installStreamingCounter(zipfile, limits) { - if (zipfile.__streamingCounterInstalled || typeof zipfile.openReadStream !== 'function') { + if ( + limits.perEntryUncompressedBytes === Infinity || + zipfile.__streamingCounterInstalled || + typeof zipfile.openReadStream !== 'function' + ) { return; }Also applies to: 213-248
🤖 Prompt for AI AgentsVerify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/zip/lib/extract.js` around lines 191 - 192, Skip installing the streaming counter when no per-entry limit is configured by checking limits.perEntryUncompressedBytes === Infinity before calling installStreamingCounter (and similarly in the other install sites around the per-entry check). Modify the code paths that call installStreamingCounter (reference: installStreamingCounter, limits.perEntryUncompressedBytes, and the zipfile handling code) so the Transform is only created when limits.perEntryUncompressedBytes is a finite number; leave behavior unchanged otherwise.
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. Nitpick comments: In `@packages/zip/lib/extract.js`: - Around line 191-192: Skip installing the streaming counter when no per-entry limit is configured by checking limits.perEntryUncompressedBytes === Infinity before calling installStreamingCounter (and similarly in the other install sites around the per-entry check). Modify the code paths that call installStreamingCounter (reference: installStreamingCounter, limits.perEntryUncompressedBytes, and the zipfile handling code) so the Transform is only created when limits.perEntryUncompressedBytes is a finite number; leave behavior unchanged otherwise.
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 2ccf229d-7080-45bb-a8d8-67f09f4bceca
📥 CommitsReviewing files that changed from the base of the PR and between f5a44ed and 2fe4bb3.
📒 Files selected for processing (2)
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Summary
Follow-up to #632. The size limits added there are enforced on entry.uncompressedSize from the central directory — declared metadata. A zip whose header lies about its uncompressed size slips past the check, and (worse) hangs extract() indefinitely.
This PR enforces limits.perEntryUncompressedBytes against the actual decompressed bytes streamed for each entry. No dependency changes.
Why the hang
yauzl already includes an AssertByteCountStream that should error mid-stream when actual bytes exceed declared. But yauzl overrides its own destroy with a closure that silently discards the error, so the mid-stream error never reaches extract-zip's pipeline() — which then waits forever on a stream that has been destroyed without emitting end or error.
The fix
In the existing onEntry wrapper, two small additions:
That's the whole fix — about 40 lines of new code in extract.js, plus refactoring throwOnEntryTooLarge into an entryTooLargeError factory so the Transform can construct the same error shape.
What's deliberately out of scope
totalUncompressedBytes still 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.
Diff
Test plan
🤖 Generated with Claude Code