@socketsecurity/cli-with-sentry 1.1.20 → 1.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/CHANGELOG.md +34 -10
  2. package/dist/cli.js +194 -151
  3. package/dist/cli.js.map +1 -1
  4. package/dist/constants.js +28 -4
  5. package/dist/constants.js.map +1 -1
  6. package/dist/flags.js +21 -3
  7. package/dist/flags.js.map +1 -1
  8. package/dist/npm-cli.js +6 -2
  9. package/dist/npm-cli.js.map +1 -1
  10. package/dist/pnpm-cli.js +6 -2
  11. package/dist/pnpm-cli.js.map +1 -1
  12. package/dist/shadow-npm-bin2.js +8 -31
  13. package/dist/shadow-npm-bin2.js.map +1 -1
  14. package/dist/shadow-pnpm-bin2.js +41 -64
  15. package/dist/shadow-pnpm-bin2.js.map +1 -1
  16. package/dist/shadow-yarn-bin.js +17 -33
  17. package/dist/shadow-yarn-bin.js.map +1 -1
  18. package/dist/tsconfig.dts.tsbuildinfo +1 -1
  19. package/dist/types/commands/fix/cmd-fix.d.mts.map +1 -1
  20. package/dist/types/commands/fix/handle-fix.d.mts +2 -2
  21. package/dist/types/commands/fix/handle-fix.d.mts.map +1 -1
  22. package/dist/types/commands/fix/types.d.mts +1 -1
  23. package/dist/types/commands/fix/types.d.mts.map +1 -1
  24. package/dist/types/commands/manifest/cmd-manifest.d.mts.map +1 -1
  25. package/dist/types/commands/optimize/handle-optimize.d.mts.map +1 -1
  26. package/dist/types/commands/organization/cmd-organization-policy.d.mts.map +1 -1
  27. package/dist/types/commands/organization/cmd-organization.d.mts.map +1 -1
  28. package/dist/types/commands/package/cmd-package.d.mts.map +1 -1
  29. package/dist/types/commands/patch/cmd-patch.d.mts.map +1 -1
  30. package/dist/types/commands/patch/handle-patch.d.mts.map +1 -1
  31. package/dist/types/commands/scan/cmd-scan.d.mts.map +1 -1
  32. package/dist/types/commands/scan/perform-reachability-analysis.d.mts.map +1 -1
  33. package/dist/types/commands/scan/suggest_branch_slug.d.mts.map +1 -1
  34. package/dist/types/constants.d.mts +8 -1
  35. package/dist/types/constants.d.mts.map +1 -1
  36. package/dist/types/flags.d.mts.map +1 -1
  37. package/dist/types/shadow/common.d.mts +0 -8
  38. package/dist/types/shadow/common.d.mts.map +1 -1
  39. package/dist/types/shadow/npm-base.d.mts.map +1 -1
  40. package/dist/types/shadow/pnpm/bin.d.mts.map +1 -1
  41. package/dist/types/shadow/yarn/bin.d.mts.map +1 -1
  42. package/dist/types/test/json-output-validation.d.mts +37 -0
  43. package/dist/types/test/json-output-validation.d.mts.map +1 -0
  44. package/dist/types/test/mocks/socket-auth.d.mts +88 -0
  45. package/dist/types/test/mocks/socket-auth.d.mts.map +1 -0
  46. package/dist/types/utils/agent.d.mts.map +1 -1
  47. package/dist/types/utils/cmd.d.mts +25 -4
  48. package/dist/types/utils/cmd.d.mts.map +1 -1
  49. package/dist/types/utils/config.d.mts +1 -1
  50. package/dist/types/utils/dlx-binary.d.mts +58 -0
  51. package/dist/types/utils/dlx-binary.d.mts.map +1 -0
  52. package/dist/types/utils/dlx-detection.d.mts +29 -0
  53. package/dist/types/utils/dlx-detection.d.mts.map +1 -0
  54. package/dist/types/utils/extract-names.d.mts +15 -0
  55. package/dist/types/utils/extract-names.d.mts.map +1 -0
  56. package/dist/types/utils/git.d.mts.map +1 -1
  57. package/dist/types/utils/meow-with-subcommands.d.mts +33 -12
  58. package/dist/types/utils/meow-with-subcommands.d.mts.map +1 -1
  59. package/dist/types/utils/shadow-links.d.mts +5 -0
  60. package/dist/types/utils/shadow-links.d.mts.map +1 -0
  61. package/dist/types/utils/terminal-link.d.mts +19 -12
  62. package/dist/types/utils/terminal-link.d.mts.map +1 -1
  63. package/dist/utils.js +533 -146
  64. package/dist/utils.js.map +1 -1
  65. package/dist/yarn-cli.js +6 -2
  66. package/dist/yarn-cli.js.map +1 -1
  67. package/package.json +1 -1
  68. package/dist/types/shadow/npm/link.d.mts +0 -2
  69. package/dist/types/shadow/npm/link.d.mts.map +0 -1
  70. package/dist/types/shadow/pnpm/link.d.mts +0 -2
  71. package/dist/types/shadow/pnpm/link.d.mts.map +0 -1
  72. package/dist/types/shadow/yarn/link.d.mts +0 -2
  73. package/dist/types/shadow/yarn/link.d.mts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"shadow-npm-bin2.js","sources":["../src/shadow/npm/link.mts","../src/shadow/stdio-ipc.mts","../src/shadow/npm-base.mts","../src/shadow/npm/bin.mts"],"sourcesContent":["import path from 'node:path'\n\nimport cmdShim from 'cmd-shim'\n\nimport constants from '../../constants.mts'\nimport {\n getNpmBinPath,\n getNpxBinPath,\n isNpmBinPathShadowed,\n isNpxBinPathShadowed,\n} from '../../utils/npm-paths.mts'\n\nexport async function installLinks(\n shadowBinPath: string,\n binName: 'npm' | 'npx',\n): Promise<string> {\n const isNpx = binName === 'npx'\n // Find package manager being shadowed by this process.\n const binPath = isNpx ? getNpxBinPath() : getNpmBinPath()\n const { WIN32 } = constants\n // TODO: Is this early exit needed?\n if (WIN32 && binPath) {\n return binPath\n }\n const shadowed = isNpx ? isNpxBinPathShadowed() : isNpmBinPathShadowed()\n // Move our bin directory to front of PATH so its found first.\n if (!shadowed) {\n if (WIN32) {\n await cmdShim(\n path.join(constants.distPath, `${binName}-cli.js`),\n path.join(shadowBinPath, binName),\n )\n }\n const { env } = process\n env['PATH'] = `${shadowBinPath}${path.delimiter}${env['PATH']}`\n }\n return binPath\n}\n","import type { StdioOptions } from 'node:child_process'\n\n/**\n * Ensures stdio configuration includes IPC channel for process communication.\n * Converts various stdio formats to include 'ipc' as the fourth element.\n */\nexport function ensureIpcInStdio(\n stdio: StdioOptions | undefined,\n): StdioOptions {\n if (typeof stdio === 'string') {\n return [stdio, stdio, stdio, 'ipc']\n } else if (Array.isArray(stdio)) {\n if (!stdio.includes('ipc')) {\n return stdio.concat('ipc')\n }\n return stdio\n } else {\n return ['pipe', 'pipe', 'pipe', 'ipc']\n }\n}\n","import {\n isNpmAuditFlag,\n isNpmLoglevelFlag,\n isNpmNodeOptionsFlag,\n isNpmProgressFlag,\n} from '@socketsecurity/registry/lib/agent'\nimport { isDebug } from '@socketsecurity/registry/lib/debug'\nimport { getOwn } from '@socketsecurity/registry/lib/objects'\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport { installLinks } from './npm/link.mts'\nimport { ensureIpcInStdio } from './stdio-ipc.mts'\nimport constants, { NODE_MODULES, NPM, NPX } from '../constants.mts'\nimport { cmdFlagsToString } from '../utils/cmd.mts'\nimport { findUp } from '../utils/fs.mts'\nimport { getPublicApiToken } from '../utils/sdk.mts'\n\nimport type { IpcObject } from '../constants.mts'\nimport type {\n SpawnExtra,\n SpawnOptions,\n SpawnResult,\n} from '@socketsecurity/registry/lib/spawn'\n\nexport type ShadowBinOptions = SpawnOptions & {\n ipc?: IpcObject | undefined\n}\n\nexport type ShadowBinResult = {\n spawnPromise: SpawnResult<string, SpawnExtra | undefined>\n}\n\nexport default async function shadowNpmBase(\n binName: typeof NPM | typeof NPX,\n args: string[] | readonly string[] = process.argv.slice(2),\n options?: ShadowBinOptions | undefined,\n extra?: SpawnExtra | undefined,\n): Promise<ShadowBinResult> {\n const {\n env: spawnEnv,\n ipc,\n ...spawnOpts\n } = { __proto__: null, ...options } as ShadowBinOptions\n const cwd = getOwn(spawnOpts, 'cwd') ?? process.cwd()\n const isShadowNpm = binName === NPM\n const terminatorPos = args.indexOf('--')\n const rawBinArgs = terminatorPos === -1 ? args : args.slice(0, terminatorPos)\n const nodeOptionsArg = rawBinArgs.findLast(isNpmNodeOptionsFlag)\n const progressArg = rawBinArgs.findLast(isNpmProgressFlag) !== '--no-progress'\n const otherArgs = terminatorPos === -1 ? [] : args.slice(terminatorPos)\n const permArgs =\n isShadowNpm && constants.SUPPORTS_NODE_PERMISSION_FLAG\n ? [\n '--permission',\n '--allow-child-process',\n // '--allow-addons',\n // '--allow-wasi',\n // Allow all reads because npm walks up directories looking for config\n // and package.json files.\n '--allow-fs-read=*',\n `--allow-fs-write=${cwd}/*`,\n `--allow-fs-write=${constants.npmGlobalPrefix}/*`,\n `--allow-fs-write=${constants.npmCachePath}/*`,\n ]\n : []\n\n const useAudit = rawBinArgs.includes('--audit')\n const useDebug = isDebug('stdio')\n const useNodeOptions = nodeOptionsArg || permArgs.length\n const binArgs = rawBinArgs.filter(\n a => !isNpmAuditFlag(a) && !isNpmProgressFlag(a),\n )\n const isSilent = !useDebug && !binArgs.some(isNpmLoglevelFlag)\n // The default value of loglevel is \"notice\". We default to \"error\" which is\n // two levels quieter.\n const logLevelArgs = isSilent ? ['--loglevel', 'error'] : []\n const noAuditArgs =\n useAudit || !(await findUp(NODE_MODULES, { cwd, onlyDirectories: true }))\n ? []\n : ['--no-audit']\n\n const stdio = ensureIpcInStdio(getOwn(spawnOpts, 'stdio'))\n\n const realBinPath = await installLinks(constants.shadowBinPath, binName)\n\n const spawnPromise = spawn(\n constants.execPath,\n [\n ...constants.nodeNoWarningsFlags,\n ...constants.nodeDebugFlags,\n ...constants.nodeHardenFlags,\n ...constants.nodeMemoryFlags,\n ...(constants.ENV.INLINED_SOCKET_CLI_SENTRY_BUILD\n ? ['--require', constants.instrumentWithSentryPath]\n : []),\n '--require',\n constants.shadowNpmInjectPath,\n realBinPath,\n ...noAuditArgs,\n ...(useNodeOptions\n ? [\n `--node-options='${nodeOptionsArg ? nodeOptionsArg.slice(15) : ''}${cmdFlagsToString(permArgs)}'`,\n ]\n : []),\n '--no-fund',\n // Add '--no-progress' to fix input being swallowed by the npm spinner.\n '--no-progress',\n // Add '--loglevel=error' if a loglevel flag is not provided and the\n // SOCKET_CLI_DEBUG environment variable is not truthy.\n ...logLevelArgs,\n ...binArgs,\n ...otherArgs,\n ],\n {\n ...spawnOpts,\n env: {\n ...process.env,\n ...constants.processEnv,\n ...spawnEnv,\n },\n stdio,\n },\n extra,\n )\n\n spawnPromise.process.send({\n [constants.SOCKET_IPC_HANDSHAKE]: {\n [constants.SOCKET_CLI_SHADOW_API_TOKEN]: getPublicApiToken(),\n [constants.SOCKET_CLI_SHADOW_BIN]: binName,\n [constants.SOCKET_CLI_SHADOW_PROGRESS]: progressArg,\n ...ipc,\n },\n })\n\n return { spawnPromise }\n}\n","import { NPM } from '../../constants.mts'\nimport shadowNpmBase from '../npm-base.mts'\n\nimport type { ShadowBinOptions, ShadowBinResult } from '../npm-base.mts'\nimport type { SpawnExtra } from '@socketsecurity/registry/lib/spawn'\n\nexport type { ShadowBinOptions, ShadowBinResult }\n\nexport default async function shadowNpmBin(\n args: string[] | readonly string[] = process.argv.slice(2),\n options?: ShadowBinOptions | undefined,\n extra?: SpawnExtra | undefined,\n): Promise<ShadowBinResult> {\n return await shadowNpmBase(NPM, args, options, extra)\n}\n"],"names":["WIN32","env","__proto__","onlyDirectories","stdio","spawnPromise"],"mappings":";;;;;;;;;;;AAYO;AAIL;AACA;;;AAEQA;AAAM;AACd;;AAEE;AACF;;AAEA;;AAEE;;AAKA;;AACQC;AAAI;AACZA;AACF;AACA;AACF;;ACnCA;AACA;AACA;AACA;AACO;AAGL;;;AAGE;AACE;AACF;AACA;AACF;;AAEA;AACF;;ACae;;AAOXA;;;AAGF;AAAMC;;;AACN;AACA;AACA;AACA;AACA;;AAEA;;AAMQ;AACA;AACA;AACA;AACA;AAOR;AACA;AACA;AACA;;AAIA;AACA;;;;AAGkDC;AAAsB;;;AAQxE;AAoBI;;AAEA;AACA;;AAMA;AACAF;;;;;AAKAG;;AAKJC;;AAEI;AACA;AACA;;AAEF;AACF;;AAESA;;AACX;;AC/He;;AAMf;;;;","debugId":"2c1bb1bc-32c9-4dd7-8742-11961fead20c"}
1
+ {"version":3,"file":"shadow-npm-bin2.js","sources":["../src/shadow/stdio-ipc.mts","../src/shadow/npm-base.mts","../src/shadow/npm/bin.mts"],"sourcesContent":["import type { StdioOptions } from 'node:child_process'\n\n/**\n * Ensures stdio configuration includes IPC channel for process communication.\n * Converts various stdio formats to include 'ipc' as the fourth element.\n */\nexport function ensureIpcInStdio(\n stdio: StdioOptions | undefined,\n): StdioOptions {\n if (typeof stdio === 'string') {\n return [stdio, stdio, stdio, 'ipc']\n } else if (Array.isArray(stdio)) {\n if (!stdio.includes('ipc')) {\n return stdio.concat('ipc')\n }\n return stdio\n } else {\n return ['pipe', 'pipe', 'pipe', 'ipc']\n }\n}\n","import { fileURLToPath } from 'node:url'\n\nimport {\n isNpmAuditFlag,\n isNpmLoglevelFlag,\n isNpmNodeOptionsFlag,\n isNpmProgressFlag,\n} from '@socketsecurity/registry/lib/agent'\nimport { isDebug } from '@socketsecurity/registry/lib/debug'\nimport { getOwn } from '@socketsecurity/registry/lib/objects'\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport { ensureIpcInStdio } from './stdio-ipc.mts'\nimport constants, {\n FLAG_LOGLEVEL,\n NODE_MODULES,\n NPM,\n NPX,\n} from '../constants.mts'\nimport { cmdFlagsToString } from '../utils/cmd.mts'\nimport { findUp } from '../utils/fs.mts'\nimport { getPublicApiToken } from '../utils/sdk.mts'\nimport { installNpmLinks, installNpxLinks } from '../utils/shadow-links.mts'\n\nimport type { IpcObject } from '../constants.mts'\nimport type {\n SpawnExtra,\n SpawnOptions,\n SpawnResult,\n} from '@socketsecurity/registry/lib/spawn'\n\nexport type ShadowBinOptions = SpawnOptions & {\n ipc?: IpcObject | undefined\n}\n\nexport type ShadowBinResult = {\n spawnPromise: SpawnResult<string, SpawnExtra | undefined>\n}\n\nexport default async function shadowNpmBase(\n binName: typeof NPM | typeof NPX,\n args: string[] | readonly string[] = process.argv.slice(2),\n options?: ShadowBinOptions | undefined,\n extra?: SpawnExtra | undefined,\n): Promise<ShadowBinResult> {\n const {\n env: spawnEnv,\n ipc,\n ...spawnOpts\n } = { __proto__: null, ...options } as ShadowBinOptions\n\n let cwd = getOwn(spawnOpts, 'cwd') ?? process.cwd()\n if (cwd instanceof URL) {\n cwd = fileURLToPath(cwd)\n }\n\n const isShadowNpm = binName === NPM\n const terminatorPos = args.indexOf('--')\n const rawBinArgs = terminatorPos === -1 ? args : args.slice(0, terminatorPos)\n const nodeOptionsArg = rawBinArgs.findLast(isNpmNodeOptionsFlag)\n const progressArg = rawBinArgs.findLast(isNpmProgressFlag) !== '--no-progress'\n const otherArgs = terminatorPos === -1 ? [] : args.slice(terminatorPos)\n const permArgs =\n isShadowNpm && constants.SUPPORTS_NODE_PERMISSION_FLAG\n ? [\n '--permission',\n '--allow-child-process',\n // '--allow-addons',\n // '--allow-wasi',\n // Allow all reads because npm walks up directories looking for config\n // and package.json files.\n '--allow-fs-read=*',\n `--allow-fs-write=${cwd}/*`,\n `--allow-fs-write=${constants.npmGlobalPrefix}/*`,\n `--allow-fs-write=${constants.npmCachePath}/*`,\n ]\n : []\n\n const useAudit = rawBinArgs.includes('--audit')\n const useDebug = isDebug('stdio')\n const useNodeOptions = nodeOptionsArg || permArgs.length\n const binArgs = rawBinArgs.filter(\n a => !isNpmAuditFlag(a) && !isNpmProgressFlag(a),\n )\n const isSilent = !useDebug && !binArgs.some(isNpmLoglevelFlag)\n // The default value of loglevel is \"notice\". We default to \"error\" which is\n // two levels quieter.\n const logLevelArgs = isSilent ? [FLAG_LOGLEVEL, 'error'] : []\n const noAuditArgs =\n useAudit || !(await findUp(NODE_MODULES, { cwd, onlyDirectories: true }))\n ? []\n : ['--no-audit']\n\n const stdio = ensureIpcInStdio(getOwn(spawnOpts, 'stdio'))\n\n const realBinPath = isShadowNpm\n ? await installNpmLinks(constants.shadowBinPath)\n : await installNpxLinks(constants.shadowBinPath)\n\n const spawnPromise = spawn(\n constants.execPath,\n [\n ...constants.nodeNoWarningsFlags,\n ...constants.nodeDebugFlags,\n ...constants.nodeHardenFlags,\n ...constants.nodeMemoryFlags,\n ...(constants.ENV.INLINED_SOCKET_CLI_SENTRY_BUILD\n ? ['--require', constants.instrumentWithSentryPath]\n : []),\n '--require',\n constants.shadowNpmInjectPath,\n realBinPath,\n ...noAuditArgs,\n ...(useNodeOptions\n ? [\n `--node-options='${nodeOptionsArg ? nodeOptionsArg.slice(15) : ''}${cmdFlagsToString(permArgs)}'`,\n ]\n : []),\n '--no-fund',\n // Add '--no-progress' to fix input being swallowed by the npm spinner.\n '--no-progress',\n // Add '--loglevel=error' if a loglevel flag is not provided and the\n // SOCKET_CLI_DEBUG environment variable is not truthy.\n ...logLevelArgs,\n ...binArgs,\n ...otherArgs,\n ],\n {\n ...spawnOpts,\n env: {\n ...process.env,\n ...constants.processEnv,\n ...spawnEnv,\n },\n stdio,\n },\n extra,\n )\n\n spawnPromise.process.send({\n [constants.SOCKET_IPC_HANDSHAKE]: {\n [constants.SOCKET_CLI_SHADOW_API_TOKEN]: getPublicApiToken(),\n [constants.SOCKET_CLI_SHADOW_BIN]: binName,\n [constants.SOCKET_CLI_SHADOW_PROGRESS]: progressArg,\n ...ipc,\n },\n })\n\n return { spawnPromise }\n}\n","import { NPM } from '../../constants.mts'\nimport shadowNpmBase from '../npm-base.mts'\n\nimport type { ShadowBinOptions, ShadowBinResult } from '../npm-base.mts'\nimport type { SpawnExtra } from '@socketsecurity/registry/lib/spawn'\n\nexport type { ShadowBinOptions, ShadowBinResult }\n\nexport default async function shadowNpmBin(\n args: string[] | readonly string[] = process.argv.slice(2),\n options?: ShadowBinOptions | undefined,\n extra?: SpawnExtra | undefined,\n): Promise<ShadowBinResult> {\n return await shadowNpmBase(NPM, args, options, extra)\n}\n"],"names":["env","__proto__","cwd","onlyDirectories","stdio","spawnPromise"],"mappings":";;;;;;;;;;AAEA;AACA;AACA;AACA;AACO;AAGL;;;AAGE;AACE;AACF;AACA;AACF;;AAEA;AACF;;ACoBe;;AAOXA;;;AAGF;AAAMC;;;AAEN;;AAEEC;AACF;AAEA;AACA;AACA;AACA;;AAEA;;AAMQ;AACA;AACA;AACA;AACA;AAOR;AACA;AACA;AACA;;AAIA;AACA;;;;AAGkDC;AAAsB;;AAMxE;AAIA;AAoBI;;AAEA;AACA;;AAMA;AACAH;;;;;AAKAI;;AAKJC;;AAEI;AACA;AACA;;AAEF;AACF;;AAESA;;AACX;;AC7Ie;;AAMf;;;;","debugId":"6d18cbc8-e145-4f23-9c89-eb5694f263dd"}
@@ -8,23 +8,23 @@ var logger = require('../external/@socketsecurity/registry/lib/logger');
8
8
  var spawn = require('../external/@socketsecurity/registry/lib/spawn');
9
9
  var constants = require('./constants.js');
10
10
  var utils = require('./utils.js');
11
+ var packages = require('../external/@socketsecurity/registry/lib/packages');
11
12
  var shadowNpmBin = require('./shadow-npm-bin2.js');
12
- var vendor = require('./vendor.js');
13
13
 
14
14
  /**
15
- * Extract package PURLs from add/dlx command arguments.
15
+ * Extract package PURLs from command arguments for add/dlx commands where
16
+ * packages are specified as arguments.
17
+ * Used by: pnpm, yarn.
16
18
  */
17
- function extractPackagePurlsFromArgs(command, rawArgs, dlxCommands) {
19
+ function extractPackagePurlsFromCommandArgs(rawArgs) {
18
20
  const packagePurls = [];
19
- const isDlxCommand = dlxCommands?.has(command);
20
- if (command === 'add' || isDlxCommand) {
21
- // For 'add package1 package2@version' or 'dlx package', get packages from args.
22
- const packageArgs = rawArgs.slice(1).filter(arg => !arg.startsWith('-') && arg !== '--');
23
- for (const pkgSpec of packageArgs) {
24
- const purl = utils.safeNpmSpecToPurl(pkgSpec);
25
- if (purl) {
26
- packagePurls.push(purl);
27
- }
21
+
22
+ // For 'add package1 package2@version' or 'dlx package', get packages from args.
23
+ const packageArgs = rawArgs.slice(1).filter(a => !a.startsWith('-') && a !== '--');
24
+ for (const pkgSpec of packageArgs) {
25
+ const purl = utils.safeNpmSpecToPurl(pkgSpec);
26
+ if (purl) {
27
+ packagePurls.push(purl);
28
28
  }
29
29
  }
30
30
  return packagePurls;
@@ -32,19 +32,22 @@ function extractPackagePurlsFromArgs(command, rawArgs, dlxCommands) {
32
32
 
33
33
  /**
34
34
  * Extract package PURLs from package.json for install/update commands.
35
+ * Used by: pnpm, yarn.
35
36
  */
36
- async function extractPackagePurlsFromPackageJson(cwd) {
37
+ async function extractPackagePurlsFromPackageJson(cwd = process.cwd()) {
37
38
  const packagePurls = [];
38
39
  try {
39
- const packageJsonContent = await fs.promises.readFile(`${cwd}/package.json`, 'utf8');
40
- const packageJson = JSON.parse(packageJsonContent);
40
+ const pkgJson = await packages.readPackageJson(cwd);
41
41
  const allDeps = {
42
- ...packageJson.dependencies,
43
- ...packageJson.devDependencies,
44
- ...packageJson.optionalDependencies,
45
- ...packageJson.peerDependencies
42
+ ...pkgJson.dependencies,
43
+ ...pkgJson.devDependencies,
44
+ ...pkgJson.optionalDependencies,
45
+ ...pkgJson.peerDependencies
46
46
  };
47
- for (const [name, version] of Object.entries(allDeps)) {
47
+ for (const {
48
+ 0: name,
49
+ 1: version
50
+ } of Object.entries(allDeps)) {
48
51
  const purl = utils.safeNpmSpecToPurl(typeof version === 'string' ? `${name}@${version}` : name);
49
52
  if (purl) {
50
53
  packagePurls.push(purl);
@@ -52,7 +55,7 @@ async function extractPackagePurlsFromPackageJson(cwd) {
52
55
  }
53
56
  utils.debugScan('start', packagePurls.length);
54
57
  } catch (e) {
55
- require$$9.debugFn('warn', 'Package.json not found or invalid during dependency scanning');
58
+ require$$9.debugFn('warn', `${constants.PACKAGE_JSON} not found or invalid during dependency scanning`);
56
59
  require$$9.debugDir('error', e);
57
60
  }
58
61
  return packagePurls;
@@ -91,8 +94,8 @@ async function scanPackagesAndLogAlerts(options) {
91
94
 
92
95
  // Extract package names from command arguments before any downloads.
93
96
  let packagePurls = [];
94
- if (command === 'add' || isDlxCommand) {
95
- packagePurls = extractPackagePurlsFromArgs(command, rawArgs, dlxCommands);
97
+ if (isDlxCommand || utils.isAddCommand(command)) {
98
+ packagePurls = extractPackagePurlsFromCommandArgs(rawArgs);
96
99
  } else if (isInstallCommand) {
97
100
  // For install/update, scan dependencies from package.json.
98
101
  // Note: This scans direct dependencies only.
@@ -150,32 +153,6 @@ async function scanPackagesAndLogAlerts(options) {
150
153
  };
151
154
  }
152
155
 
153
- async function installLinks(shadowBinPath, _binName) {
154
- // Find pnpm being shadowed by this process.
155
- const binPath = utils.getPnpmBinPath();
156
- const {
157
- WIN32
158
- } = constants.default;
159
-
160
- // TODO: Is this early exit needed?
161
- if (WIN32 && binPath) {
162
- return binPath;
163
- }
164
- const shadowed = utils.isPnpmBinPathShadowed();
165
-
166
- // Move our bin directory to front of PATH so its found first.
167
- if (!shadowed) {
168
- if (WIN32) {
169
- await vendor.libExports(path.join(constants.default.distPath, 'pnpm-cli.js'), path.join(shadowBinPath, 'pnpm'));
170
- }
171
- const {
172
- env
173
- } = process;
174
- env['PATH'] = `${shadowBinPath}${path.delimiter}${env['PATH']}`;
175
- }
176
- return binPath;
177
- }
178
-
179
156
  const DLX_COMMANDS = new Set(['dlx']);
180
157
  const INSTALL_COMMANDS = new Set(['add', 'i', 'install', 'install-test', 'it', 'update', 'up']);
181
158
  async function shadowPnpmBin(args = process.argv.slice(2), options, extra) {
@@ -188,11 +165,6 @@ async function shadowPnpmBin(args = process.argv.slice(2), options, extra) {
188
165
  ipc,
189
166
  ...spawnOpts
190
167
  } = opts;
191
- const {
192
- spinner
193
- } = opts;
194
- const wasSpinning = !!spinner?.isSpinning;
195
- spinner?.start();
196
168
  let {
197
169
  cwd = process.cwd()
198
170
  } = opts;
@@ -201,26 +173,30 @@ async function shadowPnpmBin(args = process.argv.slice(2), options, extra) {
201
173
  }
202
174
  const terminatorPos = args.indexOf('--');
203
175
  const rawPnpmArgs = terminatorPos === -1 ? args : args.slice(0, terminatorPos);
204
- const otherArgs = terminatorPos === -1 ? [] : args.slice(terminatorPos);
176
+ const {
177
+ spinner
178
+ } = opts;
179
+ const wasSpinning = !!spinner?.isSpinning;
205
180
 
206
181
  // Check if this is a command that needs security scanning.
207
182
  const command = rawPnpmArgs[0];
208
183
  const isDlxCommand = command && DLX_COMMANDS.has(command);
209
184
  const isInstallCommand = command && INSTALL_COMMANDS.has(command);
210
185
  const needsScanning = isDlxCommand || isInstallCommand;
186
+ spinner?.start();
211
187
  if (needsScanning && !rawPnpmArgs.includes(constants.FLAG_DRY_RUN)) {
212
188
  const acceptRisks = !!constants.default.ENV.SOCKET_CLI_ACCEPT_RISKS;
213
189
  const viewAllRisks = !!constants.default.ENV.SOCKET_CLI_VIEW_ALL_RISKS;
214
190
 
215
191
  // Handle add and dlx commands with shared utility.
216
- if (command === 'add' || isDlxCommand) {
192
+ if (isDlxCommand || utils.isAddCommand(command)) {
217
193
  const scanResult = await scanPackagesAndLogAlerts({
218
194
  acceptRisks,
219
195
  command,
220
196
  cwd,
221
197
  dlxCommands: DLX_COMMANDS,
222
198
  installCommands: INSTALL_COMMANDS,
223
- managerName: 'pnpm',
199
+ managerName: constants.PNPM,
224
200
  rawArgs: rawPnpmArgs,
225
201
  spinner,
226
202
  viewAllRisks
@@ -231,7 +207,7 @@ async function shadowPnpmBin(args = process.argv.slice(2), options, extra) {
231
207
  // This line is never reached in production, but helps tests.
232
208
  throw new Error('process.exit called');
233
209
  }
234
- } else if (['install', 'i', 'update', 'up'].includes(command)) {
210
+ } else if (utils.isPnpmLockfileScanCommand(command)) {
235
211
  // For install/update, scan all dependencies from pnpm-lock.yaml
236
212
  const pnpmLockPath = path.join(cwd, constants.PNPM_LOCK_YAML);
237
213
  if (fs.existsSync(pnpmLockPath)) {
@@ -258,7 +234,7 @@ async function shadowPnpmBin(args = process.argv.slice(2), options, extra) {
258
234
  hideAt: viewAllRisks ? 'none' : 'middle',
259
235
  output: process.stderr
260
236
  });
261
- const errorMessage = `Socket pnpm exiting due to risks.${viewAllRisks ? '' : `\nView all risks - Rerun with environment variable ${constants.default.SOCKET_CLI_VIEW_ALL_RISKS}=1.`}${acceptRisks ? '' : `\nAccept risks - Rerun with environment variable ${constants.default.SOCKET_CLI_ACCEPT_RISKS}=1.`}`.trim();
237
+ const errorMessage = `Socket ${constants.PNPM} exiting due to risks.${viewAllRisks ? '' : `\nView all risks - Rerun with environment variable ${constants.default.SOCKET_CLI_VIEW_ALL_RISKS}=1.`}${acceptRisks ? '' : `\nAccept risks - Rerun with environment variable ${constants.default.SOCKET_CLI_ACCEPT_RISKS}=1.`}`.trim();
262
238
  logger.logger.error(errorMessage);
263
239
  // eslint-disable-next-line n/no-process-exit
264
240
  process.exit(1);
@@ -271,17 +247,17 @@ async function shadowPnpmBin(args = process.argv.slice(2), options, extra) {
271
247
  }
272
248
  }
273
249
  } catch (e) {
274
- require$$9.debugFn('error', 'PNPM lockfile scanning failed');
250
+ require$$9.debugFn('error', `${constants.PNPM} lockfile scanning failed`);
275
251
  require$$9.debugDir('error', e);
276
252
  }
277
253
  } else {
278
- require$$9.debugFn('notice', 'skip: no pnpm-lock.yaml found, skipping bulk install scanning');
254
+ require$$9.debugFn('notice', `skip: no ${constants.PNPM_LOCK_YAML} found, skipping bulk install scanning`);
279
255
  }
280
256
  }
281
257
  require$$9.debugFn('notice', 'complete: scanning, proceeding with install');
282
258
  }
283
- const realPnpmPath = await installLinks(constants.default.shadowBinPath);
284
- spinner?.stop();
259
+ const realPnpmPath = await utils.installPnpmLinks(constants.default.shadowBinPath);
260
+ const otherArgs = terminatorPos === -1 ? [] : args.slice(terminatorPos);
285
261
  const suffixArgs = [...rawPnpmArgs, ...otherArgs];
286
262
  require$$9.debugFn('notice', `spawn: ${constants.PNPM} shadow bin ${realPnpmPath} ${utils.cmdFlagsToString(suffixArgs)}`);
287
263
  if (wasSpinning) {
@@ -292,6 +268,7 @@ async function shadowPnpmBin(args = process.argv.slice(2), options, extra) {
292
268
  const stdio = shadowNpmBin.ensureIpcInStdio(spawnOpts.stdio);
293
269
  const spawnPromise = spawn.spawn(realPnpmPath, suffixArgs, {
294
270
  ...spawnOpts,
271
+ cwd,
295
272
  env: {
296
273
  ...process.env,
297
274
  ...spawnEnv
@@ -319,5 +296,5 @@ async function shadowPnpmBin(args = process.argv.slice(2), options, extra) {
319
296
 
320
297
  exports.scanPackagesAndLogAlerts = scanPackagesAndLogAlerts;
321
298
  exports.shadowPnpmBin = shadowPnpmBin;
322
- //# debugId=cdf92b11-1bc1-407a-8db7-38adcb6998cc
299
+ //# debugId=b4cf863e-3d5c-4dcc-ad18-e70648911b2
323
300
  //# sourceMappingURL=shadow-pnpm-bin2.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shadow-pnpm-bin2.js","sources":["../src/shadow/common.mts","../src/shadow/pnpm/link.mts","../src/shadow/pnpm/bin.mts"],"sourcesContent":["import { promises as fs } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\n\nimport { debugDir, debugFn } from '@socketsecurity/registry/lib/debug'\nimport { logger } from '@socketsecurity/registry/lib/logger'\n\nimport constants, { FLAG_DRY_RUN } from '../constants.mts'\nimport { getAlertsMapFromPurls } from '../utils/alerts-map.mts'\nimport { debugScan } from '../utils/debug.mts'\nimport { safeNpmSpecToPurl } from '../utils/npm-spec.mts'\nimport { logAlertsMap } from '../utils/socket-package-alert.mts'\n\nimport type { AlertsByPurl } from '../utils/socket-package-alert.mts'\nimport type { Spinner } from '@socketsecurity/registry/lib/spinner'\n\n/**\n * Extract package PURLs from add/dlx command arguments.\n */\nexport function extractPackagePurlsFromArgs(\n command: string,\n rawArgs: string[] | readonly string[],\n dlxCommands?: Set<string>,\n): string[] {\n const packagePurls: string[] = []\n const isDlxCommand = dlxCommands?.has(command)\n\n if (command === 'add' || isDlxCommand) {\n // For 'add package1 package2@version' or 'dlx package', get packages from args.\n const packageArgs = rawArgs\n .slice(1)\n .filter(arg => !arg.startsWith('-') && arg !== '--')\n\n for (const pkgSpec of packageArgs) {\n const purl = safeNpmSpecToPurl(pkgSpec)\n if (purl) {\n packagePurls.push(purl)\n }\n }\n }\n\n return packagePurls\n}\n\n/**\n * Extract package PURLs from package.json for install/update commands.\n */\nexport async function extractPackagePurlsFromPackageJson(\n cwd: string,\n): Promise<string[]> {\n const packagePurls: string[] = []\n\n try {\n const packageJsonContent = await fs.readFile(`${cwd}/package.json`, 'utf8')\n const packageJson = JSON.parse(packageJsonContent)\n\n const allDeps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n ...packageJson.optionalDependencies,\n ...packageJson.peerDependencies,\n }\n\n for (const [name, version] of Object.entries(allDeps)) {\n const purl = safeNpmSpecToPurl(\n typeof version === 'string' ? `${name}@${version}` : name,\n )\n if (purl) {\n packagePurls.push(purl)\n }\n }\n\n debugScan('start', packagePurls.length)\n } catch (e) {\n debugFn(\n 'warn',\n 'Package.json not found or invalid during dependency scanning',\n )\n debugDir('error', e)\n }\n\n return packagePurls\n}\n\nexport type PackageScanOptions = {\n acceptRisks: boolean\n command: string | undefined\n cwd?: string | URL\n dlxCommands?: Set<string>\n installCommands: Set<string>\n managerName: string\n nothrow?: boolean\n rawArgs: string[] | readonly string[]\n spinner?: Spinner | undefined\n viewAllRisks: boolean\n}\n\nexport type PackageScanResult = {\n alertsMap?: AlertsByPurl\n shouldExit: boolean\n}\n\n/**\n * Scan packages and log alerts if found.\n */\nexport async function scanPackagesAndLogAlerts(\n options: PackageScanOptions,\n): Promise<PackageScanResult> {\n const {\n acceptRisks,\n command,\n dlxCommands,\n installCommands,\n managerName,\n nothrow = true,\n rawArgs,\n spinner,\n viewAllRisks,\n } = options\n\n let { cwd = process.cwd() } = options\n if (cwd instanceof URL) {\n cwd = fileURLToPath(cwd)\n }\n\n // Check if this is a command that needs security scanning.\n const isDlxCommand = dlxCommands && command && dlxCommands.has(command)\n const isInstallCommand = command && installCommands.has(command)\n const needsScanning = isDlxCommand || isInstallCommand\n\n if (!needsScanning || rawArgs.includes(FLAG_DRY_RUN)) {\n return { shouldExit: false }\n }\n\n // Extract package names from command arguments before any downloads.\n let packagePurls: string[] = []\n\n if (command === 'add' || isDlxCommand) {\n packagePurls = extractPackagePurlsFromArgs(command, rawArgs, dlxCommands)\n } else if (isInstallCommand) {\n // For install/update, scan dependencies from package.json.\n // Note: This scans direct dependencies only.\n packagePurls = await extractPackagePurlsFromPackageJson(cwd)\n }\n\n if (!packagePurls.length) {\n return { shouldExit: false }\n }\n\n debugScan('start', packagePurls.length)\n debugDir('inspect', { packagePurls })\n\n try {\n const alertsMap = await getAlertsMapFromPurls(packagePurls, {\n filter: acceptRisks\n ? { actions: ['error'], blocked: true }\n : { actions: ['error', 'monitor', 'warn'] },\n nothrow,\n spinner,\n })\n\n if (alertsMap.size) {\n process.exitCode = 1\n spinner?.stop()\n logAlertsMap(alertsMap, {\n hideAt: viewAllRisks ? 'none' : 'middle',\n output: process.stderr,\n })\n\n const errorMessage = `Socket ${managerName} exiting due to risks.${\n viewAllRisks\n ? ''\n : `\\nView all risks - Rerun with environment variable ${constants.SOCKET_CLI_VIEW_ALL_RISKS}=1.`\n }${\n acceptRisks\n ? ''\n : `\\nAccept risks - Rerun with environment variable ${constants.SOCKET_CLI_ACCEPT_RISKS}=1.`\n }`.trim()\n\n logger.error(errorMessage)\n return { alertsMap, shouldExit: true }\n }\n } catch (e) {\n spinner?.stop()\n // Re-throw process.exit errors from tests.\n if (e instanceof Error && e.message === 'process.exit called') {\n throw e\n }\n debugScan('error', undefined, e)\n // Continue with installation if scanning fails.\n }\n\n debugScan('complete', packagePurls.length)\n debugDir('inspect', { args: rawArgs.slice(1) })\n\n return { shouldExit: false }\n}\n","import path from 'node:path'\n\nimport cmdShim from 'cmd-shim'\n\nimport constants from '../../constants.mts'\nimport {\n getPnpmBinPath,\n isPnpmBinPathShadowed,\n} from '../../utils/pnpm-paths.mts'\n\nexport async function installLinks(\n shadowBinPath: string,\n _binName: 'pnpm',\n): Promise<string> {\n // Find pnpm being shadowed by this process.\n const binPath = getPnpmBinPath()\n const { WIN32 } = constants\n\n // TODO: Is this early exit needed?\n if (WIN32 && binPath) {\n return binPath\n }\n\n const shadowed = isPnpmBinPathShadowed()\n\n // Move our bin directory to front of PATH so its found first.\n if (!shadowed) {\n if (WIN32) {\n await cmdShim(\n path.join(constants.distPath, 'pnpm-cli.js'),\n path.join(shadowBinPath, 'pnpm'),\n )\n }\n const { env } = process\n env['PATH'] = `${shadowBinPath}${path.delimiter}${env['PATH']}`\n }\n\n return binPath\n}\n","import { existsSync } from 'node:fs'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nimport { debugDir, debugFn } from '@socketsecurity/registry/lib/debug'\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport { scanPackagesAndLogAlerts } from '../common.mts'\nimport { ensureIpcInStdio } from '../stdio-ipc.mts'\nimport { installLinks } from './link.mts'\nimport constants, {\n FLAG_DRY_RUN,\n PNPM,\n PNPM_LOCK_YAML,\n} from '../../constants.mts'\nimport { getAlertsMapFromPnpmLockfile } from '../../utils/alerts-map.mts'\nimport { cmdFlagsToString } from '../../utils/cmd.mts'\nimport { parsePnpmLockfile, readPnpmLockfile } from '../../utils/pnpm.mts'\nimport { getPublicApiToken } from '../../utils/sdk.mts'\nimport { logAlertsMap } from '../../utils/socket-package-alert.mts'\n\nimport type { IpcObject } from '../../constants.mts'\nimport type {\n SpawnExtra,\n SpawnOptions,\n SpawnResult,\n} from '@socketsecurity/registry/lib/spawn'\n\nexport type ShadowPnpmOptions = SpawnOptions & {\n ipc?: IpcObject | undefined\n}\n\nexport type ShadowPnpmResult = {\n spawnPromise: SpawnResult<string, SpawnExtra | undefined>\n}\n\nconst DLX_COMMANDS = new Set(['dlx'])\n\nconst INSTALL_COMMANDS = new Set([\n 'add',\n 'i',\n 'install',\n 'install-test',\n 'it',\n 'update',\n 'up',\n])\n\nexport default async function shadowPnpmBin(\n args: string[] | readonly string[] = process.argv.slice(2),\n options?: ShadowPnpmOptions | undefined,\n extra?: SpawnExtra | undefined,\n): Promise<ShadowPnpmResult> {\n const opts = { __proto__: null, ...options } as ShadowPnpmOptions\n const { env: spawnEnv, ipc, ...spawnOpts } = opts\n const { spinner } = opts\n\n const wasSpinning = !!spinner?.isSpinning\n\n spinner?.start()\n\n let { cwd = process.cwd() } = opts\n if (cwd instanceof URL) {\n cwd = fileURLToPath(cwd)\n }\n\n const terminatorPos = args.indexOf('--')\n const rawPnpmArgs = terminatorPos === -1 ? args : args.slice(0, terminatorPos)\n const otherArgs = terminatorPos === -1 ? [] : args.slice(terminatorPos)\n\n // Check if this is a command that needs security scanning.\n const command = rawPnpmArgs[0]\n const isDlxCommand = command && DLX_COMMANDS.has(command)\n const isInstallCommand = command && INSTALL_COMMANDS.has(command)\n const needsScanning = isDlxCommand || isInstallCommand\n\n if (needsScanning && !rawPnpmArgs.includes(FLAG_DRY_RUN)) {\n const acceptRisks = !!constants.ENV.SOCKET_CLI_ACCEPT_RISKS\n const viewAllRisks = !!constants.ENV.SOCKET_CLI_VIEW_ALL_RISKS\n\n // Handle add and dlx commands with shared utility.\n if (command === 'add' || isDlxCommand) {\n const scanResult = await scanPackagesAndLogAlerts({\n acceptRisks,\n command,\n cwd,\n dlxCommands: DLX_COMMANDS,\n installCommands: INSTALL_COMMANDS,\n managerName: 'pnpm',\n rawArgs: rawPnpmArgs,\n spinner,\n viewAllRisks,\n })\n\n if (scanResult.shouldExit) {\n // eslint-disable-next-line n/no-process-exit\n process.exit(1)\n // This line is never reached in production, but helps tests.\n throw new Error('process.exit called')\n }\n } else if (['install', 'i', 'update', 'up'].includes(command)) {\n // For install/update, scan all dependencies from pnpm-lock.yaml\n const pnpmLockPath = path.join(cwd, PNPM_LOCK_YAML)\n if (existsSync(pnpmLockPath)) {\n try {\n const lockfileContent = await readPnpmLockfile(pnpmLockPath)\n if (lockfileContent) {\n const lockfile = parsePnpmLockfile(lockfileContent)\n if (lockfile) {\n // Use existing function to scan the entire lockfile\n debugFn(\n 'notice',\n `scanning: all dependencies from ${PNPM_LOCK_YAML}`,\n )\n\n const alertsMap = await getAlertsMapFromPnpmLockfile(lockfile, {\n nothrow: true,\n filter: acceptRisks\n ? { actions: ['error'], blocked: true }\n : { actions: ['error', 'monitor', 'warn'] },\n })\n\n spinner?.stop()\n\n if (alertsMap.size) {\n process.exitCode = 1\n logAlertsMap(alertsMap, {\n hideAt: viewAllRisks ? 'none' : 'middle',\n output: process.stderr,\n })\n\n const errorMessage = `Socket pnpm exiting due to risks.${\n viewAllRisks\n ? ''\n : `\\nView all risks - Rerun with environment variable ${constants.SOCKET_CLI_VIEW_ALL_RISKS}=1.`\n }${\n acceptRisks\n ? ''\n : `\\nAccept risks - Rerun with environment variable ${constants.SOCKET_CLI_ACCEPT_RISKS}=1.`\n }`.trim()\n\n logger.error(errorMessage)\n // eslint-disable-next-line n/no-process-exit\n process.exit(1)\n // This line is never reached in production, but helps tests.\n throw new Error('process.exit called')\n }\n\n // Return early since we've already done the scanning\n debugFn(\n 'notice',\n 'complete: lockfile scanning, proceeding with install',\n )\n }\n }\n } catch (e) {\n debugFn('error', 'PNPM lockfile scanning failed')\n debugDir('error', e)\n }\n } else {\n debugFn(\n 'notice',\n 'skip: no pnpm-lock.yaml found, skipping bulk install scanning',\n )\n }\n }\n\n debugFn('notice', 'complete: scanning, proceeding with install')\n }\n\n const realPnpmPath = await installLinks(constants.shadowBinPath, PNPM)\n\n spinner?.stop()\n\n const suffixArgs = [...rawPnpmArgs, ...otherArgs]\n\n debugFn(\n 'notice',\n `spawn: ${PNPM} shadow bin ${realPnpmPath} ${cmdFlagsToString(suffixArgs)}`,\n )\n\n if (wasSpinning) {\n spinner?.start()\n }\n\n // Set up stdio with IPC channel.\n const stdio = ensureIpcInStdio(spawnOpts.stdio)\n\n const spawnPromise = spawn(\n realPnpmPath,\n suffixArgs,\n {\n ...spawnOpts,\n env: {\n ...process.env,\n ...spawnEnv,\n },\n stdio,\n // On Windows, pnpm is often a .cmd file that requires shell execution.\n // The spawn function from @socketsecurity/registry will handle this properly\n // when shell is true.\n shell: constants.WIN32,\n },\n extra,\n )\n\n // Send IPC handshake.\n spawnPromise.process.send({\n [constants.SOCKET_IPC_HANDSHAKE]: {\n [constants.SOCKET_CLI_SHADOW_API_TOKEN]: getPublicApiToken(),\n [constants.SOCKET_CLI_SHADOW_BIN]: PNPM,\n [constants.SOCKET_CLI_SHADOW_PROGRESS]: true,\n ...ipc,\n },\n })\n\n return { spawnPromise }\n}\n"],"names":["packagePurls","debugScan","debugFn","debugDir","nothrow","viewAllRisks","cwd","shouldExit","blocked","actions","spinner","hideAt","logger","args","WIN32","env","__proto__","dlxCommands","installCommands","managerName","rawArgs","process","spawnPromise"],"mappings":";;;;;;;;;;;;;AAeA;AACA;AACA;AACO;;AAML;AAEA;AACE;;AAKA;AACE;AACA;AACEA;AACF;AACF;AACF;AAEA;AACF;;AAEA;AACA;AACA;AACO;;;AAMH;AACA;AAEA;;;;AAIE;;AAGF;AACE;AAGA;AACEA;AACF;AACF;AAEAC;;AAEAC;AAIAC;AACF;AAEA;AACF;AAoBA;AACA;AACA;AACO;;;;;;;AASHC;;;AAGAC;AACF;;AAEMC;AAAoB;;AAExBA;AACF;;AAEA;;;AAGA;;;AAGWC;;AACX;;AAEA;;AAGA;;;AAGE;AACA;AACAP;AACF;AAEA;;AACWO;;AACX;AAEAN;;AACsBD;AAAa;;AAGjC;;;AAE4BQ;AAAc;AAClCC;;;AAENC;AACF;;;;;AAMIC;;AAEF;AAEA;AAUAC;;;AACoBL;;AACtB;;;AAGA;;AAEE;AACF;AACAN;AACA;AACF;AAEAA;;AACsBY;AAAuB;;AAEpCN;;AACX;;ACzLO;AAIL;AACA;;AACQO;AAAM;;AAEd;;AAEE;AACF;AAEA;;AAEA;;AAEE;;AAKA;;AACQC;AAAI;AACZA;AACF;AAEA;AACF;;ACDA;AAEA;AAUe;AAKb;AAAeC;;;;AACPD;;;AAAiC;;AACjCL;AAAQ;AAEhB;;;AAIMJ;AAAoB;;AAExBA;AACF;AAEA;AACA;AACA;;AAEA;AACA;;;AAGA;;;;;AAME;AACA;AACE;;;;AAIEW;AACAC;AACAC;AACAC;;AAEAf;AACF;;AAGE;AACAgB;AACA;AACA;AACF;AACF;AACE;;AAEA;;AAEI;AACA;AACE;AACA;AACE;AACAnB;AAKA;AACEE;;;AAE0BI;AAAc;AAClCC;AAAsC;AAC9C;;;;;AAOIE;;AAEF;;AAYAC;AACA;AACAS;AACA;AACA;AACF;;AAEA;AACAnB;AAIF;AACF;;AAEAA;AACAC;AACF;AACF;AACED;AAIF;AACF;AAEAA;AACF;;;;AAQAA;AAKA;;AAEA;;AAEA;AACA;AAEA;AAII;AACAa;;;;;AAKA;AACA;AACA;;;;AAMJ;AACAO;;AAEI;AACA;AACA;;AAEF;AACF;;AAESA;;AACX;;;","debugId":"cdf92b11-1bc1-407a-8db7-38adcb6998cc"}
1
+ {"version":3,"file":"shadow-pnpm-bin2.js","sources":["../src/shadow/common.mts","../src/shadow/pnpm/bin.mts"],"sourcesContent":["import { fileURLToPath } from 'node:url'\n\nimport { debugDir, debugFn } from '@socketsecurity/registry/lib/debug'\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { readPackageJson } from '@socketsecurity/registry/lib/packages'\n\nimport constants, { FLAG_DRY_RUN, PACKAGE_JSON } from '../constants.mts'\nimport { getAlertsMapFromPurls } from '../utils/alerts-map.mts'\nimport { isAddCommand } from '../utils/cmd.mts'\nimport { debugScan } from '../utils/debug.mts'\nimport { safeNpmSpecToPurl } from '../utils/npm-spec.mts'\nimport { logAlertsMap } from '../utils/socket-package-alert.mts'\n\nimport type { AlertsByPurl } from '../utils/socket-package-alert.mts'\nimport type { Spinner } from '@socketsecurity/registry/lib/spinner'\n\n/**\n * Extract package PURLs from command arguments for add/dlx commands where\n * packages are specified as arguments.\n * Used by: pnpm, yarn.\n */\nfunction extractPackagePurlsFromCommandArgs(\n rawArgs: string[] | readonly string[],\n): string[] {\n const packagePurls: string[] = []\n\n // For 'add package1 package2@version' or 'dlx package', get packages from args.\n const packageArgs = rawArgs\n .slice(1)\n .filter(a => !a.startsWith('-') && a !== '--')\n\n for (const pkgSpec of packageArgs) {\n const purl = safeNpmSpecToPurl(pkgSpec)\n if (purl) {\n packagePurls.push(purl)\n }\n }\n\n return packagePurls\n}\n\n/**\n * Extract package PURLs from package.json for install/update commands.\n * Used by: pnpm, yarn.\n */\nasync function extractPackagePurlsFromPackageJson(\n cwd = process.cwd(),\n): Promise<string[]> {\n const packagePurls: string[] = []\n\n try {\n const pkgJson = await readPackageJson(cwd)\n\n const allDeps = {\n ...pkgJson.dependencies,\n ...pkgJson.devDependencies,\n ...pkgJson.optionalDependencies,\n ...pkgJson.peerDependencies,\n }\n\n for (const { 0: name, 1: version } of Object.entries(allDeps)) {\n const purl = safeNpmSpecToPurl(\n typeof version === 'string' ? `${name}@${version}` : name,\n )\n if (purl) {\n packagePurls.push(purl)\n }\n }\n\n debugScan('start', packagePurls.length)\n } catch (e) {\n debugFn(\n 'warn',\n `${PACKAGE_JSON} not found or invalid during dependency scanning`,\n )\n debugDir('error', e)\n }\n\n return packagePurls\n}\n\nexport type PackageScanOptions = {\n acceptRisks: boolean\n command: string | undefined\n cwd?: string | URL\n dlxCommands?: Set<string>\n installCommands: Set<string>\n managerName: string\n nothrow?: boolean\n rawArgs: string[] | readonly string[]\n spinner?: Spinner | undefined\n viewAllRisks: boolean\n}\n\nexport type PackageScanResult = {\n alertsMap?: AlertsByPurl\n shouldExit: boolean\n}\n\n/**\n * Scan packages and log alerts if found.\n */\nexport async function scanPackagesAndLogAlerts(\n options: PackageScanOptions,\n): Promise<PackageScanResult> {\n const {\n acceptRisks,\n command,\n dlxCommands,\n installCommands,\n managerName,\n nothrow = true,\n rawArgs,\n spinner,\n viewAllRisks,\n } = options\n\n let { cwd = process.cwd() } = options\n if (cwd instanceof URL) {\n cwd = fileURLToPath(cwd)\n }\n\n // Check if this is a command that needs security scanning.\n const isDlxCommand = dlxCommands && command && dlxCommands.has(command)\n const isInstallCommand = command && installCommands.has(command)\n const needsScanning = isDlxCommand || isInstallCommand\n\n if (!needsScanning || rawArgs.includes(FLAG_DRY_RUN)) {\n return { shouldExit: false }\n }\n\n // Extract package names from command arguments before any downloads.\n let packagePurls: string[] = []\n\n if (isDlxCommand || isAddCommand(command)) {\n packagePurls = extractPackagePurlsFromCommandArgs(rawArgs)\n } else if (isInstallCommand) {\n // For install/update, scan dependencies from package.json.\n // Note: This scans direct dependencies only.\n packagePurls = await extractPackagePurlsFromPackageJson(cwd)\n }\n\n if (!packagePurls.length) {\n return { shouldExit: false }\n }\n\n debugScan('start', packagePurls.length)\n debugDir('inspect', { packagePurls })\n\n try {\n const alertsMap = await getAlertsMapFromPurls(packagePurls, {\n filter: acceptRisks\n ? { actions: ['error'], blocked: true }\n : { actions: ['error', 'monitor', 'warn'] },\n nothrow,\n spinner,\n })\n\n if (alertsMap.size) {\n process.exitCode = 1\n spinner?.stop()\n logAlertsMap(alertsMap, {\n hideAt: viewAllRisks ? 'none' : 'middle',\n output: process.stderr,\n })\n\n const errorMessage = `Socket ${managerName} exiting due to risks.${\n viewAllRisks\n ? ''\n : `\\nView all risks - Rerun with environment variable ${constants.SOCKET_CLI_VIEW_ALL_RISKS}=1.`\n }${\n acceptRisks\n ? ''\n : `\\nAccept risks - Rerun with environment variable ${constants.SOCKET_CLI_ACCEPT_RISKS}=1.`\n }`.trim()\n\n logger.error(errorMessage)\n return { alertsMap, shouldExit: true }\n }\n } catch (e) {\n spinner?.stop()\n // Re-throw process.exit errors from tests.\n if (e instanceof Error && e.message === 'process.exit called') {\n throw e\n }\n debugScan('error', undefined, e)\n // Continue with installation if scanning fails.\n }\n\n debugScan('complete', packagePurls.length)\n debugDir('inspect', { args: rawArgs.slice(1) })\n\n return { shouldExit: false }\n}\n","import { existsSync } from 'node:fs'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nimport { debugDir, debugFn } from '@socketsecurity/registry/lib/debug'\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport constants, {\n FLAG_DRY_RUN,\n PNPM,\n PNPM_LOCK_YAML,\n} from '../../constants.mts'\nimport { getAlertsMapFromPnpmLockfile } from '../../utils/alerts-map.mts'\nimport {\n cmdFlagsToString,\n isAddCommand,\n isPnpmLockfileScanCommand,\n} from '../../utils/cmd.mts'\nimport { parsePnpmLockfile, readPnpmLockfile } from '../../utils/pnpm.mts'\nimport { getPublicApiToken } from '../../utils/sdk.mts'\nimport { installPnpmLinks } from '../../utils/shadow-links.mts'\nimport { logAlertsMap } from '../../utils/socket-package-alert.mts'\nimport { scanPackagesAndLogAlerts } from '../common.mts'\nimport { ensureIpcInStdio } from '../stdio-ipc.mts'\n\nimport type { IpcObject } from '../../constants.mts'\nimport type {\n SpawnExtra,\n SpawnOptions,\n SpawnResult,\n} from '@socketsecurity/registry/lib/spawn'\n\nexport type ShadowPnpmOptions = SpawnOptions & {\n ipc?: IpcObject | undefined\n}\n\nexport type ShadowPnpmResult = {\n spawnPromise: SpawnResult<string, SpawnExtra | undefined>\n}\n\nconst DLX_COMMANDS = new Set(['dlx'])\n\nconst INSTALL_COMMANDS = new Set([\n 'add',\n 'i',\n 'install',\n 'install-test',\n 'it',\n 'update',\n 'up',\n])\n\nexport default async function shadowPnpmBin(\n args: string[] | readonly string[] = process.argv.slice(2),\n options?: ShadowPnpmOptions | undefined,\n extra?: SpawnExtra | undefined,\n): Promise<ShadowPnpmResult> {\n const opts = { __proto__: null, ...options } as ShadowPnpmOptions\n const { env: spawnEnv, ipc, ...spawnOpts } = opts\n\n let { cwd = process.cwd() } = opts\n if (cwd instanceof URL) {\n cwd = fileURLToPath(cwd)\n }\n\n const terminatorPos = args.indexOf('--')\n const rawPnpmArgs = terminatorPos === -1 ? args : args.slice(0, terminatorPos)\n\n const { spinner } = opts\n const wasSpinning = !!spinner?.isSpinning\n\n // Check if this is a command that needs security scanning.\n const command = rawPnpmArgs[0]\n const isDlxCommand = command && DLX_COMMANDS.has(command)\n const isInstallCommand = command && INSTALL_COMMANDS.has(command)\n const needsScanning = isDlxCommand || isInstallCommand\n\n spinner?.start()\n\n if (needsScanning && !rawPnpmArgs.includes(FLAG_DRY_RUN)) {\n const acceptRisks = !!constants.ENV.SOCKET_CLI_ACCEPT_RISKS\n const viewAllRisks = !!constants.ENV.SOCKET_CLI_VIEW_ALL_RISKS\n\n // Handle add and dlx commands with shared utility.\n if (isDlxCommand || isAddCommand(command)) {\n const scanResult = await scanPackagesAndLogAlerts({\n acceptRisks,\n command,\n cwd,\n dlxCommands: DLX_COMMANDS,\n installCommands: INSTALL_COMMANDS,\n managerName: PNPM,\n rawArgs: rawPnpmArgs,\n spinner,\n viewAllRisks,\n })\n\n if (scanResult.shouldExit) {\n // eslint-disable-next-line n/no-process-exit\n process.exit(1)\n // This line is never reached in production, but helps tests.\n throw new Error('process.exit called')\n }\n } else if (isPnpmLockfileScanCommand(command)) {\n // For install/update, scan all dependencies from pnpm-lock.yaml\n const pnpmLockPath = path.join(cwd, PNPM_LOCK_YAML)\n if (existsSync(pnpmLockPath)) {\n try {\n const lockfileContent = await readPnpmLockfile(pnpmLockPath)\n if (lockfileContent) {\n const lockfile = parsePnpmLockfile(lockfileContent)\n if (lockfile) {\n // Use existing function to scan the entire lockfile\n debugFn(\n 'notice',\n `scanning: all dependencies from ${PNPM_LOCK_YAML}`,\n )\n\n const alertsMap = await getAlertsMapFromPnpmLockfile(lockfile, {\n nothrow: true,\n filter: acceptRisks\n ? { actions: ['error'], blocked: true }\n : { actions: ['error', 'monitor', 'warn'] },\n })\n\n spinner?.stop()\n\n if (alertsMap.size) {\n process.exitCode = 1\n logAlertsMap(alertsMap, {\n hideAt: viewAllRisks ? 'none' : 'middle',\n output: process.stderr,\n })\n\n const errorMessage = `Socket ${PNPM} exiting due to risks.${\n viewAllRisks\n ? ''\n : `\\nView all risks - Rerun with environment variable ${constants.SOCKET_CLI_VIEW_ALL_RISKS}=1.`\n }${\n acceptRisks\n ? ''\n : `\\nAccept risks - Rerun with environment variable ${constants.SOCKET_CLI_ACCEPT_RISKS}=1.`\n }`.trim()\n\n logger.error(errorMessage)\n // eslint-disable-next-line n/no-process-exit\n process.exit(1)\n // This line is never reached in production, but helps tests.\n throw new Error('process.exit called')\n }\n\n // Return early since we've already done the scanning\n debugFn(\n 'notice',\n 'complete: lockfile scanning, proceeding with install',\n )\n }\n }\n } catch (e) {\n debugFn('error', `${PNPM} lockfile scanning failed`)\n debugDir('error', e)\n }\n } else {\n debugFn(\n 'notice',\n `skip: no ${PNPM_LOCK_YAML} found, skipping bulk install scanning`,\n )\n }\n }\n\n debugFn('notice', 'complete: scanning, proceeding with install')\n }\n\n const realPnpmPath = await installPnpmLinks(constants.shadowBinPath)\n\n const otherArgs = terminatorPos === -1 ? [] : args.slice(terminatorPos)\n const suffixArgs = [...rawPnpmArgs, ...otherArgs]\n\n debugFn(\n 'notice',\n `spawn: ${PNPM} shadow bin ${realPnpmPath} ${cmdFlagsToString(suffixArgs)}`,\n )\n\n if (wasSpinning) {\n spinner?.start()\n }\n\n // Set up stdio with IPC channel.\n const stdio = ensureIpcInStdio(spawnOpts.stdio)\n\n const spawnPromise = spawn(\n realPnpmPath,\n suffixArgs,\n {\n ...spawnOpts,\n cwd,\n env: {\n ...process.env,\n ...spawnEnv,\n },\n stdio,\n // On Windows, pnpm is often a .cmd file that requires shell execution.\n // The spawn function from @socketsecurity/registry will handle this properly\n // when shell is true.\n shell: constants.WIN32,\n },\n extra,\n )\n\n // Send IPC handshake.\n spawnPromise.process.send({\n [constants.SOCKET_IPC_HANDSHAKE]: {\n [constants.SOCKET_CLI_SHADOW_API_TOKEN]: getPublicApiToken(),\n [constants.SOCKET_CLI_SHADOW_BIN]: PNPM,\n [constants.SOCKET_CLI_SHADOW_PROGRESS]: true,\n ...ipc,\n },\n })\n\n return { spawnPromise }\n}\n"],"names":["packagePurls","debugScan","debugFn","debugDir","nothrow","viewAllRisks","cwd","shouldExit","blocked","actions","spinner","hideAt","logger","args","__proto__","env","dlxCommands","installCommands","managerName","rawArgs","process","spawnPromise"],"mappings":";;;;;;;;;;;;;AAgBA;AACA;AACA;AACA;AACA;AACA;;;AAKE;;AAKA;AACE;AACA;AACEA;AACF;AACF;AAEA;AACF;;AAEA;AACA;AACA;AACA;AACA;;;AAMI;AAEA;;;;AAIE;;AAGF;AAAa;AAAS;AAAW;AAC/B;AAGA;AACEA;AACF;AACF;AAEAC;;AAEAC;AAIAC;AACF;AAEA;AACF;AAoBA;AACA;AACA;AACO;;;;;;;AASHC;;;AAGAC;AACF;;AAEMC;AAAoB;;AAExBA;AACF;;AAEA;;;AAGA;;;AAGWC;;AACX;;AAEA;;AAGA;AACEP;;AAEA;AACA;AACAA;AACF;AAEA;;AACWO;;AACX;AAEAN;;AACsBD;AAAa;;AAGjC;;;AAE4BQ;AAAc;AAClCC;;;AAENC;AACF;;;;;AAMIC;;AAEF;AAEA;AAUAC;;;AACoBL;;AACtB;;;AAGA;;AAEE;AACF;AACAN;AACA;AACF;AAEAA;;AACsBY;AAAuB;;AAEpCN;;AACX;;ACxJA;AAEA;AAUe;AAKb;AAAeO;;;;AACPC;;;AAAiC;;AAEnCT;AAAoB;;AAExBA;AACF;AAEA;AACA;;AAEQI;AAAQ;AAChB;;AAEA;AACA;;;AAGA;;;;;;AAQE;AACA;AACE;;;;AAIEM;AACAC;AACAC;AACAC;;AAEAd;AACF;;AAGE;AACAe;AACA;AACA;AACF;AACF;AACE;;AAEA;;AAEI;AACA;AACE;AACA;AACE;AACAlB;AAKA;AACEE;;;AAE0BI;AAAc;AAClCC;AAAsC;AAC9C;;;;;AAOIE;;AAEF;AAEA;AAUAC;AACA;AACAQ;AACA;AACA;AACF;;AAEA;AACAlB;AAIF;AACF;;AAEAA;AACAC;AACF;AACF;AACED;AAIF;AACF;AAEAA;AACF;;AAIA;;AAGAA;AAKA;;AAEA;;AAEA;AACA;AAEA;AAII;;AAEAa;;;;;AAKA;AACA;AACA;;;;AAMJ;AACAM;;AAEI;AACA;AACA;;AAEF;AACF;;AAESA;;AACX;;;","debugId":"b4cf863e-3d5c-4dcc-ad18-e70648911b2"}
@@ -1,34 +1,12 @@
1
1
  'use strict';
2
2
 
3
+ var require$$0 = require('node:url');
3
4
  var require$$9 = require('../external/@socketsecurity/registry/lib/debug');
4
5
  var spawn = require('../external/@socketsecurity/registry/lib/spawn');
5
- var shadowPnpmBin = require('./shadow-pnpm-bin2.js');
6
- var shadowNpmBin = require('./shadow-npm-bin2.js');
7
- var path = require('node:path');
8
- var vendor = require('./vendor.js');
9
6
  var constants = require('./constants.js');
10
7
  var utils = require('./utils.js');
11
-
12
- async function installLinks(shadowBinPath, binName) {
13
- const binPath = utils.getYarnBinPath();
14
- const {
15
- WIN32
16
- } = constants.default;
17
- if (WIN32 && binPath) {
18
- return binPath;
19
- }
20
- const shadowed = utils.isYarnBinPathShadowed();
21
- if (!shadowed) {
22
- if (WIN32) {
23
- await vendor.libExports(path.join(constants.default.distPath, `${binName}-cli.js`), path.join(shadowBinPath, binName));
24
- }
25
- const {
26
- env
27
- } = process;
28
- env['PATH'] = `${shadowBinPath}${path.delimiter}${env['PATH']}`;
29
- }
30
- return binPath;
31
- }
8
+ var shadowPnpmBin = require('./shadow-pnpm-bin2.js');
9
+ var shadowNpmBin = require('./shadow-npm-bin2.js');
32
10
 
33
11
  const DLX_COMMANDS = new Set(['dlx']);
34
12
  const INSTALL_COMMANDS = new Set(['add', 'install', 'up', 'upgrade', 'upgrade-interactive']);
@@ -42,24 +20,29 @@ async function shadowYarnBin(args = process.argv.slice(2), options, extra) {
42
20
  ipc,
43
21
  ...spawnOpts
44
22
  } = opts;
23
+ let {
24
+ cwd = process.cwd()
25
+ } = opts;
26
+ if (cwd instanceof URL) {
27
+ cwd = require$$0.fileURLToPath(cwd);
28
+ }
29
+ const terminatorPos = args.indexOf('--');
30
+ const rawYarnArgs = terminatorPos === -1 ? args : args.slice(0, terminatorPos);
45
31
  const {
46
32
  spinner
47
33
  } = opts;
48
34
  const wasSpinning = !!spinner?.isSpinning;
49
35
  spinner?.start();
50
- const terminatorPos = args.indexOf('--');
51
- const rawYarnArgs = terminatorPos === -1 ? args : args.slice(0, terminatorPos);
52
- const otherArgs = terminatorPos === -1 ? [] : args.slice(terminatorPos);
53
36
 
54
37
  // Check for package scanning.
55
38
  const command = rawYarnArgs[0];
56
39
  const scanResult = await shadowPnpmBin.scanPackagesAndLogAlerts({
57
40
  acceptRisks: !!constants.default.ENV.SOCKET_CLI_ACCEPT_RISKS,
58
41
  command,
59
- cwd: process.cwd(),
42
+ cwd,
60
43
  dlxCommands: DLX_COMMANDS,
61
44
  installCommands: INSTALL_COMMANDS,
62
- managerName: 'yarn',
45
+ managerName: constants.YARN,
63
46
  rawArgs: rawYarnArgs,
64
47
  spinner,
65
48
  viewAllRisks: !!constants.default.ENV.SOCKET_CLI_VIEW_ALL_RISKS
@@ -70,8 +53,8 @@ async function shadowYarnBin(args = process.argv.slice(2), options, extra) {
70
53
  // This line is never reached in production, but helps tests.
71
54
  throw new Error('process.exit called');
72
55
  }
73
- const realYarnPath = await installLinks(constants.default.shadowBinPath, constants.YARN);
74
- spinner?.stop();
56
+ const realYarnPath = await utils.installYarnLinks(constants.default.shadowBinPath);
57
+ const otherArgs = terminatorPos === -1 ? [] : args.slice(terminatorPos);
75
58
  const suffixArgs = [...rawYarnArgs, ...otherArgs];
76
59
  require$$9.debugFn('notice', `spawn: ${constants.YARN} shadow bin ${realYarnPath} ${utils.cmdFlagsToString(suffixArgs)}`);
77
60
  if (wasSpinning) {
@@ -82,6 +65,7 @@ async function shadowYarnBin(args = process.argv.slice(2), options, extra) {
82
65
  const stdio = shadowNpmBin.ensureIpcInStdio(spawnOpts.stdio);
83
66
  const spawnPromise = spawn.spawn(realYarnPath, suffixArgs, {
84
67
  ...spawnOpts,
68
+ cwd,
85
69
  env: {
86
70
  ...process.env,
87
71
  ...spawnEnv
@@ -108,5 +92,5 @@ async function shadowYarnBin(args = process.argv.slice(2), options, extra) {
108
92
  }
109
93
 
110
94
  module.exports = shadowYarnBin;
111
- //# debugId=1cf735f7-d72e-4a95-9a5f-bc6822d5a468
95
+ //# debugId=673b7dc1-02c4-46a2-b70b-e0f78c541d47
112
96
  //# sourceMappingURL=shadow-yarn-bin.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shadow-yarn-bin.js","sources":["../src/shadow/yarn/link.mts","../src/shadow/yarn/bin.mts"],"sourcesContent":["import path from 'node:path'\n\nimport cmdShim from 'cmd-shim'\n\nimport constants from '../../constants.mts'\nimport {\n getYarnBinPath,\n isYarnBinPathShadowed,\n} from '../../utils/yarn-paths.mts'\n\nexport async function installLinks(\n shadowBinPath: string,\n binName: 'yarn',\n): Promise<string> {\n const binPath = getYarnBinPath()\n const { WIN32 } = constants\n\n if (WIN32 && binPath) {\n return binPath\n }\n\n const shadowed = isYarnBinPathShadowed()\n\n if (!shadowed) {\n if (WIN32) {\n await cmdShim(\n path.join(constants.distPath, `${binName}-cli.js`),\n path.join(shadowBinPath, binName),\n )\n }\n const { env } = process\n env['PATH'] = `${shadowBinPath}${path.delimiter}${env['PATH']}`\n }\n\n return binPath\n}\n","import { debugFn } from '@socketsecurity/registry/lib/debug'\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport { scanPackagesAndLogAlerts } from '../common.mts'\nimport { ensureIpcInStdio } from '../stdio-ipc.mts'\nimport { installLinks } from './link.mts'\nimport constants, { YARN } from '../../constants.mts'\nimport { cmdFlagsToString } from '../../utils/cmd.mts'\nimport { getPublicApiToken } from '../../utils/sdk.mts'\n\nimport type { IpcObject } from '../../constants.mts'\nimport type {\n SpawnExtra,\n SpawnOptions,\n SpawnResult,\n} from '@socketsecurity/registry/lib/spawn'\n\nexport type ShadowYarnOptions = SpawnOptions & {\n ipc?: IpcObject | undefined\n}\n\nexport type ShadowYarnResult = {\n spawnPromise: SpawnResult<string, SpawnExtra | undefined>\n}\n\nconst DLX_COMMANDS = new Set(['dlx'])\n\nconst INSTALL_COMMANDS = new Set([\n 'add',\n 'install',\n 'up',\n 'upgrade',\n 'upgrade-interactive',\n])\n\nexport default async function shadowYarnBin(\n args: string[] | readonly string[] = process.argv.slice(2),\n options?: ShadowYarnOptions | undefined,\n extra?: SpawnExtra | undefined,\n): Promise<ShadowYarnResult> {\n const opts = { __proto__: null, ...options } as ShadowYarnOptions\n const { env: spawnEnv, ipc, ...spawnOpts } = opts\n const { spinner } = opts\n\n const wasSpinning = !!spinner?.isSpinning\n\n spinner?.start()\n\n const terminatorPos = args.indexOf('--')\n const rawYarnArgs = terminatorPos === -1 ? args : args.slice(0, terminatorPos)\n const otherArgs = terminatorPos === -1 ? [] : args.slice(terminatorPos)\n\n // Check for package scanning.\n const command = rawYarnArgs[0]\n const scanResult = await scanPackagesAndLogAlerts({\n acceptRisks: !!constants.ENV.SOCKET_CLI_ACCEPT_RISKS,\n command,\n cwd: process.cwd(),\n dlxCommands: DLX_COMMANDS,\n installCommands: INSTALL_COMMANDS,\n managerName: 'yarn',\n rawArgs: rawYarnArgs,\n spinner,\n viewAllRisks: !!constants.ENV.SOCKET_CLI_VIEW_ALL_RISKS,\n })\n\n if (scanResult.shouldExit) {\n // eslint-disable-next-line n/no-process-exit\n process.exit(1)\n // This line is never reached in production, but helps tests.\n throw new Error('process.exit called')\n }\n\n const realYarnPath = await installLinks(constants.shadowBinPath, YARN)\n\n spinner?.stop()\n\n const suffixArgs = [...rawYarnArgs, ...otherArgs]\n\n debugFn(\n 'notice',\n `spawn: ${YARN} shadow bin ${realYarnPath} ${cmdFlagsToString(suffixArgs)}`,\n )\n\n if (wasSpinning) {\n spinner?.start()\n }\n\n // Set up stdio with IPC channel.\n const stdio = ensureIpcInStdio(spawnOpts.stdio)\n\n const spawnPromise = spawn(\n realYarnPath,\n suffixArgs,\n {\n ...spawnOpts,\n env: {\n ...process.env,\n ...spawnEnv,\n },\n stdio,\n // On Windows, yarn is often a .cmd file that requires shell execution.\n // The spawn function from @socketsecurity/registry will handle this properly\n // when shell is true.\n shell: constants.WIN32,\n },\n extra,\n )\n\n // Send IPC handshake.\n spawnPromise.process.send({\n [constants.SOCKET_IPC_HANDSHAKE]: {\n [constants.SOCKET_CLI_SHADOW_API_TOKEN]: getPublicApiToken(),\n [constants.SOCKET_CLI_SHADOW_BIN]: YARN,\n [constants.SOCKET_CLI_SHADOW_PROGRESS]: true,\n ...ipc,\n },\n })\n\n return { spawnPromise }\n}\n"],"names":["WIN32","env","__proto__","spinner","acceptRisks","cwd","dlxCommands","installCommands","managerName","rawArgs","viewAllRisks","process","debugFn","spawnPromise"],"mappings":";;;;;;;;;;;AAUO;AAIL;;AACQA;AAAM;;AAGZ;AACF;AAEA;;AAGE;;AAKA;;AACQC;AAAI;AACZA;AACF;AAEA;AACF;;ACVA;AAEA;AAQe;AAKb;AAAeC;;;;AACPD;;;AAAiC;;AACjCE;AAAQ;AAEhB;;AAIA;AACA;AACA;;AAEA;AACA;AACA;AACEC;;AAEAC;AACAC;AACAC;AACAC;AACAC;;AAEAC;AACF;;AAGE;AACAC;AACA;AACA;AACF;;;;AAQAC;AAKA;;AAEA;;AAEA;AACA;AAEA;AAII;AACAX;;;;;AAKA;AACA;AACA;;;;AAMJ;AACAY;;AAEI;AACA;AACA;;AAEF;AACF;;AAESA;;AACX;;","debugId":"1cf735f7-d72e-4a95-9a5f-bc6822d5a468"}
1
+ {"version":3,"file":"shadow-yarn-bin.js","sources":["../src/shadow/yarn/bin.mts"],"sourcesContent":["import { fileURLToPath } from 'node:url'\n\nimport { debugFn } from '@socketsecurity/registry/lib/debug'\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport constants, { YARN } from '../../constants.mts'\nimport { cmdFlagsToString } from '../../utils/cmd.mts'\nimport { getPublicApiToken } from '../../utils/sdk.mts'\nimport { installYarnLinks } from '../../utils/shadow-links.mts'\nimport { scanPackagesAndLogAlerts } from '../common.mts'\nimport { ensureIpcInStdio } from '../stdio-ipc.mts'\n\nimport type { IpcObject } from '../../constants.mts'\nimport type {\n SpawnExtra,\n SpawnOptions,\n SpawnResult,\n} from '@socketsecurity/registry/lib/spawn'\n\nexport type ShadowYarnOptions = SpawnOptions & {\n ipc?: IpcObject | undefined\n}\n\nexport type ShadowYarnResult = {\n spawnPromise: SpawnResult<string, SpawnExtra | undefined>\n}\n\nconst DLX_COMMANDS = new Set(['dlx'])\n\nconst INSTALL_COMMANDS = new Set([\n 'add',\n 'install',\n 'up',\n 'upgrade',\n 'upgrade-interactive',\n])\n\nexport default async function shadowYarnBin(\n args: string[] | readonly string[] = process.argv.slice(2),\n options?: ShadowYarnOptions | undefined,\n extra?: SpawnExtra | undefined,\n): Promise<ShadowYarnResult> {\n const opts = { __proto__: null, ...options } as ShadowYarnOptions\n const { env: spawnEnv, ipc, ...spawnOpts } = opts\n\n let { cwd = process.cwd() } = opts\n if (cwd instanceof URL) {\n cwd = fileURLToPath(cwd)\n }\n\n const terminatorPos = args.indexOf('--')\n const rawYarnArgs = terminatorPos === -1 ? args : args.slice(0, terminatorPos)\n\n const { spinner } = opts\n const wasSpinning = !!spinner?.isSpinning\n\n spinner?.start()\n\n // Check for package scanning.\n const command = rawYarnArgs[0]\n const scanResult = await scanPackagesAndLogAlerts({\n acceptRisks: !!constants.ENV.SOCKET_CLI_ACCEPT_RISKS,\n command,\n cwd,\n dlxCommands: DLX_COMMANDS,\n installCommands: INSTALL_COMMANDS,\n managerName: YARN,\n rawArgs: rawYarnArgs,\n spinner,\n viewAllRisks: !!constants.ENV.SOCKET_CLI_VIEW_ALL_RISKS,\n })\n\n if (scanResult.shouldExit) {\n // eslint-disable-next-line n/no-process-exit\n process.exit(1)\n // This line is never reached in production, but helps tests.\n throw new Error('process.exit called')\n }\n\n const realYarnPath = await installYarnLinks(constants.shadowBinPath)\n\n const otherArgs = terminatorPos === -1 ? [] : args.slice(terminatorPos)\n const suffixArgs = [...rawYarnArgs, ...otherArgs]\n\n debugFn(\n 'notice',\n `spawn: ${YARN} shadow bin ${realYarnPath} ${cmdFlagsToString(suffixArgs)}`,\n )\n\n if (wasSpinning) {\n spinner?.start()\n }\n\n // Set up stdio with IPC channel.\n const stdio = ensureIpcInStdio(spawnOpts.stdio)\n\n const spawnPromise = spawn(\n realYarnPath,\n suffixArgs,\n {\n ...spawnOpts,\n cwd,\n env: {\n ...process.env,\n ...spawnEnv,\n },\n stdio,\n // On Windows, yarn is often a .cmd file that requires shell execution.\n // The spawn function from @socketsecurity/registry will handle this properly\n // when shell is true.\n shell: constants.WIN32,\n },\n extra,\n )\n\n // Send IPC handshake.\n spawnPromise.process.send({\n [constants.SOCKET_IPC_HANDSHAKE]: {\n [constants.SOCKET_CLI_SHADOW_API_TOKEN]: getPublicApiToken(),\n [constants.SOCKET_CLI_SHADOW_BIN]: YARN,\n [constants.SOCKET_CLI_SHADOW_PROGRESS]: true,\n ...ipc,\n },\n })\n\n return { spawnPromise }\n}\n"],"names":["__proto__","env","cwd","spinner","acceptRisks","dlxCommands","installCommands","managerName","rawArgs","viewAllRisks","process","debugFn","spawnPromise"],"mappings":";;;;;;;;;;AA2BA;AAEA;AAQe;AAKb;AAAeA;;;;AACPC;;;AAAiC;;AAEnCC;AAAoB;;AAExBA;AACF;AAEA;AACA;;AAEQC;AAAQ;AAChB;;;AAIA;AACA;AACA;AACEC;;;AAGAC;AACAC;AACAC;AACAC;;AAEAC;AACF;;AAGE;AACAC;AACA;AACA;AACF;;AAIA;;AAGAC;AAKA;;AAEA;;AAEA;AACA;AAEA;AAII;;AAEAV;;;;;AAKA;AACA;AACA;;;;AAMJ;AACAW;;AAEI;AACA;AACA;;AAEF;AACF;;AAESA;;AACX;;","debugId":"673b7dc1-02c4-46a2-b70b-e0f78c541d47"}