@contrast/contrast 1.0.0 → 1.0.1

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.
Files changed (201) hide show
  1. package/.prettierignore +2 -0
  2. package/README.md +120 -47
  3. package/dist/audit/AnalysisEngine.js +37 -0
  4. package/dist/audit/catalogueApplication/catalogueApplication.js +36 -0
  5. package/dist/audit/dotnetAnalysisEngine/index.js +25 -0
  6. package/dist/audit/dotnetAnalysisEngine/parseLockFileContents.js +35 -0
  7. package/dist/audit/dotnetAnalysisEngine/parseProjectFileContents.js +15 -0
  8. package/dist/audit/dotnetAnalysisEngine/readLockFileContents.js +18 -0
  9. package/dist/audit/dotnetAnalysisEngine/readProjectFileContents.js +14 -0
  10. package/dist/audit/dotnetAnalysisEngine/sanitizer.js +9 -0
  11. package/dist/audit/goAnalysisEngine/index.js +17 -0
  12. package/dist/audit/goAnalysisEngine/parseProjectFileContents.js +164 -0
  13. package/dist/audit/goAnalysisEngine/readProjectFileContents.js +21 -0
  14. package/dist/audit/goAnalysisEngine/sanitizer.js +5 -0
  15. package/dist/audit/javaAnalysisEngine/index.js +34 -0
  16. package/dist/audit/javaAnalysisEngine/parseMavenProjectFileContents.js +153 -0
  17. package/dist/audit/javaAnalysisEngine/parseProjectFileContents.js +353 -0
  18. package/dist/audit/javaAnalysisEngine/readProjectFileContents.js +98 -0
  19. package/dist/audit/javaAnalysisEngine/sanitizer.js +5 -0
  20. package/dist/audit/languageAnalysisEngine/checkForMultipleIdentifiedLanguages.js +24 -0
  21. package/dist/audit/languageAnalysisEngine/checkForMultipleIdentifiedProjectFiles.js +24 -0
  22. package/dist/audit/languageAnalysisEngine/checkIdentifiedLanguageHasLockFile.js +35 -0
  23. package/dist/audit/languageAnalysisEngine/checkIdentifiedLanguageHasProjectFile.js +23 -0
  24. package/dist/audit/languageAnalysisEngine/commonApi.js +18 -0
  25. package/dist/audit/languageAnalysisEngine/constants.js +20 -0
  26. package/dist/audit/languageAnalysisEngine/filterProjectPath.js +20 -0
  27. package/dist/audit/languageAnalysisEngine/getIdentifiedLanguageInfo.js +25 -0
  28. package/dist/audit/languageAnalysisEngine/getProjectRootFilenames.js +39 -0
  29. package/dist/audit/languageAnalysisEngine/index.js +39 -0
  30. package/dist/audit/languageAnalysisEngine/langugageAnalysisFactory.js +70 -0
  31. package/dist/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +121 -0
  32. package/dist/audit/languageAnalysisEngine/report/checkIgnoreDevDep.js +17 -0
  33. package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +257 -0
  34. package/dist/audit/languageAnalysisEngine/report/newReportingFeature.js +81 -0
  35. package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +133 -0
  36. package/dist/audit/languageAnalysisEngine/sendSnapshot.js +41 -0
  37. package/dist/audit/languageAnalysisEngine/util/capabilities.js +11 -0
  38. package/dist/audit/languageAnalysisEngine/util/generalAPI.js +39 -0
  39. package/dist/audit/languageAnalysisEngine/util/requestUtils.js +14 -0
  40. package/dist/audit/nodeAnalysisEngine/handleNPMLockFileV2.js +40 -0
  41. package/dist/audit/nodeAnalysisEngine/index.js +31 -0
  42. package/dist/audit/nodeAnalysisEngine/parseNPMLockFileContents.js +18 -0
  43. package/dist/audit/nodeAnalysisEngine/parseYarn2LockFileContents.js +51 -0
  44. package/dist/audit/nodeAnalysisEngine/parseYarnLockFileContents.js +18 -0
  45. package/dist/audit/nodeAnalysisEngine/readNPMLockFileContents.js +17 -0
  46. package/dist/audit/nodeAnalysisEngine/readProjectFileContents.js +14 -0
  47. package/dist/audit/nodeAnalysisEngine/readYarnLockFileContents.js +24 -0
  48. package/dist/audit/nodeAnalysisEngine/sanitizer.js +9 -0
  49. package/dist/audit/phpAnalysisEngine/index.js +23 -0
  50. package/dist/audit/phpAnalysisEngine/parseLockFileContents.js +52 -0
  51. package/dist/audit/phpAnalysisEngine/readLockFileContents.js +13 -0
  52. package/dist/audit/phpAnalysisEngine/readProjectFileContents.js +16 -0
  53. package/dist/audit/phpAnalysisEngine/sanitizer.js +5 -0
  54. package/dist/audit/pythonAnalysisEngine/index.js +25 -0
  55. package/dist/audit/pythonAnalysisEngine/parsePipfileLockContents.js +17 -0
  56. package/dist/audit/pythonAnalysisEngine/parseProjectFileContents.js +21 -0
  57. package/dist/audit/pythonAnalysisEngine/readPipfileLockFileContents.js +13 -0
  58. package/dist/audit/pythonAnalysisEngine/readPythonProjectFileContents.js +14 -0
  59. package/dist/audit/pythonAnalysisEngine/sanitizer.js +7 -0
  60. package/dist/audit/rubyAnalysisEngine/index.js +25 -0
  61. package/dist/audit/rubyAnalysisEngine/parseGemfileLockContents.js +176 -0
  62. package/dist/audit/rubyAnalysisEngine/parsedGemfile.js +22 -0
  63. package/dist/audit/rubyAnalysisEngine/readGemfileContents.js +14 -0
  64. package/dist/audit/rubyAnalysisEngine/readGemfileLockContents.js +14 -0
  65. package/dist/audit/rubyAnalysisEngine/sanitizer.js +6 -0
  66. package/dist/commands/audit/auditConfig.js +25 -0
  67. package/dist/commands/audit/auditController.js +31 -0
  68. package/dist/commands/audit/help.js +52 -0
  69. package/dist/commands/audit/processAudit.js +18 -0
  70. package/dist/commands/auth/auth.js +1 -1
  71. package/dist/commands/scan/processScan.js +19 -5
  72. package/dist/common/HTTPClient.js +101 -13
  73. package/dist/common/errorHandling.js +49 -1
  74. package/dist/common/findLatestCLIVersion.js +23 -0
  75. package/dist/constants/constants.js +1 -1
  76. package/dist/constants/lambda.js +32 -4
  77. package/dist/constants/locales.js +39 -16
  78. package/dist/constants.js +148 -20
  79. package/dist/index.js +7 -1
  80. package/dist/lambda/aws.js +14 -11
  81. package/dist/lambda/help.js +4 -0
  82. package/dist/lambda/lambda.js +50 -27
  83. package/dist/lambda/lambdaUtils.js +72 -0
  84. package/dist/lambda/logUtils.js +11 -1
  85. package/dist/lambda/scanDetailCompletion.js +4 -4
  86. package/dist/lambda/scanRequest.js +11 -5
  87. package/dist/lambda/utils.js +110 -53
  88. package/dist/scan/autoDetection.js +0 -32
  89. package/dist/scan/fileUtils.js +1 -1
  90. package/dist/scan/help.js +12 -40
  91. package/dist/scan/populateProjectIdAndProjectName.js +4 -0
  92. package/dist/scan/saveResults.js +15 -0
  93. package/dist/scan/scan.js +77 -42
  94. package/dist/scan/scanConfig.js +20 -0
  95. package/dist/scan/scanController.js +13 -15
  96. package/dist/scan/scanResults.js +18 -16
  97. package/dist/utils/commonApi.js +3 -3
  98. package/dist/utils/fileUtils.js +31 -0
  99. package/dist/utils/paramsUtil/commandlineParams.js +1 -20
  100. package/dist/utils/paramsUtil/genericCommandLineParams.js +12 -0
  101. package/dist/utils/paramsUtil/paramHandler.js +3 -6
  102. package/dist/utils/parsedCLIOptions.js +14 -8
  103. package/package.json +26 -21
  104. package/src/audit/AnalysisEngine.js +103 -0
  105. package/src/audit/catalogueApplication/catalogueApplication.js +42 -0
  106. package/src/audit/dotnetAnalysisEngine/index.js +26 -0
  107. package/src/audit/dotnetAnalysisEngine/parseLockFileContents.js +47 -0
  108. package/src/audit/dotnetAnalysisEngine/parseProjectFileContents.js +29 -0
  109. package/src/audit/dotnetAnalysisEngine/readLockFileContents.js +30 -0
  110. package/src/audit/dotnetAnalysisEngine/readProjectFileContents.js +26 -0
  111. package/src/audit/dotnetAnalysisEngine/sanitizer.js +11 -0
  112. package/src/audit/goAnalysisEngine/index.js +18 -0
  113. package/src/audit/goAnalysisEngine/parseProjectFileContents.js +209 -0
  114. package/src/audit/goAnalysisEngine/readProjectFileContents.js +31 -0
  115. package/src/audit/goAnalysisEngine/sanitizer.js +7 -0
  116. package/src/audit/javaAnalysisEngine/index.js +41 -0
  117. package/src/audit/javaAnalysisEngine/parseMavenProjectFileContents.js +222 -0
  118. package/src/audit/javaAnalysisEngine/parseProjectFileContents.js +420 -0
  119. package/src/audit/javaAnalysisEngine/readProjectFileContents.js +141 -0
  120. package/src/audit/javaAnalysisEngine/sanitizer.js +6 -0
  121. package/src/audit/languageAnalysisEngine/checkForMultipleIdentifiedLanguages.js +35 -0
  122. package/src/audit/languageAnalysisEngine/checkForMultipleIdentifiedProjectFiles.js +41 -0
  123. package/src/audit/languageAnalysisEngine/checkIdentifiedLanguageHasLockFile.js +54 -0
  124. package/src/audit/languageAnalysisEngine/checkIdentifiedLanguageHasProjectFile.js +32 -0
  125. package/src/audit/languageAnalysisEngine/commonApi.js +20 -0
  126. package/src/audit/languageAnalysisEngine/constants.js +23 -0
  127. package/src/audit/languageAnalysisEngine/filterProjectPath.js +21 -0
  128. package/src/audit/languageAnalysisEngine/getIdentifiedLanguageInfo.js +41 -0
  129. package/src/audit/languageAnalysisEngine/getProjectRootFilenames.js +72 -0
  130. package/src/audit/languageAnalysisEngine/index.js +45 -0
  131. package/src/audit/languageAnalysisEngine/langugageAnalysisFactory.js +94 -0
  132. package/src/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +177 -0
  133. package/src/audit/languageAnalysisEngine/report/checkIgnoreDevDep.js +27 -0
  134. package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.js +303 -0
  135. package/src/audit/languageAnalysisEngine/report/newReportingFeature.js +124 -0
  136. package/src/audit/languageAnalysisEngine/report/reportingFeature.js +190 -0
  137. package/src/audit/languageAnalysisEngine/sendSnapshot.js +51 -0
  138. package/src/audit/languageAnalysisEngine/util/capabilities.js +12 -0
  139. package/src/audit/languageAnalysisEngine/util/generalAPI.js +43 -0
  140. package/src/audit/languageAnalysisEngine/util/requestUtils.js +17 -0
  141. package/src/audit/nodeAnalysisEngine/handleNPMLockFileV2.js +49 -0
  142. package/src/audit/nodeAnalysisEngine/index.js +35 -0
  143. package/src/audit/nodeAnalysisEngine/parseNPMLockFileContents.js +20 -0
  144. package/src/audit/nodeAnalysisEngine/parseYarn2LockFileContents.js +63 -0
  145. package/src/audit/nodeAnalysisEngine/parseYarnLockFileContents.js +26 -0
  146. package/src/audit/nodeAnalysisEngine/readNPMLockFileContents.js +23 -0
  147. package/src/audit/nodeAnalysisEngine/readProjectFileContents.js +27 -0
  148. package/src/audit/nodeAnalysisEngine/readYarnLockFileContents.js +36 -0
  149. package/src/audit/nodeAnalysisEngine/sanitizer.js +11 -0
  150. package/src/audit/phpAnalysisEngine/index.js +27 -0
  151. package/src/audit/phpAnalysisEngine/parseLockFileContents.js +60 -0
  152. package/src/audit/phpAnalysisEngine/readLockFileContents.js +14 -0
  153. package/src/audit/phpAnalysisEngine/readProjectFileContents.js +25 -0
  154. package/src/audit/phpAnalysisEngine/sanitizer.js +4 -0
  155. package/src/audit/pythonAnalysisEngine/index.js +55 -0
  156. package/src/audit/pythonAnalysisEngine/parsePipfileLockContents.js +23 -0
  157. package/src/audit/pythonAnalysisEngine/parseProjectFileContents.js +33 -0
  158. package/src/audit/pythonAnalysisEngine/readPipfileLockFileContents.js +16 -0
  159. package/src/audit/pythonAnalysisEngine/readPythonProjectFileContents.js +22 -0
  160. package/src/audit/pythonAnalysisEngine/sanitizer.js +9 -0
  161. package/src/audit/rubyAnalysisEngine/index.js +30 -0
  162. package/src/audit/rubyAnalysisEngine/parseGemfileLockContents.js +215 -0
  163. package/src/audit/rubyAnalysisEngine/parsedGemfile.js +39 -0
  164. package/src/audit/rubyAnalysisEngine/readGemfileContents.js +18 -0
  165. package/src/audit/rubyAnalysisEngine/readGemfileLockContents.js +17 -0
  166. package/src/audit/rubyAnalysisEngine/sanitizer.js +8 -0
  167. package/src/commands/audit/auditConfig.ts +30 -0
  168. package/src/commands/audit/auditController.ts +31 -0
  169. package/src/commands/audit/help.ts +48 -0
  170. package/src/commands/audit/processAudit.ts +19 -0
  171. package/src/commands/auth/auth.js +1 -1
  172. package/src/commands/scan/processScan.js +20 -5
  173. package/src/common/HTTPClient.js +136 -14
  174. package/src/common/errorHandling.ts +56 -1
  175. package/src/common/findLatestCLIVersion.ts +27 -0
  176. package/src/constants/constants.js +1 -1
  177. package/src/constants/lambda.js +45 -4
  178. package/src/constants/locales.js +48 -20
  179. package/src/constants.js +168 -22
  180. package/src/index.ts +9 -2
  181. package/src/lambda/aws.ts +13 -12
  182. package/src/lambda/help.ts +4 -0
  183. package/src/lambda/lambda.ts +53 -34
  184. package/src/lambda/lambdaUtils.ts +111 -0
  185. package/src/lambda/logUtils.ts +19 -1
  186. package/src/lambda/scanDetailCompletion.ts +4 -4
  187. package/src/lambda/scanRequest.ts +13 -11
  188. package/src/lambda/utils.ts +149 -81
  189. package/src/scan/autoDetection.js +0 -29
  190. package/src/scan/fileUtils.js +1 -1
  191. package/src/scan/help.js +12 -45
  192. package/src/scan/populateProjectIdAndProjectName.js +4 -0
  193. package/src/scan/saveResults.js +15 -0
  194. package/src/scan/scan.js +95 -59
  195. package/src/scan/scanConfig.js +29 -0
  196. package/src/scan/scanController.js +13 -13
  197. package/src/scan/scanResults.js +21 -19
  198. package/src/utils/commonApi.js +2 -3
  199. package/src/utils/paramsUtil/commandlineParams.js +1 -26
  200. package/src/utils/paramsUtil/paramHandler.js +3 -7
  201. package/src/utils/parsedCLIOptions.js +11 -9
@@ -0,0 +1,2 @@
1
+ test/commands/**
2
+ dist/**
package/README.md CHANGED
@@ -1,13 +1,33 @@
1
1
  # Contrast Command Line Interface
2
2
 
3
- Install Contrast, authenticate, and then start running a Lambda scan.
4
- This version supports **Java** and **Python** functions on AWS.
3
+ - [About Contrast CLI](#about-contrast-cli)
4
+ - [Requirements](#requirements)
5
+ - [Step 1 – Install](#step-1--install)
6
+ - [Installation via Homebrew](#installation-via-homebrew)
7
+ - [Install NPM / YARN](#install-npm--yarn)
8
+ - [Install with binaries](#install-with-binaries)
9
+ - [Step 2 – Authenticate](#step-2--authenticate)
10
+ - [Step 3 – Scan](#step-3--scan)
11
+ - [Usage](#usage)
12
+ - [Commands](#commands)
13
+ - [Examples of usage](#examples-of-usage)
14
+ - [Example of Results](#example-of-results)
15
+ - [Dependencies Vulnerabilities](#dependencies-vulnerabilities)
16
+ - [Least Privilege](#least-privilege)
17
+
18
+ ## About Contrast CLI
19
+
20
+ Contrast CLI helps you find & fix security issues on AWS lambda functions (supports **Java** and **Python**)
21
+ By running a scan on your lambda functions, you can find:
22
+
23
+ - Least privilege identity and access management (IAM) vulnerabilities (over permissive policies) and remediation
24
+ - The Common Vulnerabilities and Exposures (CVE) from your libraries (Vulnerable Dependencies) and remediation
5
25
 
6
26
  ## Requirements
7
27
 
8
28
  - AWS credentials should be **available** on your local configure (usually `~/.aws/credentials`)
9
29
  - You have an option run lambda scan with your aws-profile to pass `--profile`
10
- - You also can export differnt credentials
30
+ - You also can export different credentials
11
31
 
12
32
  ```shell
13
33
  export AWS_DEFAULT_REGION=<YOUR_AWS_REGION>
@@ -17,45 +37,48 @@ export AWS_SECRET_ACCESS_KEY=<YOUR_SECRET_ACCESS_KEY>
17
37
 
18
38
  These permissions are required to gather all required information on an AWS Lambda to use the `contrast lambda` command:
19
39
 
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)
40
+ - 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)
41
+ - 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
42
 
23
43
  Policy example:
24
- ```
44
+
45
+ ```json
25
46
  {
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
- ]
47
+ "Version": "2012-10-17",
48
+ "Statement": [
49
+ {
50
+ "Sid": "VisualEditor0",
51
+ "Effect": "Allow",
52
+ "Action": [
53
+ "iam:GetPolicyVersion",
54
+ "iam:GetPolicy",
55
+ "lambda:GetLayerVersion",
56
+ "lambda:GetFunction",
57
+ "iam:ListAttachedRolePolicies",
58
+ "iam:ListRolePolicies",
59
+ "iam:GetRolePolicy"
60
+ ],
61
+ "Resource": [
62
+ "arn:aws:lambda:*:YOUR_ACCOUNT:layer:*:*",
63
+ "arn:aws:lambda:*:YOUR_ACCOUNT:function:*",
64
+ "arn:aws:iam::YOUR_ACCOUNT:role/*",
65
+ "arn:aws:iam::YOUR_ACCOUNT:policy/*"
66
+ ]
67
+ }
68
+ ]
48
69
  }
49
70
  ```
50
71
 
51
- ## Installation via Homebrew
72
+ ## Step 1 – Install
73
+
74
+ ### Installation via Homebrew
52
75
 
53
76
  - `brew tap Contrast-Security-OSS/homebrew-contrast`
54
77
  - `brew install contrast`
55
78
 
56
79
  ### Install NPM / YARN
57
80
 
58
- - `npm i -g @contrast/contrast`
81
+ - `npm install -g @contrast/contrast`
59
82
  - `yarn global add @contrast/contrast`
60
83
 
61
84
  ### Install with binaries
@@ -70,40 +93,90 @@ Policy example:
70
93
  | 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
94
  | 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
95
 
73
- ## Usage
96
+ ## Step 2 – Authenticate
74
97
 
75
- - `contrast [command] [option]`
76
- - `contrast lambda --function-name <function> [options]`
98
+ Authenticate using your existing [GitHub](https://github.com/) or [Google](https://www.google.com/) account.
77
99
 
78
- ## Running a scan on a Lambda function
100
+ ```shell
101
+ contrast auth
102
+ ```
103
+
104
+ ## Step 3 – Scan
79
105
 
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>`
106
+ Use contrast lambda to scan your AWS Lambda functions:
84
107
 
85
- More infromation
108
+ ```shell
109
+ contrast lambda --function-name MyFunctionName --region my-aws-region
110
+ ```
86
111
 
112
+ ### Usage
113
+
114
+ - `contrast [command] [option]`
115
+ - `contrast lambda --list-functions`
116
+ - `contrast lambda --function-name <function> [options]`
87
117
  - `contrast lambda --help`
88
118
 
89
- ## Commands
119
+ ### Commands
90
120
 
91
121
  - `auth` - Authenticate Contrast using your `Github` or `Google` account
92
122
  - `lambda` - Perform scan on AWS Lambda function
123
+ - `--function-name` - Name of AWS lambda function to scan
124
+ - `--list-functions` - List all available lambda functions to scan
125
+ - `--endpoint-url` (optional) - AWS Endpoint override, works like in AWS CLI
126
+ - `--region` (optional) - Region override, default to AWS_DEAFAULT_REGION env var, works like in AWS CLI
127
+ - `--profile` (optional) - AWS configuration profile override, works like in AWS CLI
128
+ - `--json-output` (optional) - Return response in JSON (versus default human readable format)
129
+ - `--verbose` (optional) - Returns extended information to the terminal
130
+ - `--help` Displays usage guide
93
131
  - `version` - Displays version of Contrast CLI
94
- - `config` - Displays stored credentials (`–c, --clear` - Removes stored credentials)
132
+ - `config` - Displays stored credentials
133
+ - `config --clear` - Removes stored credentials
95
134
  - `help` - Displays usage guide
96
135
 
97
- ## Example of Running
136
+ ### Examples of usage
137
+
138
+ show help for lambda
139
+
140
+ ```shell
141
+ contrast lambda --help
142
+ ```
143
+
144
+ get list of all available functions for scan
145
+
146
+ ```shell
147
+ contrast lambda --list-functions
148
+ ```
149
+
150
+ scan lambda function in specific region
98
151
 
99
152
  ```shell
100
- contrast lambda --function-name myFunctionName
101
153
  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
154
+ ```
155
+
156
+ scan lambda function with different profile
157
+
158
+ ```shell
159
+ contrast lambda -f myFunctionName --profile myDevProfile
160
+ ```
161
+
162
+ scan lambda function with full details in json format
163
+
164
+ ```shell
165
+ contrast lambda -f myFunctionName --json-output
166
+ ```
167
+
168
+ scan lambda function with all possible flags
169
+
170
+ ```shell
171
+ contrast lambda -f myFunctionName --region eu-cental-1 --profile myDevProfile --endpoint-url https://adbb-94-188-169-138.eu.ngrok.io/ --verbose --json-output
105
172
  ```
106
173
 
107
174
  ## Example of Results
108
175
 
109
- ![image](https://user-images.githubusercontent.com/289035/165555050-e9a709c9-f2a9-4edc-a064-8208445238bc.png)
176
+ ### Dependency vulnerabilities
177
+
178
+ ![image](https://user-images.githubusercontent.com/289035/166472066-fa4a179c-cbef-436f-bc8e-9cbb8a4b465e.png)
179
+
180
+ ### Least Privilege
181
+
182
+ ![image](https://user-images.githubusercontent.com/289035/166480331-54ec133f-3379-4023-9fe4-c0db352c5b16.png)
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ class AnalysisEngine {
3
+ constructor(initAnalysis = {}) {
4
+ this.analyzers = [];
5
+ this.analysis = { ...initAnalysis };
6
+ }
7
+ use(analyzer) {
8
+ if (Array.isArray(analyzer)) {
9
+ this.analyzers = [...this.analyzers, ...analyzer];
10
+ return;
11
+ }
12
+ this.analyzers.push(analyzer);
13
+ }
14
+ analyze(callback, config) {
15
+ let i = 0;
16
+ const next = err => {
17
+ if (err) {
18
+ return setImmediate(() => callback(err, this.analysis));
19
+ }
20
+ if (i >= this.analyzers.length) {
21
+ return setImmediate(() => callback(null, this.analysis));
22
+ }
23
+ const analyzer = this.analyzers[i];
24
+ i++;
25
+ setImmediate(() => {
26
+ try {
27
+ analyzer(this.analysis, next, config);
28
+ }
29
+ catch (uncaughtErr) {
30
+ next(uncaughtErr);
31
+ }
32
+ });
33
+ };
34
+ next();
35
+ }
36
+ }
37
+ module.exports = exports = AnalysisEngine;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ const i18n = require('i18n');
3
+ const { getHttpClient, handleResponseErrors } = require('../../utils/commonApi');
4
+ const locationOfApp = (config, appId) => {
5
+ return `${config.host}/Contrast/static/ng/index.html#/${config.organizationId}/applications/${appId}`;
6
+ };
7
+ const displaySuccessMessage = (config, appId) => {
8
+ console.log('\n **************************' +
9
+ i18n.__('successHeader') +
10
+ '************************** \n');
11
+ console.log('\n' + i18n.__('catalogueSuccessCommand') + appId + '\n');
12
+ console.log(locationOfApp(config, appId));
13
+ console.log('\n *********************************************************** \n');
14
+ };
15
+ const catalogueApplication = async (config) => {
16
+ const client = getHttpClient(config);
17
+ let appId;
18
+ await client
19
+ .catalogueCommand(config)
20
+ .then(res => {
21
+ if (res.statusCode === 201) {
22
+ displaySuccessMessage(config, res.body.application.app_id);
23
+ appId = res.body.application.app_id;
24
+ }
25
+ else {
26
+ handleResponseErrors(res, 'catalogue');
27
+ }
28
+ })
29
+ .catch(err => {
30
+ console.log(err);
31
+ });
32
+ return appId;
33
+ };
34
+ module.exports = {
35
+ catalogueApplication: catalogueApplication
36
+ };
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ const AnalysisEngine = require('../AnalysisEngine');
3
+ const readProjectFileContents = require('./readProjectFileContents');
4
+ const parseProjectFileContents = require('./parseProjectFileContents');
5
+ const readLockFileContents = require('./readLockFileContents');
6
+ const parseLockFileContents = require('./parseLockFileContents');
7
+ const sanitizer = require('./sanitizer');
8
+ const i18n = require('i18n');
9
+ module.exports = exports = (language, config, callback) => {
10
+ const ae = new AnalysisEngine({ language, config, dotnet: {} });
11
+ ae.use([
12
+ readProjectFileContents,
13
+ parseProjectFileContents,
14
+ readLockFileContents,
15
+ parseLockFileContents,
16
+ sanitizer
17
+ ]);
18
+ ae.analyze((err, analysis) => {
19
+ if (err) {
20
+ callback(new Error(i18n.__('dotnetAnalysisFailure') + err.message));
21
+ return;
22
+ }
23
+ callback(null, analysis);
24
+ });
25
+ };
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ const i18n = require('i18n');
3
+ module.exports = exports = ({ language: { lockFilePath }, dotnet }, next) => {
4
+ const { rawLockFileContents } = dotnet;
5
+ if (!rawLockFileContents) {
6
+ next();
7
+ return;
8
+ }
9
+ try {
10
+ let count = 0;
11
+ dotnet.lockFile = JSON.parse(rawLockFileContents);
12
+ for (const dependenciesNode in dotnet.lockFile.dependencies) {
13
+ for (const innerNode in dotnet.lockFile.dependencies[dependenciesNode]) {
14
+ const nodeValidation = JSON.stringify(dotnet.lockFile.dependencies[dependenciesNode][innerNode]);
15
+ if (nodeValidation.includes('"type":"Project"')) {
16
+ count += 1;
17
+ delete dotnet.lockFile.dependencies[dependenciesNode][innerNode];
18
+ dotnet.additionalInfo = 'dependenciesNote';
19
+ }
20
+ }
21
+ }
22
+ if (count > 0) {
23
+ const multiLevelProjectWarning = () => {
24
+ console.log('');
25
+ console.log(i18n.__('dependenciesNote'));
26
+ };
27
+ setTimeout(multiLevelProjectWarning, 7000);
28
+ }
29
+ }
30
+ catch (err) {
31
+ next(new Error(i18n.__('dotnetParseLockfile', lockFilePath) + `${err.message}`));
32
+ return;
33
+ }
34
+ next();
35
+ };
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ const xml2js = require('xml2js');
3
+ const i18n = require('i18n');
4
+ module.exports = exports = ({ language: { projectFilePath }, dotnet }, next) => {
5
+ const { rawProjectFileContents } = dotnet;
6
+ const parser = new xml2js.Parser({ explicitArray: false, mergeAttrs: true });
7
+ parser.parseString(rawProjectFileContents, (err, projectFileXML) => {
8
+ if (err) {
9
+ next(new Error(i18n.__('dotnetParseProjectFile', projectFilePath) + `${err}`));
10
+ return;
11
+ }
12
+ dotnet.projectFile = projectFileXML;
13
+ next();
14
+ });
15
+ };
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ const fs = require('fs');
3
+ const i18n = require('i18n');
4
+ module.exports = exports = (analysis, next) => {
5
+ const { language: { lockFilePath }, dotnet } = analysis;
6
+ if (!lockFilePath) {
7
+ next();
8
+ return;
9
+ }
10
+ try {
11
+ dotnet.rawLockFileContents = fs.readFileSync(lockFilePath);
12
+ }
13
+ catch (err) {
14
+ next(new Error(i18n.__('dotnetReadLockfile', lockFilePath) + `${err.message}`));
15
+ return;
16
+ }
17
+ next();
18
+ };
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ const fs = require('fs');
3
+ const i18n = require('i18n');
4
+ module.exports = exports = (analysis, next) => {
5
+ const { language: { projectFilePath }, dotnet } = analysis;
6
+ try {
7
+ dotnet.rawProjectFileContents = fs.readFileSync(projectFilePath);
8
+ }
9
+ catch (err) {
10
+ next(new Error(i18n.__('dotnetReadProjectFile', projectFilePath) + `${err.message}`));
11
+ return;
12
+ }
13
+ next();
14
+ };
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ module.exports = exports = ({ dotnet }, next) => {
3
+ delete dotnet.rawProjectFileContents;
4
+ delete dotnet.parsedProjectFileContents;
5
+ delete dotnet.projectFileXML;
6
+ delete dotnet.packageReferences;
7
+ delete dotnet.rawLockFileContents;
8
+ next();
9
+ };
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ const AnalysisEngine = require('../AnalysisEngine');
3
+ const readProjectFileContents = require('./readProjectFileContents');
4
+ const parseProjectFileContents = require('./parseProjectFileContents');
5
+ const sanitizer = require('./sanitizer');
6
+ const i18n = require('i18n');
7
+ module.exports = exports = (language, config, callback) => {
8
+ const ae = new AnalysisEngine({ language, config, go: {} });
9
+ ae.use([readProjectFileContents, parseProjectFileContents, sanitizer]);
10
+ ae.analyze((err, analysis) => {
11
+ if (err) {
12
+ callback(new Error(i18n.__('goAnalysisError') + `${err.message}`));
13
+ return;
14
+ }
15
+ callback(null, analysis);
16
+ });
17
+ };
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ const i18n = require('i18n');
3
+ const crypto = require('crypto');
4
+ module.exports = exports = ({ go }, next) => {
5
+ const { modGraphOutput } = go;
6
+ try {
7
+ go.goDependencyTrees = parseGo(modGraphOutput);
8
+ }
9
+ catch (err) {
10
+ next(new Error(i18n.__('goParseProjectFile') + `${err.message}`));
11
+ return;
12
+ }
13
+ next();
14
+ };
15
+ const splitAllLinesIntoArray = modGraphOutput => {
16
+ return modGraphOutput.split(/\r\n|\r|\n/);
17
+ };
18
+ const parseGo = modGraphOutput => {
19
+ let splitLines = splitAllLinesIntoArray(modGraphOutput);
20
+ const directDepNames = getDirectDepNames(splitLines);
21
+ const uniqueTransitiveDepNames = getAllUniqueTransitiveDepNames(splitLines, directDepNames);
22
+ let rootNodes = createRootNodes(splitLines);
23
+ createTransitiveDeps(uniqueTransitiveDepNames, splitLines, rootNodes);
24
+ return rootNodes;
25
+ };
26
+ const getAllDepsOfADepAsEdge = (dep, deps) => {
27
+ let edges = {};
28
+ const depRows = deps.filter(line => {
29
+ return line.startsWith(dep);
30
+ });
31
+ depRows.forEach(dep => {
32
+ const edgeName = dep.split(' ')[1];
33
+ edges[edgeName] = edgeName;
34
+ });
35
+ return edges;
36
+ };
37
+ const getAllDepsOfADepAsName = (dep, deps) => {
38
+ let edges = [];
39
+ const depRows = deps.filter(line => {
40
+ return line.startsWith(dep);
41
+ });
42
+ depRows.forEach(dep => {
43
+ const edgeName = dep.split(' ')[1];
44
+ edges.push(edgeName);
45
+ });
46
+ return edges;
47
+ };
48
+ const createRootNodes = deps => {
49
+ let rootDep = {};
50
+ const rootDeps = getRootDeps(deps);
51
+ const edges = rootDeps.map(dep => {
52
+ return dep.split(' ')[1];
53
+ });
54
+ rootDep[rootDeps[0].split(' ')[0]] = {};
55
+ edges.forEach(edge => {
56
+ const splitEdge = edge.split('@');
57
+ const splitGroupName = splitEdge[0].split('/');
58
+ const name = splitGroupName.pop();
59
+ const lastSlash = splitEdge[0].lastIndexOf('/');
60
+ let group = splitEdge[0].substring(0, lastSlash);
61
+ const hash = getHash(splitEdge[0]);
62
+ group = checkGroupExists(group, name);
63
+ const edgesOfDep = getAllDepsOfADepAsEdge(edge, deps);
64
+ rootDep[rootDeps[0].split(' ')[0]][edge] = {
65
+ artifactID: name,
66
+ group: group,
67
+ version: splitEdge[1],
68
+ scope: '"compile',
69
+ type: 'direct',
70
+ hash: hash,
71
+ edges: edgesOfDep
72
+ };
73
+ });
74
+ return rootDep;
75
+ };
76
+ const getRootDeps = deps => {
77
+ const rootDeps = deps.filter(dep => {
78
+ const parentDep = dep.split(' ')[0];
79
+ if (parentDep.split('@v').length === 1) {
80
+ return dep;
81
+ }
82
+ });
83
+ return rootDeps;
84
+ };
85
+ const getHash = library => {
86
+ let shaSum = crypto.createHash('sha1');
87
+ shaSum.update(library);
88
+ return shaSum.digest('hex');
89
+ };
90
+ const getDirectDepNames = deps => {
91
+ const directDepNames = [];
92
+ deps.forEach(dep => {
93
+ const parentDep = dep.split(' ')[0];
94
+ if (parentDep.split('@v').length === 1) {
95
+ dep.split(' ')[1] !== undefined
96
+ ? directDepNames.push(dep.split(' ')[1])
97
+ : null;
98
+ }
99
+ });
100
+ return directDepNames;
101
+ };
102
+ const getAllUniqueTransitiveDepNames = (deps, directDepNames) => {
103
+ let uniqueDeps = [];
104
+ deps.forEach(dep => {
105
+ const parentDep = dep.split(' ')[0];
106
+ if (parentDep.split('@v').length !== 1) {
107
+ if (!directDepNames.includes(parentDep)) {
108
+ if (!uniqueDeps.includes(parentDep)) {
109
+ parentDep.length > 1 ? uniqueDeps.push(parentDep) : null;
110
+ }
111
+ }
112
+ }
113
+ });
114
+ return uniqueDeps;
115
+ };
116
+ const checkGroupExists = (group, name) => {
117
+ if (group === null || group === '') {
118
+ return name;
119
+ }
120
+ return group;
121
+ };
122
+ const createTransitiveDeps = (transitiveDeps, splitLines, rootNodes) => {
123
+ transitiveDeps.forEach(dep => {
124
+ const splitEdge = dep.split('@');
125
+ const splitGroupName = splitEdge[0].split('/');
126
+ const name = splitGroupName.pop();
127
+ const lastSlash = splitEdge[0].lastIndexOf('/');
128
+ let group = splitEdge[0].substring(0, lastSlash);
129
+ const hash = getHash(splitEdge[0]);
130
+ group = checkGroupExists(group, name);
131
+ const transitiveDep = {
132
+ artifactID: name,
133
+ group: group,
134
+ version: splitEdge[1],
135
+ scope: 'compile',
136
+ type: 'transitive',
137
+ hash: hash,
138
+ edges: {}
139
+ };
140
+ const edges = getAllDepsOfADepAsEdge(dep, splitLines);
141
+ transitiveDep.edges = edges;
142
+ const edgesAsName = getAllDepsOfADepAsName(dep, splitLines);
143
+ edgesAsName.forEach(dep => {
144
+ const splitEdge = dep.split('@');
145
+ const splitGroupName = splitEdge[0].split('/');
146
+ const name = splitGroupName.pop();
147
+ const lastSlash = splitEdge[0].lastIndexOf('/');
148
+ let group = splitEdge[0].substring(0, lastSlash);
149
+ const hash = getHash(splitEdge[0]);
150
+ group = checkGroupExists(group, name);
151
+ const transitiveDep = {
152
+ artifactID: name,
153
+ group: group,
154
+ version: splitEdge[1],
155
+ scope: 'compile',
156
+ type: 'transitive',
157
+ hash: hash,
158
+ edges: {}
159
+ };
160
+ rootNodes[Object.keys(rootNodes)[0]][dep] = transitiveDep;
161
+ });
162
+ rootNodes[Object.keys(rootNodes)[0]][dep] = transitiveDep;
163
+ });
164
+ };
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ const child_process = require('child_process');
3
+ const i18n = require('i18n');
4
+ module.exports = exports = async ({ language: { projectFilePath }, go }, next) => {
5
+ let cmdStdout;
6
+ let cwd;
7
+ try {
8
+ cwd = projectFilePath.replace('go.mod', '');
9
+ cmdStdout = child_process.execSync('go mod graph', { cwd });
10
+ go.modGraphOutput = cmdStdout.toString();
11
+ next();
12
+ }
13
+ catch (err) {
14
+ if (err.message === 'spawnSync /bin/sh ENOENT') {
15
+ err.message =
16
+ '\n\n*************** No transitive dependencies ***************\n\nWe are unable to build a dependency tree view from your repository as there were no transitive dependencies found.';
17
+ }
18
+ next(new Error(i18n.__('goReadProjectFile', cwd, `${err.message ? err.message : ''}`)));
19
+ return;
20
+ }
21
+ };
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ module.exports = exports = ({ go }, next) => {
3
+ delete go.modGraphOutput;
4
+ next();
5
+ };
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ const AnalysisEngine = require('../AnalysisEngine');
3
+ const readProjectFileContents = require('./readProjectFileContents');
4
+ const parseMavenProjectFileContents = require('./parseMavenProjectFileContents');
5
+ const parseProjectFileContents = require('./parseProjectFileContents');
6
+ const sanitizer = require('./sanitizer');
7
+ const i18n = require('i18n');
8
+ module.exports = exports = (language, config, callback) => {
9
+ const ae = new AnalysisEngine({ language, config, java: {} });
10
+ language.projectFilePath = language.projectFilePath.replace('build.gradle.kts', 'build.gradle');
11
+ if (config['beta_unified_java_parser']) {
12
+ console.log('Using new parser...');
13
+ ae.use([readProjectFileContents, parseProjectFileContents, sanitizer]);
14
+ }
15
+ else if (language.projectFilePath.endsWith('pom.xml') &&
16
+ !config['beta_unified_java_parser']) {
17
+ ae.use([readProjectFileContents, parseMavenProjectFileContents, sanitizer]);
18
+ }
19
+ else {
20
+ ae.use([
21
+ readProjectFileContents,
22
+ parseMavenProjectFileContents,
23
+ parseProjectFileContents,
24
+ sanitizer
25
+ ]);
26
+ }
27
+ ae.analyze((err, analysis) => {
28
+ if (err) {
29
+ console.log(i18n.__('javaAnalysisError'), err.message);
30
+ return;
31
+ }
32
+ callback(null, analysis, config);
33
+ }, config);
34
+ };