@socketsecurity/cli-with-sentry 1.1.8 → 1.1.9

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 (35) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/README.md +3 -3
  3. package/dist/cli.js +96 -51
  4. package/dist/cli.js.map +1 -1
  5. package/dist/constants.js +8 -5
  6. package/dist/constants.js.map +1 -1
  7. package/dist/shadow-npm-inject.js +6 -8
  8. package/dist/shadow-npm-inject.js.map +1 -1
  9. package/dist/tsconfig.dts.tsbuildinfo +1 -1
  10. package/dist/types/commands/fix/cmd-fix.d.mts.map +1 -1
  11. package/dist/types/commands/fix/handle-fix.d.mts +5 -0
  12. package/dist/types/commands/fix/handle-fix.d.mts.map +1 -1
  13. package/dist/types/commands/package/output-purls-shallow-score.d.mts.map +1 -1
  14. package/dist/types/commands/patch/handle-patch.d.mts.map +1 -1
  15. package/dist/types/constants.d.mts +3 -1
  16. package/dist/types/constants.d.mts.map +1 -1
  17. package/dist/types/shadow/npm/arborist-helpers.d.mts.map +1 -1
  18. package/dist/types/utils/api.d.mts +22 -1
  19. package/dist/types/utils/api.d.mts.map +1 -1
  20. package/dist/types/utils/cve-to-ghsa.d.mts +6 -0
  21. package/dist/types/utils/cve-to-ghsa.d.mts.map +1 -0
  22. package/dist/types/utils/github.d.mts.map +1 -1
  23. package/dist/types/utils/output-formatting.d.mts.map +1 -1
  24. package/dist/types/utils/purl-to-ghsa.d.mts +6 -0
  25. package/dist/types/utils/purl-to-ghsa.d.mts.map +1 -0
  26. package/dist/types/utils/requirements.d.mts +4 -0
  27. package/dist/types/utils/requirements.d.mts.map +1 -1
  28. package/dist/types/utils/semver.d.mts +1 -2
  29. package/dist/types/utils/semver.d.mts.map +1 -1
  30. package/dist/utils.js +215 -42
  31. package/dist/utils.js.map +1 -1
  32. package/dist/vendor.js +9 -9
  33. package/external/@socketsecurity/registry/lib/url.js +13 -12
  34. package/package.json +7 -7
  35. package/requirements.json +2 -2
package/dist/utils.js CHANGED
@@ -11,21 +11,21 @@ var path$1 = require('../external/@socketsecurity/registry/lib/path');
11
11
  var sorts = require('../external/@socketsecurity/registry/lib/sorts');
12
12
  var spinner = require('../external/@socketsecurity/registry/lib/spinner');
13
13
  var words = require('../external/@socketsecurity/registry/lib/words');
14
- var Module = require('node:module');
15
- var path = require('node:path');
16
14
  var flags = require('./flags.js');
15
+ var path = require('node:path');
17
16
  var regexps = require('../external/@socketsecurity/registry/lib/regexps');
18
17
  var prompts = require('../external/@socketsecurity/registry/lib/prompts');
19
18
  var spawn = require('../external/@socketsecurity/registry/lib/spawn');
20
19
  var fs = require('../external/@socketsecurity/registry/lib/fs');
20
+ var Module = require('node:module');
21
21
  var shadowNpmBin = require('./shadow-npm-bin.js');
22
22
  var fs$1 = require('node:fs');
23
+ var require$$13 = require('../external/@socketsecurity/registry/lib/url');
23
24
  var promises = require('node:timers/promises');
24
25
  var npm = require('../external/@socketsecurity/registry/lib/npm');
25
26
  var globs = require('../external/@socketsecurity/registry/lib/globs');
26
27
  var packages = require('../external/@socketsecurity/registry/lib/packages');
27
28
  var streams = require('../external/@socketsecurity/registry/lib/streams');
28
- var require$$13 = require('../external/@socketsecurity/registry/lib/url');
29
29
 
30
30
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
31
31
  const sensitiveConfigKeyLookup = new Set(['apiToken']);
@@ -256,6 +256,22 @@ function updateConfigValue(configKey, value) {
256
256
  };
257
257
  }
258
258
 
259
+ const require$2 = Module.createRequire(require('node:url').pathToFileURL(__filename).href);
260
+ let _requirements;
261
+ function getRequirements() {
262
+ if (_requirements === undefined) {
263
+ _requirements = /*@__PURE__*/require$2(path.join(constants.default.rootPath, 'requirements.json'));
264
+ }
265
+ return _requirements;
266
+ }
267
+
268
+ /**
269
+ * Convert command path to requirements key.
270
+ */
271
+ function getRequirementsKey(cmdPath) {
272
+ return cmdPath.replace(/^socket[: ]/, '').replace(/ +/g, ':');
273
+ }
274
+
259
275
  const TOKEN_PREFIX = 'sktsec_';
260
276
  const TOKEN_PREFIX_LENGTH = TOKEN_PREFIX.length;
261
277
  const TOKEN_VISIBLE_LENGTH = 5;
@@ -330,10 +346,14 @@ async function setupSdk(options) {
330
346
  return {
331
347
  ok: true,
332
348
  data: new vendor.distExports.SocketSdk(apiToken, {
333
- agent: apiProxy ? new ProxyAgent({
334
- proxy: apiProxy
335
- }) : undefined,
336
- baseUrl: apiBaseUrl,
349
+ ...(apiProxy ? {
350
+ agent: new ProxyAgent({
351
+ proxy: apiProxy
352
+ })
353
+ } : {}),
354
+ ...(apiBaseUrl ? {
355
+ baseUrl: apiBaseUrl
356
+ } : {}),
337
357
  timeout: constants.default.ENV.SOCKET_CLI_API_TIMEOUT,
338
358
  userAgent: vendor.distExports.createUserAgentFromPkgJson({
339
359
  name: constants.default.ENV.INLINED_SOCKET_CLI_NAME,
@@ -345,6 +365,32 @@ async function setupSdk(options) {
345
365
  }
346
366
 
347
367
  const NO_ERROR_MESSAGE = 'No error message returned';
368
+ /**
369
+ * Get command requirements from requirements.json based on command path.
370
+ */
371
+ function getCommandRequirements(cmdPath) {
372
+ if (!cmdPath) {
373
+ return undefined;
374
+ }
375
+ const requirements = getRequirements();
376
+ const key = getRequirementsKey(cmdPath);
377
+ return requirements.api[key] || undefined;
378
+ }
379
+
380
+ /**
381
+ * Log required permissions for a command when encountering 403 errors.
382
+ */
383
+ function logPermissionsFor403(cmdPath) {
384
+ const requirements = getCommandRequirements(cmdPath);
385
+ if (!requirements?.permissions?.length) {
386
+ return;
387
+ }
388
+ logger.logger.error('This command requires the following API permissions:');
389
+ for (const permission of requirements.permissions) {
390
+ logger.logger.error(` - ${permission}`);
391
+ }
392
+ logger.logger.error('Please ensure your API token has the required permissions.');
393
+ }
348
394
 
349
395
  // The Socket API server that should be used for operations.
350
396
  function getDefaultApiBaseUrl() {
@@ -355,6 +401,10 @@ function getDefaultApiBaseUrl() {
355
401
  const API_V0_URL = constants.default.API_V0_URL;
356
402
  return API_V0_URL;
357
403
  }
404
+
405
+ /**
406
+ * Get user-friendly error message for HTTP status codes.
407
+ */
358
408
  async function getErrorMessageForHttpStatusCode(code) {
359
409
  if (code === 400) {
360
410
  return 'One of the options passed might be incorrect';
@@ -370,8 +420,12 @@ async function getErrorMessageForHttpStatusCode(code) {
370
420
  }
371
421
  return `Server responded with status code ${code}`;
372
422
  }
423
+ /**
424
+ * Handle Socket SDK API calls with error handling and permission logging.
425
+ */
373
426
  async function handleApiCall(value, options) {
374
427
  const {
428
+ commandPath,
375
429
  description,
376
430
  spinner
377
431
  } = {
@@ -399,7 +453,7 @@ async function handleApiCall(value, options) {
399
453
  spinner?.stop();
400
454
  const socketSdkErrorResult = {
401
455
  ok: false,
402
- message: 'Socket API returned an error',
456
+ message: 'Socket API error',
403
457
  cause: vendor.messageWithCauses(e)
404
458
  };
405
459
  if (description) {
@@ -430,12 +484,17 @@ async function handleApiCall(value, options) {
430
484
  const cause = reason && message !== reason ? `${message} (reason: ${reason})` : message;
431
485
  const socketSdkErrorResult = {
432
486
  ok: false,
433
- message: 'Socket API returned an error',
487
+ message: 'Socket API error',
434
488
  cause,
435
489
  data: {
436
490
  code: sdkResult.status
437
491
  }
438
492
  };
493
+
494
+ // Log required permissions for 403 errors when in a command context.
495
+ if (commandPath && sdkResult.status === 403) {
496
+ logPermissionsFor403(commandPath);
497
+ }
439
498
  return socketSdkErrorResult;
440
499
  }
441
500
  const socketSdkSuccessResult = {
@@ -454,7 +513,7 @@ async function handleApiCallNoSpinner(value, description) {
454
513
  error: e
455
514
  });
456
515
  const errStr = e ? String(e).trim() : '';
457
- const message = 'Socket API returned an error';
516
+ const message = 'Socket API error';
458
517
  const rawCause = errStr || NO_ERROR_MESSAGE;
459
518
  const cause = message !== rawCause ? rawCause : '';
460
519
  return {
@@ -479,7 +538,7 @@ async function handleApiCallNoSpinner(value, description) {
479
538
  const cause = reason && message !== reason ? `${message} (reason: ${reason})` : message;
480
539
  return {
481
540
  ok: false,
482
- message: 'Socket API returned an error',
541
+ message: 'Socket API error',
483
542
  cause,
484
543
  data: {
485
544
  code: sdkResult.status
@@ -494,9 +553,9 @@ async function handleApiCallNoSpinner(value, description) {
494
553
  }
495
554
  }
496
555
  async function queryApi(path, apiToken) {
497
- const baseUrl = getDefaultApiBaseUrl() || '';
556
+ const baseUrl = getDefaultApiBaseUrl();
498
557
  if (!baseUrl) {
499
- logger.logger.warn('API endpoint is not set and default was empty. Request is likely to fail.');
558
+ throw new Error('Socket API endpoint is not configured');
500
559
  }
501
560
  return await fetch(`${baseUrl}${baseUrl.endsWith('/') ? '' : '/'}${path}`, {
502
561
  method: 'GET',
@@ -505,7 +564,11 @@ async function queryApi(path, apiToken) {
505
564
  }
506
565
  });
507
566
  }
508
- async function queryApiSafeText(path, description) {
567
+
568
+ /**
569
+ * Query Socket API endpoint and return text response with error handling.
570
+ */
571
+ async function queryApiSafeText(path, description, commandPath) {
509
572
  const apiToken = getDefaultApiToken();
510
573
  if (!apiToken) {
511
574
  return {
@@ -550,11 +613,10 @@ async function queryApiSafeText(path, description) {
550
613
  const {
551
614
  status
552
615
  } = result;
553
- const reason = await getErrorMessageForHttpStatusCode(status);
554
616
  return {
555
617
  ok: false,
556
- message: 'Socket API returned an error',
557
- cause: `${result.statusText} (reason: ${reason})`,
618
+ message: 'Socket API error',
619
+ cause: `${result.statusText} (reason: ${await getErrorMessageForHttpStatusCode(status)})`,
558
620
  data: {
559
621
  code: status
560
622
  }
@@ -578,6 +640,10 @@ async function queryApiSafeText(path, description) {
578
640
  };
579
641
  }
580
642
  }
643
+
644
+ /**
645
+ * Query Socket API endpoint and return parsed JSON response.
646
+ */
581
647
  async function queryApiSafeJson(path, description = '') {
582
648
  const result = await queryApiSafeText(path, description);
583
649
  if (!result.ok) {
@@ -592,10 +658,13 @@ async function queryApiSafeJson(path, description = '') {
592
658
  return {
593
659
  ok: false,
594
660
  message: 'Server returned invalid JSON',
595
- cause: `Please report this. JSON.parse threw an error over the following response: \`${(result.data?.slice?.(0, 100) || '<empty>').trim() + (result.data?.length > 100 ? '...' : '')}\``
661
+ cause: `Please report this. JSON.parse threw an error over the following response: \`${(result.data?.slice?.(0, 100) || constants.EMPTY_VALUE).trim() + (result.data?.length > 100 ? '...' : '')}\``
596
662
  };
597
663
  }
598
664
  }
665
+ /**
666
+ * Send POST/PUT request to Socket API with JSON response handling.
667
+ */
599
668
  async function sendApiRequest(path, options) {
600
669
  const apiToken = getDefaultApiToken();
601
670
  if (!apiToken) {
@@ -605,12 +674,17 @@ async function sendApiRequest(path, options) {
605
674
  cause: 'User must be authenticated to run this command. To log in, run the command `socket login` and enter your Socket API token.'
606
675
  };
607
676
  }
608
- const baseUrl = getDefaultApiBaseUrl() || '';
677
+ const baseUrl = getDefaultApiBaseUrl();
609
678
  if (!baseUrl) {
610
- logger.logger.warn('API endpoint is not set and default was empty. Request is likely to fail.');
679
+ return {
680
+ ok: false,
681
+ message: 'Configuration Error',
682
+ cause: 'Socket API endpoint is not configured. Please check your environment configuration.'
683
+ };
611
684
  }
612
685
  const {
613
686
  body,
687
+ commandPath,
614
688
  description,
615
689
  method
616
690
  } = {
@@ -663,11 +737,14 @@ async function sendApiRequest(path, options) {
663
737
  const {
664
738
  status
665
739
  } = result;
666
- const reason = await getErrorMessageForHttpStatusCode(status);
740
+ // Log required permissions for 403 errors when in a command context.
741
+ if (commandPath && status === 403) {
742
+ logPermissionsFor403(commandPath);
743
+ }
667
744
  return {
668
745
  ok: false,
669
- message: 'Socket API returned an error',
670
- cause: `${result.statusText} (reason: ${reason})`,
746
+ message: 'Socket API error',
747
+ cause: `${result.statusText} (reason: ${await getErrorMessageForHttpStatusCode(status)})`,
671
748
  data: {
672
749
  code: status
673
750
  }
@@ -693,7 +770,7 @@ async function sendApiRequest(path, options) {
693
770
  }
694
771
 
695
772
  function failMsgWithBadge(badge, message) {
696
- const prefix = vendor.yoctocolorsCjsExports.bgRed(vendor.yoctocolorsCjsExports.bold(vendor.yoctocolorsCjsExports.white(` ${badge}${message ? ': ' : ''}`)));
773
+ const prefix = vendor.yoctocolorsCjsExports.bgRedBright(vendor.yoctocolorsCjsExports.bold(vendor.yoctocolorsCjsExports.red(` ${badge}${message ? ': ' : ''}`)));
697
774
  const postfix = message ? ` ${vendor.yoctocolorsCjsExports.bold(message)}` : '';
698
775
  return `${prefix}${postfix}`;
699
776
  }
@@ -887,15 +964,6 @@ function getOutputKind(json, markdown) {
887
964
  return constants.OUTPUT_TEXT;
888
965
  }
889
966
 
890
- const require$2 = Module.createRequire(require('node:url').pathToFileURL(__filename).href);
891
- let _requirements;
892
- function getRequirements() {
893
- if (_requirements === undefined) {
894
- _requirements = /*@__PURE__*/require$2(path.join(constants.default.rootPath, 'requirements.json'));
895
- }
896
- return _requirements;
897
- }
898
-
899
967
  function camelToKebab(string) {
900
968
  return string.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
901
969
  }
@@ -906,20 +974,21 @@ function getFlagApiRequirementsOutput(cmdPath, options) {
906
974
  __proto__: null,
907
975
  ...options
908
976
  };
909
- const key = cmdPath.replace(/^socket[: ]/, '').replace(/ +/g, ':');
977
+ const key = getRequirementsKey(cmdPath);
910
978
  const requirements = getRequirements();
911
979
  const data = requirements.api[key];
912
980
  let result = '';
913
981
  if (data) {
914
982
  const quota = data?.quota;
915
- const perms = data?.permissions;
983
+ const rawPerms = data?.permissions;
916
984
  const padding = ''.padEnd(indent);
917
985
  const lines = [];
918
- if (typeof quota === 'number') {
986
+ if (Number.isFinite(quota) && quota > 0) {
919
987
  lines.push(`${padding}- Quota: ${quota} ${words.pluralize('unit', quota)}`);
920
988
  }
921
- if (Array.isArray(perms) && perms.length) {
922
- lines.push(`${padding}- Permissions: ${perms.join(' ')}`);
989
+ if (Array.isArray(rawPerms) && rawPerms.length) {
990
+ const perms = rawPerms.slice().sort(sorts.naturalCompare);
991
+ lines.push(`${padding}- Permissions: ${arrays.joinAnd(perms)}`);
923
992
  }
924
993
  result += lines.join('\n');
925
994
  }
@@ -2959,8 +3028,17 @@ async function enablePrAutoMerge({
2959
3028
  }
2960
3029
  async function setGitRemoteGithubRepoUrl(owner, repo, token, cwd = process.cwd()) {
2961
3030
  const {
2962
- host
2963
- } = new URL(constants.default.ENV.GITHUB_SERVER_URL);
3031
+ GITHUB_SERVER_URL
3032
+ } = constants.default.ENV;
3033
+ const urlObj = require$$13.parseUrl(GITHUB_SERVER_URL);
3034
+ const host = urlObj?.host;
3035
+ if (!host) {
3036
+ require$$9.debugFn('error', 'invalid: GITHUB_SERVER_URL env var');
3037
+ require$$9.debugDir('inspect', {
3038
+ GITHUB_SERVER_URL
3039
+ });
3040
+ return false;
3041
+ }
2964
3042
  const url = `https://x-access-token:${token}@${host}/${owner}/${repo}`;
2965
3043
  const stdioIgnoreOptions = {
2966
3044
  cwd,
@@ -2980,7 +3058,100 @@ async function setGitRemoteGithubRepoUrl(owner, repo, token, cwd = process.cwd()
2980
3058
  return false;
2981
3059
  }
2982
3060
 
2983
- const RangeStyles = ['caret', 'gt', 'gte', 'lt', 'lte', 'pin', 'preserve', 'tilde'];
3061
+ /**
3062
+ * Converts CVE IDs to GHSA IDs using GitHub API.
3063
+ */
3064
+ async function convertCveToGhsa(cveId) {
3065
+ try {
3066
+ const cacheKey = `cve-to-ghsa-${cveId}`;
3067
+ const octokit = getOctokit();
3068
+ const response = await cacheFetch(cacheKey, () => octokit.rest.securityAdvisories.listGlobalAdvisories({
3069
+ cve_id: cveId,
3070
+ per_page: 1
3071
+ }));
3072
+ if (!response.data.length) {
3073
+ return {
3074
+ ok: false,
3075
+ message: `No GHSA found for CVE ${cveId}`
3076
+ };
3077
+ }
3078
+ return {
3079
+ ok: true,
3080
+ data: response.data[0].ghsa_id
3081
+ };
3082
+ } catch (e) {
3083
+ return {
3084
+ ok: false,
3085
+ message: `Failed to convert CVE to GHSA: ${e instanceof Error ? e.message : 'Unknown error'}`
3086
+ };
3087
+ }
3088
+ }
3089
+
3090
+ const PURL_TO_GITHUB_ECOSYSTEM_MAPPING = {
3091
+ __proto__: null,
3092
+ // GitHub Advisory Database supported ecosystems
3093
+ cargo: 'rust',
3094
+ composer: 'composer',
3095
+ gem: 'rubygems',
3096
+ go: 'go',
3097
+ golang: 'go',
3098
+ maven: 'maven',
3099
+ npm: 'npm',
3100
+ nuget: 'nuget',
3101
+ pypi: 'pip',
3102
+ swift: 'swift'
3103
+ };
3104
+
3105
+ /**
3106
+ * Converts PURL to GHSA IDs using GitHub API.
3107
+ */
3108
+ async function convertPurlToGhsas(purl) {
3109
+ try {
3110
+ const purlObj = getPurlObject(purl, {
3111
+ throws: false
3112
+ });
3113
+ if (!purlObj) {
3114
+ return {
3115
+ ok: false,
3116
+ message: `Invalid PURL format: ${purl}`
3117
+ };
3118
+ }
3119
+ const {
3120
+ name,
3121
+ type: ecosystem,
3122
+ version
3123
+ } = purlObj;
3124
+
3125
+ // Map PURL ecosystem to GitHub ecosystem.
3126
+ const githubEcosystem = PURL_TO_GITHUB_ECOSYSTEM_MAPPING[ecosystem];
3127
+ if (!githubEcosystem) {
3128
+ return {
3129
+ ok: false,
3130
+ message: `Unsupported PURL ecosystem: ${ecosystem}`
3131
+ };
3132
+ }
3133
+
3134
+ // Search for advisories affecting this package.
3135
+ const cacheKey = `purl-to-ghsa-${ecosystem}-${name}-${version || constants.LATEST}`;
3136
+ const octokit = getOctokit();
3137
+ const affects = version ? `${name}@${version}` : name;
3138
+ const response = await cacheFetch(cacheKey, () => octokit.rest.securityAdvisories.listGlobalAdvisories({
3139
+ ecosystem: githubEcosystem,
3140
+ affects
3141
+ }));
3142
+ return {
3143
+ ok: true,
3144
+ data: response.data.map(a => a.ghsa_id)
3145
+ };
3146
+ } catch (e) {
3147
+ return {
3148
+ ok: false,
3149
+ message: `Failed to convert PURL to GHSA: ${e instanceof Error ? e.message : constants.UNKNOWN_ERROR}`
3150
+ };
3151
+ }
3152
+ }
3153
+
3154
+ const RangeStyles = ['pin', 'preserve'];
2984
3155
  function getMajor(version) {
2985
3156
  try {
2986
3157
  const coerced = vendor.semverExports.coerce(version);
@@ -4053,6 +4224,8 @@ exports.checkCommandInput = checkCommandInput;
4053
4224
  exports.cmdFlagValueToArray = cmdFlagValueToArray;
4054
4225
  exports.cmdFlagsToString = cmdFlagsToString;
4055
4226
  exports.cmdPrefixMessage = cmdPrefixMessage;
4227
+ exports.convertCveToGhsa = convertCveToGhsa;
4228
+ exports.convertPurlToGhsas = convertPurlToGhsas;
4056
4229
  exports.createEnum = createEnum;
4057
4230
  exports.detectAndValidatePackageEnvironment = detectAndValidatePackageEnvironment;
4058
4231
  exports.detectDefaultBranch = detectDefaultBranch;
@@ -4138,5 +4311,5 @@ exports.toFilterConfig = toFilterConfig;
4138
4311
  exports.updateConfigValue = updateConfigValue;
4139
4312
  exports.walkNestedMap = walkNestedMap;
4140
4313
  exports.writeSocketJson = writeSocketJson;
4141
- //# debugId=737faea9-c80e-4b25-92fc-cf5802905b27
4314
+ //# debugId=60d49a4c-4734-44f0-b9b1-eb6a8f55f7d3
4142
4315
  //# sourceMappingURL=utils.js.map