socket 1.1.11 → 1.1.13

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 (95) hide show
  1. package/CHANGELOG.md +49 -28
  2. package/bin/cli.js +2 -1
  3. package/bin/npm-cli.js +2 -1
  4. package/bin/npx-cli.js +2 -1
  5. package/bin/pnpm-cli.js +29 -0
  6. package/bin/yarn-cli.js +29 -0
  7. package/dist/cli.js +728 -532
  8. package/dist/cli.js.map +1 -1
  9. package/dist/constants.js +27 -5
  10. package/dist/constants.js.map +1 -1
  11. package/dist/npm-cli.js +26 -0
  12. package/dist/npm-cli.js.map +1 -0
  13. package/dist/npx-cli.js +26 -0
  14. package/dist/npx-cli.js.map +1 -0
  15. package/dist/pnpm-cli.js +26 -0
  16. package/dist/pnpm-cli.js.map +1 -0
  17. package/dist/shadow-npm-inject.js +2 -2
  18. package/dist/shadow-npm-inject.js.map +1 -1
  19. package/dist/shadow-pnpm-bin.js +235 -0
  20. package/dist/shadow-pnpm-bin.js.map +1 -0
  21. package/dist/shadow-yarn-bin.js +200 -0
  22. package/dist/shadow-yarn-bin.js.map +1 -0
  23. package/dist/tsconfig.dts.tsbuildinfo +1 -1
  24. package/dist/types/commands/fix/cmd-fix.d.mts.map +1 -1
  25. package/dist/types/commands/fix/coana-fix.d.mts.map +1 -1
  26. package/dist/types/commands/fix/handle-fix.d.mts +3 -1
  27. package/dist/types/commands/fix/handle-fix.d.mts.map +1 -1
  28. package/dist/types/commands/fix/pull-request.d.mts.map +1 -1
  29. package/dist/types/commands/fix/types.d.mts +2 -0
  30. package/dist/types/commands/fix/types.d.mts.map +1 -1
  31. package/dist/types/commands/json/cmd-json.d.mts.map +1 -1
  32. package/dist/types/commands/manifest/cmd-manifest-conda.d.mts.map +1 -1
  33. package/dist/types/commands/manifest/cmd-manifest-gradle.d.mts.map +1 -1
  34. package/dist/types/commands/manifest/cmd-manifest-kotlin.d.mts.map +1 -1
  35. package/dist/types/commands/manifest/cmd-manifest-setup.d.mts.map +1 -1
  36. package/dist/types/commands/manifest/cmd-manifest.d.mts.map +1 -1
  37. package/dist/types/commands/manifest/detect-manifest-actions.d.mts.map +1 -1
  38. package/dist/types/commands/manifest/generate_auto_manifest.d.mts.map +1 -1
  39. package/dist/types/commands/manifest/output-requirements.d.mts.map +1 -1
  40. package/dist/types/commands/manifest/run-cdxgen.d.mts.map +1 -1
  41. package/dist/types/commands/manifest/setup-manifest-config.d.mts.map +1 -1
  42. package/dist/types/commands/npm/cmd-npm.d.mts.map +1 -1
  43. package/dist/types/commands/npx/cmd-npx.d.mts.map +1 -1
  44. package/dist/types/commands/pnpm/cmd-pnpm.d.mts +10 -0
  45. package/dist/types/commands/pnpm/cmd-pnpm.d.mts.map +1 -0
  46. package/dist/types/commands/scan/cmd-scan-setup.d.mts.map +1 -1
  47. package/dist/types/commands/scan/fetch-create-org-full-scan.d.mts +1 -1
  48. package/dist/types/commands/scan/fetch-create-org-full-scan.d.mts.map +1 -1
  49. package/dist/types/commands/yarn/cmd-yarn.d.mts +10 -0
  50. package/dist/types/commands/yarn/cmd-yarn.d.mts.map +1 -0
  51. package/dist/types/commands.d.mts +10 -0
  52. package/dist/types/commands.d.mts.map +1 -1
  53. package/dist/types/constants.d.mts +15 -1
  54. package/dist/types/constants.d.mts.map +1 -1
  55. package/dist/types/npm-cli.d.mts +3 -0
  56. package/dist/types/npm-cli.d.mts.map +1 -0
  57. package/dist/types/npx-cli.d.mts +3 -0
  58. package/dist/types/npx-cli.d.mts.map +1 -0
  59. package/dist/types/pnpm-cli.d.mts +3 -0
  60. package/dist/types/pnpm-cli.d.mts.map +1 -0
  61. package/dist/types/shadow/npm/install.d.mts +1 -1
  62. package/dist/types/shadow/npm/install.d.mts.map +1 -1
  63. package/dist/types/shadow/pnpm/bin.d.mts +10 -0
  64. package/dist/types/shadow/pnpm/bin.d.mts.map +1 -0
  65. package/dist/types/shadow/pnpm/link.d.mts +2 -0
  66. package/dist/types/shadow/pnpm/link.d.mts.map +1 -0
  67. package/dist/types/shadow/yarn/bin.d.mts +10 -0
  68. package/dist/types/shadow/yarn/bin.d.mts.map +1 -0
  69. package/dist/types/shadow/yarn/link.d.mts +2 -0
  70. package/dist/types/shadow/yarn/link.d.mts.map +1 -0
  71. package/dist/types/utils/alerts-map.d.mts.map +1 -1
  72. package/dist/types/utils/coana.d.mts.map +1 -1
  73. package/dist/types/utils/github.d.mts.map +1 -1
  74. package/dist/types/utils/meow-with-subcommands.d.mts.map +1 -1
  75. package/dist/types/utils/package-environment.d.mts.map +1 -1
  76. package/dist/types/utils/pnpm-paths.d.mts +5 -0
  77. package/dist/types/utils/pnpm-paths.d.mts.map +1 -0
  78. package/dist/types/utils/socket-json.d.mts +3 -0
  79. package/dist/types/utils/socket-json.d.mts.map +1 -1
  80. package/dist/types/utils/yarn-paths.d.mts +5 -0
  81. package/dist/types/utils/yarn-paths.d.mts.map +1 -0
  82. package/dist/types/utils/yarn-version.d.mts +2 -0
  83. package/dist/types/utils/yarn-version.d.mts.map +1 -0
  84. package/dist/types/yarn-cli.d.mts +3 -0
  85. package/dist/types/yarn-cli.d.mts.map +1 -0
  86. package/dist/utils.js +242 -63
  87. package/dist/utils.js.map +1 -1
  88. package/dist/vendor.js +3622 -1386
  89. package/dist/yarn-cli.js +26 -0
  90. package/dist/yarn-cli.js.map +1 -0
  91. package/package.json +6 -2
  92. package/shadow-bin/npm +1 -1
  93. package/shadow-bin/npx +1 -1
  94. package/shadow-bin/pnpm +27 -0
  95. package/shadow-bin/yarn +27 -0
@@ -0,0 +1,235 @@
1
+ 'use strict';
2
+
3
+ var fs = require('node:fs');
4
+ var path = require('node:path');
5
+ var require$$0 = require('node:url');
6
+ var require$$9 = require('../external/@socketsecurity/registry/lib/debug');
7
+ var logger = require('../external/@socketsecurity/registry/lib/logger');
8
+ var spawn = require('../external/@socketsecurity/registry/lib/spawn');
9
+ var vendor = require('./vendor.js');
10
+ var constants = require('./constants.js');
11
+ var utils = require('./utils.js');
12
+
13
+ async function installLinks(shadowBinPath, _binName) {
14
+ // Find pnpm being shadowed by this process.
15
+ const binPath = utils.getPnpmBinPath();
16
+ const {
17
+ WIN32
18
+ } = constants.default;
19
+
20
+ // TODO: Is this early exit needed?
21
+ if (WIN32 && binPath) {
22
+ return binPath;
23
+ }
24
+ const shadowed = utils.isPnpmBinPathShadowed();
25
+
26
+ // Move our bin directory to front of PATH so its found first.
27
+ if (!shadowed) {
28
+ if (WIN32) {
29
+ await vendor.libExports(path.join(constants.default.distPath, 'pnpm-cli.js'), path.join(shadowBinPath, 'pnpm'));
30
+ }
31
+ const {
32
+ env
33
+ } = process;
34
+ env['PATH'] = `${shadowBinPath}${path.delimiter}${env['PATH']}`;
35
+ }
36
+ return binPath;
37
+ }
38
+
39
+ const INSTALL_COMMANDS = new Set(['add', 'i', 'install', 'install-test', 'it', 'update', 'up']);
40
+ async function shadowPnpm(args = process.argv.slice(2), options, extra) {
41
+ const opts = {
42
+ __proto__: null,
43
+ ...options
44
+ };
45
+ const {
46
+ env: spawnEnv,
47
+ ipc,
48
+ ...spawnOpts
49
+ } = opts;
50
+ let {
51
+ cwd = process.cwd()
52
+ } = opts;
53
+ if (cwd instanceof URL) {
54
+ cwd = require$$0.fileURLToPath(cwd);
55
+ }
56
+ const terminatorPos = args.indexOf('--');
57
+ const rawPnpmArgs = terminatorPos === -1 ? args : args.slice(0, terminatorPos);
58
+ const otherArgs = terminatorPos === -1 ? [] : args.slice(terminatorPos);
59
+
60
+ // Check if this is an install-type command that needs security scanning
61
+ const command = rawPnpmArgs[0];
62
+ const needsScanning = command && INSTALL_COMMANDS.has(command);
63
+
64
+ // Get pnpm path
65
+ const realPnpmPath = await installLinks(constants.default.shadowBinPath);
66
+ const permArgs = ['--reporter=silent',
67
+ // Disable update checks during security scanning
68
+ '--no-update-notifier'];
69
+ const prefixArgs = [];
70
+ const suffixArgs = [...rawPnpmArgs, ...permArgs, ...otherArgs];
71
+ if (needsScanning && !rawPnpmArgs.includes('--dry-run')) {
72
+ const acceptRisks = Boolean(process.env['SOCKET_CLI_ACCEPT_RISKS']);
73
+ const viewAllRisks = Boolean(process.env['SOCKET_CLI_VIEW_ALL_RISKS']);
74
+
75
+ // Extract package names from command arguments before any downloads
76
+ const packagePurls = [];
77
+ if (command === 'add') {
78
+ // For 'pnpm add package1 package2@version', get packages from args
79
+ const packageArgs = rawPnpmArgs.slice(1).filter(arg => !arg.startsWith('-') && arg !== '--');
80
+ for (const pkgSpec of packageArgs) {
81
+ // Handle package specs like 'lodash', 'lodash@4.17.21', '@types/node@^20.0.0'
82
+ let name;
83
+ let version;
84
+ if (pkgSpec.startsWith('@')) {
85
+ // Scoped package: @scope/name or @scope/name@version
86
+ const parts = pkgSpec.split('@');
87
+ if (parts.length === 2) {
88
+ // @scope/name (no version)
89
+ name = pkgSpec;
90
+ } else {
91
+ // @scope/name@version
92
+ name = `@${parts[1]}`;
93
+ version = parts[2];
94
+ }
95
+ } else {
96
+ // Regular package: name or name@version
97
+ const atIndex = pkgSpec.indexOf('@');
98
+ if (atIndex === -1) {
99
+ name = pkgSpec;
100
+ } else {
101
+ name = pkgSpec.slice(0, atIndex);
102
+ version = pkgSpec.slice(atIndex + 1);
103
+ }
104
+ }
105
+ if (name) {
106
+ packagePurls.push(version ? utils.idToNpmPurl(`${name}@${version}`) : utils.idToNpmPurl(name));
107
+ }
108
+ }
109
+ } else if (['install', 'i', 'update', 'up'].includes(command)) {
110
+ // For install/update, scan all dependencies from pnpm-lock.yaml
111
+ const pnpmLockPath = path.join(cwd, constants.PNPM_LOCK_YAML);
112
+ if (fs.existsSync(pnpmLockPath)) {
113
+ try {
114
+ const lockfileContent = await utils.readPnpmLockfile(pnpmLockPath);
115
+ if (lockfileContent) {
116
+ const lockfile = utils.parsePnpmLockfile(lockfileContent);
117
+ if (lockfile) {
118
+ // Use existing function to scan the entire lockfile
119
+ if (require$$9.isDebug()) {
120
+ require$$9.debugFn('notice', `scanning: all dependencies from ${constants.PNPM_LOCK_YAML}`);
121
+ }
122
+ const alertsMap = await utils.getAlertsMapFromPnpmLockfile(lockfile, {
123
+ nothrow: true,
124
+ filter: acceptRisks ? {
125
+ actions: ['error'],
126
+ blocked: true
127
+ } : {
128
+ actions: ['error', 'monitor', 'warn']
129
+ }
130
+ });
131
+ if (alertsMap.size) {
132
+ process.exitCode = 1;
133
+ utils.logAlertsMap(alertsMap, {
134
+ hideAt: viewAllRisks ? 'none' : 'middle',
135
+ output: process.stderr
136
+ });
137
+ 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();
138
+ logger.logger.error(errorMessage);
139
+ // eslint-disable-next-line n/no-process-exit
140
+ process.exit(1);
141
+ // This line is never reached in production, but helps tests.
142
+ throw new Error('process.exit called');
143
+ }
144
+
145
+ // Return early since we've already done the scanning
146
+ if (require$$9.isDebug()) {
147
+ require$$9.debugFn('notice', 'complete: lockfile scanning, proceeding with install');
148
+ }
149
+ }
150
+ }
151
+ } catch (e) {
152
+ if (require$$9.isDebug()) {
153
+ require$$9.debugFn('error', 'caught: pnpm lockfile scanning error');
154
+ require$$9.debugDir('inspect', {
155
+ error: e
156
+ });
157
+ }
158
+ }
159
+ } else if (require$$9.isDebug()) {
160
+ require$$9.debugFn('notice', 'skip: no pnpm-lock.yaml found, skipping bulk install scanning');
161
+ }
162
+ }
163
+ if (packagePurls.length > 0) {
164
+ if (require$$9.isDebug()) {
165
+ require$$9.debugFn('notice', 'scanning: packages before download');
166
+ require$$9.debugDir('inspect', {
167
+ packagePurls
168
+ });
169
+ }
170
+ try {
171
+ const alertsMap = await utils.getAlertsMapFromPurls(packagePurls, {
172
+ nothrow: true,
173
+ filter: acceptRisks ? {
174
+ actions: ['error'],
175
+ blocked: true
176
+ } : {
177
+ actions: ['error', 'monitor', 'warn']
178
+ }
179
+ });
180
+ if (alertsMap.size) {
181
+ process.exitCode = 1;
182
+ utils.logAlertsMap(alertsMap, {
183
+ hideAt: viewAllRisks ? 'none' : 'middle',
184
+ output: process.stderr
185
+ });
186
+ const errorMessage = `
187
+ 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();
188
+ logger.logger.error(errorMessage);
189
+ // eslint-disable-next-line n/no-process-exit
190
+ process.exit(1);
191
+ // This line is never reached in production, but helps tests.
192
+ throw new Error('process.exit called');
193
+ }
194
+ } catch (e) {
195
+ // Re-throw process.exit errors from tests.
196
+ if (e instanceof Error && e.message === 'process.exit called') {
197
+ throw e;
198
+ }
199
+ if (require$$9.isDebug()) {
200
+ require$$9.debugFn('error', 'caught: package scanning error');
201
+ require$$9.debugDir('inspect', {
202
+ error: e
203
+ });
204
+ }
205
+ // Continue with installation if scanning fails
206
+ }
207
+ }
208
+ if (require$$9.isDebug()) {
209
+ require$$9.debugFn('notice', 'complete: scanning, proceeding with install');
210
+ require$$9.debugDir('inspect', {
211
+ args: rawPnpmArgs.slice(1)
212
+ });
213
+ }
214
+ }
215
+ const argsToString = utils.cmdFlagsToString([...prefixArgs, ...suffixArgs]);
216
+ const env = {
217
+ ...process.env,
218
+ ...spawnEnv
219
+ };
220
+ if (require$$9.isDebug()) {
221
+ require$$9.debugFn('notice', `spawn: pnpm shadow bin ${realPnpmPath} ${argsToString}`);
222
+ }
223
+ const spawnPromise = spawn.spawn(realPnpmPath, [...prefixArgs, ...suffixArgs], {
224
+ ...spawnOpts,
225
+ env,
226
+ extra
227
+ });
228
+ return {
229
+ spawnPromise
230
+ };
231
+ }
232
+
233
+ module.exports = shadowPnpm;
234
+ //# debugId=95396bfd-89e3-4dec-a9d6-623419962b28
235
+ //# sourceMappingURL=shadow-pnpm-bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shadow-pnpm-bin.js","sources":["../src/shadow/pnpm/link.mts","../src/shadow/pnpm/bin.mts"],"sourcesContent":["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, isDebug } from '@socketsecurity/registry/lib/debug'\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport { installLinks } from './link.mts'\nimport constants, { PNPM_LOCK_YAML } from '../../constants.mts'\nimport {\n getAlertsMapFromPnpmLockfile,\n getAlertsMapFromPurls,\n} from '../../utils/alerts-map.mts'\nimport { cmdFlagsToString } from '../../utils/cmd.mts'\nimport { parsePnpmLockfile, readPnpmLockfile } from '../../utils/pnpm.mts'\nimport { logAlertsMap } from '../../utils/socket-package-alert.mts'\nimport { idToNpmPurl } from '../../utils/spec.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 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 shadowPnpm(\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 const otherArgs = terminatorPos === -1 ? [] : args.slice(terminatorPos)\n\n // Check if this is an install-type command that needs security scanning\n const command = rawPnpmArgs[0]\n const needsScanning = command && INSTALL_COMMANDS.has(command)\n\n // Get pnpm path\n const realPnpmPath = await installLinks(constants.shadowBinPath, 'pnpm')\n\n const permArgs = [\n '--reporter=silent',\n // Disable update checks during security scanning\n '--no-update-notifier',\n ]\n\n const prefixArgs: string[] = []\n const suffixArgs = [...rawPnpmArgs, ...permArgs, ...otherArgs]\n\n if (needsScanning && !rawPnpmArgs.includes('--dry-run')) {\n const acceptRisks = Boolean(process.env['SOCKET_CLI_ACCEPT_RISKS'])\n const viewAllRisks = Boolean(process.env['SOCKET_CLI_VIEW_ALL_RISKS'])\n\n // Extract package names from command arguments before any downloads\n const packagePurls: string[] = []\n\n if (command === 'add') {\n // For 'pnpm add package1 package2@version', get packages from args\n const packageArgs = rawPnpmArgs\n .slice(1)\n .filter(arg => !arg.startsWith('-') && arg !== '--')\n\n for (const pkgSpec of packageArgs) {\n // Handle package specs like 'lodash', 'lodash@4.17.21', '@types/node@^20.0.0'\n let name: string\n let version: string | undefined\n\n if (pkgSpec.startsWith('@')) {\n // Scoped package: @scope/name or @scope/name@version\n const parts = pkgSpec.split('@')\n if (parts.length === 2) {\n // @scope/name (no version)\n name = pkgSpec\n } else {\n // @scope/name@version\n name = `@${parts[1]}`\n version = parts[2]\n }\n } else {\n // Regular package: name or name@version\n const atIndex = pkgSpec.indexOf('@')\n if (atIndex === -1) {\n name = pkgSpec\n } else {\n name = pkgSpec.slice(0, atIndex)\n version = pkgSpec.slice(atIndex + 1)\n }\n }\n\n if (name) {\n packagePurls.push(\n version ? idToNpmPurl(`${name}@${version}`) : idToNpmPurl(name),\n )\n }\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 if (isDebug()) {\n debugFn(\n 'notice',\n `scanning: all dependencies from ${PNPM_LOCK_YAML}`,\n )\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 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 if (isDebug()) {\n debugFn(\n 'notice',\n 'complete: lockfile scanning, proceeding with install',\n )\n }\n }\n }\n } catch (e) {\n if (isDebug()) {\n debugFn('error', 'caught: pnpm lockfile scanning error')\n debugDir('inspect', { error: e })\n }\n }\n } else if (isDebug()) {\n debugFn(\n 'notice',\n 'skip: no pnpm-lock.yaml found, skipping bulk install scanning',\n )\n }\n }\n\n if (packagePurls.length > 0) {\n if (isDebug()) {\n debugFn('notice', 'scanning: packages before download')\n debugDir('inspect', { packagePurls })\n }\n\n try {\n const alertsMap = await getAlertsMapFromPurls(packagePurls, {\n nothrow: true,\n filter: acceptRisks\n ? { actions: ['error'], blocked: true }\n : { actions: ['error', 'monitor', 'warn'] },\n })\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 = `\nSocket 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 } catch (e) {\n // Re-throw process.exit errors from tests.\n if (e instanceof Error && e.message === 'process.exit called') {\n throw e\n }\n if (isDebug()) {\n debugFn('error', 'caught: package scanning error')\n debugDir('inspect', { error: e })\n }\n // Continue with installation if scanning fails\n }\n }\n\n if (isDebug()) {\n debugFn('notice', 'complete: scanning, proceeding with install')\n debugDir('inspect', { args: rawPnpmArgs.slice(1) })\n }\n }\n\n const argsToString = cmdFlagsToString([...prefixArgs, ...suffixArgs])\n const env = {\n ...process.env,\n ...spawnEnv,\n } as Record<string, string>\n\n if (isDebug()) {\n debugFn('notice', `spawn: pnpm shadow bin ${realPnpmPath} ${argsToString}`)\n }\n\n const spawnPromise = spawn(realPnpmPath, [...prefixArgs, ...suffixArgs], {\n ...spawnOpts,\n env,\n extra,\n })\n\n return { spawnPromise }\n}\n"],"names":["WIN32","env","__proto__","cwd","name","version","packagePurls","debugFn","nothrow","blocked","actions","hideAt","logger","process","error","args","extra","spawnPromise"],"mappings":";;;;;;;;;;;;AAUO;AAIL;AACA;;AACQA;AAAM;;AAEd;;AAEE;AACF;AAEA;;AAEA;;AAEE;;AAKA;;AACQC;AAAI;AACZA;AACF;AAEA;AACF;;ACJA;AAUe;AAKb;AAAeC;;;;AACPD;;;AAAiC;;AAEnCE;AAAoB;;AAExBA;AACF;AAEA;AACA;AACA;;AAEA;AACA;;;AAGA;;;AAKE;AACA;;;;;;;AAUA;;;AAIE;;AAKA;AACE;AACA;AACA;AAEA;AACE;AACA;AACA;AACE;AACAC;AACF;AACE;AACAA;AACAC;AACF;AACF;AACE;AACA;AACA;AACED;AACF;;;AAGA;AACF;AAEA;AACEE;AAGF;AACF;AACF;AACE;;AAEA;;AAEI;AACA;AACE;AACA;AACE;;AAEEC;AAIF;AAEA;AACEC;;;AAE0BC;AAAc;AAClCC;AAAsC;AAC9C;;;;AAKIC;;AAEF;;AAYAC;AACA;AACAC;AACA;AACA;AACF;;AAEA;;AAEEN;AAIF;AACF;AACF;;;AAGEA;;AACsBO;AAAS;AACjC;AACF;AACF;AACEP;AAIF;AACF;AAEA;;AAEIA;;AACsBD;AAAa;AACrC;;AAGE;AACEE;;;AAE0BC;AAAc;AAClCC;AAAsC;AAC9C;;;;AAKIC;;AAEF;AAEA;AACV;AAUUC;AACA;AACAC;AACA;AACA;AACF;;AAEA;;AAEE;AACF;;AAEEN;;AACsBO;AAAS;AACjC;AACA;AACF;AACF;;AAGEP;;AACsBQ;AAA2B;AACnD;AACF;;AAGA;;;;;;AAOA;AAEA;AACE;;AAEAC;AACF;;AAESC;;AACX;;","debugId":"95396bfd-89e3-4dec-a9d6-623419962b28"}
@@ -0,0 +1,200 @@
1
+ 'use strict';
2
+
3
+ var fs = require('node:fs');
4
+ var require$$9 = require('../external/@socketsecurity/registry/lib/debug');
5
+ var logger = require('../external/@socketsecurity/registry/lib/logger');
6
+ var spawn = require('../external/@socketsecurity/registry/lib/spawn');
7
+ var path = require('node:path');
8
+ var vendor = require('./vendor.js');
9
+ var constants = require('./constants.js');
10
+ 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
+ }
32
+
33
+ const INSTALL_COMMANDS = new Set(['add', 'install', 'up', 'upgrade', 'upgrade-interactive']);
34
+ const DLX_COMMANDS = new Set(['dlx']);
35
+ async function shadowYarn(args = process.argv.slice(2), options, extra) {
36
+ const {
37
+ env: spawnEnv,
38
+ ipc,
39
+ ...spawnOpts
40
+ } = {
41
+ __proto__: null,
42
+ ...options
43
+ };
44
+ const terminatorPos = args.indexOf('--');
45
+ const rawYarnArgs = terminatorPos === -1 ? args : args.slice(0, terminatorPos);
46
+ const otherArgs = terminatorPos === -1 ? [] : args.slice(terminatorPos);
47
+
48
+ // Check if this is a command that needs security scanning
49
+ const command = rawYarnArgs[0];
50
+ const needsScanning = command && (INSTALL_COMMANDS.has(command) || DLX_COMMANDS.has(command));
51
+
52
+ // Get yarn path
53
+ const realYarnPath = await installLinks(constants.default.shadowBinPath, 'yarn');
54
+ const permArgs = [];
55
+ const prefixArgs = [];
56
+ const suffixArgs = [...rawYarnArgs, ...permArgs, ...otherArgs];
57
+ if (needsScanning && !rawYarnArgs.includes('--dry-run')) {
58
+ const acceptRisks = Boolean(process.env['SOCKET_CLI_ACCEPT_RISKS']);
59
+ const viewAllRisks = Boolean(process.env['SOCKET_CLI_VIEW_ALL_RISKS']);
60
+
61
+ // Extract package names from command arguments before any downloads
62
+ const packagePurls = [];
63
+ if (command === 'add' || command === 'dlx') {
64
+ // For 'yarn add package1 package2@version' or 'yarn dlx package'
65
+ const packageArgs = rawYarnArgs.slice(1).filter(arg => !arg.startsWith('-') && arg !== '--');
66
+ for (const pkgSpec of packageArgs) {
67
+ // Handle package specs like 'lodash', 'lodash@4.17.21', '@types/node@^20.0.0'
68
+ let name;
69
+ let version;
70
+ if (pkgSpec.startsWith('@')) {
71
+ // Scoped package: @scope/name or @scope/name@version
72
+ const parts = pkgSpec.split('@');
73
+ if (parts.length === 2) {
74
+ // @scope/name (no version)
75
+ name = pkgSpec;
76
+ } else {
77
+ // @scope/name@version
78
+ name = `@${parts[1]}`;
79
+ version = parts[2];
80
+ }
81
+ } else {
82
+ // Regular package: name or name@version
83
+ const atIndex = pkgSpec.indexOf('@');
84
+ if (atIndex === -1) {
85
+ name = pkgSpec;
86
+ } else {
87
+ name = pkgSpec.slice(0, atIndex);
88
+ version = pkgSpec.slice(atIndex + 1);
89
+ }
90
+ }
91
+ if (name) {
92
+ packagePurls.push(version ? utils.idToNpmPurl(`${name}@${version}`) : utils.idToNpmPurl(name));
93
+ }
94
+ }
95
+ } else if (['install', 'up', 'upgrade', 'upgrade-interactive'].includes(command)) {
96
+ // For install/upgrade, scan all dependencies from package.json
97
+ // Note: This scans direct dependencies only. For full transitive dependency
98
+ // scanning, yarn.lock parsing would be needed (not yet implemented)
99
+ try {
100
+ const packageJsonContent = await fs.promises.readFile('package.json', 'utf8');
101
+ const packageJson = JSON.parse(packageJsonContent);
102
+ const allDeps = {
103
+ ...packageJson.dependencies,
104
+ ...packageJson.devDependencies,
105
+ ...packageJson.optionalDependencies,
106
+ ...packageJson.peerDependencies
107
+ };
108
+ for (const [name, version] of Object.entries(allDeps)) {
109
+ if (typeof version === 'string') {
110
+ packagePurls.push(utils.idToNpmPurl(`${name}@${version}`));
111
+ } else {
112
+ packagePurls.push(utils.idToNpmPurl(name));
113
+ }
114
+ }
115
+ if (require$$9.isDebug()) {
116
+ require$$9.debugFn('notice', `scanning: ${packagePurls.length} direct dependencies from package.json`);
117
+ require$$9.debugFn('notice', 'note: transitive dependencies not scanned (yarn.lock parsing not implemented)');
118
+ }
119
+ } catch (e) {
120
+ if (require$$9.isDebug()) {
121
+ require$$9.debugFn('error', 'caught: package.json read error during dependency scanning');
122
+ require$$9.debugDir('inspect', {
123
+ error: e
124
+ });
125
+ }
126
+ }
127
+ }
128
+ if (packagePurls.length > 0) {
129
+ if (require$$9.isDebug()) {
130
+ require$$9.debugFn('notice', 'scanning: packages before download');
131
+ require$$9.debugDir('inspect', {
132
+ packagePurls
133
+ });
134
+ }
135
+ try {
136
+ const alertsMap = await utils.getAlertsMapFromPurls(packagePurls, {
137
+ nothrow: true,
138
+ filter: acceptRisks ? {
139
+ actions: ['error'],
140
+ blocked: true
141
+ } : {
142
+ actions: ['error', 'monitor', 'warn']
143
+ }
144
+ });
145
+ if (alertsMap.size) {
146
+ process.exitCode = 1;
147
+ utils.logAlertsMap(alertsMap, {
148
+ hideAt: viewAllRisks ? 'none' : 'middle',
149
+ output: process.stderr
150
+ });
151
+ const errorMessage = `
152
+ Socket yarn 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();
153
+ logger.logger.error(errorMessage);
154
+ // eslint-disable-next-line n/no-process-exit
155
+ process.exit(1);
156
+ // This line is never reached in production, but helps tests.
157
+ throw new Error('process.exit called');
158
+ }
159
+ } catch (e) {
160
+ // Re-throw process.exit errors from tests.
161
+ if (e instanceof Error && e.message === 'process.exit called') {
162
+ throw e;
163
+ }
164
+ if (require$$9.isDebug()) {
165
+ require$$9.debugFn('error', 'caught: package scanning error');
166
+ require$$9.debugDir('inspect', {
167
+ error: e
168
+ });
169
+ }
170
+ // Continue with installation if scanning fails
171
+ }
172
+ }
173
+ if (require$$9.isDebug()) {
174
+ require$$9.debugFn('notice', 'complete: scanning, proceeding with install');
175
+ require$$9.debugDir('inspect', {
176
+ args: rawYarnArgs.slice(1)
177
+ });
178
+ }
179
+ }
180
+ const argsToString = utils.cmdFlagsToString([...prefixArgs, ...suffixArgs]);
181
+ const env = {
182
+ ...process.env,
183
+ ...spawnEnv
184
+ };
185
+ if (require$$9.isDebug()) {
186
+ require$$9.debugFn('notice', `spawn: yarn shadow bin ${realYarnPath} ${argsToString}`);
187
+ }
188
+ const spawnPromise = spawn.spawn(realYarnPath, [...prefixArgs, ...suffixArgs], {
189
+ ...spawnOpts,
190
+ env,
191
+ extra
192
+ });
193
+ return {
194
+ spawnPromise
195
+ };
196
+ }
197
+
198
+ module.exports = shadowYarn;
199
+ //# debugId=ff5e070d-ede1-4e55-b8e9-dfa667ad45a0
200
+ //# sourceMappingURL=shadow-yarn-bin.js.map
@@ -0,0 +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 { promises as fs } from 'node:fs'\n\nimport { debugDir, debugFn, isDebug } from '@socketsecurity/registry/lib/debug'\nimport { logger } from '@socketsecurity/registry/lib/logger'\nimport { spawn } from '@socketsecurity/registry/lib/spawn'\n\nimport { installLinks } from './link.mts'\nimport constants from '../../constants.mts'\nimport { getAlertsMapFromPurls } from '../../utils/alerts-map.mts'\nimport { cmdFlagsToString } from '../../utils/cmd.mts'\nimport { logAlertsMap } from '../../utils/socket-package-alert.mts'\nimport { idToNpmPurl } from '../../utils/spec.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 INSTALL_COMMANDS = new Set([\n 'add',\n 'install',\n 'up',\n 'upgrade',\n 'upgrade-interactive',\n])\n\nconst DLX_COMMANDS = new Set(['dlx'])\n\nexport default async function shadowYarn(\n args: string[] | readonly string[] = process.argv.slice(2),\n options?: ShadowYarnOptions | undefined,\n extra?: SpawnExtra | undefined,\n): Promise<ShadowYarnResult> {\n const {\n env: spawnEnv,\n ipc,\n ...spawnOpts\n } = { __proto__: null, ...options } as ShadowYarnOptions\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 if this is a command that needs security scanning\n const command = rawYarnArgs[0]\n const needsScanning =\n command && (INSTALL_COMMANDS.has(command) || DLX_COMMANDS.has(command))\n\n // Get yarn path\n const realYarnPath = await installLinks(constants.shadowBinPath, 'yarn')\n\n const permArgs: string[] = []\n\n const prefixArgs: string[] = []\n const suffixArgs = [...rawYarnArgs, ...permArgs, ...otherArgs]\n\n if (needsScanning && !rawYarnArgs.includes('--dry-run')) {\n const acceptRisks = Boolean(process.env['SOCKET_CLI_ACCEPT_RISKS'])\n const viewAllRisks = Boolean(process.env['SOCKET_CLI_VIEW_ALL_RISKS'])\n\n // Extract package names from command arguments before any downloads\n const packagePurls: string[] = []\n\n if (command === 'add' || command === 'dlx') {\n // For 'yarn add package1 package2@version' or 'yarn dlx package'\n const packageArgs = rawYarnArgs\n .slice(1)\n .filter(arg => !arg.startsWith('-') && arg !== '--')\n\n for (const pkgSpec of packageArgs) {\n // Handle package specs like 'lodash', 'lodash@4.17.21', '@types/node@^20.0.0'\n let name: string\n let version: string | undefined\n\n if (pkgSpec.startsWith('@')) {\n // Scoped package: @scope/name or @scope/name@version\n const parts = pkgSpec.split('@')\n if (parts.length === 2) {\n // @scope/name (no version)\n name = pkgSpec\n } else {\n // @scope/name@version\n name = `@${parts[1]}`\n version = parts[2]\n }\n } else {\n // Regular package: name or name@version\n const atIndex = pkgSpec.indexOf('@')\n if (atIndex === -1) {\n name = pkgSpec\n } else {\n name = pkgSpec.slice(0, atIndex)\n version = pkgSpec.slice(atIndex + 1)\n }\n }\n\n if (name) {\n packagePurls.push(\n version ? idToNpmPurl(`${name}@${version}`) : idToNpmPurl(name),\n )\n }\n }\n } else if (\n ['install', 'up', 'upgrade', 'upgrade-interactive'].includes(command)\n ) {\n // For install/upgrade, scan all dependencies from package.json\n // Note: This scans direct dependencies only. For full transitive dependency\n // scanning, yarn.lock parsing would be needed (not yet implemented)\n try {\n const packageJsonContent = await fs.readFile('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 if (typeof version === 'string') {\n packagePurls.push(idToNpmPurl(`${name}@${version}`))\n } else {\n packagePurls.push(idToNpmPurl(name))\n }\n }\n\n if (isDebug()) {\n debugFn(\n 'notice',\n `scanning: ${packagePurls.length} direct dependencies from package.json`,\n )\n debugFn(\n 'notice',\n 'note: transitive dependencies not scanned (yarn.lock parsing not implemented)',\n )\n }\n } catch (e) {\n if (isDebug()) {\n debugFn(\n 'error',\n 'caught: package.json read error during dependency scanning',\n )\n debugDir('inspect', { error: e })\n }\n }\n }\n\n if (packagePurls.length > 0) {\n if (isDebug()) {\n debugFn('notice', 'scanning: packages before download')\n debugDir('inspect', { packagePurls })\n }\n\n try {\n const alertsMap = await getAlertsMapFromPurls(packagePurls, {\n nothrow: true,\n filter: acceptRisks\n ? { actions: ['error'], blocked: true }\n : { actions: ['error', 'monitor', 'warn'] },\n })\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 = `\nSocket yarn 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 } catch (e) {\n // Re-throw process.exit errors from tests.\n if (e instanceof Error && e.message === 'process.exit called') {\n throw e\n }\n if (isDebug()) {\n debugFn('error', 'caught: package scanning error')\n debugDir('inspect', { error: e })\n }\n // Continue with installation if scanning fails\n }\n }\n\n if (isDebug()) {\n debugFn('notice', 'complete: scanning, proceeding with install')\n debugDir('inspect', { args: rawYarnArgs.slice(1) })\n }\n }\n\n const argsToString = cmdFlagsToString([...prefixArgs, ...suffixArgs])\n const env = {\n ...process.env,\n ...spawnEnv,\n } as Record<string, string>\n\n if (isDebug()) {\n debugFn('notice', `spawn: yarn shadow bin ${realYarnPath} ${argsToString}`)\n }\n\n const spawnPromise = spawn(realYarnPath, [...prefixArgs, ...suffixArgs], {\n ...spawnOpts,\n env,\n extra,\n })\n\n return { spawnPromise }\n}\n"],"names":["WIN32","env","__proto__","name","version","packagePurls","debugFn","error","nothrow","blocked","actions","hideAt","logger","process","args","extra","spawnPromise"],"mappings":";;;;;;;;;;;AAUO;AAIL;;AACQA;AAAM;;AAGZ;AACF;AAEA;;AAGE;;AAKA;;AACQC;AAAI;AACZA;AACF;AAEA;AACF;;ACPA;AAQA;AAEe;;AAMXA;;;AAGF;AAAMC;;;AACN;AACA;AACA;;AAEA;AACA;AACA;;AAGA;;;;;;;;;AAYE;;AAGA;AACE;;AAKA;AACE;AACA;AACA;AAEA;AACE;AACA;AACA;AACE;AACAC;AACF;AACE;AACAA;AACAC;AACF;AACF;AACE;AACA;AACA;AACED;AACF;;;AAGA;AACF;AAEA;AACEE;AAGF;AACF;AACF;AAGE;AACA;AACA;;;AAGE;AAEA;;;;AAIE;;AAGF;AACE;;AAEA;AACEA;AACF;AACF;;;AAOEC;AAIF;;;AAGEA;;AAIsBC;AAAS;AACjC;AACF;AACF;AAEA;;AAEID;;AACsBD;AAAa;AACrC;;AAGE;AACEG;;;AAE0BC;AAAc;AAClCC;AAAsC;AAC9C;;;;AAKIC;;AAEF;AAEA;AACV;AAUUC;AACA;AACAC;AACA;AACA;AACF;;AAEA;;AAEE;AACF;;AAEEP;;AACsBC;AAAS;AACjC;AACA;AACF;AACF;;AAGED;;AACsBQ;AAA2B;AACnD;AACF;;AAGA;;;;;;AAOA;AAEA;AACE;;AAEAC;AACF;;AAESC;;AACX;;","debugId":"ff5e070d-ede1-4e55-b8e9-dfa667ad45a0"}