@socketsecurity/cli 0.6.0 → 0.7.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/lib/commands/index.js +2 -0
- package/lib/commands/login/index.js +66 -0
- package/lib/commands/logout/index.js +32 -0
- package/lib/commands/report/create.js +11 -1
- package/lib/shadow/npm-injection.cjs +5 -1
- package/lib/utils/api-helpers.js +1 -1
- package/lib/utils/path-resolve.js +61 -48
- package/lib/utils/sdk.js +6 -7
- package/lib/utils/settings.js +57 -0
- package/package.json +5 -3
package/lib/commands/index.js
CHANGED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import isInteractive from 'is-interactive'
|
|
2
|
+
import meow from 'meow'
|
|
3
|
+
import ora from 'ora'
|
|
4
|
+
import prompts from 'prompts'
|
|
5
|
+
|
|
6
|
+
import { ChalkOrMarkdown } from '../../utils/chalk-markdown.js'
|
|
7
|
+
import { AuthError, InputError } from '../../utils/errors.js'
|
|
8
|
+
import { setupSdk } from '../../utils/sdk.js'
|
|
9
|
+
import { getSetting, updateSetting } from '../../utils/settings.js'
|
|
10
|
+
|
|
11
|
+
const description = 'Socket API login'
|
|
12
|
+
|
|
13
|
+
/** @type {import('../../utils/meow-with-subcommands').CliSubcommand} */
|
|
14
|
+
export const login = {
|
|
15
|
+
description,
|
|
16
|
+
run: async (argv, importMeta, { parentName }) => {
|
|
17
|
+
const name = parentName + ' login'
|
|
18
|
+
const cli = meow(`
|
|
19
|
+
Usage
|
|
20
|
+
$ ${name}
|
|
21
|
+
|
|
22
|
+
Logs into the Socket API by prompting for an API key
|
|
23
|
+
|
|
24
|
+
Examples
|
|
25
|
+
$ ${name}
|
|
26
|
+
`, {
|
|
27
|
+
argv,
|
|
28
|
+
description,
|
|
29
|
+
importMeta,
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
if (cli.input.length) cli.showHelp()
|
|
33
|
+
|
|
34
|
+
if (!isInteractive()) {
|
|
35
|
+
throw new InputError('cannot prompt for credentials in a non-interactive shell')
|
|
36
|
+
}
|
|
37
|
+
const format = new ChalkOrMarkdown(false)
|
|
38
|
+
const { apiKey } = await prompts({
|
|
39
|
+
type: 'password',
|
|
40
|
+
name: 'apiKey',
|
|
41
|
+
message: `Enter your ${format.hyperlink(
|
|
42
|
+
'Socket.dev API key',
|
|
43
|
+
'https://docs.socket.dev/docs/api-keys'
|
|
44
|
+
)}`,
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
if (!apiKey) {
|
|
48
|
+
ora('API key not updated').warn()
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const spinner = ora('Verifying API key...').start()
|
|
53
|
+
|
|
54
|
+
const oldKey = getSetting('apiKey')
|
|
55
|
+
updateSetting('apiKey', apiKey)
|
|
56
|
+
try {
|
|
57
|
+
const sdk = await setupSdk()
|
|
58
|
+
const quota = await sdk.getQuota()
|
|
59
|
+
if (!quota.success) throw new AuthError()
|
|
60
|
+
spinner.succeed(`API key ${oldKey ? 'updated' : 'set'}`)
|
|
61
|
+
} catch (e) {
|
|
62
|
+
updateSetting('apiKey', oldKey)
|
|
63
|
+
spinner.fail('Invalid API key')
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
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').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
|
+
ora('Successfully logged out').succeed()
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -181,7 +181,17 @@ async function setupCommand (name, description, argv, importMeta) {
|
|
|
181
181
|
}
|
|
182
182
|
})
|
|
183
183
|
|
|
184
|
-
|
|
184
|
+
// TODO: setupSdk(getDefaultKey() || FREE_API_KEY)
|
|
185
|
+
const socketSdk = await setupSdk()
|
|
186
|
+
const supportedFiles = await socketSdk.getReportSupportedFiles()
|
|
187
|
+
.then(res => {
|
|
188
|
+
if (!res.success) handleUnsuccessfulApiResponse('getReportSupportedFiles', res, ora())
|
|
189
|
+
return res.data
|
|
190
|
+
}).catch(cause => {
|
|
191
|
+
throw new ErrorWithCause('Failed getting supported files for report', { cause })
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
const packagePaths = await getPackageFiles(cwd, cli.input, config, supportedFiles, debugLog)
|
|
185
195
|
|
|
186
196
|
return {
|
|
187
197
|
config,
|
|
@@ -12,6 +12,7 @@ const oraPromise = import('ora')
|
|
|
12
12
|
const isInteractivePromise = import('is-interactive')
|
|
13
13
|
const chalkPromise = import('chalk')
|
|
14
14
|
const chalkMarkdownPromise = import('../utils/chalk-markdown.js')
|
|
15
|
+
const settingsPromise = import('../utils/settings.js')
|
|
15
16
|
const ipc_version = require('../../package.json').version
|
|
16
17
|
|
|
17
18
|
try {
|
|
@@ -32,7 +33,9 @@ try {
|
|
|
32
33
|
* @typedef {import('stream').Writable} Writable
|
|
33
34
|
*/
|
|
34
35
|
|
|
35
|
-
const
|
|
36
|
+
const pubTokenPromise = settingsPromise.then(({ getSetting }) =>
|
|
37
|
+
getSetting('apiKey') || 'sktsec_t_--RAN5U4ivauy4w37-6aoKyYPDt5ZbaT5JBVMqiwKo_api'
|
|
38
|
+
);
|
|
36
39
|
|
|
37
40
|
// shadow `npm` and `npx` to mitigate subshells
|
|
38
41
|
require('./link.cjs')(fs.realpathSync(path.join(__dirname, 'bin')), 'npm')
|
|
@@ -64,6 +67,7 @@ const pkgidParts = (pkgid) => {
|
|
|
64
67
|
async function * batchScan (
|
|
65
68
|
pkgids
|
|
66
69
|
) {
|
|
70
|
+
const pubToken = await pubTokenPromise
|
|
67
71
|
const query = {
|
|
68
72
|
packages: pkgids.map(pkgid => {
|
|
69
73
|
const { name, version } = pkgidParts(pkgid)
|
package/lib/utils/api-helpers.js
CHANGED
|
@@ -8,7 +8,7 @@ import { AuthError } from './errors.js'
|
|
|
8
8
|
* @param {T} _name
|
|
9
9
|
* @param {import('@socketsecurity/sdk').SocketSdkErrorType<T>} result
|
|
10
10
|
* @param {import('ora').Ora} spinner
|
|
11
|
-
* @returns {
|
|
11
|
+
* @returns {never}
|
|
12
12
|
*/
|
|
13
13
|
export function handleUnsuccessfulApiResponse (_name, result, spinner) {
|
|
14
14
|
const resultError = 'error' in result && result.error && typeof result.error === 'object' ? result.error : {}
|
|
@@ -5,17 +5,12 @@ import { globby } from 'globby'
|
|
|
5
5
|
import ignore from 'ignore'
|
|
6
6
|
// @ts-ignore This package provides no types
|
|
7
7
|
import { directories } from 'ignore-by-default'
|
|
8
|
+
import micromatch from 'micromatch'
|
|
8
9
|
import { ErrorWithCause } from 'pony-cause'
|
|
9
10
|
|
|
10
11
|
import { InputError } from './errors.js'
|
|
11
12
|
import { isErrnoException } from './type-helpers.js'
|
|
12
13
|
|
|
13
|
-
/** @type {readonly string[]} */
|
|
14
|
-
const SUPPORTED_LOCKFILES = [
|
|
15
|
-
'package-lock.json',
|
|
16
|
-
'yarn.lock',
|
|
17
|
-
]
|
|
18
|
-
|
|
19
14
|
/**
|
|
20
15
|
* There are a lot of possible folders that we should not be looking in and "ignore-by-default" helps us with defining those
|
|
21
16
|
*
|
|
@@ -23,10 +18,17 @@ const SUPPORTED_LOCKFILES = [
|
|
|
23
18
|
*/
|
|
24
19
|
const ignoreByDefault = directories()
|
|
25
20
|
|
|
26
|
-
/** @type {
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
21
|
+
/** @type {import('globby').Options} */
|
|
22
|
+
const BASE_GLOBBY_OPTS = {
|
|
23
|
+
absolute: true,
|
|
24
|
+
expandDirectories: false,
|
|
25
|
+
gitignore: true,
|
|
26
|
+
ignore: [
|
|
27
|
+
...ignoreByDefault.map(item => '**/' + item)
|
|
28
|
+
],
|
|
29
|
+
markDirectories: true,
|
|
30
|
+
unique: true,
|
|
31
|
+
}
|
|
30
32
|
|
|
31
33
|
/**
|
|
32
34
|
* Resolves package.json and lockfiles from (globbed) input paths, applying relevant ignores
|
|
@@ -34,28 +36,24 @@ const GLOB_IGNORE = [
|
|
|
34
36
|
* @param {string} cwd The working directory to use when resolving paths
|
|
35
37
|
* @param {string[]} inputPaths A list of paths to folders, package.json files and/or recognized lockfiles. Supports globs.
|
|
36
38
|
* @param {import('@socketsecurity/config').SocketYml|undefined} config
|
|
39
|
+
* @param {import('@socketsecurity/sdk').SocketSdkReturnType<"getReportSupportedFiles">['data']} supportedFiles
|
|
37
40
|
* @param {typeof console.error} debugLog
|
|
38
41
|
* @returns {Promise<string[]>}
|
|
39
42
|
* @throws {InputError}
|
|
40
43
|
*/
|
|
41
|
-
export async function getPackageFiles (cwd, inputPaths, config, debugLog) {
|
|
44
|
+
export async function getPackageFiles (cwd, inputPaths, config, supportedFiles, debugLog) {
|
|
42
45
|
debugLog(`Globbed resolving ${inputPaths.length} paths:`, inputPaths)
|
|
43
46
|
|
|
44
47
|
// TODO: Does not support `~/` paths
|
|
45
48
|
const entries = await globby(inputPaths, {
|
|
46
|
-
|
|
49
|
+
...BASE_GLOBBY_OPTS,
|
|
47
50
|
cwd,
|
|
48
|
-
|
|
49
|
-
gitignore: true,
|
|
50
|
-
ignore: [...GLOB_IGNORE],
|
|
51
|
-
markDirectories: true,
|
|
52
|
-
onlyFiles: false,
|
|
53
|
-
unique: true,
|
|
51
|
+
onlyFiles: false
|
|
54
52
|
})
|
|
55
53
|
|
|
56
54
|
debugLog(`Globbed resolved ${inputPaths.length} paths to ${entries.length} paths:`, entries)
|
|
57
55
|
|
|
58
|
-
const packageFiles = await mapGlobResultToFiles(entries)
|
|
56
|
+
const packageFiles = await mapGlobResultToFiles(entries, supportedFiles)
|
|
59
57
|
|
|
60
58
|
debugLog(`Mapped ${entries.length} entries to ${packageFiles.length} files:`, packageFiles)
|
|
61
59
|
|
|
@@ -73,11 +71,14 @@ export async function getPackageFiles (cwd, inputPaths, config, debugLog) {
|
|
|
73
71
|
* Takes paths to folders, package.json and/or recognized lock files and resolves them to package.json + lockfile pairs (where possible)
|
|
74
72
|
*
|
|
75
73
|
* @param {string[]} entries
|
|
74
|
+
* @param {import('@socketsecurity/sdk').SocketSdkReturnType<"getReportSupportedFiles">['data']} supportedFiles
|
|
76
75
|
* @returns {Promise<string[]>}
|
|
77
76
|
* @throws {InputError}
|
|
78
77
|
*/
|
|
79
|
-
export async function mapGlobResultToFiles (entries) {
|
|
80
|
-
const packageFiles = await Promise.all(
|
|
78
|
+
export async function mapGlobResultToFiles (entries, supportedFiles) {
|
|
79
|
+
const packageFiles = await Promise.all(
|
|
80
|
+
entries.map(entry => mapGlobEntryToFiles(entry, supportedFiles))
|
|
81
|
+
)
|
|
81
82
|
|
|
82
83
|
const uniquePackageFiles = [...new Set(packageFiles.flat())]
|
|
83
84
|
|
|
@@ -88,46 +89,58 @@ export async function mapGlobResultToFiles (entries) {
|
|
|
88
89
|
* 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
|
*
|
|
90
91
|
* @param {string} entry
|
|
92
|
+
* @param {import('@socketsecurity/sdk').SocketSdkReturnType<'getReportSupportedFiles'>['data']} supportedFiles
|
|
91
93
|
* @returns {Promise<string[]>}
|
|
92
94
|
* @throws {InputError}
|
|
93
95
|
*/
|
|
94
|
-
export async function mapGlobEntryToFiles (entry) {
|
|
96
|
+
export async function mapGlobEntryToFiles (entry, supportedFiles) {
|
|
95
97
|
/** @type {string|undefined} */
|
|
96
|
-
let
|
|
97
|
-
/** @type {string
|
|
98
|
-
let
|
|
99
|
-
|
|
98
|
+
let pkgJSFile
|
|
99
|
+
/** @type {string[]} */
|
|
100
|
+
let jsLockFiles = []
|
|
101
|
+
/** @type {string[]} */
|
|
102
|
+
let pyFiles = []
|
|
103
|
+
|
|
104
|
+
const jsSupported = supportedFiles['npm'] || {}
|
|
105
|
+
const jsLockFilePatterns = Object.keys(jsSupported)
|
|
106
|
+
.filter(key => key !== 'packagejson')
|
|
107
|
+
.map(key => /** @type {{ pattern: string }} */ (jsSupported[key]).pattern)
|
|
108
|
+
|
|
109
|
+
const pyFilePatterns = Object.values(supportedFiles['pypi'] || {}).map(p => p.pattern)
|
|
100
110
|
if (entry.endsWith('/')) {
|
|
101
111
|
// If the match is a folder and that folder contains a package.json file, then include it
|
|
102
112
|
const filePath = path.resolve(entry, 'package.json')
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
if (await fileExists(filePath)) pkgJSFile = filePath
|
|
114
|
+
pyFiles = await globby(pyFilePatterns, {
|
|
115
|
+
...BASE_GLOBBY_OPTS,
|
|
116
|
+
cwd: entry
|
|
117
|
+
})
|
|
118
|
+
} else {
|
|
119
|
+
const entryFile = path.basename(entry)
|
|
120
|
+
|
|
121
|
+
if (entryFile === 'package.json') {
|
|
122
|
+
// If the match is a package.json file, then include it
|
|
123
|
+
pkgJSFile = entry
|
|
124
|
+
} else if (micromatch.isMatch(entryFile, jsLockFilePatterns)) {
|
|
125
|
+
jsLockFiles = [entry]
|
|
126
|
+
pkgJSFile = path.resolve(path.dirname(entry), 'package.json')
|
|
127
|
+
if (!(await fileExists(pkgJSFile))) return []
|
|
128
|
+
} else if (micromatch.isMatch(entryFile, pyFilePatterns)) {
|
|
129
|
+
pyFiles = [entry]
|
|
130
|
+
}
|
|
111
131
|
}
|
|
112
132
|
|
|
113
133
|
// If we will include a package.json file but don't already have a corresponding lockfile, then look for one
|
|
114
|
-
if (!
|
|
115
|
-
const pkgDir = path.dirname(
|
|
116
|
-
|
|
117
|
-
for (const name of SUPPORTED_LOCKFILES) {
|
|
118
|
-
const lockFileAlternative = path.resolve(pkgDir, name)
|
|
119
|
-
if (await fileExists(lockFileAlternative)) {
|
|
120
|
-
lockFile = lockFileAlternative
|
|
121
|
-
break
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
134
|
+
if (!jsLockFiles.length && pkgJSFile) {
|
|
135
|
+
const pkgDir = path.dirname(pkgJSFile)
|
|
125
136
|
|
|
126
|
-
|
|
127
|
-
|
|
137
|
+
jsLockFiles = await globby(jsLockFilePatterns, {
|
|
138
|
+
...BASE_GLOBBY_OPTS,
|
|
139
|
+
cwd: pkgDir
|
|
140
|
+
})
|
|
128
141
|
}
|
|
129
142
|
|
|
130
|
-
return
|
|
143
|
+
return [...jsLockFiles, ...pyFiles].concat(pkgJSFile ? [pkgJSFile] : [])
|
|
131
144
|
}
|
|
132
145
|
|
|
133
146
|
/**
|
package/lib/utils/sdk.js
CHANGED
|
@@ -7,28 +7,27 @@ import isInteractive from 'is-interactive'
|
|
|
7
7
|
import prompts from 'prompts'
|
|
8
8
|
|
|
9
9
|
import { AuthError } from './errors.js'
|
|
10
|
+
import { getSetting } from './settings.js'
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
|
-
*
|
|
13
|
+
* This API key should be stored globally for the duration of the CLI execution
|
|
13
14
|
*
|
|
14
15
|
* @type {string | undefined}
|
|
15
16
|
*/
|
|
16
|
-
let
|
|
17
|
+
let sessionAPIKey
|
|
17
18
|
|
|
18
19
|
/** @returns {Promise<import('@socketsecurity/sdk').SocketSdk>} */
|
|
19
20
|
export async function setupSdk () {
|
|
20
|
-
|
|
21
|
-
apiKey = process.env['SOCKET_SECURITY_API_KEY']
|
|
22
|
-
}
|
|
21
|
+
let apiKey = getSetting('apiKey') || process.env['SOCKET_SECURITY_API_KEY'] || sessionAPIKey
|
|
23
22
|
|
|
24
23
|
if (!apiKey && isInteractive()) {
|
|
25
24
|
const input = await prompts({
|
|
26
25
|
type: 'password',
|
|
27
26
|
name: 'apiKey',
|
|
28
|
-
message: 'Enter your Socket.dev API key',
|
|
27
|
+
message: 'Enter your Socket.dev API key (not saved)',
|
|
29
28
|
})
|
|
30
29
|
|
|
31
|
-
apiKey = input.apiKey
|
|
30
|
+
apiKey = sessionAPIKey = input.apiKey
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
if (!apiKey) {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as fs from 'fs'
|
|
2
|
+
import * as os from 'os'
|
|
3
|
+
import * as path from 'path'
|
|
4
|
+
|
|
5
|
+
import ora from 'ora'
|
|
6
|
+
|
|
7
|
+
let dataHome = process.platform === 'win32'
|
|
8
|
+
? process.env['LOCALAPPDATA']
|
|
9
|
+
: process.env['XDG_DATA_HOME']
|
|
10
|
+
|
|
11
|
+
if (!dataHome) {
|
|
12
|
+
if (process.platform === 'win32') throw new Error('missing %LOCALAPPDATA%')
|
|
13
|
+
const home = os.homedir()
|
|
14
|
+
dataHome = path.join(home, ...(process.platform === 'darwin'
|
|
15
|
+
? ['Library', 'Application Support']
|
|
16
|
+
: ['.local', 'share']
|
|
17
|
+
))
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const settingsPath = path.join(dataHome, 'socket', 'settings')
|
|
21
|
+
|
|
22
|
+
/** @type {{apiKey?: string | null}} */
|
|
23
|
+
let settings = {}
|
|
24
|
+
|
|
25
|
+
if (fs.existsSync(settingsPath)) {
|
|
26
|
+
const raw = fs.readFileSync(settingsPath, 'utf-8')
|
|
27
|
+
try {
|
|
28
|
+
settings = JSON.parse(Buffer.from(raw, 'base64').toString())
|
|
29
|
+
} catch (e) {
|
|
30
|
+
ora(`Failed to parse settings at ${settingsPath}`).warn()
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
fs.mkdirSync(path.dirname(settingsPath), { recursive: true })
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @template {keyof typeof settings} Key
|
|
38
|
+
* @param {Key} key
|
|
39
|
+
* @returns {typeof settings[Key]}
|
|
40
|
+
*/
|
|
41
|
+
export function getSetting (key) {
|
|
42
|
+
return settings[key]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @template {keyof typeof settings} Key
|
|
47
|
+
* @param {Key} key
|
|
48
|
+
* @param {typeof settings[Key]} value
|
|
49
|
+
* @returns {void}
|
|
50
|
+
*/
|
|
51
|
+
export function updateSetting (key, value) {
|
|
52
|
+
settings[key] = value
|
|
53
|
+
fs.writeFileSync(
|
|
54
|
+
settingsPath,
|
|
55
|
+
Buffer.from(JSON.stringify(settings)).toString('base64')
|
|
56
|
+
)
|
|
57
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@socketsecurity/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "CLI tool for Socket.dev",
|
|
5
5
|
"homepage": "http://github.com/SocketDev/socket-cli-js",
|
|
6
6
|
"repository": {
|
|
@@ -43,10 +43,11 @@
|
|
|
43
43
|
"test": "run-s check test:*"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@socketsecurity/eslint-config": "^
|
|
46
|
+
"@socketsecurity/eslint-config": "^3.0.1",
|
|
47
47
|
"@tsconfig/node14": "^1.0.3",
|
|
48
48
|
"@types/chai": "^4.3.3",
|
|
49
49
|
"@types/chai-as-promised": "^7.1.5",
|
|
50
|
+
"@types/micromatch": "^4.0.2",
|
|
50
51
|
"@types/mocha": "^10.0.1",
|
|
51
52
|
"@types/mock-fs": "^4.13.1",
|
|
52
53
|
"@types/node": "^14.18.31",
|
|
@@ -84,7 +85,7 @@
|
|
|
84
85
|
"dependencies": {
|
|
85
86
|
"@apideck/better-ajv-errors": "^0.3.6",
|
|
86
87
|
"@socketsecurity/config": "^2.0.0",
|
|
87
|
-
"@socketsecurity/sdk": "^0.
|
|
88
|
+
"@socketsecurity/sdk": "^0.6.0",
|
|
88
89
|
"chalk": "^5.1.2",
|
|
89
90
|
"globby": "^13.1.3",
|
|
90
91
|
"hpagent": "^1.2.0",
|
|
@@ -93,6 +94,7 @@
|
|
|
93
94
|
"is-interactive": "^2.0.0",
|
|
94
95
|
"is-unicode-supported": "^1.3.0",
|
|
95
96
|
"meow": "^11.0.0",
|
|
97
|
+
"micromatch": "^4.0.5",
|
|
96
98
|
"ora": "^6.1.2",
|
|
97
99
|
"pony-cause": "^2.1.8",
|
|
98
100
|
"prompts": "^2.4.2",
|