Skip to content

Commit 78cd6db

Browse files
committed
Move the dependencies command to a subcommand of the organization
1 parent 47c5e59 commit 78cd6db

File tree

10 files changed

+171
-143
lines changed

10 files changed

+171
-143
lines changed

src/cli.mts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import { cmdAnalytics } from './commands/analytics/cmd-analytics.mts'
1313
import { cmdAuditLog } from './commands/audit-log/cmd-audit-log.mts'
1414
import { cmdCI } from './commands/ci/cmd-ci.mts'
1515
import { cmdConfig } from './commands/config/cmd-config.mts'
16-
import { cmdScanCreate } from './commands/dependencies/cmd-dependencies.mts'
1716
import { cmdFix } from './commands/fix/cmd-fix.mts'
1817
import { cmdInstall } from './commands/install/cmd-install.mts'
1918
import { cmdJson } from './commands/json/cmd-json.mts'
@@ -25,6 +24,7 @@ import { cmdNpm } from './commands/npm/cmd-npm.mts'
2524
import { cmdNpx } from './commands/npx/cmd-npx.mts'
2625
import { cmdOops } from './commands/oops/cmd-oops.mts'
2726
import { cmdOptimize } from './commands/optimize/cmd-optimize.mts'
27+
import { cmdOrganizationDependencies } from './commands/organization/cmd-organization-dependencies.mts'
2828
import { cmdOrganizationPolicyLicense } from './commands/organization/cmd-organization-policy-license.mts'
2929
import { cmdOrganizationPolicySecurity } from './commands/organization/cmd-organization-policy-security.mts'
3030
import { cmdOrganization } from './commands/organization/cmd-organization.mts'
@@ -77,7 +77,6 @@ void (async () => {
7777
scan: cmdScan,
7878
'audit-log': cmdAuditLog,
7979
repos: cmdRepository,
80-
dependencies: cmdScanCreate,
8180
analytics: cmdAnalytics,
8281
'threat-feed': cmdThreatFeed,
8382
manifest: cmdManifest,
@@ -111,7 +110,7 @@ void (async () => {
111110
argv: ['manifest', 'cdxgen'],
112111
},
113112
deps: {
114-
description: cmdScanCreate.description,
113+
description: cmdOrganizationDependencies.description,
115114
hidden: true,
116115
argv: ['dependencies'],
117116
},

src/commands/audit-log/output-audit-log.mts

Lines changed: 128 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -65,127 +65,7 @@ export async function outputAuditLog(
6565
return
6666
}
6767

68-
const filteredLogs = result.data.results
69-
const formattedOutput = filteredLogs.map(logs => [
70-
logs.event_id ?? '',
71-
msAtHome(logs.created_at ?? ''),
72-
logs.type ?? '',
73-
logs.user_email ?? '',
74-
logs.ip_address ?? '',
75-
logs.user_agent ?? '',
76-
])
77-
const headers = [
78-
'event id',
79-
' created at',
80-
' event type',
81-
' user email',
82-
' ip address',
83-
' user agent',
84-
]
85-
86-
// Note: this temporarily takes over the terminal (just like `man` does).
87-
const ScreenWidget = require('blessed/lib/widgets/screen.js')
88-
// Lazily access constants.blessedOptions.
89-
const screen: Widgets.Screen = new ScreenWidget({
90-
...constants.blessedOptions,
91-
})
92-
// Register these keys first so you can always exit, even when it gets stuck
93-
// If we don't do this and the code crashes, the user must hard-kill the
94-
// node process just to exit it. That's very bad UX.
95-
// eslint-disable-next-line n/no-process-exit
96-
screen.key(['escape', 'q', 'C-c'], () => process.exit(0))
97-
98-
const TableWidget = require('blessed-contrib/lib/widget/table.js')
99-
const tipsBoxHeight = 1 // 1 row for tips box
100-
const detailsBoxHeight = 20 // bottom N rows for details box. 20 gives 4 lines for condensed payload before it scrolls out of view
101-
102-
const maxWidths = [10, 10, 10, 10, 10, 10]
103-
formattedOutput.forEach(row => {
104-
row.forEach((str, i) => {
105-
maxWidths[i] = Math.max(str.length, maxWidths[i] ?? str.length)
106-
})
107-
})
108-
109-
const table: any = new TableWidget({
110-
keys: 'true',
111-
fg: 'white',
112-
selectedFg: 'white',
113-
selectedBg: 'magenta',
114-
interactive: 'true',
115-
label: `Audit Logs for ${orgSlug}`,
116-
width: '100%',
117-
top: 0,
118-
bottom: detailsBoxHeight + tipsBoxHeight,
119-
border: {
120-
type: 'line',
121-
fg: 'cyan',
122-
},
123-
columnWidth: maxWidths, //[10, 30, 40, 25, 15, 200],
124-
// Note: spacing works as long as you don't reserve more than total width
125-
columnSpacing: 4,
126-
truncate: '_',
127-
})
128-
129-
const BoxWidget = require('blessed/lib/widgets/box.js')
130-
const tipsBox: Widgets.BoxElement = new BoxWidget({
131-
bottom: detailsBoxHeight, // sits just above the details box
132-
height: tipsBoxHeight,
133-
width: '100%',
134-
style: {
135-
fg: 'yellow',
136-
bg: 'black',
137-
},
138-
tags: true,
139-
content: '↑/↓: Move Enter: Select q/ESC: Quit',
140-
})
141-
const detailsBox: Widgets.BoxElement = new BoxWidget({
142-
bottom: 0,
143-
height: detailsBoxHeight,
144-
width: '100%',
145-
border: {
146-
type: 'line',
147-
fg: 'cyan',
148-
},
149-
label: 'Details',
150-
content: formatResult(filteredLogs[0], true),
151-
style: {
152-
fg: 'white',
153-
},
154-
})
155-
156-
table.setData({
157-
headers: headers,
158-
data: formattedOutput,
159-
})
160-
161-
// allow control the table with the keyboard
162-
table.focus()
163-
164-
// Stacking order: table (top), tipsBox (middle), detailsBox (bottom)
165-
screen.append(table)
166-
screen.append(tipsBox)
167-
screen.append(detailsBox)
168-
169-
// Update details box when selection changes
170-
table.rows.on('select item', () => {
171-
const selectedIndex = table.rows.selected
172-
if (selectedIndex !== undefined && selectedIndex >= 0) {
173-
const selectedRow = filteredLogs[selectedIndex]
174-
detailsBox.setContent(formatResult(selectedRow))
175-
screen.render()
176-
}
177-
})
178-
179-
screen.render()
180-
181-
screen.key(['return'], () => {
182-
const selectedIndex = table.rows.selected
183-
screen.destroy()
184-
const selectedRow = formattedOutput[selectedIndex]
185-
? formatResult(filteredLogs[selectedIndex], true)
186-
: '(none)'
187-
logger.log(`Last selection:\n${selectedRow.trim()}`)
188-
})
68+
await outputWithBlessed(result.data, orgSlug)
18969
}
19070

19171
function formatResult(
@@ -308,3 +188,130 @@ ${table}
308188
return ''
309189
}
310190
}
191+
192+
async function outputWithBlessed(
193+
data: SocketSdkReturnType<'getAuditLogEvents'>['data'],
194+
orgSlug: string,
195+
) {
196+
const filteredLogs = data.results
197+
const formattedOutput = filteredLogs.map(logs => [
198+
logs.event_id ?? '',
199+
msAtHome(logs.created_at ?? ''),
200+
logs.type ?? '',
201+
logs.user_email ?? '',
202+
logs.ip_address ?? '',
203+
logs.user_agent ?? '',
204+
])
205+
const headers = [
206+
' Event id',
207+
' Created at',
208+
' Event type',
209+
' User email',
210+
' IP address',
211+
' User agent',
212+
]
213+
214+
// Note: this temporarily takes over the terminal (just like `man` does).
215+
const ScreenWidget = require('blessed/lib/widgets/screen.js')
216+
// Lazily access constants.blessedOptions.
217+
const screen: Widgets.Screen = new ScreenWidget({
218+
...constants.blessedOptions,
219+
})
220+
// Register these keys first so you can always exit, even when it gets stuck
221+
// If we don't do this and the code crashes, the user must hard-kill the
222+
// node process just to exit it. That's very bad UX.
223+
// eslint-disable-next-line n/no-process-exit
224+
screen.key(['escape', 'q', 'C-c'], () => process.exit(0))
225+
226+
const TableWidget = require('blessed-contrib/lib/widget/table.js')
227+
const tipsBoxHeight = 1 // 1 row for tips box
228+
const detailsBoxHeight = 20 // bottom N rows for details box. 20 gives 4 lines for condensed payload before it scrolls out of view
229+
230+
const maxWidths = headers.map(s => s.length + 1)
231+
formattedOutput.forEach(row => {
232+
row.forEach((str, i) => {
233+
maxWidths[i] = Math.max(str.length, maxWidths[i] ?? str.length)
234+
})
235+
})
236+
237+
const table: any = new TableWidget({
238+
keys: 'true',
239+
fg: 'white',
240+
selectedFg: 'white',
241+
selectedBg: 'magenta',
242+
interactive: 'true',
243+
label: `Audit Logs for ${orgSlug}`,
244+
width: '100%',
245+
top: 0,
246+
bottom: detailsBoxHeight + tipsBoxHeight,
247+
border: {
248+
type: 'line',
249+
fg: 'cyan',
250+
},
251+
columnWidth: maxWidths, //[10, 30, 40, 25, 15, 200],
252+
// Note: spacing works as long as you don't reserve more than total width
253+
columnSpacing: 4,
254+
truncate: '_',
255+
})
256+
257+
const BoxWidget = require('blessed/lib/widgets/box.js')
258+
const tipsBox: Widgets.BoxElement = new BoxWidget({
259+
bottom: detailsBoxHeight, // sits just above the details box
260+
height: tipsBoxHeight,
261+
width: '100%',
262+
style: {
263+
fg: 'yellow',
264+
bg: 'black',
265+
},
266+
tags: true,
267+
content: `↑/↓: Move Enter: Select q/ESC: Quit`,
268+
})
269+
const detailsBox: Widgets.BoxElement = new BoxWidget({
270+
bottom: 0,
271+
height: detailsBoxHeight,
272+
width: '100%',
273+
border: {
274+
type: 'line',
275+
fg: 'cyan',
276+
},
277+
label: 'Details',
278+
content: formatResult(filteredLogs[0], true),
279+
style: {
280+
fg: 'white',
281+
},
282+
})
283+
284+
table.setData({
285+
headers: headers,
286+
data: formattedOutput,
287+
})
288+
289+
// allow control the table with the keyboard
290+
table.focus()
291+
292+
// Stacking order: table (top), tipsBox (middle), detailsBox (bottom)
293+
screen.append(table)
294+
screen.append(tipsBox)
295+
screen.append(detailsBox)
296+
297+
// Update details box when selection changes
298+
table.rows.on('select item', () => {
299+
const selectedIndex = table.rows.selected
300+
if (selectedIndex !== undefined && selectedIndex >= 0) {
301+
const selectedRow = filteredLogs[selectedIndex]
302+
detailsBox.setContent(formatResult(selectedRow))
303+
screen.render()
304+
}
305+
})
306+
307+
screen.render()
308+
309+
screen.key(['return'], () => {
310+
const selectedIndex = table.rows.selected
311+
screen.destroy()
312+
const selectedRow = formattedOutput[selectedIndex]
313+
? formatResult(filteredLogs[selectedIndex], true)
314+
: '(none)'
315+
logger.log(`Last selection:\n${selectedRow.trim()}`)
316+
})
317+
}

src/commands/cli.test.mts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ describe('socket root command', async () => {
7171
expect(`\n ${stderr}`).toMatchInlineSnapshot(`
7272
"
7373
\\x1b[31m\\xd7\\x1b[39m Received a visible command that was not added to the list here; json
74+
\\x1b[31m\\xd7\\x1b[39m Found commands in the list that were not marked as public or were not defined at all: [ 'dependencies' ]
7475
_____ _ _ /---------------
7576
| __|___ ___| |_ ___| |_ | Socket.dev CLI ver <redacted>
7677
|__ | * | _| '_| -_| _| | Node: <redacted>, API token set: <redacted>

src/commands/dependencies/cmd-dependencies.mts renamed to src/commands/organization/cmd-organization-dependencies.mts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const config: CliCommandConfig = {
4949
`,
5050
}
5151

52-
export const cmdScanCreate = {
52+
export const cmdOrganizationDependencies = {
5353
description: config.description,
5454
hidden: config.hidden,
5555
run,

src/commands/dependencies/cmd-dependencies.test.mts renamed to src/commands/organization/cmd-organization-dependencies.test.mts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ import { describe, expect } from 'vitest'
33
import constants from '../../../src/constants.mts'
44
import { cmdit, invokeNpm } from '../../../test/utils.mts'
55

6-
describe('socket dependencies', async () => {
6+
describe('socket organization dependencies', async () => {
77
// Lazily access constants.binCliPath.
88
const { binCliPath } = constants
99

1010
cmdit(
11-
['dependencies', '--help', '--config', '{}'],
11+
['organization', 'dependencies', '--help', '--config', '{}'],
1212
'should support --help',
1313
async cmd => {
1414
const { code, stderr, stdout } = await invokeNpm(binCliPath, cmd)
@@ -17,7 +17,7 @@ describe('socket dependencies', async () => {
1717
"Search for any dependency that is being used in your organization
1818
1919
Usage
20-
socket dependencies [options]
20+
socket organization dependencies [options]
2121
2222
API Token Requirements
2323
- Quota: 1 unit
@@ -30,27 +30,33 @@ describe('socket dependencies', async () => {
3030
--offset Page number
3131
3232
Examples
33-
socket dependencies
34-
socket dependencies --limit 20 --offset 10"
33+
socket organization dependencies
34+
socket organization dependencies --limit 20 --offset 10"
3535
`,
3636
)
3737
expect(`\n ${stderr}`).toMatchInlineSnapshot(`
3838
"
3939
_____ _ _ /---------------
4040
| __|___ ___| |_ ___| |_ | Socket.dev CLI ver <redacted>
4141
|__ | * | _| '_| -_| _| | Node: <redacted>, API token set: <redacted>
42-
|_____|___|___|_,_|___|_|.dev | Command: \`socket dependencies\`, cwd: <redacted>"
42+
|_____|___|___|_,_|___|_|.dev | Command: \`socket organization dependencies\`, cwd: <redacted>"
4343
`)
4444

4545
expect(code, 'explicit help should exit with code 0').toBe(0)
4646
expect(stderr, 'banner includes base command').toContain(
47-
'`socket dependencies`',
47+
'`socket organization dependencies`',
4848
)
4949
},
5050
)
5151

5252
cmdit(
53-
['dependencies', '--dry-run', '--config', '{"apiToken":"anything"}'],
53+
[
54+
'organization',
55+
'dependencies',
56+
'--dry-run',
57+
'--config',
58+
'{"apiToken":"anything"}',
59+
],
5460
'should require args with just dry-run',
5561
async cmd => {
5662
const { code, stderr, stdout } = await invokeNpm(binCliPath, cmd)
@@ -60,7 +66,7 @@ describe('socket dependencies', async () => {
6066
_____ _ _ /---------------
6167
| __|___ ___| |_ ___| |_ | Socket.dev CLI ver <redacted>
6268
|__ | * | _| '_| -_| _| | Node: <redacted>, API token set: <redacted>
63-
|_____|___|___|_,_|___|_|.dev | Command: \`socket dependencies\`, cwd: <redacted>"
69+
|_____|___|___|_,_|___|_|.dev | Command: \`socket organization dependencies\`, cwd: <redacted>"
6470
`)
6571

6672
expect(code, 'dry-run should exit with code 0 if input ok').toBe(0)

src/commands/organization/cmd-organization.mts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { cmdOrganizationDependencies } from './cmd-organization-dependencies.mts'
12
import { cmdOrganizationList } from './cmd-organization-list.mts'
23
import { cmdOrganizationPolicyLicense } from './cmd-organization-policy-license.mts'
34
import { cmdOrganizationPolicySecurity } from './cmd-organization-policy-security.mts'
@@ -15,6 +16,7 @@ export const cmdOrganization: CliSubcommand = {
1516
async run(argv, importMeta, { parentName }) {
1617
await meowWithSubcommands(
1718
{
19+
dependencies: cmdOrganizationDependencies,
1820
list: cmdOrganizationList,
1921
quota: cmdOrganizationQuota,
2022
policy: cmdOrganizationPolicy,

0 commit comments

Comments
 (0)