Skip to content

Commit ffec641

Browse files
Merge pull request #186 from SocketDev/cg/addDiffScanCommand
Add diff scan command
2 parents c3abf4f + bf4fbc2 commit ffec641

File tree

8 files changed

+216
-0
lines changed

8 files changed

+216
-0
lines changed

.dep-stats.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
"hpagent": "^1.2.0",
106106
"ignore": "^5.3.1",
107107
"ini": "4.1.3",
108+
"node-domexception": "^1.0.0",
108109
"onetime": "^5.1.0",
109110
"pacote": "^18.0.6",
110111
"pony-cause": "^2.1.11",
@@ -129,6 +130,7 @@
129130
"fast-glob": "^3.3.2",
130131
"graceful-fs": "^4.2.6",
131132
"ini": "4.1.3",
133+
"node-domexception": "^1.0.0",
132134
"onetime": "^5.1.0",
133135
"rc": "1.2.8",
134136
"registry-auth-token": "^5.0.2",

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"hpagent": "^1.2.0",
4646
"ignore": "^5.3.1",
4747
"ini": "4.1.3",
48+
"node-domexception": "^1.0.0",
4849
"onetime": "^5.1.0",
4950
"pacote": "^18.0.6",
5051
"pony-cause": "^2.1.11",

src/commands/analytics.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// @ts-ignore
22
import blessed from 'blessed'
3+
// @ts-ignore
34
import contrib from 'blessed-contrib'
45
import fs from 'fs'
56
import meow from 'meow'

src/commands/diff-scan/get.ts

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
import chalk from 'chalk'
2+
import fs from 'fs'
3+
import meow from 'meow'
4+
import ora from 'ora'
5+
import util from 'util'
6+
7+
import { outputFlags } from '../../flags'
8+
import { printFlagList } from '../../utils/formatting'
9+
import { getDefaultKey } from '../../utils/sdk'
10+
11+
import type { CliSubcommand } from '../../utils/meow-with-subcommands'
12+
import type { Ora } from 'ora'
13+
import { AuthError } from '../../utils/errors'
14+
import { handleAPIError, queryAPI } from '../../utils/api-helpers'
15+
16+
export const get: CliSubcommand = {
17+
description: 'Get a diff scan for an organization',
18+
async run(argv, importMeta, { parentName }) {
19+
const name = `${parentName} get`
20+
const input = setupCommand(name, get.description, argv, importMeta)
21+
if (input) {
22+
const apiKey = getDefaultKey()
23+
if(!apiKey){
24+
throw new AuthError("User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.")
25+
}
26+
const spinnerText = 'Getting diff scan... \n'
27+
const spinner = ora(spinnerText).start()
28+
await getDiffScan(input, spinner, apiKey)
29+
}
30+
}
31+
}
32+
33+
const getDiffScanFlags: { [key: string]: any } = {
34+
before: {
35+
type: 'string',
36+
shortFlag: 'b',
37+
default: '',
38+
description: 'The full scan ID of the base scan'
39+
},
40+
after: {
41+
type: 'string',
42+
shortFlag: 'a',
43+
default: '',
44+
description: 'The full scan ID of the head scan'
45+
},
46+
preview: {
47+
type: 'boolean',
48+
shortFlag: 'p',
49+
default: true,
50+
description: 'A boolean flag to persist or not the diff scan result'
51+
},
52+
file: {
53+
type: 'string',
54+
shortFlag: 'f',
55+
default: '',
56+
description: 'Path to a local file where the output should be saved'
57+
}
58+
}
59+
60+
// Internal functions
61+
62+
type CommandContext = {
63+
outputJson: boolean
64+
outputMarkdown: boolean
65+
before: string
66+
after: string
67+
preview: boolean
68+
orgSlug: string
69+
file: string
70+
}
71+
72+
function setupCommand(
73+
name: string,
74+
description: string,
75+
argv: readonly string[],
76+
importMeta: ImportMeta
77+
): CommandContext | undefined {
78+
const flags: { [key: string]: any } = {
79+
...outputFlags,
80+
...getDiffScanFlags
81+
}
82+
83+
const cli = meow(
84+
`
85+
Usage
86+
$ ${name} <org slug> --before=<before> --after=<after>
87+
88+
Options
89+
${printFlagList(flags, 6)}
90+
91+
Examples
92+
$ ${name} FakeCorp --before=aaa0aa0a-aaaa-0000-0a0a-0000000a00a0 --after=aaa1aa1a-aaaa-1111-1a1a-1111111a11a1
93+
`,
94+
{
95+
argv,
96+
description,
97+
importMeta,
98+
flags
99+
}
100+
)
101+
102+
const {
103+
json: outputJson,
104+
markdown: outputMarkdown,
105+
before,
106+
after,
107+
preview,
108+
file
109+
} = cli.flags
110+
111+
if (!before || !after) {
112+
console.error(
113+
`${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`
114+
)
115+
cli.showHelp()
116+
return
117+
}
118+
119+
if(cli.input.length < 1){
120+
console.error(
121+
`${chalk.bgRed.white('Input error')}: Please provide an organization slug \n`
122+
)
123+
cli.showHelp()
124+
return
125+
}
126+
127+
const [orgSlug = ''] = cli.input
128+
129+
return <CommandContext>{
130+
outputJson,
131+
outputMarkdown,
132+
before,
133+
after,
134+
preview,
135+
orgSlug,
136+
file
137+
}
138+
}
139+
140+
async function getDiffScan(
141+
{ before, after, orgSlug, file }: CommandContext,
142+
spinner: Ora,
143+
apiKey: string,
144+
): Promise<void> {
145+
const response = await queryAPI(`${orgSlug}/full-scans/diff?before=${before}&after=${after}&preview`, apiKey)
146+
const data = await response.json();
147+
148+
if(!response.ok){
149+
spinner.stop()
150+
const err = await handleAPIError(response.status)
151+
console.error(
152+
`${chalk.bgRed.white(response.statusText)}: ${err} \n`
153+
)
154+
return
155+
}
156+
157+
spinner.stop()
158+
159+
if(file){
160+
fs.writeFile(file, JSON.stringify(data), err => {
161+
err ? console.error(err) : console.log(`Data successfully written to ${file}`)
162+
})
163+
return
164+
}
165+
166+
console.log(`\n Diff scan result: \n`)
167+
console.log(util.inspect(data, {showHidden: false, depth: null, colors: true}))
168+
}

src/commands/diff-scan/index.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { get } from './get'
2+
import { meowWithSubcommands } from '../../utils/meow-with-subcommands'
3+
4+
import type { CliSubcommand } from '../../utils/meow-with-subcommands'
5+
6+
const description = 'Diff scans related commands'
7+
8+
export const diffScan: CliSubcommand = {
9+
description,
10+
run: async (argv, importMeta, { parentName }) => {
11+
await meowWithSubcommands(
12+
{
13+
get
14+
},
15+
{
16+
argv,
17+
description,
18+
importMeta,
19+
name: parentName + ' diff-scan'
20+
}
21+
)
22+
}
23+
}

src/commands/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ export * from './audit-log'
1414
export * from './repos'
1515
export * from './dependencies'
1616
export * from './analytics'
17+
export * from './diff-scan'

src/utils/api-helpers.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,22 @@ export async function handleApiCall<T>(
4545

4646
return result
4747
}
48+
49+
export async function handleAPIError(code: number) {
50+
if(code === 400){
51+
return `One of the options passed might be incorrect.`
52+
} else if (code === 403){
53+
return `You might be trying to access an organization that is not linked to the API key you are logged in with.`
54+
}
55+
}
56+
57+
const API_V0_URL = 'https://api.socket.dev/v0'
58+
59+
export async function queryAPI(path: string, apiKey: string) {
60+
return await fetch(`${API_V0_URL}/orgs/${path}`, {
61+
method: 'GET',
62+
headers: {
63+
'Authorization': 'Basic ' + btoa(`${apiKey}:${apiKey}`)
64+
}
65+
});
66+
}

0 commit comments

Comments
 (0)