@socketsecurity/cli 0.10.1 → 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.
- package/README.md +22 -22
- package/bin/npm +2 -0
- package/bin/npx +2 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +3419 -0
- package/dist/errors.d.ts +7 -0
- package/dist/link.d.ts +2 -0
- package/dist/link.js +45 -0
- package/dist/npm-cli.d.ts +2 -0
- package/dist/npm-cli.js +84 -0
- package/dist/npm-injection.d.ts +1 -0
- package/dist/npm-injection.js +913 -0
- package/dist/npm-injection2.d.ts +25 -0
- package/dist/npm-injection2.js +899 -0
- package/dist/npx-cli.d.ts +2 -0
- package/dist/npx-cli.js +60 -0
- package/dist/path-resolve.d.ts +12 -0
- package/dist/path-resolve.js +139 -0
- package/dist/sdk.d.ts +27 -0
- package/dist/sdk.js +224 -0
- package/dist/settings.d.ts +9 -0
- package/dist/type-helpers.d.ts +3 -0
- package/dist/vendor.js +25421 -0
- package/package.json +105 -52
- package/{lib/shadow/translations.json → translations.json} +20 -20
- package/cli.js +0 -72
- package/lib/commands/audit-log/index.js +0 -162
- package/lib/commands/cdxgen/index.js +0 -211
- package/lib/commands/dependencies/index.js +0 -150
- package/lib/commands/index.js +0 -14
- package/lib/commands/info/index.js +0 -287
- package/lib/commands/login/index.js +0 -170
- package/lib/commands/logout/index.js +0 -35
- package/lib/commands/npm/index.js +0 -27
- package/lib/commands/npx/index.js +0 -22
- package/lib/commands/raw-npm/index.js +0 -59
- package/lib/commands/raw-npx/index.js +0 -59
- package/lib/commands/report/create.js +0 -251
- package/lib/commands/report/index.js +0 -24
- package/lib/commands/report/view.js +0 -176
- package/lib/commands/repos/create.js +0 -166
- package/lib/commands/repos/delete.js +0 -93
- package/lib/commands/repos/index.js +0 -30
- package/lib/commands/repos/list.js +0 -170
- package/lib/commands/repos/update.js +0 -166
- package/lib/commands/repos/view.js +0 -128
- package/lib/commands/scan/create.js +0 -245
- package/lib/commands/scan/delete.js +0 -112
- package/lib/commands/scan/index.js +0 -30
- package/lib/commands/scan/list.js +0 -192
- package/lib/commands/scan/metadata.js +0 -113
- package/lib/commands/scan/stream.js +0 -115
- package/lib/commands/wrapper/index.js +0 -199
- package/lib/flags/command.js +0 -14
- package/lib/flags/index.js +0 -3
- package/lib/flags/output.js +0 -16
- package/lib/flags/validation.js +0 -14
- package/lib/shadow/bin/npm +0 -2
- package/lib/shadow/bin/npx +0 -2
- package/lib/shadow/link.cjs +0 -50
- package/lib/shadow/npm-cli.cjs +0 -27
- package/lib/shadow/npm-injection.cjs +0 -649
- package/lib/shadow/npx-cli.cjs +0 -27
- package/lib/shadow/package.json +0 -3
- package/lib/shadow/tty-server.cjs +0 -222
- package/lib/shadow/update-notifier.mjs +0 -3
- package/lib/utils/api-helpers.js +0 -42
- package/lib/utils/chalk-markdown.js +0 -125
- package/lib/utils/errors.js +0 -14
- package/lib/utils/flags.js +0 -27
- package/lib/utils/format-issues.js +0 -99
- package/lib/utils/formatting.js +0 -47
- package/lib/utils/issue-rules.cjs +0 -180
- package/lib/utils/meow-with-subcommands.js +0 -87
- package/lib/utils/misc.js +0 -61
- package/lib/utils/path-resolve.js +0 -204
- package/lib/utils/sdk.js +0 -99
- package/lib/utils/settings.js +0 -69
- package/lib/utils/type-helpers.cjs +0 -13
- package/lib/utils/update-notifier.js +0 -18
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
import isInteractive from 'is-interactive'
|
|
2
|
-
import meow from 'meow'
|
|
3
|
-
import ora from 'ora'
|
|
4
|
-
import prompts from 'prompts'
|
|
5
|
-
import terminalLink from 'terminal-link'
|
|
6
|
-
|
|
7
|
-
import { AuthError, InputError } from '../../utils/errors.js'
|
|
8
|
-
import { prepareFlags } from '../../utils/flags.js'
|
|
9
|
-
import { printFlagList } from '../../utils/formatting.js'
|
|
10
|
-
import { FREE_API_KEY, setupSdk } from '../../utils/sdk.js'
|
|
11
|
-
import { getSetting, updateSetting } from '../../utils/settings.js'
|
|
12
|
-
|
|
13
|
-
const description = 'Socket API login'
|
|
14
|
-
|
|
15
|
-
/** @type {import('../../utils/meow-with-subcommands.js').CliSubcommand} */
|
|
16
|
-
export const login = {
|
|
17
|
-
description,
|
|
18
|
-
run: async (argv, importMeta, { parentName }) => {
|
|
19
|
-
const flags = prepareFlags({
|
|
20
|
-
apiBaseUrl: {
|
|
21
|
-
type: 'string',
|
|
22
|
-
description: 'API server to connect to for login',
|
|
23
|
-
},
|
|
24
|
-
apiProxy: {
|
|
25
|
-
type: 'string',
|
|
26
|
-
description: 'Proxy to use when making connection to API server'
|
|
27
|
-
}
|
|
28
|
-
})
|
|
29
|
-
const name = parentName + ' login'
|
|
30
|
-
const cli = meow(`
|
|
31
|
-
Usage
|
|
32
|
-
$ ${name}
|
|
33
|
-
|
|
34
|
-
Logs into the Socket API by prompting for an API key
|
|
35
|
-
|
|
36
|
-
Options
|
|
37
|
-
${printFlagList({
|
|
38
|
-
'api-base-url': flags.apiBaseUrl.description,
|
|
39
|
-
'api-proxy': flags.apiProxy.description
|
|
40
|
-
}, 8)}
|
|
41
|
-
|
|
42
|
-
Examples
|
|
43
|
-
$ ${name}
|
|
44
|
-
`, {
|
|
45
|
-
argv,
|
|
46
|
-
description,
|
|
47
|
-
importMeta,
|
|
48
|
-
flags
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* @param {{aborted: boolean}} state
|
|
53
|
-
*/
|
|
54
|
-
const promptAbortHandler = (state) => {
|
|
55
|
-
if (state.aborted) {
|
|
56
|
-
process.nextTick(() => process.exit(1))
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (cli.input.length) cli.showHelp()
|
|
61
|
-
|
|
62
|
-
if (!isInteractive()) {
|
|
63
|
-
throw new InputError('cannot prompt for credentials in a non-interactive shell')
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* @type {{ apiKey: string }}
|
|
67
|
-
*/
|
|
68
|
-
const result = await prompts({
|
|
69
|
-
type: 'password',
|
|
70
|
-
name: 'apiKey',
|
|
71
|
-
message: `Enter your ${terminalLink(
|
|
72
|
-
'Socket.dev API key',
|
|
73
|
-
'https://docs.socket.dev/docs/api-keys'
|
|
74
|
-
)} (leave blank for a public key)`,
|
|
75
|
-
onState: promptAbortHandler
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
const apiKey = result.apiKey || FREE_API_KEY
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* @type {string | null | undefined}
|
|
82
|
-
*/
|
|
83
|
-
let apiBaseUrl = cli.flags.apiBaseUrl
|
|
84
|
-
apiBaseUrl ??= getSetting('apiBaseUrl') ??
|
|
85
|
-
undefined
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* @type {string | null | undefined}
|
|
89
|
-
*/
|
|
90
|
-
let apiProxy = cli.flags.apiProxy
|
|
91
|
-
apiProxy ??= getSetting('apiProxy') ??
|
|
92
|
-
undefined
|
|
93
|
-
|
|
94
|
-
const spinner = ora('Verifying API key...').start()
|
|
95
|
-
|
|
96
|
-
/** @type {import('@socketsecurity/sdk').SocketSdkReturnType<'getOrganizations'>['data']} */
|
|
97
|
-
let orgs
|
|
98
|
-
|
|
99
|
-
try {
|
|
100
|
-
const sdk = await setupSdk(apiKey, apiBaseUrl, apiProxy)
|
|
101
|
-
const result = await sdk.getOrganizations()
|
|
102
|
-
if (!result.success) throw new AuthError()
|
|
103
|
-
orgs = result.data
|
|
104
|
-
spinner.succeed('API key verified\n')
|
|
105
|
-
} catch (e) {
|
|
106
|
-
spinner.fail('Invalid API key')
|
|
107
|
-
return
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* @template T
|
|
112
|
-
* @param {T | null | undefined} value
|
|
113
|
-
* @returns {value is T}
|
|
114
|
-
*/
|
|
115
|
-
const nonNullish = value => value != null
|
|
116
|
-
|
|
117
|
-
/** @type {prompts.Choice[]} */
|
|
118
|
-
const enforcedChoices = Object.values(orgs.organizations)
|
|
119
|
-
.filter(nonNullish)
|
|
120
|
-
.filter(org => org.plan === 'enterprise')
|
|
121
|
-
.map(org => ({
|
|
122
|
-
title: org.name,
|
|
123
|
-
value: org.id
|
|
124
|
-
}))
|
|
125
|
-
|
|
126
|
-
/** @type {string[]} */
|
|
127
|
-
let enforcedOrgs = []
|
|
128
|
-
|
|
129
|
-
if (enforcedChoices.length > 1) {
|
|
130
|
-
/**
|
|
131
|
-
* @type { {id: string} }
|
|
132
|
-
*/
|
|
133
|
-
const { id } = await prompts({
|
|
134
|
-
type: 'select',
|
|
135
|
-
name: 'id',
|
|
136
|
-
hint: '\n Pick "None" if this is a personal device',
|
|
137
|
-
message: 'Which organization\'s policies should Socket enforce system-wide?',
|
|
138
|
-
choices: enforcedChoices.concat({
|
|
139
|
-
title: 'None',
|
|
140
|
-
value: null
|
|
141
|
-
}),
|
|
142
|
-
onState: promptAbortHandler
|
|
143
|
-
})
|
|
144
|
-
if (id) enforcedOrgs = [id]
|
|
145
|
-
} else if (enforcedChoices.length) {
|
|
146
|
-
/**
|
|
147
|
-
* @type { {confirmOrg: boolean} }
|
|
148
|
-
*/
|
|
149
|
-
const { confirmOrg } = await prompts({
|
|
150
|
-
type: 'confirm',
|
|
151
|
-
name: 'confirmOrg',
|
|
152
|
-
message: `Should Socket enforce ${enforcedChoices[0]?.title}'s security policies system-wide?`,
|
|
153
|
-
initial: true,
|
|
154
|
-
onState: promptAbortHandler
|
|
155
|
-
})
|
|
156
|
-
if (confirmOrg) {
|
|
157
|
-
const existing = /** @type {undefined | {value: string}} */(enforcedChoices[0])
|
|
158
|
-
if (existing) {
|
|
159
|
-
enforcedOrgs = [existing.value]
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
// MUST DO all updateSetting ON SAME TICK TO AVOID PARTIAL WRITE
|
|
164
|
-
updateSetting('enforcedOrgs', enforcedOrgs)
|
|
165
|
-
const oldKey = getSetting('apiKey')
|
|
166
|
-
updateSetting('apiKey', apiKey)
|
|
167
|
-
updateSetting('apiBaseUrl', apiBaseUrl)
|
|
168
|
-
spinner.succeed(`API credentials ${oldKey ? 'updated' : 'set'}`)
|
|
169
|
-
}
|
|
170
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import meow from 'meow'
|
|
2
|
-
import ora from 'ora'
|
|
3
|
-
|
|
4
|
-
import { updateSetting } from '../../utils/settings.js'
|
|
5
|
-
|
|
6
|
-
const description = 'Socket API logout'
|
|
7
|
-
|
|
8
|
-
/** @type {import('../../utils/meow-with-subcommands.js').CliSubcommand} */
|
|
9
|
-
export const logout = {
|
|
10
|
-
description,
|
|
11
|
-
run: async (argv, importMeta, { parentName }) => {
|
|
12
|
-
const name = parentName + ' logout'
|
|
13
|
-
const cli = meow(`
|
|
14
|
-
Usage
|
|
15
|
-
$ ${name}
|
|
16
|
-
|
|
17
|
-
Logs out of the Socket API and clears all Socket credentials from disk
|
|
18
|
-
|
|
19
|
-
Examples
|
|
20
|
-
$ ${name}
|
|
21
|
-
`, {
|
|
22
|
-
argv,
|
|
23
|
-
description,
|
|
24
|
-
importMeta,
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
if (cli.input.length) cli.showHelp()
|
|
28
|
-
|
|
29
|
-
updateSetting('apiKey', null)
|
|
30
|
-
updateSetting('apiBaseUrl', null)
|
|
31
|
-
updateSetting('apiProxy', null)
|
|
32
|
-
updateSetting('enforcedOrgs', null)
|
|
33
|
-
ora('Successfully logged out').succeed()
|
|
34
|
-
}
|
|
35
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { spawn, execSync } from 'child_process'
|
|
2
|
-
import { fileURLToPath } from 'url'
|
|
3
|
-
|
|
4
|
-
const description = 'npm wrapper functionality'
|
|
5
|
-
|
|
6
|
-
/** @type {import('../../utils/meow-with-subcommands.js').CliSubcommand} */
|
|
7
|
-
export const npm = {
|
|
8
|
-
description,
|
|
9
|
-
run: async (argv, _importMeta, _ctx) => {
|
|
10
|
-
const npmVersion = execSync('npm -v').toString()
|
|
11
|
-
const wrapperPath = fileURLToPath(new URL('../../shadow/npm-cli.cjs', import.meta.url))
|
|
12
|
-
process.exitCode = 1
|
|
13
|
-
spawn(process.execPath, [wrapperPath, ...argv], {
|
|
14
|
-
stdio: 'inherit',
|
|
15
|
-
env: {
|
|
16
|
-
...process.env,
|
|
17
|
-
NPM_VERSION: npmVersion
|
|
18
|
-
}
|
|
19
|
-
}).on('exit', (code, signal) => {
|
|
20
|
-
if (signal) {
|
|
21
|
-
process.kill(process.pid, signal)
|
|
22
|
-
} else if (code !== null) {
|
|
23
|
-
process.exit(code)
|
|
24
|
-
}
|
|
25
|
-
})
|
|
26
|
-
}
|
|
27
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'child_process'
|
|
2
|
-
import { fileURLToPath } from 'url'
|
|
3
|
-
|
|
4
|
-
const description = 'npx wrapper functionality'
|
|
5
|
-
|
|
6
|
-
/** @type {import('../../utils/meow-with-subcommands.js').CliSubcommand} */
|
|
7
|
-
export const npx = {
|
|
8
|
-
description,
|
|
9
|
-
run: async (argv, _importMeta, _ctx) => {
|
|
10
|
-
const wrapperPath = fileURLToPath(new URL('../../shadow/npx-cli.cjs', import.meta.url))
|
|
11
|
-
process.exitCode = 1
|
|
12
|
-
spawn(process.execPath, [wrapperPath, ...argv], {
|
|
13
|
-
stdio: 'inherit'
|
|
14
|
-
}).on('exit', (code, signal) => {
|
|
15
|
-
if (signal) {
|
|
16
|
-
process.kill(process.pid, signal)
|
|
17
|
-
} else if (code !== null) {
|
|
18
|
-
process.exit(code)
|
|
19
|
-
}
|
|
20
|
-
})
|
|
21
|
-
}
|
|
22
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'child_process'
|
|
2
|
-
|
|
3
|
-
import meow from 'meow'
|
|
4
|
-
|
|
5
|
-
import { validationFlags } from '../../flags/index.js'
|
|
6
|
-
import { printFlagList } from '../../utils/formatting.js'
|
|
7
|
-
|
|
8
|
-
/** @type {import('../../utils/meow-with-subcommands.js').CliSubcommand} */
|
|
9
|
-
export const rawNpm = {
|
|
10
|
-
description: 'Temporarily disable the Socket npm wrapper',
|
|
11
|
-
async run (argv, importMeta, { parentName }) {
|
|
12
|
-
const name = parentName + ' raw-npm'
|
|
13
|
-
|
|
14
|
-
setupCommand(name, rawNpm.description, argv, importMeta)
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* @param {string} name
|
|
20
|
-
* @param {string} description
|
|
21
|
-
* @param {readonly string[]} argv
|
|
22
|
-
* @param {ImportMeta} importMeta
|
|
23
|
-
* @returns {void}
|
|
24
|
-
*/
|
|
25
|
-
function setupCommand (name, description, argv, importMeta) {
|
|
26
|
-
const flags = validationFlags
|
|
27
|
-
|
|
28
|
-
const cli = meow(`
|
|
29
|
-
Usage
|
|
30
|
-
$ ${name} <npm command>
|
|
31
|
-
|
|
32
|
-
Options
|
|
33
|
-
${printFlagList(flags, 6)}
|
|
34
|
-
|
|
35
|
-
Examples
|
|
36
|
-
$ ${name} install
|
|
37
|
-
`, {
|
|
38
|
-
argv,
|
|
39
|
-
description,
|
|
40
|
-
importMeta,
|
|
41
|
-
flags
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
if (!argv[0]) {
|
|
45
|
-
cli.showHelp()
|
|
46
|
-
return
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
spawn('npm', [argv.join(' ')], {
|
|
50
|
-
stdio: 'inherit',
|
|
51
|
-
shell: true
|
|
52
|
-
}).on('exit', (code, signal) => {
|
|
53
|
-
if (signal) {
|
|
54
|
-
process.kill(process.pid, signal)
|
|
55
|
-
} else if (code !== null) {
|
|
56
|
-
process.exit(code)
|
|
57
|
-
}
|
|
58
|
-
})
|
|
59
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'child_process'
|
|
2
|
-
|
|
3
|
-
import meow from 'meow'
|
|
4
|
-
|
|
5
|
-
import { validationFlags } from '../../flags/index.js'
|
|
6
|
-
import { printFlagList } from '../../utils/formatting.js'
|
|
7
|
-
|
|
8
|
-
/** @type {import('../../utils/meow-with-subcommands.js').CliSubcommand} */
|
|
9
|
-
export const rawNpx = {
|
|
10
|
-
description: 'Temporarily disable the Socket npm/npx wrapper',
|
|
11
|
-
async run (argv, importMeta, { parentName }) {
|
|
12
|
-
const name = parentName + ' raw-npx'
|
|
13
|
-
|
|
14
|
-
setupCommand(name, rawNpx.description, argv, importMeta)
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* @param {string} name
|
|
20
|
-
* @param {string} description
|
|
21
|
-
* @param {readonly string[]} argv
|
|
22
|
-
* @param {ImportMeta} importMeta
|
|
23
|
-
* @returns {void}
|
|
24
|
-
*/
|
|
25
|
-
function setupCommand (name, description, argv, importMeta) {
|
|
26
|
-
const flags = validationFlags
|
|
27
|
-
|
|
28
|
-
const cli = meow(`
|
|
29
|
-
Usage
|
|
30
|
-
$ ${name} <npx command>
|
|
31
|
-
|
|
32
|
-
Options
|
|
33
|
-
${printFlagList(flags, 6)}
|
|
34
|
-
|
|
35
|
-
Examples
|
|
36
|
-
$ ${name} install
|
|
37
|
-
`, {
|
|
38
|
-
argv,
|
|
39
|
-
description,
|
|
40
|
-
importMeta,
|
|
41
|
-
flags
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
if (!argv[0]) {
|
|
45
|
-
cli.showHelp()
|
|
46
|
-
return
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
spawn('npx', [argv.join(' ')], {
|
|
50
|
-
stdio: 'inherit',
|
|
51
|
-
shell: true
|
|
52
|
-
}).on('exit', (code, signal) => {
|
|
53
|
-
if (signal) {
|
|
54
|
-
process.kill(process.pid, signal)
|
|
55
|
-
} else if (code !== null) {
|
|
56
|
-
process.exit(code)
|
|
57
|
-
}
|
|
58
|
-
})
|
|
59
|
-
}
|
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
|
|
3
|
-
import path from 'node:path'
|
|
4
|
-
|
|
5
|
-
import { betterAjvErrors } from '@apideck/better-ajv-errors'
|
|
6
|
-
import { readSocketConfig, SocketValidationError } from '@socketsecurity/config'
|
|
7
|
-
import meow from 'meow'
|
|
8
|
-
import ora from 'ora'
|
|
9
|
-
import { ErrorWithCause } from 'pony-cause'
|
|
10
|
-
|
|
11
|
-
import { fetchReportData, formatReportDataOutput } from './view.js'
|
|
12
|
-
import { outputFlags, validationFlags } from '../../flags/index.js'
|
|
13
|
-
import { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api-helpers.js'
|
|
14
|
-
import { ChalkOrMarkdown, logSymbols } from '../../utils/chalk-markdown.js'
|
|
15
|
-
import { InputError } from '../../utils/errors.js'
|
|
16
|
-
import { prepareFlags } from '../../utils/flags.js'
|
|
17
|
-
import { printFlagList } from '../../utils/formatting.js'
|
|
18
|
-
import { createDebugLogger } from '../../utils/misc.js'
|
|
19
|
-
import { getPackageFiles } from '../../utils/path-resolve.js'
|
|
20
|
-
import { setupSdk } from '../../utils/sdk.js'
|
|
21
|
-
|
|
22
|
-
/** @type {import('../../utils/meow-with-subcommands.js').CliSubcommand} */
|
|
23
|
-
export const create = {
|
|
24
|
-
description: 'Create a project report',
|
|
25
|
-
async run (argv, importMeta, { parentName }) {
|
|
26
|
-
const name = parentName + ' create'
|
|
27
|
-
|
|
28
|
-
const input = await setupCommand(name, create.description, argv, importMeta)
|
|
29
|
-
|
|
30
|
-
if (input) {
|
|
31
|
-
const {
|
|
32
|
-
config,
|
|
33
|
-
cwd,
|
|
34
|
-
debugLog,
|
|
35
|
-
dryRun,
|
|
36
|
-
includeAllIssues,
|
|
37
|
-
outputJson,
|
|
38
|
-
outputMarkdown,
|
|
39
|
-
packagePaths,
|
|
40
|
-
strict,
|
|
41
|
-
view,
|
|
42
|
-
} = input
|
|
43
|
-
|
|
44
|
-
const result = input && await createReport(packagePaths, { config, cwd, debugLog, dryRun })
|
|
45
|
-
|
|
46
|
-
if (result && view) {
|
|
47
|
-
const reportId = result.data.id
|
|
48
|
-
const reportData = input && await fetchReportData(reportId, { includeAllIssues, strict })
|
|
49
|
-
|
|
50
|
-
if (reportData) {
|
|
51
|
-
formatReportDataOutput(reportData, { includeAllIssues, name, outputJson, outputMarkdown, reportId, strict })
|
|
52
|
-
}
|
|
53
|
-
} else if (result) {
|
|
54
|
-
formatReportCreationOutput(result.data, { outputJson, outputMarkdown })
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Internal functions
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* @typedef CommandContext
|
|
64
|
-
* @property {import('@socketsecurity/config').SocketYml|undefined} config
|
|
65
|
-
* @property {string} cwd
|
|
66
|
-
* @property {typeof console.error} debugLog
|
|
67
|
-
* @property {boolean} dryRun
|
|
68
|
-
* @property {boolean} includeAllIssues
|
|
69
|
-
* @property {boolean} outputJson
|
|
70
|
-
* @property {boolean} outputMarkdown
|
|
71
|
-
* @property {string[]} packagePaths
|
|
72
|
-
* @property {boolean} strict
|
|
73
|
-
* @property {boolean} view
|
|
74
|
-
*/
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* @param {string} name
|
|
78
|
-
* @param {string} description
|
|
79
|
-
* @param {readonly string[]} argv
|
|
80
|
-
* @param {ImportMeta} importMeta
|
|
81
|
-
* @returns {Promise<void|CommandContext>}
|
|
82
|
-
*/
|
|
83
|
-
async function setupCommand (name, description, argv, importMeta) {
|
|
84
|
-
const flags = prepareFlags({
|
|
85
|
-
...outputFlags,
|
|
86
|
-
...validationFlags,
|
|
87
|
-
debug: {
|
|
88
|
-
type: 'boolean',
|
|
89
|
-
shortFlag: 'd',
|
|
90
|
-
default: false,
|
|
91
|
-
description: 'Output debug information',
|
|
92
|
-
},
|
|
93
|
-
dryRun: {
|
|
94
|
-
type: 'boolean',
|
|
95
|
-
default: false,
|
|
96
|
-
description: 'Only output what will be done without actually doing it',
|
|
97
|
-
},
|
|
98
|
-
view: {
|
|
99
|
-
type: 'boolean',
|
|
100
|
-
shortFlag: 'v',
|
|
101
|
-
default: false,
|
|
102
|
-
description: 'Will wait for and return the created report'
|
|
103
|
-
},
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
const cli = meow(`
|
|
107
|
-
Usage
|
|
108
|
-
$ ${name} <paths-to-package-folders-and-files>
|
|
109
|
-
|
|
110
|
-
Uploads the specified "package.json" and lock files for JavaScript, Python, and Go dependency manifests.
|
|
111
|
-
If any folder is specified, the ones found in there recursively are uploaded.
|
|
112
|
-
|
|
113
|
-
Supports globbing such as "**/package.json", "**/requirements.txt", "**/pyproject.toml", and "**/go.mod".
|
|
114
|
-
|
|
115
|
-
Ignores any file specified in your project's ".gitignore", your project's
|
|
116
|
-
"socket.yml" file's "projectIgnorePaths" and also has a sensible set of
|
|
117
|
-
default ignores from the "ignore-by-default" module.
|
|
118
|
-
|
|
119
|
-
Options
|
|
120
|
-
${printFlagList({
|
|
121
|
-
'all': 'Include all issues',
|
|
122
|
-
'debug': 'Output debug information',
|
|
123
|
-
'dry-run': 'Only output what will be done without actually doing it',
|
|
124
|
-
'json': 'Output result as json',
|
|
125
|
-
'markdown': 'Output result as markdown',
|
|
126
|
-
'strict': 'Exits with an error code if any matching issues are found',
|
|
127
|
-
'view': 'Will wait for and return the created report'
|
|
128
|
-
}, 6)}
|
|
129
|
-
|
|
130
|
-
Examples
|
|
131
|
-
$ ${name} .
|
|
132
|
-
$ ${name} '**/package.json'
|
|
133
|
-
$ ${name} /path/to/a/package.json /path/to/another/package.json
|
|
134
|
-
$ ${name} . --view --json
|
|
135
|
-
`, {
|
|
136
|
-
argv,
|
|
137
|
-
description,
|
|
138
|
-
importMeta,
|
|
139
|
-
flags,
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
const {
|
|
143
|
-
all: includeAllIssues,
|
|
144
|
-
dryRun,
|
|
145
|
-
json: outputJson,
|
|
146
|
-
markdown: outputMarkdown,
|
|
147
|
-
strict,
|
|
148
|
-
view,
|
|
149
|
-
} = cli.flags
|
|
150
|
-
|
|
151
|
-
if (!cli.input[0]) {
|
|
152
|
-
cli.showHelp()
|
|
153
|
-
return
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const debugLog = createDebugLogger(dryRun || cli.flags.debug)
|
|
157
|
-
|
|
158
|
-
// TODO: Allow setting a custom cwd and/or configFile path?
|
|
159
|
-
const cwd = process.cwd()
|
|
160
|
-
const absoluteConfigPath = path.join(cwd, 'socket.yml')
|
|
161
|
-
|
|
162
|
-
const config = await readSocketConfig(absoluteConfigPath)
|
|
163
|
-
.catch(/** @param {unknown} cause */ cause => {
|
|
164
|
-
if (cause && typeof cause === 'object' && cause instanceof SocketValidationError) {
|
|
165
|
-
// Inspired by workbox-build: https://github.com/GoogleChrome/workbox/blob/95f97a207fd51efb3f8a653f6e3e58224183a778/packages/workbox-build/src/lib/validate-options.ts#L68-L71
|
|
166
|
-
const betterErrors = betterAjvErrors({
|
|
167
|
-
basePath: 'config',
|
|
168
|
-
data: cause.data,
|
|
169
|
-
errors: cause.validationErrors,
|
|
170
|
-
// @ts-ignore
|
|
171
|
-
schema: cause.schema,
|
|
172
|
-
})
|
|
173
|
-
throw new InputError(
|
|
174
|
-
'The socket.yml config is not valid',
|
|
175
|
-
betterErrors.map((err) => `[${err.path}] ${err.message}.${err.suggestion ? err.suggestion : ''}`).join('\n')
|
|
176
|
-
)
|
|
177
|
-
} else {
|
|
178
|
-
throw new ErrorWithCause('Failed to read socket.yml config', { cause })
|
|
179
|
-
}
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
const socketSdk = await setupSdk()
|
|
183
|
-
const supportedFiles = await socketSdk.getReportSupportedFiles()
|
|
184
|
-
.then(res => {
|
|
185
|
-
if (!res.success) handleUnsuccessfulApiResponse('getReportSupportedFiles', res, ora())
|
|
186
|
-
return res.data
|
|
187
|
-
}).catch(
|
|
188
|
-
/** @type {(cause: Error) => never} */
|
|
189
|
-
(cause) => {
|
|
190
|
-
throw new ErrorWithCause('Failed getting supported files for report', { cause })
|
|
191
|
-
})
|
|
192
|
-
|
|
193
|
-
const packagePaths = await getPackageFiles(cwd, cli.input, config, supportedFiles, debugLog)
|
|
194
|
-
|
|
195
|
-
return {
|
|
196
|
-
config,
|
|
197
|
-
cwd,
|
|
198
|
-
debugLog,
|
|
199
|
-
dryRun,
|
|
200
|
-
includeAllIssues,
|
|
201
|
-
outputJson,
|
|
202
|
-
outputMarkdown,
|
|
203
|
-
packagePaths,
|
|
204
|
-
strict,
|
|
205
|
-
view,
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* @param {string[]} packagePaths
|
|
211
|
-
* @param {Pick<CommandContext, 'config' | 'cwd' | 'debugLog' | 'dryRun'>} context
|
|
212
|
-
* @returns {Promise<void|import('@socketsecurity/sdk').SocketSdkReturnType<'createReport'>>}
|
|
213
|
-
*/
|
|
214
|
-
async function createReport (packagePaths, { config, cwd, debugLog, dryRun }) {
|
|
215
|
-
debugLog('Uploading:', packagePaths.join(`\n${logSymbols.info} Uploading: `))
|
|
216
|
-
|
|
217
|
-
if (dryRun) {
|
|
218
|
-
return
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
const socketSdk = await setupSdk()
|
|
222
|
-
const spinner = ora(`Creating report with ${packagePaths.length} package files`).start()
|
|
223
|
-
const apiCall = socketSdk.createReportFromFilePaths(packagePaths, cwd, config?.issueRules)
|
|
224
|
-
const result = await handleApiCall(apiCall, 'creating report')
|
|
225
|
-
|
|
226
|
-
if (result.success === false) {
|
|
227
|
-
return handleUnsuccessfulApiResponse('createReport', result, spinner)
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// Conclude the status of the API call
|
|
231
|
-
|
|
232
|
-
spinner.succeed()
|
|
233
|
-
|
|
234
|
-
return result
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* @param {import('@socketsecurity/sdk').SocketSdkReturnType<'createReport'>["data"]} data
|
|
239
|
-
* @param {Pick<CommandContext, 'outputJson' | 'outputMarkdown'>} context
|
|
240
|
-
* @returns {void}
|
|
241
|
-
*/
|
|
242
|
-
function formatReportCreationOutput (data, { outputJson, outputMarkdown }) {
|
|
243
|
-
if (outputJson) {
|
|
244
|
-
console.log(JSON.stringify(data, undefined, 2))
|
|
245
|
-
return
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
const format = new ChalkOrMarkdown(!!outputMarkdown)
|
|
249
|
-
|
|
250
|
-
console.log('\nNew report: ' + format.hyperlink(data.id, data.url, { fallbackToUrl: true }))
|
|
251
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { create } from './create.js'
|
|
2
|
-
import { view } from './view.js'
|
|
3
|
-
import { meowWithSubcommands } from '../../utils/meow-with-subcommands.js'
|
|
4
|
-
|
|
5
|
-
const description = 'Project report related commands'
|
|
6
|
-
|
|
7
|
-
/** @type {import('../../utils/meow-with-subcommands.js').CliSubcommand} */
|
|
8
|
-
export const report = {
|
|
9
|
-
description,
|
|
10
|
-
run: async (argv, importMeta, { parentName }) => {
|
|
11
|
-
await meowWithSubcommands(
|
|
12
|
-
{
|
|
13
|
-
create,
|
|
14
|
-
view,
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
argv,
|
|
18
|
-
description,
|
|
19
|
-
importMeta,
|
|
20
|
-
name: parentName + ' report',
|
|
21
|
-
}
|
|
22
|
-
)
|
|
23
|
-
}
|
|
24
|
-
}
|