ci: add Node.js 26 to the test matrix - #141
Conversation
isRealPathSafe() stopped walking as soon as realpath() failed on a dangling link, checking only that link's immediate target. A destination reached through several hops, or through a linked directory, was therefore only partially resolved, and the entry could land somewhere the check had not accounted for. Resolve the remaining hops by hand instead, bounded by MAX_SYMLINK_DEPTH so a chain realpath() cannot see does not recurse without end. File entries no longer write through a symlink sitting at the destination. The link is replaced by the entry, which is how tar(1), node-tar, tar-fs and libarchive all behave. On platforms that have it, the write also opens with O_NOFOLLOW so the destination is never resolved through a link. Linked directories inside the extraction directory are still traversed, so entries written beneath them land where they always did.
The recursive walk always computed its relative path from parentDir. When a dangling link named its target in the real namespace, as with /var against /private/var on macOS, that relative path climbed out through '..' and the walk rejected a target that was in fact inside the extraction directory, so the entry was skipped. Pick the root that actually contains the target before walking, and fail closed when neither does. Adds a regression test that builds the two namespaces itself rather than relying on the host having a symlinked temp directory. Also settle the promise in createZipBuffer() when called with no entries, since an empty archive never finalizes, and register its listeners before adding entries.
Windows resolves the dangling link in that setup differently and skips the entry, which predates this change. The /var against /private/var divergence the test covers is a POSIX shape, and macOS and Linux still exercise it.
Node 26 is the current release line and becomes LTS in October, so running it now surfaces any breakage before the promotion.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
[skip ci] ## <small>2.1.2 (2026-08-05)</small> * test: use node:crypto randomUUID instead of uuid dependency (#143) ([c0d269f](c0d269f)), closes [#143](#143) [#139](#139) * ci: add Node.js 26 to the test matrix (#141) ([5c725e6](5c725e6)), closes [#141](#141) [#140](#140) * fix: resolve symlink chains fully when extracting (#140) ([72a3c84](72a3c84)), closes [#140](#140)
|
🎉 This PR is included in version 2.1.2 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Stacked on #140, so the diff here is just the workflow change.
Node 26 is the current release line (26.6.0, released 2026-08-03) and becomes LTS in October. Running it now surfaces breakage before the promotion rather than after.
enginesstays at>= 18, so this only widens what CI covers.