@aikidosec/ci-api-client 1.0.3 → 1.0.5

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.
package/README.md CHANGED
@@ -31,14 +31,14 @@ $ aikido-api-client apikey <your-api-key-here>
31
31
  Using the `aikido-api-client` to start new scans is very straightforward.
32
32
 
33
33
  ```sh
34
- $ aikido-api-client scan <repository_id> <base_commit_id> <head_commit_id>
34
+ $ aikido-api-client scan <repository_id or repository_name> <base_commit_id> <head_commit_id>
35
35
  ```
36
36
 
37
37
  The process will report scan progress and will exit with exitCode `0` if the scan was successfull (`gate_passed: true`). The process will exit with exitCode `10` if the scan was unsuccesfull (`gate_passed: false`). If anything else goes wrong (e.g. API unavailable, scanning unavailable, other unexpected issue) the process will exit with exitCode `1`.
38
38
 
39
39
  If you want the scan to run quietly (without output), you can add the `--quiet` option to the command.
40
40
 
41
- Please note that the repository_id which you need to provide to the CLI is the unique ID of the Git provider you are using, not the ID of the repository in Aikido. You can also find this ID in Aikido, by going to the repository's detail page and clicking on the Git provider's icon in the header.
41
+ Please note that the repository_id which you need to provide to the CLI is the unique ID of the Git provider you are using, not the ID of the repository in Aikido. You can also find this ID in Aikido, by going to the repository's detail page and clicking on the Git provider's icon in the header. Alternatively, you can pass the repository name as it is defined in Aikido.
42
42
 
43
43
  ```sh
44
44
  # For more options and combinations, check the help output
@@ -11,6 +11,7 @@ export type TScanApiOptions = {
11
11
  fail_on_dependency_scan?: boolean;
12
12
  fail_on_sast_scan?: boolean;
13
13
  fail_on_iac_scan?: boolean;
14
+ fail_on_secrets_scan?: boolean;
14
15
  minimum_severity?: string;
15
16
  version: string;
16
17
  };
@@ -23,6 +24,7 @@ export type TPollIsScanningResult = {
23
24
  dependency_scan_completed: boolean;
24
25
  sast_scan_completed: boolean;
25
26
  iac_scan_completed: boolean;
27
+ secrets_scan_completed: boolean;
26
28
  sbom_scan_completed?: boolean;
27
29
  };
28
30
  type TPollScanCompletedOptions = {
@@ -33,6 +35,7 @@ type TPollScanFeatureBranchCompletedOptions = {
33
35
  new_dependency_issues_found: number;
34
36
  new_sast_issues_found: number;
35
37
  new_iac_issues_found: number;
38
+ new_leaked_secret_issues_found: number;
36
39
  diff_url: string;
37
40
  };
38
41
  type TPollScanDefaultBranchCompletedOptions = {
@@ -21,6 +21,7 @@ type TScanUserCliOptions = {
21
21
  selfManagedScanners?: string[];
22
22
  failOnDependencyScan?: boolean;
23
23
  failOnSastScan?: boolean;
24
+ failOnSecretsScan?: boolean;
24
25
  failOnIacScan?: boolean;
25
26
  minimumSeverityLevel?: string;
26
27
  pollInterval?: number;
@@ -144,6 +144,9 @@ const parseCliOptions = (userCliOptions) => {
144
144
  if (userCliOptions.failOnIacScan != undefined) {
145
145
  apiOptions.fail_on_iac_scan = userCliOptions.failOnIacScan;
146
146
  }
147
+ if (userCliOptions.failOnSecretsScan != undefined) {
148
+ apiOptions.fail_on_secrets_scan = userCliOptions.failOnSecretsScan;
149
+ }
147
150
  if (userCliOptions.minimumSeverityLevel) {
148
151
  apiOptions.minimum_severity = userCliOptions.minimumSeverityLevel;
149
152
  }
@@ -182,6 +185,7 @@ export const cliSetup = (program) => program
182
185
  .addOption(new Option('--no-fail-on-dependency-scan', "Don't fail when scanning depedencies..."))
183
186
  .option('--fail-on-sast-scan', 'Let Aikido fail when new static code analysis issues have been detected...')
184
187
  .option('--fail-on-iac-scan', 'Let Aikido fail when new infrastructure as code issues have been detected...')
188
+ .option('--fail-on-secrets-scan', 'Let Aikido fail when new leaked secrets have been detected...')
185
189
  .addOption(new Option('--minimum-severity-level <level>', 'Set the minimum severity level. Accepted options are: LOW, MEDIUM, HIGH and CRITICAL.').choices(['LOW', 'MEDIUM', 'HIGH', 'CRITICAL']))
186
190
  .addOption(new Option('--poll-interval [interval]', 'The poll interval when checking for an updated scan result')
187
191
  .preset(5)
package/lib/index.js CHANGED
@@ -10,7 +10,7 @@ export const program = new Command();
10
10
  program
11
11
  .name('Aikido API Client')
12
12
  .description('CLI api client to easily integrate the Aikido public CI API into custom deploy scripts')
13
- .version('1.0.3');
13
+ .version('1.0.4');
14
14
  apiKey.cliSetup(program);
15
15
  scan.cliSetup(program);
16
16
  upload.cliSetup(program);
package/lib/output.js CHANGED
@@ -17,30 +17,24 @@ export const outputError = (message, exitCode = 1) => {
17
17
  });
18
18
  };
19
19
  export const outputHttpError = (axiosError) => {
20
- if (axiosError.code === 'ECONNREFUSED') {
21
- outputError(`Could not connect to Aikido API (${axiosError.message}). Please verify your network settings`);
22
- }
23
- else if (axiosError.response?.status &&
24
- axiosError.response?.status === 401) {
25
- outputError('Request failed. The provided api key is most likely no longer valid and has been rotated or revoked. Visit https://app.aikido.dev/settings/integrations/continuous-integration to generate a new key.');
26
- }
27
- else if (axiosError.response?.status &&
28
- axiosError.response?.status === 403) {
29
- outputError('Could not authenticate with the Aikido API. Please verify your Aikdio API key.');
30
- }
31
- else if (axiosError.response?.status &&
32
- axiosError.response?.status === 500) {
33
- outputError('Something went wrong contacting the Aikido API.');
34
- }
35
- const statusStr = axiosError.response?.status
36
- ? ` (${axiosError.response?.status})`
37
- : '';
38
- if (axiosError.response) {
39
- outputDebug(axiosError.response?.status);
40
- outputDebug(axiosError.response?.headers);
41
- outputDebug(axiosError.response?.data);
42
- }
43
- outputError(`Something unexpected went wrong${statusStr}... Please contact us if this problem persists.`);
20
+ outputDebug(axiosError);
21
+ if (axiosError.isAxiosError) {
22
+ if (axiosError.response) {
23
+ const statusStr = `${axiosError.response.status} ${axiosError.response.statusText}`;
24
+ switch (axiosError.response.status) {
25
+ case 401:
26
+ return outputError(`${statusStr}: The provided api key is most likely no longer valid and has been rotated or revoked. Visit https://app.aikido.dev/settings/integrations/continuous-integration to generate a new key.`);
27
+ case 403:
28
+ return outputError(`${statusStr}: Could not authenticate with the Aikido API. Please verify your Aikdio API key.`);
29
+ case 500:
30
+ return outputError(`${statusStr}: Something went wrong contacting the Aikido API. Please try again later.`);
31
+ default:
32
+ return outputError(`${statusStr}: ${axiosError.response.data ?? ''} Please contact us if this problem persists.`);
33
+ }
34
+ }
35
+ return outputError(`${axiosError.name}: ${axiosError.message}`);
36
+ }
37
+ return outputError('Unexpected error occurred. Please contact us if this problem persists.');
44
38
  };
45
39
  export const startSpinner = (message) => {
46
40
  if (process.env.QUIET) {
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@aikidosec/ci-api-client",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "CLI api client to easily integrate the Aikido public CI API into custom deploy scripts",
5
5
  "license": "MIT",
6
6
  "author": "Bert Devriese <bert@builtinbruges.com>",
7
+ "private": false,
7
8
  "type": "module",
8
9
  "main": "lib/index.js",
9
10
  "bin": {
@@ -18,7 +19,10 @@
18
19
  "build": "tsc -p .",
19
20
  "local": "yarn build && yarn global add file:$PWD; aikido-api-client",
20
21
  "local-rm": "yarn global remove aikido-api-client",
21
- "format": "prettier --write 'src/**/*.ts'"
22
+ "format": "prettier --write 'src/**/*.ts'",
23
+ "//": {
24
+ "refresh": "rm -rf ./node_modules ./yarn.lock && yarn"
25
+ }
22
26
  },
23
27
  "dependencies": {
24
28
  "axios": "^1.4.0",
@@ -43,6 +47,5 @@
43
47
  "aikido",
44
48
  "security",
45
49
  "cli"
46
- ],
47
- "packageManager": "yarn@4.1.1"
48
- }
50
+ ]
51
+ }
package/src/aikidoApi.ts CHANGED
@@ -22,6 +22,7 @@ export type TScanApiOptions = {
22
22
  fail_on_dependency_scan?: boolean;
23
23
  fail_on_sast_scan?: boolean;
24
24
  fail_on_iac_scan?: boolean;
25
+ fail_on_secrets_scan?: boolean;
25
26
  minimum_severity?: string;
26
27
  version: string;
27
28
  };
@@ -58,6 +59,7 @@ export type TPollIsScanningResult = {
58
59
  dependency_scan_completed: boolean;
59
60
  sast_scan_completed: boolean;
60
61
  iac_scan_completed: boolean;
62
+ secrets_scan_completed: boolean;
61
63
  sbom_scan_completed?: boolean;
62
64
  };
63
65
 
@@ -70,6 +72,7 @@ type TPollScanFeatureBranchCompletedOptions = {
70
72
  new_dependency_issues_found: number;
71
73
  new_sast_issues_found: number;
72
74
  new_iac_issues_found: number;
75
+ new_leaked_secret_issues_found: number;
73
76
  diff_url: string;
74
77
  };
75
78
 
@@ -5,7 +5,8 @@ import { outputError, outputLog } from '../output.js';
5
5
  const API_KEY_REGEX = /^AIK_CI_[a-zA-Z0-9]{64}$/g;
6
6
 
7
7
  function cli(apiKey: string): void {
8
- const isValidApiKey = API_KEY_REGEX.test(apiKey) || apiKey.trim().length === 128;
8
+ const isValidApiKey =
9
+ API_KEY_REGEX.test(apiKey) || apiKey.trim().length === 128;
9
10
  if (apiKey && !isValidApiKey) {
10
11
  outputError('That does not seem right, please verify your api key');
11
12
  }
@@ -59,6 +59,7 @@ type TScanUserCliOptions = {
59
59
  selfManagedScanners?: string[];
60
60
  failOnDependencyScan?: boolean;
61
61
  failOnSastScan?: boolean;
62
+ failOnSecretsScan?: boolean;
62
63
  failOnIacScan?: boolean;
63
64
  minimumSeverityLevel?: string;
64
65
  pollInterval?: number;
@@ -271,6 +272,9 @@ const parseCliOptions = (userCliOptions: TScanUserCliOptions) => {
271
272
  if (userCliOptions.failOnIacScan != undefined) {
272
273
  apiOptions.fail_on_iac_scan = userCliOptions.failOnIacScan;
273
274
  }
275
+ if (userCliOptions.failOnSecretsScan != undefined) {
276
+ apiOptions.fail_on_secrets_scan = userCliOptions.failOnSecretsScan;
277
+ }
274
278
  if (userCliOptions.minimumSeverityLevel) {
275
279
  apiOptions.minimum_severity = userCliOptions.minimumSeverityLevel;
276
280
  }
@@ -353,6 +357,10 @@ export const cliSetup = (program: Command) =>
353
357
  '--fail-on-iac-scan',
354
358
  'Let Aikido fail when new infrastructure as code issues have been detected...'
355
359
  )
360
+ .option(
361
+ '--fail-on-secrets-scan',
362
+ 'Let Aikido fail when new exposed secrets have been detected...'
363
+ )
356
364
  .addOption(
357
365
  new Option(
358
366
  '--minimum-severity-level <level>',
package/src/index.ts CHANGED
@@ -19,7 +19,7 @@ program
19
19
  .description(
20
20
  'CLI api client to easily integrate the Aikido public CI API into custom deploy scripts'
21
21
  )
22
- .version('1.0.3');
22
+ .version('1.0.4');
23
23
 
24
24
  // Load in all app commands and set them up in the `program` instance
25
25
  apiKey.cliSetup(program);
package/src/output.ts CHANGED
@@ -30,43 +30,38 @@ export const outputError = (message: string, exitCode: number = 1): void => {
30
30
  };
31
31
 
32
32
  export const outputHttpError = (axiosError: AxiosError): void => {
33
- if (axiosError.code === 'ECONNREFUSED') {
34
- outputError(
35
- `Could not connect to Aikido API (${axiosError.message}). Please verify your network settings`
36
- );
37
- } else if (
38
- axiosError.response?.status &&
39
- axiosError.response?.status === 401
40
- ) {
41
- outputError(
42
- 'Request failed. The provided api key is most likely no longer valid and has been rotated or revoked. Visit https://app.aikido.dev/settings/integrations/continuous-integration to generate a new key.'
43
- );
44
- } else if (
45
- axiosError.response?.status &&
46
- axiosError.response?.status === 403
47
- ) {
48
- outputError(
49
- 'Could not authenticate with the Aikido API. Please verify your Aikdio API key.'
50
- );
51
- } else if (
52
- axiosError.response?.status &&
53
- axiosError.response?.status === 500
54
- ) {
55
- outputError('Something went wrong contacting the Aikido API.');
56
- }
33
+ outputDebug(axiosError);
57
34
 
58
- const statusStr = axiosError.response?.status
59
- ? ` (${axiosError.response?.status})`
60
- : '';
35
+ if (axiosError.isAxiosError) {
36
+ if (axiosError.response) {
37
+ const statusStr = `${axiosError.response.status} ${axiosError.response.statusText}`;
38
+ switch (axiosError.response.status) {
39
+ case 401:
40
+ return outputError(
41
+ `${statusStr}: The provided api key is most likely no longer valid and has been rotated or revoked. Visit https://app.aikido.dev/settings/integrations/continuous-integration to generate a new key.`
42
+ );
43
+ case 403:
44
+ return outputError(
45
+ `${statusStr}: Could not authenticate with the Aikido API. Please verify your Aikdio API key.`
46
+ );
47
+ case 500:
48
+ return outputError(
49
+ `${statusStr}: Something went wrong contacting the Aikido API. Please try again later.`
50
+ );
51
+ default:
52
+ return outputError(
53
+ `${statusStr}: ${
54
+ axiosError.response.data ?? ''
55
+ } Please contact us if this problem persists.`
56
+ );
57
+ }
58
+ }
61
59
 
62
- if (axiosError.response) {
63
- outputDebug(axiosError.response?.status);
64
- outputDebug(axiosError.response?.headers);
65
- outputDebug(axiosError.response?.data);
60
+ return outputError(`${axiosError.name}: ${axiosError.message}`);
66
61
  }
67
62
 
68
- outputError(
69
- `Something unexpected went wrong${statusStr}... Please contact us if this problem persists.`
63
+ return outputError(
64
+ 'Unexpected error occurred. Please contact us if this problem persists.'
70
65
  );
71
66
  };
72
67
 
package/.npmrc DELETED
File without changes