Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add diff scan command #186

Merged
merged 11 commits into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .dep-stats.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
"hpagent": "^1.2.0",
"ignore": "^5.3.1",
"ini": "4.1.3",
"node-domexception": "^1.0.0",
"onetime": "^5.1.0",
"pacote": "^18.0.6",
"pony-cause": "^2.1.11",
Expand All @@ -129,6 +130,7 @@
"fast-glob": "^3.3.2",
"graceful-fs": "^4.2.6",
"ini": "4.1.3",
"node-domexception": "^1.0.0",
"onetime": "^5.1.0",
"rc": "1.2.8",
"registry-auth-token": "^5.0.2",
Expand Down
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"hpagent": "^1.2.0",
"ignore": "^5.3.1",
"ini": "4.1.3",
"node-domexception": "^1.0.0",
"onetime": "^5.1.0",
"pacote": "^18.0.6",
"pony-cause": "^2.1.11",
Expand Down
1 change: 1 addition & 0 deletions src/commands/analytics.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// @ts-ignore
import blessed from 'blessed'
// @ts-ignore
import contrib from 'blessed-contrib'

Check warning on line 4 in src/commands/analytics.ts

View workflow job for this annotation

GitHub Actions / Linting / Test (20, ubuntu-latest)

There should be at least one empty line between import groups
import fs from 'fs'

Check warning on line 5 in src/commands/analytics.ts

View workflow job for this annotation

GitHub Actions / Linting / Test (20, ubuntu-latest)

There should be at least one empty line between import groups

Check warning on line 5 in src/commands/analytics.ts

View workflow job for this annotation

GitHub Actions / Linting / Test (20, ubuntu-latest)

`fs` import should occur before import of `blessed`
import meow from 'meow'
import ora from 'ora'

Expand All @@ -12,8 +13,8 @@
import { getDefaultKey, setupSdk } from '../utils/sdk'

import type { CliSubcommand } from '../utils/meow-with-subcommands'
import type { Ora } from "ora"

Check warning on line 16 in src/commands/analytics.ts

View workflow job for this annotation

GitHub Actions / Linting / Test (20, ubuntu-latest)

There should be at least one empty line between import groups
import chalk from 'chalk'

Check warning on line 17 in src/commands/analytics.ts

View workflow job for this annotation

GitHub Actions / Linting / Test (20, ubuntu-latest)

`chalk` import should occur before import of `meow`

export const analytics: CliSubcommand = {
description: `Look up analytics data \n
Expand Down
168 changes: 168 additions & 0 deletions src/commands/diff-scan/get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import chalk from 'chalk'

Check warning on line 1 in src/commands/diff-scan/get.ts

View workflow job for this annotation

GitHub Actions / Linting / Test (20, ubuntu-latest)

There should be at least one empty line between import groups
import fs from 'fs'
import meow from 'meow'
import ora from 'ora'
import util from 'util'

import { outputFlags } from '../../flags'
import { printFlagList } from '../../utils/formatting'
import { getDefaultKey } from '../../utils/sdk'

import type { CliSubcommand } from '../../utils/meow-with-subcommands'
import type { Ora } from 'ora'
import { AuthError } from '../../utils/errors'
import { handleAPIError, queryAPI } from '../../utils/api-helpers'

export const get: CliSubcommand = {
description: 'Get a diff scan for an organization',
async run(argv, importMeta, { parentName }) {
const name = `${parentName} get`
const input = setupCommand(name, get.description, argv, importMeta)
if (input) {
const apiKey = getDefaultKey()
if(!apiKey){
throw new AuthError("User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.")
}
const spinnerText = 'Getting diff scan... \n'
const spinner = ora(spinnerText).start()
await getDiffScan(input, spinner, apiKey)
}
}
}

const getDiffScanFlags: { [key: string]: any } = {
before: {
type: 'string',
shortFlag: 'b',
default: '',
description: 'The full scan ID of the base scan'
},
after: {
type: 'string',
shortFlag: 'a',
default: '',
description: 'The full scan ID of the head scan'
},
preview: {
type: 'boolean',
shortFlag: 'p',
default: true,
description: 'A boolean flag to persist or not the diff scan result'
},
file: {
type: 'string',
shortFlag: 'f',
default: '',
description: 'Path to a local file where the output should be saved'
}
}

// Internal functions

type CommandContext = {
outputJson: boolean
outputMarkdown: boolean
before: string
after: string
preview: boolean
orgSlug: string
file: string
}

function setupCommand(
name: string,
description: string,
argv: readonly string[],
importMeta: ImportMeta
): CommandContext | undefined {
const flags: { [key: string]: any } = {
...outputFlags,
...getDiffScanFlags
}

const cli = meow(
`
Usage
$ ${name} <org slug> --before=<before> --after=<after>

Options
${printFlagList(flags, 6)}

Examples
$ ${name} FakeCorp --before=aaa0aa0a-aaaa-0000-0a0a-0000000a00a0 --after=aaa1aa1a-aaaa-1111-1a1a-1111111a11a1
`,
{
argv,
description,
importMeta,
flags
}
)

const {
json: outputJson,
markdown: outputMarkdown,
before,
after,
preview,
file
} = cli.flags

if (!before || !after) {
console.error(
`${chalk.bgRed.white('Input error')}: Please specify a before and after full scan ID. To get full scans IDs, you can run the command "socket scan list <your org slug>". \n`
)
cli.showHelp()
return
}

if(cli.input.length < 1){
console.error(
`${chalk.bgRed.white('Input error')}: Please provide an organization slug \n`
)
cli.showHelp()
return
}

const [orgSlug = ''] = cli.input

return <CommandContext>{
outputJson,
outputMarkdown,
before,
after,
preview,
orgSlug,
file
}
}

async function getDiffScan(
{ before, after, orgSlug, file }: CommandContext,
spinner: Ora,
apiKey: string,
): Promise<void> {
const response = await queryAPI(`${orgSlug}/full-scans/diff?before=${before}&after=${after}&preview`, apiKey)
const data = await response.json();

if(!response.ok){
spinner.stop()
const err = await handleAPIError(response.status)
console.error(
`${chalk.bgRed.white(response.statusText)}: ${err} \n`
)
return
}

spinner.stop()

if(file){
fs.writeFile(file, JSON.stringify(data), err => {
err ? console.error(err) : console.log(`Data successfully written to ${file}`)
})
return
}

console.log(`\n Diff scan result: \n`)
console.log(util.inspect(data, {showHidden: false, depth: null, colors: true}))
}
23 changes: 23 additions & 0 deletions src/commands/diff-scan/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { get } from './get'
import { meowWithSubcommands } from '../../utils/meow-with-subcommands'

import type { CliSubcommand } from '../../utils/meow-with-subcommands'

const description = 'Diff scans related commands'

export const diffScan: CliSubcommand = {
description,
run: async (argv, importMeta, { parentName }) => {
await meowWithSubcommands(
{
get
},
{
argv,
description,
importMeta,
name: parentName + ' diff-scan'
}
)
}
}
1 change: 1 addition & 0 deletions src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ export * from './audit-log'
export * from './repos'
export * from './dependencies'
export * from './analytics'
export * from './diff-scan'
19 changes: 19 additions & 0 deletions src/utils/api-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,22 @@ export async function handleApiCall<T>(

return result
}

export async function handleAPIError(code: number) {
if(code === 400){
return `One of the options passed might be incorrect.`
} else if (code === 403){
return `You might be trying to access an organization that is not linked to the API key you are logged in with.`
}
}

const API_V0_URL = 'https://api.socket.dev/v0'

export async function queryAPI(path: string, apiKey: string) {
return await fetch(`${API_V0_URL}/orgs/${path}`, {
method: 'GET',
headers: {
'Authorization': 'Basic ' + btoa(`${apiKey}:${apiKey}`)
}
});
}
Loading