From b63d51cb64de09ccd8a90602cfa4f2cafb4912eb Mon Sep 17 00:00:00 2001 From: Charlie Gerard Date: Thu, 27 Jun 2024 09:20:52 -0700 Subject: [PATCH 1/4] [wip] add dependencies command --- lib/commands/dependencies/index.js | 131 +++++++++++++++++++++++++++++ lib/commands/index.js | 1 + 2 files changed, 132 insertions(+) create mode 100644 lib/commands/dependencies/index.js diff --git a/lib/commands/dependencies/index.js b/lib/commands/dependencies/index.js new file mode 100644 index 00000000..48bbce29 --- /dev/null +++ b/lib/commands/dependencies/index.js @@ -0,0 +1,131 @@ +/* eslint-disable no-console */ + +// import chalk from 'chalk' +import meow from 'meow' +import ora from 'ora' + +import { outputFlags } from '../../flags/index.js' +import { handleApiCall, handleUnsuccessfulApiResponse } from '../../utils/api-helpers.js' +import { prepareFlags } from '../../utils/flags.js' +import { printFlagList } from '../../utils/formatting.js' +import { getDefaultKey, setupSdk } from '../../utils/sdk.js' + +/** @type {import('../../utils/meow-with-subcommands.js').CliSubcommand} */ +export const dependencies = { + description: 'Search for any dependency that is being used in your organization', + async run (argv, importMeta, { parentName }) { + const name = parentName + ' dependencies' + + const input = setupCommand(name, dependencies.description, argv, importMeta) + if (input) { + const spinnerText = 'Searching dependencies...' + const spinner = ora(spinnerText).start() + await searchDeps(input.limit, input.offset, spinner) + } + } +} + +const dependenciesFlags = prepareFlags({ + limit: { + type: 'number', + shortFlag: 'l', + default: 50, + description: 'Repository name', + }, + offset: { + type: 'number', + shortFlag: 'o', + default: 0, + description: 'Branch name', + } + }) + +// Internal functions + +/** + * @typedef Command + * @property {boolean} outputJson + * @property {boolean} outputMarkdown + * @property {number} limit + * @property {number} offset + */ + +/** + * @param {string} name + * @param {string} description + * @param {readonly string[]} argv + * @param {ImportMeta} importMeta + * @returns {void|Command} + */ +function setupCommand (name, description, argv, importMeta) { + const flags = { + ...outputFlags, + ...dependenciesFlags + } + + const cli = meow(` + Usage + $ ${name} + + Options + ${printFlagList(flags, 6)} + + Examples + $ ${name} FakeOrg + `, { + argv, + description, + importMeta, + flags + }) + + const { + json: outputJson, + markdown: outputMarkdown, + limit, + offset + } = cli.flags + +// if (cli.input.length < 2) { +// console.error(`${chalk.bgRed('Input error')}: Please specify an organization slug and a scan ID.\n`) +// cli.showHelp() +// return +// } + + return { + outputJson, + outputMarkdown, + limit, + offset + } +} + +/** + * @typedef DependenciesData + * @property {import('@socketsecurity/sdk').SocketSdkReturnType<'searchDependencies'>["data"]} data + */ + +/** + * @param {number} limit + * @param {number} offset + * @param {import('ora').Ora} spinner + * @returns {Promise} + */ +async function searchDeps (limit, offset, spinner) { + const socketSdk = await setupSdk(getDefaultKey()) + // @ts-ignore + const result = await handleApiCall(socketSdk.searchDependencies({ limit, offset }), 'Searching dependencies') + + if (!result.success) { + return handleUnsuccessfulApiResponse('searchDependencies', result, spinner) + } + + spinner.stop() + + console.log('Organization dependencies: \n') + console.log(result.data) + + return { + data: result.data + } +} diff --git a/lib/commands/index.js b/lib/commands/index.js index f5f5039c..749118a8 100644 --- a/lib/commands/index.js +++ b/lib/commands/index.js @@ -11,3 +11,4 @@ export * from './wrapper/index.js' export * from './scan/index.js' export * from './audit-log/index.js' export * from './repos/index.js' +export * from './dependencies/index.js' From bf7ac22887c2287abcb96baa9513a1c39af83fb1 Mon Sep 17 00:00:00 2001 From: Charlie Gerard Date: Thu, 27 Jun 2024 12:40:10 -0700 Subject: [PATCH 2/4] wip --- lib/commands/dependencies/index.js | 44 ++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/lib/commands/dependencies/index.js b/lib/commands/dependencies/index.js index 48bbce29..be0371fe 100644 --- a/lib/commands/dependencies/index.js +++ b/lib/commands/dependencies/index.js @@ -1,6 +1,8 @@ /* eslint-disable no-console */ -// import chalk from 'chalk' +import chalk from 'chalk' +// @ts-ignore +import chalkTable from 'chalk-table' import meow from 'meow' import ora from 'ora' @@ -20,7 +22,7 @@ export const dependencies = { if (input) { const spinnerText = 'Searching dependencies...' const spinner = ora(spinnerText).start() - await searchDeps(input.limit, input.offset, spinner) + await searchDeps(input, spinner) } } } @@ -30,13 +32,13 @@ const dependenciesFlags = prepareFlags({ type: 'number', shortFlag: 'l', default: 50, - description: 'Repository name', + description: 'Maximum number of dependencies returned', }, offset: { type: 'number', shortFlag: 'o', default: 0, - description: 'Branch name', + description: 'Page number', } }) @@ -71,7 +73,7 @@ function setupCommand (name, description, argv, importMeta) { ${printFlagList(flags, 6)} Examples - $ ${name} FakeOrg + $ ${name} `, { argv, description, @@ -106,12 +108,11 @@ function setupCommand (name, description, argv, importMeta) { */ /** - * @param {number} limit - * @param {number} offset + * @param {Command} input * @param {import('ora').Ora} spinner * @returns {Promise} */ -async function searchDeps (limit, offset, spinner) { +async function searchDeps ({ limit, offset, outputJson }, spinner) { const socketSdk = await setupSdk(getDefaultKey()) // @ts-ignore const result = await handleApiCall(socketSdk.searchDependencies({ limit, offset }), 'Searching dependencies') @@ -123,7 +124,32 @@ async function searchDeps (limit, offset, spinner) { spinner.stop() console.log('Organization dependencies: \n') - console.log(result.data) + + if (outputJson) { + return console.log(result.data) + } + + const options = { + columns: [ + { field: 'namespace', name: chalk.cyan('Namespace') }, + { field: 'name', name: chalk.cyan('Name') }, + { field: 'version', name: chalk.cyan('Version') }, + { field: 'repository', name: chalk.cyan('Repository') }, + { field: 'branch', name: chalk.cyan('Branch') }, + { field: 'type', name: chalk.cyan('Type') }, + { field: 'direct', name: chalk.cyan('Direct') } + ] + } + + const formattedResults = result.data.rows.map((/** @type {{[key:string]: any}} */ d) => { + return { + ...d + } + }) + + const table = chalkTable(options, formattedResults) + + console.log(table, '\n') return { data: result.data From f2fa02b84f35d3fab435976fd3d3e9686fde686a Mon Sep 17 00:00:00 2001 From: Charlie Gerard Date: Thu, 27 Jun 2024 12:54:43 -0700 Subject: [PATCH 3/4] wip --- lib/commands/dependencies/index.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/commands/dependencies/index.js b/lib/commands/dependencies/index.js index be0371fe..1a4c6306 100644 --- a/lib/commands/dependencies/index.js +++ b/lib/commands/dependencies/index.js @@ -88,12 +88,6 @@ function setupCommand (name, description, argv, importMeta) { offset } = cli.flags -// if (cli.input.length < 2) { -// console.error(`${chalk.bgRed('Input error')}: Please specify an organization slug and a scan ID.\n`) -// cli.showHelp() -// return -// } - return { outputJson, outputMarkdown, From 3e6d97e19fbbcc0eb817ac5c326868b1e6622d5c Mon Sep 17 00:00:00 2001 From: Charlie Gerard Date: Thu, 27 Jun 2024 13:29:22 -0700 Subject: [PATCH 4/4] wi[ --- lib/commands/dependencies/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/commands/dependencies/index.js b/lib/commands/dependencies/index.js index 1a4c6306..9c731136 100644 --- a/lib/commands/dependencies/index.js +++ b/lib/commands/dependencies/index.js @@ -108,7 +108,6 @@ function setupCommand (name, description, argv, importMeta) { */ async function searchDeps ({ limit, offset, outputJson }, spinner) { const socketSdk = await setupSdk(getDefaultKey()) - // @ts-ignore const result = await handleApiCall(socketSdk.searchDependencies({ limit, offset }), 'Searching dependencies') if (!result.success) {