@socketsecurity/cli 0.11.0 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +22 -22
  2. package/bin/npm +2 -0
  3. package/bin/npx +2 -0
  4. package/dist/cli.d.ts +3 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +3419 -0
  7. package/dist/errors.d.ts +7 -0
  8. package/dist/link.d.ts +2 -0
  9. package/dist/link.js +45 -0
  10. package/dist/npm-cli.d.ts +2 -0
  11. package/dist/npm-cli.js +84 -0
  12. package/dist/npm-injection.d.ts +1 -0
  13. package/dist/npm-injection.js +913 -0
  14. package/dist/npm-injection2.d.ts +25 -0
  15. package/dist/npm-injection2.js +899 -0
  16. package/dist/npx-cli.d.ts +2 -0
  17. package/dist/npx-cli.js +60 -0
  18. package/dist/path-resolve.d.ts +12 -0
  19. package/dist/path-resolve.js +139 -0
  20. package/dist/sdk.d.ts +27 -0
  21. package/dist/sdk.js +224 -0
  22. package/dist/settings.d.ts +9 -0
  23. package/dist/type-helpers.d.ts +3 -0
  24. package/dist/vendor.js +25421 -0
  25. package/package.json +105 -52
  26. package/{lib/shadow/translations.json → translations.json} +20 -20
  27. package/cli.js +0 -72
  28. package/lib/commands/audit-log/index.js +0 -162
  29. package/lib/commands/cdxgen/index.js +0 -211
  30. package/lib/commands/dependencies/index.js +0 -150
  31. package/lib/commands/index.js +0 -15
  32. package/lib/commands/info/index.js +0 -287
  33. package/lib/commands/login/index.js +0 -170
  34. package/lib/commands/logout/index.js +0 -35
  35. package/lib/commands/npm/index.js +0 -27
  36. package/lib/commands/npx/index.js +0 -22
  37. package/lib/commands/organizations/index.js +0 -81
  38. package/lib/commands/raw-npm/index.js +0 -59
  39. package/lib/commands/raw-npx/index.js +0 -59
  40. package/lib/commands/report/create.js +0 -251
  41. package/lib/commands/report/index.js +0 -24
  42. package/lib/commands/report/view.js +0 -176
  43. package/lib/commands/repos/create.js +0 -166
  44. package/lib/commands/repos/delete.js +0 -93
  45. package/lib/commands/repos/index.js +0 -30
  46. package/lib/commands/repos/list.js +0 -170
  47. package/lib/commands/repos/update.js +0 -166
  48. package/lib/commands/repos/view.js +0 -128
  49. package/lib/commands/scan/create.js +0 -245
  50. package/lib/commands/scan/delete.js +0 -112
  51. package/lib/commands/scan/index.js +0 -30
  52. package/lib/commands/scan/list.js +0 -192
  53. package/lib/commands/scan/metadata.js +0 -113
  54. package/lib/commands/scan/stream.js +0 -115
  55. package/lib/commands/wrapper/index.js +0 -199
  56. package/lib/flags/command.js +0 -14
  57. package/lib/flags/index.js +0 -3
  58. package/lib/flags/output.js +0 -16
  59. package/lib/flags/validation.js +0 -14
  60. package/lib/shadow/bin/npm +0 -2
  61. package/lib/shadow/bin/npx +0 -2
  62. package/lib/shadow/link.cjs +0 -50
  63. package/lib/shadow/npm-cli.cjs +0 -27
  64. package/lib/shadow/npm-injection.cjs +0 -649
  65. package/lib/shadow/npx-cli.cjs +0 -27
  66. package/lib/shadow/package.json +0 -3
  67. package/lib/shadow/tty-server.cjs +0 -222
  68. package/lib/shadow/update-notifier.mjs +0 -3
  69. package/lib/utils/api-helpers.js +0 -42
  70. package/lib/utils/chalk-markdown.js +0 -125
  71. package/lib/utils/errors.js +0 -14
  72. package/lib/utils/flags.js +0 -27
  73. package/lib/utils/format-issues.js +0 -99
  74. package/lib/utils/formatting.js +0 -47
  75. package/lib/utils/issue-rules.cjs +0 -180
  76. package/lib/utils/meow-with-subcommands.js +0 -87
  77. package/lib/utils/misc.js +0 -61
  78. package/lib/utils/path-resolve.js +0 -204
  79. package/lib/utils/sdk.js +0 -99
  80. package/lib/utils/settings.js +0 -69
  81. package/lib/utils/type-helpers.cjs +0 -13
  82. package/lib/utils/update-notifier.js +0 -18
@@ -1,211 +0,0 @@
1
- /* eslint-disable no-console */
2
-
3
- import { existsSync, promises as fs } from 'node:fs'
4
- import path from 'node:path'
5
- import { fileURLToPath } from 'node:url'
6
-
7
- import chalk from 'chalk'
8
- import { $ } from 'execa'
9
- import yargsParse from 'yargs-parser'
10
-
11
- const __dirname = path.dirname(fileURLToPath(import.meta.url))
12
-
13
- const {
14
- SBOM_SIGN_ALGORITHM, // Algorithm. Example: RS512
15
- SBOM_SIGN_PRIVATE_KEY, // Location to the RSA private key
16
- SBOM_SIGN_PUBLIC_KEY // Optional. Location to the RSA public key
17
- } = process.env
18
-
19
- const toLower = (/** @type {string} */ arg) => arg.toLowerCase()
20
- const arrayToLower = (/** @type {string[]} */ arg) => arg.map(toLower)
21
-
22
- const execaConfig = {
23
- env: { NODE_ENV: '' },
24
- localDir: path.join(__dirname, 'node_modules'),
25
- }
26
-
27
- const nodejsPlatformTypes = [
28
- 'javascript',
29
- 'js',
30
- 'nodejs',
31
- 'npm',
32
- 'pnpm',
33
- 'ts',
34
- 'tsx',
35
- 'typescript'
36
- ]
37
-
38
- const yargsConfig = {
39
- configuration: {
40
- 'camel-case-expansion': false,
41
- 'strip-aliased': true,
42
- 'parse-numbers': false,
43
- 'populate--': true,
44
- 'unknown-options-as-args': true
45
- },
46
- coerce: {
47
- author: arrayToLower,
48
- filter: arrayToLower,
49
- only: arrayToLower,
50
- profile: toLower,
51
- standard: arrayToLower,
52
- type: toLower
53
- },
54
- default: {
55
- //author: ['OWASP Foundation'],
56
- //'auto-compositions': true,
57
- //babel: true,
58
- //evidence: false,
59
- //'include-crypto': false,
60
- //'include-formulation': false,
61
- //'install-deps': true,
62
- //output: 'bom.json',
63
- //profile: 'generic',
64
- //'project-version': '',
65
- //recurse: true,
66
- //'server-host': '127.0.0.1',
67
- //'server-port': '9090',
68
- //'spec-version': '1.5',
69
- type: 'js',
70
- //validate: true,
71
- },
72
- alias: {
73
- help: ['h'],
74
- output: ['o'],
75
- print: ['p'],
76
- recurse: ['r'],
77
- 'resolve-class': ['c'],
78
- type: ['t'],
79
- version: ['v'],
80
- },
81
- array: [
82
- { key: 'author', type: 'string' },
83
- { key: 'exclude', type: 'string' },
84
- { key: 'filter', type: 'string' },
85
- { key: 'only', type: 'string' },
86
- { key: 'standard', type: 'string' }
87
- ],
88
- boolean: [
89
- 'auto-compositions',
90
- 'babel',
91
- 'deep',
92
- 'evidence',
93
- 'fail-on-error',
94
- 'generate-key-and-sign',
95
- 'help',
96
- 'include-formulation',
97
- 'include-crypto',
98
- 'install-deps',
99
- 'print',
100
- 'required-only',
101
- 'server',
102
- 'validate',
103
- 'version',
104
- ],
105
- string: [
106
- 'api-key',
107
- 'output',
108
- 'parent-project-id',
109
- 'profile',
110
- 'project-group',
111
- 'project-name',
112
- 'project-version',
113
- 'project-id',
114
- 'server-host',
115
- 'server-port',
116
- 'server-url',
117
- 'spec-version',
118
- ]
119
- }
120
-
121
- /**
122
- *
123
- * @param {{ [key: string]: boolean | null | number | string | (string | number)[]}} argv
124
- * @returns {string[]}
125
- */
126
- function argvToArray (/** @type {any} */ argv) {
127
- if (argv['help']) return ['--help']
128
- const result = []
129
- for (const { 0: key, 1: value } of Object.entries(argv)) {
130
- if (key === '_' || key === '--') continue
131
- if (key === 'babel' || key === 'install-deps' || key === 'validate') {
132
- // cdxgen documents no-babel, no-install-deps, and no-validate flags so
133
- // use them when relevant.
134
- result.push(`--${value ? key : `no-${key}`}`)
135
- } else if (value === true) {
136
- result.push(`--${key}`)
137
- } else if (typeof value === 'string') {
138
- result.push(`--${key}=${value}`)
139
- } else if (Array.isArray(value)) {
140
- result.push(`--${key}`, ...value.map(String))
141
- }
142
- }
143
- if (argv['--']) {
144
- result.push('--', ...argv['--'])
145
- }
146
- return result
147
- }
148
-
149
- /** @type {import('../../utils/meow-with-subcommands.js').CliSubcommand} */
150
- export const cdxgen = {
151
- description: 'Create an SBOM with CycloneDX generator (cdxgen)',
152
- async run (argv_) {
153
- const /** @type {any} */ yargv = {
154
- __proto__: null,
155
- // @ts-ignore
156
- ...yargsParse(argv_, yargsConfig)
157
- }
158
-
159
- const /** @type {string[]} */ unknown = yargv._
160
- const { length: unknownLength } = unknown
161
- if (unknownLength) {
162
- console.error(`Unknown argument${unknownLength > 1 ? 's' : ''}: ${yargv._.join(', ')}`)
163
- process.exitCode = 1
164
- return
165
- }
166
-
167
- let cleanupPackageLock = false
168
- if (
169
- yargv.type !== 'yarn' &&
170
- nodejsPlatformTypes.includes(yargv.type) &&
171
- existsSync('./yarn.lock')
172
- ) {
173
- if (existsSync('./package-lock.json')) {
174
- yargv.type = 'npm'
175
- } else {
176
- // Use synp to create a package-lock.json from the yarn.lock,
177
- // based on the node_modules folder, for a more accurate SBOM.
178
- try {
179
- await $(execaConfig)`synp --source-file ./yarn.lock`
180
- yargv.type = 'npm'
181
- cleanupPackageLock = true
182
- } catch {}
183
- }
184
- }
185
-
186
- if (yargv.output === undefined) {
187
- yargv.output = 'socket-cdx.json'
188
- }
189
-
190
- await $({
191
- ...execaConfig,
192
- env: {
193
- NODE_ENV: '',
194
- SBOM_SIGN_ALGORITHM,
195
- SBOM_SIGN_PRIVATE_KEY,
196
- SBOM_SIGN_PUBLIC_KEY
197
- },
198
- stdout: 'inherit'
199
- })`cdxgen ${argvToArray(yargv)}`
200
-
201
- if (cleanupPackageLock) {
202
- try {
203
- await fs.unlink('./package-lock.json')
204
- } catch {}
205
- }
206
- const fullOutputPath = path.join(process.cwd(), yargv.output)
207
- if (existsSync(fullOutputPath)) {
208
- console.log(chalk.cyanBright(`${yargv.output} created!`))
209
- }
210
- }
211
- }
@@ -1,150 +0,0 @@
1
- /* eslint-disable no-console */
2
-
3
- import chalk from 'chalk'
4
- // @ts-ignore
5
- import chalkTable from 'chalk-table'
6
- import meow from 'meow'
7
- import ora from 'ora'
8
-
9
- import { outputFlags } from '../../flags/index.js'
10
- import { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api-helpers.js'
11
- import { prepareFlags } from '../../utils/flags.js'
12
- import { printFlagList } from '../../utils/formatting.js'
13
- import { getDefaultKey, setupSdk } from '../../utils/sdk.js'
14
-
15
- /** @type {import('../../utils/meow-with-subcommands.js').CliSubcommand} */
16
- export const dependencies = {
17
- description: 'Search for any dependency that is being used in your organization',
18
- async run (argv, importMeta, { parentName }) {
19
- const name = parentName + ' dependencies'
20
-
21
- const input = setupCommand(name, dependencies.description, argv, importMeta)
22
- if (input) {
23
- const spinnerText = 'Searching dependencies...'
24
- const spinner = ora(spinnerText).start()
25
- await searchDeps(input, spinner)
26
- }
27
- }
28
- }
29
-
30
- const dependenciesFlags = prepareFlags({
31
- limit: {
32
- type: 'number',
33
- shortFlag: 'l',
34
- default: 50,
35
- description: 'Maximum number of dependencies returned',
36
- },
37
- offset: {
38
- type: 'number',
39
- shortFlag: 'o',
40
- default: 0,
41
- description: 'Page number',
42
- }
43
- })
44
-
45
- // Internal functions
46
-
47
- /**
48
- * @typedef Command
49
- * @property {boolean} outputJson
50
- * @property {boolean} outputMarkdown
51
- * @property {number} limit
52
- * @property {number} offset
53
- */
54
-
55
- /**
56
- * @param {string} name
57
- * @param {string} description
58
- * @param {readonly string[]} argv
59
- * @param {ImportMeta} importMeta
60
- * @returns {void|Command}
61
- */
62
- function setupCommand (name, description, argv, importMeta) {
63
- const flags = {
64
- ...outputFlags,
65
- ...dependenciesFlags
66
- }
67
-
68
- const cli = meow(`
69
- Usage
70
- $ ${name}
71
-
72
- Options
73
- ${printFlagList(flags, 6)}
74
-
75
- Examples
76
- $ ${name}
77
- `, {
78
- argv,
79
- description,
80
- importMeta,
81
- flags
82
- })
83
-
84
- const {
85
- json: outputJson,
86
- markdown: outputMarkdown,
87
- limit,
88
- offset
89
- } = cli.flags
90
-
91
- return {
92
- outputJson,
93
- outputMarkdown,
94
- limit,
95
- offset
96
- }
97
- }
98
-
99
- /**
100
- * @typedef DependenciesData
101
- * @property {import('@socketsecurity/sdk').SocketSdkReturnType<'searchDependencies'>["data"]} data
102
- */
103
-
104
- /**
105
- * @param {Command} input
106
- * @param {import('ora').Ora} spinner
107
- * @returns {Promise<void|DependenciesData>}
108
- */
109
- async function searchDeps ({ limit, offset, outputJson }, spinner) {
110
- const socketSdk = await setupSdk(getDefaultKey())
111
- const result = await handleApiCall(socketSdk.searchDependencies({ limit, offset }), 'Searching dependencies')
112
-
113
- if (!result.success) {
114
- return handleUnsuccessfulApiResponse('searchDependencies', result, spinner)
115
- }
116
-
117
- spinner.stop()
118
-
119
- console.log('Organization dependencies: \n')
120
-
121
- if (outputJson) {
122
- return console.log(result.data)
123
- }
124
-
125
- const options = {
126
- columns: [
127
- { field: 'namespace', name: chalk.cyan('Namespace') },
128
- { field: 'name', name: chalk.cyan('Name') },
129
- { field: 'version', name: chalk.cyan('Version') },
130
- { field: 'repository', name: chalk.cyan('Repository') },
131
- { field: 'branch', name: chalk.cyan('Branch') },
132
- { field: 'type', name: chalk.cyan('Type') },
133
- { field: 'direct', name: chalk.cyan('Direct') }
134
- ]
135
- }
136
-
137
- const formattedResults = result.data.rows.map((/** @type {{[key:string]: any}} */ d) => {
138
- return {
139
- ...d
140
- }
141
- })
142
-
143
- const table = chalkTable(options, formattedResults)
144
-
145
- console.log(table, '\n')
146
-
147
- return {
148
- data: result.data
149
- }
150
- }
@@ -1,15 +0,0 @@
1
- export * from './cdxgen/index.js'
2
- export * from './info/index.js'
3
- export * from './login/index.js'
4
- export * from './logout/index.js'
5
- export * from './npm/index.js'
6
- export * from './npx/index.js'
7
- export * from './raw-npm/index.js'
8
- export * from './raw-npx/index.js'
9
- export * from './report/index.js'
10
- export * from './wrapper/index.js'
11
- export * from './scan/index.js'
12
- export * from './audit-log/index.js'
13
- export * from './repos/index.js'
14
- export * from './dependencies/index.js'
15
- export * from './organizations/index.js'
@@ -1,287 +0,0 @@
1
- /* eslint-disable no-console */
2
-
3
- import chalk from 'chalk'
4
- import meow from 'meow'
5
- import ora from 'ora'
6
-
7
- import { outputFlags, validationFlags } from '../../flags/index.js'
8
- import { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api-helpers.js'
9
- import { ChalkOrMarkdown } from '../../utils/chalk-markdown.js'
10
- import { prepareFlags } from '../../utils/flags.js'
11
- import { formatSeverityCount, getCountSeverity } from '../../utils/format-issues.js'
12
- import { printFlagList } from '../../utils/formatting.js'
13
- import { objectSome } from '../../utils/misc.js'
14
- import { FREE_API_KEY, getDefaultKey, setupSdk } from '../../utils/sdk.js'
15
-
16
- /** @type {import('../../utils/meow-with-subcommands.js').CliSubcommand} */
17
- export const info = {
18
- description: 'Look up info regarding a package',
19
- async run (argv, importMeta, { parentName }) {
20
- const name = parentName + ' info'
21
-
22
- const input = setupCommand(name, info.description, argv, importMeta)
23
- if (input) {
24
- const spinnerText = `Looking up data for packages: ${input.packages.join(', ')}\n`
25
- const spinner = ora(spinnerText).start()
26
- const packageData = await fetchPackageData(input.packages, input.includeAlerts, spinner)
27
- if (packageData) {
28
- formatPackageDataOutput(packageData, { name, ...input }, spinner)
29
- }
30
- }
31
- }
32
- }
33
-
34
- const infoFlags = prepareFlags({
35
- // At the moment in API v0, alerts and license do the same thing.
36
- // The license parameter will be implemented later.
37
- // license: {
38
- // type: 'boolean',
39
- // shortFlag: 'l',
40
- // default: false,
41
- // description: 'Include license - Default is false',
42
- // },
43
- alerts: {
44
- type: 'boolean',
45
- shortFlag: 'a',
46
- default: false,
47
- description: 'Include alerts - Default is false',
48
- }
49
- })
50
-
51
- // Internal functions
52
-
53
- /**
54
- * @typedef CommandContext
55
- * @property {boolean} includeAlerts
56
- * @property {boolean} outputJson
57
- * @property {boolean} outputMarkdown
58
- * @property {string[]} packages
59
- * @property {boolean} strict
60
- */
61
-
62
- /**
63
- * @param {string} name
64
- * @param {string} description
65
- * @param {readonly string[]} argv
66
- * @param {ImportMeta} importMeta
67
- * @returns {void|CommandContext}
68
- */
69
- function setupCommand (name, description, argv, importMeta) {
70
- const flags = {
71
- ...outputFlags,
72
- ...validationFlags,
73
- ...infoFlags
74
- }
75
-
76
- const cli = meow(`
77
- Usage
78
- $ ${name} <ecosystem>:<name>@<version>
79
-
80
- Options
81
- ${printFlagList(flags, 6)}
82
-
83
- Examples
84
- $ ${name} npm:webtorrent
85
- $ ${name} npm:webtorrent@1.9.1
86
- `, {
87
- argv,
88
- description,
89
- importMeta,
90
- flags
91
- })
92
-
93
- const {
94
- alerts: includeAlerts,
95
- json: outputJson,
96
- markdown: outputMarkdown,
97
- strict,
98
- } = cli.flags
99
-
100
- const [rawPkgName = ''] = cli.input
101
-
102
- if (!rawPkgName) {
103
- console.error(`${chalk.bgRed('Input error')}: Please provide an ecosystem and package name`)
104
- cli.showHelp()
105
- return
106
- }
107
-
108
- const /** @type {string[]} */inputPkgs = []
109
-
110
- cli.input.map(pkg => {
111
- const ecosystem = pkg.split(':')[0]
112
- if (!ecosystem) {
113
- console.error(`Package name ${pkg} formatted incorrectly.`)
114
- return cli.showHelp()
115
- } else {
116
- const versionSeparator = pkg.lastIndexOf('@')
117
- const ecosystemSeparator = pkg.lastIndexOf(ecosystem)
118
- const pkgName = versionSeparator < 1 ? pkg.slice(ecosystemSeparator + ecosystem.length + 1) : pkg.slice(ecosystemSeparator + ecosystem.length + 1, versionSeparator)
119
- const pkgVersion = versionSeparator < 1 ? 'latest' : pkg.slice(versionSeparator + 1)
120
- inputPkgs.push(`${ecosystem}/${pkgName}@${pkgVersion}`)
121
- }
122
- return inputPkgs
123
- })
124
-
125
- return {
126
- includeAlerts,
127
- outputJson,
128
- outputMarkdown,
129
- packages: inputPkgs,
130
- strict,
131
- }
132
- }
133
-
134
- /**
135
- * @typedef PackageData
136
- * @property {import('@socketsecurity/sdk').SocketSdkReturnType<'batchPackageFetch'>["data"]} data
137
- */
138
-
139
- /**
140
- * @param {string[]} packages
141
- * @param {boolean} includeAlerts
142
- * @param {import('ora').Ora} spinner
143
- * @returns {Promise<void|PackageData>}
144
- */
145
- async function fetchPackageData (packages, includeAlerts, spinner) {
146
- const socketSdk = await setupSdk(getDefaultKey() || FREE_API_KEY)
147
-
148
- const components = packages.map(pkg => {
149
- return { 'purl': `pkg:${pkg}` }
150
- })
151
-
152
- const result = await handleApiCall(socketSdk.batchPackageFetch(
153
- { alerts: includeAlerts.toString() },
154
- {
155
- components
156
- }), 'looking up package')
157
-
158
- if (!result.success) {
159
- return handleUnsuccessfulApiResponse('batchPackageFetch', result, spinner)
160
- }
161
-
162
- // @ts-ignore
163
- result.data.map(pkg => {
164
- const severityCount = pkg.alerts && getCountSeverity(pkg.alerts, includeAlerts ? undefined : 'high')
165
- pkg.severityCount = severityCount
166
- return pkg
167
- })
168
-
169
- spinner.stop()
170
-
171
- return {
172
- data: result.data
173
- }
174
- }
175
-
176
- /**
177
- * @param {CommandContext} data
178
- * @param {{ name: string } & CommandContext} context
179
- * @param {import('ora').Ora} spinner
180
- * @returns {void}
181
- */
182
- function formatPackageDataOutput (/** @type {{ [key: string]: any }} */ { data }, { outputJson, outputMarkdown, strict }, spinner) {
183
- if (outputJson) {
184
- console.log(JSON.stringify(data, undefined, 2))
185
- } else {
186
- data.map((/** @type {{[key:string]: any}} */ d) => {
187
- const { score, license, name, severityCount, version } = d
188
- console.log(`\nPackage metrics for ${name}:`)
189
-
190
- const scoreResult = {
191
- 'Supply Chain Risk': Math.floor(score.supplyChain * 100),
192
- 'Maintenance': Math.floor(score.maintenance * 100),
193
- 'Quality': Math.floor(score.quality * 100),
194
- 'Vulnerabilities': Math.floor(score.vulnerability * 100),
195
- 'License': Math.floor(score.license * 100),
196
- 'Overall': Math.floor(score.overall * 100)
197
- }
198
-
199
- Object.entries(scoreResult).map(score => console.log(`- ${score[0]}: ${formatScore(score[1])}`))
200
-
201
- // Package license
202
- console.log('\nPackage license:')
203
- console.log(`${license}`)
204
-
205
- // Package issues list
206
- if (objectSome(severityCount)) {
207
- const issueSummary = formatSeverityCount(severityCount)
208
- console.log('\n')
209
- spinner[strict ? 'fail' : 'succeed'](`Package has these issues: ${issueSummary}`)
210
- formatPackageIssuesDetails(data.alerts, outputMarkdown)
211
- } else if (severityCount && !objectSome(severityCount)) {
212
- console.log('\n')
213
- spinner.succeed('Package has no issues')
214
- }
215
-
216
- // Link to issues list
217
- const format = new ChalkOrMarkdown(!!outputMarkdown)
218
- const url = `https://socket.dev/npm/package/${name}/overview/${version}`
219
- if (version === 'latest') {
220
- console.log('\nDetailed info on socket.dev: ' + format.hyperlink(`${name}`, url, { fallbackToUrl: true }))
221
- } else {
222
- console.log('\nDetailed info on socket.dev: ' + format.hyperlink(`${name} v${version}`, url, { fallbackToUrl: true }))
223
- }
224
- if (!outputMarkdown) {
225
- console.log(chalk.dim('\nOr rerun', chalk.italic(name), 'using the', chalk.italic('--json'), 'flag to get full JSON output'))
226
- }
227
-
228
- if (strict && objectSome(severityCount)) {
229
- process.exit(1)
230
- }
231
- return d
232
- })
233
- }
234
- }
235
-
236
- /**
237
- * @param {{[key: string]: any}[]} alertsData
238
- * @param {boolean} outputMarkdown
239
- * @returns {void[]}
240
- */
241
- function formatPackageIssuesDetails (alertsData, outputMarkdown) {
242
- const issueDetails = alertsData.filter(d => d['severity'] === 'high' || d['severity'] === 'critical')
243
-
244
- const uniqueIssues = issueDetails.reduce((/** @type {{ [key: string]: {count: Number, label: string | undefined} }} */ acc, issue) => {
245
- const { type } = issue
246
- if (type) {
247
- if (!acc[type]) {
248
- acc[type] = {
249
- label: issue['type'],
250
- count: 1
251
- }
252
- } else {
253
- // @ts-ignore
254
- acc[type].count += 1
255
- }
256
- }
257
- return acc
258
- }, {})
259
-
260
- const format = new ChalkOrMarkdown(!!outputMarkdown)
261
-
262
- return Object.keys(uniqueIssues).map(issue => {
263
- const issueWithLink = format.hyperlink(`${uniqueIssues[issue]?.label}`, `https://socket.dev/npm/issue/${issue}`, { fallbackToUrl: true })
264
- if (uniqueIssues[issue]?.count === 1) {
265
- return console.log(`- ${issueWithLink}`)
266
- }
267
- return console.log(`- ${issueWithLink}: ${uniqueIssues[issue]?.count}`)
268
- })
269
- }
270
-
271
- /**
272
- * @param {number} score
273
- * @returns {string}
274
- */
275
- function formatScore (score) {
276
- const error = chalk.hex('#de7c7b')
277
- const warning = chalk.hex('#e59361')
278
- const success = chalk.hex('#a4cb9d')
279
-
280
- if (score > 80) {
281
- return `${success(score)}`
282
- } else if (score < 80 && score > 60) {
283
- return `${warning(score)}`
284
- } else {
285
- return `${error(score)}`
286
- }
287
- }