@socketsecurity/cli-with-sentry 1.1.49 → 1.1.51
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 +13 -0
- package/bin/npm-cli.js +1 -1
- package/bin/npx-cli.js +2 -2
- package/dist/cli.js +100 -509
- package/dist/cli.js.map +1 -1
- package/dist/constants.js +6 -4
- package/dist/constants.js.map +1 -1
- package/dist/tsconfig.dts.tsbuildinfo +1 -1
- package/dist/types/commands/ci/handle-ci.d.mts.map +1 -1
- package/dist/types/commands/patch/cmd-patch.d.mts +1 -1
- package/dist/types/commands/patch/cmd-patch.d.mts.map +1 -1
- package/dist/types/commands/scan/cmd-scan-create.d.mts.map +1 -1
- package/dist/types/commands/scan/cmd-scan-reach.d.mts.map +1 -1
- package/dist/types/commands/scan/output-scan-report.d.mts.map +1 -1
- package/dist/types/commands/scan/perform-reachability-analysis.d.mts +1 -0
- package/dist/types/commands/scan/perform-reachability-analysis.d.mts.map +1 -1
- package/dist/types/commands/scan/reachability-flags.d.mts.map +1 -1
- package/dist/types/commands.d.mts +1 -1
- package/dist/types/constants.d.mts +1 -0
- package/dist/types/constants.d.mts.map +1 -1
- package/dist/types/utils/config.d.mts +6 -0
- package/dist/types/utils/config.d.mts.map +1 -1
- package/dist/types/utils/editable-json.d.mts +63 -0
- package/dist/types/utils/editable-json.d.mts.map +1 -0
- package/dist/types/utils/package-environment.d.mts.map +1 -1
- package/dist/utils.js +482 -50
- package/dist/utils.js.map +1 -1
- package/dist/vendor.js +13495 -3663
- package/package.json +4 -3
- package/dist/types/commands/patch/handle-patch.d.mts +0 -12
- package/dist/types/commands/patch/handle-patch.d.mts.map +0 -1
- package/dist/types/commands/patch/manifest-schema.d.mts +0 -34
- package/dist/types/commands/patch/manifest-schema.d.mts.map +0 -1
- package/dist/types/commands/patch/output-patch-result.d.mts +0 -5
- package/dist/types/commands/patch/output-patch-result.d.mts.map +0 -1
package/dist/utils.js
CHANGED
|
@@ -16,9 +16,9 @@ var path = require('node:path');
|
|
|
16
16
|
var regexps = require('../external/@socketsecurity/registry/lib/regexps');
|
|
17
17
|
var prompts = require('../external/@socketsecurity/registry/lib/prompts');
|
|
18
18
|
var spawn = require('../external/@socketsecurity/registry/lib/spawn');
|
|
19
|
-
var fs = require('../external/@socketsecurity/registry/lib/fs');
|
|
19
|
+
var fs$1 = require('../external/@socketsecurity/registry/lib/fs');
|
|
20
20
|
var require$$5 = require('node:module');
|
|
21
|
-
var fs
|
|
21
|
+
var fs = require('node:fs');
|
|
22
22
|
var require$$13 = require('../external/@socketsecurity/registry/lib/url');
|
|
23
23
|
var agent = require('../external/@socketsecurity/registry/lib/agent');
|
|
24
24
|
var bin = require('../external/@socketsecurity/registry/lib/bin');
|
|
@@ -27,6 +27,7 @@ var require$$0$1 = require('node:url');
|
|
|
27
27
|
var globs = require('../external/@socketsecurity/registry/lib/globs');
|
|
28
28
|
var streams = require('../external/@socketsecurity/registry/lib/streams');
|
|
29
29
|
var promises = require('node:timers/promises');
|
|
30
|
+
var require$$1 = require('node:util');
|
|
30
31
|
var os = require('node:os');
|
|
31
32
|
var process$1 = require('node:process');
|
|
32
33
|
var require$$0 = require('node:crypto');
|
|
@@ -163,6 +164,324 @@ function debugGit(operation, success, details) {
|
|
|
163
164
|
}
|
|
164
165
|
}
|
|
165
166
|
|
|
167
|
+
/**
|
|
168
|
+
* @fileoverview EditableJson utility for non-destructive JSON file manipulation.
|
|
169
|
+
* Preserves formatting (indentation and line endings) when updating JSON files.
|
|
170
|
+
* This is a standalone implementation copied from @socketsecurity/lib/json/edit.
|
|
171
|
+
*/
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
// Symbols used to store formatting metadata in JSON objects.
|
|
175
|
+
const INDENT_SYMBOL = Symbol.for('indent');
|
|
176
|
+
const NEWLINE_SYMBOL = Symbol.for('newline');
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Formatting metadata for JSON files.
|
|
180
|
+
*/
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Options for saving editable JSON files.
|
|
184
|
+
*/
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Detect indentation from a JSON string.
|
|
188
|
+
* Supports space-based indentation (returns count) or mixed indentation (returns string).
|
|
189
|
+
*/
|
|
190
|
+
function detectIndent(json) {
|
|
191
|
+
const match = json.match(/^[{[][\r\n]+(\s+)/m);
|
|
192
|
+
if (!match || !match[1]) {
|
|
193
|
+
return 2;
|
|
194
|
+
}
|
|
195
|
+
const indent = match[1];
|
|
196
|
+
if (/^ +$/.test(indent)) {
|
|
197
|
+
return indent.length;
|
|
198
|
+
}
|
|
199
|
+
return indent;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Detect newline character(s) from a JSON string.
|
|
204
|
+
* Supports LF (\n) and CRLF (\r\n) line endings.
|
|
205
|
+
*/
|
|
206
|
+
function detectNewline(json) {
|
|
207
|
+
const match = json.match(/\r?\n/);
|
|
208
|
+
return match ? match[0] : '\n';
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Sort object keys alphabetically.
|
|
213
|
+
* Creates a new object with sorted keys (does not mutate input).
|
|
214
|
+
*/
|
|
215
|
+
function sortKeys(obj) {
|
|
216
|
+
const sorted = {
|
|
217
|
+
__proto__: null
|
|
218
|
+
};
|
|
219
|
+
const keys = Object.keys(obj).sort();
|
|
220
|
+
for (const key of keys) {
|
|
221
|
+
sorted[key] = obj[key];
|
|
222
|
+
}
|
|
223
|
+
return sorted;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Stringify JSON with specific formatting.
|
|
228
|
+
* Applies indentation and line ending preferences.
|
|
229
|
+
*/
|
|
230
|
+
function stringifyWithFormatting(content, formatting) {
|
|
231
|
+
const {
|
|
232
|
+
indent,
|
|
233
|
+
newline
|
|
234
|
+
} = formatting;
|
|
235
|
+
const format = indent === undefined || indent === null ? ' ' : indent;
|
|
236
|
+
const eol = newline === undefined || newline === null ? '\n' : newline;
|
|
237
|
+
return `${JSON.stringify(content, undefined, format)}\n`.replace(/\n/g, eol);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Strip formatting symbols from content object.
|
|
242
|
+
* Removes Symbol.for('indent') and Symbol.for('newline') from the object.
|
|
243
|
+
*/
|
|
244
|
+
function stripFormattingSymbols(content) {
|
|
245
|
+
const {
|
|
246
|
+
[INDENT_SYMBOL]: _indent,
|
|
247
|
+
[NEWLINE_SYMBOL]: _newline,
|
|
248
|
+
...rest
|
|
249
|
+
} = content;
|
|
250
|
+
return rest;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Extract formatting from content object that has symbol-based metadata.
|
|
255
|
+
*/
|
|
256
|
+
function getFormattingFromContent(content) {
|
|
257
|
+
const indent = content[INDENT_SYMBOL];
|
|
258
|
+
const newline = content[NEWLINE_SYMBOL];
|
|
259
|
+
return {
|
|
260
|
+
indent: indent === undefined || indent === null ? 2 : indent,
|
|
261
|
+
newline: newline === undefined || newline === null ? '\n' : newline
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Determine if content should be saved based on changes and options.
|
|
267
|
+
*/
|
|
268
|
+
function shouldSave(currentContent, originalContent, originalFileContent, options = {}) {
|
|
269
|
+
const {
|
|
270
|
+
ignoreWhitespace = false,
|
|
271
|
+
sort = false
|
|
272
|
+
} = options;
|
|
273
|
+
const content = stripFormattingSymbols(currentContent);
|
|
274
|
+
const sortedContent = sort ? sortKeys(content) : content;
|
|
275
|
+
const origContent = originalContent ? stripFormattingSymbols(originalContent) : {};
|
|
276
|
+
if (ignoreWhitespace) {
|
|
277
|
+
return !require$$1.isDeepStrictEqual(sortedContent, origContent);
|
|
278
|
+
}
|
|
279
|
+
const formatting = getFormattingFromContent(currentContent);
|
|
280
|
+
const newFileContent = stringifyWithFormatting(sortedContent, formatting);
|
|
281
|
+
return newFileContent.trim() !== originalFileContent.trim();
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Retry write operation with exponential backoff for file system issues.
|
|
286
|
+
*/
|
|
287
|
+
async function retryWrite(filepath, content, retries = 3, baseDelay = 10) {
|
|
288
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
289
|
+
try {
|
|
290
|
+
// eslint-disable-next-line no-await-in-loop
|
|
291
|
+
await fs.promises.writeFile(filepath, content);
|
|
292
|
+
if (process.platform === 'win32') {
|
|
293
|
+
// eslint-disable-next-line no-await-in-loop
|
|
294
|
+
await promises.setTimeout(50);
|
|
295
|
+
let accessRetries = 0;
|
|
296
|
+
const maxAccessRetries = 5;
|
|
297
|
+
while (accessRetries < maxAccessRetries) {
|
|
298
|
+
try {
|
|
299
|
+
// eslint-disable-next-line no-await-in-loop
|
|
300
|
+
await fs.promises.access(filepath);
|
|
301
|
+
// eslint-disable-next-line no-await-in-loop
|
|
302
|
+
await promises.setTimeout(10);
|
|
303
|
+
break;
|
|
304
|
+
} catch {
|
|
305
|
+
const delay = 20 * (accessRetries + 1);
|
|
306
|
+
// eslint-disable-next-line no-await-in-loop
|
|
307
|
+
await promises.setTimeout(delay);
|
|
308
|
+
accessRetries++;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return;
|
|
313
|
+
} catch (err) {
|
|
314
|
+
const isLastAttempt = attempt === retries;
|
|
315
|
+
const isRetriableError = err instanceof Error && 'code' in err && (err.code === 'EPERM' || err.code === 'EBUSY' || err.code === 'ENOENT');
|
|
316
|
+
if (!isRetriableError || isLastAttempt) {
|
|
317
|
+
throw err;
|
|
318
|
+
}
|
|
319
|
+
const delay = baseDelay * 2 ** attempt;
|
|
320
|
+
// eslint-disable-next-line no-await-in-loop
|
|
321
|
+
await promises.setTimeout(delay);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Parse JSON string.
|
|
328
|
+
*/
|
|
329
|
+
function parseJson(content) {
|
|
330
|
+
return JSON.parse(content);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Read file with retry logic for file system issues.
|
|
335
|
+
*/
|
|
336
|
+
async function readFile(filepath) {
|
|
337
|
+
const maxRetries = process.platform === 'win32' ? 5 : 1;
|
|
338
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
339
|
+
try {
|
|
340
|
+
// eslint-disable-next-line no-await-in-loop
|
|
341
|
+
return await fs.promises.readFile(filepath, 'utf8');
|
|
342
|
+
} catch (err) {
|
|
343
|
+
const isLastAttempt = attempt === maxRetries;
|
|
344
|
+
const isEnoent = err instanceof Error && 'code' in err && err.code === 'ENOENT';
|
|
345
|
+
if (!isEnoent || isLastAttempt) {
|
|
346
|
+
throw err;
|
|
347
|
+
}
|
|
348
|
+
const delay = process.platform === 'win32' ? 50 * (attempt + 1) : 20;
|
|
349
|
+
// eslint-disable-next-line no-await-in-loop
|
|
350
|
+
await promises.setTimeout(delay);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
throw new Error('Unreachable code');
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* EditableJson class for non-destructive JSON file manipulation.
|
|
358
|
+
* Preserves formatting when updating JSON files.
|
|
359
|
+
*/
|
|
360
|
+
class EditableJson {
|
|
361
|
+
_canSave = true;
|
|
362
|
+
_content = {};
|
|
363
|
+
_path = undefined;
|
|
364
|
+
_readFileContent = '';
|
|
365
|
+
_readFileJson = undefined;
|
|
366
|
+
get content() {
|
|
367
|
+
return this._content;
|
|
368
|
+
}
|
|
369
|
+
get filename() {
|
|
370
|
+
const path = this._path;
|
|
371
|
+
if (!path) {
|
|
372
|
+
return '';
|
|
373
|
+
}
|
|
374
|
+
return path;
|
|
375
|
+
}
|
|
376
|
+
get path() {
|
|
377
|
+
return this._path;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Create a new JSON file instance.
|
|
382
|
+
*/
|
|
383
|
+
create(path) {
|
|
384
|
+
this._path = path;
|
|
385
|
+
this._content = {};
|
|
386
|
+
this._canSave = true;
|
|
387
|
+
return this;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Initialize from content object (disables saving).
|
|
392
|
+
*/
|
|
393
|
+
fromContent(data) {
|
|
394
|
+
this._content = data;
|
|
395
|
+
this._canSave = false;
|
|
396
|
+
return this;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Initialize from JSON string.
|
|
401
|
+
*/
|
|
402
|
+
fromJSON(data) {
|
|
403
|
+
const parsed = parseJson(data);
|
|
404
|
+
const indent = detectIndent(data);
|
|
405
|
+
const newline = detectNewline(data)
|
|
406
|
+
// Use type assertion to allow symbol indexing.
|
|
407
|
+
;
|
|
408
|
+
parsed[INDENT_SYMBOL] = indent;
|
|
409
|
+
parsed[NEWLINE_SYMBOL] = newline;
|
|
410
|
+
this._content = parsed;
|
|
411
|
+
return this;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Load JSON file from disk.
|
|
416
|
+
*/
|
|
417
|
+
async load(path, create) {
|
|
418
|
+
this._path = path;
|
|
419
|
+
try {
|
|
420
|
+
this._readFileContent = await readFile(this.filename);
|
|
421
|
+
this.fromJSON(this._readFileContent);
|
|
422
|
+
this._readFileJson = parseJson(this._readFileContent);
|
|
423
|
+
} catch (err) {
|
|
424
|
+
if (!create) {
|
|
425
|
+
throw err;
|
|
426
|
+
}
|
|
427
|
+
// File doesn't exist and create is true - initialize empty.
|
|
428
|
+
this._content = {};
|
|
429
|
+
this._readFileContent = '';
|
|
430
|
+
this._readFileJson = undefined;
|
|
431
|
+
this._canSave = true;
|
|
432
|
+
}
|
|
433
|
+
return this;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Update content with new values.
|
|
438
|
+
*/
|
|
439
|
+
update(content) {
|
|
440
|
+
this._content = {
|
|
441
|
+
...this._content,
|
|
442
|
+
...content
|
|
443
|
+
};
|
|
444
|
+
return this;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Save JSON file to disk asynchronously.
|
|
449
|
+
*/
|
|
450
|
+
async save(options) {
|
|
451
|
+
if (!this._canSave || this.content === undefined) {
|
|
452
|
+
throw new Error('No file path to save to');
|
|
453
|
+
}
|
|
454
|
+
if (!shouldSave(this._content, this._readFileJson, this._readFileContent, options)) {
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
const content = stripFormattingSymbols(this._content);
|
|
458
|
+
const sortedContent = options?.sort ? sortKeys(content) : content;
|
|
459
|
+
const formatting = getFormattingFromContent(this._content);
|
|
460
|
+
const fileContent = stringifyWithFormatting(sortedContent, formatting);
|
|
461
|
+
await retryWrite(this.filename, fileContent);
|
|
462
|
+
this._readFileContent = fileContent;
|
|
463
|
+
this._readFileJson = parseJson(fileContent);
|
|
464
|
+
return true;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Check if save will occur based on current changes.
|
|
469
|
+
*/
|
|
470
|
+
willSave(options) {
|
|
471
|
+
if (!this._canSave || this.content === undefined) {
|
|
472
|
+
return false;
|
|
473
|
+
}
|
|
474
|
+
return shouldSave(this._content, this._readFileJson, this._readFileContent, options);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Get the EditableJson class for JSON file manipulation.
|
|
480
|
+
*/
|
|
481
|
+
function getEditableJsonClass() {
|
|
482
|
+
return EditableJson;
|
|
483
|
+
}
|
|
484
|
+
|
|
166
485
|
/**
|
|
167
486
|
* Error utilities for Socket CLI.
|
|
168
487
|
* Provides consistent error handling, formatting, and message extraction.
|
|
@@ -307,14 +626,15 @@ function getConfigValues() {
|
|
|
307
626
|
socketAppDataPath
|
|
308
627
|
} = constants.default;
|
|
309
628
|
if (socketAppDataPath) {
|
|
310
|
-
const
|
|
629
|
+
const configFilePath = path.join(socketAppDataPath, 'config.json');
|
|
630
|
+
const raw = fs$1.safeReadFileSync(configFilePath);
|
|
311
631
|
if (raw) {
|
|
312
632
|
try {
|
|
313
633
|
Object.assign(_cachedConfig, JSON.parse(Buffer.from(raw, 'base64').toString()));
|
|
314
|
-
debugConfig(
|
|
634
|
+
debugConfig(configFilePath, true);
|
|
315
635
|
} catch (e) {
|
|
316
|
-
logger.logger.warn(`Failed to parse config at ${
|
|
317
|
-
debugConfig(
|
|
636
|
+
logger.logger.warn(`Failed to parse config at ${configFilePath}`);
|
|
637
|
+
debugConfig(configFilePath, false, e);
|
|
318
638
|
}
|
|
319
639
|
// Normalize apiKey to apiToken and persist it.
|
|
320
640
|
// This is a one time migration per user.
|
|
@@ -324,7 +644,7 @@ function getConfigValues() {
|
|
|
324
644
|
updateConfigValue(constants.CONFIG_KEY_API_TOKEN, token);
|
|
325
645
|
}
|
|
326
646
|
} else {
|
|
327
|
-
fs
|
|
647
|
+
fs.mkdirSync(socketAppDataPath, {
|
|
328
648
|
recursive: true
|
|
329
649
|
});
|
|
330
650
|
}
|
|
@@ -353,10 +673,10 @@ function findSocketYmlSync(dir = process.cwd()) {
|
|
|
353
673
|
let prevDir = null;
|
|
354
674
|
while (dir !== prevDir) {
|
|
355
675
|
let ymlPath = path.join(dir, constants.SOCKET_YML);
|
|
356
|
-
let yml = fs.safeReadFileSync(ymlPath);
|
|
676
|
+
let yml = fs$1.safeReadFileSync(ymlPath);
|
|
357
677
|
if (yml === undefined) {
|
|
358
678
|
ymlPath = path.join(dir, constants.SOCKET_YAML);
|
|
359
|
-
yml = fs.safeReadFileSync(ymlPath);
|
|
679
|
+
yml = fs$1.safeReadFileSync(ymlPath);
|
|
360
680
|
}
|
|
361
681
|
if (typeof yml === 'string') {
|
|
362
682
|
try {
|
|
@@ -519,11 +839,68 @@ function updateConfigValue(configKey, value) {
|
|
|
519
839
|
_pendingSave = true;
|
|
520
840
|
process.nextTick(() => {
|
|
521
841
|
_pendingSave = false;
|
|
842
|
+
// Capture the config state at write time, not at schedule time.
|
|
843
|
+
// This ensures all updates in the same tick are included.
|
|
844
|
+
const configToSave = {
|
|
845
|
+
...localConfig
|
|
846
|
+
};
|
|
522
847
|
const {
|
|
523
848
|
socketAppDataPath
|
|
524
849
|
} = constants.default;
|
|
525
850
|
if (socketAppDataPath) {
|
|
526
|
-
fs
|
|
851
|
+
fs.mkdirSync(socketAppDataPath, {
|
|
852
|
+
recursive: true
|
|
853
|
+
});
|
|
854
|
+
const configFilePath = path.join(socketAppDataPath, 'config.json');
|
|
855
|
+
// Read existing file to preserve formatting, then update with new values.
|
|
856
|
+
const existingRaw = fs$1.safeReadFileSync(configFilePath);
|
|
857
|
+
const EditableJson = getEditableJsonClass();
|
|
858
|
+
const editor = new EditableJson();
|
|
859
|
+
if (existingRaw !== undefined) {
|
|
860
|
+
const rawString = Buffer.isBuffer(existingRaw) ? existingRaw.toString('utf8') : existingRaw;
|
|
861
|
+
try {
|
|
862
|
+
const decoded = Buffer.from(rawString, 'base64').toString('utf8');
|
|
863
|
+
editor.fromJSON(decoded);
|
|
864
|
+
} catch {
|
|
865
|
+
// If decoding fails, start fresh.
|
|
866
|
+
}
|
|
867
|
+
} else {
|
|
868
|
+
// Initialize empty editor for new file.
|
|
869
|
+
editor.create(configFilePath);
|
|
870
|
+
}
|
|
871
|
+
// Update with the captured config state.
|
|
872
|
+
// Note: We need to handle deletions explicitly since editor.update() only merges.
|
|
873
|
+
// First, get all keys from the existing content.
|
|
874
|
+
const existingKeys = new Set(Object.keys(editor.content).filter(k => typeof k === 'string'));
|
|
875
|
+
const newKeys = new Set(Object.keys(configToSave));
|
|
876
|
+
|
|
877
|
+
// Delete keys that are in existing but not in new config.
|
|
878
|
+
for (const key of existingKeys) {
|
|
879
|
+
if (!newKeys.has(key)) {
|
|
880
|
+
delete editor.content[key];
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
// Now update with new values.
|
|
885
|
+
editor.update(configToSave);
|
|
886
|
+
// Use the editor's internal stringify which preserves formatting.
|
|
887
|
+
// Extract the formatting symbols from the content.
|
|
888
|
+
const INDENT_SYMBOL = Symbol.for('indent');
|
|
889
|
+
const NEWLINE_SYMBOL = Symbol.for('newline');
|
|
890
|
+
const indent = editor.content[INDENT_SYMBOL] ?? 2;
|
|
891
|
+
const newline = editor.content[NEWLINE_SYMBOL] ?? '\n';
|
|
892
|
+
|
|
893
|
+
// Strip formatting symbols from content.
|
|
894
|
+
const contentToSave = {};
|
|
895
|
+
for (const [key, val] of Object.entries(editor.content)) {
|
|
896
|
+
if (typeof key === 'string') {
|
|
897
|
+
contentToSave[key] = val;
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
// Stringify with formatting preserved.
|
|
902
|
+
const jsonContent = JSON.stringify(contentToSave, undefined, indent).replace(/\n/g, newline);
|
|
903
|
+
fs.writeFileSync(configFilePath, Buffer.from(jsonContent + newline).toString('base64'));
|
|
527
904
|
}
|
|
528
905
|
});
|
|
529
906
|
}
|
|
@@ -3894,7 +4271,7 @@ function* walkNestedMap(map, keys = []) {
|
|
|
3894
4271
|
*/
|
|
3895
4272
|
|
|
3896
4273
|
function extractTier1ReachabilityScanId(socketFactsFile) {
|
|
3897
|
-
const json = fs.readJsonSync(socketFactsFile, {
|
|
4274
|
+
const json = fs$1.readJsonSync(socketFactsFile, {
|
|
3898
4275
|
throws: false
|
|
3899
4276
|
});
|
|
3900
4277
|
const tier1ReachabilityScanId = String(json?.['tier1ReachabilityScanId'] ?? '').trim();
|
|
@@ -3952,7 +4329,7 @@ async function findUp(name, options) {
|
|
|
3952
4329
|
const thePath = path.join(dir, name);
|
|
3953
4330
|
try {
|
|
3954
4331
|
// eslint-disable-next-line no-await-in-loop
|
|
3955
|
-
const stats = await fs
|
|
4332
|
+
const stats = await fs.promises.stat(thePath);
|
|
3956
4333
|
if (!onlyDirectories && stats.isFile()) {
|
|
3957
4334
|
return thePath;
|
|
3958
4335
|
}
|
|
@@ -3994,7 +4371,7 @@ async function getWorkspaceGlobs(agent, cwd = process.cwd()) {
|
|
|
3994
4371
|
let workspacePatterns;
|
|
3995
4372
|
if (agent === constants.PNPM) {
|
|
3996
4373
|
const workspacePath = path.join(cwd, 'pnpm-workspace.yaml');
|
|
3997
|
-
const yml = await fs.safeReadFile(workspacePath);
|
|
4374
|
+
const yml = await fs$1.safeReadFile(workspacePath);
|
|
3998
4375
|
if (yml) {
|
|
3999
4376
|
try {
|
|
4000
4377
|
workspacePatterns = vendor.distExports$1.parse(yml)?.packages;
|
|
@@ -4104,7 +4481,7 @@ async function globWithGitIgnore(patterns, options) {
|
|
|
4104
4481
|
cwd,
|
|
4105
4482
|
ignore: DEFAULT_IGNORE_FOR_GIT_IGNORE
|
|
4106
4483
|
});
|
|
4107
|
-
for await (const ignorePatterns of streams.transform(gitIgnoreStream, async filepath => ignoreFileToGlobPatterns((await fs.safeReadFile(filepath)) ?? '', filepath, cwd), {
|
|
4484
|
+
for await (const ignorePatterns of streams.transform(gitIgnoreStream, async filepath => ignoreFileToGlobPatterns((await fs$1.safeReadFile(filepath)) ?? '', filepath, cwd), {
|
|
4108
4485
|
concurrency: 8
|
|
4109
4486
|
})) {
|
|
4110
4487
|
for (const p of ignorePatterns) {
|
|
@@ -4166,7 +4543,7 @@ function pathsToGlobPatterns(paths, cwd) {
|
|
|
4166
4543
|
}
|
|
4167
4544
|
const absolutePath = path.isAbsolute(p) ? p : path.resolve(cwd ?? process.cwd(), p);
|
|
4168
4545
|
// If the path is a directory, scan it recursively for all files.
|
|
4169
|
-
if (fs.isDirSync(absolutePath)) {
|
|
4546
|
+
if (fs$1.isDirSync(absolutePath)) {
|
|
4170
4547
|
return `${p}/**/*`;
|
|
4171
4548
|
}
|
|
4172
4549
|
return p;
|
|
@@ -4219,11 +4596,11 @@ function findNpmDirPathSync(npmBinPath) {
|
|
|
4219
4596
|
// Use existsSync here because statsSync, even with { throwIfNoEntry: false },
|
|
4220
4597
|
// will throw an ENOTDIR error for paths like ./a-file-that-exists/a-directory-that-does-not.
|
|
4221
4598
|
// See https://github.com/nodejs/node/issues/56993.
|
|
4222
|
-
fs.isDirSync(libNmNpmPath)) {
|
|
4599
|
+
fs$1.isDirSync(libNmNpmPath)) {
|
|
4223
4600
|
thePath = libNmNpmPath;
|
|
4224
4601
|
}
|
|
4225
|
-
const hasNmInCurrPath = fs.isDirSync(path.join(thePath, constants.NODE_MODULES));
|
|
4226
|
-
const hasNmInParentPath = !hasNmInCurrPath && fs.isDirSync(path.join(thePath, `../${constants.NODE_MODULES}`));
|
|
4602
|
+
const hasNmInCurrPath = fs$1.isDirSync(path.join(thePath, constants.NODE_MODULES));
|
|
4603
|
+
const hasNmInParentPath = !hasNmInCurrPath && fs$1.isDirSync(path.join(thePath, `../${constants.NODE_MODULES}`));
|
|
4227
4604
|
if (
|
|
4228
4605
|
// npm bin paths may look like:
|
|
4229
4606
|
// /usr/local/share/npm/bin/npm
|
|
@@ -4241,7 +4618,7 @@ function findNpmDirPathSync(npmBinPath) {
|
|
|
4241
4618
|
// Optimistically look for the default location.
|
|
4242
4619
|
path.basename(thePath) === constants.NPM ||
|
|
4243
4620
|
// Chocolatey installs npm bins in the same directory as node bins.
|
|
4244
|
-
WIN32 && fs
|
|
4621
|
+
WIN32 && fs.existsSync(path.join(thePath, `${constants.NPM}.cmd`)))) {
|
|
4245
4622
|
return hasNmInParentPath ? path.dirname(thePath) : thePath;
|
|
4246
4623
|
}
|
|
4247
4624
|
const parent = path.dirname(thePath);
|
|
@@ -4635,7 +5012,7 @@ function getDefaultSocketJson() {
|
|
|
4635
5012
|
}
|
|
4636
5013
|
function readSocketJsonSync(cwd, defaultOnError = false) {
|
|
4637
5014
|
const sockJsonPath = path.join(cwd, constants.SOCKET_JSON);
|
|
4638
|
-
if (!fs
|
|
5015
|
+
if (!fs.existsSync(sockJsonPath)) {
|
|
4639
5016
|
require$$9.debugFn('notice', `miss: ${constants.SOCKET_JSON} not found at ${cwd}`);
|
|
4640
5017
|
return {
|
|
4641
5018
|
ok: true,
|
|
@@ -4644,7 +5021,7 @@ function readSocketJsonSync(cwd, defaultOnError = false) {
|
|
|
4644
5021
|
}
|
|
4645
5022
|
let jsonContent = null;
|
|
4646
5023
|
try {
|
|
4647
|
-
jsonContent = fs
|
|
5024
|
+
jsonContent = fs.readFileSync(sockJsonPath, 'utf8');
|
|
4648
5025
|
} catch (e) {
|
|
4649
5026
|
if (defaultOnError) {
|
|
4650
5027
|
logger.logger.warn(`Failed to read ${constants.SOCKET_JSON}, using default`);
|
|
@@ -4718,7 +5095,7 @@ async function writeSocketJson(cwd, sockJson) {
|
|
|
4718
5095
|
};
|
|
4719
5096
|
}
|
|
4720
5097
|
const filepath = path.join(cwd, constants.SOCKET_JSON);
|
|
4721
|
-
await fs
|
|
5098
|
+
await fs.promises.writeFile(filepath, `${jsonContent}\n`, 'utf8');
|
|
4722
5099
|
return {
|
|
4723
5100
|
ok: true,
|
|
4724
5101
|
data: undefined
|
|
@@ -4755,11 +5132,11 @@ async function readCache(key,
|
|
|
4755
5132
|
// 5 minute in milliseconds time to live (TTL).
|
|
4756
5133
|
ttlMs = 5 * 60 * 1000) {
|
|
4757
5134
|
const cacheJsonPath = path.join(constants.default.githubCachePath, `${key}.json`);
|
|
4758
|
-
const stat = fs.safeStatsSync(cacheJsonPath);
|
|
5135
|
+
const stat = fs$1.safeStatsSync(cacheJsonPath);
|
|
4759
5136
|
if (stat) {
|
|
4760
5137
|
const isExpired = Date.now() - stat.mtimeMs > ttlMs;
|
|
4761
5138
|
if (!isExpired) {
|
|
4762
|
-
return await fs.readJson(cacheJsonPath);
|
|
5139
|
+
return await fs$1.readJson(cacheJsonPath);
|
|
4763
5140
|
}
|
|
4764
5141
|
}
|
|
4765
5142
|
return undefined;
|
|
@@ -4769,12 +5146,12 @@ async function writeCache(key, data) {
|
|
|
4769
5146
|
githubCachePath
|
|
4770
5147
|
} = constants.default;
|
|
4771
5148
|
const cacheJsonPath = path.join(githubCachePath, `${key}.json`);
|
|
4772
|
-
if (!fs
|
|
4773
|
-
await fs
|
|
5149
|
+
if (!fs.existsSync(githubCachePath)) {
|
|
5150
|
+
await fs.promises.mkdir(githubCachePath, {
|
|
4774
5151
|
recursive: true
|
|
4775
5152
|
});
|
|
4776
5153
|
}
|
|
4777
|
-
await fs.writeJson(cacheJsonPath, data);
|
|
5154
|
+
await fs$1.writeJson(cacheJsonPath, data);
|
|
4778
5155
|
}
|
|
4779
5156
|
async function cacheFetch(key, fetcher, ttlMs) {
|
|
4780
5157
|
// Optionally disable cache.
|
|
@@ -5251,7 +5628,7 @@ const COMPLETION_CMD_PREFIX = 'complete -F _socket_completion';
|
|
|
5251
5628
|
function getCompletionSourcingCommand() {
|
|
5252
5629
|
// Note: this is exported to distPath in .config/rollup.dist.config.mjs
|
|
5253
5630
|
const completionScriptExportPath = path.join(constants.default.distPath, 'socket-completion.bash');
|
|
5254
|
-
if (!fs
|
|
5631
|
+
if (!fs.existsSync(completionScriptExportPath)) {
|
|
5255
5632
|
return {
|
|
5256
5633
|
ok: false,
|
|
5257
5634
|
message: 'Tab Completion script not found',
|
|
@@ -5372,7 +5749,7 @@ function getNpmRequire() {
|
|
|
5372
5749
|
if (_npmRequire === undefined) {
|
|
5373
5750
|
const npmDirPath = getNpmDirPath();
|
|
5374
5751
|
const npmNmPath = path.join(npmDirPath, `${constants.NODE_MODULES}/npm`);
|
|
5375
|
-
_npmRequire = require$$5.createRequire(path.join(fs
|
|
5752
|
+
_npmRequire = require$$5.createRequire(path.join(fs.existsSync(npmNmPath) ? npmNmPath : npmDirPath, '<dummy-basename>'));
|
|
5376
5753
|
}
|
|
5377
5754
|
return _npmRequire;
|
|
5378
5755
|
}
|
|
@@ -5588,8 +5965,8 @@ const readLockFileByAgent = (() => {
|
|
|
5588
5965
|
return undefined;
|
|
5589
5966
|
};
|
|
5590
5967
|
}
|
|
5591
|
-
const binaryReader = wrapReader(fs.readFileBinary);
|
|
5592
|
-
const defaultReader = wrapReader(async lockPath => await fs.readFileUtf8(lockPath));
|
|
5968
|
+
const binaryReader = wrapReader(fs$1.readFileBinary);
|
|
5969
|
+
const defaultReader = wrapReader(async lockPath => await fs$1.readFileUtf8(lockPath));
|
|
5593
5970
|
return new Map([[BUN, wrapReader(async (lockPath, agentExecPath, cwd = process.cwd()) => {
|
|
5594
5971
|
const ext = path.extname(lockPath);
|
|
5595
5972
|
if (ext === EXT_LOCK) {
|
|
@@ -5637,20 +6014,54 @@ const LOCKS = {
|
|
|
5637
6014
|
// it has to be handled differently.
|
|
5638
6015
|
[`${NODE_MODULES}/${DOT_PACKAGE_LOCK_JSON}`]: NPM
|
|
5639
6016
|
};
|
|
6017
|
+
function preferWindowsCmdShim(binPath, binName) {
|
|
6018
|
+
// Only Windows uses .cmd shims
|
|
6019
|
+
if (!constants.default.WIN32) {
|
|
6020
|
+
return binPath;
|
|
6021
|
+
}
|
|
6022
|
+
|
|
6023
|
+
// Relative paths might be shell commands or aliases, not file paths with potential shims
|
|
6024
|
+
if (!path.isAbsolute(binPath)) {
|
|
6025
|
+
return binPath;
|
|
6026
|
+
}
|
|
6027
|
+
|
|
6028
|
+
// If the path already has an extension (.exe, .bat, etc.), it is probably a Windows executable
|
|
6029
|
+
if (path.extname(binPath) !== '') {
|
|
6030
|
+
return binPath;
|
|
6031
|
+
}
|
|
6032
|
+
|
|
6033
|
+
// Ensures binPath actually points to the expected binary, not a parent directory that happens to match `binName`
|
|
6034
|
+
// For example, if binPath is C:\foo\npm\something and binName is npm, we shouldn't replace it
|
|
6035
|
+
if (path.basename(binPath).toLowerCase() !== binName.toLowerCase()) {
|
|
6036
|
+
return binPath;
|
|
6037
|
+
}
|
|
6038
|
+
|
|
6039
|
+
// Finally attempt to construct a .cmd shim from binPAth
|
|
6040
|
+
const cmdShim = path.join(path.dirname(binPath), `${binName}.cmd`);
|
|
6041
|
+
|
|
6042
|
+
// Ensure shim exists, otherwise failback to binPath
|
|
6043
|
+
return fs.existsSync(cmdShim) ? cmdShim : binPath;
|
|
6044
|
+
}
|
|
5640
6045
|
async function getAgentExecPath(agent) {
|
|
5641
6046
|
const binName = binByAgent.get(agent);
|
|
5642
6047
|
if (binName === NPM) {
|
|
5643
6048
|
// Try to use constants.npmExecPath first, but verify it exists.
|
|
5644
|
-
const npmPath = constants.default.npmExecPath;
|
|
5645
|
-
if (fs
|
|
6049
|
+
const npmPath = preferWindowsCmdShim(constants.default.npmExecPath, NPM);
|
|
6050
|
+
if (fs.existsSync(npmPath)) {
|
|
5646
6051
|
return npmPath;
|
|
5647
6052
|
}
|
|
5648
6053
|
// If npmExecPath doesn't exist, try common locations.
|
|
5649
6054
|
// Check npm in the same directory as node.
|
|
5650
6055
|
const nodeDir = path.dirname(process.execPath);
|
|
6056
|
+
if (constants.default.WIN32) {
|
|
6057
|
+
const npmCmdInNodeDir = path.join(nodeDir, `${NPM}.cmd`);
|
|
6058
|
+
if (fs.existsSync(npmCmdInNodeDir)) {
|
|
6059
|
+
return npmCmdInNodeDir;
|
|
6060
|
+
}
|
|
6061
|
+
}
|
|
5651
6062
|
const npmInNodeDir = path.join(nodeDir, NPM);
|
|
5652
|
-
if (fs
|
|
5653
|
-
return npmInNodeDir;
|
|
6063
|
+
if (fs.existsSync(npmInNodeDir)) {
|
|
6064
|
+
return preferWindowsCmdShim(npmInNodeDir, NPM);
|
|
5654
6065
|
}
|
|
5655
6066
|
// Fall back to whichBin.
|
|
5656
6067
|
return (await bin.whichBin(binName, {
|
|
@@ -5660,7 +6071,7 @@ async function getAgentExecPath(agent) {
|
|
|
5660
6071
|
if (binName === PNPM) {
|
|
5661
6072
|
// Try to use constants.pnpmExecPath first, but verify it exists.
|
|
5662
6073
|
const pnpmPath = constants.default.pnpmExecPath;
|
|
5663
|
-
if (fs
|
|
6074
|
+
if (fs.existsSync(pnpmPath)) {
|
|
5664
6075
|
return pnpmPath;
|
|
5665
6076
|
}
|
|
5666
6077
|
// Fall back to whichBin.
|
|
@@ -5677,19 +6088,42 @@ async function getAgentVersion(agent, agentExecPath, cwd) {
|
|
|
5677
6088
|
const quotedCmd = `\`${agent} ${constants.FLAG_VERSION}\``;
|
|
5678
6089
|
require$$9.debugFn('stdio', `spawn: ${quotedCmd}`);
|
|
5679
6090
|
try {
|
|
6091
|
+
let stdout;
|
|
6092
|
+
|
|
6093
|
+
// Some package manager "executables" may resolve to non-executable wrapper scripts
|
|
6094
|
+
// (e.g. the extensionless `npm` shim on Windows). Resolve the underlying entrypoint
|
|
6095
|
+
// and run it with Node when it is a JS file.
|
|
6096
|
+
let shouldRunWithNode = null;
|
|
6097
|
+
if (constants.default.WIN32) {
|
|
6098
|
+
try {
|
|
6099
|
+
const resolved = bin.resolveBinPathSync(agentExecPath);
|
|
6100
|
+
const ext = path.extname(resolved).toLowerCase();
|
|
6101
|
+
if (ext === '.js' || ext === '.cjs' || ext === '.mjs') {
|
|
6102
|
+
shouldRunWithNode = resolved;
|
|
6103
|
+
}
|
|
6104
|
+
} catch (e) {
|
|
6105
|
+
require$$9.debugFn('warn', `Failed to resolve bin path for ${agentExecPath}, falling back to direct spawn.`);
|
|
6106
|
+
require$$9.debugDir('error', e);
|
|
6107
|
+
}
|
|
6108
|
+
}
|
|
6109
|
+
if (shouldRunWithNode) {
|
|
6110
|
+
stdout = (await spawn.spawn(constants.default.execPath, [...constants.default.nodeNoWarningsFlags, shouldRunWithNode, constants.FLAG_VERSION], {
|
|
6111
|
+
cwd
|
|
6112
|
+
})).stdout;
|
|
6113
|
+
} else {
|
|
6114
|
+
stdout = (await spawn.spawn(agentExecPath, [constants.FLAG_VERSION], {
|
|
6115
|
+
cwd,
|
|
6116
|
+
// On Windows, package managers are often .cmd files that require shell execution.
|
|
6117
|
+
// The spawn function from @socketsecurity/registry will handle this properly
|
|
6118
|
+
// when shell is true.
|
|
6119
|
+
shell: constants.default.WIN32
|
|
6120
|
+
})).stdout;
|
|
6121
|
+
}
|
|
5680
6122
|
result =
|
|
5681
6123
|
// Coerce version output into a valid semver version by passing it through
|
|
5682
6124
|
// semver.coerce which strips leading v's, carets (^), comparators (<,<=,>,>=,=),
|
|
5683
6125
|
// and tildes (~).
|
|
5684
|
-
vendor.semverExports.coerce(
|
|
5685
|
-
// All package managers support the "--version" flag.
|
|
5686
|
-
(await spawn.spawn(agentExecPath, [constants.FLAG_VERSION], {
|
|
5687
|
-
cwd,
|
|
5688
|
-
// On Windows, package managers are often .cmd files that require shell execution.
|
|
5689
|
-
// The spawn function from @socketsecurity/registry will handle this properly
|
|
5690
|
-
// when shell is true.
|
|
5691
|
-
shell: constants.default.WIN32
|
|
5692
|
-
})).stdout) ?? undefined;
|
|
6126
|
+
vendor.semverExports.coerce(stdout) ?? undefined;
|
|
5693
6127
|
} catch (e) {
|
|
5694
6128
|
require$$9.debugFn('error', `Package manager command failed: ${quotedCmd}`);
|
|
5695
6129
|
require$$9.debugDir('inspect', {
|
|
@@ -5711,7 +6145,7 @@ async function detectPackageEnvironment({
|
|
|
5711
6145
|
const pkgJsonPath = lockPath ? path.resolve(lockPath, `${isHiddenLockFile ? '../' : ''}../${PACKAGE_JSON}`) : await findUp(PACKAGE_JSON, {
|
|
5712
6146
|
cwd
|
|
5713
6147
|
});
|
|
5714
|
-
const pkgPath = pkgJsonPath && fs
|
|
6148
|
+
const pkgPath = pkgJsonPath && fs.existsSync(pkgJsonPath) ? path.dirname(pkgJsonPath) : undefined;
|
|
5715
6149
|
const editablePkgJson = pkgPath ? await packages.readPackageJson(pkgPath, {
|
|
5716
6150
|
editable: true
|
|
5717
6151
|
}) : undefined;
|
|
@@ -6266,7 +6700,7 @@ function parsePnpmLockfile(lockfileContent) {
|
|
|
6266
6700
|
return require$$11.isObjectObject(result) ? result : null;
|
|
6267
6701
|
}
|
|
6268
6702
|
async function readPnpmLockfile(lockfilePath) {
|
|
6269
|
-
return fs
|
|
6703
|
+
return fs.existsSync(lockfilePath) ? await fs$1.readFileUtf8(lockfilePath) : undefined;
|
|
6270
6704
|
}
|
|
6271
6705
|
function stripLeadingPnpmDepPathSlash(depPath) {
|
|
6272
6706
|
return isPnpmDepPath(depPath) ? depPath.slice(1) : depPath;
|
|
@@ -7041,7 +7475,6 @@ exports.getOrgSlugs = getOrgSlugs;
|
|
|
7041
7475
|
exports.getOutputKind = getOutputKind;
|
|
7042
7476
|
exports.getPackageFilesForScan = getPackageFilesForScan;
|
|
7043
7477
|
exports.getPublicApiToken = getPublicApiToken;
|
|
7044
|
-
exports.getPurlObject = getPurlObject;
|
|
7045
7478
|
exports.getRepoInfo = getRepoInfo;
|
|
7046
7479
|
exports.getRepoName = getRepoName;
|
|
7047
7480
|
exports.getSocketDevPackageOverviewUrlFromPurl = getSocketDevPackageOverviewUrlFromPurl;
|
|
@@ -7085,7 +7518,6 @@ exports.mdTableStringNumber = mdTableStringNumber;
|
|
|
7085
7518
|
exports.meowOrExit = meowOrExit;
|
|
7086
7519
|
exports.meowWithSubcommands = meowWithSubcommands;
|
|
7087
7520
|
exports.msAtHome = msAtHome;
|
|
7088
|
-
exports.normalizePurl = normalizePurl;
|
|
7089
7521
|
exports.parsePnpmLockfile = parsePnpmLockfile;
|
|
7090
7522
|
exports.queryApiSafeJson = queryApiSafeJson;
|
|
7091
7523
|
exports.queryApiSafeText = queryApiSafeText;
|
|
@@ -7120,5 +7552,5 @@ exports.updateConfigValue = updateConfigValue;
|
|
|
7120
7552
|
exports.walkNestedMap = walkNestedMap;
|
|
7121
7553
|
exports.webLink = webLink;
|
|
7122
7554
|
exports.writeSocketJson = writeSocketJson;
|
|
7123
|
-
//# debugId=
|
|
7555
|
+
//# debugId=223b2750-92b4-4170-901e-7e9746f5b2c5
|
|
7124
7556
|
//# sourceMappingURL=utils.js.map
|