@socketsecurity/cli-with-sentry 1.1.18 → 1.1.19
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.
- package/CHANGELOG.md +6 -0
- package/bin/npm-cli.js +2 -2
- package/bin/npx-cli.js +2 -2
- package/bin/pnpm-cli.js +2 -2
- package/bin/yarn-cli.js +2 -2
- package/dist/cli.js +238 -94
- package/dist/cli.js.map +1 -1
- package/dist/constants.js +5 -3
- package/dist/constants.js.map +1 -1
- package/dist/flags.js +3 -2
- package/dist/flags.js.map +1 -1
- package/dist/npm-cli.js +3 -4
- package/dist/npm-cli.js.map +1 -1
- package/dist/npx-cli.js +3 -3
- package/dist/npx-cli.js.map +1 -1
- package/dist/pnpm-cli.js +3 -3
- package/dist/pnpm-cli.js.map +1 -1
- package/dist/shadow-npm-bin.js +3 -106
- package/dist/shadow-npm-bin.js.map +1 -1
- package/dist/shadow-npm-bin2.js +125 -0
- package/dist/shadow-npm-bin2.js.map +1 -0
- package/dist/shadow-npx-bin.js +12 -0
- package/dist/shadow-npx-bin.js.map +1 -0
- package/dist/shadow-pnpm-bin.js +3 -228
- package/dist/shadow-pnpm-bin.js.map +1 -1
- package/dist/shadow-pnpm-bin2.js +319 -0
- package/dist/shadow-pnpm-bin2.js.map +1 -0
- package/dist/shadow-yarn-bin.js +58 -150
- package/dist/shadow-yarn-bin.js.map +1 -1
- package/dist/tsconfig.dts.tsbuildinfo +1 -1
- package/dist/types/commands/analytics/cmd-analytics.d.mts.map +1 -1
- package/dist/types/commands/analytics/output-analytics.d.mts.map +1 -1
- package/dist/types/commands/audit-log/cmd-audit-log.d.mts.map +1 -1
- package/dist/types/commands/audit-log/output-audit-log.d.mts.map +1 -1
- package/dist/types/commands/ci/handle-ci.d.mts.map +1 -1
- package/dist/types/commands/config/cmd-config-auto.d.mts.map +1 -1
- package/dist/types/commands/config/cmd-config-get.d.mts.map +1 -1
- package/dist/types/commands/config/cmd-config-list.d.mts.map +1 -1
- package/dist/types/commands/config/cmd-config-set.d.mts.map +1 -1
- package/dist/types/commands/config/cmd-config-unset.d.mts.map +1 -1
- package/dist/types/commands/config/handle-config-set.d.mts.map +1 -1
- package/dist/types/commands/fix/cmd-fix.d.mts.map +1 -1
- package/dist/types/commands/fix/coana-fix.d.mts.map +1 -1
- package/dist/types/commands/fix/handle-fix.d.mts.map +1 -1
- package/dist/types/commands/fix/pull-request.d.mts.map +1 -1
- package/dist/types/commands/manifest/cmd-manifest-conda.d.mts.map +1 -1
- package/dist/types/commands/npm/cmd-npm.d.mts.map +1 -1
- package/dist/types/commands/optimize/handle-optimize.d.mts.map +1 -1
- package/dist/types/commands/organization/cmd-organization-dependencies.d.mts.map +1 -1
- package/dist/types/commands/organization/cmd-organization-list.d.mts.map +1 -1
- package/dist/types/commands/organization/handle-dependencies.d.mts.map +1 -1
- package/dist/types/commands/organization/handle-organization-list.d.mts.map +1 -1
- package/dist/types/commands/package/handle-purl-deep-score.d.mts.map +1 -1
- package/dist/types/commands/package/handle-purls-shallow-score.d.mts.map +1 -1
- package/dist/types/commands/pnpm/cmd-pnpm.d.mts.map +1 -1
- package/dist/types/commands/repository/cmd-repository-list.d.mts.map +1 -1
- package/dist/types/commands/repository/cmd-repository-view.d.mts.map +1 -1
- package/dist/types/commands/repository/handle-create-repo.d.mts.map +1 -1
- package/dist/types/commands/scan/cmd-scan-diff.d.mts.map +1 -1
- package/dist/types/commands/scan/create-scan-from-github.d.mts.map +1 -1
- package/dist/types/commands/scan/fetch-report-data.d.mts.map +1 -1
- package/dist/types/commands/scan/handle-create-new-scan.d.mts.map +1 -1
- package/dist/types/commands/wrapper/postinstall-wrapper.d.mts.map +1 -1
- package/dist/types/commands/yarn/cmd-yarn.d.mts.map +1 -1
- package/dist/types/constants.d.mts +1 -0
- package/dist/types/constants.d.mts.map +1 -1
- package/dist/types/flags.d.mts.map +1 -1
- package/dist/types/shadow/common.d.mts +31 -0
- package/dist/types/shadow/common.d.mts.map +1 -0
- package/dist/types/shadow/npm/bin.d.mts +4 -10
- package/dist/types/shadow/npm/bin.d.mts.map +1 -1
- package/dist/types/shadow/npm-base.d.mts +11 -0
- package/dist/types/shadow/npm-base.d.mts.map +1 -0
- package/dist/types/shadow/npx/bin.d.mts +5 -0
- package/dist/types/shadow/npx/bin.d.mts.map +1 -0
- package/dist/types/shadow/pnpm/bin.d.mts +1 -1
- package/dist/types/shadow/pnpm/bin.d.mts.map +1 -1
- package/dist/types/shadow/stdio-ipc.d.mts +7 -0
- package/dist/types/shadow/stdio-ipc.d.mts.map +1 -0
- package/dist/types/shadow/yarn/bin.d.mts +1 -1
- package/dist/types/shadow/yarn/bin.d.mts.map +1 -1
- package/dist/types/utils/agent.d.mts.map +1 -1
- package/dist/types/utils/alerts-map.d.mts.map +1 -1
- package/dist/types/utils/api.d.mts.map +1 -1
- package/dist/types/utils/cmd.d.mts.map +1 -1
- package/dist/types/utils/coana.d.mts.map +1 -1
- package/dist/types/utils/color-or-markdown.d.mts.map +1 -1
- package/dist/types/utils/config.d.mts.map +1 -1
- package/dist/types/utils/cve-to-ghsa.d.mts.map +1 -1
- package/dist/types/utils/debug.d.mts +45 -0
- package/dist/types/utils/debug.d.mts.map +1 -0
- package/dist/types/utils/dlx.d.mts +1 -1
- package/dist/types/utils/dlx.d.mts.map +1 -1
- package/dist/types/utils/ecosystem.d.mts.map +1 -1
- package/dist/types/utils/errors.d.mts +48 -0
- package/dist/types/utils/errors.d.mts.map +1 -1
- package/dist/types/utils/filter-config.d.mts.map +1 -1
- package/dist/types/utils/fs.d.mts.map +1 -1
- package/dist/types/utils/get-output-kind.d.mts.map +1 -1
- package/dist/types/utils/git.d.mts.map +1 -1
- package/dist/types/utils/github.d.mts.map +1 -1
- package/dist/types/utils/markdown.d.mts +17 -0
- package/dist/types/utils/markdown.d.mts.map +1 -1
- package/dist/types/utils/meow-with-subcommands.d.mts.map +1 -1
- package/dist/types/utils/npm-package-arg.d.mts +5 -1
- package/dist/types/utils/npm-package-arg.d.mts.map +1 -1
- package/dist/types/utils/npm-paths.d.mts.map +1 -1
- package/dist/types/utils/npm-spec.d.mts +57 -0
- package/dist/types/utils/npm-spec.d.mts.map +1 -0
- package/dist/types/utils/output-formatting.d.mts.map +1 -1
- package/dist/types/utils/package-environment.d.mts.map +1 -1
- package/dist/types/utils/pnpm-paths.d.mts.map +1 -1
- package/dist/types/utils/purl-to-ghsa.d.mts.map +1 -1
- package/dist/types/utils/purl.d.mts +24 -0
- package/dist/types/utils/purl.d.mts.map +1 -1
- package/dist/types/utils/requirements.d.mts.map +1 -1
- package/dist/types/utils/sdk.d.mts.map +1 -1
- package/dist/types/utils/serialize-result-json.d.mts.map +1 -1
- package/dist/types/utils/socket-json.d.mts.map +1 -1
- package/dist/types/utils/socket-package-alert.d.mts.map +1 -1
- package/dist/types/utils/socket-url.d.mts.map +1 -1
- package/dist/types/utils/strings.d.mts +12 -0
- package/dist/types/utils/strings.d.mts.map +1 -1
- package/dist/types/utils/tildify.d.mts +0 -2
- package/dist/types/utils/tildify.d.mts.map +1 -1
- package/dist/types/utils/yarn-paths.d.mts.map +1 -1
- package/dist/utils.js +1303 -457
- package/dist/utils.js.map +1 -1
- package/dist/vendor.js +311 -311
- package/package.json +3 -3
- package/shadow-bin/npm +2 -2
- package/shadow-bin/npx +2 -2
- package/shadow-bin/pnpm +2 -2
- package/shadow-bin/yarn +2 -2
|
@@ -0,0 +1,319 @@
|
|
|
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 constants = require('./constants.js');
|
|
10
|
+
var utils = require('./utils.js');
|
|
11
|
+
var shadowNpmBin = require('./shadow-npm-bin2.js');
|
|
12
|
+
var vendor = require('./vendor.js');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Extract package PURLs from add/dlx command arguments.
|
|
16
|
+
*/
|
|
17
|
+
function extractPackagePurlsFromArgs(command, rawArgs, dlxCommands) {
|
|
18
|
+
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
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return packagePurls;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Extract package PURLs from package.json for install/update commands.
|
|
35
|
+
*/
|
|
36
|
+
async function extractPackagePurlsFromPackageJson(cwd) {
|
|
37
|
+
const packagePurls = [];
|
|
38
|
+
try {
|
|
39
|
+
const packageJsonContent = await fs.promises.readFile(`${cwd}/package.json`, 'utf8');
|
|
40
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
41
|
+
const allDeps = {
|
|
42
|
+
...packageJson.dependencies,
|
|
43
|
+
...packageJson.devDependencies,
|
|
44
|
+
...packageJson.optionalDependencies,
|
|
45
|
+
...packageJson.peerDependencies
|
|
46
|
+
};
|
|
47
|
+
for (const [name, version] of Object.entries(allDeps)) {
|
|
48
|
+
const purl = utils.safeNpmSpecToPurl(typeof version === 'string' ? `${name}@${version}` : name);
|
|
49
|
+
if (purl) {
|
|
50
|
+
packagePurls.push(purl);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
utils.debugScan('start', packagePurls.length);
|
|
54
|
+
} catch (e) {
|
|
55
|
+
require$$9.debugFn('warn', 'Package.json not found or invalid during dependency scanning');
|
|
56
|
+
require$$9.debugDir('error', e);
|
|
57
|
+
}
|
|
58
|
+
return packagePurls;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Scan packages and log alerts if found.
|
|
62
|
+
*/
|
|
63
|
+
async function scanPackagesAndLogAlerts(options) {
|
|
64
|
+
const {
|
|
65
|
+
acceptRisks,
|
|
66
|
+
command,
|
|
67
|
+
dlxCommands,
|
|
68
|
+
installCommands,
|
|
69
|
+
managerName,
|
|
70
|
+
nothrow = true,
|
|
71
|
+
rawArgs,
|
|
72
|
+
spinner,
|
|
73
|
+
viewAllRisks
|
|
74
|
+
} = options;
|
|
75
|
+
let {
|
|
76
|
+
cwd = process.cwd()
|
|
77
|
+
} = options;
|
|
78
|
+
if (cwd instanceof URL) {
|
|
79
|
+
cwd = require$$0.fileURLToPath(cwd);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Check if this is a command that needs security scanning.
|
|
83
|
+
const isDlxCommand = dlxCommands && command && dlxCommands.has(command);
|
|
84
|
+
const isInstallCommand = command && installCommands.has(command);
|
|
85
|
+
const needsScanning = isDlxCommand || isInstallCommand;
|
|
86
|
+
if (!needsScanning || rawArgs.includes(constants.FLAG_DRY_RUN)) {
|
|
87
|
+
return {
|
|
88
|
+
shouldExit: false
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Extract package names from command arguments before any downloads.
|
|
93
|
+
let packagePurls = [];
|
|
94
|
+
if (command === 'add' || isDlxCommand) {
|
|
95
|
+
packagePurls = extractPackagePurlsFromArgs(command, rawArgs, dlxCommands);
|
|
96
|
+
} else if (isInstallCommand) {
|
|
97
|
+
// For install/update, scan dependencies from package.json.
|
|
98
|
+
// Note: This scans direct dependencies only.
|
|
99
|
+
packagePurls = await extractPackagePurlsFromPackageJson(cwd);
|
|
100
|
+
}
|
|
101
|
+
if (!packagePurls.length) {
|
|
102
|
+
return {
|
|
103
|
+
shouldExit: false
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
utils.debugScan('start', packagePurls.length);
|
|
107
|
+
require$$9.debugDir('inspect', {
|
|
108
|
+
packagePurls
|
|
109
|
+
});
|
|
110
|
+
try {
|
|
111
|
+
const alertsMap = await utils.getAlertsMapFromPurls(packagePurls, {
|
|
112
|
+
filter: acceptRisks ? {
|
|
113
|
+
actions: ['error'],
|
|
114
|
+
blocked: true
|
|
115
|
+
} : {
|
|
116
|
+
actions: ['error', 'monitor', 'warn']
|
|
117
|
+
},
|
|
118
|
+
nothrow,
|
|
119
|
+
spinner
|
|
120
|
+
});
|
|
121
|
+
if (alertsMap.size) {
|
|
122
|
+
process.exitCode = 1;
|
|
123
|
+
spinner?.stop();
|
|
124
|
+
utils.logAlertsMap(alertsMap, {
|
|
125
|
+
hideAt: viewAllRisks ? 'none' : 'middle',
|
|
126
|
+
output: process.stderr
|
|
127
|
+
});
|
|
128
|
+
const errorMessage = `Socket ${managerName} 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();
|
|
129
|
+
logger.logger.error(errorMessage);
|
|
130
|
+
return {
|
|
131
|
+
alertsMap,
|
|
132
|
+
shouldExit: true
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
} catch (e) {
|
|
136
|
+
spinner?.stop();
|
|
137
|
+
// Re-throw process.exit errors from tests.
|
|
138
|
+
if (e instanceof Error && e.message === 'process.exit called') {
|
|
139
|
+
throw e;
|
|
140
|
+
}
|
|
141
|
+
utils.debugScan('error', undefined, e);
|
|
142
|
+
// Continue with installation if scanning fails.
|
|
143
|
+
}
|
|
144
|
+
utils.debugScan('complete', packagePurls.length);
|
|
145
|
+
require$$9.debugDir('inspect', {
|
|
146
|
+
args: rawArgs.slice(1)
|
|
147
|
+
});
|
|
148
|
+
return {
|
|
149
|
+
shouldExit: false
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
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
|
+
const DLX_COMMANDS = new Set(['dlx']);
|
|
180
|
+
const INSTALL_COMMANDS = new Set(['add', 'i', 'install', 'install-test', 'it', 'update', 'up']);
|
|
181
|
+
async function shadowPnpmBin(args = process.argv.slice(2), options, extra) {
|
|
182
|
+
const opts = {
|
|
183
|
+
__proto__: null,
|
|
184
|
+
...options
|
|
185
|
+
};
|
|
186
|
+
const {
|
|
187
|
+
env: spawnEnv,
|
|
188
|
+
ipc,
|
|
189
|
+
...spawnOpts
|
|
190
|
+
} = opts;
|
|
191
|
+
const {
|
|
192
|
+
spinner
|
|
193
|
+
} = opts;
|
|
194
|
+
const wasSpinning = !!spinner?.isSpinning;
|
|
195
|
+
spinner?.start();
|
|
196
|
+
let {
|
|
197
|
+
cwd = process.cwd()
|
|
198
|
+
} = opts;
|
|
199
|
+
if (cwd instanceof URL) {
|
|
200
|
+
cwd = require$$0.fileURLToPath(cwd);
|
|
201
|
+
}
|
|
202
|
+
const terminatorPos = args.indexOf('--');
|
|
203
|
+
const rawPnpmArgs = terminatorPos === -1 ? args : args.slice(0, terminatorPos);
|
|
204
|
+
const otherArgs = terminatorPos === -1 ? [] : args.slice(terminatorPos);
|
|
205
|
+
|
|
206
|
+
// Check if this is a command that needs security scanning.
|
|
207
|
+
const command = rawPnpmArgs[0];
|
|
208
|
+
const isDlxCommand = command && DLX_COMMANDS.has(command);
|
|
209
|
+
const isInstallCommand = command && INSTALL_COMMANDS.has(command);
|
|
210
|
+
const needsScanning = isDlxCommand || isInstallCommand;
|
|
211
|
+
if (needsScanning && !rawPnpmArgs.includes(constants.FLAG_DRY_RUN)) {
|
|
212
|
+
const acceptRisks = !!constants.default.ENV.SOCKET_CLI_ACCEPT_RISKS;
|
|
213
|
+
const viewAllRisks = !!constants.default.ENV.SOCKET_CLI_VIEW_ALL_RISKS;
|
|
214
|
+
|
|
215
|
+
// Handle add and dlx commands with shared utility.
|
|
216
|
+
if (command === 'add' || isDlxCommand) {
|
|
217
|
+
const scanResult = await scanPackagesAndLogAlerts({
|
|
218
|
+
acceptRisks,
|
|
219
|
+
command,
|
|
220
|
+
cwd,
|
|
221
|
+
dlxCommands: DLX_COMMANDS,
|
|
222
|
+
installCommands: INSTALL_COMMANDS,
|
|
223
|
+
managerName: 'pnpm',
|
|
224
|
+
rawArgs: rawPnpmArgs,
|
|
225
|
+
spinner,
|
|
226
|
+
viewAllRisks
|
|
227
|
+
});
|
|
228
|
+
if (scanResult.shouldExit) {
|
|
229
|
+
// eslint-disable-next-line n/no-process-exit
|
|
230
|
+
process.exit(1);
|
|
231
|
+
// This line is never reached in production, but helps tests.
|
|
232
|
+
throw new Error('process.exit called');
|
|
233
|
+
}
|
|
234
|
+
} else if (['install', 'i', 'update', 'up'].includes(command)) {
|
|
235
|
+
// For install/update, scan all dependencies from pnpm-lock.yaml
|
|
236
|
+
const pnpmLockPath = path.join(cwd, constants.PNPM_LOCK_YAML);
|
|
237
|
+
if (fs.existsSync(pnpmLockPath)) {
|
|
238
|
+
try {
|
|
239
|
+
const lockfileContent = await utils.readPnpmLockfile(pnpmLockPath);
|
|
240
|
+
if (lockfileContent) {
|
|
241
|
+
const lockfile = utils.parsePnpmLockfile(lockfileContent);
|
|
242
|
+
if (lockfile) {
|
|
243
|
+
// Use existing function to scan the entire lockfile
|
|
244
|
+
require$$9.debugFn('notice', `scanning: all dependencies from ${constants.PNPM_LOCK_YAML}`);
|
|
245
|
+
const alertsMap = await utils.getAlertsMapFromPnpmLockfile(lockfile, {
|
|
246
|
+
nothrow: true,
|
|
247
|
+
filter: acceptRisks ? {
|
|
248
|
+
actions: ['error'],
|
|
249
|
+
blocked: true
|
|
250
|
+
} : {
|
|
251
|
+
actions: ['error', 'monitor', 'warn']
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
spinner?.stop();
|
|
255
|
+
if (alertsMap.size) {
|
|
256
|
+
process.exitCode = 1;
|
|
257
|
+
utils.logAlertsMap(alertsMap, {
|
|
258
|
+
hideAt: viewAllRisks ? 'none' : 'middle',
|
|
259
|
+
output: process.stderr
|
|
260
|
+
});
|
|
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();
|
|
262
|
+
logger.logger.error(errorMessage);
|
|
263
|
+
// eslint-disable-next-line n/no-process-exit
|
|
264
|
+
process.exit(1);
|
|
265
|
+
// This line is never reached in production, but helps tests.
|
|
266
|
+
throw new Error('process.exit called');
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Return early since we've already done the scanning
|
|
270
|
+
require$$9.debugFn('notice', 'complete: lockfile scanning, proceeding with install');
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
} catch (e) {
|
|
274
|
+
require$$9.debugFn('error', 'PNPM lockfile scanning failed');
|
|
275
|
+
require$$9.debugDir('error', e);
|
|
276
|
+
}
|
|
277
|
+
} else {
|
|
278
|
+
require$$9.debugFn('notice', 'skip: no pnpm-lock.yaml found, skipping bulk install scanning');
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
require$$9.debugFn('notice', 'complete: scanning, proceeding with install');
|
|
282
|
+
}
|
|
283
|
+
const realPnpmPath = await installLinks(constants.default.shadowBinPath);
|
|
284
|
+
spinner?.stop();
|
|
285
|
+
const suffixArgs = [...rawPnpmArgs, ...otherArgs];
|
|
286
|
+
require$$9.debugFn('notice', `spawn: ${constants.PNPM} shadow bin ${realPnpmPath} ${utils.cmdFlagsToString(suffixArgs)}`);
|
|
287
|
+
if (wasSpinning) {
|
|
288
|
+
spinner?.start();
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Set up stdio with IPC channel.
|
|
292
|
+
const stdio = shadowNpmBin.ensureIpcInStdio(spawnOpts.stdio);
|
|
293
|
+
const spawnPromise = spawn.spawn(realPnpmPath, suffixArgs, {
|
|
294
|
+
...spawnOpts,
|
|
295
|
+
env: {
|
|
296
|
+
...process.env,
|
|
297
|
+
...spawnEnv
|
|
298
|
+
},
|
|
299
|
+
stdio
|
|
300
|
+
}, extra);
|
|
301
|
+
|
|
302
|
+
// Send IPC handshake.
|
|
303
|
+
spawnPromise.process.send({
|
|
304
|
+
[constants.default.SOCKET_IPC_HANDSHAKE]: {
|
|
305
|
+
[constants.default.SOCKET_CLI_SHADOW_API_TOKEN]: utils.getPublicApiToken(),
|
|
306
|
+
[constants.default.SOCKET_CLI_SHADOW_BIN]: constants.PNPM,
|
|
307
|
+
[constants.default.SOCKET_CLI_SHADOW_PROGRESS]: true,
|
|
308
|
+
...ipc
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
return {
|
|
312
|
+
spawnPromise
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
exports.scanPackagesAndLogAlerts = scanPackagesAndLogAlerts;
|
|
317
|
+
exports.shadowPnpmBin = shadowPnpmBin;
|
|
318
|
+
//# debugId=acc15873-04df-4d32-aa27-434eb8c520e1
|
|
319
|
+
//# sourceMappingURL=shadow-pnpm-bin2.js.map
|
|
@@ -0,0 +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 },\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","stdio","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;;;;AAIAO;;;AAKJ;AACAC;;AAEI;AACA;AACA;;AAEF;AACF;;AAESA;;AACX;;;","debugId":"acc15873-04df-4d32-aa27-434eb8c520e1"}
|
package/dist/shadow-yarn-bin.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var fs = require('node:fs');
|
|
4
3
|
var require$$9 = require('../external/@socketsecurity/registry/lib/debug');
|
|
5
|
-
var logger = require('../external/@socketsecurity/registry/lib/logger');
|
|
6
4
|
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
7
|
var path = require('node:path');
|
|
8
8
|
var vendor = require('./vendor.js');
|
|
9
9
|
var constants = require('./constants.js');
|
|
@@ -30,171 +30,79 @@ async function installLinks(shadowBinPath, binName) {
|
|
|
30
30
|
return binPath;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
const INSTALL_COMMANDS = new Set(['add', 'install', 'up', 'upgrade', 'upgrade-interactive']);
|
|
34
33
|
const DLX_COMMANDS = new Set(['dlx']);
|
|
35
|
-
|
|
34
|
+
const INSTALL_COMMANDS = new Set(['add', 'install', 'up', 'upgrade', 'upgrade-interactive']);
|
|
35
|
+
async function shadowYarnBin(args = process.argv.slice(2), options, extra) {
|
|
36
|
+
const opts = {
|
|
37
|
+
__proto__: null,
|
|
38
|
+
...options
|
|
39
|
+
};
|
|
36
40
|
const {
|
|
37
41
|
env: spawnEnv,
|
|
38
42
|
ipc,
|
|
39
43
|
...spawnOpts
|
|
40
|
-
} =
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
};
|
|
44
|
+
} = opts;
|
|
45
|
+
const {
|
|
46
|
+
spinner
|
|
47
|
+
} = opts;
|
|
48
|
+
const wasSpinning = !!spinner?.isSpinning;
|
|
49
|
+
spinner?.start();
|
|
44
50
|
const terminatorPos = args.indexOf('--');
|
|
45
51
|
const rawYarnArgs = terminatorPos === -1 ? args : args.slice(0, terminatorPos);
|
|
46
52
|
const otherArgs = terminatorPos === -1 ? [] : args.slice(terminatorPos);
|
|
47
53
|
|
|
48
|
-
// Check
|
|
54
|
+
// Check for package scanning.
|
|
49
55
|
const command = rawYarnArgs[0];
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
}
|
|
56
|
+
const scanResult = await shadowPnpmBin.scanPackagesAndLogAlerts({
|
|
57
|
+
acceptRisks: !!constants.default.ENV.SOCKET_CLI_ACCEPT_RISKS,
|
|
58
|
+
command,
|
|
59
|
+
cwd: process.cwd(),
|
|
60
|
+
dlxCommands: DLX_COMMANDS,
|
|
61
|
+
installCommands: INSTALL_COMMANDS,
|
|
62
|
+
managerName: 'yarn',
|
|
63
|
+
rawArgs: rawYarnArgs,
|
|
64
|
+
spinner,
|
|
65
|
+
viewAllRisks: !!constants.default.ENV.SOCKET_CLI_VIEW_ALL_RISKS
|
|
66
|
+
});
|
|
67
|
+
if (scanResult.shouldExit) {
|
|
68
|
+
// eslint-disable-next-line n/no-process-exit
|
|
69
|
+
process.exit(1);
|
|
70
|
+
// This line is never reached in production, but helps tests.
|
|
71
|
+
throw new Error('process.exit called');
|
|
179
72
|
}
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
require$$9.debugFn('notice', `spawn: yarn shadow bin ${realYarnPath} ${argsToString}`);
|
|
73
|
+
const realYarnPath = await installLinks(constants.default.shadowBinPath, constants.YARN);
|
|
74
|
+
spinner?.stop();
|
|
75
|
+
const suffixArgs = [...rawYarnArgs, ...otherArgs];
|
|
76
|
+
require$$9.debugFn('notice', `spawn: ${constants.YARN} shadow bin ${realYarnPath} ${utils.cmdFlagsToString(suffixArgs)}`);
|
|
77
|
+
if (wasSpinning) {
|
|
78
|
+
spinner?.start();
|
|
187
79
|
}
|
|
188
|
-
|
|
80
|
+
|
|
81
|
+
// Set up stdio with IPC channel.
|
|
82
|
+
const stdio = shadowNpmBin.ensureIpcInStdio(spawnOpts.stdio);
|
|
83
|
+
const spawnPromise = spawn.spawn(realYarnPath, suffixArgs, {
|
|
189
84
|
...spawnOpts,
|
|
190
|
-
env
|
|
191
|
-
|
|
85
|
+
env: {
|
|
86
|
+
...process.env,
|
|
87
|
+
...spawnEnv
|
|
88
|
+
},
|
|
89
|
+
stdio
|
|
90
|
+
}, extra);
|
|
91
|
+
|
|
92
|
+
// Send IPC handshake.
|
|
93
|
+
spawnPromise.process.send({
|
|
94
|
+
[constants.default.SOCKET_IPC_HANDSHAKE]: {
|
|
95
|
+
[constants.default.SOCKET_CLI_SHADOW_API_TOKEN]: utils.getPublicApiToken(),
|
|
96
|
+
[constants.default.SOCKET_CLI_SHADOW_BIN]: constants.YARN,
|
|
97
|
+
[constants.default.SOCKET_CLI_SHADOW_PROGRESS]: true,
|
|
98
|
+
...ipc
|
|
99
|
+
}
|
|
192
100
|
});
|
|
193
101
|
return {
|
|
194
102
|
spawnPromise
|
|
195
103
|
};
|
|
196
104
|
}
|
|
197
105
|
|
|
198
|
-
module.exports =
|
|
199
|
-
//# debugId=
|
|
106
|
+
module.exports = shadowYarnBin;
|
|
107
|
+
//# debugId=13fbcedb-c0f8-4da1-b471-4a7bc1ea6bd
|
|
200
108
|
//# 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 {
|
|
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 },\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","stdio","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;;;;AAIAY;;;AAKJ;AACAC;;AAEI;AACA;AACA;;AAEF;AACF;;AAESA;;AACX;;","debugId":"13fbcedb-c0f8-4da1-b471-4a7bc1ea6bd"}
|