From 3a7bfc2f5b6dbef5a1a5d879de05a8accc8c5932 Mon Sep 17 00:00:00 2001 From: ilyakhd <14272298+IlyaKhD@users.noreply.github.com> Date: Thu, 16 Apr 2026 18:29:54 +0300 Subject: [PATCH 1/5] =?UTF-8?q?=E2=9C=A8=20retarget=20to=20the=20folder=20?= =?UTF-8?q?within=20node=5Fmodules/.pnpm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- install-internal-package/replace-package.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/install-internal-package/replace-package.js b/install-internal-package/replace-package.js index da59663..ba5532a 100644 --- a/install-internal-package/replace-package.js +++ b/install-internal-package/replace-package.js @@ -1,6 +1,6 @@ const assert = require('node:assert'); const { execFileSync } = require('node:child_process'); -const { rmSync, mkdirSync, lstatSync, unlinkSync } = require('node:fs'); +const { rmSync, mkdirSync, lstatSync, readlinkSync, realpathSync } = require('node:fs'); const { join } = require('node:path'); const { createRequire } = require('node:module'); @@ -21,16 +21,17 @@ for (const searchDir of cwdRequire.resolve.paths(packageName) || []) { assert(entryPath, `Package "${packageName}" is not installed. It must be installed before it can be replaced.`); -if (lstatSync(entryPath).isSymbolicLink()) { - unlinkSync(entryPath); -} else { - rmSync(entryPath, { recursive: true, force: true }); -} +// If it's a symlink (pnpm), replace the target content to preserve the resolution chain. +// pnpm places dependencies as siblings of the target, so the symlink must stay intact. +const targetPath = lstatSync(entryPath).isSymbolicLink() + ? realpathSync(entryPath) + : entryPath; -mkdirSync(entryPath, { recursive: true }); +rmSync(targetPath, { recursive: true, force: true }); +mkdirSync(targetPath, { recursive: true }); const listing = execFileSync('tar', ['-tzf', packageFile]).toString(); const unsafeEntry = listing.split('\n').find(e => e.includes('..') || e.startsWith('/')); assert(!unsafeEntry, `Archive contains unsafe path: ${unsafeEntry}`); -execFileSync('tar', ['-xzf', packageFile, '-C', entryPath, '--strip-components=1']); +execFileSync('tar', ['-xzf', packageFile, '-C', targetPath, '--strip-components=1']); From 5eea3f852752973b940112abe857a61dec9e31e3 Mon Sep 17 00:00:00 2001 From: ilyakhd <14272298+IlyaKhD@users.noreply.github.com> Date: Thu, 16 Apr 2026 18:30:55 +0300 Subject: [PATCH 2/5] chore(env): include .DS_Store into .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8f0e7ae..f137c43 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .idea/ .vscode/ +.DS_Store logs *.log From c9c1442a4133b6ef700f14fa96d84a9b90a7b14d Mon Sep 17 00:00:00 2001 From: "ilya.kharchenko" <14272298+IlyaKhD@users.noreply.github.com> Date: Thu, 16 Apr 2026 09:38:57 -0700 Subject: [PATCH 3/5] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- install-internal-package/replace-package.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install-internal-package/replace-package.js b/install-internal-package/replace-package.js index ba5532a..aabb647 100644 --- a/install-internal-package/replace-package.js +++ b/install-internal-package/replace-package.js @@ -1,6 +1,6 @@ const assert = require('node:assert'); const { execFileSync } = require('node:child_process'); -const { rmSync, mkdirSync, lstatSync, readlinkSync, realpathSync } = require('node:fs'); +const { rmSync, mkdirSync, lstatSync, realpathSync } = require('node:fs'); const { join } = require('node:path'); const { createRequire } = require('node:module'); From adb5e35e98f0365b1d3801d5a1e3afb2133f2772 Mon Sep 17 00:00:00 2001 From: ilyakhd <14272298+IlyaKhD@users.noreply.github.com> Date: Thu, 16 Apr 2026 19:50:09 +0300 Subject: [PATCH 4/5] =?UTF-8?q?=E2=9C=A8=20address=20copilot=20review=20co?= =?UTF-8?q?mments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- install-internal-package/replace-package.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/install-internal-package/replace-package.js b/install-internal-package/replace-package.js index aabb647..c9bba7a 100644 --- a/install-internal-package/replace-package.js +++ b/install-internal-package/replace-package.js @@ -23,9 +23,15 @@ assert(entryPath, `Package "${packageName}" is not installed. It must be install // If it's a symlink (pnpm), replace the target content to preserve the resolution chain. // pnpm places dependencies as siblings of the target, so the symlink must stay intact. -const targetPath = lstatSync(entryPath).isSymbolicLink() - ? realpathSync(entryPath) - : entryPath; +const isSymlink = lstatSync(entryPath).isSymbolicLink(); +const targetPath = isSymlink ? realpathSync(entryPath) : entryPath; + +if (isSymlink) { + assert( + targetPath.startsWith(process.cwd() + '/'), + `Symlink target "${targetPath}" resolves outside the project`, + ); +} rmSync(targetPath, { recursive: true, force: true }); mkdirSync(targetPath, { recursive: true }); From 494745b9e834f926e129e6420bf8f2decb851562 Mon Sep 17 00:00:00 2001 From: ilyakhd <14272298+IlyaKhD@users.noreply.github.com> Date: Thu, 16 Apr 2026 19:50:56 +0300 Subject: [PATCH 5/5] refactor --- install-internal-package/replace-package.js | 23 +++++++++++---------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/install-internal-package/replace-package.js b/install-internal-package/replace-package.js index c9bba7a..5f894f7 100644 --- a/install-internal-package/replace-package.js +++ b/install-internal-package/replace-package.js @@ -21,17 +21,18 @@ for (const searchDir of cwdRequire.resolve.paths(packageName) || []) { assert(entryPath, `Package "${packageName}" is not installed. It must be installed before it can be replaced.`); -// If it's a symlink (pnpm), replace the target content to preserve the resolution chain. -// pnpm places dependencies as siblings of the target, so the symlink must stay intact. -const isSymlink = lstatSync(entryPath).isSymbolicLink(); -const targetPath = isSymlink ? realpathSync(entryPath) : entryPath; - -if (isSymlink) { - assert( - targetPath.startsWith(process.cwd() + '/'), - `Symlink target "${targetPath}" resolves outside the project`, - ); -} +const targetPath = (() => { + if (!lstatSync(entryPath).isSymbolicLink()) { + return entryPath; + } + + // If it's a symlink (pnpm), replace the target content to preserve the resolution chain. + // pnpm places dependencies as siblings of the target, so the symlink must stay intact. + const resolved = realpathSync(entryPath); + assert(resolved.startsWith(process.cwd() + '/'), `Symlink target "${resolved}" resolves outside the project`); + return resolved; + +})(); rmSync(targetPath, { recursive: true, force: true }); mkdirSync(targetPath, { recursive: true });