@socketsecurity/cli 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/cli.js +12 -1
- package/lib/commands/audit-log/index.js +162 -0
- package/lib/commands/cdxgen/index.js +211 -0
- package/lib/commands/dependencies/index.js +150 -0
- package/lib/commands/index.js +11 -3
- package/lib/commands/info/index.js +123 -81
- package/lib/commands/login/index.js +1 -1
- package/lib/commands/logout/index.js +1 -1
- package/lib/commands/npm/index.js +8 -3
- package/lib/commands/npx/index.js +1 -1
- package/lib/commands/raw-npm/index.js +59 -0
- package/lib/commands/raw-npx/index.js +59 -0
- package/lib/commands/report/create.js +1 -1
- package/lib/commands/report/index.js +1 -1
- package/lib/commands/report/view.js +1 -1
- package/lib/commands/repos/create.js +166 -0
- package/lib/commands/repos/delete.js +93 -0
- package/lib/commands/repos/index.js +30 -0
- package/lib/commands/repos/list.js +170 -0
- package/lib/commands/repos/update.js +166 -0
- package/lib/commands/repos/view.js +128 -0
- package/lib/commands/scan/create.js +245 -0
- package/lib/commands/scan/delete.js +112 -0
- package/lib/commands/scan/index.js +30 -0
- package/lib/commands/scan/list.js +192 -0
- package/lib/commands/scan/metadata.js +113 -0
- package/lib/commands/scan/stream.js +115 -0
- package/lib/commands/wrapper/index.js +199 -0
- package/lib/flags/command.js +14 -0
- package/lib/flags/index.js +1 -0
- package/lib/shadow/npm-injection.cjs +11 -1
- package/lib/utils/format-issues.js +28 -1
- package/lib/utils/meow-with-subcommands.js +1 -2
- package/lib/utils/misc.js +0 -1
- package/lib/utils/path-resolve.js +31 -6
- package/lib/utils/sdk.js +0 -3
- package/package.json +79 -62
|
@@ -0,0 +1,113 @@
|
|
|
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 } from '../../flags/index.js'
|
|
8
|
+
import { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api-helpers.js'
|
|
9
|
+
import { printFlagList } from '../../utils/formatting.js'
|
|
10
|
+
import { getDefaultKey, setupSdk } from '../../utils/sdk.js'
|
|
11
|
+
|
|
12
|
+
/** @type {import('../../utils/meow-with-subcommands.js').CliSubcommand} */
|
|
13
|
+
export const metadata = {
|
|
14
|
+
description: 'Get a scan\'s metadata',
|
|
15
|
+
async run (argv, importMeta, { parentName }) {
|
|
16
|
+
const name = parentName + ' metadata'
|
|
17
|
+
|
|
18
|
+
const input = setupCommand(name, metadata.description, argv, importMeta)
|
|
19
|
+
if (input) {
|
|
20
|
+
const spinnerText = 'Getting scan\'s metadata... \n'
|
|
21
|
+
const spinner = ora(spinnerText).start()
|
|
22
|
+
await getOrgScanMetadata(input.orgSlug, input.scanID, spinner)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Internal functions
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @typedef CommandContext
|
|
31
|
+
* @property {boolean} outputJson
|
|
32
|
+
* @property {boolean} outputMarkdown
|
|
33
|
+
* @property {string} orgSlug
|
|
34
|
+
* @property {string} scanID
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param {string} name
|
|
39
|
+
* @param {string} description
|
|
40
|
+
* @param {readonly string[]} argv
|
|
41
|
+
* @param {ImportMeta} importMeta
|
|
42
|
+
* @returns {void|CommandContext}
|
|
43
|
+
*/
|
|
44
|
+
function setupCommand (name, description, argv, importMeta) {
|
|
45
|
+
const flags = {
|
|
46
|
+
...outputFlags,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const cli = meow(`
|
|
50
|
+
Usage
|
|
51
|
+
$ ${name} <org slug> <scan id>
|
|
52
|
+
|
|
53
|
+
Options
|
|
54
|
+
${printFlagList(flags, 6)}
|
|
55
|
+
|
|
56
|
+
Examples
|
|
57
|
+
$ ${name} FakeOrg 000aaaa1-0000-0a0a-00a0-00a0000000a0
|
|
58
|
+
`, {
|
|
59
|
+
argv,
|
|
60
|
+
description,
|
|
61
|
+
importMeta,
|
|
62
|
+
flags
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
const {
|
|
66
|
+
json: outputJson,
|
|
67
|
+
markdown: outputMarkdown,
|
|
68
|
+
} = cli.flags
|
|
69
|
+
|
|
70
|
+
if (cli.input.length < 2) {
|
|
71
|
+
console.error(`${chalk.bgRed('Input error')}: Please specify an organization slug and a scan ID.\n`)
|
|
72
|
+
cli.showHelp()
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const [orgSlug = '', scanID = ''] = cli.input
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
outputJson,
|
|
80
|
+
outputMarkdown,
|
|
81
|
+
orgSlug,
|
|
82
|
+
scanID
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @typedef FullScansData
|
|
88
|
+
* @property {import('@socketsecurity/sdk').SocketSdkReturnType<'getOrgFullScanMetadata'>["data"]} data
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @param {string} orgSlug
|
|
93
|
+
* @param {string} scanId
|
|
94
|
+
* @param {import('ora').Ora} spinner
|
|
95
|
+
* @returns {Promise<void|FullScansData>}
|
|
96
|
+
*/
|
|
97
|
+
async function getOrgScanMetadata (orgSlug, scanId, spinner) {
|
|
98
|
+
const socketSdk = await setupSdk(getDefaultKey())
|
|
99
|
+
const result = await handleApiCall(socketSdk.getOrgFullScanMetadata(orgSlug, scanId), 'Listing scans')
|
|
100
|
+
|
|
101
|
+
if (!result.success) {
|
|
102
|
+
return handleUnsuccessfulApiResponse('getOrgFullScanMetadata', result, spinner)
|
|
103
|
+
}
|
|
104
|
+
spinner.stop()
|
|
105
|
+
|
|
106
|
+
console.log('\nScan metadata: \n')
|
|
107
|
+
|
|
108
|
+
console.log(result.data)
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
data: result.data
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
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 } from '../../flags/index.js'
|
|
8
|
+
import { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api-helpers.js'
|
|
9
|
+
import { printFlagList } from '../../utils/formatting.js'
|
|
10
|
+
import { getDefaultKey, setupSdk } from '../../utils/sdk.js'
|
|
11
|
+
|
|
12
|
+
/** @type {import('../../utils/meow-with-subcommands.js').CliSubcommand} */
|
|
13
|
+
export const stream = {
|
|
14
|
+
description: 'Stream the output of a scan',
|
|
15
|
+
async run (argv, importMeta, { parentName }) {
|
|
16
|
+
const name = parentName + ' stream'
|
|
17
|
+
|
|
18
|
+
const input = setupCommand(name, stream.description, argv, importMeta)
|
|
19
|
+
if (input) {
|
|
20
|
+
const spinnerText = 'Streaming scan... \n'
|
|
21
|
+
const spinner = ora(spinnerText).start()
|
|
22
|
+
await getOrgFullScan(input.orgSlug, input.fullScanId, input.file, spinner)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Internal functions
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @typedef CommandContext
|
|
31
|
+
* @property {boolean} outputJson
|
|
32
|
+
* @property {boolean} outputMarkdown
|
|
33
|
+
* @property {string} orgSlug
|
|
34
|
+
* @property {string} fullScanId
|
|
35
|
+
* @property {string | undefined} file
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {string} name
|
|
40
|
+
* @param {string} description
|
|
41
|
+
* @param {readonly string[]} argv
|
|
42
|
+
* @param {ImportMeta} importMeta
|
|
43
|
+
* @returns {void|CommandContext}
|
|
44
|
+
*/
|
|
45
|
+
function setupCommand (name, description, argv, importMeta) {
|
|
46
|
+
const flags = {
|
|
47
|
+
...outputFlags
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const cli = meow(`
|
|
51
|
+
Usage
|
|
52
|
+
$ ${name} <org slug> <scan ID> <path to output file>
|
|
53
|
+
|
|
54
|
+
Options
|
|
55
|
+
${printFlagList(flags, 6)}
|
|
56
|
+
|
|
57
|
+
Examples
|
|
58
|
+
$ ${name} FakeOrg 000aaaa1-0000-0a0a-00a0-00a0000000a0 ./stream.txt
|
|
59
|
+
`, {
|
|
60
|
+
argv,
|
|
61
|
+
description,
|
|
62
|
+
importMeta,
|
|
63
|
+
flags
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
const {
|
|
67
|
+
json: outputJson,
|
|
68
|
+
markdown: outputMarkdown,
|
|
69
|
+
} = cli.flags
|
|
70
|
+
|
|
71
|
+
if (cli.input.length < 2) {
|
|
72
|
+
console.error(`${chalk.bgRed('Input error')}: Please specify an organization slug and a scan ID.\n`)
|
|
73
|
+
cli.showHelp()
|
|
74
|
+
return
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const [orgSlug = '', fullScanId = '', file] = cli.input
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
outputJson,
|
|
81
|
+
outputMarkdown,
|
|
82
|
+
orgSlug,
|
|
83
|
+
fullScanId,
|
|
84
|
+
file
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @typedef FullScanData
|
|
90
|
+
* @property {import('@socketsecurity/sdk').SocketSdkReturnType<'getOrgFullScan'>["data"]} data
|
|
91
|
+
*/
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @param {string} orgSlug
|
|
95
|
+
* @param {string} fullScanId
|
|
96
|
+
* @param {string | undefined} file
|
|
97
|
+
* @param {import('ora').Ora} spinner
|
|
98
|
+
* @returns {Promise<void|FullScanData>}
|
|
99
|
+
*/
|
|
100
|
+
async function getOrgFullScan (orgSlug, fullScanId, file, spinner) {
|
|
101
|
+
const socketSdk = await setupSdk(getDefaultKey())
|
|
102
|
+
const result = await handleApiCall(socketSdk.getOrgFullScan(orgSlug, fullScanId, file), 'Streaming a scan')
|
|
103
|
+
|
|
104
|
+
if (!result?.success) {
|
|
105
|
+
return handleUnsuccessfulApiResponse('getOrgFullScan', result, spinner)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
spinner.stop()
|
|
109
|
+
|
|
110
|
+
console.log(file ? `\nFull scan details written to ${file} \n` : '\nFull scan details: \n')
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
data: result.data
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
import homedir from 'os'
|
|
4
|
+
import readline from 'readline'
|
|
5
|
+
|
|
6
|
+
import meow from 'meow'
|
|
7
|
+
|
|
8
|
+
import { commandFlags } from '../../flags/index.js'
|
|
9
|
+
import { printFlagList } from '../../utils/formatting.js'
|
|
10
|
+
|
|
11
|
+
const BASH_FILE = `${homedir.homedir()}/.bashrc`
|
|
12
|
+
const ZSH_BASH_FILE = `${homedir.homedir()}/.zshrc`
|
|
13
|
+
|
|
14
|
+
/** @type {import('../../utils/meow-with-subcommands.js').CliSubcommand} */
|
|
15
|
+
export const wrapper = {
|
|
16
|
+
description: 'Enable or disable the Socket npm/npx wrapper',
|
|
17
|
+
async run (argv, importMeta, { parentName }) {
|
|
18
|
+
const name = parentName + ' wrapper'
|
|
19
|
+
|
|
20
|
+
setupCommand(name, wrapper.description, argv, importMeta)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param {string} name
|
|
26
|
+
* @param {string} description
|
|
27
|
+
* @param {readonly string[]} argv
|
|
28
|
+
* @param {ImportMeta} importMeta
|
|
29
|
+
* @returns {void}
|
|
30
|
+
*/
|
|
31
|
+
function setupCommand (name, description, argv, importMeta) {
|
|
32
|
+
const flags = commandFlags
|
|
33
|
+
|
|
34
|
+
const cli = meow(`
|
|
35
|
+
Usage
|
|
36
|
+
$ ${name} <flag>
|
|
37
|
+
|
|
38
|
+
Options
|
|
39
|
+
${printFlagList(flags, 6)}
|
|
40
|
+
|
|
41
|
+
Examples
|
|
42
|
+
$ ${name} --enable
|
|
43
|
+
$ ${name} --disable
|
|
44
|
+
`, {
|
|
45
|
+
argv,
|
|
46
|
+
description,
|
|
47
|
+
importMeta,
|
|
48
|
+
flags
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
const { enable, disable } = cli.flags
|
|
52
|
+
|
|
53
|
+
if (argv[0] === '--postinstall') {
|
|
54
|
+
// Check if the wrapper is already enabled before showing the postinstall prompt
|
|
55
|
+
const socketWrapperEnabled = (fs.existsSync(BASH_FILE) && checkSocketWrapperAlreadySetup(BASH_FILE)) || (fs.existsSync(ZSH_BASH_FILE) && checkSocketWrapperAlreadySetup(ZSH_BASH_FILE))
|
|
56
|
+
|
|
57
|
+
if (!socketWrapperEnabled) {
|
|
58
|
+
installSafeNpm(`The Socket CLI is now successfully installed! 🎉
|
|
59
|
+
|
|
60
|
+
To better protect yourself against supply-chain attacks, our "safe npm" wrapper can warn you about malicious packages whenever you run 'npm install'.
|
|
61
|
+
|
|
62
|
+
Do you want to install "safe npm" (this will create an alias to the socket-npm command)? (y/n)`)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!enable && !disable) {
|
|
69
|
+
cli.showHelp()
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (enable) {
|
|
74
|
+
if (fs.existsSync(BASH_FILE)) {
|
|
75
|
+
const socketWrapperEnabled = checkSocketWrapperAlreadySetup(BASH_FILE)
|
|
76
|
+
!socketWrapperEnabled && addAlias(BASH_FILE)
|
|
77
|
+
}
|
|
78
|
+
if (fs.existsSync(ZSH_BASH_FILE)) {
|
|
79
|
+
const socketWrapperEnabled = checkSocketWrapperAlreadySetup(ZSH_BASH_FILE)
|
|
80
|
+
!socketWrapperEnabled && addAlias(ZSH_BASH_FILE)
|
|
81
|
+
}
|
|
82
|
+
} else if (disable) {
|
|
83
|
+
if (fs.existsSync(BASH_FILE)) {
|
|
84
|
+
removeAlias(BASH_FILE)
|
|
85
|
+
}
|
|
86
|
+
if (fs.existsSync(ZSH_BASH_FILE)) {
|
|
87
|
+
removeAlias(ZSH_BASH_FILE)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (!fs.existsSync(BASH_FILE) && !fs.existsSync(ZSH_BASH_FILE)) {
|
|
91
|
+
console.error('There was an issue setting up the alias in your bash profile')
|
|
92
|
+
}
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @param {string} query
|
|
98
|
+
* @returns {void}
|
|
99
|
+
*/
|
|
100
|
+
const installSafeNpm = (query) => {
|
|
101
|
+
console.log(`
|
|
102
|
+
_____ _ _
|
|
103
|
+
| __|___ ___| |_ ___| |_
|
|
104
|
+
|__ | . | _| '_| -_| _|
|
|
105
|
+
|_____|___|___|_,_|___|_|
|
|
106
|
+
|
|
107
|
+
`)
|
|
108
|
+
|
|
109
|
+
const rl = readline.createInterface({
|
|
110
|
+
input: process.stdin,
|
|
111
|
+
output: process.stdout,
|
|
112
|
+
})
|
|
113
|
+
return askQuestion(rl, query)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* @param {any} rl
|
|
118
|
+
* @param {string} query
|
|
119
|
+
* @returns {void}
|
|
120
|
+
*/
|
|
121
|
+
const askQuestion = (rl, query) => {
|
|
122
|
+
rl.question(query, (/** @type {string} */ ans) => {
|
|
123
|
+
if (ans.toLowerCase() === 'y') {
|
|
124
|
+
try {
|
|
125
|
+
if (fs.existsSync(BASH_FILE)) {
|
|
126
|
+
addAlias(BASH_FILE)
|
|
127
|
+
}
|
|
128
|
+
if (fs.existsSync(ZSH_BASH_FILE)) {
|
|
129
|
+
addAlias(ZSH_BASH_FILE)
|
|
130
|
+
}
|
|
131
|
+
} catch (e) {
|
|
132
|
+
throw new Error(`There was an issue setting up the alias: ${e}`)
|
|
133
|
+
}
|
|
134
|
+
rl.close()
|
|
135
|
+
} else if (ans.toLowerCase() !== 'n') {
|
|
136
|
+
askQuestion(rl, 'Incorrect input: please enter either y (yes) or n (no): ')
|
|
137
|
+
} else {
|
|
138
|
+
rl.close()
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @param {string} file
|
|
145
|
+
* @returns {void}
|
|
146
|
+
*/
|
|
147
|
+
const addAlias = (file) => {
|
|
148
|
+
return fs.appendFile(file, 'alias npm="socket npm"\nalias npx="socket npx"\n', (err) => {
|
|
149
|
+
if (err) {
|
|
150
|
+
return new Error(`There was an error setting up the alias: ${err}`)
|
|
151
|
+
}
|
|
152
|
+
console.log(`
|
|
153
|
+
The alias was added to ${file}. Running 'npm install' will now be wrapped in Socket's "safe npm" 🎉
|
|
154
|
+
If you want to disable it at any time, run \`socket wrapper --disable\`
|
|
155
|
+
`)
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* @param {string} file
|
|
161
|
+
* @returns {void}
|
|
162
|
+
*/
|
|
163
|
+
const removeAlias = (file) => {
|
|
164
|
+
return fs.readFile(file, 'utf8', function (err, data) {
|
|
165
|
+
if (err) {
|
|
166
|
+
console.error(`There was an error removing the alias: ${err}`)
|
|
167
|
+
return
|
|
168
|
+
}
|
|
169
|
+
const linesWithoutSocketAlias = data.split('\n').filter(l => l !== 'alias npm="socket npm"' && l !== 'alias npx="socket npx"')
|
|
170
|
+
|
|
171
|
+
const updatedFileContent = linesWithoutSocketAlias.join('\n')
|
|
172
|
+
|
|
173
|
+
fs.writeFile(file, updatedFileContent, function (err) {
|
|
174
|
+
if (err) {
|
|
175
|
+
console.log(err)
|
|
176
|
+
return
|
|
177
|
+
} else {
|
|
178
|
+
console.log(`
|
|
179
|
+
The alias was removed from ${file}. Running 'npm install' will now run the standard npm command.
|
|
180
|
+
`)
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* @param {string} file
|
|
188
|
+
* @returns {boolean}
|
|
189
|
+
*/
|
|
190
|
+
const checkSocketWrapperAlreadySetup = (file) => {
|
|
191
|
+
const fileContent = fs.readFileSync(file, 'utf-8')
|
|
192
|
+
const linesWithSocketAlias = fileContent.split('\n').filter(l => l === 'alias npm="socket npm"' || l === 'alias npx="socket npx"')
|
|
193
|
+
|
|
194
|
+
if (linesWithSocketAlias.length) {
|
|
195
|
+
console.log(`The Socket npm/npx wrapper is set up in your bash profile (${file}).`)
|
|
196
|
+
return true
|
|
197
|
+
}
|
|
198
|
+
return false
|
|
199
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { prepareFlags } from '../utils/flags.js'
|
|
2
|
+
|
|
3
|
+
export const commandFlags = prepareFlags({
|
|
4
|
+
enable: {
|
|
5
|
+
type: 'boolean',
|
|
6
|
+
default: false,
|
|
7
|
+
description: 'Enables the Socket npm/npx wrapper',
|
|
8
|
+
},
|
|
9
|
+
disable: {
|
|
10
|
+
type: 'boolean',
|
|
11
|
+
default: false,
|
|
12
|
+
description: 'Disables the Socket npm/npx wrapper',
|
|
13
|
+
}
|
|
14
|
+
})
|
package/lib/flags/index.js
CHANGED
|
@@ -268,7 +268,17 @@ function findRoot (filepath) {
|
|
|
268
268
|
}
|
|
269
269
|
const npmDir = findRoot(path.dirname(npmEntrypoint))
|
|
270
270
|
const arboristLibClassPath = path.join(npmDir, 'node_modules', '@npmcli', 'arborist', 'lib', 'arborist', 'index.js')
|
|
271
|
-
|
|
271
|
+
|
|
272
|
+
const npmVersion = process.env.NPM_VERSION.split('.')
|
|
273
|
+
let npmlog
|
|
274
|
+
|
|
275
|
+
if(npmVersion[0] === '10' && npmVersion[1] >= '6'){
|
|
276
|
+
const { log } = require(path.join(npmDir, 'node_modules', 'proc-log', 'lib', 'index.js'))
|
|
277
|
+
npmlog = log
|
|
278
|
+
} else {
|
|
279
|
+
npmlog = require(path.join(npmDir, 'node_modules', 'npmlog', 'lib', 'log.js'))
|
|
280
|
+
}
|
|
281
|
+
|
|
272
282
|
/**
|
|
273
283
|
* @type {import('pacote')}
|
|
274
284
|
*/
|
|
@@ -27,7 +27,7 @@ const SEVERITIES_BY_ORDER = /** @type {const} */ ([
|
|
|
27
27
|
|
|
28
28
|
return result
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
/* TODO: Delete this function when we remove the report command */
|
|
31
31
|
/**
|
|
32
32
|
* @param {SocketIssueList} issues
|
|
33
33
|
* @param {SocketIssue['severity']} [lowestToInclude]
|
|
@@ -54,6 +54,33 @@ export function getSeverityCount (issues, lowestToInclude) {
|
|
|
54
54
|
return severityCount
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
/* The following function is the updated one */
|
|
58
|
+
/**
|
|
59
|
+
* @param {Array<SocketIssue>} issues
|
|
60
|
+
* @param {SocketIssue['severity']} [lowestToInclude]
|
|
61
|
+
* @returns {Record<SocketIssue['severity'], number>}
|
|
62
|
+
*/
|
|
63
|
+
export function getCountSeverity (issues, lowestToInclude) {
|
|
64
|
+
const severityCount = pick(
|
|
65
|
+
{ low: 0, middle: 0, high: 0, critical: 0 },
|
|
66
|
+
getDesiredSeverities(lowestToInclude)
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
for (const issue of issues) {
|
|
70
|
+
const severity = issue.severity
|
|
71
|
+
|
|
72
|
+
if (!severity) {
|
|
73
|
+
continue
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (severityCount[severity] !== undefined) {
|
|
77
|
+
severityCount[severity] += 1
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return severityCount
|
|
82
|
+
}
|
|
83
|
+
|
|
57
84
|
/**
|
|
58
85
|
* @param {Record<SocketIssue['severity'], number>} severityCount
|
|
59
86
|
* @returns {string}
|
|
@@ -25,9 +25,8 @@ import { printFlagList, printHelpList } from './formatting.js'
|
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* @template {import('meow').AnyFlags} Flags
|
|
29
28
|
* @param {Record<string, CliSubcommand>} subcommands
|
|
30
|
-
* @param {import('meow').Options<
|
|
29
|
+
* @param {import('meow').Options<any> & { aliases?: CliAliases, argv: readonly string[], name: string }} options
|
|
31
30
|
* @returns {Promise<void>}
|
|
32
31
|
*/
|
|
33
32
|
export async function meowWithSubcommands (subcommands, options) {
|
package/lib/utils/misc.js
CHANGED
|
@@ -12,7 +12,6 @@ import { isErrnoException } from './type-helpers.cjs'
|
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* There are a lot of possible folders that we should not be looking in and "ignore-by-default" helps us with defining those
|
|
15
|
-
*
|
|
16
15
|
* @type {readonly string[]}
|
|
17
16
|
*/
|
|
18
17
|
const ignoreByDefault = directories()
|
|
@@ -31,7 +30,6 @@ const BASE_GLOBBY_OPTS = {
|
|
|
31
30
|
|
|
32
31
|
/**
|
|
33
32
|
* Resolves package.json and lockfiles from (globbed) input paths, applying relevant ignores
|
|
34
|
-
*
|
|
35
33
|
* @param {string} cwd The working directory to use when resolving paths
|
|
36
34
|
* @param {string[]} inputPaths A list of paths to folders, package.json files and/or recognized lockfiles. Supports globs.
|
|
37
35
|
* @param {import('@socketsecurity/config').SocketYml|undefined} config
|
|
@@ -57,18 +55,46 @@ export async function getPackageFiles (cwd, inputPaths, config, supportedFiles,
|
|
|
57
55
|
debugLog(`Mapped ${entries.length} entries to ${packageFiles.length} files:`, packageFiles)
|
|
58
56
|
|
|
59
57
|
const includedPackageFiles = config?.projectIgnorePaths?.length
|
|
58
|
+
// @ts-ignore
|
|
60
59
|
? ignore()
|
|
61
60
|
.add(config.projectIgnorePaths)
|
|
62
61
|
.filter(packageFiles.map(item => path.relative(cwd, item)))
|
|
63
|
-
.map(item => path.resolve(cwd, item))
|
|
62
|
+
.map((/** @type {string} */ item) => path.resolve(cwd, item))
|
|
64
63
|
: packageFiles
|
|
65
64
|
|
|
66
65
|
return includedPackageFiles
|
|
67
66
|
}
|
|
68
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Resolves package.json and lockfiles from (globbed) input paths, applying relevant ignores
|
|
70
|
+
* @param {string} cwd The working directory to use when resolving paths
|
|
71
|
+
* @param {string[]} inputPaths A list of paths to folders, package.json files and/or recognized lockfiles. Supports globs.
|
|
72
|
+
* @param {import('@socketsecurity/sdk').SocketSdkReturnType<"getReportSupportedFiles">['data']} supportedFiles
|
|
73
|
+
* @param {typeof console.error} debugLog
|
|
74
|
+
* @returns {Promise<string[]>}
|
|
75
|
+
* @throws {InputError}
|
|
76
|
+
*/
|
|
77
|
+
export async function getPackageFilesFullScans (cwd, inputPaths, supportedFiles, debugLog) {
|
|
78
|
+
debugLog(`Globbed resolving ${inputPaths.length} paths:`, inputPaths)
|
|
79
|
+
|
|
80
|
+
// TODO: Does not support `~/` paths
|
|
81
|
+
const entries = await globby(inputPaths, {
|
|
82
|
+
...BASE_GLOBBY_OPTS,
|
|
83
|
+
cwd,
|
|
84
|
+
onlyFiles: false
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
debugLog(`Globbed resolved ${inputPaths.length} paths to ${entries.length} paths:`, entries)
|
|
88
|
+
|
|
89
|
+
const packageFiles = await mapGlobResultToFiles(entries, supportedFiles)
|
|
90
|
+
|
|
91
|
+
debugLog(`Mapped ${entries.length} entries to ${packageFiles.length} files:`, packageFiles)
|
|
92
|
+
|
|
93
|
+
return packageFiles
|
|
94
|
+
}
|
|
95
|
+
|
|
69
96
|
/**
|
|
70
97
|
* Takes paths to folders, package.json and/or recognized lock files and resolves them to package.json + lockfile pairs (where possible)
|
|
71
|
-
*
|
|
72
98
|
* @param {string[]} entries
|
|
73
99
|
* @param {import('@socketsecurity/sdk').SocketSdkReturnType<"getReportSupportedFiles">['data']} supportedFiles
|
|
74
100
|
* @returns {Promise<string[]>}
|
|
@@ -86,7 +112,6 @@ export async function mapGlobResultToFiles (entries, supportedFiles) {
|
|
|
86
112
|
|
|
87
113
|
/**
|
|
88
114
|
* Takes a single path to a folder, package.json or a recognized lock file and resolves to a package.json + lockfile pair (where possible)
|
|
89
|
-
*
|
|
90
115
|
* @param {string} entry
|
|
91
116
|
* @param {import('@socketsecurity/sdk').SocketSdkReturnType<'getReportSupportedFiles'>['data']} supportedFiles
|
|
92
117
|
* @returns {Promise<string[]>}
|
|
@@ -101,7 +126,7 @@ export async function mapGlobEntryToFiles (entry, supportedFiles) {
|
|
|
101
126
|
const pyFilePatterns = Object.values(supportedFiles['pypi'] || {})
|
|
102
127
|
.map(p => `**/${/** @type {{ pattern: string }} */ (p).pattern}`)
|
|
103
128
|
|
|
104
|
-
const goSupported = supportedFiles['
|
|
129
|
+
const goSupported = supportedFiles['golang'] || {}
|
|
105
130
|
const goSupplementalPatterns = Object.values(goSupported)
|
|
106
131
|
// .filter(key => key !== 'gomod')
|
|
107
132
|
.map(p => `**/${/** @type {{ pattern: string }} */ (p).pattern}`)
|
package/lib/utils/sdk.js
CHANGED
|
@@ -13,7 +13,6 @@ export const FREE_API_KEY = 'sktsec_t_--RAN5U4ivauy4w37-6aoKyYPDt5ZbaT5JBVMqiwKo
|
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* This API key should be stored globally for the duration of the CLI execution
|
|
16
|
-
*
|
|
17
16
|
* @type {string | undefined}
|
|
18
17
|
*/
|
|
19
18
|
let defaultKey
|
|
@@ -26,7 +25,6 @@ export function getDefaultKey () {
|
|
|
26
25
|
|
|
27
26
|
/**
|
|
28
27
|
* The API server that should be used for operations
|
|
29
|
-
*
|
|
30
28
|
* @type {string | undefined}
|
|
31
29
|
*/
|
|
32
30
|
let defaultAPIBaseUrl
|
|
@@ -41,7 +39,6 @@ export function getDefaultAPIBaseUrl () {
|
|
|
41
39
|
|
|
42
40
|
/**
|
|
43
41
|
* The API server that should be used for operations
|
|
44
|
-
*
|
|
45
42
|
* @type {string | undefined}
|
|
46
43
|
*/
|
|
47
44
|
let defaultApiProxy
|