@aikidosec/ci-api-client 1.0.4 → 1.0.6

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.
@@ -1,373 +1,381 @@
1
- import chalk from 'chalk';
2
- import { Argument, Command, InvalidArgumentError, Option } from 'commander';
3
- import { Ora } from 'ora';
4
- import {
5
- TPollIsScanningResult,
6
- TPollScanCompletedDefaultBranchResult,
7
- TPollScanFeatureBranchCompletedResult,
8
- TScanApiOptions,
9
- TStartScanResult,
10
- pollScanStatus,
11
- startScan,
12
- } from '../aikidoApi.js';
13
- import { getApiKey } from '../configuration.js';
14
- import {
15
- outputError,
16
- outputHttpError,
17
- outputLog,
18
- startSpinner,
19
- } from '../output.js';
20
-
21
- type TScanArguments = {
22
- repoId: string | number;
23
- baseCommitId: string;
24
- headCommitId: string;
25
- branchName: string;
26
- options: TScanApiOptions;
27
- pollInterval: number;
28
- onStart?: () => void | null;
29
- onStartComplete?: (startResult: any) => void | null;
30
- onStartFail?: (error: any) => void | null;
31
- onScanStart?: (
32
- startResult:
33
- | TPollIsScanningResult
34
- | TPollScanFeatureBranchCompletedResult
35
- | TPollScanCompletedDefaultBranchResult
36
- ) => void | null;
37
- onNextPoll?: (
38
- pollResult:
39
- | TPollIsScanningResult
40
- | TPollScanFeatureBranchCompletedResult
41
- | TPollScanCompletedDefaultBranchResult
42
- ) => void | null;
43
- onScanComplete?: (
44
- pollResult:
45
- | TPollIsScanningResult
46
- | TPollScanFeatureBranchCompletedResult
47
- | TPollScanCompletedDefaultBranchResult
48
- ) => void | null;
49
- onScanFail?: (error: any) => void | null;
50
- };
51
-
52
- type TScanCliOptions = {
53
- pollInterval: number;
54
- };
55
-
56
- type TScanUserCliOptions = {
57
- pullRequestTitle?: string;
58
- pullRequestUrl?: string;
59
- selfManagedScanners?: string[];
60
- failOnDependencyScan?: boolean;
61
- failOnSastScan?: boolean;
62
- failOnIacScan?: boolean;
63
- minimumSeverityLevel?: string;
64
- pollInterval?: number;
65
- };
66
-
67
- async function cli(
68
- repoId: string,
69
- baseCommitId: string,
70
- headCommitId: string,
71
- branchName: string,
72
- options: TScanUserCliOptions,
73
- command: string
74
- ) {
75
- const apiKey = getApiKey();
76
-
77
- if (!apiKey) {
78
- outputError('Please set an api key using: aikido-cli apikey <key>');
79
- }
80
-
81
- // Process command options and group them into apiOptions hash
82
- const { apiOptions, cliOptions } = parseCliOptions(options);
83
-
84
- let loader: Ora | null;
85
- let pollCount: number = 1;
86
-
87
- // Setup different scan() event handlers
88
- const onStart = () => {
89
- loader = startSpinner('Starting Aikido Security scan');
90
- };
91
-
92
- const onStartComplete = (startResult: TStartScanResult) => {
93
- loader?.succeed(
94
- `Aikido Security scan started (id: ${startResult.scan_id})`
95
- );
96
- };
97
-
98
- const onNextPoll = () => {
99
- if (loader) {
100
- loader.text = `Polling for Aikido Security scan to complete (${pollCount})`;
101
- }
102
-
103
- pollCount += 1;
104
- };
105
-
106
- const onScanStart = () => {
107
- loader = startSpinner('Waiting for scan to complete');
108
- };
109
-
110
- const onScanComplete = (pollResult: any) => {
111
- if (pollResult.gate_passed === true) {
112
- loader?.succeed('Scan completed, no new issues found');
113
- if (pollResult.diff_url) {
114
- outputLog(chalk.gray(`* Diff url: ${pollResult.diff_url}`));
115
- }
116
- } else {
117
- loader?.fail('Scan completed with issues');
118
-
119
- if (pollResult.open_issues_found) {
120
- outputLog(
121
- chalk.gray(
122
- chalk.bold('Open issues found: ') + pollResult.open_issues_found
123
- )
124
- );
125
- }
126
-
127
- if (pollResult.issue_links) {
128
- outputLog(
129
- chalk.gray(
130
- pollResult.issue_links
131
- .map((issueLink: string) => '- ' + issueLink)
132
- .join('\n')
133
- )
134
- );
135
- }
136
-
137
- if (pollResult.diff_url) {
138
- outputLog(chalk.gray(`* Diff url: ${pollResult.diff_url}`));
139
- }
140
-
141
- process.exit(10);
142
- }
143
- };
144
-
145
- const onFail = (error: any) => {
146
- loader?.fail();
147
-
148
- if (error.response?.status && error.response?.status === 404) {
149
- outputError(
150
- 'Please verify your repoId, baseCommitId, headCommitId and branchName'
151
- );
152
- } else {
153
- outputHttpError(error);
154
- }
155
-
156
- process.exit(1);
157
- };
158
-
159
- await scan({
160
- repoId,
161
- baseCommitId,
162
- headCommitId,
163
- branchName,
164
- options: apiOptions,
165
- pollInterval: cliOptions.pollInterval,
166
- onStart,
167
- onStartComplete,
168
- onStartFail: onFail,
169
- onNextPoll,
170
- onScanStart,
171
- onScanComplete,
172
- onScanFail: onFail,
173
- });
174
- }
175
-
176
- export const scan = async ({
177
- repoId,
178
- baseCommitId,
179
- headCommitId,
180
- branchName,
181
- options,
182
- pollInterval = 5,
183
- onStart,
184
- onStartComplete,
185
- onStartFail,
186
- onScanStart,
187
- onNextPoll,
188
- onScanComplete,
189
- onScanFail,
190
- }: TScanArguments): Promise<void> => {
191
- onStart?.();
192
-
193
- let result: any | null = null;
194
-
195
- // Initialize a scan and call onStartComplete, onStartFail
196
- // handlers where needed
197
- try {
198
- result = await startScan({
199
- repository_id: repoId,
200
- base_commit_id: baseCommitId,
201
- head_commit_id: headCommitId,
202
- branch_name: branchName,
203
- ...options,
204
- });
205
-
206
- if (result.scan_id) {
207
- onStartComplete?.(result);
208
- } else {
209
- onStartFail?.(result);
210
- return;
211
- }
212
- } catch (error) {
213
- onStartFail?.(error);
214
- return;
215
- }
216
-
217
- onScanStart?.(result);
218
- let pollResult;
219
-
220
- // Poll status with a setTimeout
221
- const pollStatus = async () => {
222
- try {
223
- pollResult = await pollScanStatus(result.scan_id);
224
-
225
- // If "all_scans_completed" returns true, call the onScanComplete
226
- // handler, if not, re poll with `pollInterval`
227
- // Note that onScanComplete can return a successfull or
228
- // unsuccessfull scan result
229
- if (pollResult.all_scans_completed === false) {
230
- onNextPoll?.(pollResult);
231
- setTimeout(pollStatus, pollInterval * 1000);
232
- } else {
233
- onScanComplete?.(pollResult);
234
- }
235
- } catch (error) {
236
- onScanFail?.(error);
237
- }
238
- };
239
-
240
- // Start polling
241
- pollStatus();
242
- };
243
-
244
- const parseCliOptions = (userCliOptions: TScanUserCliOptions) => {
245
- // Version provided to the API corresponds with the version in package.json
246
- // of the cli client
247
- const apiOptions: TScanApiOptions = { version: '1.0.5' };
248
- const cliOptions: TScanCliOptions = { pollInterval: 5 };
249
-
250
- if (userCliOptions.pullRequestTitle) {
251
- apiOptions.pull_request_metadata = {
252
- ...(apiOptions.pull_request_metadata ?? {}),
253
- title: userCliOptions.pullRequestTitle,
254
- };
255
- }
256
- if (userCliOptions.pullRequestUrl) {
257
- apiOptions.pull_request_metadata = {
258
- ...(apiOptions.pull_request_metadata ?? {}),
259
- url: userCliOptions.pullRequestUrl,
260
- };
261
- }
262
- if (userCliOptions.selfManagedScanners) {
263
- apiOptions.self_managed_scanners = userCliOptions.selfManagedScanners;
264
- }
265
- if (userCliOptions.failOnDependencyScan != undefined) {
266
- apiOptions.fail_on_dependency_scan = userCliOptions.failOnDependencyScan;
267
- }
268
- if (userCliOptions.failOnSastScan != undefined) {
269
- apiOptions.fail_on_sast_scan = userCliOptions.failOnSastScan;
270
- }
271
- if (userCliOptions.failOnIacScan != undefined) {
272
- apiOptions.fail_on_iac_scan = userCliOptions.failOnIacScan;
273
- }
274
- if (userCliOptions.minimumSeverityLevel) {
275
- apiOptions.minimum_severity = userCliOptions.minimumSeverityLevel;
276
- }
277
- if (
278
- userCliOptions.pollInterval &&
279
- (isNaN(userCliOptions.pollInterval) || userCliOptions.pollInterval <= 0)
280
- ) {
281
- outputError('Please provide a valid poll interval');
282
- } else if (userCliOptions.pollInterval) {
283
- cliOptions.pollInterval = userCliOptions.pollInterval;
284
- }
285
-
286
- return { apiOptions, cliOptions };
287
- };
288
-
289
- const validateCommitId = (value: string) => {
290
- const testCommitId = (commitId: string): boolean =>
291
- commitId.length === 40 && /^[0-9a-f]{40}$/.test(commitId);
292
-
293
- if (testCommitId(value) === false) {
294
- throw new InvalidArgumentError('Please provide a valid commit ID');
295
- }
296
-
297
- return value;
298
- };
299
-
300
- export const cliSetup = (program: Command) =>
301
- program
302
- .command('scan')
303
- .addArgument(
304
- new Argument(
305
- '<repository_id>',
306
- 'The internal GitHub/Gitlab/Bitbucket/.. repository id you want to scan.'
307
- ).argRequired()
308
- )
309
- .addArgument(
310
- new Argument(
311
- '<base_commit_id>',
312
- 'The base commit of the code you want to scan (e.g. the commit where you branched from for your PR or the initial commit of your repo)'
313
- )
314
- .argRequired()
315
- .argParser(validateCommitId)
316
- )
317
- .addArgument(
318
- new Argument(
319
- '<head_commit_id>',
320
- 'The latest commit you want to include in your scan (e.g. the latest commit id of your pull request)'
321
- )
322
- .argRequired()
323
- .argParser(validateCommitId)
324
- )
325
- .addArgument(
326
- new Argument('<branch_name>', 'The branch name')
327
- .argOptional()
328
- .default('main')
329
- )
330
- .option('--pull-request-title <title>', 'Your pull request title')
331
- .option('--pull-request-url <url>', 'Your pull request URL')
332
- .addOption(
333
- new Option(
334
- '--self-managed-scanners <scanners...>',
335
- 'Set the minimum severity level. Accepted options are: LOW, MEDIUM, HIGH and CRITICAL.'
336
- ).choices(['checkov', 'json-sbom'])
337
- )
338
- .option(
339
- '--expected-amount-json-sboms <amount>',
340
- 'The expected amount of json sbombs'
341
- )
342
- .addOption(
343
- new Option(
344
- '--no-fail-on-dependency-scan',
345
- "Don't fail when scanning depedencies..."
346
- )
347
- )
348
- .option(
349
- '--fail-on-sast-scan',
350
- 'Let Aikido fail when new static code analysis issues have been detected...'
351
- )
352
- .option(
353
- '--fail-on-iac-scan',
354
- 'Let Aikido fail when new infrastructure as code issues have been detected...'
355
- )
356
- .addOption(
357
- new Option(
358
- '--minimum-severity-level <level>',
359
- 'Set the minimum severity level. Accepted options are: LOW, MEDIUM, HIGH and CRITICAL.'
360
- ).choices(['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'])
361
- )
362
- .addOption(
363
- new Option(
364
- '--poll-interval [interval]',
365
- 'The poll interval when checking for an updated scan result'
366
- )
367
- .preset(5)
368
- .argParser(parseFloat)
369
- )
370
- .description('Run a scan of an Aikido repo.')
371
- .action(cli);
372
-
373
- export default { cli, cliSetup, scan };
1
+ import chalk from 'chalk';
2
+ import { Argument, Command, InvalidArgumentError, Option } from 'commander';
3
+ import { Ora } from 'ora';
4
+ import {
5
+ TPollIsScanningResult,
6
+ TPollScanCompletedDefaultBranchResult,
7
+ TPollScanFeatureBranchCompletedResult,
8
+ TScanApiOptions,
9
+ TStartScanResult,
10
+ pollScanStatus,
11
+ startScan,
12
+ } from '../aikidoApi.js';
13
+ import { getApiKey } from '../configuration.js';
14
+ import {
15
+ outputError,
16
+ outputHttpError,
17
+ outputLog,
18
+ startSpinner,
19
+ } from '../output.js';
20
+
21
+ type TScanArguments = {
22
+ repoId: string | number;
23
+ baseCommitId: string;
24
+ headCommitId: string;
25
+ branchName: string;
26
+ options: TScanApiOptions;
27
+ pollInterval: number;
28
+ onStart?: () => void | null;
29
+ onStartComplete?: (startResult: any) => void | null;
30
+ onStartFail?: (error: any) => void | null;
31
+ onScanStart?: (
32
+ startResult:
33
+ | TPollIsScanningResult
34
+ | TPollScanFeatureBranchCompletedResult
35
+ | TPollScanCompletedDefaultBranchResult
36
+ ) => void | null;
37
+ onNextPoll?: (
38
+ pollResult:
39
+ | TPollIsScanningResult
40
+ | TPollScanFeatureBranchCompletedResult
41
+ | TPollScanCompletedDefaultBranchResult
42
+ ) => void | null;
43
+ onScanComplete?: (
44
+ pollResult:
45
+ | TPollIsScanningResult
46
+ | TPollScanFeatureBranchCompletedResult
47
+ | TPollScanCompletedDefaultBranchResult
48
+ ) => void | null;
49
+ onScanFail?: (error: any) => void | null;
50
+ };
51
+
52
+ type TScanCliOptions = {
53
+ pollInterval: number;
54
+ };
55
+
56
+ type TScanUserCliOptions = {
57
+ pullRequestTitle?: string;
58
+ pullRequestUrl?: string;
59
+ selfManagedScanners?: string[];
60
+ failOnDependencyScan?: boolean;
61
+ failOnSastScan?: boolean;
62
+ failOnSecretsScan?: boolean;
63
+ failOnIacScan?: boolean;
64
+ minimumSeverityLevel?: string;
65
+ pollInterval?: number;
66
+ };
67
+
68
+ async function cli(
69
+ repoId: string,
70
+ baseCommitId: string,
71
+ headCommitId: string,
72
+ branchName: string,
73
+ options: TScanUserCliOptions,
74
+ command: string
75
+ ) {
76
+ const apiKey = getApiKey();
77
+
78
+ if (!apiKey) {
79
+ outputError('Please set an api key using: aikido-cli apikey <key>');
80
+ }
81
+
82
+ // Process command options and group them into apiOptions hash
83
+ const { apiOptions, cliOptions } = parseCliOptions(options);
84
+
85
+ let loader: Ora | null;
86
+ let pollCount: number = 1;
87
+
88
+ // Setup different scan() event handlers
89
+ const onStart = () => {
90
+ loader = startSpinner('Starting Aikido Security scan');
91
+ };
92
+
93
+ const onStartComplete = (startResult: TStartScanResult) => {
94
+ loader?.succeed(
95
+ `Aikido Security scan started (id: ${startResult.scan_id})`
96
+ );
97
+ };
98
+
99
+ const onNextPoll = () => {
100
+ if (loader) {
101
+ loader.text = `Polling for Aikido Security scan to complete (${pollCount})`;
102
+ }
103
+
104
+ pollCount += 1;
105
+ };
106
+
107
+ const onScanStart = () => {
108
+ loader = startSpinner('Waiting for scan to complete');
109
+ };
110
+
111
+ const onScanComplete = (pollResult: any) => {
112
+ if (pollResult.gate_passed === true) {
113
+ loader?.succeed('Scan completed, no new issues found');
114
+ if (pollResult.diff_url) {
115
+ outputLog(chalk.gray(`* Diff url: ${pollResult.diff_url}`));
116
+ }
117
+ } else {
118
+ loader?.fail('Scan completed with issues');
119
+
120
+ if (pollResult.open_issues_found) {
121
+ outputLog(
122
+ chalk.gray(
123
+ chalk.bold('Open issues found: ') + pollResult.open_issues_found
124
+ )
125
+ );
126
+ }
127
+
128
+ if (pollResult.issue_links) {
129
+ outputLog(
130
+ chalk.gray(
131
+ pollResult.issue_links
132
+ .map((issueLink: string) => '- ' + issueLink)
133
+ .join('\n')
134
+ )
135
+ );
136
+ }
137
+
138
+ if (pollResult.diff_url) {
139
+ outputLog(chalk.gray(`* Diff url: ${pollResult.diff_url}`));
140
+ }
141
+
142
+ process.exit(10);
143
+ }
144
+ };
145
+
146
+ const onFail = (error: any) => {
147
+ loader?.fail();
148
+
149
+ if (error.response?.status && error.response?.status === 404) {
150
+ outputError(
151
+ 'Please verify your repoId, baseCommitId, headCommitId and branchName'
152
+ );
153
+ } else {
154
+ outputHttpError(error);
155
+ }
156
+
157
+ process.exit(1);
158
+ };
159
+
160
+ await scan({
161
+ repoId,
162
+ baseCommitId,
163
+ headCommitId,
164
+ branchName,
165
+ options: apiOptions,
166
+ pollInterval: cliOptions.pollInterval,
167
+ onStart,
168
+ onStartComplete,
169
+ onStartFail: onFail,
170
+ onNextPoll,
171
+ onScanStart,
172
+ onScanComplete,
173
+ onScanFail: onFail,
174
+ });
175
+ }
176
+
177
+ export const scan = async ({
178
+ repoId,
179
+ baseCommitId,
180
+ headCommitId,
181
+ branchName,
182
+ options,
183
+ pollInterval = 5,
184
+ onStart,
185
+ onStartComplete,
186
+ onStartFail,
187
+ onScanStart,
188
+ onNextPoll,
189
+ onScanComplete,
190
+ onScanFail,
191
+ }: TScanArguments): Promise<void> => {
192
+ onStart?.();
193
+
194
+ let result: any | null = null;
195
+
196
+ // Initialize a scan and call onStartComplete, onStartFail
197
+ // handlers where needed
198
+ try {
199
+ result = await startScan({
200
+ repository_id: repoId,
201
+ base_commit_id: baseCommitId,
202
+ head_commit_id: headCommitId,
203
+ branch_name: branchName,
204
+ ...options,
205
+ });
206
+
207
+ if (result.scan_id) {
208
+ onStartComplete?.(result);
209
+ } else {
210
+ onStartFail?.(result);
211
+ return;
212
+ }
213
+ } catch (error) {
214
+ onStartFail?.(error);
215
+ return;
216
+ }
217
+
218
+ onScanStart?.(result);
219
+ let pollResult;
220
+
221
+ // Poll status with a setTimeout
222
+ const pollStatus = async () => {
223
+ try {
224
+ pollResult = await pollScanStatus(result.scan_id);
225
+
226
+ // If "all_scans_completed" returns true, call the onScanComplete
227
+ // handler, if not, re poll with `pollInterval`
228
+ // Note that onScanComplete can return a successfull or
229
+ // unsuccessfull scan result
230
+ if (pollResult.all_scans_completed === false) {
231
+ onNextPoll?.(pollResult);
232
+ setTimeout(pollStatus, pollInterval * 1000);
233
+ } else {
234
+ onScanComplete?.(pollResult);
235
+ }
236
+ } catch (error) {
237
+ onScanFail?.(error);
238
+ }
239
+ };
240
+
241
+ // Start polling
242
+ pollStatus();
243
+ };
244
+
245
+ const parseCliOptions = (userCliOptions: TScanUserCliOptions) => {
246
+ // Version provided to the API corresponds with the version in package.json
247
+ // of the cli client
248
+ const apiOptions: TScanApiOptions = { version: '1.0.6' };
249
+ const cliOptions: TScanCliOptions = { pollInterval: 5 };
250
+
251
+ if (userCliOptions.pullRequestTitle) {
252
+ apiOptions.pull_request_metadata = {
253
+ ...(apiOptions.pull_request_metadata ?? {}),
254
+ title: userCliOptions.pullRequestTitle,
255
+ };
256
+ }
257
+ if (userCliOptions.pullRequestUrl) {
258
+ apiOptions.pull_request_metadata = {
259
+ ...(apiOptions.pull_request_metadata ?? {}),
260
+ url: userCliOptions.pullRequestUrl,
261
+ };
262
+ }
263
+ if (userCliOptions.selfManagedScanners) {
264
+ apiOptions.self_managed_scanners = userCliOptions.selfManagedScanners;
265
+ }
266
+ if (userCliOptions.failOnDependencyScan != undefined) {
267
+ apiOptions.fail_on_dependency_scan = userCliOptions.failOnDependencyScan;
268
+ }
269
+ if (userCliOptions.failOnSastScan != undefined) {
270
+ apiOptions.fail_on_sast_scan = userCliOptions.failOnSastScan;
271
+ }
272
+ if (userCliOptions.failOnIacScan != undefined) {
273
+ apiOptions.fail_on_iac_scan = userCliOptions.failOnIacScan;
274
+ }
275
+ if (userCliOptions.failOnSecretsScan != undefined) {
276
+ apiOptions.fail_on_secrets_scan = userCliOptions.failOnSecretsScan;
277
+ }
278
+ if (userCliOptions.minimumSeverityLevel) {
279
+ apiOptions.minimum_severity = userCliOptions.minimumSeverityLevel;
280
+ }
281
+ if (
282
+ userCliOptions.pollInterval &&
283
+ (isNaN(userCliOptions.pollInterval) || userCliOptions.pollInterval <= 0)
284
+ ) {
285
+ outputError('Please provide a valid poll interval');
286
+ } else if (userCliOptions.pollInterval) {
287
+ cliOptions.pollInterval = userCliOptions.pollInterval;
288
+ }
289
+
290
+ return { apiOptions, cliOptions };
291
+ };
292
+
293
+ const validateCommitId = (value: string) => {
294
+ const testCommitId = (commitId: string): boolean =>
295
+ commitId.length === 40 && /^[0-9a-f]{40}$/.test(commitId);
296
+
297
+ if (testCommitId(value) === false) {
298
+ throw new InvalidArgumentError('Please provide a valid commit ID');
299
+ }
300
+
301
+ return value;
302
+ };
303
+
304
+ export const cliSetup = (program: Command) =>
305
+ program
306
+ .command('scan')
307
+ .addArgument(
308
+ new Argument(
309
+ '<repository_id>',
310
+ 'The internal GitHub/Gitlab/Bitbucket/.. repository id you want to scan.'
311
+ ).argRequired()
312
+ )
313
+ .addArgument(
314
+ new Argument(
315
+ '<base_commit_id>',
316
+ 'The base commit of the code you want to scan (e.g. the commit where you branched from for your PR or the initial commit of your repo)'
317
+ )
318
+ .argRequired()
319
+ .argParser(validateCommitId)
320
+ )
321
+ .addArgument(
322
+ new Argument(
323
+ '<head_commit_id>',
324
+ 'The latest commit you want to include in your scan (e.g. the latest commit id of your pull request)'
325
+ )
326
+ .argRequired()
327
+ .argParser(validateCommitId)
328
+ )
329
+ .addArgument(
330
+ new Argument('<branch_name>', 'The branch name')
331
+ .argOptional()
332
+ .default('main')
333
+ )
334
+ .option('--pull-request-title <title>', 'Your pull request title')
335
+ .option('--pull-request-url <url>', 'Your pull request URL')
336
+ .addOption(
337
+ new Option(
338
+ '--self-managed-scanners <scanners...>',
339
+ 'Set the minimum severity level. Accepted options are: LOW, MEDIUM, HIGH and CRITICAL.'
340
+ ).choices(['checkov', 'json-sbom'])
341
+ )
342
+ .option(
343
+ '--expected-amount-json-sboms <amount>',
344
+ 'The expected amount of json sbombs'
345
+ )
346
+ .addOption(
347
+ new Option(
348
+ '--no-fail-on-dependency-scan',
349
+ "Don't fail when scanning depedencies..."
350
+ )
351
+ )
352
+ .option(
353
+ '--fail-on-sast-scan',
354
+ 'Let Aikido fail when new static code analysis issues have been detected...'
355
+ )
356
+ .option(
357
+ '--fail-on-iac-scan',
358
+ 'Let Aikido fail when new infrastructure as code issues have been detected...'
359
+ )
360
+ .option(
361
+ '--fail-on-secrets-scan',
362
+ 'Let Aikido fail when new exposed secrets have been detected...'
363
+ )
364
+ .addOption(
365
+ new Option(
366
+ '--minimum-severity-level <level>',
367
+ 'Set the minimum severity level. Accepted options are: LOW, MEDIUM, HIGH and CRITICAL.'
368
+ ).choices(['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'])
369
+ )
370
+ .addOption(
371
+ new Option(
372
+ '--poll-interval [interval]',
373
+ 'The poll interval when checking for an updated scan result'
374
+ )
375
+ .preset(5)
376
+ .argParser(parseFloat)
377
+ )
378
+ .description('Run a scan of an Aikido repo.')
379
+ .action(cli);
380
+
381
+ export default { cli, cliSetup, scan };