@socketsecurity/cli-with-sentry 0.14.68 → 0.14.70

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.
@@ -19,6 +19,7 @@ const logger = require('@socketsecurity/registry/lib/logger')
19
19
  const assert = require('node:assert')
20
20
  const fs = require('node:fs/promises')
21
21
  const commonTags = _socketInterop(require('common-tags'))
22
+ const debug = require('@socketsecurity/registry/lib/debug')
22
23
  const strings = require('@socketsecurity/registry/lib/strings')
23
24
  const shadowNpmInject = require('./shadow-npm-inject.js')
24
25
  const constants = require('./constants.js')
@@ -27,22 +28,21 @@ const path$1 = require('node:path')
27
28
  const objects = require('@socketsecurity/registry/lib/objects')
28
29
  const path = require('@socketsecurity/registry/lib/path')
29
30
  const regexps = require('@socketsecurity/registry/lib/regexps')
30
- const prompts = require('@socketsecurity/registry/lib/prompts')
31
31
  const yargsParse = _socketInterop(require('yargs-parser'))
32
32
  const words = require('@socketsecurity/registry/lib/words')
33
33
  const fs$1 = require('node:fs')
34
34
  const shadowBin = require('./shadow-bin.js')
35
+ const prompts = require('@socketsecurity/registry/lib/prompts')
35
36
  const chalkTable = _socketInterop(require('chalk-table'))
36
37
  const require$$0$1 = require('node:util')
37
38
  const registry = require('@socketsecurity/registry')
38
39
  const npm = require('@socketsecurity/registry/lib/npm')
39
40
  const packages = require('@socketsecurity/registry/lib/packages')
40
41
  const lockfile_fs = _socketInterop(require('@pnpm/lockfile.fs'))
42
+ const spawn = require('@socketsecurity/registry/lib/spawn')
41
43
  const lockfile_detectDepTypes = _socketInterop(
42
44
  require('@pnpm/lockfile.detect-dep-types')
43
45
  )
44
- const debug = require('@socketsecurity/registry/lib/debug')
45
- const spawn = require('@socketsecurity/registry/lib/spawn')
46
46
  const shadowNpmPaths = require('./shadow-npm-paths.js')
47
47
  const browserslist = _socketInterop(require('browserslist'))
48
48
  const semver = _socketInterop(require('semver'))
@@ -56,8 +56,6 @@ const npa = _socketInterop(require('npm-package-arg'))
56
56
  const tinyglobby = _socketInterop(require('tinyglobby'))
57
57
  const promises = require('@socketsecurity/registry/lib/promises')
58
58
  const yaml = _socketInterop(require('yaml'))
59
- const betterAjvErrors = _socketInterop(require('@apideck/better-ajv-errors'))
60
- const config$K = require('@socketsecurity/config')
61
59
 
62
60
  function failMsgWithBadge(badge, msg) {
63
61
  return `${colors.bgRed(colors.bold(colors.white(` ${badge}: `)))} ${colors.bold(msg)}`
@@ -72,7 +70,7 @@ function handleUnsuccessfulApiResponse(_name, sockSdkError) {
72
70
  spinner.stop()
73
71
  throw new shadowNpmInject.AuthError(message)
74
72
  }
75
- logger.logger.fail(failMsgWithBadge('API returned an error:', message))
73
+ logger.logger.fail(failMsgWithBadge('Socket API returned an error', message))
76
74
 
77
75
  process$1.exit(1)
78
76
  }
@@ -80,23 +78,25 @@ async function handleApiCall(value, description) {
80
78
  let result
81
79
  try {
82
80
  result = await value
83
- } catch (cause) {
81
+ } catch (e) {
82
+ debug.debugLog(`handleApiCall[${description}] error:\n`, e)
84
83
  throw new Error(`Failed ${description}`, {
85
- cause
84
+ cause: e
86
85
  })
87
86
  }
88
87
  return result
89
88
  }
90
89
  async function handleApiError(code) {
91
90
  if (code === 400) {
92
- return 'One of the options passed might be incorrect.'
93
- } else if (code === 403) {
94
- return 'Your API token may not have the required permissions for this command or you might be trying to access (data from) an organization that is not linked to the API key you are logged in with.'
95
- } else if (code === 404) {
91
+ return 'One of the options passed might be incorrect'
92
+ }
93
+ if (code === 403) {
94
+ return 'Your API token may not have the required permissions for this command or you might be trying to access (data from) an organization that is not linked to the API key you are logged in with'
95
+ }
96
+ if (code === 404) {
96
97
  return 'The requested Socket API endpoint was not found (404) or there was no result for the requested parameters. This could be a temporary problem caused by an incident or a bug in the CLI. If the problem persists please let us know.'
97
- } else {
98
- return `Server responded with status code ${code}`
99
98
  }
99
+ return `Server responded with status code ${code}`
100
100
  }
101
101
  function getLastFiveOfApiToken(token) {
102
102
  // Get the last 5 characters of the API token before the trailing "_api".
@@ -141,14 +141,13 @@ async function fetchOrgAnalyticsData(time, spinner) {
141
141
  )
142
142
  if (result.success === false) {
143
143
  handleUnsuccessfulApiResponse('getOrgAnalytics', result)
144
- return undefined
145
144
  }
146
145
  spinner.stop()
147
146
  if (!result.data.length) {
148
147
  logger.logger.log(
149
148
  'No analytics data is available for this organization yet.'
150
149
  )
151
- return undefined
150
+ return
152
151
  }
153
152
  return result.data
154
153
  }
@@ -161,14 +160,13 @@ async function fetchRepoAnalyticsData(repo, time, spinner) {
161
160
  )
162
161
  if (result.success === false) {
163
162
  handleUnsuccessfulApiResponse('getRepoAnalytics', result)
164
- return undefined
165
163
  }
166
164
  spinner.stop()
167
165
  if (!result.data.length) {
168
166
  logger.logger.log(
169
167
  'No analytics data is available for this organization yet.'
170
168
  )
171
- return undefined
169
+ return
172
170
  }
173
171
  return result.data
174
172
  }
@@ -730,7 +728,7 @@ function getHelpListOutput(
730
728
  return result.trim() || '(none)'
731
729
  }
732
730
 
733
- const { DRY_RUN_LABEL: DRY_RUN_LABEL$1, REDACTED } = constants
731
+ const { DRY_RUN_LABEL, REDACTED: REDACTED$1 } = constants
734
732
  async function meowWithSubcommands(subcommands, options) {
735
733
  const {
736
734
  aliases = {},
@@ -803,15 +801,43 @@ async function meowWithSubcommands(subcommands, options) {
803
801
  // Hard override the config if instructed to do so.
804
802
  // The env var overrides the --flag, which overrides the persisted config
805
803
  // Also, when either of these are used, config updates won't persist.
804
+ let configOverrideResult
806
805
  if (process$1.env['SOCKET_CLI_CONFIG']) {
807
- shadowNpmInject.overrideCachedConfig(
808
- JSON.parse(process$1.env['SOCKET_CLI_CONFIG'])
806
+ configOverrideResult = shadowNpmInject.overrideCachedConfig(
807
+ process$1.env['SOCKET_CLI_CONFIG']
809
808
  )
810
809
  } else if (cli.flags['config']) {
811
- shadowNpmInject.overrideCachedConfig(
812
- JSON.parse(String(cli.flags['config'] || ''))
810
+ configOverrideResult = shadowNpmInject.overrideCachedConfig(
811
+ String(cli.flags['config'] || '')
813
812
  )
814
813
  }
814
+ if (process$1.env['SOCKET_CLI_NO_API_TOKEN']) {
815
+ // This overrides the config override and even the explicit token env var.
816
+ // The config will be marked as readOnly to prevent persisting it.
817
+ shadowNpmInject.overrideConfigApiToken(undefined)
818
+ } else {
819
+ // Note: these are SOCKET_SECURITY prefixed because they're not specific to
820
+ // the CLI. For the sake of consistency we'll also support the env
821
+ // keys that do have the SOCKET_CLI prefix, it's an easy mistake.
822
+ // In case multiple are supplied, the tokens supersede the keys and the
823
+ // security prefix supersedes the cli prefix. "Adventure mode" ;)
824
+ const tokenOverride =
825
+ process$1.env['SOCKET_CLI_API_KEY'] ||
826
+ process$1.env['SOCKET_SECURITY_API_KEY'] ||
827
+ process$1.env['SOCKET_CLI_API_TOKEN'] ||
828
+ process$1.env['SOCKET_SECURITY_API_TOKEN']
829
+ if (tokenOverride) {
830
+ // This will set the token (even if there was a config override) and
831
+ // set it to readOnly, making sure the temp token won't be persisted.
832
+ shadowNpmInject.overrideConfigApiToken(tokenOverride)
833
+ }
834
+ }
835
+ if (configOverrideResult?.ok === false) {
836
+ emitBanner(name)
837
+ logger.logger.fail(configOverrideResult.message)
838
+ process$1.exitCode = 2
839
+ return
840
+ }
815
841
 
816
842
  // If we got at least some args, then lets find out if we can find a command.
817
843
  if (commandOrAliasName) {
@@ -836,7 +862,7 @@ async function meowWithSubcommands(subcommands, options) {
836
862
  }
837
863
  if (!cli.flags['help'] && cli.flags['dryRun']) {
838
864
  process$1.exitCode = 0
839
- logger.logger.log(`${DRY_RUN_LABEL$1}: No-op, call a sub-command; ok`)
865
+ logger.logger.log(`${DRY_RUN_LABEL}: No-op, call a sub-command; ok`)
840
866
  } else {
841
867
  cli.showHelp()
842
868
  }
@@ -885,9 +911,9 @@ function emitBanner(name) {
885
911
  logger.logger.error(getAsciiHeader(name))
886
912
  }
887
913
  function getAsciiHeader(command) {
888
- const cliVersion = '0.14.68:23c5456:b5e74c63:pub' // The '@rollup/plugin-replace' will replace "process.env['INLINED_SOCKET_CLI_VERSION_HASH']".
914
+ const cliVersion = '0.14.70:1042a5b:4857980f:pub' // The '@rollup/plugin-replace' will replace "process.env['INLINED_SOCKET_CLI_VERSION_HASH']".
889
915
  const nodeVersion = process$1.version
890
- const apiToken = shadowNpmInject.getConfigValue('apiToken')
916
+ const apiToken = shadowNpmInject.getDefaultToken()
891
917
  const shownToken = apiToken ? getLastFiveOfApiToken(apiToken) : 'no'
892
918
  const relCwd = path.normalizePath(
893
919
  process$1
@@ -908,7 +934,7 @@ function getAsciiHeader(command) {
908
934
  return ` ${body}\n`
909
935
  }
910
936
 
911
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$I } = constants
937
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$G } = constants
912
938
  const config$J = {
913
939
  commandName: 'analytics',
914
940
  description: `Look up analytics data`,
@@ -921,7 +947,7 @@ const config$J = {
921
947
  shortFlag: 'f',
922
948
  default: '-',
923
949
  description:
924
- 'Path to a local file to save the output. Only valid with --json/--markdown. Defaults to stdout.'
950
+ 'Filepath to save output. Only valid with --json/--markdown. Defaults to stdout.'
925
951
  },
926
952
  repo: {
927
953
  type: 'string',
@@ -947,6 +973,10 @@ const config$J = {
947
973
  Usage
948
974
  $ ${command} --scope=<scope> --time=<time filter>
949
975
 
976
+ API Token Requirements
977
+ - Quota: 1 unit
978
+ - Permissions: report:write
979
+
950
980
  Default parameters are set to show the organization-level analytics over the
951
981
  last 7 days.
952
982
 
@@ -1022,7 +1052,7 @@ async function run$J(argv, importMeta, { parentName }) {
1022
1052
  return
1023
1053
  }
1024
1054
  if (cli.flags['dryRun']) {
1025
- logger.logger.log(DRY_RUN_BAIL_TEXT$I)
1055
+ logger.logger.log(DRY_RUN_BAIL_TEXT$G)
1026
1056
  return
1027
1057
  }
1028
1058
  assert(assertScope(scope))
@@ -1063,31 +1093,43 @@ async function fetchAuditLog({ logType, orgSlug, outputKind, page, perPage }) {
1063
1093
  )
1064
1094
  if (!result.success) {
1065
1095
  handleUnsuccessfulApiResponse('getAuditLogEvents', result)
1066
- return
1067
1096
  }
1068
1097
  spinner.stop()
1069
1098
  return result.data
1070
1099
  }
1071
1100
 
1101
+ const { REDACTED } = constants
1072
1102
  async function outputAuditLog(
1073
1103
  auditLogs,
1074
1104
  { logType, orgSlug, outputKind, page, perPage }
1075
1105
  ) {
1076
1106
  if (outputKind === 'json') {
1077
- await outputAsJson(auditLogs.results, orgSlug, logType, page, perPage)
1078
- } else if (outputKind === 'markdown') {
1079
- await outputAsMarkdown(auditLogs.results, orgSlug, logType, page, perPage)
1107
+ logger.logger.log(
1108
+ await outputAsJson(auditLogs.results, {
1109
+ logType,
1110
+ orgSlug,
1111
+ page,
1112
+ perPage
1113
+ })
1114
+ )
1080
1115
  } else {
1081
- await outputAsPrint(auditLogs.results, orgSlug, logType)
1116
+ logger.logger.log(
1117
+ await outputAsMarkdown(auditLogs.results, {
1118
+ logType,
1119
+ orgSlug,
1120
+ page,
1121
+ perPage
1122
+ })
1123
+ )
1082
1124
  }
1083
1125
  }
1084
- async function outputAsJson(auditLogs, orgSlug, logType, page, perPage) {
1126
+ async function outputAsJson(auditLogs, { logType, orgSlug, page, perPage }) {
1085
1127
  let json
1086
1128
  try {
1087
1129
  json = JSON.stringify(
1088
1130
  {
1089
1131
  desc: 'Audit logs for given query',
1090
- generated: new Date().toISOString(),
1132
+ generated: false ? REDACTED : new Date().toISOString(),
1091
1133
  org: orgSlug,
1092
1134
  logType,
1093
1135
  page,
@@ -1116,15 +1158,21 @@ async function outputAsJson(auditLogs, orgSlug, logType, page, perPage) {
1116
1158
  2
1117
1159
  )
1118
1160
  } catch (e) {
1119
- process.exitCode = 1
1161
+ process$1.exitCode = 1
1120
1162
  logger.logger.fail(
1121
1163
  'There was a problem converting the logs to JSON, please try without the `--json` flag'
1122
1164
  )
1123
- return
1165
+ if (debug.isDebug()) {
1166
+ debug.debugLog('Error:\n', e)
1167
+ }
1168
+ return '{}'
1124
1169
  }
1125
- logger.logger.log(json)
1170
+ return json
1126
1171
  }
1127
- async function outputAsMarkdown(auditLogs, orgSlug, logType, page, perPage) {
1172
+ async function outputAsMarkdown(
1173
+ auditLogs,
1174
+ { logType, orgSlug, page, perPage }
1175
+ ) {
1128
1176
  try {
1129
1177
  const table = mdTable(auditLogs, [
1130
1178
  'event_id',
@@ -1134,7 +1182,7 @@ async function outputAsMarkdown(auditLogs, orgSlug, logType, page, perPage) {
1134
1182
  'ip_address',
1135
1183
  'user_agent'
1136
1184
  ])
1137
- logger.logger.log(commonTags.stripIndents`
1185
+ return `
1138
1186
  # Socket Audit Logs
1139
1187
 
1140
1188
  These are the Socket.dev audit logs as per requested query.
@@ -1142,50 +1190,21 @@ These are the Socket.dev audit logs as per requested query.
1142
1190
  - type filter: ${logType || '(none)'}
1143
1191
  - page: ${page}
1144
1192
  - per page: ${perPage}
1145
- - generated: ${new Date().toISOString()}
1193
+ - generated: ${false ? REDACTED : new Date().toISOString()}
1146
1194
 
1147
1195
  ${table}
1148
- `)
1196
+ `
1149
1197
  } catch (e) {
1150
- process.exitCode = 1
1198
+ process$1.exitCode = 1
1151
1199
  logger.logger.fail(
1152
- 'There was a problem converting the logs to JSON, please try without the `--json` flag'
1200
+ 'There was a problem converting the logs to Markdown, please try the `--json` flag'
1153
1201
  )
1154
- logger.logger.error(e)
1155
- return
1156
- }
1157
- }
1158
- async function outputAsPrint(auditLogs, orgSlug, logType) {
1159
- const data = []
1160
- const logDetails = {}
1161
- for (const d of auditLogs) {
1162
- const { created_at } = d
1163
- if (created_at) {
1164
- const name = `${new Date(created_at).toLocaleDateString('en-us', {
1165
- year: 'numeric',
1166
- month: 'numeric',
1167
- day: 'numeric'
1168
- })} - ${d.user_email} - ${d.type} - ${d.ip_address} - ${d.user_agent}`
1169
- data.push(
1170
- {
1171
- name
1172
- },
1173
- new prompts.Separator()
1174
- )
1175
- logDetails[name] = JSON.stringify(d.payload)
1202
+ if (debug.isDebug()) {
1203
+ debug.debugLog('Error:\n', e)
1176
1204
  }
1205
+ // logger.error(e)
1206
+ return ''
1177
1207
  }
1178
- logger.logger.log(
1179
- logDetails[
1180
- await prompts.select({
1181
- message: logType
1182
- ? `\n Audit log for: ${orgSlug} with type: ${logType}\n`
1183
- : `\n Audit log for: ${orgSlug}\n`,
1184
- choices: data,
1185
- pageSize: 30
1186
- })
1187
- ]
1188
- )
1189
1208
  }
1190
1209
 
1191
1210
  async function handleAuditLog({ logType, orgSlug, outputKind, page, perPage }) {
@@ -1208,7 +1227,7 @@ async function handleAuditLog({ logType, orgSlug, outputKind, page, perPage }) {
1208
1227
  })
1209
1228
  }
1210
1229
 
1211
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$H } = constants
1230
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$F } = constants
1212
1231
  const config$I = {
1213
1232
  commandName: 'audit-log',
1214
1233
  description: 'Look up the audit log for an organization',
@@ -1239,6 +1258,10 @@ const config$I = {
1239
1258
  Usage
1240
1259
  $ ${command} <org slug>
1241
1260
 
1261
+ API Token Requirements
1262
+ - Quota: 1 unit
1263
+ - Permissions: audit-log:list
1264
+
1242
1265
  This feature requires an Enterprise Plan. To learn more about getting access
1243
1266
  to this feature and many more, please visit https://socket.dev/pricing
1244
1267
 
@@ -1294,7 +1317,7 @@ async function run$I(argv, importMeta, { parentName }) {
1294
1317
  return
1295
1318
  }
1296
1319
  if (cli.flags['dryRun']) {
1297
- logger.logger.log(DRY_RUN_BAIL_TEXT$H)
1320
+ logger.logger.log(DRY_RUN_BAIL_TEXT$F)
1298
1321
  return
1299
1322
  }
1300
1323
  await handleAuditLog({
@@ -1422,7 +1445,7 @@ function isHelpFlag(cmdArg) {
1422
1445
  }
1423
1446
 
1424
1447
  // import { meowOrExit } from '../../utils/meow-with-subcommands'
1425
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$G } = constants
1448
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$E } = constants
1426
1449
 
1427
1450
  // TODO: convert yargs to meow. Or convert all the other things to yargs.
1428
1451
  const toLower = arg => arg.toLowerCase()
@@ -1585,7 +1608,7 @@ async function run$H(argv, importMeta, { parentName }) {
1585
1608
  return
1586
1609
  }
1587
1610
  if (cli.flags['dryRun']) {
1588
- logger.logger.log(DRY_RUN_BAIL_TEXT$G)
1611
+ logger.logger.log(DRY_RUN_BAIL_TEXT$E)
1589
1612
  return
1590
1613
  }
1591
1614
  if (yargv.output === undefined) {
@@ -1621,7 +1644,7 @@ async function discoverConfigValue(key) {
1621
1644
  success: false,
1622
1645
  value: undefined,
1623
1646
  message:
1624
- 'When uncertain, unset this key. Otherwise ask your network administrator.'
1647
+ 'When uncertain, unset this key. Otherwise ask your network administrator'
1625
1648
  }
1626
1649
  }
1627
1650
  if (key === 'apiToken') {
@@ -1835,7 +1858,7 @@ async function handleConfigAuto({ key, outputKind }) {
1835
1858
  await outputConfigAuto(key, result, outputKind)
1836
1859
  }
1837
1860
 
1838
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$F } = constants
1861
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$D } = constants
1839
1862
  const config$G = {
1840
1863
  commandName: 'auto',
1841
1864
  description: 'Automatically discover and set the correct value config item',
@@ -1900,7 +1923,7 @@ async function run$G(argv, importMeta, { parentName }) {
1900
1923
  return
1901
1924
  }
1902
1925
  if (cli.flags['dryRun']) {
1903
- logger.logger.log(DRY_RUN_BAIL_TEXT$F)
1926
+ logger.logger.log(DRY_RUN_BAIL_TEXT$D)
1904
1927
  return
1905
1928
  }
1906
1929
  await handleConfigAuto({
@@ -1909,7 +1932,13 @@ async function run$G(argv, importMeta, { parentName }) {
1909
1932
  })
1910
1933
  }
1911
1934
 
1912
- async function outputConfigGet(key, value, outputKind) {
1935
+ async function outputConfigGet(
1936
+ key,
1937
+ value,
1938
+ readOnly,
1939
+ // Is config in read-only mode? (Overrides applied)
1940
+ outputKind
1941
+ ) {
1913
1942
  if (outputKind === 'json') {
1914
1943
  logger.logger.log(
1915
1944
  JSON.stringify({
@@ -1917,24 +1946,38 @@ async function outputConfigGet(key, value, outputKind) {
1917
1946
  result: {
1918
1947
  key,
1919
1948
  value
1920
- }
1949
+ },
1950
+ readOnly
1921
1951
  })
1922
1952
  )
1923
1953
  } else if (outputKind === 'markdown') {
1924
1954
  logger.logger.log(`# Config Value`)
1925
1955
  logger.logger.log('')
1926
1956
  logger.logger.log(`Config key '${key}' has value '${value}`)
1957
+ if (readOnly) {
1958
+ logger.logger.log('')
1959
+ logger.logger.log(
1960
+ 'Note: the config is in read-only mode, meaning at least one key was temporarily\n overridden from an env var or command flag.'
1961
+ )
1962
+ }
1927
1963
  } else {
1928
1964
  logger.logger.log(`${key}: ${value}`)
1965
+ if (readOnly) {
1966
+ logger.logger.log('')
1967
+ logger.logger.log(
1968
+ 'Note: the config is in read-only mode, meaning at least one key was temporarily overridden from an env var or command flag.'
1969
+ )
1970
+ }
1929
1971
  }
1930
1972
  }
1931
1973
 
1932
1974
  async function handleConfigGet({ key, outputKind }) {
1933
1975
  const value = shadowNpmInject.getConfigValue(key)
1934
- await outputConfigGet(key, value, outputKind)
1976
+ const readOnly = shadowNpmInject.isReadOnlyConfig()
1977
+ await outputConfigGet(key, value, readOnly, outputKind)
1935
1978
  }
1936
1979
 
1937
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$E } = constants
1980
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$C } = constants
1938
1981
  const config$F = {
1939
1982
  commandName: 'get',
1940
1983
  description: 'Get the value of a local CLI config item',
@@ -1994,7 +2037,7 @@ async function run$F(argv, importMeta, { parentName }) {
1994
2037
  return
1995
2038
  }
1996
2039
  if (cli.flags['dryRun']) {
1997
- logger.logger.log(DRY_RUN_BAIL_TEXT$E)
2040
+ logger.logger.log(DRY_RUN_BAIL_TEXT$C)
1998
2041
  return
1999
2042
  }
2000
2043
  await handleConfigGet({
@@ -2004,6 +2047,7 @@ async function run$F(argv, importMeta, { parentName }) {
2004
2047
  }
2005
2048
 
2006
2049
  async function outputConfigList({ full, outputKind }) {
2050
+ const readOnly = shadowNpmInject.isReadOnlyConfig()
2007
2051
  if (outputKind === 'json') {
2008
2052
  const obj = {}
2009
2053
  for (const key of shadowNpmInject.supportedConfigKeys.keys()) {
@@ -2020,7 +2064,8 @@ async function outputConfigList({ full, outputKind }) {
2020
2064
  {
2021
2065
  success: true,
2022
2066
  full,
2023
- config: obj
2067
+ config: obj,
2068
+ readOnly
2024
2069
  },
2025
2070
  null,
2026
2071
  2
@@ -2045,10 +2090,16 @@ async function outputConfigList({ full, outputKind }) {
2045
2090
  )
2046
2091
  }
2047
2092
  }
2093
+ if (readOnly) {
2094
+ logger.logger.log('')
2095
+ logger.logger.log(
2096
+ 'Note: the config is in read-only mode, meaning at least one key was temporarily\n overridden from an env var or command flag.'
2097
+ )
2098
+ }
2048
2099
  }
2049
2100
  }
2050
2101
 
2051
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$D } = constants
2102
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$B } = constants
2052
2103
  const config$E = {
2053
2104
  commandName: 'list',
2054
2105
  description: 'Show all local CLI config items and their values',
@@ -2104,7 +2155,7 @@ async function run$E(argv, importMeta, { parentName }) {
2104
2155
  return
2105
2156
  }
2106
2157
  if (cli.flags['dryRun']) {
2107
- logger.logger.log(DRY_RUN_BAIL_TEXT$D)
2158
+ logger.logger.log(DRY_RUN_BAIL_TEXT$B)
2108
2159
  return
2109
2160
  }
2110
2161
  await outputConfigList({
@@ -2113,29 +2164,43 @@ async function run$E(argv, importMeta, { parentName }) {
2113
2164
  })
2114
2165
  }
2115
2166
 
2116
- async function outputConfigSet(key, _value, outputKind) {
2167
+ async function outputConfigSet(key, _value, readOnly, outputKind) {
2117
2168
  if (outputKind === 'json') {
2118
2169
  logger.logger.log(
2119
2170
  JSON.stringify({
2120
2171
  success: true,
2121
- message: `Config key '${key}' was updated`
2172
+ message: `Config key '${key}' was updated${readOnly ? ' (Note: since at least one value was overridden from flag/env, the config was not persisted)' : ''}`,
2173
+ readOnly
2122
2174
  })
2123
2175
  )
2124
2176
  } else if (outputKind === 'markdown') {
2125
2177
  logger.logger.log(`# Update config`)
2126
2178
  logger.logger.log('')
2127
2179
  logger.logger.log(`Config key '${key}' was updated`)
2180
+ if (readOnly) {
2181
+ logger.logger.log('')
2182
+ logger.logger.log(
2183
+ 'Note: The change was not persisted because the config is in read-only mode,\n meaning at least one key was temporarily overridden from an env var or\n command flag.'
2184
+ )
2185
+ }
2128
2186
  } else {
2129
2187
  logger.logger.log(`OK`)
2188
+ if (readOnly) {
2189
+ logger.logger.log('')
2190
+ logger.logger.log(
2191
+ 'Note: The change was not persisted because the config is in read-only mode, meaning at least one key was temporarily overridden from an env var or command flag.'
2192
+ )
2193
+ }
2130
2194
  }
2131
2195
  }
2132
2196
 
2133
2197
  async function handleConfigSet({ key, outputKind, value }) {
2134
2198
  shadowNpmInject.updateConfigValue(key, value)
2135
- await outputConfigSet(key, value, outputKind)
2199
+ const readOnly = shadowNpmInject.isReadOnlyConfig()
2200
+ await outputConfigSet(key, value, readOnly, outputKind)
2136
2201
  }
2137
2202
 
2138
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$C } = constants
2203
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$A } = constants
2139
2204
  const config$D = {
2140
2205
  commandName: 'set',
2141
2206
  description: 'Update the value of a local CLI config item',
@@ -2209,7 +2274,7 @@ async function run$D(argv, importMeta, { parentName }) {
2209
2274
  return
2210
2275
  }
2211
2276
  if (cli.flags['dryRun']) {
2212
- logger.logger.log(DRY_RUN_BAIL_TEXT$C)
2277
+ logger.logger.log(DRY_RUN_BAIL_TEXT$A)
2213
2278
  return
2214
2279
  }
2215
2280
  await handleConfigSet({
@@ -2241,7 +2306,7 @@ async function handleConfigUnset({ key, outputKind }) {
2241
2306
  await outputConfigUnset(key, outputKind)
2242
2307
  }
2243
2308
 
2244
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$B } = constants
2309
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$z } = constants
2245
2310
  const config$C = {
2246
2311
  commandName: 'unset',
2247
2312
  description: 'Clear the value of a local CLI config item',
@@ -2301,7 +2366,7 @@ async function run$C(argv, importMeta, { parentName }) {
2301
2366
  return
2302
2367
  }
2303
2368
  if (cli.flags['dryRun']) {
2304
- logger.logger.log(DRY_RUN_BAIL_TEXT$B)
2369
+ logger.logger.log(DRY_RUN_BAIL_TEXT$z)
2305
2370
  return
2306
2371
  }
2307
2372
  await handleConfigUnset({
@@ -2350,7 +2415,6 @@ async function fetchDependencies({ limit, offset }) {
2350
2415
  spinner.successAndStop('Received organization dependencies response.')
2351
2416
  if (!result.success) {
2352
2417
  handleUnsuccessfulApiResponse('searchDependencies', result)
2353
- return
2354
2418
  }
2355
2419
  return result.data
2356
2420
  }
@@ -2429,7 +2493,7 @@ async function handleDependencies({ limit, offset, outputKind }) {
2429
2493
  })
2430
2494
  }
2431
2495
 
2432
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$A } = constants
2496
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$y } = constants
2433
2497
  const config$B = {
2434
2498
  commandName: 'dependencies',
2435
2499
  description:
@@ -2455,6 +2519,10 @@ const config$B = {
2455
2519
  Usage
2456
2520
  ${command}
2457
2521
 
2522
+ API Token Requirements
2523
+ - Quota: 1 unit
2524
+ - Permissions: none (does need token with access to target org)
2525
+
2458
2526
  Options
2459
2527
  ${getFlagListOutput(config.flags, 6)}
2460
2528
 
@@ -2498,7 +2566,7 @@ async function run$B(argv, importMeta, { parentName }) {
2498
2566
  return
2499
2567
  }
2500
2568
  if (cli.flags['dryRun']) {
2501
- logger.logger.log(DRY_RUN_BAIL_TEXT$A)
2569
+ logger.logger.log(DRY_RUN_BAIL_TEXT$y)
2502
2570
  return
2503
2571
  }
2504
2572
  await handleDependencies({
@@ -2612,7 +2680,7 @@ async function handleDiffScan({
2612
2680
  })
2613
2681
  }
2614
2682
 
2615
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$z } = constants
2683
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$x } = constants
2616
2684
  const config$A = {
2617
2685
  commandName: 'get',
2618
2686
  description: 'Get a diff scan for an organization',
@@ -2656,6 +2724,10 @@ const config$A = {
2656
2724
  Usage
2657
2725
  $ ${command} <org slug> --before=<before> --after=<after>
2658
2726
 
2727
+ API Token Requirements
2728
+ - Quota: 1 unit
2729
+ - Permissions: full-scans:list
2730
+
2659
2731
  This command displays the package changes between two scans. The full output
2660
2732
  can be pretty large depending on the size of your repo and time range. It is
2661
2733
  best stored to disk to be further analyzed by other tools.
@@ -2687,7 +2759,7 @@ async function run$A(argv, importMeta, { parentName }) {
2687
2759
  {
2688
2760
  test: !!(before && after),
2689
2761
  message:
2690
- 'Specify a before and after scan ID\nThe args are expecting a full `aaa0aa0a-aaaa-0000-0a0a-0000000a00a0` scan ID.',
2762
+ 'Specify a before and after scan ID.\nThe args are expecting a full `aaa0aa0a-aaaa-0000-0a0a-0000000a00a0` scan ID.',
2691
2763
  pass: 'ok',
2692
2764
  fail:
2693
2765
  !before && !after
@@ -2724,7 +2796,7 @@ async function run$A(argv, importMeta, { parentName }) {
2724
2796
  return
2725
2797
  }
2726
2798
  if (cli.flags['dryRun']) {
2727
- logger.logger.log(DRY_RUN_BAIL_TEXT$z)
2799
+ logger.logger.log(DRY_RUN_BAIL_TEXT$x)
2728
2800
  return
2729
2801
  }
2730
2802
  await handleDiffScan({
@@ -2764,8 +2836,13 @@ const { NPM: NPM$f } = constants
2764
2836
  function isTopLevel(tree, node) {
2765
2837
  return tree.children.get(node.name) === node
2766
2838
  }
2767
- async function npmFix(_pkgEnvDetails, cwd, options) {
2768
- const { spinner } = {
2839
+ async function npmFix(_pkgEnvDetails, options) {
2840
+ const {
2841
+ cwd = process.cwd(),
2842
+ spinner,
2843
+ test = false,
2844
+ testScript = 'test'
2845
+ } = {
2769
2846
  __proto__: null,
2770
2847
  ...options
2771
2848
  }
@@ -2781,7 +2858,8 @@ async function npmFix(_pkgEnvDetails, cwd, options) {
2781
2858
  existing: true,
2782
2859
  unfixable: false,
2783
2860
  upgradable: false
2784
- }
2861
+ },
2862
+ nothrow: true
2785
2863
  })
2786
2864
  const infoByPkg = shadowNpmInject.getCveInfoByAlertsMap(alertsMap)
2787
2865
  if (!infoByPkg) {
@@ -2826,11 +2904,13 @@ async function npmFix(_pkgEnvDetails, cwd, options) {
2826
2904
  shadowNpmInject.updateNode(node, packument, vulnerableVersionRange)
2827
2905
  ) {
2828
2906
  try {
2829
- // eslint-disable-next-line no-await-in-loop
2830
- await npm.runScript('test', [], {
2831
- spinner,
2832
- stdio: 'ignore'
2833
- })
2907
+ if (test) {
2908
+ // eslint-disable-next-line no-await-in-loop
2909
+ await npm.runScript(testScript, [], {
2910
+ spinner,
2911
+ stdio: 'ignore'
2912
+ })
2913
+ }
2834
2914
  spinner?.info(`Patched ${name} ${oldVersion} -> ${node.version}`)
2835
2915
  if (isTopLevel(tree, node)) {
2836
2916
  for (const depField of [
@@ -2866,16 +2946,24 @@ async function npmFix(_pkgEnvDetails, cwd, options) {
2866
2946
  spinner?.stop()
2867
2947
  }
2868
2948
 
2869
- async function getAlertsMapFromPnpmLockfile(lockfile, options) {
2870
- const { include: _include, spinner } = {
2949
+ async function getAlertsMapFromPnpmLockfile(lockfile, options_) {
2950
+ const options = {
2871
2951
  __proto__: null,
2872
- ...options
2952
+ consolidate: false,
2953
+ nothrow: false,
2954
+ ...options_
2873
2955
  }
2874
2956
  const include = {
2875
2957
  __proto__: null,
2958
+ blocked: true,
2959
+ critical: true,
2960
+ cve: true,
2961
+ existing: false,
2876
2962
  unfixable: true,
2877
- ..._include
2963
+ upgradable: false,
2964
+ ...options.include
2878
2965
  }
2966
+ const { spinner } = options
2879
2967
  const depTypes = lockfile_detectDepTypes.detectDepTypes(lockfile)
2880
2968
  const pkgIds = Object.keys(depTypes)
2881
2969
  let { length: remaining } = pkgIds
@@ -2890,9 +2978,11 @@ async function getAlertsMapFromPnpmLockfile(lockfile, options) {
2890
2978
  )
2891
2979
  const toAlertsMapOptions = {
2892
2980
  overrides: lockfile.overrides,
2893
- ...options
2981
+ consolidate: options.consolidate,
2982
+ include,
2983
+ spinner
2894
2984
  }
2895
- for await (const batchPackageFetchResult of sockSdk.batchPackageStream(
2985
+ for await (const batchResult of sockSdk.batchPackageStream(
2896
2986
  {
2897
2987
  alerts: 'true',
2898
2988
  compact: 'true',
@@ -2904,12 +2994,18 @@ async function getAlertsMapFromPnpmLockfile(lockfile, options) {
2904
2994
  }))
2905
2995
  }
2906
2996
  )) {
2907
- if (batchPackageFetchResult.success) {
2997
+ if (batchResult.success) {
2908
2998
  await shadowNpmInject.addArtifactToAlertsMap(
2909
- batchPackageFetchResult.data,
2999
+ batchResult.data,
2910
3000
  alertsByPkgId,
2911
3001
  toAlertsMapOptions
2912
3002
  )
3003
+ } else if (!options.nothrow) {
3004
+ const statusCode = batchResult.status ?? 'unknown'
3005
+ const statusMessage = batchResult.error ?? 'No status message'
3006
+ throw new Error(
3007
+ `Socket API server error (${statusCode}): ${statusMessage}`
3008
+ )
2913
3009
  }
2914
3010
  remaining -= 1
2915
3011
  if (spinner && remaining > 0) {
@@ -3025,13 +3121,13 @@ function runAgentInstall(pkgEnvDetails, options) {
3025
3121
  }
3026
3122
  return spawn.spawn(agentExecPath, ['install', ...args], {
3027
3123
  spinner,
3028
- stdio: debug.isDebug() ? 'inherit' : 'ignore',
3124
+ stdio: debug.isDebug() ? 'inherit' : 'inherit',
3029
3125
  ...spawnOptions,
3030
3126
  env: {
3031
3127
  ...process.env,
3032
3128
  NODE_OPTIONS: cmdFlagsToString([
3033
3129
  // Lazily access constants.nodeHardenFlags.
3034
- ...constants.nodeHardenFlags,
3130
+ // ...constants.nodeHardenFlags,
3035
3131
  // Lazily access constants.nodeNoWarningsFlags.
3036
3132
  ...constants.nodeNoWarningsFlags
3037
3133
  ]),
@@ -3041,12 +3137,99 @@ function runAgentInstall(pkgEnvDetails, options) {
3041
3137
  }
3042
3138
 
3043
3139
  const { NPM: NPM$c, OVERRIDES: OVERRIDES$2, PNPM: PNPM$9 } = constants
3044
- async function pnpmFix(pkgEnvDetails, cwd, options) {
3045
- const { spinner } = {
3140
+ async function branchExists(branchName, cwd) {
3141
+ try {
3142
+ await spawn.spawn('git', ['rev-parse', '--verify', branchName], {
3143
+ cwd,
3144
+ stdio: 'ignore'
3145
+ })
3146
+ return true
3147
+ } catch {
3148
+ return false
3149
+ }
3150
+ }
3151
+ async function remoteBranchExists(branchName, cwd) {
3152
+ try {
3153
+ const result = await spawn.spawn(
3154
+ 'git',
3155
+ ['ls-remote', '--heads', 'origin', branchName],
3156
+ {
3157
+ cwd,
3158
+ stdio: 'pipe'
3159
+ }
3160
+ )
3161
+ return !!result.stdout.trim()
3162
+ } catch {
3163
+ return false
3164
+ }
3165
+ }
3166
+ async function commitAndPushFix(branchName, commitMsg, cwd) {
3167
+ const localExists = await branchExists(branchName, cwd)
3168
+ const remoteExists = await remoteBranchExists(branchName, cwd)
3169
+ if (localExists || remoteExists) {
3170
+ logger.logger.warn(
3171
+ `Branch "${branchName}" already exists. Skipping creation.`
3172
+ )
3173
+ return
3174
+ }
3175
+ await spawn.spawn('git', ['checkout', '-b', branchName], {
3176
+ cwd
3177
+ })
3178
+ await spawn.spawn('git', ['add', 'package.json', 'pnpm-lock.yaml'], {
3179
+ cwd
3180
+ })
3181
+ await spawn.spawn('git', ['commit', '-m', commitMsg], {
3182
+ cwd
3183
+ })
3184
+ await spawn.spawn('git', ['push', '--set-upstream', 'origin', branchName], {
3185
+ cwd
3186
+ })
3187
+ }
3188
+ async function createPullRequest({
3189
+ base = 'main',
3190
+ body,
3191
+ head,
3192
+ owner,
3193
+ repo,
3194
+ title
3195
+ }) {
3196
+ const octokit = new vendor.Octokit({
3197
+ auth: process.env['GITHUB_TOKEN']
3198
+ })
3199
+ await octokit.pulls.create({
3200
+ owner,
3201
+ repo,
3202
+ title,
3203
+ head,
3204
+ base,
3205
+ ...(body
3206
+ ? {
3207
+ body
3208
+ }
3209
+ : {})
3210
+ })
3211
+ }
3212
+ function getRepoInfo() {
3213
+ const repoString = process.env['GITHUB_REPOSITORY']
3214
+ if (!repoString || !repoString.includes('/')) {
3215
+ throw new Error('GITHUB_REPOSITORY is not set or invalid')
3216
+ }
3217
+ const { 0: owner, 1: repo } = repoString.split('/')
3218
+ return {
3219
+ owner,
3220
+ repo
3221
+ }
3222
+ }
3223
+ async function pnpmFix(pkgEnvDetails, options) {
3224
+ const {
3225
+ cwd = process.cwd(),
3226
+ spinner,
3227
+ test = false,
3228
+ testScript = 'test'
3229
+ } = {
3046
3230
  __proto__: null,
3047
3231
  ...options
3048
3232
  }
3049
- spinner?.start()
3050
3233
  const lockfile = await lockfile_fs.readWantedLockfile(cwd, {
3051
3234
  ignoreIncompatible: false
3052
3235
  })
@@ -3060,7 +3243,8 @@ async function pnpmFix(pkgEnvDetails, cwd, options) {
3060
3243
  existing: true,
3061
3244
  unfixable: false,
3062
3245
  upgradable: false
3063
- }
3246
+ },
3247
+ nothrow: true
3064
3248
  })
3065
3249
  const infoByPkg = shadowNpmInject.getCveInfoByAlertsMap(alertsMap)
3066
3250
  if (!infoByPkg) {
@@ -3076,11 +3260,12 @@ async function pnpmFix(pkgEnvDetails, cwd, options) {
3076
3260
  editable: true
3077
3261
  })
3078
3262
  const { content: pkgJson } = editablePkgJson
3263
+ spinner?.stop()
3079
3264
  for (const { 0: name, 1: infos } of infoByPkg) {
3080
3265
  const tree = arb.actualTree
3081
3266
  const hasUpgrade = !!registry.getManifestData(NPM$c, name)
3082
3267
  if (hasUpgrade) {
3083
- spinner?.info(`Skipping ${name}. Socket Optimize package exists.`)
3268
+ logger.logger.info(`Skipping ${name}. Socket Optimize package exists.`)
3084
3269
  continue
3085
3270
  }
3086
3271
  const nodes = shadowNpmInject.findPackageNodes(tree, name)
@@ -3102,6 +3287,7 @@ async function pnpmFix(pkgEnvDetails, cwd, options) {
3102
3287
  const { firstPatchedVersionIdentifier, vulnerableVersionRange } =
3103
3288
  infos[j]
3104
3289
  const { version: oldVersion } = node
3290
+ const oldSpec = `${name}@${oldVersion}`
3105
3291
  const availableVersions = Object.keys(packument.versions)
3106
3292
  // Find the highest non-vulnerable version within the same major range
3107
3293
  const targetVersion = shadowNpmInject.findBestPatchVersion(
@@ -3112,20 +3298,28 @@ async function pnpmFix(pkgEnvDetails, cwd, options) {
3112
3298
  const targetPackument = targetVersion
3113
3299
  ? packument.versions[targetVersion]
3114
3300
  : undefined
3115
- if (targetPackument) {
3301
+ spinner?.stop()
3302
+
3303
+ // Check targetVersion to make TypeScript happy.
3304
+ if (targetVersion && targetPackument) {
3116
3305
  const oldPnpm = pkgJson[PNPM$9]
3117
3306
  const oldOverrides = oldPnpm?.[OVERRIDES$2]
3118
- try {
3119
- editablePkgJson.update({
3120
- [PNPM$9]: {
3121
- ...oldPnpm,
3122
- [OVERRIDES$2]: {
3123
- [`${node.name}@${vulnerableVersionRange}`]: `^${targetVersion}`,
3124
- ...oldOverrides
3125
- }
3307
+ const overrideKey = `${node.name}@${vulnerableVersionRange}`
3308
+ const overrideRange = `^${targetVersion}`
3309
+ const fixSpec = `${name}@${overrideRange}`
3310
+ const data = {
3311
+ [PNPM$9]: {
3312
+ ...oldPnpm,
3313
+ [OVERRIDES$2]: {
3314
+ [overrideKey]: overrideRange,
3315
+ ...oldOverrides
3126
3316
  }
3127
- })
3128
- spinner?.info(`Patched ${name} ${oldVersion} -> ${node.version}`)
3317
+ }
3318
+ }
3319
+ try {
3320
+ editablePkgJson.update(data)
3321
+ spinner?.start()
3322
+ spinner?.info(`Installing ${fixSpec}`)
3129
3323
 
3130
3324
  // eslint-disable-next-line no-await-in-loop
3131
3325
  await editablePkgJson.save()
@@ -3133,11 +3327,70 @@ async function pnpmFix(pkgEnvDetails, cwd, options) {
3133
3327
  await runAgentInstall(pkgEnvDetails, {
3134
3328
  spinner
3135
3329
  })
3330
+ if (test) {
3331
+ spinner?.info(`Testing ${fixSpec}`)
3332
+ // eslint-disable-next-line no-await-in-loop
3333
+ await npm.runScript(testScript, [], {
3334
+ spinner,
3335
+ stdio: 'ignore'
3336
+ })
3337
+ }
3338
+ try {
3339
+ const branchName = `fix-${name}-${targetVersion.replace(/\./g, '-')}`
3340
+ const commitMsg = `fix: upgrade ${name} to ${targetVersion}`
3341
+ const { owner, repo } = getRepoInfo()
3342
+ // eslint-disable-next-line no-await-in-loop
3343
+ await commitAndPushFix(branchName, commitMsg, cwd)
3344
+ // eslint-disable-next-line no-await-in-loop
3345
+ await createPullRequest({
3346
+ owner,
3347
+ repo,
3348
+ title: commitMsg,
3349
+ head: branchName,
3350
+ base: process.env['GITHUB_REF_NAME'] ?? 'master',
3351
+ body: `This PR fixes a security issue in \`${name}\` by upgrading to \`${targetVersion}\`.`
3352
+ })
3353
+ } catch (e) {
3354
+ console.log(e)
3355
+ }
3356
+ logger.logger.success(`Fixed ${name}`)
3136
3357
  } catch {
3137
- spinner?.error(`Reverting ${name} to ${oldVersion}`)
3358
+ spinner?.error(`Reverting ${fixSpec}`)
3359
+ const pnpmKeyCount = Object.keys(data[PNPM$9]).length
3360
+ const pnpmOverridesKeyCount = Object.keys(
3361
+ data[PNPM$9][OVERRIDES$2]
3362
+ ).length
3363
+ if (pnpmKeyCount === 1 && pnpmOverridesKeyCount === 1) {
3364
+ editablePkgJson.update({
3365
+ // Setting to `undefined` will remove the property.
3366
+ [PNPM$9]: undefined
3367
+ })
3368
+ } else {
3369
+ editablePkgJson.update({
3370
+ [PNPM$9]: {
3371
+ ...oldPnpm,
3372
+ [OVERRIDES$2]:
3373
+ pnpmOverridesKeyCount === 1
3374
+ ? undefined
3375
+ : {
3376
+ [overrideKey]: undefined,
3377
+ ...oldOverrides
3378
+ }
3379
+ }
3380
+ })
3381
+ }
3382
+ // eslint-disable-next-line no-await-in-loop
3383
+ await editablePkgJson.save()
3384
+ // eslint-disable-next-line no-await-in-loop
3385
+ await runAgentInstall(pkgEnvDetails, {
3386
+ spinner
3387
+ })
3388
+ spinner?.stop()
3389
+ logger.logger.error(`Failed to fix ${oldSpec}`)
3138
3390
  }
3139
3391
  } else {
3140
- spinner?.error(`Could not patch ${name} ${oldVersion}`)
3392
+ spinner?.stop()
3393
+ logger.logger.error(`Could not patch ${oldSpec}`)
3141
3394
  }
3142
3395
  }
3143
3396
  }
@@ -3543,39 +3796,59 @@ async function detectAndValidatePackageEnvironment(cwd, options) {
3543
3796
 
3544
3797
  const { NPM: NPM$a, PNPM: PNPM$7 } = constants
3545
3798
  const CMD_NAME$2 = 'socket fix'
3546
- async function runFix() {
3547
- // Lazily access constants.spinner.
3548
- const { spinner } = constants
3549
- spinner.start()
3550
- const cwd = process.cwd()
3799
+ async function runFix({
3800
+ cwd = process.cwd(),
3801
+ spinner,
3802
+ test = false,
3803
+ testScript = 'test'
3804
+ }) {
3551
3805
  const pkgEnvDetails = await detectAndValidatePackageEnvironment(cwd, {
3552
3806
  cmdName: CMD_NAME$2,
3553
3807
  logger: logger.logger
3554
3808
  })
3555
3809
  if (!pkgEnvDetails) {
3556
- spinner.stop()
3810
+ spinner?.stop()
3557
3811
  return
3558
3812
  }
3813
+ logger.logger.info(`Fixing packages for ${pkgEnvDetails.agent}`)
3559
3814
  switch (pkgEnvDetails.agent) {
3560
3815
  case NPM$a: {
3561
- await npmFix(pkgEnvDetails, cwd)
3816
+ await npmFix(pkgEnvDetails, {
3817
+ spinner,
3818
+ test,
3819
+ testScript
3820
+ })
3562
3821
  break
3563
3822
  }
3564
3823
  case PNPM$7: {
3565
- await pnpmFix(pkgEnvDetails, cwd)
3824
+ await pnpmFix(pkgEnvDetails, {
3825
+ spinner,
3826
+ test,
3827
+ testScript
3828
+ })
3566
3829
  break
3567
3830
  }
3568
3831
  }
3569
- spinner.successAndStop('Socket.dev fix successful')
3832
+ // spinner.successAndStop('Socket.dev fix successful')
3570
3833
  }
3571
3834
 
3572
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$y } = constants
3835
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$w } = constants
3573
3836
  const config$z = {
3574
3837
  commandName: 'fix',
3575
3838
  description: 'Fix "fixable" Socket alerts',
3576
3839
  hidden: true,
3577
3840
  flags: {
3578
- ...commonFlags
3841
+ ...commonFlags,
3842
+ test: {
3843
+ type: 'boolean',
3844
+ default: true,
3845
+ description: 'Very the fix by running unit tests'
3846
+ },
3847
+ testScript: {
3848
+ type: 'string',
3849
+ default: 'test',
3850
+ description: 'The test script to run for each fix attempt'
3851
+ }
3579
3852
  },
3580
3853
  help: (command, config) => `
3581
3854
  Usage
@@ -3598,10 +3871,17 @@ async function run$z(argv, importMeta, { parentName }) {
3598
3871
  parentName
3599
3872
  })
3600
3873
  if (cli.flags['dryRun']) {
3601
- logger.logger.log(DRY_RUN_BAIL_TEXT$y)
3874
+ logger.logger.log(DRY_RUN_BAIL_TEXT$w)
3602
3875
  return
3603
3876
  }
3604
- await runFix()
3877
+
3878
+ // Lazily access constants.spinner.
3879
+ const { spinner } = constants
3880
+ await runFix({
3881
+ spinner,
3882
+ test: Boolean(cli.flags['test']),
3883
+ testScript: cli.flags['testScript']
3884
+ })
3605
3885
  }
3606
3886
 
3607
3887
  async function fetchPackageInfo(pkgName, pkgVersion, includeAllIssues) {
@@ -3626,10 +3906,10 @@ async function fetchPackageInfo(pkgName, pkgVersion, includeAllIssues) {
3626
3906
  )
3627
3907
  spinner.successAndStop('Data fetched')
3628
3908
  if (result.success === false) {
3629
- return handleUnsuccessfulApiResponse('getIssuesByNPMPackage', result)
3909
+ handleUnsuccessfulApiResponse('getIssuesByNPMPackage', result)
3630
3910
  }
3631
3911
  if (scoreResult.success === false) {
3632
- return handleUnsuccessfulApiResponse('getScoreByNPMPackage', scoreResult)
3912
+ handleUnsuccessfulApiResponse('getScoreByNPMPackage', scoreResult)
3633
3913
  }
3634
3914
  const severityCount = shadowNpmInject.getSeverityCount(
3635
3915
  result.data,
@@ -3790,7 +4070,7 @@ async function handlePackageInfo({
3790
4070
  }
3791
4071
  }
3792
4072
 
3793
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$x } = constants
4073
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$v } = constants
3794
4074
  const config$y = {
3795
4075
  commandName: 'info',
3796
4076
  description: 'Look up info regarding a package',
@@ -3858,7 +4138,7 @@ async function run$y(argv, importMeta, { parentName }) {
3858
4138
  const pkgVersion =
3859
4139
  versionSeparator < 1 ? 'latest' : rawPkgName.slice(versionSeparator + 1)
3860
4140
  if (cli.flags['dryRun']) {
3861
- logger.logger.log(DRY_RUN_BAIL_TEXT$x)
4141
+ logger.logger.log(DRY_RUN_BAIL_TEXT$v)
3862
4142
  return
3863
4143
  }
3864
4144
  await handlePackageInfo({
@@ -3895,7 +4175,6 @@ async function attemptLogin(apiBaseUrl, apiProxy) {
3895
4175
  if (!result.success) {
3896
4176
  logger.logger.fail('Authentication failed...')
3897
4177
  handleUnsuccessfulApiResponse('getOrganizations', result)
3898
- return
3899
4178
  }
3900
4179
  logger.logger.success('API key verified')
3901
4180
  const orgs = result.data
@@ -3933,16 +4212,24 @@ async function attemptLogin(apiBaseUrl, apiProxy) {
3933
4212
  }
3934
4213
  }
3935
4214
  spinner.stop()
3936
- const oldToken = shadowNpmInject.getConfigValue('apiToken')
4215
+ const previousPersistedToken = shadowNpmInject.getConfigValue('apiToken')
3937
4216
  try {
3938
4217
  applyLogin(apiToken, enforcedOrgs, apiBaseUrl, apiProxy)
3939
- logger.logger.success(`API credentials ${oldToken ? 'updated' : 'set'}`)
4218
+ logger.logger.success(
4219
+ `API credentials ${previousPersistedToken === apiToken ? 'refreshed' : previousPersistedToken ? 'updated' : 'set'}`
4220
+ )
4221
+ if (!shadowNpmInject.isReadOnlyConfig()) {
4222
+ logger.logger.log('')
4223
+ logger.logger.warn(
4224
+ 'Note: config is in read-only mode, at least one key was overridden through flag/env, so the login was not persisted!'
4225
+ )
4226
+ }
3940
4227
  } catch {
3941
4228
  logger.logger.fail(`API login failed`)
3942
4229
  }
3943
4230
  }
3944
4231
 
3945
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$w } = constants
4232
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$u } = constants
3946
4233
  const config$x = {
3947
4234
  commandName: 'login',
3948
4235
  description: 'Socket API login',
@@ -3962,6 +4249,9 @@ const config$x = {
3962
4249
  Usage
3963
4250
  $ ${command}
3964
4251
 
4252
+ API Token Requirements
4253
+ - Quota: 1 unit
4254
+
3965
4255
  Logs into the Socket API by prompting for an API key
3966
4256
 
3967
4257
  Options
@@ -3987,7 +4277,7 @@ async function run$x(argv, importMeta, { parentName }) {
3987
4277
  const apiBaseUrl = cli.flags['apiBaseUrl']
3988
4278
  const apiProxy = cli.flags['apiProxy']
3989
4279
  if (cli.flags['dryRun']) {
3990
- logger.logger.log(DRY_RUN_BAIL_TEXT$w)
4280
+ logger.logger.log(DRY_RUN_BAIL_TEXT$u)
3991
4281
  return
3992
4282
  }
3993
4283
  if (!isInteractive()) {
@@ -4009,12 +4299,18 @@ function attemptLogout() {
4009
4299
  try {
4010
4300
  applyLogout()
4011
4301
  logger.logger.success('Successfully logged out')
4302
+ if (!shadowNpmInject.isReadOnlyConfig()) {
4303
+ logger.logger.log('')
4304
+ logger.logger.warn(
4305
+ 'Note: config is in read-only mode, at least one key was overridden through flag/env, so the logout was not persisted!'
4306
+ )
4307
+ }
4012
4308
  } catch {
4013
4309
  logger.logger.fail('Failed to complete logout steps')
4014
4310
  }
4015
4311
  }
4016
4312
 
4017
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$v } = constants
4313
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$t } = constants
4018
4314
  const config$w = {
4019
4315
  commandName: 'logout',
4020
4316
  description: 'Socket API logout',
@@ -4042,7 +4338,7 @@ async function run$w(argv, importMeta, { parentName }) {
4042
4338
  parentName
4043
4339
  })
4044
4340
  if (cli.flags['dryRun']) {
4045
- logger.logger.log(DRY_RUN_BAIL_TEXT$v)
4341
+ logger.logger.log(DRY_RUN_BAIL_TEXT$t)
4046
4342
  return
4047
4343
  }
4048
4344
  attemptLogout()
@@ -4150,7 +4446,7 @@ async function convertGradleToMaven(target, bin, _out, verbose, gradleOpts) {
4150
4446
  }
4151
4447
  }
4152
4448
 
4153
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$u } = constants
4449
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$s } = constants
4154
4450
  const config$v = {
4155
4451
  commandName: 'gradle',
4156
4452
  description:
@@ -4297,7 +4593,7 @@ async function run$v(argv, importMeta, { parentName }) {
4297
4593
  .filter(Boolean)
4298
4594
  }
4299
4595
  if (cli.flags['dryRun']) {
4300
- logger.logger.log(DRY_RUN_BAIL_TEXT$u)
4596
+ logger.logger.log(DRY_RUN_BAIL_TEXT$s)
4301
4597
  return
4302
4598
  }
4303
4599
  await convertGradleToMaven(target, bin, out, verbose, gradleOpts)
@@ -4406,7 +4702,7 @@ async function convertSbtToMaven(target, bin, out, verbose, sbtOpts) {
4406
4702
  }
4407
4703
  }
4408
4704
 
4409
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$t } = constants
4705
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$r } = constants
4410
4706
  const config$u = {
4411
4707
  commandName: 'scala',
4412
4708
  description:
@@ -4551,13 +4847,13 @@ async function run$u(argv, importMeta, { parentName }) {
4551
4847
  .filter(Boolean)
4552
4848
  }
4553
4849
  if (cli.flags['dryRun']) {
4554
- logger.logger.log(DRY_RUN_BAIL_TEXT$t)
4850
+ logger.logger.log(DRY_RUN_BAIL_TEXT$r)
4555
4851
  return
4556
4852
  }
4557
4853
  await convertSbtToMaven(target, bin, out, verbose, sbtOpts)
4558
4854
  }
4559
4855
 
4560
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$s } = constants
4856
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$q } = constants
4561
4857
  const config$t = {
4562
4858
  commandName: 'auto',
4563
4859
  description: 'Auto-detect build and attempt to generate manifest file',
@@ -4623,7 +4919,7 @@ async function run$t(argv, importMeta, { parentName }) {
4623
4919
  }
4624
4920
  subArgs.push(dir)
4625
4921
  if (cli.flags['dryRun']) {
4626
- logger.logger.log(DRY_RUN_BAIL_TEXT$s)
4922
+ logger.logger.log(DRY_RUN_BAIL_TEXT$q)
4627
4923
  return
4628
4924
  }
4629
4925
  await cmdManifestScala.run(subArgs, importMeta, {
@@ -4640,7 +4936,7 @@ async function run$t(argv, importMeta, { parentName }) {
4640
4936
  subArgs.push(cwd)
4641
4937
  }
4642
4938
  if (cli.flags['dryRun']) {
4643
- logger.logger.log(DRY_RUN_BAIL_TEXT$s)
4939
+ logger.logger.log(DRY_RUN_BAIL_TEXT$q)
4644
4940
  return
4645
4941
  }
4646
4942
  await cmdManifestGradle.run(subArgs, importMeta, {
@@ -4649,7 +4945,7 @@ async function run$t(argv, importMeta, { parentName }) {
4649
4945
  return
4650
4946
  }
4651
4947
  if (cli.flags['dryRun']) {
4652
- logger.logger.log(DRY_RUN_BAIL_TEXT$s)
4948
+ logger.logger.log(DRY_RUN_BAIL_TEXT$q)
4653
4949
  return
4654
4950
  }
4655
4951
 
@@ -4678,7 +4974,7 @@ async function run$t(argv, importMeta, { parentName }) {
4678
4974
  .showHelp()
4679
4975
  }
4680
4976
 
4681
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$r } = constants
4977
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$p } = constants
4682
4978
 
4683
4979
  // TODO: we may want to dedupe some pieces for all gradle languages. I think it
4684
4980
  // makes sense to have separate commands for them and I think it makes
@@ -4831,7 +5127,7 @@ async function run$s(argv, importMeta, { parentName }) {
4831
5127
  .filter(Boolean)
4832
5128
  }
4833
5129
  if (cli.flags['dryRun']) {
4834
- logger.logger.log(DRY_RUN_BAIL_TEXT$r)
5130
+ logger.logger.log(DRY_RUN_BAIL_TEXT$p)
4835
5131
  return
4836
5132
  }
4837
5133
  await convertGradleToMaven(target, bin, out, verbose, gradleOpts)
@@ -4882,7 +5178,7 @@ async function wrapNpm(argv) {
4882
5178
  await shadowBin(NPM$8, argv)
4883
5179
  }
4884
5180
 
4885
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$q, NPM: NPM$7 } = constants
5181
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$o, NPM: NPM$7 } = constants
4886
5182
  const config$q = {
4887
5183
  commandName: 'npm',
4888
5184
  description: `${NPM$7} wrapper functionality`,
@@ -4909,7 +5205,7 @@ async function run$q(argv, importMeta, { parentName }) {
4909
5205
  parentName
4910
5206
  })
4911
5207
  if (cli.flags['dryRun']) {
4912
- logger.logger.log(DRY_RUN_BAIL_TEXT$q)
5208
+ logger.logger.log(DRY_RUN_BAIL_TEXT$o)
4913
5209
  return
4914
5210
  }
4915
5211
  await wrapNpm(argv)
@@ -4922,7 +5218,7 @@ async function wrapNpx(argv) {
4922
5218
  await shadowBin(NPX$2, argv)
4923
5219
  }
4924
5220
 
4925
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$p, NPX: NPX$1 } = constants
5221
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$n, NPX: NPX$1 } = constants
4926
5222
  const config$p = {
4927
5223
  commandName: 'npx',
4928
5224
  description: `${NPX$1} wrapper functionality`,
@@ -4949,13 +5245,13 @@ async function run$p(argv, importMeta, { parentName }) {
4949
5245
  parentName
4950
5246
  })
4951
5247
  if (cli.flags['dryRun']) {
4952
- logger.logger.log(DRY_RUN_BAIL_TEXT$p)
5248
+ logger.logger.log(DRY_RUN_BAIL_TEXT$n)
4953
5249
  return
4954
5250
  }
4955
5251
  await wrapNpx(argv)
4956
5252
  }
4957
5253
 
4958
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$o } = constants
5254
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$m } = constants
4959
5255
  const config$o = {
4960
5256
  commandName: 'oops',
4961
5257
  description: 'Trigger an intentional error (for development)',
@@ -4983,7 +5279,7 @@ async function run$o(argv, importMeta, { parentName }) {
4983
5279
  parentName
4984
5280
  })
4985
5281
  if (cli.flags['dryRun']) {
4986
- logger.logger.log(DRY_RUN_BAIL_TEXT$o)
5282
+ logger.logger.log(DRY_RUN_BAIL_TEXT$m)
4987
5283
  return
4988
5284
  }
4989
5285
  throw new Error('This error was intentionally left blank')
@@ -5872,7 +6168,7 @@ async function applyOptimization(cwd, pin, prod) {
5872
6168
  }
5873
6169
  }
5874
6170
 
5875
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$n } = constants
6171
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$l } = constants
5876
6172
  const config$n = {
5877
6173
  commandName: 'optimize',
5878
6174
  description: 'Optimize dependencies with @socketregistry overrides',
@@ -5916,7 +6212,7 @@ async function run$n(argv, importMeta, { parentName }) {
5916
6212
  })
5917
6213
  const cwd = process.cwd()
5918
6214
  if (cli.flags['dryRun']) {
5919
- logger.logger.log(DRY_RUN_BAIL_TEXT$n)
6215
+ logger.logger.log(DRY_RUN_BAIL_TEXT$l)
5920
6216
  return
5921
6217
  }
5922
6218
  await applyOptimization(
@@ -5939,7 +6235,6 @@ async function fetchOrganization() {
5939
6235
  spinner.successAndStop('Received organization list response.')
5940
6236
  if (!result.success) {
5941
6237
  handleUnsuccessfulApiResponse('getOrganizations', result)
5942
- return
5943
6238
  }
5944
6239
  return result.data
5945
6240
  }
@@ -6018,7 +6313,7 @@ async function handleOrganizationList(outputKind = 'text') {
6018
6313
  await outputOrganizationList(data, outputKind)
6019
6314
  }
6020
6315
 
6021
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$m } = constants
6316
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$k } = constants
6022
6317
  const config$m = {
6023
6318
  commandName: 'list',
6024
6319
  description: 'List organizations associated with the API key used',
@@ -6031,6 +6326,10 @@ const config$m = {
6031
6326
  Usage
6032
6327
  $ ${command}
6033
6328
 
6329
+ API Token Requirements
6330
+ - Quota: 1 unit
6331
+ - Permissions: none (does need a token)
6332
+
6034
6333
  Options
6035
6334
  ${getFlagListOutput(config$m.flags, 6)}
6036
6335
  `
@@ -6071,7 +6370,7 @@ async function run$m(argv, importMeta, { parentName }) {
6071
6370
  return
6072
6371
  }
6073
6372
  if (cli.flags['dryRun']) {
6074
- logger.logger.log(DRY_RUN_BAIL_TEXT$m)
6373
+ logger.logger.log(DRY_RUN_BAIL_TEXT$k)
6075
6374
  return
6076
6375
  }
6077
6376
  await handleOrganizationList(json ? 'json' : markdown ? 'markdown' : 'text')
@@ -6090,7 +6389,6 @@ async function fetchLicensePolicy(orgSlug) {
6090
6389
  spinner.successAndStop('Received organization license policy response.')
6091
6390
  if (!result.success) {
6092
6391
  handleUnsuccessfulApiResponse('getOrgLicensePolicy', result)
6093
- return
6094
6392
  }
6095
6393
  return result.data
6096
6394
  }
@@ -6135,7 +6433,7 @@ async function handleLicensePolicy(orgSlug, outputKind) {
6135
6433
  await outputLicensePolicy(data, outputKind)
6136
6434
  }
6137
6435
 
6138
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$l } = constants
6436
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$j } = constants
6139
6437
 
6140
6438
  // TODO: secret toplevel alias `socket license policy`?
6141
6439
  const config$l = {
@@ -6150,6 +6448,10 @@ const config$l = {
6150
6448
  Usage
6151
6449
  $ ${command} <org slug>
6152
6450
 
6451
+ API Token Requirements
6452
+ - Quota: 1 unit
6453
+ - Permissions: license-policy:read
6454
+
6153
6455
  Options
6154
6456
  ${getFlagListOutput(config$l.flags, 6)}
6155
6457
 
@@ -6206,7 +6508,7 @@ async function run$l(argv, importMeta, { parentName }) {
6206
6508
  return
6207
6509
  }
6208
6510
  if (cli.flags['dryRun']) {
6209
- logger.logger.log(DRY_RUN_BAIL_TEXT$l)
6511
+ logger.logger.log(DRY_RUN_BAIL_TEXT$j)
6210
6512
  return
6211
6513
  }
6212
6514
  await handleLicensePolicy(
@@ -6228,7 +6530,6 @@ async function fetchSecurityPolicy(orgSlug) {
6228
6530
  spinner.successAndStop('Received organization security policy response.')
6229
6531
  if (!result.success) {
6230
6532
  handleUnsuccessfulApiResponse('getOrgSecurityPolicy', result)
6231
- return
6232
6533
  }
6233
6534
  return result.data
6234
6535
  }
@@ -6274,7 +6575,7 @@ async function handleSecurityPolicy(orgSlug, outputKind) {
6274
6575
  await outputSecurityPolicy(data, outputKind)
6275
6576
  }
6276
6577
 
6277
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$k } = constants
6578
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$i } = constants
6278
6579
 
6279
6580
  // TODO: secret toplevel alias `socket security policy`?
6280
6581
  const config$k = {
@@ -6289,6 +6590,10 @@ const config$k = {
6289
6590
  Usage
6290
6591
  $ ${command} <org slug>
6291
6592
 
6593
+ API Token Requirements
6594
+ - Quota: 1 unit
6595
+ - Permissions: security-policy:read
6596
+
6292
6597
  Options
6293
6598
  ${getFlagListOutput(config$k.flags, 6)}
6294
6599
 
@@ -6345,7 +6650,7 @@ async function run$k(argv, importMeta, { parentName }) {
6345
6650
  return
6346
6651
  }
6347
6652
  if (cli.flags['dryRun']) {
6348
- logger.logger.log(DRY_RUN_BAIL_TEXT$k)
6653
+ logger.logger.log(DRY_RUN_BAIL_TEXT$i)
6349
6654
  return
6350
6655
  }
6351
6656
  await handleSecurityPolicy(
@@ -6393,7 +6698,6 @@ async function fetchQuota() {
6393
6698
  spinner.successAndStop('Received organization quota response.')
6394
6699
  if (!result.success) {
6395
6700
  handleUnsuccessfulApiResponse('getQuota', result)
6396
- return
6397
6701
  }
6398
6702
  return result.data
6399
6703
  }
@@ -6432,7 +6736,7 @@ async function handleQuota(outputKind = 'text') {
6432
6736
  await outputQuota(data, outputKind)
6433
6737
  }
6434
6738
 
6435
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$j } = constants
6739
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$h } = constants
6436
6740
  const config$j = {
6437
6741
  commandName: 'quota',
6438
6742
  description: 'List organizations associated with the API key used',
@@ -6485,7 +6789,7 @@ async function run$j(argv, importMeta, { parentName }) {
6485
6789
  return
6486
6790
  }
6487
6791
  if (cli.flags['dryRun']) {
6488
- logger.logger.log(DRY_RUN_BAIL_TEXT$j)
6792
+ logger.logger.log(DRY_RUN_BAIL_TEXT$h)
6489
6793
  return
6490
6794
  }
6491
6795
  await handleQuota(json ? 'json' : markdown ? 'markdown' : 'text')
@@ -6518,6 +6822,7 @@ const cmdOrganization = {
6518
6822
  }
6519
6823
  }
6520
6824
 
6825
+ const { SOCKET_CLI_ISSUES_URL } = constants
6521
6826
  async function fetchPurlDeepScore(purl) {
6522
6827
  const apiToken = shadowNpmInject.getDefaultToken()
6523
6828
  if (!apiToken) {
@@ -6559,7 +6864,7 @@ async function fetchPurlDeepScore(purl) {
6559
6864
  return JSON.parse(data)
6560
6865
  } catch (e) {
6561
6866
  throw new Error(
6562
- 'Was unable to JSON parse the input from the server. It may not have been a proper JSON response. Please report this problem.'
6867
+ `Unable to parse JSON response from the Socket API.\nPlease report to ${SOCKET_CLI_ISSUES_URL}`
6563
6868
  )
6564
6869
  }
6565
6870
  }
@@ -6752,7 +7057,7 @@ async function outputPurlScore(purl, data, outputKind) {
6752
7057
  )
6753
7058
  } else {
6754
7059
  logger.logger.log(
6755
- 'This package had no alerts and neither did any of its direct/transitive dependencies.'
7060
+ 'This package had no alerts and neither did any of its direct/transitive dependencies'
6756
7061
  )
6757
7062
  }
6758
7063
  logger.logger.log('')
@@ -6827,7 +7132,7 @@ function parsePackageSpecifiers(ecosystem, pkgs) {
6827
7132
  }
6828
7133
  }
6829
7134
 
6830
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$i } = constants
7135
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$g } = constants
6831
7136
  const config$i = {
6832
7137
  commandName: 'score',
6833
7138
  description:
@@ -6841,13 +7146,13 @@ const config$i = {
6841
7146
  Usage
6842
7147
  $ ${command} <<ecosystem> <name> | <purl>>
6843
7148
 
7149
+ API Token Requirements
7150
+ - Quota: 100 units
7151
+ - Permissions: packages:list
7152
+
6844
7153
  Options
6845
7154
  ${getFlagListOutput(config.flags, 6)}
6846
7155
 
6847
- Requirements
6848
- - quota: 100
6849
- - scope: \`packages:list\`
6850
-
6851
7156
  Show deep scoring details for one package. The score will reflect the package
6852
7157
  itself, any of its dependencies, and any of its transitive dependencies.
6853
7158
 
@@ -6919,7 +7224,7 @@ async function run$i(argv, importMeta, { parentName }) {
6919
7224
  return
6920
7225
  }
6921
7226
  if (cli.flags['dryRun']) {
6922
- logger.logger.log(DRY_RUN_BAIL_TEXT$i)
7227
+ logger.logger.log(DRY_RUN_BAIL_TEXT$g)
6923
7228
  return
6924
7229
  }
6925
7230
  await handlePurlDeepScore(
@@ -6943,10 +7248,6 @@ async function fetchPurlsShallowScore(purls) {
6943
7248
  sockSdk.batchPackageFetch(
6944
7249
  {
6945
7250
  alerts: 'true'
6946
- // compact: false,
6947
- // fixable: false,
6948
- // licenseattrib: false,
6949
- // licensedetails: false
6950
7251
  },
6951
7252
  {
6952
7253
  components: purls.map(purl => ({
@@ -6959,7 +7260,6 @@ async function fetchPurlsShallowScore(purls) {
6959
7260
  spinner.successAndStop('Request completed')
6960
7261
  if (!result.success) {
6961
7262
  handleUnsuccessfulApiResponse('batchPackageFetch', result)
6962
- return
6963
7263
  }
6964
7264
  return result
6965
7265
  }
@@ -7116,7 +7416,7 @@ async function handlePurlsShallowScore({ outputKind, purls }) {
7116
7416
  outputPurlsShallowScore(purls, packageData.data, outputKind)
7117
7417
  }
7118
7418
 
7119
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$h } = constants
7419
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$f } = constants
7120
7420
  const config$h = {
7121
7421
  commandName: 'shallow',
7122
7422
  description:
@@ -7130,13 +7430,13 @@ const config$h = {
7130
7430
  Usage
7131
7431
  $ ${command} <<ecosystem> <name> [<name> ...] | <purl> [<purl> ...]>
7132
7432
 
7433
+ API Token Requirements
7434
+ - Quota: 100 units
7435
+ - Permissions: packages:list
7436
+
7133
7437
  Options
7134
7438
  ${getFlagListOutput(config.flags, 6)}
7135
7439
 
7136
- Requirements
7137
- - quota: 100
7138
- - scope: \`packages:list\`
7139
-
7140
7440
  Show scoring details for one or more packages purely based on their own package.
7141
7441
  This means that any dependency scores are not reflected by the score. You can
7142
7442
  use the \`socket package score <pkg>\` command to get its full transitive score.
@@ -7207,7 +7507,7 @@ async function run$h(argv, importMeta, { parentName }) {
7207
7507
  return
7208
7508
  }
7209
7509
  if (cli.flags['dryRun']) {
7210
- logger.logger.log(DRY_RUN_BAIL_TEXT$h)
7510
+ logger.logger.log(DRY_RUN_BAIL_TEXT$f)
7211
7511
  return
7212
7512
  }
7213
7513
  await handlePurlsShallowScore({
@@ -7260,7 +7560,7 @@ async function runRawNpm(argv) {
7260
7560
  await spawnPromise
7261
7561
  }
7262
7562
 
7263
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$g, NPM } = constants
7563
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$e, NPM } = constants
7264
7564
  const config$g = {
7265
7565
  commandName: 'raw-npm',
7266
7566
  description: `Temporarily disable the Socket ${NPM} wrapper`,
@@ -7288,7 +7588,7 @@ async function run$g(argv, importMeta, { parentName }) {
7288
7588
  parentName
7289
7589
  })
7290
7590
  if (cli.flags['dryRun']) {
7291
- logger.logger.log(DRY_RUN_BAIL_TEXT$g)
7591
+ logger.logger.log(DRY_RUN_BAIL_TEXT$e)
7292
7592
  return
7293
7593
  }
7294
7594
  await runRawNpm(argv)
@@ -7310,7 +7610,7 @@ async function runRawNpx(argv) {
7310
7610
  await spawnPromise
7311
7611
  }
7312
7612
 
7313
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$f, NPX } = constants
7613
+ const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$d, NPX } = constants
7314
7614
  const config$f = {
7315
7615
  commandName: 'raw-npx',
7316
7616
  description: `Temporarily disable the Socket ${NPX} wrapper`,
@@ -7338,242 +7638,12 @@ async function run$f(argv, importMeta, { parentName }) {
7338
7638
  parentName
7339
7639
  })
7340
7640
  if (cli.flags['dryRun']) {
7341
- logger.logger.log(DRY_RUN_BAIL_TEXT$f)
7641
+ logger.logger.log(DRY_RUN_BAIL_TEXT$d)
7342
7642
  return
7343
7643
  }
7344
7644
  await runRawNpx(argv)
7345
7645
  }
7346
7646
 
7347
- const { DRY_RUN_LABEL } = constants
7348
- async function createReport(socketConfig, inputPaths, { cwd, dryRun }) {
7349
- // Lazily access constants.spinner.
7350
- const { spinner } = constants
7351
- const sockSdk = await shadowNpmInject.setupSdk()
7352
- const supportedFiles = await sockSdk
7353
- .getReportSupportedFiles()
7354
- .then(res => {
7355
- if (!res.success) {
7356
- handleUnsuccessfulApiResponse('getReportSupportedFiles', res)
7357
- }
7358
- return res.data
7359
- })
7360
- .catch(cause => {
7361
- throw new Error('Failed getting supported files for report', {
7362
- cause
7363
- })
7364
- })
7365
- const packagePaths = await shadowNpmPaths.getPackageFilesForScan(
7366
- cwd,
7367
- inputPaths,
7368
- supportedFiles,
7369
- socketConfig
7370
- )
7371
- const packagePathsCount = packagePaths.length
7372
- if (packagePathsCount && debug.isDebug()) {
7373
- for (const pkgPath of packagePaths) {
7374
- debug.debugLog(`Uploading: ${pkgPath}`)
7375
- }
7376
- }
7377
- if (dryRun) {
7378
- debug.debugLog(`${DRY_RUN_LABEL}: Skipped actual upload`)
7379
- return undefined
7380
- }
7381
- spinner.start(
7382
- `Creating report with ${packagePathsCount} package ${words.pluralize('file', packagePathsCount)}`
7383
- )
7384
- const apiCall = sockSdk.createReportFromFilePaths(
7385
- packagePaths,
7386
- cwd,
7387
- socketConfig?.issueRules
7388
- )
7389
- const result = await handleApiCall(apiCall, 'creating report')
7390
- if (!result.success) {
7391
- handleUnsuccessfulApiResponse('createReport', result)
7392
- return undefined
7393
- }
7394
- spinner.successAndStop()
7395
- return result
7396
- }
7397
-
7398
- async function getSocketConfig(absoluteConfigPath) {
7399
- const socketConfig = await config$K
7400
- .readSocketConfig(absoluteConfigPath)
7401
- .catch(cause => {
7402
- if (
7403
- cause &&
7404
- typeof cause === 'object' &&
7405
- cause instanceof config$K.SocketValidationError
7406
- ) {
7407
- // Inspired by workbox-build:
7408
- // https://github.com/GoogleChrome/workbox/blob/95f97a207fd51efb3f8a653f6e3e58224183a778/packages/workbox-build/src/lib/validate-options.ts#L68-L71
7409
- const betterErrors = betterAjvErrors.betterAjvErrors({
7410
- basePath: 'config',
7411
- data: cause.data,
7412
- errors: cause.validationErrors,
7413
- schema: cause.schema
7414
- })
7415
- throw new shadowNpmInject.InputError(
7416
- 'The socket.yml config is not valid',
7417
- betterErrors
7418
- .map(
7419
- err =>
7420
- `[${err.path}] ${err.message}.${err.suggestion ? err.suggestion : ''}`
7421
- )
7422
- .join('\n')
7423
- )
7424
- } else {
7425
- throw new Error('Failed to read socket.yml config', {
7426
- cause
7427
- })
7428
- }
7429
- })
7430
- return socketConfig
7431
- }
7432
-
7433
- const MAX_TIMEOUT_RETRY = 5
7434
- const HTTP_CODE_TIMEOUT = 524
7435
- async function fetchReportData$1(reportId, includeAllIssues, strict) {
7436
- // Lazily access constants.spinner.
7437
- const { spinner } = constants
7438
- spinner.log('Fetching report with ID ${reportId} (this could take a while)')
7439
- spinner.start(`Fetch started... (this could take a while)`)
7440
- const sockSdk = await shadowNpmInject.setupSdk()
7441
- let result
7442
- for (let retry = 1; !result; ++retry) {
7443
- try {
7444
- // eslint-disable-next-line no-await-in-loop
7445
- result = await handleApiCall(
7446
- sockSdk.getReport(reportId),
7447
- 'fetching report'
7448
- )
7449
- } catch (err) {
7450
- if (
7451
- retry >= MAX_TIMEOUT_RETRY ||
7452
- !(err instanceof Error) ||
7453
- err.cause?.cause?.response?.statusCode !== HTTP_CODE_TIMEOUT
7454
- ) {
7455
- spinner.stop(`Failed to fetch report`)
7456
- throw err
7457
- }
7458
- spinner.fail(`Retrying report fetch ${retry} / ${MAX_TIMEOUT_RETRY}`)
7459
- }
7460
- }
7461
- if (!result.success) {
7462
- return handleUnsuccessfulApiResponse('getReport', result)
7463
- }
7464
-
7465
- // Conclude the status of the API call.
7466
- if (strict) {
7467
- if (result.data.healthy) {
7468
- spinner.success('Report result is healthy and great!')
7469
- } else {
7470
- spinner.error('Report result deemed unhealthy for project')
7471
- }
7472
- } else if (!result.data.healthy) {
7473
- const severityCount = shadowNpmInject.getSeverityCount(
7474
- result.data.issues,
7475
- includeAllIssues ? undefined : 'high'
7476
- )
7477
- const issueSummary = shadowNpmInject.formatSeverityCount(severityCount)
7478
- spinner.success(`Report has these issues: ${issueSummary}`)
7479
- } else {
7480
- spinner.success('Report has no issues')
7481
- }
7482
- spinner.stop()
7483
- return result.data
7484
- }
7485
-
7486
- function formatReportDataOutput(
7487
- reportId,
7488
- data,
7489
- commandName,
7490
- outputKind,
7491
- strict,
7492
- artifacts
7493
- ) {
7494
- if (outputKind === 'json') {
7495
- logger.logger.log(JSON.stringify(data, undefined, 2))
7496
- } else {
7497
- const format = new shadowNpmInject.ColorOrMarkdown(
7498
- outputKind === 'markdown'
7499
- )
7500
- logger.logger.log(commonTags.stripIndents`
7501
- Detailed info on socket.dev: ${format.hyperlink(reportId, data.url, {
7502
- fallbackToUrl: true
7503
- })}`)
7504
- if (outputKind === 'print') {
7505
- logger.logger.log(data)
7506
- logger.logger.log(
7507
- colors.dim(
7508
- `Or rerun ${colors.italic(commandName)} using the ${colors.italic('--json')} flag to get full JSON output`
7509
- )
7510
- )
7511
- logger.logger.log('The scan:')
7512
- logger.logger.log(artifacts)
7513
- }
7514
- }
7515
- if (strict && !data.healthy) {
7516
-
7517
- process$1.exit(1)
7518
- }
7519
- }
7520
-
7521
- async function fetchScan(orgSlug, scanId) {
7522
- const apiToken = shadowNpmInject.getDefaultToken()
7523
- if (!apiToken) {
7524
- throw new shadowNpmInject.AuthError(
7525
- 'User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.'
7526
- )
7527
- }
7528
-
7529
- // Lazily access constants.spinner.
7530
- const { spinner } = constants
7531
- spinner.start('Fetching scan data...')
7532
- const response = await queryApi(
7533
- `orgs/${orgSlug}/full-scans/${encodeURIComponent(scanId)}`,
7534
- apiToken
7535
- )
7536
- spinner.successAndStop('Received response while fetching scan data.')
7537
- if (!response.ok) {
7538
- const err = await handleApiError(response.status)
7539
- logger.logger.fail(
7540
- failMsgWithBadge(response.statusText, `Fetch error: ${err}`)
7541
- )
7542
- return
7543
- }
7544
-
7545
- // This is nd-json; each line is a json object
7546
- const jsons = await response.text()
7547
- const lines = jsons.split('\n').filter(Boolean)
7548
- const data = lines.map(line => {
7549
- try {
7550
- return JSON.parse(line)
7551
- } catch {
7552
- console.error(
7553
- 'At least one line item was returned that could not be parsed as JSON...'
7554
- )
7555
- return {}
7556
- }
7557
- })
7558
- return data
7559
- }
7560
-
7561
- async function viewReport(reportId, { all, commandName, outputKind, strict }) {
7562
- const result = await fetchReportData$1(reportId, all, strict)
7563
- const artifacts = await fetchScan('socketdev', reportId)
7564
- if (result) {
7565
- formatReportDataOutput(
7566
- reportId,
7567
- result,
7568
- commandName,
7569
- outputKind,
7570
- strict,
7571
- artifacts
7572
- )
7573
- }
7574
- }
7575
-
7576
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$e } = constants
7577
7647
  const config$e = {
7578
7648
  commandName: 'create',
7579
7649
  description: '[Deprecated] Create a project report',
@@ -7605,57 +7675,17 @@ const cmdReportCreate = {
7605
7675
  run: run$e
7606
7676
  }
7607
7677
  async function run$e(argv, importMeta, { parentName }) {
7608
- const cli = meowOrExit({
7678
+ meowOrExit({
7609
7679
  argv,
7610
7680
  config: config$e,
7611
7681
  importMeta,
7612
7682
  parentName
7613
7683
  })
7614
-
7615
- // TODO: Allow setting a custom cwd and/or configFile path?
7616
- const cwd = process.cwd()
7617
- const absoluteConfigPath = path$1.join(cwd, 'socket.yml')
7618
- const dryRun = Boolean(cli.flags['dryRun'])
7619
- const json = Boolean(cli.flags['json'])
7620
- const markdown = Boolean(cli.flags['markdown'])
7621
- const strict = Boolean(cli.flags['strict'])
7622
- const includeAllIssues = Boolean(cli.flags['all'])
7623
- const view = Boolean(cli.flags['view'])
7624
-
7625
- // Note exiting earlier to skirt a hidden auth requirement
7626
- if (cli.flags['dryRun']) {
7627
- logger.logger.log(DRY_RUN_BAIL_TEXT$e)
7628
- return
7629
- }
7630
- const socketConfig = await getSocketConfig(absoluteConfigPath)
7631
- const result = await createReport(socketConfig, cli.input, {
7632
- cwd,
7633
- dryRun
7634
- })
7635
- const commandName = `${parentName} ${config$e.commandName}`
7636
- if (result?.success) {
7637
- if (view) {
7638
- const reportId = result.data.id
7639
- await viewReport(reportId, {
7640
- all: includeAllIssues,
7641
- commandName,
7642
- outputKind: json ? 'json' : markdown ? 'markdown' : 'print',
7643
- strict
7644
- })
7645
- } else if (json) {
7646
- logger.logger.log(JSON.stringify(result.data, undefined, 2))
7647
- } else {
7648
- const format = new shadowNpmInject.ColorOrMarkdown(markdown)
7649
- logger.logger.log(
7650
- `New report: ${format.hyperlink(result.data.id, result.data.url, {
7651
- fallbackToUrl: true
7652
- })}`
7653
- )
7654
- }
7655
- }
7684
+ logger.logger.fail(
7685
+ 'This command has been sunset. Instead, please look at `socket scan create` to create scans and `socket scan report` to view a report of your scans.'
7686
+ )
7656
7687
  }
7657
7688
 
7658
- const { DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$d } = constants
7659
7689
  const config$d = {
7660
7690
  commandName: 'view',
7661
7691
  description: '[Deprecated] View a project report',
@@ -7676,49 +7706,15 @@ const cmdReportView = {
7676
7706
  run: run$d
7677
7707
  }
7678
7708
  async function run$d(argv, importMeta, { parentName }) {
7679
- const cli = meowOrExit({
7709
+ meowOrExit({
7680
7710
  argv,
7681
7711
  config: config$d,
7682
7712
  importMeta,
7683
7713
  parentName
7684
7714
  })
7685
- const { json, markdown } = cli.flags
7686
- const [reportId = '', ...extraInput] = cli.input
7687
- const wasBadInput = handleBadInput(
7688
- {
7689
- test: reportId,
7690
- message: 'Need at least one report ID',
7691
- pass: 'ok',
7692
- fail: 'missing'
7693
- },
7694
- {
7695
- nook: true,
7696
- test: extraInput.length === 0,
7697
- message: 'Can only handle a single report ID',
7698
- pass: 'ok',
7699
- fail: 'received ' + (extraInput.length + 1)
7700
- },
7701
- {
7702
- nook: true,
7703
- test: !json || !markdown,
7704
- message: 'The json and markdown flags cannot be both set, pick one',
7705
- pass: 'ok',
7706
- fail: 'omit one'
7707
- }
7715
+ logger.logger.fail(
7716
+ 'This command has been sunset. Instead, please look at `socket scan create` to create scans and `socket scan report` to view a report of your scans.'
7708
7717
  )
7709
- if (wasBadInput) {
7710
- return
7711
- }
7712
- if (cli.flags['dryRun']) {
7713
- logger.logger.log(DRY_RUN_BAIL_TEXT$d)
7714
- return
7715
- }
7716
- await viewReport(reportId, {
7717
- all: Boolean(cli.flags['all']),
7718
- commandName: `${parentName} ${config$d.commandName}`,
7719
- outputKind: json ? 'json' : markdown ? 'markdown' : 'print',
7720
- strict: Boolean(cli.flags['strict'])
7721
- })
7722
7718
  }
7723
7719
 
7724
7720
  const description$2 = '[Deprecated] Project report related commands'
@@ -7768,7 +7764,6 @@ async function fetchCreateRepo({
7768
7764
  spinner.successAndStop('Received response requesting to create a repository.')
7769
7765
  if (!result.success) {
7770
7766
  handleUnsuccessfulApiResponse('createOrgRepo', result)
7771
- return
7772
7767
  }
7773
7768
  return result.data
7774
7769
  }
@@ -7841,6 +7836,10 @@ const config$c = {
7841
7836
  Usage
7842
7837
  $ ${command} <org slug>
7843
7838
 
7839
+ API Token Requirements
7840
+ - Quota: 1 unit
7841
+ - Permissions: repo:create
7842
+
7844
7843
  Options
7845
7844
  ${getFlagListOutput(config.flags, 6)}
7846
7845
 
@@ -7916,7 +7915,6 @@ async function handleDeleteRepo(orgSlug, repoName) {
7916
7915
  )
7917
7916
  if (!result.success) {
7918
7917
  handleUnsuccessfulApiResponse('deleteOrgRepo', result)
7919
- return
7920
7918
  }
7921
7919
  spinner.successAndStop('Repository deleted successfully')
7922
7920
  }
@@ -7933,6 +7931,10 @@ const config$b = {
7933
7931
  Usage
7934
7932
  $ ${command} <org slug> <repo slug>
7935
7933
 
7934
+ API Token Requirements
7935
+ - Quota: 1 unit
7936
+ - Permissions: repo:delete
7937
+
7936
7938
  Options
7937
7939
  ${getFlagListOutput(config.flags, 6)}
7938
7940
 
@@ -8007,7 +8009,6 @@ async function fetchListRepos({ direction, orgSlug, page, per_page, sort }) {
8007
8009
  spinner.successAndStop('Received response for repository list.')
8008
8010
  if (!result.success) {
8009
8011
  handleUnsuccessfulApiResponse('getOrgRepoList', result)
8010
- return
8011
8012
  }
8012
8013
  return result.data
8013
8014
  }
@@ -8109,6 +8110,10 @@ const config$a = {
8109
8110
  Usage
8110
8111
  $ ${command} <org slug>
8111
8112
 
8113
+ API Token Requirements
8114
+ - Quota: 1 unit
8115
+ - Permissions: repo:list
8116
+
8112
8117
  Options
8113
8118
  ${getFlagListOutput(config.flags, 6)}
8114
8119
 
@@ -8201,7 +8206,6 @@ async function fetchUpdateRepo({
8201
8206
  spinner.successAndStop('Received response trying to update a repository')
8202
8207
  if (!result.success) {
8203
8208
  handleUnsuccessfulApiResponse('updateOrgRepo', result)
8204
- return
8205
8209
  }
8206
8210
  return result.data
8207
8211
  }
@@ -8274,6 +8278,10 @@ const config$9 = {
8274
8278
  Usage
8275
8279
  $ ${command} <org slug>
8276
8280
 
8281
+ API Token Requirements
8282
+ - Quota: 1 unit
8283
+ - Permissions: repo:update
8284
+
8277
8285
  Options
8278
8286
  ${getFlagListOutput(config.flags, 6)}
8279
8287
 
@@ -8350,7 +8358,6 @@ async function fetchViewRepo(orgSlug, repoName) {
8350
8358
  spinner.successAndStop('Received response while fetched repository data.')
8351
8359
  if (!result.success) {
8352
8360
  handleUnsuccessfulApiResponse('getOrgRepo', result)
8353
- return
8354
8361
  }
8355
8362
  return result.data
8356
8363
  }
@@ -8445,6 +8452,10 @@ const config$8 = {
8445
8452
  Usage
8446
8453
  $ ${command} <org slug>
8447
8454
 
8455
+ API Token Requirements
8456
+ - Quota: 1 unit
8457
+ - Permissions: repo:list
8458
+
8448
8459
  Options
8449
8460
  ${getFlagListOutput(config.flags, 6)}
8450
8461
 
@@ -8550,7 +8561,9 @@ async function fetchCreateOrgFullScan(
8550
8561
 
8551
8562
  // Lazily access constants.spinner.
8552
8563
  const { spinner } = constants
8553
- spinner.start(`Creating a scan with ${packagePaths.length} packages...`)
8564
+ spinner.start(
8565
+ `Sending request to create a scan with ${packagePaths.length} packages...`
8566
+ )
8554
8567
  const result = await handleApiCall(
8555
8568
  sockSdk.createOrgFullScan(
8556
8569
  orgSlug,
@@ -8567,10 +8580,9 @@ async function fetchCreateOrgFullScan(
8567
8580
  ),
8568
8581
  'Creating scan'
8569
8582
  )
8570
- spinner.successAndStop('Scan created successfully')
8583
+ spinner.successAndStop('Completed request to create a new scan.')
8571
8584
  if (!result.success) {
8572
8585
  handleUnsuccessfulApiResponse('CreateOrgFullScan', result)
8573
- return
8574
8586
  }
8575
8587
  return result.data
8576
8588
  }
@@ -8585,12 +8597,12 @@ async function fetchSupportedScanFileNames() {
8585
8597
  sockSdk.getReportSupportedFiles(),
8586
8598
  'fetching supported scan file types'
8587
8599
  )
8588
- spinner.successAndStop(
8600
+ spinner.stop()
8601
+ logger.logger.success(
8589
8602
  'Received response while fetched supported scan file types.'
8590
8603
  )
8591
8604
  if (!result.success) {
8592
8605
  handleUnsuccessfulApiResponse('getReportSupportedFiles', result)
8593
- return
8594
8606
  }
8595
8607
  return result.data
8596
8608
  }
@@ -8628,7 +8640,6 @@ async function handleCreateNewScan({
8628
8640
  cwd,
8629
8641
  targets,
8630
8642
  supportedFileNames
8631
- // socketConfig
8632
8643
  )
8633
8644
  handleBadInput({
8634
8645
  nook: true,
@@ -8692,7 +8703,7 @@ async function suggestOrgSlug() {
8692
8703
  }
8693
8704
  } else {
8694
8705
  logger.logger.fail(
8695
- 'Failed to lookup organization list from API, unable to suggest.'
8706
+ 'Failed to lookup organization list from API, unable to suggest'
8696
8707
  )
8697
8708
  }
8698
8709
  }
@@ -8947,6 +8958,10 @@ const config$7 = {
8947
8958
  Usage
8948
8959
  $ ${command} [...options] <org> <TARGET> [TARGET...]
8949
8960
 
8961
+ API Token Requirements
8962
+ - Quota: 1 unit
8963
+ - Permissions: full-scans:create
8964
+
8950
8965
  Uploads the specified "package.json" and lock files for JavaScript, Python,
8951
8966
  Go, Scala, Gradle, and Kotlin dependency manifests.
8952
8967
  If any folder is specified, the ones found in there recursively are uploaded.
@@ -8988,7 +9003,7 @@ async function run$7(argv, importMeta, { parentName }) {
8988
9003
  cwdOverride && cwdOverride !== 'process.cwd()'
8989
9004
  ? String(cwdOverride)
8990
9005
  : process.cwd()
8991
- let { branch: branchName, repo: repoName } = cli.flags
9006
+ let { branch: branchName = '', repo: repoName = '' } = cli.flags
8992
9007
 
8993
9008
  // We're going to need an api token to suggest data because those suggestions
8994
9009
  // must come from data we already know. Don't error on missing api token yet.
@@ -9116,7 +9131,6 @@ async function fetchDeleteOrgFullScan(orgSlug, scanId) {
9116
9131
  spinner.successAndStop('Received response for deleting a scan.')
9117
9132
  if (!result.success) {
9118
9133
  handleUnsuccessfulApiResponse('deleteOrgFullScan', result)
9119
- return
9120
9134
  }
9121
9135
  return result.data
9122
9136
  }
@@ -9146,6 +9160,10 @@ const config$6 = {
9146
9160
  Usage
9147
9161
  $ ${command} <org slug> <scan ID>
9148
9162
 
9163
+ API Token Requirements
9164
+ - Quota: 1 unit
9165
+ - Permissions: full-scans:delete
9166
+
9149
9167
  Options
9150
9168
  ${getFlagListOutput(config.flags, 6)}
9151
9169
 
@@ -9228,7 +9246,6 @@ async function fetchListScans({
9228
9246
  spinner.successAndStop(`Received response for list of scans.`)
9229
9247
  if (!result.success) {
9230
9248
  handleUnsuccessfulApiResponse('getOrgFullScanList', result)
9231
- return
9232
9249
  }
9233
9250
  return result.data
9234
9251
  }
@@ -9349,6 +9366,10 @@ const config$5 = {
9349
9366
  Usage
9350
9367
  $ ${command} <org slug>
9351
9368
 
9369
+ API Token Requirements
9370
+ - Quota: 1 unit
9371
+ - Permissions: full-scans:list
9372
+
9352
9373
  Options
9353
9374
  ${getFlagListOutput(config.flags, 6)}
9354
9375
 
@@ -9427,7 +9448,6 @@ async function fetchScanMetadata(orgSlug, scanId) {
9427
9448
  spinner.successAndStop('Received response for scan meta data.')
9428
9449
  if (!result.success) {
9429
9450
  handleUnsuccessfulApiResponse('getOrgFullScanMetadata', result)
9430
- return
9431
9451
  }
9432
9452
  return result.data
9433
9453
  }
@@ -9489,6 +9509,10 @@ const config$4 = {
9489
9509
  Usage
9490
9510
  $ ${command} <org slug> <scan id>
9491
9511
 
9512
+ API Token Requirements
9513
+ - Quota: 1 unit
9514
+ - Permissions: full-scans:list
9515
+
9492
9516
  Options
9493
9517
  ${getFlagListOutput(config.flags, 6)}
9494
9518
 
@@ -9560,14 +9584,8 @@ async function run$4(argv, importMeta, { parentName }) {
9560
9584
  /**
9561
9585
  * This fetches all the relevant pieces of data to generate a report, given a
9562
9586
  * full scan ID.
9563
- * It can optionally only fetch the security or license side of things.
9564
9587
  */
9565
- async function fetchReportData(
9566
- orgSlug,
9567
- scanId,
9568
- // includeLicensePolicy: boolean,
9569
- includeSecurityPolicy
9570
- ) {
9588
+ async function fetchReportData(orgSlug, scanId, includeLicensePolicy) {
9571
9589
  const apiToken = shadowNpmInject.getDefaultToken()
9572
9590
  if (!apiToken) {
9573
9591
  throw new shadowNpmInject.AuthError(
@@ -9576,7 +9594,6 @@ async function fetchReportData(
9576
9594
  }
9577
9595
  const sockSdk = await shadowNpmInject.setupSdk(apiToken)
9578
9596
  let haveScan = false
9579
- // let haveLicensePolicy = false
9580
9597
  let haveSecurityPolicy = false
9581
9598
 
9582
9599
  // Lazily access constants.spinner.
@@ -9584,48 +9601,26 @@ async function fetchReportData(
9584
9601
  function updateProgress() {
9585
9602
  const needs = [
9586
9603
  !haveScan ? 'scan' : undefined,
9587
- // includeLicensePolicy && !haveLicensePolicy ? 'license policy' : undefined,
9588
- includeSecurityPolicy && !haveSecurityPolicy
9589
- ? 'security policy'
9590
- : undefined
9604
+ !haveSecurityPolicy ? 'security policy' : undefined
9591
9605
  ].filter(Boolean)
9592
- if (needs.length > 2) {
9593
- // .toOxford()
9594
- needs[needs.length - 1] = `and ${needs[needs.length - 1]}`
9595
- }
9596
9606
  const haves = [
9597
9607
  haveScan ? 'scan' : undefined,
9598
- // includeLicensePolicy && haveLicensePolicy ? 'license policy' : undefined,
9599
- includeSecurityPolicy && haveSecurityPolicy
9600
- ? 'security policy'
9601
- : undefined
9608
+ haveSecurityPolicy ? 'security policy' : undefined
9602
9609
  ].filter(Boolean)
9603
- if (haves.length > 2) {
9604
- // .toOxford()
9605
- haves[haves.length - 1] = `and ${haves[haves.length - 1]}`
9606
- }
9607
9610
  if (needs.length) {
9608
9611
  spinner.start(
9609
- `Fetching ${needs.join(needs.length > 2 ? ', ' : ' and ')}...${haves.length ? ` Completed fetching ${haves.join(haves.length > 2 ? ', ' : ' and ')}.` : ''}`
9612
+ `Fetching ${needs.join(' and ')}...${haves.length ? ` Completed fetching ${haves.join(' and ')}.` : ''}`
9610
9613
  )
9611
9614
  } else {
9612
- spinner.successAndStop(
9613
- `Completed fetching ${haves.join(haves.length > 2 ? ', ' : ' and ')}.`
9614
- )
9615
+ spinner.successAndStop(`Completed fetching ${haves.join(' and ')}.`)
9615
9616
  }
9616
9617
  }
9617
9618
  updateProgress()
9618
-
9619
- // @ts-ignore
9620
- const [
9621
- scan,
9622
- // licensePolicyMaybe,
9623
- securityPolicyMaybe
9624
- ] = await Promise.all([
9619
+ const [scan, securityPolicyMaybe] = await Promise.all([
9625
9620
  (async () => {
9626
9621
  try {
9627
9622
  const response = await queryApi(
9628
- `orgs/${orgSlug}/full-scans/${encodeURIComponent(scanId)}`,
9623
+ `orgs/${orgSlug}/full-scans/${encodeURIComponent(scanId)}${includeLicensePolicy ? '?include_license_details=true' : ''}`,
9629
9624
  apiToken
9630
9625
  )
9631
9626
  haveScan = true
@@ -9651,32 +9646,16 @@ async function fetchReportData(
9651
9646
  })
9652
9647
  return data
9653
9648
  } catch (e) {
9654
- spinner.errorAndStop(
9655
- 'There was an issue while fetching full scan data.'
9656
- )
9649
+ spinner.errorAndStop('There was an issue while fetching full scan data')
9657
9650
  throw e
9658
9651
  }
9659
9652
  })(),
9660
- // includeLicensePolicy &&
9661
- // (async () => {
9662
- // const r = await sockSdk.getOrgSecurityPolicy(orgSlug)
9663
- // haveLicensePolicy = true
9664
- // updateProgress()
9665
- // return await handleApiCall(
9666
- // r,
9667
- // "looking up organization's license policy"
9668
- // )
9669
- // })(),
9670
- includeSecurityPolicy &&
9671
- (async () => {
9672
- const r = await sockSdk.getOrgSecurityPolicy(orgSlug)
9673
- haveSecurityPolicy = true
9674
- updateProgress()
9675
- return await handleApiCall(
9676
- r,
9677
- "looking up organization's security policy"
9678
- )
9679
- })()
9653
+ (async () => {
9654
+ const r = await sockSdk.getOrgSecurityPolicy(orgSlug)
9655
+ haveSecurityPolicy = true
9656
+ updateProgress()
9657
+ return await handleApiCall(r, "looking up organization's security policy")
9658
+ })()
9680
9659
  ]).finally(() => spinner.stop())
9681
9660
  if (!Array.isArray(scan)) {
9682
9661
  logger.logger.error('Was unable to fetch scan, bailing')
@@ -9684,55 +9663,30 @@ async function fetchReportData(
9684
9663
  return {
9685
9664
  ok: false,
9686
9665
  scan: undefined,
9687
- // licensePolicy: undefined,
9688
9666
  securityPolicy: undefined
9689
9667
  }
9690
9668
  }
9691
-
9692
- // // Note: security->license once the api ships in the sdk
9693
- // let licensePolicy: undefined | SocketSdkReturnType<'getOrgSecurityPolicy'> =
9694
- // undefined
9695
- // if (includeLicensePolicy) {
9696
- // if (licensePolicyMaybe && licensePolicyMaybe.success) {
9697
- // licensePolicy = licensePolicyMaybe
9698
- // } else {
9699
- // logger.error('Was unable to fetch license policy, bailing')
9700
- // process.exitCode = 1
9701
- // return {
9702
- // ok: false,
9703
- // scan: undefined,
9704
- // licensePolicy: undefined,
9705
- // securityPolicy: undefined
9706
- // }
9707
- // }
9708
- // }
9709
-
9710
9669
  let securityPolicy = undefined
9711
- if (includeSecurityPolicy) {
9712
- if (securityPolicyMaybe && securityPolicyMaybe.success) {
9713
- securityPolicy = securityPolicyMaybe
9714
- } else {
9715
- logger.logger.error('Was unable to fetch security policy, bailing')
9716
- process.exitCode = 1
9717
- return {
9718
- ok: false,
9719
- scan: undefined,
9720
- // licensePolicy: undefined,
9721
- securityPolicy: undefined
9722
- }
9670
+ if (securityPolicyMaybe && securityPolicyMaybe.success) {
9671
+ securityPolicy = securityPolicyMaybe
9672
+ } else {
9673
+ logger.logger.error('Was unable to fetch security policy, bailing')
9674
+ process.exitCode = 1
9675
+ return {
9676
+ ok: false,
9677
+ scan: undefined,
9678
+ securityPolicy: undefined
9723
9679
  }
9724
9680
  }
9725
9681
  return {
9726
9682
  ok: true,
9727
9683
  scan,
9728
- // licensePolicy,
9729
9684
  securityPolicy
9730
9685
  }
9731
9686
  }
9732
9687
 
9733
9688
  function generateReport(
9734
9689
  scan,
9735
- _licensePolicy,
9736
9690
  securityPolicy,
9737
9691
  { fold, orgSlug, reportLevel, scanId, short, spinner }
9738
9692
  ) {
@@ -9758,6 +9712,14 @@ function generateReport(
9758
9712
  // - monitor/ignore: no action
9759
9713
  // - defer: unknown (no action)
9760
9714
 
9715
+ // Note: the server will emit alerts for license policy violations but
9716
+ // those are only included if you set the flag when requesting the scan
9717
+ // data. The alerts map to a single security policy key that determines
9718
+ // what to do with any violation, regardless of the concrete license.
9719
+ // That rule is called "License Policy Violation".
9720
+ // The license policy part is implicitly handled here. Either they are
9721
+ // included and may show up, or they are not and won't show up.
9722
+
9761
9723
  const violations = new Map()
9762
9724
  let healthy = true
9763
9725
  const securityRules = securityPolicy?.data.securityPolicyRules
@@ -10004,13 +9966,11 @@ function* walkNestedMap(map, keys = []) {
10004
9966
 
10005
9967
  async function outputScanReport(
10006
9968
  scan,
10007
- // licensePolicy: undefined | SocketSdkReturnType<'getOrgSecurityPolicy'>,
10008
9969
  securityPolicy,
10009
9970
  {
10010
9971
  filePath,
10011
9972
  fold,
10012
9973
  includeLicensePolicy,
10013
- includeSecurityPolicy,
10014
9974
  orgSlug,
10015
9975
  outputKind,
10016
9976
  reportLevel,
@@ -10018,25 +9978,15 @@ async function outputScanReport(
10018
9978
  short
10019
9979
  }
10020
9980
  ) {
10021
- if (!includeSecurityPolicy) {
10022
- process.exitCode = 1
10023
- return // caller should assert
10024
- }
10025
- const scanReport = generateReport(
10026
- scan,
10027
- undefined,
10028
- // licensePolicy,
10029
- securityPolicy,
10030
- {
10031
- orgSlug,
10032
- scanId,
10033
- fold,
10034
- reportLevel,
10035
- short,
10036
- // Lazily access constants.spinner.
10037
- spinner: constants.spinner
10038
- }
10039
- )
9981
+ const scanReport = generateReport(scan, securityPolicy, {
9982
+ orgSlug,
9983
+ scanId,
9984
+ fold,
9985
+ reportLevel,
9986
+ short,
9987
+ // Lazily access constants.spinner.
9988
+ spinner: constants.spinner
9989
+ })
10040
9990
  if (!scanReport.healthy) {
10041
9991
  process.exitCode = 1
10042
9992
  }
@@ -10044,7 +9994,9 @@ async function outputScanReport(
10044
9994
  outputKind === 'json' ||
10045
9995
  (outputKind === 'text' && filePath && filePath.endsWith('.json'))
10046
9996
  ) {
10047
- const json = short ? JSON.stringify(scanReport) : toJsonReport(scanReport)
9997
+ const json = short
9998
+ ? JSON.stringify(scanReport)
9999
+ : toJsonReport(scanReport, includeLicensePolicy)
10048
10000
  if (filePath !== '-') {
10049
10001
  logger.logger.log('Writing json report to', filePath)
10050
10002
  return await fs.writeFile(filePath, json)
@@ -10055,7 +10007,7 @@ async function outputScanReport(
10055
10007
  if (outputKind === 'markdown' || filePath.endsWith('.md')) {
10056
10008
  const md = short
10057
10009
  ? `healthy = ${scanReport.healthy}`
10058
- : toMarkdownReport(scanReport)
10010
+ : toMarkdownReport(scanReport, includeLicensePolicy)
10059
10011
  if (filePath !== '-') {
10060
10012
  logger.logger.log('Writing markdown report to', filePath)
10061
10013
  return await fs.writeFile(filePath, md)
@@ -10071,10 +10023,11 @@ async function outputScanReport(
10071
10023
  })
10072
10024
  }
10073
10025
  }
10074
- function toJsonReport(report) {
10026
+ function toJsonReport(report, includeLicensePolicy) {
10075
10027
  const obj = mapToObject(report.alerts)
10076
10028
  const json = JSON.stringify(
10077
10029
  {
10030
+ includeLicensePolicy,
10078
10031
  ...report,
10079
10032
  alerts: obj
10080
10033
  },
@@ -10083,7 +10036,7 @@ function toJsonReport(report) {
10083
10036
  )
10084
10037
  return json
10085
10038
  }
10086
- function toMarkdownReport(report) {
10039
+ function toMarkdownReport(report, includeLicensePolicy) {
10087
10040
  const flatData = Array.from(walkNestedMap(report.alerts)).map(
10088
10041
  ({ keys, value }) => {
10089
10042
  const { manifest, policy, type, url } = value
@@ -10102,11 +10055,11 @@ function toMarkdownReport(report) {
10102
10055
  # Scan Policy Report
10103
10056
 
10104
10057
  This report tells you whether the results of a Socket scan results violate the
10105
- security or license policy set by your organization.
10058
+ security${includeLicensePolicy ? ' or license' : ''} policy set by your organization.
10106
10059
 
10107
10060
  ## Health status
10108
10061
 
10109
- ${report.healthy ? 'The scan *PASSES* all requirements set by your security and license policy.' : 'The scan *VIOLATES* one or more policies set to the "error" level.'}
10062
+ ${report.healthy ? `The scan *PASSES* all requirements set by your security${includeLicensePolicy ? ' and license' : ''} policy.` : 'The scan *VIOLATES* one or more policies set to the "error" level.'}
10110
10063
 
10111
10064
  ## Settings
10112
10065
 
@@ -10116,6 +10069,7 @@ Configuration used to generate this report:
10116
10069
  - Scan ID: ${report.scanId}
10117
10070
  - Alert folding: ${report.options.fold === 'none' ? 'none' : `up to ${report.options.fold}`}
10118
10071
  - Minimal policy level for alert to be included in report: ${report.options.reportLevel === 'defer' ? 'everything' : report.options.reportLevel}
10072
+ - Include license alerts: ${includeLicensePolicy ? 'yes' : 'no'}
10119
10073
 
10120
10074
  ## Alerts
10121
10075
 
@@ -10130,27 +10084,16 @@ async function handleScanReport({
10130
10084
  filePath,
10131
10085
  fold,
10132
10086
  includeLicensePolicy,
10133
- includeSecurityPolicy,
10134
10087
  orgSlug,
10135
10088
  outputKind,
10136
10089
  reportLevel,
10137
10090
  scanId,
10138
10091
  short
10139
10092
  }) {
10140
- if (!includeSecurityPolicy) {
10141
- process.exitCode = 1
10142
- return // caller should assert
10143
- }
10144
- const {
10145
- // licensePolicy,
10146
- ok,
10147
- scan,
10148
- securityPolicy
10149
- } = await fetchReportData(
10093
+ const { ok, scan, securityPolicy } = await fetchReportData(
10150
10094
  orgSlug,
10151
10095
  scanId,
10152
- // includeLicensePolicy
10153
- includeSecurityPolicy
10096
+ includeLicensePolicy
10154
10097
  )
10155
10098
  if (!ok) {
10156
10099
  return
@@ -10160,7 +10103,6 @@ async function handleScanReport({
10160
10103
  fold,
10161
10104
  scanId: scanId,
10162
10105
  includeLicensePolicy,
10163
- includeSecurityPolicy,
10164
10106
  orgSlug,
10165
10107
  outputKind,
10166
10108
  reportLevel,
@@ -10173,8 +10115,7 @@ const config$3 = {
10173
10115
  commandName: 'report',
10174
10116
  description:
10175
10117
  'Check whether a scan result passes the organizational policies (security, license)',
10176
- hidden: true,
10177
- // [beta]
10118
+ hidden: false,
10178
10119
  flags: {
10179
10120
  ...commonFlags,
10180
10121
  ...outputFlags,
@@ -10193,31 +10134,23 @@ const config$3 = {
10193
10134
  default: false,
10194
10135
  description: 'Report only the healthy status'
10195
10136
  },
10196
- // license: {
10197
- // type: 'boolean',
10198
- // default: true,
10199
- // description: 'Report the license policy status. Default: true'
10200
- // },
10201
- security: {
10137
+ license: {
10202
10138
  type: 'boolean',
10203
- default: true,
10204
- description: 'Report the security policy status. Default: true'
10139
+ default: false,
10140
+ description: 'Also report the license policy status. Default: false'
10205
10141
  }
10206
10142
  },
10207
10143
  help: (command, config) => `
10208
10144
  Usage
10209
10145
  $ ${command} <org slug> <scan ID> [path to output file]
10210
10146
 
10147
+ API Token Requirements
10148
+ - Quota: 2 units
10149
+ - Permissions: full-scans:list security-policy:read
10150
+
10211
10151
  Options
10212
10152
  ${getFlagListOutput(config.flags, 6)}
10213
10153
 
10214
- This consumes 1 quota unit plus 1 for each of the requested policy types.
10215
-
10216
- Note: By default it reports both so by default it consumes 3 quota units.
10217
-
10218
- Your API token will need the \`full-scans:list\` scope regardless. Additionally
10219
- it needs \`security-policy:read\` to report on the security policy.
10220
-
10221
10154
  By default the result is a nested object that looks like this:
10222
10155
  \`{[ecosystem]: {[pkgName]: {[version]: {[file]: {[type:loc]: policy}}}}\`
10223
10156
  You can fold this up to given level: 'pkg', 'version', 'file', and 'none'.
@@ -10229,6 +10162,7 @@ const config$3 = {
10229
10162
 
10230
10163
  Examples
10231
10164
  $ ${command} FakeOrg 000aaaa1-0000-0a0a-00a0-00a0000000a0 --json --fold=version
10165
+ $ ${command} FakeOrg 000aaaa1-0000-0a0a-00a0-00a0000000a0 --license --markdown --short
10232
10166
  `
10233
10167
  }
10234
10168
  const cmdScanReport = {
@@ -10246,10 +10180,9 @@ async function run$3(argv, importMeta, { parentName }) {
10246
10180
  const {
10247
10181
  fold = 'none',
10248
10182
  json,
10249
- // license,
10183
+ license,
10250
10184
  markdown,
10251
- reportLevel = 'warn',
10252
- security
10185
+ reportLevel = 'warn'
10253
10186
  } = cli.flags
10254
10187
  const defaultOrgSlug = shadowNpmInject.getConfigValue('defaultOrg')
10255
10188
  const orgSlug = defaultOrgSlug || cli.input[0] || ''
@@ -10296,9 +10229,7 @@ async function run$3(argv, importMeta, { parentName }) {
10296
10229
  await handleScanReport({
10297
10230
  orgSlug,
10298
10231
  scanId: scanId,
10299
- includeLicensePolicy: false,
10300
- // !!license,
10301
- includeSecurityPolicy: typeof security === 'boolean' ? security : true,
10232
+ includeLicensePolicy: !!license,
10302
10233
  outputKind: json ? 'json' : markdown ? 'markdown' : 'text',
10303
10234
  filePath: file,
10304
10235
  fold: fold,
@@ -10307,6 +10238,46 @@ async function run$3(argv, importMeta, { parentName }) {
10307
10238
  })
10308
10239
  }
10309
10240
 
10241
+ async function fetchScan(orgSlug, scanId) {
10242
+ const apiToken = shadowNpmInject.getDefaultToken()
10243
+ if (!apiToken) {
10244
+ throw new shadowNpmInject.AuthError(
10245
+ 'User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.'
10246
+ )
10247
+ }
10248
+
10249
+ // Lazily access constants.spinner.
10250
+ const { spinner } = constants
10251
+ spinner.start('Fetching scan data...')
10252
+ const response = await queryApi(
10253
+ `orgs/${orgSlug}/full-scans/${encodeURIComponent(scanId)}`,
10254
+ apiToken
10255
+ )
10256
+ spinner.successAndStop('Received response while fetching scan data.')
10257
+ if (!response.ok) {
10258
+ const err = await handleApiError(response.status)
10259
+ logger.logger.fail(
10260
+ failMsgWithBadge(response.statusText, `Fetch error: ${err}`)
10261
+ )
10262
+ return
10263
+ }
10264
+
10265
+ // This is nd-json; each line is a json object
10266
+ const jsons = await response.text()
10267
+ const lines = jsons.split('\n').filter(Boolean)
10268
+ const data = lines.map(line => {
10269
+ try {
10270
+ return JSON.parse(line)
10271
+ } catch {
10272
+ console.error(
10273
+ 'At least one line item was returned that could not be parsed as JSON...'
10274
+ )
10275
+ return {}
10276
+ }
10277
+ })
10278
+ return data
10279
+ }
10280
+
10310
10281
  async function outputScanView(artifacts, orgSlug, scanId, filePath) {
10311
10282
  const display = artifacts.map(art => {
10312
10283
  const author = Array.isArray(art.author)
@@ -10367,7 +10338,6 @@ async function streamScan(orgSlug, scanId, file) {
10367
10338
  spinner.successAndStop(`Full scan details written to ${file}`)
10368
10339
  if (!data?.success) {
10369
10340
  handleUnsuccessfulApiResponse('getOrgFullScan', data)
10370
- return
10371
10341
  }
10372
10342
  return data
10373
10343
  }
@@ -10385,6 +10355,10 @@ const config$2 = {
10385
10355
  Usage
10386
10356
  $ ${command} <org slug> <scan ID> [path to output file]
10387
10357
 
10358
+ API Token Requirements
10359
+ - Quota: 1 unit
10360
+ - Permissions: full-scans:list
10361
+
10388
10362
  When no output path is given the contents is sent to stdout.
10389
10363
 
10390
10364
  Options
@@ -10734,6 +10708,11 @@ const config$1 = {
10734
10708
  Usage
10735
10709
  $ ${command}
10736
10710
 
10711
+ API Token Requirements
10712
+ - Quota: 1 unit
10713
+ - Permissions: threat-feed:list
10714
+ - Special access
10715
+
10737
10716
  This feature requires a Threat Feed license. Please contact
10738
10717
  sales@socket.dev if you are interested in purchasing this access.
10739
10718
 
@@ -10852,7 +10831,7 @@ function checkSocketWrapperSetup(file) {
10852
10831
  )
10853
10832
  if (linesWithSocketAlias.length) {
10854
10833
  logger.logger.log(
10855
- `The Socket npm/npx wrapper is set up in your bash profile (${file}).`
10834
+ `The Socket npm/npx wrapper is set up in your bash profile (${file})`
10856
10835
  )
10857
10836
  return true
10858
10837
  }
@@ -11034,7 +11013,7 @@ void (async () => {
11034
11013
  await vendor.updater({
11035
11014
  name: SOCKET_CLI_BIN_NAME,
11036
11015
  // The '@rollup/plugin-replace' will replace "process.env['INLINED_SOCKET_CLI_VERSION']".
11037
- version: '0.14.68',
11016
+ version: '0.14.70',
11038
11017
  ttl: 86_400_000 /* 24 hours in milliseconds */
11039
11018
  })
11040
11019
  try {
@@ -11105,5 +11084,5 @@ void (async () => {
11105
11084
  await shadowNpmInject.captureException(e)
11106
11085
  }
11107
11086
  })()
11108
- //# debugId=fc908e09-aa24-49c9-8845-925a3bdb637b
11087
+ //# debugId=ac285c1d-4a7f-4a16-9e7c-31e9cf627038
11109
11088
  //# sourceMappingURL=cli.js.map