@contrast/contrast 1.0.0
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 +109 -0
- package/bin/contrast.js +2 -0
- package/dist/commands/auth/auth.js +61 -0
- package/dist/commands/config/config.js +24 -0
- package/dist/commands/scan/processScan.js +23 -0
- package/dist/common/HTTPClient.js +192 -0
- package/dist/common/errorHandling.js +60 -0
- package/dist/constants/constants.js +30 -0
- package/dist/constants/lambda.js +31 -0
- package/dist/constants/locales.js +259 -0
- package/dist/constants.js +150 -0
- package/dist/index.js +56 -0
- package/dist/lambda/__mocks__/aws.js +21 -0
- package/dist/lambda/__mocks__/lambdaConfig.json +42 -0
- package/dist/lambda/arn.js +21 -0
- package/dist/lambda/aws.js +169 -0
- package/dist/lambda/cliError.js +76 -0
- package/dist/lambda/constants.js +11 -0
- package/dist/lambda/help.js +75 -0
- package/dist/lambda/lambda.js +130 -0
- package/dist/lambda/logUtils.js +36 -0
- package/dist/lambda/scanDetail.js +30 -0
- package/dist/lambda/scanDetailCompletion.js +56 -0
- package/dist/lambda/scanRequest.js +93 -0
- package/dist/lambda/scanResults.js +16 -0
- package/dist/lambda/utils.js +90 -0
- package/dist/scan/autoDetection.js +76 -0
- package/dist/scan/fileFinder.js +15 -0
- package/dist/scan/fileUtils.js +31 -0
- package/dist/scan/help.js +68 -0
- package/dist/scan/populateProjectIdAndProjectName.js +55 -0
- package/dist/scan/scan.js +96 -0
- package/dist/scan/scanController.js +54 -0
- package/dist/scan/scanResults.js +85 -0
- package/dist/utils/commonApi.js +45 -0
- package/dist/utils/filterProjectPath.js +20 -0
- package/dist/utils/getConfig.js +30 -0
- package/dist/utils/oraWrapper.js +20 -0
- package/dist/utils/paramsUtil/commandlineParams.js +31 -0
- package/dist/utils/paramsUtil/configStoreParams.js +18 -0
- package/dist/utils/paramsUtil/envVariableParams.js +10 -0
- package/dist/utils/paramsUtil/paramHandler.js +28 -0
- package/dist/utils/paramsUtil/yamlParams.js +6 -0
- package/dist/utils/parsedCLIOptions.js +13 -0
- package/dist/utils/requestUtils.js +18 -0
- package/dist/utils/validationCheck.js +26 -0
- package/package.json +123 -0
- package/src/commands/auth/auth.js +73 -0
- package/src/commands/config/config.js +25 -0
- package/src/commands/scan/processScan.js +29 -0
- package/src/common/HTTPClient.js +269 -0
- package/src/common/errorHandling.ts +79 -0
- package/src/constants/constants.js +34 -0
- package/src/constants/lambda.js +41 -0
- package/src/constants/locales.js +381 -0
- package/src/constants.js +168 -0
- package/src/index.ts +69 -0
- package/src/lambda/__mocks__/aws.ts +32 -0
- package/src/lambda/__mocks__/lambdaConfig.json +42 -0
- package/src/lambda/arn.ts +32 -0
- package/src/lambda/aws.ts +247 -0
- package/src/lambda/cliError.ts +72 -0
- package/src/lambda/constants.ts +11 -0
- package/src/lambda/help.ts +76 -0
- package/src/lambda/lambda.ts +174 -0
- package/src/lambda/logUtils.ts +46 -0
- package/src/lambda/scanDetailCompletion.ts +78 -0
- package/src/lambda/scanRequest.ts +142 -0
- package/src/lambda/scanResults.ts +29 -0
- package/src/lambda/utils.ts +125 -0
- package/src/scan/autoDetection.js +77 -0
- package/src/scan/fileUtils.js +33 -0
- package/src/scan/help.js +74 -0
- package/src/scan/populateProjectIdAndProjectName.js +62 -0
- package/src/scan/scan.js +126 -0
- package/src/scan/scanController.js +69 -0
- package/src/scan/scanResults.js +96 -0
- package/src/utils/commonApi.js +54 -0
- package/src/utils/filterProjectPath.js +21 -0
- package/src/utils/getConfig.ts +42 -0
- package/src/utils/oraWrapper.js +24 -0
- package/src/utils/paramsUtil/commandlineParams.js +37 -0
- package/src/utils/paramsUtil/configStoreParams.js +19 -0
- package/src/utils/paramsUtil/envVariableParams.js +10 -0
- package/src/utils/paramsUtil/paramHandler.js +28 -0
- package/src/utils/parsedCLIOptions.js +17 -0
- package/src/utils/requestUtils.js +22 -0
- package/src/utils/validationCheck.js +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Contrast Command Line Interface
|
|
2
|
+
|
|
3
|
+
Install Contrast, authenticate, and then start running a Lambda scan.
|
|
4
|
+
This version supports **Java** and **Python** functions on AWS.
|
|
5
|
+
|
|
6
|
+
## Requirements
|
|
7
|
+
|
|
8
|
+
- AWS credentials should be **available** on your local configure (usually `~/.aws/credentials`)
|
|
9
|
+
- You have an option run lambda scan with your aws-profile to pass `--profile`
|
|
10
|
+
- You also can export differnt credentials
|
|
11
|
+
|
|
12
|
+
```shell
|
|
13
|
+
export AWS_DEFAULT_REGION=<YOUR_AWS_REGION>
|
|
14
|
+
export AWS_ACCESS_KEY_ID=<YOUR_ACCESS_KEY_ID>
|
|
15
|
+
export AWS_SECRET_ACCESS_KEY=<YOUR_SECRET_ACCESS_KEY>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
These permissions are required to gather all required information on an AWS Lambda to use the `contrast lambda` command:
|
|
19
|
+
|
|
20
|
+
- Lambda: [GetFunction](https://docs.aws.amazon.com/lambda/latest/dg/API_GetFunction.html), [GetLayerVersion](https://docs.aws.amazon.com/lambda/latest/dg/API_GetLayerVersion.html)
|
|
21
|
+
- IAM: [GetRolePolicy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetRolePolicy.html), [GetPolicy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetPolicy.html), [GetPolicyVersion](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetPolicyVersion.html), [ListRolePolicies](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListRolePolicies.html), [ListAttachedRolePolicies](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListAttachedRolePolicies.html)
|
|
22
|
+
|
|
23
|
+
Policy example:
|
|
24
|
+
```
|
|
25
|
+
{
|
|
26
|
+
"Version": "2012-10-17",
|
|
27
|
+
"Statement": [
|
|
28
|
+
{
|
|
29
|
+
"Sid": "VisualEditor0",
|
|
30
|
+
"Effect": "Allow",
|
|
31
|
+
"Action": [
|
|
32
|
+
"iam:GetPolicyVersion",
|
|
33
|
+
"iam:GetPolicy",
|
|
34
|
+
"lambda:GetLayerVersion",
|
|
35
|
+
"lambda:GetFunction",
|
|
36
|
+
"iam:ListAttachedRolePolicies",
|
|
37
|
+
"iam:ListRolePolicies",
|
|
38
|
+
"iam:GetRolePolicy"
|
|
39
|
+
],
|
|
40
|
+
"Resource": [
|
|
41
|
+
"arn:aws:lambda:*:YOUR_ACCOUNT:layer:*:*",
|
|
42
|
+
"arn:aws:lambda:*:YOUR_ACCOUNT:function:*",
|
|
43
|
+
"arn:aws:iam::YOUR_ACCOUNT:role/*",
|
|
44
|
+
"arn:aws:iam::YOUR_ACCOUNT:policy/*"
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Installation via Homebrew
|
|
52
|
+
|
|
53
|
+
- `brew tap Contrast-Security-OSS/homebrew-contrast`
|
|
54
|
+
- `brew install contrast`
|
|
55
|
+
|
|
56
|
+
### Install NPM / YARN
|
|
57
|
+
|
|
58
|
+
- `npm i -g @contrast/contrast`
|
|
59
|
+
- `yarn global add @contrast/contrast`
|
|
60
|
+
|
|
61
|
+
### Install with binaries
|
|
62
|
+
|
|
63
|
+
- Go to [https://pkg.contrastsecurity.com/ui/repos/tree/General/cli](https://pkg.contrastsecurity.com/ui/repos/tree/General/cli)
|
|
64
|
+
- Select your operating system and download the package
|
|
65
|
+
- You must allow **execute permissions** on the file depending on your OS
|
|
66
|
+
|
|
67
|
+
| Architecture | Link |
|
|
68
|
+
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
69
|
+
| macOS | [https://pkg.contrastsecurity.com/ui/repos/tree/General/cli/1.0.0/mac/contrast](https://pkg.contrastsecurity.com/ui/repos/tree/General/cli/1.0.0/mac/contrast) |
|
|
70
|
+
| Linux | [https://pkg.contrastsecurity.com/ui/repos/tree/General/cli/1.0.0/linux/contrast](https://pkg.contrastsecurity.com/ui/repos/tree/General/cli/1.0.0/linux/contrast) |
|
|
71
|
+
| Windows | [https://pkg.contrastsecurity.com/ui/repos/tree/General/cli/1.0.0/windows/contrast.exe](https://pkg.contrastsecurity.com/ui/repos/tree/General/cli/1.0.0/windows/contrast.exe) |
|
|
72
|
+
|
|
73
|
+
## Usage
|
|
74
|
+
|
|
75
|
+
- `contrast [command] [option]`
|
|
76
|
+
- `contrast lambda --function-name <function> [options]`
|
|
77
|
+
|
|
78
|
+
## Running a scan on a Lambda function
|
|
79
|
+
|
|
80
|
+
1. `contrast auth`
|
|
81
|
+
Authenticate by entering contrast auth in the terminal.
|
|
82
|
+
In the resulting browser window, log in and authenticate with your GitHub or Google credentials.
|
|
83
|
+
2. `contrast lambda --function-name <YOUR_FUNCTION_NAME> --region <AWS_REGION>`
|
|
84
|
+
|
|
85
|
+
More infromation
|
|
86
|
+
|
|
87
|
+
- `contrast lambda --help`
|
|
88
|
+
|
|
89
|
+
## Commands
|
|
90
|
+
|
|
91
|
+
- `auth` - Authenticate Contrast using your `Github` or `Google` account
|
|
92
|
+
- `lambda` - Perform scan on AWS Lambda function
|
|
93
|
+
- `version` - Displays version of Contrast CLI
|
|
94
|
+
- `config` - Displays stored credentials (`–c, --clear` - Removes stored credentials)
|
|
95
|
+
- `help` - Displays usage guide
|
|
96
|
+
|
|
97
|
+
## Example of Running
|
|
98
|
+
|
|
99
|
+
```shell
|
|
100
|
+
contrast lambda --function-name myFunctionName
|
|
101
|
+
contrast lambda -f myFunctionName --region eu-cental-1
|
|
102
|
+
contrast lambda -f myFunctionName --region eu-cental-1 --profile myDevProfile
|
|
103
|
+
contrast lambda -f myFunctionName -v -j -r eu-cental-1 -p myDevProfile
|
|
104
|
+
contrast lambda --function-name myFunctionName --verbose --json-output --region eu-cental-1 --profile myDevProfile
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Example of Results
|
|
108
|
+
|
|
109
|
+

|
package/bin/contrast.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const { v4: uuidv4 } = require('uuid');
|
|
3
|
+
const { setConfigValues } = require('../../utils/getConfig');
|
|
4
|
+
const open = require('open');
|
|
5
|
+
const commonApi = require('../../utils/commonApi');
|
|
6
|
+
const { sleep } = require('../../utils/requestUtils');
|
|
7
|
+
const i18n = require('i18n');
|
|
8
|
+
const { returnOra, startSpinner, failSpinner, succeedSpinner } = require('../../utils/oraWrapper');
|
|
9
|
+
const { TIMEOUT, AUTH_UI_URL } = require('../../constants/constants');
|
|
10
|
+
const processAuth = async (config) => {
|
|
11
|
+
const token = uuidv4();
|
|
12
|
+
const url = `${AUTH_UI_URL}/?token=${token}`;
|
|
13
|
+
console.log(i18n.__('redirectAuth', url));
|
|
14
|
+
try {
|
|
15
|
+
await setTimeout(() => {
|
|
16
|
+
open(url);
|
|
17
|
+
}, 0);
|
|
18
|
+
const result = await isAuthComplete(token, TIMEOUT, config);
|
|
19
|
+
if (result) {
|
|
20
|
+
setConfigValues(config, result);
|
|
21
|
+
}
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
const isAuthComplete = async (token, timeout, config) => {
|
|
28
|
+
const authSpinner = returnOra(i18n.__('authWaitingMessage'));
|
|
29
|
+
startSpinner(authSpinner);
|
|
30
|
+
const client = commonApi.getHttpClient(config);
|
|
31
|
+
let startTime = new Date();
|
|
32
|
+
let complete = false;
|
|
33
|
+
while (!complete) {
|
|
34
|
+
let result = await pollAuthResult(token, client);
|
|
35
|
+
if (result.statusCode === 200) {
|
|
36
|
+
succeedSpinner(authSpinner, i18n.__('authSuccessMessage'));
|
|
37
|
+
console.log(i18n.__('runScanMessage'));
|
|
38
|
+
return result.body;
|
|
39
|
+
}
|
|
40
|
+
let endTime = new Date() - startTime;
|
|
41
|
+
if (endTime > timeout) {
|
|
42
|
+
failSpinner(authSpinner, i18n.__('authTimedOutMessage'));
|
|
43
|
+
process.exit(1);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const pollAuthResult = async (token, client) => {
|
|
49
|
+
await sleep(5000);
|
|
50
|
+
return client
|
|
51
|
+
.pollForAuth(token)
|
|
52
|
+
.then(res => {
|
|
53
|
+
return res;
|
|
54
|
+
})
|
|
55
|
+
.catch(err => {
|
|
56
|
+
console.log(err);
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
module.exports = {
|
|
60
|
+
processAuth: processAuth
|
|
61
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const commandLineArgs = require('command-line-args');
|
|
3
|
+
const processConfig = (argv, config) => {
|
|
4
|
+
const options = [{ name: 'clear', alias: 'c', type: Boolean }];
|
|
5
|
+
try {
|
|
6
|
+
const configOptions = commandLineArgs(options, {
|
|
7
|
+
argv,
|
|
8
|
+
caseInsensitive: true,
|
|
9
|
+
camelCase: true
|
|
10
|
+
});
|
|
11
|
+
if (configOptions.clear) {
|
|
12
|
+
config.clear();
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
console.log(JSON.parse(JSON.stringify(config.store)));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
catch (e) {
|
|
19
|
+
console.log(e.message.toString());
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
module.exports = {
|
|
23
|
+
processConfig: processConfig
|
|
24
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const { startScan } = require('../../scan/scanController');
|
|
3
|
+
const paramHandler = require('../../utils/paramsUtil/paramHandler');
|
|
4
|
+
const { formatScanOutput } = require('../../scan/scan');
|
|
5
|
+
const { scanUsageGuide } = require('../../scan/help');
|
|
6
|
+
const processScan = async () => {
|
|
7
|
+
let getScanSubCommands = paramHandler.getScanSubCommands();
|
|
8
|
+
if (getScanSubCommands.help) {
|
|
9
|
+
printHelpMessage();
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
let scanResults = await startScan();
|
|
13
|
+
if (scanResults) {
|
|
14
|
+
formatScanOutput(scanResults?.projectOverview, scanResults?.scanResultsInstances);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
const printHelpMessage = () => {
|
|
18
|
+
console.log(scanUsageGuide);
|
|
19
|
+
};
|
|
20
|
+
module.exports = {
|
|
21
|
+
processScan,
|
|
22
|
+
printHelpMessage
|
|
23
|
+
};
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const _ = require('lodash');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const requestUtils = require('./../utils/requestUtils');
|
|
5
|
+
const { AUTH_CALLBACK_URL } = require('../constants/constants');
|
|
6
|
+
function HTTPClient(config) {
|
|
7
|
+
const apiKey = config.apiKey;
|
|
8
|
+
const authToken = config.authorization;
|
|
9
|
+
const superApiKey = config.super_api_key;
|
|
10
|
+
const superAuthToken = config.super_authorization;
|
|
11
|
+
this.requestOptions = {
|
|
12
|
+
forever: true,
|
|
13
|
+
json: true,
|
|
14
|
+
rejectUnauthorized: this.rejectUnauthorized,
|
|
15
|
+
uri: config.host,
|
|
16
|
+
followRedirect: false,
|
|
17
|
+
headers: {
|
|
18
|
+
'Content-Type': 'application/json; charset=utf-8',
|
|
19
|
+
Authorization: authToken,
|
|
20
|
+
'API-Key': apiKey,
|
|
21
|
+
SuperAuthorization: superAuthToken,
|
|
22
|
+
'Super-API-Key': superApiKey
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
if (config.proxy) {
|
|
26
|
+
this.requestOptions.proxy = config.proxy;
|
|
27
|
+
}
|
|
28
|
+
this.maybeAddCertsToRequest(config);
|
|
29
|
+
}
|
|
30
|
+
HTTPClient.prototype.maybeAddCertsToRequest = function (config) {
|
|
31
|
+
const caCertFilePath = config.cacert;
|
|
32
|
+
if (caCertFilePath) {
|
|
33
|
+
const caFileContent = fs.readFileSync(caCertFilePath);
|
|
34
|
+
if (caFileContent instanceof Error) {
|
|
35
|
+
throw new Error(`Unable to read CA from config option contrast.api.certificate.ca_file='${caCertFilePath}', msg: ${caFileContent.message}`);
|
|
36
|
+
}
|
|
37
|
+
this.requestOptions.ca = caFileContent;
|
|
38
|
+
}
|
|
39
|
+
const certPath = config.cert;
|
|
40
|
+
if (certPath) {
|
|
41
|
+
const certFile = fs.readFileSync(certPath);
|
|
42
|
+
if (certFile instanceof Error) {
|
|
43
|
+
throw new Error(`Unable to read Certificate PEM file from config option contrast.api.certificate.cert_file='${certPath}', msg: ${certFile.message}`);
|
|
44
|
+
}
|
|
45
|
+
this.requestOptions.cert = certFile;
|
|
46
|
+
}
|
|
47
|
+
const keyPath = config.key;
|
|
48
|
+
if (keyPath) {
|
|
49
|
+
const keyFile = fs.readFileSync(keyPath);
|
|
50
|
+
if (keyFile instanceof Error) {
|
|
51
|
+
throw new Error(`Unable to read Key PEM file from config option contrast.api.certificate.key_file='${keyPath}', msg: ${keyFile.message}`);
|
|
52
|
+
}
|
|
53
|
+
this.requestOptions.key = keyFile;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
HTTPClient.prototype.getScanResultsInstances = function getScanResultsInstances(config, scanId) {
|
|
57
|
+
const options = _.cloneDeep(this.requestOptions);
|
|
58
|
+
let url = createScanResultsInstancesURL(config, scanId);
|
|
59
|
+
options.url = url;
|
|
60
|
+
return requestUtils.sendRequest({ method: 'get', options });
|
|
61
|
+
};
|
|
62
|
+
HTTPClient.prototype.getSpecificScanResult = function getSpecificScanResult(config, scanId) {
|
|
63
|
+
const options = _.cloneDeep(this.requestOptions);
|
|
64
|
+
let url = createSpecificScanResultURL(config, scanId);
|
|
65
|
+
options.url = url;
|
|
66
|
+
return requestUtils.sendRequest({ method: 'get', options });
|
|
67
|
+
};
|
|
68
|
+
HTTPClient.prototype.getScanId = function getScanId(config, codeArtifactId) {
|
|
69
|
+
const options = _.cloneDeep(this.requestOptions);
|
|
70
|
+
let url = createGetScanIdURL(config);
|
|
71
|
+
options.url = url;
|
|
72
|
+
options.body = {
|
|
73
|
+
codeArtifactId: codeArtifactId,
|
|
74
|
+
label: `Started by CLI tool at ${new Date().toString()}`
|
|
75
|
+
};
|
|
76
|
+
return requestUtils.sendRequest({ method: 'post', options });
|
|
77
|
+
};
|
|
78
|
+
HTTPClient.prototype.sendArtifact = async function sendArtifact(config) {
|
|
79
|
+
const options = _.cloneDeep(this.requestOptions);
|
|
80
|
+
let formData = {
|
|
81
|
+
filename: fs.createReadStream(config.file)
|
|
82
|
+
};
|
|
83
|
+
options.formData = formData;
|
|
84
|
+
options.headers['Content-Type'] = 'multipart/form-data';
|
|
85
|
+
options.url = createHarmonyUrl(config);
|
|
86
|
+
return requestUtils.sendRequest({ method: 'post', options });
|
|
87
|
+
};
|
|
88
|
+
HTTPClient.prototype.createProjectId = function createProjectId(config) {
|
|
89
|
+
const options = _.cloneDeep(this.requestOptions);
|
|
90
|
+
options.body = {
|
|
91
|
+
name: config.name,
|
|
92
|
+
archived: 'false',
|
|
93
|
+
language: config.language
|
|
94
|
+
};
|
|
95
|
+
options.url = createHarmonyProjectsUrl(config);
|
|
96
|
+
return requestUtils.sendRequest({ method: 'post', options });
|
|
97
|
+
};
|
|
98
|
+
HTTPClient.prototype.getProjectIdByName = function getProjectIdByName(config) {
|
|
99
|
+
const options = _.cloneDeep(this.requestOptions);
|
|
100
|
+
options.url = createHarmonyProjectsUrl(config) + '?name=' + config.name;
|
|
101
|
+
return requestUtils.sendRequest({ method: 'get', options });
|
|
102
|
+
};
|
|
103
|
+
HTTPClient.prototype.getScanProjectById = function getScanProjectById(config) {
|
|
104
|
+
const options = _.cloneDeep(this.requestOptions);
|
|
105
|
+
options.url = createScanProjectUrl(config);
|
|
106
|
+
return requestUtils.sendRequest({ method: 'get', options });
|
|
107
|
+
};
|
|
108
|
+
HTTPClient.prototype.getGlobalProperties = function getGlobalProperties() {
|
|
109
|
+
const options = _.cloneDeep(this.requestOptions);
|
|
110
|
+
let url = createGlobalPropertiesUrl(options.uri);
|
|
111
|
+
options.url = url;
|
|
112
|
+
return requestUtils.sendRequest({ method: 'get', options });
|
|
113
|
+
};
|
|
114
|
+
HTTPClient.prototype.pollForAuth = function pollForAuth(token) {
|
|
115
|
+
const options = _.cloneDeep(this.requestOptions);
|
|
116
|
+
let url = pollForAuthUrl();
|
|
117
|
+
options.url = url;
|
|
118
|
+
let requestBody = {};
|
|
119
|
+
requestBody.token = token;
|
|
120
|
+
options.body = requestBody;
|
|
121
|
+
return requestUtils.sendRequest({ method: 'post', options });
|
|
122
|
+
};
|
|
123
|
+
function getServerlessHost(config = {}) {
|
|
124
|
+
const originalHost = config?.host || config?.get('host');
|
|
125
|
+
const host = originalHost?.endsWith('/')
|
|
126
|
+
? originalHost.slice(0, -1)
|
|
127
|
+
: originalHost;
|
|
128
|
+
return `${host}/Contrast/api/serverless`;
|
|
129
|
+
}
|
|
130
|
+
function createScanFunctionPostUrl(config, params) {
|
|
131
|
+
const url = getServerlessHost(config);
|
|
132
|
+
const { provider, accountId, organizationId } = params;
|
|
133
|
+
return `${url}/organizations/${organizationId}/providers/${provider}/accounts/${accountId}/function-scan`;
|
|
134
|
+
}
|
|
135
|
+
function createScanResourcesGetUrl(config, params, scanId) {
|
|
136
|
+
const url = getServerlessHost(config);
|
|
137
|
+
const { provider, accountId, organizationId } = params;
|
|
138
|
+
const encodedScanId = encodeURIComponent(scanId);
|
|
139
|
+
return `${url}/organizations/${organizationId}/providers/${provider}/accounts/${accountId}/scans/${encodedScanId}/resources`;
|
|
140
|
+
}
|
|
141
|
+
function createScanResultsGetUrl(config, params, scanId, functionArn) {
|
|
142
|
+
const url = getServerlessHost(config);
|
|
143
|
+
const encodedScanId = encodeURIComponent(scanId);
|
|
144
|
+
const encodedFunctionArn = encodeURIComponent(functionArn);
|
|
145
|
+
const { provider, accountId, organizationId } = params;
|
|
146
|
+
return `${url}/organizations/${organizationId}/providers/${provider}/accounts/${accountId}/scans/${encodedScanId}/resources/${encodedFunctionArn}/results`;
|
|
147
|
+
}
|
|
148
|
+
HTTPClient.prototype.postFunctionScan = async function postFunctionScan(config, parameters, body) {
|
|
149
|
+
const url = createScanFunctionPostUrl(config, parameters);
|
|
150
|
+
const options = { ...this.requestOptions, body, url };
|
|
151
|
+
return requestUtils.sendRequest({ method: 'post', options });
|
|
152
|
+
};
|
|
153
|
+
HTTPClient.prototype.getScanResources = async function getScanResources(config, parameters, scanId) {
|
|
154
|
+
const url = createScanResourcesGetUrl(config, parameters, scanId);
|
|
155
|
+
const options = { ...this.requestOptions, url };
|
|
156
|
+
return requestUtils.sendRequest({ method: 'get', options });
|
|
157
|
+
};
|
|
158
|
+
HTTPClient.prototype.getFunctionScanResults = async function getFunctionScanResults(config, parameters, scanId, functionArn) {
|
|
159
|
+
const url = createScanResultsGetUrl(config, parameters, scanId, functionArn);
|
|
160
|
+
const options = { ...this.requestOptions, url };
|
|
161
|
+
return requestUtils.sendRequest({ method: 'get', options });
|
|
162
|
+
};
|
|
163
|
+
const createGetScanIdURL = config => {
|
|
164
|
+
return `${config.host}/Contrast/api/sast/v1/organizations/${config.organizationId}/projects/${config.projectId}/scans/`;
|
|
165
|
+
};
|
|
166
|
+
const createScanResultsInstancesURL = (config, scanId) => {
|
|
167
|
+
return `${config.host}/Contrast/api/sast/v1/organizations/${config.organizationId}/projects/${config.projectId}/scans/${scanId}/result-instances?sort=severity,asc`;
|
|
168
|
+
};
|
|
169
|
+
const createRawOutputURL = (config, codeArtifactId) => {
|
|
170
|
+
return `${config.host}/Contrast/api/sast/v1/organizations/${config.organizationId}/projects/${config.projectId}/scans/${codeArtifactId}/raw-output`;
|
|
171
|
+
};
|
|
172
|
+
const createSpecificScanResultURL = (config, scanId) => {
|
|
173
|
+
return `${config.host}/Contrast/api/sast/v1/organizations/${config.organizationId}/projects/${config.projectId}/scans/${scanId}`;
|
|
174
|
+
};
|
|
175
|
+
function createHarmonyUrl(config) {
|
|
176
|
+
return `${config.host}/Contrast/api/sast/v1/organizations/${config.organizationId}/projects/${config.projectId}/code-artifacts`;
|
|
177
|
+
}
|
|
178
|
+
function createHarmonyProjectsUrl(config) {
|
|
179
|
+
return `${config.host}/Contrast/api/sast/v1/organizations/${config.organizationId}/projects`;
|
|
180
|
+
}
|
|
181
|
+
function createScanProjectUrl(config) {
|
|
182
|
+
return `${config.host}/Contrast/api/sast/v1/organizations/${config.organizationId}/projects/${config.projectId}`;
|
|
183
|
+
}
|
|
184
|
+
const createGlobalPropertiesUrl = protocol => {
|
|
185
|
+
return `${protocol}/Contrast/api/ng/global/properties`;
|
|
186
|
+
};
|
|
187
|
+
const pollForAuthUrl = () => {
|
|
188
|
+
return `${AUTH_CALLBACK_URL}/auth/credentials`;
|
|
189
|
+
};
|
|
190
|
+
module.exports = HTTPClient;
|
|
191
|
+
module.exports.pollForAuthUrl = pollForAuthUrl;
|
|
192
|
+
module.exports.getServerlessHost = getServerlessHost;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getErrorMessage = exports.generalError = exports.hostWarningError = exports.failOptionError = exports.proxyError = exports.forbiddenError = exports.badRequestError = exports.unauthenticatedError = exports.genericError = void 0;
|
|
7
|
+
const i18n_1 = __importDefault(require("i18n"));
|
|
8
|
+
const genericError = (missingCliOption) => {
|
|
9
|
+
console.log(`*************************** ${i18n_1.default.__('yamlMissingParametersHeader')} ***************************\n${missingCliOption}`);
|
|
10
|
+
console.error(i18n_1.default.__('yamlMissingParametersMessage'));
|
|
11
|
+
process.exit(1);
|
|
12
|
+
};
|
|
13
|
+
exports.genericError = genericError;
|
|
14
|
+
const unauthenticatedError = () => {
|
|
15
|
+
generalError('unauthenticatedErrorHeader', 'unauthenticatedErrorMessage');
|
|
16
|
+
};
|
|
17
|
+
exports.unauthenticatedError = unauthenticatedError;
|
|
18
|
+
const badRequestError = (catalogue) => {
|
|
19
|
+
catalogue === true
|
|
20
|
+
? generalError('badRequestErrorHeader', 'badRequestCatalogueErrorMessage')
|
|
21
|
+
: generalError('badRequestErrorHeader', 'badRequestErrorMessage');
|
|
22
|
+
};
|
|
23
|
+
exports.badRequestError = badRequestError;
|
|
24
|
+
const forbiddenError = () => {
|
|
25
|
+
generalError('forbiddenRequestErrorHeader', 'forbiddenRequestErrorMessage');
|
|
26
|
+
};
|
|
27
|
+
exports.forbiddenError = forbiddenError;
|
|
28
|
+
const proxyError = () => {
|
|
29
|
+
generalError('proxyErrorHeader', 'proxyErrorMessage');
|
|
30
|
+
};
|
|
31
|
+
exports.proxyError = proxyError;
|
|
32
|
+
const hostWarningError = () => {
|
|
33
|
+
console.log(i18n_1.default.__('snapshotHostMessage'));
|
|
34
|
+
};
|
|
35
|
+
exports.hostWarningError = hostWarningError;
|
|
36
|
+
const failOptionError = () => {
|
|
37
|
+
console.log('\n ******************************** ' +
|
|
38
|
+
i18n_1.default.__('snapshotFailureHeader') +
|
|
39
|
+
' ********************************\n' +
|
|
40
|
+
i18n_1.default.__('failOptionErrorMessage'));
|
|
41
|
+
};
|
|
42
|
+
exports.failOptionError = failOptionError;
|
|
43
|
+
const getErrorMessage = (header, message) => {
|
|
44
|
+
const title = `******************************** ${i18n_1.default.__(header)} ********************************`;
|
|
45
|
+
const multiLine = message?.includes('\n');
|
|
46
|
+
let finalMessage = '';
|
|
47
|
+
if (multiLine) {
|
|
48
|
+
finalMessage = `\n${message}`;
|
|
49
|
+
}
|
|
50
|
+
else if (message) {
|
|
51
|
+
finalMessage = `\n${i18n_1.default.__(message)}`;
|
|
52
|
+
}
|
|
53
|
+
return `${title}${finalMessage}`;
|
|
54
|
+
};
|
|
55
|
+
exports.getErrorMessage = getErrorMessage;
|
|
56
|
+
const generalError = (header, message) => {
|
|
57
|
+
const finalMessage = getErrorMessage(header, message);
|
|
58
|
+
console.log(finalMessage);
|
|
59
|
+
};
|
|
60
|
+
exports.generalError = generalError;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const NODE = 'NODE';
|
|
3
|
+
const DOTNET = 'DOTNET';
|
|
4
|
+
const JAVA = 'JAVA';
|
|
5
|
+
const RUBY = 'RUBY';
|
|
6
|
+
const PYTHON = 'PYTHON';
|
|
7
|
+
const GO = 'GO';
|
|
8
|
+
const PHP = 'PHP';
|
|
9
|
+
const JAVASCRIPT = 'JAVASCRIPT';
|
|
10
|
+
const LOW = 'LOW';
|
|
11
|
+
const MEDIUM = 'MEDIUM';
|
|
12
|
+
const HIGH = 'HIGH';
|
|
13
|
+
const CRITICAL = 'CRITICAL';
|
|
14
|
+
const APP_NAME = 'contrast';
|
|
15
|
+
const APP_VERSION = '1.0.0';
|
|
16
|
+
const TIMEOUT = 120000;
|
|
17
|
+
const AUTH_UI_URL = 'https://cli-auth.contrastsecurity.com';
|
|
18
|
+
const AUTH_CALLBACK_URL = 'https://cli-auth-api.contrastsecurity.com';
|
|
19
|
+
module.exports = {
|
|
20
|
+
supportedLanguages: { NODE, DOTNET, JAVA, RUBY, PYTHON, GO, PHP, JAVASCRIPT },
|
|
21
|
+
LOW,
|
|
22
|
+
MEDIUM,
|
|
23
|
+
HIGH,
|
|
24
|
+
CRITICAL,
|
|
25
|
+
APP_VERSION,
|
|
26
|
+
APP_NAME,
|
|
27
|
+
TIMEOUT,
|
|
28
|
+
AUTH_UI_URL,
|
|
29
|
+
AUTH_CALLBACK_URL
|
|
30
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const lambda = {
|
|
3
|
+
failedToStartScan: 'Failed to start scan',
|
|
4
|
+
failedToParseArn: 'Failed to parse ARN',
|
|
5
|
+
failedToGetScan: 'Failed to get scan',
|
|
6
|
+
missingLambdaConfig: 'Missing Lambda Configuration',
|
|
7
|
+
missingLambdaArn: 'Missing Lambda ARN',
|
|
8
|
+
validationFailed: 'Request validation failed',
|
|
9
|
+
missingFunctionName: 'Required parameter --function-name is missing.\nRun command with --help to see usage',
|
|
10
|
+
failedToGetResults: 'Failed to get results',
|
|
11
|
+
missingResults: 'Missing vulnerabilities',
|
|
12
|
+
missingParameter: 'Required function parameter is missing',
|
|
13
|
+
awsError: 'AWS error',
|
|
14
|
+
missingFlagArguments: 'The following flags are missing an arguments:\n%s',
|
|
15
|
+
notSupportedFlags: 'The following flags are not supported:\n%s\nRun command with --help to see usage',
|
|
16
|
+
something_went_wrong: 'Something went wrong',
|
|
17
|
+
not_found_404: '404 error - Not found',
|
|
18
|
+
internal_error: 'Internal error',
|
|
19
|
+
inactive_account: 'Scanning a function of an inactive account is not supported',
|
|
20
|
+
not_supported_runtime: 'Scanning resource of runtime "%s" is not supported.\nSupported runtimes: %s',
|
|
21
|
+
not_supported_onboard_account: 'Scanning a function of onboard account is not supported',
|
|
22
|
+
scan_lock: 'Other scan is still running. Please wait until the previous scan finishes',
|
|
23
|
+
unsupported: 'unsupported',
|
|
24
|
+
excluded: 'excluded',
|
|
25
|
+
canceled: 'canceled',
|
|
26
|
+
failed: 'failed',
|
|
27
|
+
dismissed: 'dismissed'
|
|
28
|
+
};
|
|
29
|
+
module.exports = {
|
|
30
|
+
lambda
|
|
31
|
+
};
|