From 0d7ed411eefc6d798964153e86426420e2b00172 Mon Sep 17 00:00:00 2001 From: Martin Torp Date: Mon, 29 Jun 2026 11:58:46 +0200 Subject: [PATCH] fix(scan): ignore project .pnpmfile.cjs when launching tools via pnpm dlx (1.1.130) Reachability scans launch Coana (and cdxgen/synp) via `pnpm dlx` with the target repo as cwd. In a pnpm workspace root, `pnpm dlx` evaluates that repo's root `.pnpmfile.cjs`, so a broken or environment-specific hook there (e.g. a `require()` of a file that is still an unresolved Git LFS pointer) crashes the launcher with a bare exit code before the tool ever starts. Set `npm_config_ignore_pnpmfile=true` on the pnpm dlx launch env so the project's pnpm hooks never run. The dlx tool installs into an isolated store, so those hooks are irrelevant to it. The `--ignore-pnpmfile` CLI flag is rejected by `pnpm dlx`; only the env/config form works. --- CHANGELOG.md | 5 +++++ package.json | 2 +- src/utils/dlx.mts | 31 +++++++++++++++++++------------ src/utils/dlx.test.mts | 19 +++++++++++++++++++ 4 files changed, 44 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed77a4e74..573e966b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). +## [1.1.130](https://github.com/SocketDev/socket-cli/releases/tag/v1.1.130) - 2026-06-29 + +### Fixed +- Reachability analysis no longer fails to start in pnpm workspaces that define a `.pnpmfile.cjs`. Socket now launches its bundled analysis tools without running the project's pnpm hooks, so a broken or environment-specific hook (for example, one that loads a file managed by Git LFS) can no longer stop a scan before it begins. + ## [1.1.129](https://github.com/SocketDev/socket-cli/releases/tag/v1.1.129) - 2026-06-26 ### Changed diff --git a/package.json b/package.json index 34d0d7e6c..f34b927ec 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "socket", - "version": "1.1.129", + "version": "1.1.130", "description": "CLI for Socket.dev", "homepage": "https://github.com/SocketDev/socket-cli", "license": "MIT", diff --git a/src/utils/dlx.mts b/src/utils/dlx.mts index 57bc752a9..f5fb6c20a 100644 --- a/src/utils/dlx.mts +++ b/src/utils/dlx.mts @@ -128,19 +128,26 @@ export async function spawnDlx( spawnArgs.push(FLAG_SILENT) } spawnArgs.push('dlx') + // Never let the target project's `.pnpmfile.cjs` hooks run while we launch + // a third-party tool via `pnpm dlx`. In a pnpm workspace root, `pnpm dlx` + // loads the cwd's `.pnpmfile.cjs`, so a broken hook there (e.g. a `require` + // of an unresolved Git LFS pointer) crashes the launcher with a bare exit + // code before our tool ever starts. The dlx tool installs into an isolated + // store, so the project's install hooks are irrelevant to it. pnpm honors + // this only as a config setting, not as a `dlx` CLI flag, so it must be set + // via the npm_config_ env var. See: https://pnpm.io/npmrc#settings + const pnpmEnv: Record = { + ...getOwn(finalShadowOptions, 'env'), + npm_config_ignore_pnpmfile: 'true', + } if (force) { - // For pnpm, set dlx-cache-max-age to 0 via env to force fresh download. - // This ensures we always get the latest version within the range. - finalShadowOptions = { - ...finalShadowOptions, - env: { - ...getOwn(finalShadowOptions, 'env'), - // Set dlx cache max age to 0 minutes to bypass cache. - // The npm_config_ prefix is how pnpm reads config from environment variables. - // See: https://pnpm.io/npmrc#settings - npm_config_dlx_cache_max_age: '0', - }, - } + // Set dlx-cache-max-age to 0 minutes to bypass cache and force a fresh + // download. This ensures we always get the latest version within the range. + pnpmEnv['npm_config_dlx_cache_max_age'] = '0' + } + finalShadowOptions = { + ...finalShadowOptions, + env: pnpmEnv, } spawnArgs.push(packageString, ...args) diff --git a/src/utils/dlx.test.mts b/src/utils/dlx.test.mts index 4a219f891..888b62874 100644 --- a/src/utils/dlx.test.mts +++ b/src/utils/dlx.test.mts @@ -181,6 +181,25 @@ describe('utils/dlx', () => { expect(options.env.npm_config_dlx_cache_max_age).toBe('0') }) + it('should set npm_config_ignore_pnpmfile env var for pnpm regardless of force', async () => { + const packageSpec: DlxPackageSpec = { + name: '@coana-tech/cli', + version: '1.0.0', + } + + // force defaults to false here, exercising the non-force path. + await spawnDlx(packageSpec, ['run', '/some/path'], { agent: 'pnpm' }) + + expect(mockShadowPnpmBin).toHaveBeenCalledTimes(1) + const [, options] = mockShadowPnpmBin.mock.calls[0] + + // The target project's `.pnpmfile.cjs` must be ignored so a broken hook + // (e.g. a require of an unresolved Git LFS pointer) cannot crash the + // `pnpm dlx` launcher before the tool starts. + expect(options.env).toBeDefined() + expect(options.env.npm_config_ignore_pnpmfile).toBe('true') + }) + it('should handle pinned version without silent flag by default', async () => { const packageSpec: DlxPackageSpec = { name: '@coana-tech/cli',