@socketsecurity/cli 0.3.0 → 0.4.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/LICENSE +1 -1
- package/README.md +8 -1
- package/cli.js +6 -0
- package/lib/commands/report/create.js +9 -5
- package/lib/commands/report/index.js +1 -1
- package/lib/commands/report/view.js +15 -16
- package/lib/utils/meow-with-subcommands.js +37 -18
- package/lib/utils/path-resolve.js +3 -0
- package/lib/utils/sdk.js +8 -1
- package/lib/utils/type-helpers.js +0 -10
- package/package.json +12 -12
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# Socket CLI
|
|
2
2
|
|
|
3
|
+
[](https://socket.dev/npm/package/@socketsecurity/cli)
|
|
3
4
|
[](https://www.npmjs.com/package/@socketsecurity/cli)
|
|
4
5
|
[](https://github.com/SocketDev/eslint-config)
|
|
5
6
|
[](https://twitter.com/SocketSecurity)
|
|
@@ -33,6 +34,12 @@ socket report view QXU8PmK7LfH608RAwfIKdbcHgwEd_ZeWJ9QEGv05FJUQ
|
|
|
33
34
|
|
|
34
35
|
* `socket report view <report-id>` - looks up issues and scores from a report
|
|
35
36
|
|
|
37
|
+
## Aliases
|
|
38
|
+
|
|
39
|
+
All aliases supports flags and arguments of the commands they alias.
|
|
40
|
+
|
|
41
|
+
* `socket ci` - alias for `socket report create --view --strict` which creates a report and quits with an exit code if the result is unhealthy. Use like eg. `socket ci .` for a report for the current folder
|
|
42
|
+
|
|
36
43
|
## Flags
|
|
37
44
|
|
|
38
45
|
### Command specific flags
|
|
@@ -47,7 +54,7 @@ socket report view QXU8PmK7LfH608RAwfIKdbcHgwEd_ZeWJ9QEGv05FJUQ
|
|
|
47
54
|
## Strictness flags
|
|
48
55
|
|
|
49
56
|
* `--all` - by default only `high` and `critical` issues are included, by setting this flag all issues will be included
|
|
50
|
-
* `--strict` - when set, exits with an error code if
|
|
57
|
+
* `--strict` - when set, exits with an error code if report result is deemed unhealthy
|
|
51
58
|
|
|
52
59
|
### Other flags
|
|
53
60
|
|
package/cli.js
CHANGED
|
@@ -18,6 +18,12 @@ try {
|
|
|
18
18
|
await meowWithSubcommands(
|
|
19
19
|
cliCommands,
|
|
20
20
|
{
|
|
21
|
+
aliases: {
|
|
22
|
+
ci: {
|
|
23
|
+
description: 'Alias for "report create --view --strict"',
|
|
24
|
+
argv: ['report', 'create', '--view', '--strict']
|
|
25
|
+
},
|
|
26
|
+
},
|
|
21
27
|
argv: process.argv.slice(2),
|
|
22
28
|
name: 'socket',
|
|
23
29
|
importMeta: import.meta
|
|
@@ -8,6 +8,7 @@ import meow from 'meow'
|
|
|
8
8
|
import ora from 'ora'
|
|
9
9
|
import { ErrorWithCause } from 'pony-cause'
|
|
10
10
|
|
|
11
|
+
import { fetchReportData, formatReportDataOutput } from './view.js'
|
|
11
12
|
import { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api-helpers.js'
|
|
12
13
|
import { ChalkOrMarkdown, logSymbols } from '../../utils/chalk-markdown.js'
|
|
13
14
|
import { InputError } from '../../utils/errors.js'
|
|
@@ -15,7 +16,6 @@ import { printFlagList } from '../../utils/formatting.js'
|
|
|
15
16
|
import { createDebugLogger } from '../../utils/misc.js'
|
|
16
17
|
import { getPackageFiles } from '../../utils/path-resolve.js'
|
|
17
18
|
import { setupSdk } from '../../utils/sdk.js'
|
|
18
|
-
import { fetchReportData, formatReportDataOutput } from './view.js'
|
|
19
19
|
|
|
20
20
|
/** @type {import('../../utils/meow-with-subcommands').CliSubcommand} */
|
|
21
21
|
export const create = {
|
|
@@ -27,6 +27,7 @@ export const create = {
|
|
|
27
27
|
|
|
28
28
|
if (input) {
|
|
29
29
|
const {
|
|
30
|
+
config,
|
|
30
31
|
cwd,
|
|
31
32
|
debugLog,
|
|
32
33
|
dryRun,
|
|
@@ -38,7 +39,7 @@ export const create = {
|
|
|
38
39
|
view,
|
|
39
40
|
} = input
|
|
40
41
|
|
|
41
|
-
const result = input && await createReport(packagePaths, { cwd, debugLog, dryRun })
|
|
42
|
+
const result = input && await createReport(packagePaths, { config, cwd, debugLog, dryRun })
|
|
42
43
|
|
|
43
44
|
if (result && view) {
|
|
44
45
|
const reportId = result.data.id
|
|
@@ -58,6 +59,7 @@ export const create = {
|
|
|
58
59
|
|
|
59
60
|
/**
|
|
60
61
|
* @typedef CommandContext
|
|
62
|
+
* @property {import('@socketsecurity/config').SocketYml|undefined} config
|
|
61
63
|
* @property {string} cwd
|
|
62
64
|
* @property {typeof console.error} debugLog
|
|
63
65
|
* @property {boolean} dryRun
|
|
@@ -191,6 +193,7 @@ async function setupCommand (name, description, argv, importMeta) {
|
|
|
191
193
|
const packagePaths = await getPackageFiles(cwd, cli.input, config, debugLog)
|
|
192
194
|
|
|
193
195
|
return {
|
|
196
|
+
config,
|
|
194
197
|
cwd,
|
|
195
198
|
debugLog,
|
|
196
199
|
dryRun,
|
|
@@ -205,10 +208,10 @@ async function setupCommand (name, description, argv, importMeta) {
|
|
|
205
208
|
|
|
206
209
|
/**
|
|
207
210
|
* @param {string[]} packagePaths
|
|
208
|
-
* @param {Pick<CommandContext, 'cwd' | 'debugLog' | 'dryRun'>} context
|
|
211
|
+
* @param {Pick<CommandContext, 'config' | 'cwd' | 'debugLog' | 'dryRun'>} context
|
|
209
212
|
* @returns {Promise<void|import('@socketsecurity/sdk').SocketSdkReturnType<'createReport'>>}
|
|
210
213
|
*/
|
|
211
|
-
async function createReport (packagePaths, { cwd, debugLog, dryRun }) {
|
|
214
|
+
async function createReport (packagePaths, { config, cwd, debugLog, dryRun }) {
|
|
212
215
|
debugLog('Uploading:', packagePaths.join(`\n${logSymbols.info} Uploading: `))
|
|
213
216
|
|
|
214
217
|
if (dryRun) {
|
|
@@ -217,7 +220,8 @@ async function createReport (packagePaths, { cwd, debugLog, dryRun }) {
|
|
|
217
220
|
|
|
218
221
|
const socketSdk = await setupSdk()
|
|
219
222
|
const spinner = ora(`Creating report with ${packagePaths.length} package files`).start()
|
|
220
|
-
const
|
|
223
|
+
const apiCall = socketSdk.createReportFromFilePaths(packagePaths, cwd, config?.issueRules)
|
|
224
|
+
const result = await handleApiCall(apiCall, spinner, 'creating report')
|
|
221
225
|
|
|
222
226
|
if (result.success === false) {
|
|
223
227
|
return handleUnsuccessfulApiResponse(result, spinner)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { meowWithSubcommands } from '../../utils/meow-with-subcommands.js'
|
|
2
1
|
import { create } from './create.js'
|
|
3
2
|
import { view } from './view.js'
|
|
3
|
+
import { meowWithSubcommands } from '../../utils/meow-with-subcommands.js'
|
|
4
4
|
|
|
5
5
|
const description = 'Project report related commands'
|
|
6
6
|
|
|
@@ -9,7 +9,6 @@ import { ChalkOrMarkdown } from '../../utils/chalk-markdown.js'
|
|
|
9
9
|
import { InputError } from '../../utils/errors.js'
|
|
10
10
|
import { getSeverityCount, formatSeverityCount } from '../../utils/format-issues.js'
|
|
11
11
|
import { printFlagList } from '../../utils/formatting.js'
|
|
12
|
-
import { objectSome } from '../../utils/misc.js'
|
|
13
12
|
import { setupSdk } from '../../utils/sdk.js'
|
|
14
13
|
|
|
15
14
|
/** @type {import('../../utils/meow-with-subcommands').CliSubcommand} */
|
|
@@ -56,7 +55,7 @@ function setupCommand (name, description, argv, importMeta) {
|
|
|
56
55
|
'--all': 'Include all issues',
|
|
57
56
|
'--json': 'Output result as json',
|
|
58
57
|
'--markdown': 'Output result as markdown',
|
|
59
|
-
'--strict': 'Exits with an error code if
|
|
58
|
+
'--strict': 'Exits with an error code if report result is deemed unhealthy',
|
|
60
59
|
}, 6)}
|
|
61
60
|
|
|
62
61
|
Examples
|
|
@@ -119,9 +118,7 @@ function setupCommand (name, description, argv, importMeta) {
|
|
|
119
118
|
}
|
|
120
119
|
|
|
121
120
|
/**
|
|
122
|
-
* @typedef ReportData
|
|
123
|
-
* @property {import('@socketsecurity/sdk').SocketSdkReturnType<'getReport'>["data"]} data
|
|
124
|
-
* @property {Record<import('../../utils/format-issues').SocketIssue['severity'], number>} severityCount
|
|
121
|
+
* @typedef {import('@socketsecurity/sdk').SocketSdkReturnType<'getReport'>["data"]} ReportData
|
|
125
122
|
*/
|
|
126
123
|
|
|
127
124
|
/**
|
|
@@ -142,27 +139,29 @@ export async function fetchReportData (reportId, { includeAllIssues, strict }) {
|
|
|
142
139
|
|
|
143
140
|
// Conclude the status of the API call
|
|
144
141
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
142
|
+
if (strict) {
|
|
143
|
+
if (result.data.healthy) {
|
|
144
|
+
spinner.succeed('Report result is healthy and great!')
|
|
145
|
+
} else {
|
|
146
|
+
spinner.fail('Report result deemed unhealthy for project')
|
|
147
|
+
}
|
|
148
|
+
} else if (result.data.healthy === false) {
|
|
149
|
+
const severityCount = getSeverityCount(result.data.issues, includeAllIssues ? undefined : 'high')
|
|
148
150
|
const issueSummary = formatSeverityCount(severityCount)
|
|
149
|
-
spinner
|
|
151
|
+
spinner.succeed(`Report has these issues: ${issueSummary}`)
|
|
150
152
|
} else {
|
|
151
153
|
spinner.succeed('Report has no issues')
|
|
152
154
|
}
|
|
153
155
|
|
|
154
|
-
return
|
|
155
|
-
data: result.data,
|
|
156
|
-
severityCount,
|
|
157
|
-
}
|
|
156
|
+
return result.data
|
|
158
157
|
}
|
|
159
158
|
|
|
160
159
|
/**
|
|
161
|
-
* @param {ReportData}
|
|
160
|
+
* @param {ReportData} data
|
|
162
161
|
* @param {{ name: string } & CommandContext} context
|
|
163
162
|
* @returns {void}
|
|
164
163
|
*/
|
|
165
|
-
export function formatReportDataOutput (
|
|
164
|
+
export function formatReportDataOutput (data, { name, outputJson, outputMarkdown, reportId, strict }) {
|
|
166
165
|
if (outputJson) {
|
|
167
166
|
console.log(JSON.stringify(data, undefined, 2))
|
|
168
167
|
} else {
|
|
@@ -175,7 +174,7 @@ export function formatReportDataOutput ({ data, severityCount }, { name, outputJ
|
|
|
175
174
|
}
|
|
176
175
|
}
|
|
177
176
|
|
|
178
|
-
if (strict &&
|
|
177
|
+
if (strict && data.healthy === false) {
|
|
179
178
|
process.exit(1)
|
|
180
179
|
}
|
|
181
180
|
}
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import meow from 'meow'
|
|
2
2
|
|
|
3
3
|
import { printFlagList, printHelpList } from './formatting.js'
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @typedef CliAlias
|
|
7
|
+
* @property {string} description
|
|
8
|
+
* @property {readonly string[]} argv
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** @typedef {Record<string, CliAlias>} CliAliases */
|
|
5
12
|
|
|
6
13
|
/**
|
|
7
14
|
* @callback CliSubcommandRun
|
|
@@ -20,39 +27,51 @@ import { ensureIsKeyOf } from './type-helpers.js'
|
|
|
20
27
|
/**
|
|
21
28
|
* @template {import('meow').AnyFlags} Flags
|
|
22
29
|
* @param {Record<string, CliSubcommand>} subcommands
|
|
23
|
-
* @param {import('meow').Options<Flags> & { argv: readonly string[], name: string }} options
|
|
30
|
+
* @param {import('meow').Options<Flags> & { aliases?: CliAliases, argv: readonly string[], name: string }} options
|
|
24
31
|
* @returns {Promise<void>}
|
|
25
32
|
*/
|
|
26
33
|
export async function meowWithSubcommands (subcommands, options) {
|
|
27
34
|
const {
|
|
35
|
+
aliases = {},
|
|
28
36
|
argv,
|
|
29
37
|
name,
|
|
30
38
|
importMeta,
|
|
31
39
|
...additionalOptions
|
|
32
40
|
} = options
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
|
|
42
|
+
const [commandOrAliasName, ...rawCommandArgv] = argv
|
|
43
|
+
|
|
44
|
+
// If we got at least some args, then lets find out if we can find a command
|
|
45
|
+
if (commandOrAliasName) {
|
|
46
|
+
const alias = aliases[commandOrAliasName]
|
|
47
|
+
|
|
48
|
+
// First: Resolve argv data from alias if its an alias that's been given
|
|
49
|
+
const [commandName, ...commandArgv] = alias
|
|
50
|
+
? [...alias.argv, ...rawCommandArgv]
|
|
51
|
+
: [commandOrAliasName, ...rawCommandArgv]
|
|
52
|
+
|
|
53
|
+
// Second: Find a command definition using that data
|
|
54
|
+
const commandDefinition = commandName ? subcommands[commandName] : undefined
|
|
55
|
+
|
|
56
|
+
// Third: If a valid command has been found, then we run it...
|
|
57
|
+
if (commandDefinition) {
|
|
58
|
+
return await commandDefinition.run(
|
|
59
|
+
commandArgv,
|
|
60
|
+
importMeta,
|
|
61
|
+
{
|
|
62
|
+
parentName: name
|
|
63
|
+
}
|
|
64
|
+
)
|
|
65
|
+
}
|
|
47
66
|
}
|
|
48
67
|
|
|
49
|
-
// ...else provide basic instructions and help
|
|
68
|
+
// ...else we provide basic instructions and help
|
|
50
69
|
const cli = meow(`
|
|
51
70
|
Usage
|
|
52
71
|
$ ${name} <command>
|
|
53
72
|
|
|
54
73
|
Commands
|
|
55
|
-
${printHelpList(subcommands, 6)}
|
|
74
|
+
${printHelpList({ ...subcommands, ...aliases }, 6)}
|
|
56
75
|
|
|
57
76
|
Options
|
|
58
77
|
${printFlagList({}, 6)}
|
|
@@ -39,6 +39,9 @@ const GLOB_IGNORE = [
|
|
|
39
39
|
* @throws {InputError}
|
|
40
40
|
*/
|
|
41
41
|
export async function getPackageFiles (cwd, inputPaths, config, debugLog) {
|
|
42
|
+
debugLog(`Globbed resolving ${inputPaths.length} paths:`, inputPaths)
|
|
43
|
+
|
|
44
|
+
// TODO: Does not support `~/` paths
|
|
42
45
|
const entries = await globby(inputPaths, {
|
|
43
46
|
absolute: true,
|
|
44
47
|
cwd,
|
package/lib/utils/sdk.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readFile } from 'node:fs/promises'
|
|
2
|
+
import { dirname, join } from 'node:path'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
|
|
5
|
+
import { SocketSdk, createUserAgentFromPkgJson } from '@socketsecurity/sdk'
|
|
2
6
|
import isInteractive from 'is-interactive'
|
|
3
7
|
import prompts from 'prompts'
|
|
4
8
|
|
|
@@ -34,11 +38,14 @@ export async function setupSdk () {
|
|
|
34
38
|
https: new HttpsProxyAgent({ proxy: process.env['SOCKET_SECURITY_API_PROXY'] }),
|
|
35
39
|
}
|
|
36
40
|
}
|
|
41
|
+
const packageJsonPath = join(dirname(fileURLToPath(import.meta.url)), '../../package.json')
|
|
42
|
+
const packageJson = await readFile(packageJsonPath, 'utf8')
|
|
37
43
|
|
|
38
44
|
/** @type {import('@socketsecurity/sdk').SocketSdkOptions} */
|
|
39
45
|
const sdkOptions = {
|
|
40
46
|
agent,
|
|
41
47
|
baseUrl: process.env['SOCKET_SECURITY_API_BASE_URL'],
|
|
48
|
+
userAgent: createUserAgentFromPkgJson(JSON.parse(packageJson))
|
|
42
49
|
}
|
|
43
50
|
|
|
44
51
|
return new SocketSdk(apiKey || '', sdkOptions)
|
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @template T
|
|
3
|
-
* @param {T} obj
|
|
4
|
-
* @param {string|undefined} key
|
|
5
|
-
* @returns {(keyof T) | undefined}
|
|
6
|
-
*/
|
|
7
|
-
export function ensureIsKeyOf (obj, key) {
|
|
8
|
-
return /** @type {keyof T} */ (key && Object.prototype.hasOwnProperty.call(obj, key) ? key : undefined)
|
|
9
|
-
}
|
|
10
|
-
|
|
11
1
|
/**
|
|
12
2
|
* @param {unknown} value
|
|
13
3
|
* @returns {value is NodeJS.ErrnoException}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@socketsecurity/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "CLI tool for Socket.dev",
|
|
5
5
|
"homepage": "http://github.com/SocketDev/socket-cli-js",
|
|
6
6
|
"repository": {
|
|
@@ -47,36 +47,36 @@
|
|
|
47
47
|
"@types/node": "^14.18.31",
|
|
48
48
|
"@types/prompts": "^2.4.1",
|
|
49
49
|
"@types/update-notifier": "^6.0.1",
|
|
50
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
51
|
-
"@typescript-eslint/parser": "^5.
|
|
50
|
+
"@typescript-eslint/eslint-plugin": "^5.48.2",
|
|
51
|
+
"@typescript-eslint/parser": "^5.48.2",
|
|
52
52
|
"c8": "^7.12.0",
|
|
53
53
|
"chai": "^4.3.6",
|
|
54
54
|
"chai-as-promised": "^7.1.1",
|
|
55
55
|
"dependency-check": "^5.0.0-7",
|
|
56
|
-
"eslint": "^8.
|
|
56
|
+
"eslint": "^8.32.0",
|
|
57
57
|
"eslint-config-standard": "^17.0.0",
|
|
58
58
|
"eslint-config-standard-jsx": "^11.0.0",
|
|
59
|
-
"eslint-import-resolver-typescript": "^3.5.
|
|
60
|
-
"eslint-plugin-import": "^2.
|
|
59
|
+
"eslint-import-resolver-typescript": "^3.5.3",
|
|
60
|
+
"eslint-plugin-import": "^2.27.5",
|
|
61
61
|
"eslint-plugin-jsdoc": "^39.5.0",
|
|
62
|
-
"eslint-plugin-n": "^15.
|
|
62
|
+
"eslint-plugin-n": "^15.6.1",
|
|
63
63
|
"eslint-plugin-promise": "^6.1.1",
|
|
64
|
-
"eslint-plugin-react": "^7.
|
|
64
|
+
"eslint-plugin-react": "^7.32.1",
|
|
65
65
|
"eslint-plugin-react-hooks": "^4.6.0",
|
|
66
66
|
"eslint-plugin-unicorn": "^45.0.2",
|
|
67
67
|
"husky": "^8.0.1",
|
|
68
68
|
"installed-check": "^6.0.5",
|
|
69
69
|
"mocha": "^10.0.0",
|
|
70
70
|
"mock-fs": "^5.2.0",
|
|
71
|
-
"nock": "^13.
|
|
71
|
+
"nock": "^13.3.0",
|
|
72
72
|
"npm-run-all2": "^6.0.2",
|
|
73
73
|
"type-coverage": "^2.24.1",
|
|
74
|
-
"typescript": "~4.9.
|
|
74
|
+
"typescript": "~4.9.4"
|
|
75
75
|
},
|
|
76
76
|
"dependencies": {
|
|
77
77
|
"@apideck/better-ajv-errors": "^0.3.6",
|
|
78
|
-
"@socketsecurity/config": "^
|
|
79
|
-
"@socketsecurity/sdk": "^0.
|
|
78
|
+
"@socketsecurity/config": "^2.0.0",
|
|
79
|
+
"@socketsecurity/sdk": "^0.5.2",
|
|
80
80
|
"chalk": "^5.1.2",
|
|
81
81
|
"globby": "^13.1.3",
|
|
82
82
|
"hpagent": "^1.2.0",
|