@socketsecurity/cli 0.7.2 → 0.8.2

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.
@@ -0,0 +1,222 @@
1
+ const path = require('path')
2
+ const { PassThrough } = require('stream')
3
+
4
+ const ipc_version = require('../../package.json').version
5
+ const { isErrnoException } = require('../utils/type-helpers.cjs')
6
+
7
+ /**
8
+ * @typedef {import('stream').Readable} Readable
9
+ */
10
+ /**
11
+ * @typedef {import('stream').Writable} Writable
12
+ */
13
+ /**
14
+ * @param {import('chalk')['default']['level']} colorLevel
15
+ * @param {boolean} isInteractive
16
+ * @param {any} npmlog
17
+ * @returns {Promise<{ captureTTY<RET extends any>(mutexFn: (input: Readable | null, output?: Writable, colorLevel: import('chalk')['default']['level']) => Promise<RET>): Promise<RET> }>}
18
+ */
19
+ module.exports = async function createTTYServer (colorLevel, isInteractive, npmlog) {
20
+ const TTY_IPC = process.env['SOCKET_SECURITY_TTY_IPC']
21
+ const net = require('net')
22
+ /**
23
+ * @type {import('readline')}
24
+ */
25
+ let readline
26
+ const isSTDINInteractive = isInteractive
27
+ if (!isSTDINInteractive && TTY_IPC) {
28
+ return {
29
+ async captureTTY (mutexFn) {
30
+ return new Promise((resolve, reject) => {
31
+ const conn = net.createConnection({
32
+ path: TTY_IPC
33
+ }).on('error', reject)
34
+ let captured = false
35
+ /**
36
+ * @type {Array<Buffer>}
37
+ */
38
+ const bufs = []
39
+ conn.on('data', function awaitCapture (chunk) {
40
+ bufs.push(chunk)
41
+ /**
42
+ * @type {Buffer | null}
43
+ */
44
+ let lineBuff = Buffer.concat(bufs)
45
+ try {
46
+ if (!captured) {
47
+ const EOL = lineBuff.indexOf('\n'.charCodeAt(0))
48
+ if (EOL !== -1) {
49
+ conn.removeListener('data', awaitCapture)
50
+ conn.push(lineBuff.slice(EOL + 1))
51
+ const {
52
+ ipc_version: remote_ipc_version,
53
+ capabilities: { input: hasInput, output: hasOutput, colorLevel: ipcColorLevel }
54
+ } = JSON.parse(lineBuff.slice(0, EOL).toString('utf-8'))
55
+ lineBuff = null
56
+ captured = true
57
+ if (remote_ipc_version !== ipc_version) {
58
+ throw new Error('Mismatched STDIO tunnel IPC version, ensure you only have 1 version of socket CLI being called.')
59
+ }
60
+ const input = hasInput ? new PassThrough() : null
61
+ input?.pause()
62
+ if (input) conn.pipe(input)
63
+ const output = hasOutput ? new PassThrough() : null
64
+ output?.pipe(conn)
65
+ // make ora happy
66
+ // @ts-ignore
67
+ output.isTTY = true
68
+ // @ts-ignore
69
+ output.cursorTo = function cursorTo (x, y, callback) {
70
+ readline = readline || require('readline')
71
+ // @ts-ignore
72
+ readline.cursorTo(this, x, y, callback)
73
+ }
74
+ // @ts-ignore
75
+ output.clearLine = function clearLine (dir, callback) {
76
+ readline = readline || require('readline')
77
+ // @ts-ignore
78
+ readline.clearLine(this, dir, callback)
79
+ }
80
+ mutexFn(hasInput ? input : null, hasOutput ? /** @type {Writable} */(output) : undefined, ipcColorLevel)
81
+ .then(resolve, reject)
82
+ .finally(() => {
83
+ conn.unref()
84
+ conn.end()
85
+ input?.end()
86
+ output?.end()
87
+ // process.exit(13)
88
+ })
89
+ }
90
+ }
91
+ } catch (e) {
92
+ reject(e)
93
+ }
94
+ })
95
+ })
96
+ }
97
+ }
98
+ }
99
+ /**
100
+ * @type {Array<{resolve(): void}>}}
101
+ */
102
+ const pendingCaptures = []
103
+ let captured = false
104
+ const sock = path.join(require('os').tmpdir(), `socket-security-tty-${process.pid}.sock`)
105
+ process.env['SOCKET_SECURITY_TTY_IPC'] = sock
106
+ try {
107
+ await require('fs/promises').unlink(sock)
108
+ } catch (e) {
109
+ if (isErrnoException(e) && e.code !== 'ENOENT') {
110
+ throw e
111
+ }
112
+ }
113
+ const input = isSTDINInteractive ? process.stdin : null
114
+ const output = process.stderr
115
+ if (input) {
116
+ await new Promise((resolve, reject) => {
117
+ const server = net.createServer(async (conn) => {
118
+ if (captured) {
119
+ const captured = new Promise((resolve) => {
120
+ pendingCaptures.push({
121
+ resolve () {
122
+ resolve(undefined)
123
+ }
124
+ })
125
+ })
126
+ await captured
127
+ } else {
128
+ captured = true
129
+ }
130
+ const wasProgressEnabled = npmlog.progressEnabled
131
+ npmlog.pause()
132
+ if (wasProgressEnabled) {
133
+ npmlog.disableProgress()
134
+ }
135
+ conn.write(`${JSON.stringify({
136
+ ipc_version,
137
+ capabilities: {
138
+ input: Boolean(input),
139
+ output: true,
140
+ colorLevel
141
+ }
142
+ })}\n`)
143
+ conn.on('data', (data) => {
144
+ output.write(data)
145
+ })
146
+ conn.on('error', (e) => {
147
+ output.write(`there was an error prompting from a subshell (${e.message}), socket npm closing`)
148
+ process.exit(1)
149
+ })
150
+ input.on('data', (data) => {
151
+ conn.write(data)
152
+ })
153
+ input.on('end', () => {
154
+ conn.unref()
155
+ conn.end()
156
+ if (wasProgressEnabled) {
157
+ npmlog.enableProgress()
158
+ }
159
+ npmlog.resume()
160
+ nextCapture()
161
+ })
162
+ }).listen(sock, () => resolve(server)).on('error', (err) => {
163
+ reject(err)
164
+ }).unref()
165
+ process.on('exit', () => {
166
+ server.close()
167
+ try {
168
+ require('fs').unlinkSync(sock)
169
+ } catch (e) {
170
+ if (isErrnoException(e) && e.code !== 'ENOENT') {
171
+ throw e
172
+ }
173
+ }
174
+ })
175
+ resolve(server)
176
+ })
177
+ }
178
+ /**
179
+ *
180
+ */
181
+ function nextCapture () {
182
+ if (pendingCaptures.length > 0) {
183
+ const nextCapture = pendingCaptures.shift()
184
+ if (nextCapture) {
185
+ nextCapture.resolve()
186
+ }
187
+ } else {
188
+ captured = false
189
+ }
190
+ }
191
+ return {
192
+ async captureTTY (mutexFn) {
193
+ if (captured) {
194
+ const captured = new Promise((resolve) => {
195
+ pendingCaptures.push({
196
+ resolve () {
197
+ resolve(undefined)
198
+ }
199
+ })
200
+ })
201
+ await captured
202
+ } else {
203
+ captured = true
204
+ }
205
+ const wasProgressEnabled = npmlog.progressEnabled
206
+ try {
207
+ npmlog.pause()
208
+ if (wasProgressEnabled) {
209
+ npmlog.disableProgress()
210
+ }
211
+ // need await here for proper finally timing
212
+ return await mutexFn(input, output, colorLevel)
213
+ } finally {
214
+ if (wasProgressEnabled) {
215
+ npmlog.enableProgress()
216
+ }
217
+ npmlog.resume()
218
+ nextCapture()
219
+ }
220
+ }
221
+ }
222
+ }
@@ -25,18 +25,16 @@ export function handleUnsuccessfulApiResponse (_name, result, spinner) {
25
25
  /**
26
26
  * @template T
27
27
  * @param {Promise<T>} value
28
- * @param {import('ora').Ora} spinner
29
28
  * @param {string} description
30
29
  * @returns {Promise<T>}
31
30
  */
32
- export async function handleApiCall (value, spinner, description) {
31
+ export async function handleApiCall (value, description) {
33
32
  /** @type {T} */
34
33
  let result
35
34
 
36
35
  try {
37
36
  result = await value
38
37
  } catch (cause) {
39
- spinner.fail()
40
38
  throw new ErrorWithCause(`Failed ${description}`, { cause })
41
39
  }
42
40
 
@@ -0,0 +1,180 @@
1
+ //#region UX Constants
2
+ /**
3
+ * @typedef {{block: boolean, display: boolean}} RuleActionUX
4
+ */
5
+ const IGNORE_UX = {
6
+ block: false,
7
+ display: false
8
+ }
9
+ const WARN_UX = {
10
+ block: false,
11
+ display: true
12
+ }
13
+ const ERROR_UX = {
14
+ block: true,
15
+ display: true
16
+ }
17
+ //#endregion
18
+ //#region utils
19
+ /**
20
+ * @typedef { NonNullable<NonNullable<NonNullable<(Awaited<ReturnType<import('@socketsecurity/sdk').SocketSdk['postSettings']>> & {success: true})['data']['entries'][number]['settings'][string]>['issueRules']>>[string] | boolean } NonNormalizedIssueRule
21
+ */
22
+ /**
23
+ * @typedef { (NonNullable<NonNullable<(Awaited<ReturnType<import('@socketsecurity/sdk').SocketSdk['postSettings']>> & {success: true})['data']['defaults']['issueRules']>[string]> & { action: string }) | boolean } NonNormalizedResolvedIssueRule
24
+ */
25
+ /**
26
+ * Iterates over all entries with ordered issue rule for deferal
27
+ * Iterates over all issue rules and finds the first defined value that does not defer otherwise uses the defaultValue
28
+ * Takes the value and converts into a UX workflow
29
+ *
30
+ * @param {Iterable<Iterable<NonNormalizedIssueRule>>} entriesOrderedIssueRules
31
+ * @param {NonNormalizedResolvedIssueRule} defaultValue
32
+ * @returns {RuleActionUX}
33
+ */
34
+ function resolveIssueRuleUX (entriesOrderedIssueRules, defaultValue) {
35
+ if (defaultValue === true || defaultValue == null) {
36
+ defaultValue = {
37
+ action: 'error'
38
+ }
39
+ } else if (defaultValue === false) {
40
+ defaultValue = {
41
+ action: 'ignore'
42
+ }
43
+ }
44
+ let block = false
45
+ let display = false
46
+ let needDefault = true
47
+ iterate_entries:
48
+ for (const issueRuleArr of entriesOrderedIssueRules) {
49
+ for (const rule of issueRuleArr) {
50
+ if (issueRuleValueDoesNotDefer(rule)) {
51
+ // there was a rule, even if a defer, don't narrow to the default
52
+ needDefault = false
53
+ const narrowingFilter = uxForDefinedNonDeferValue(rule)
54
+ block = block || narrowingFilter.block
55
+ display = display || narrowingFilter.display
56
+ continue iterate_entries
57
+ }
58
+ }
59
+ // all rules defer, narrow
60
+ const narrowingFilter = uxForDefinedNonDeferValue(defaultValue)
61
+ block = block || narrowingFilter.block
62
+ display = display || narrowingFilter.display
63
+ }
64
+ if (needDefault) {
65
+ // no config set a
66
+ const narrowingFilter = uxForDefinedNonDeferValue(defaultValue)
67
+ block = block || narrowingFilter.block
68
+ display = display || narrowingFilter.display
69
+ }
70
+ return {
71
+ block,
72
+ display
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Negative form because it is narrowing the type
78
+ *
79
+ * @type {(issueRuleValue: NonNormalizedIssueRule) => issueRuleValue is NonNormalizedResolvedIssueRule}
80
+ */
81
+ function issueRuleValueDoesNotDefer (issueRule) {
82
+ if (issueRule === undefined) {
83
+ return false
84
+ } else if (typeof issueRule === 'object' && issueRule) {
85
+ const { action } = issueRule
86
+ if (action === undefined || action === 'defer') {
87
+ return false
88
+ }
89
+ }
90
+ return true
91
+ }
92
+
93
+ /**
94
+ * Handles booleans for backwards compatibility
95
+ *
96
+ * @param {NonNormalizedResolvedIssueRule} issueRuleValue
97
+ * @returns {RuleActionUX}
98
+ */
99
+ function uxForDefinedNonDeferValue (issueRuleValue) {
100
+ if (typeof issueRuleValue === 'boolean') {
101
+ return issueRuleValue ? ERROR_UX : IGNORE_UX
102
+ }
103
+ const { action } = issueRuleValue
104
+ if (action === 'warn') {
105
+ return WARN_UX
106
+ } else if (action === 'ignore') {
107
+ return IGNORE_UX
108
+ }
109
+ return ERROR_UX
110
+ }
111
+ //#endregion
112
+ //#region exports
113
+ module.exports = {
114
+ /**
115
+ *
116
+ * @param {(Awaited<ReturnType<import('@socketsecurity/sdk').SocketSdk['postSettings']>> & {success: true})['data']} settings
117
+ * @returns {(context: {package: {name: string, version: string}, issue: {type: string}}) => RuleActionUX}
118
+ */
119
+ createIssueUXLookup (settings) {
120
+ /**
121
+ * @type {Map<keyof (typeof settings.defaults.issueRules), RuleActionUX>}
122
+ */
123
+ const cachedUX = new Map()
124
+ return (context) => {
125
+ const key = context.issue.type
126
+ /**
127
+ * @type {RuleActionUX | undefined}
128
+ */
129
+ let ux = cachedUX.get(key)
130
+ if (ux) {
131
+ return ux
132
+ }
133
+ /**
134
+ * @type {Array<Array<NonNormalizedIssueRule>>}
135
+ */
136
+ const entriesOrderedIssueRules = []
137
+ for (const settingsEntry of settings.entries) {
138
+ /**
139
+ * @type {Array<NonNormalizedIssueRule>}
140
+ */
141
+ const orderedIssueRules = []
142
+ let target = settingsEntry.start
143
+ while (target !== null) {
144
+ const resolvedTarget = settingsEntry.settings[target]
145
+ if (!resolvedTarget) {
146
+ break
147
+ }
148
+ const issueRuleValue = resolvedTarget.issueRules?.[key]
149
+ if (typeof issueRuleValue !== 'undefined') {
150
+ orderedIssueRules.push(issueRuleValue)
151
+ }
152
+ target = resolvedTarget.deferTo ?? null
153
+ }
154
+ entriesOrderedIssueRules.push(orderedIssueRules)
155
+ }
156
+ const defaultValue = settings.defaults.issueRules[key]
157
+ /**
158
+ * @type {NonNormalizedResolvedIssueRule}
159
+ */
160
+ let resolvedDefaultValue = {
161
+ action: 'error'
162
+ }
163
+ // @ts-ignore backcompat, cover with tests
164
+ if (defaultValue === false) {
165
+ resolvedDefaultValue = {
166
+ action: 'ignore'
167
+ }
168
+ // @ts-ignore backcompat, cover with tests
169
+ } else if (defaultValue && defaultValue !== true) {
170
+ resolvedDefaultValue = {
171
+ action: defaultValue.action ?? 'error'
172
+ }
173
+ }
174
+ ux = resolveIssueRuleUX(entriesOrderedIssueRules, resolvedDefaultValue)
175
+ cachedUX.set(key, ux)
176
+ return ux
177
+ }
178
+ }
179
+ }
180
+ //#endregion
package/lib/utils/misc.js CHANGED
@@ -7,7 +7,7 @@ import { logSymbols } from './chalk-markdown.js'
7
7
  export function createDebugLogger (printDebugLogs) {
8
8
  return printDebugLogs
9
9
  // eslint-disable-next-line no-console
10
- ? (...params) => console.error(logSymbols.info, ...params)
10
+ ? /** @type { (...params: unknown[]) => void } */(...params) => console.error(logSymbols.info, ...params)
11
11
  : () => {}
12
12
  }
13
13
 
@@ -5,11 +5,10 @@ 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'
9
8
  import { ErrorWithCause } from 'pony-cause'
10
9
 
11
10
  import { InputError } from './errors.js'
12
- import { isErrnoException } from './type-helpers.js'
11
+ import { isErrnoException } from './type-helpers.cjs'
13
12
 
14
13
  /**
15
14
  * There are a lot of possible folders that we should not be looking in and "ignore-by-default" helps us with defining those
@@ -94,53 +93,65 @@ export async function mapGlobResultToFiles (entries, supportedFiles) {
94
93
  * @throws {InputError}
95
94
  */
96
95
  export async function mapGlobEntryToFiles (entry, supportedFiles) {
97
- /** @type {string|undefined} */
98
- let pkgJSFile
99
- /** @type {string[]} */
100
- let jsLockFiles = []
101
- /** @type {string[]} */
102
- let pyFiles = []
103
-
104
96
  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)
110
- if (entry.endsWith('/')) {
111
- // If the match is a folder and that folder contains a package.json file, then include it
112
- const filePath = path.resolve(entry, 'package.json')
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
- }
131
- }
132
-
133
- // If we will include a package.json file but don't already have a corresponding lockfile, then look for one
134
- if (!jsLockFiles.length && pkgJSFile) {
135
- const pkgDir = path.dirname(pkgJSFile)
136
-
137
- jsLockFiles = await globby(jsLockFilePatterns, {
138
- ...BASE_GLOBBY_OPTS,
139
- cwd: pkgDir
140
- })
141
- }
142
-
143
- return [...jsLockFiles, ...pyFiles].concat(pkgJSFile ? [pkgJSFile] : [])
97
+ const jsLockFilePatterns = Object.values(jsSupported)
98
+ // .filter(key => key !== 'packagejson')
99
+ .map(p => `**/${/** @type {{ pattern: string }} */ (p).pattern}`)
100
+
101
+ const pyFilePatterns = Object.values(supportedFiles['pypi'] || {})
102
+ .map(p => `**/${/** @type {{ pattern: string }} */ (p).pattern}`)
103
+
104
+ const goSupported = supportedFiles['go'] || {}
105
+ const goSupplementalPatterns = Object.values(goSupported)
106
+ // .filter(key => key !== 'gomod')
107
+ .map(p => `**/${/** @type {{ pattern: string }} */ (p).pattern}`)
108
+
109
+ const files = await globby([
110
+ ...jsLockFilePatterns,
111
+ ...pyFilePatterns,
112
+ ...goSupplementalPatterns
113
+ ], {
114
+ ...BASE_GLOBBY_OPTS,
115
+ onlyFiles: true,
116
+ cwd: path.resolve((await stat(entry)).isDirectory() ? entry : path.dirname(entry))
117
+ })
118
+ return files
119
+
120
+ // if (entry.endsWith('/')) {
121
+ // // If the match is a folder and that folder contains a package.json file, then include it
122
+ // const jsPkg = path.resolve(entry, 'package.json')
123
+ // if (await fileExists(jsPkg)) pkgJSFile = jsPkg
124
+
125
+ // const goPkg = path.resolve(entry, 'go.mod')
126
+ // if (await fileExists(goPkg)) pkgGoFile = goPkg
127
+
128
+ // pyFiles = await globby(pyFilePatterns, {
129
+ // ...BASE_GLOBBY_OPTS,
130
+ // cwd: entry
131
+ // })
132
+ // } else {
133
+ // const entryFile = path.basename(entry)
134
+
135
+ // if (entryFile === 'package.json') {
136
+ // // If the match is a package.json file, then include it
137
+ // pkgJSFile = entry
138
+ // } else if (micromatch.isMatch(entryFile, jsLockFilePatterns)) {
139
+ // jsLockFiles = [entry]
140
+ // pkgJSFile = path.resolve(path.dirname(entry), 'package.json')
141
+ // if (!(await fileExists(pkgJSFile))) return []
142
+ // } else if (entryFile === 'go.mod') {
143
+ // pkgGoFile = entry
144
+ // } else if (micromatch.isMatch(entryFile, goSupplementalPatterns)) {
145
+ // goExtraFiles = [entry]
146
+ // pkgGoFile = path.resolve(path.dirname(entry), 'go.mod')
147
+ // } else if (micromatch.isMatch(entryFile, pyFilePatterns)) {
148
+ // pyFiles = [entry]
149
+ // }
150
+ // }
151
+
152
+ // return [...jsLockFiles, ...pyFiles, ...goExtraFiles]
153
+ // .concat(pkgJSFile ? [pkgJSFile] : [])
154
+ // .concat(pkgGoFile ? [pkgGoFile] : [])
144
155
  }
145
156
 
146
157
  /**
package/lib/utils/sdk.js CHANGED
@@ -9,25 +9,69 @@ import prompts from 'prompts'
9
9
  import { AuthError } from './errors.js'
10
10
  import { getSetting } from './settings.js'
11
11
 
12
+ export const FREE_API_KEY = 'sktsec_t_--RAN5U4ivauy4w37-6aoKyYPDt5ZbaT5JBVMqiwKo_api'
13
+
12
14
  /**
13
15
  * This API key should be stored globally for the duration of the CLI execution
14
16
  *
15
17
  * @type {string | undefined}
16
18
  */
17
- let sessionAPIKey
19
+ let defaultKey
20
+
21
+ /** @returns {string | undefined} */
22
+ export function getDefaultKey () {
23
+ defaultKey = process.env['SOCKET_SECURITY_API_KEY'] || getSetting('apiKey') || defaultKey
24
+ return defaultKey
25
+ }
26
+
27
+ /**
28
+ * The API server that should be used for operations
29
+ *
30
+ * @type {string | undefined}
31
+ */
32
+ let defaultAPIBaseUrl
33
+
34
+ /**
35
+ * @returns {string | undefined}
36
+ */
37
+ export function getDefaultAPIBaseUrl () {
38
+ defaultAPIBaseUrl = process.env['SOCKET_SECURITY_API_BASE_URL'] || getSetting('apiBaseUrl') || undefined
39
+ return defaultAPIBaseUrl
40
+ }
41
+
42
+ /**
43
+ * The API server that should be used for operations
44
+ *
45
+ * @type {string | undefined}
46
+ */
47
+ let defaultApiProxy
18
48
 
19
- /** @returns {Promise<import('@socketsecurity/sdk').SocketSdk>} */
20
- export async function setupSdk () {
21
- let apiKey = getSetting('apiKey') || process.env['SOCKET_SECURITY_API_KEY'] || sessionAPIKey
49
+ /**
50
+ * @returns {string | undefined}
51
+ */
52
+ export function getDefaultHTTPProxy () {
53
+ defaultApiProxy = process.env['SOCKET_SECURITY_API_PROXY'] || getSetting('apiProxy') || undefined
54
+ return defaultApiProxy
55
+ }
22
56
 
23
- if (!apiKey && isInteractive()) {
57
+ /**
58
+ * @param {string} [apiKey]
59
+ * @param {string} [apiBaseUrl]
60
+ * @param {string} [proxy]
61
+ * @returns {Promise<import('@socketsecurity/sdk').SocketSdk>}
62
+ */
63
+ export async function setupSdk (apiKey = getDefaultKey(), apiBaseUrl = getDefaultAPIBaseUrl(), proxy = getDefaultHTTPProxy()) {
64
+ if (apiKey == null && isInteractive()) {
65
+ /**
66
+ * @type {{ apiKey: string }}
67
+ */
24
68
  const input = await prompts({
25
69
  type: 'password',
26
70
  name: 'apiKey',
27
- message: 'Enter your Socket.dev API key (not saved)',
71
+ message: 'Enter your Socket.dev API key (not saved, use socket login to persist)',
28
72
  })
29
73
 
30
- apiKey = sessionAPIKey = input.apiKey
74
+ apiKey = defaultKey = input.apiKey
31
75
  }
32
76
 
33
77
  if (!apiKey) {
@@ -37,11 +81,11 @@ export async function setupSdk () {
37
81
  /** @type {import('@socketsecurity/sdk').SocketSdkOptions["agent"]} */
38
82
  let agent
39
83
 
40
- if (process.env['SOCKET_SECURITY_API_PROXY']) {
84
+ if (proxy) {
41
85
  const { HttpProxyAgent, HttpsProxyAgent } = await import('hpagent')
42
86
  agent = {
43
- http: new HttpProxyAgent({ proxy: process.env['SOCKET_SECURITY_API_PROXY'] }),
44
- https: new HttpsProxyAgent({ proxy: process.env['SOCKET_SECURITY_API_PROXY'] }),
87
+ http: new HttpProxyAgent({ proxy }),
88
+ https: new HttpsProxyAgent({ proxy }),
45
89
  }
46
90
  }
47
91
  const packageJsonPath = join(dirname(fileURLToPath(import.meta.url)), '../../package.json')
@@ -50,7 +94,7 @@ export async function setupSdk () {
50
94
  /** @type {import('@socketsecurity/sdk').SocketSdkOptions} */
51
95
  const sdkOptions = {
52
96
  agent,
53
- baseUrl: process.env['SOCKET_SECURITY_API_BASE_URL'],
97
+ baseUrl: apiBaseUrl,
54
98
  userAgent: createUserAgentFromPkgJson(JSON.parse(packageJson))
55
99
  }
56
100