@contrast/contrast 1.0.12 → 1.0.13
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/dist/commands/audit/processAudit.js +10 -0
- package/dist/commands/scan/processScan.js +9 -0
- package/dist/commands/scan/sca/scaAnalysis.js +3 -0
- package/dist/common/HTTPClient.js +30 -2
- package/dist/common/fail.js +7 -3
- package/dist/common/versionChecker.js +11 -5
- package/dist/constants/constants.js +1 -1
- package/dist/constants/locales.js +2 -2
- package/dist/index.js +1 -1
- package/dist/lambda/lambda.js +7 -0
- package/dist/scaAnalysis/common/scaServicesUpload.js +52 -0
- package/dist/scaAnalysis/javascript/index.js +4 -0
- package/dist/scaAnalysis/javascript/scaServiceParser.js +109 -0
- package/dist/scaAnalysis/ruby/analysis.js +106 -9
- package/dist/scaAnalysis/ruby/index.js +6 -1
- package/dist/scan/scanResults.js +1 -1
- package/dist/{audit/languageAnalysisEngine/util → utils}/capabilities.js +0 -0
- package/dist/{audit/languageAnalysisEngine/util → utils}/generalAPI.js +14 -5
- package/package.json +1 -1
- package/src/commands/audit/processAudit.ts +8 -0
- package/src/commands/scan/processScan.js +14 -0
- package/src/commands/scan/sca/scaAnalysis.js +10 -0
- package/src/common/HTTPClient.js +44 -2
- package/src/common/fail.js +7 -3
- package/src/common/versionChecker.ts +16 -6
- package/src/constants/constants.js +1 -1
- package/src/constants/locales.js +2 -3
- package/src/index.ts +1 -2
- package/src/lambda/lambda.ts +12 -0
- package/src/scaAnalysis/common/scaServicesUpload.js +54 -0
- package/src/scaAnalysis/javascript/index.js +4 -0
- package/src/scaAnalysis/javascript/scaServiceParser.js +145 -0
- package/src/scaAnalysis/ruby/analysis.js +137 -9
- package/src/scaAnalysis/ruby/index.js +6 -1
- package/src/scan/scanResults.js +1 -1
- package/src/{audit/languageAnalysisEngine/util → utils}/capabilities.js +0 -0
- package/src/{audit/languageAnalysisEngine/util → utils}/generalAPI.js +16 -6
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.processAudit = void 0;
|
|
4
7
|
const auditConfig_1 = require("./auditConfig");
|
|
5
8
|
const help_1 = require("./help");
|
|
6
9
|
const scaAnalysis_1 = require("../scan/sca/scaAnalysis");
|
|
7
10
|
const telemetry_1 = require("../../telemetry/telemetry");
|
|
11
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
12
|
const processAudit = async (contrastConf, argv) => {
|
|
9
13
|
if (argv.indexOf('--help') != -1) {
|
|
10
14
|
printHelpMessage();
|
|
@@ -12,9 +16,15 @@ const processAudit = async (contrastConf, argv) => {
|
|
|
12
16
|
}
|
|
13
17
|
const config = await (0, auditConfig_1.getAuditConfig)(contrastConf, 'audit', argv);
|
|
14
18
|
await (0, scaAnalysis_1.processSca)(config);
|
|
19
|
+
postRunMessage();
|
|
15
20
|
await (0, telemetry_1.sendTelemetryConfigAsObject)(config, 'audit', argv, 'SUCCESS', config.language);
|
|
16
21
|
};
|
|
17
22
|
exports.processAudit = processAudit;
|
|
18
23
|
const printHelpMessage = () => {
|
|
19
24
|
console.log(help_1.auditUsageGuide);
|
|
20
25
|
};
|
|
26
|
+
const postRunMessage = () => {
|
|
27
|
+
console.log('\n' + chalk_1.default.underline.bold('Other Codesec Features:'));
|
|
28
|
+
console.log("'contrast scan' to run CodeSec’s industry leading SAST scanner");
|
|
29
|
+
console.log("'contrast lambda' to secure your AWS serverless functions\n");
|
|
30
|
+
};
|
|
@@ -7,9 +7,12 @@ const { formatScanOutput } = require('../../scan/formatScanOutput');
|
|
|
7
7
|
const { processSca } = require('./sca/scaAnalysis');
|
|
8
8
|
const common = require('../../common/fail');
|
|
9
9
|
const { sendTelemetryConfigAsObject } = require('../../telemetry/telemetry');
|
|
10
|
+
const chalk = require('chalk');
|
|
11
|
+
const generalAPI = require('../../utils/generalAPI');
|
|
10
12
|
const processScan = async (contrastConf, argv) => {
|
|
11
13
|
let config = await scanConfig.getScanConfig(contrastConf, 'scan', argv);
|
|
12
14
|
let output = undefined;
|
|
15
|
+
config.mode = await generalAPI.getMode(config);
|
|
13
16
|
if (config.experimental) {
|
|
14
17
|
await processSca(config, argv);
|
|
15
18
|
}
|
|
@@ -24,6 +27,12 @@ const processScan = async (contrastConf, argv) => {
|
|
|
24
27
|
if (config.fail) {
|
|
25
28
|
common.processFail(config, output);
|
|
26
29
|
}
|
|
30
|
+
postRunMessage();
|
|
31
|
+
};
|
|
32
|
+
const postRunMessage = () => {
|
|
33
|
+
console.log('\n' + chalk.underline.bold('Other Codesec Features:'));
|
|
34
|
+
console.log("'contrast audit' to find vulnerabilities in your open source dependencies");
|
|
35
|
+
console.log("'contrast lambda' to secure your AWS serverless functions\n");
|
|
27
36
|
};
|
|
28
37
|
module.exports = {
|
|
29
38
|
processScan
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
const autoDetection = require('../../../scan/autoDetection');
|
|
3
3
|
const javaAnalysis = require('../../../scaAnalysis/java');
|
|
4
4
|
const treeUpload = require('../../../scaAnalysis/common/treeUpload');
|
|
5
|
+
const scaUpload = require('../../../scaAnalysis/common/scaServicesUpload');
|
|
5
6
|
const auditController = require('../../audit/auditController');
|
|
6
7
|
const { supportedLanguages: { JAVA, GO, PYTHON, RUBY, JAVASCRIPT, NODE, PHP, DOTNET } } = require('../../../constants/constants');
|
|
7
8
|
const goAnalysis = require('../../../scaAnalysis/go/goAnalysis');
|
|
@@ -18,7 +19,9 @@ const { dotNetAnalysis } = require('../../../scaAnalysis/dotnet');
|
|
|
18
19
|
const { auditUsageGuide } = require('../../audit/help');
|
|
19
20
|
const rootFile = require('../../../audit/languageAnalysisEngine/getProjectRootFilenames');
|
|
20
21
|
const path = require('path');
|
|
22
|
+
const generalAPI = require('../../../utils/generalAPI');
|
|
21
23
|
const processSca = async (config) => {
|
|
24
|
+
config.mode = await generalAPI.getMode(config);
|
|
22
25
|
const startTime = performance.now();
|
|
23
26
|
let filesFound;
|
|
24
27
|
if (config.help) {
|
|
@@ -130,9 +130,9 @@ HTTPClient.prototype.getScanProjectById = function getScanProjectById(config) {
|
|
|
130
130
|
options.url = createScanProjectUrl(config);
|
|
131
131
|
return requestUtils.sendRequest({ method: 'get', options });
|
|
132
132
|
};
|
|
133
|
-
HTTPClient.prototype.getGlobalProperties = function getGlobalProperties() {
|
|
133
|
+
HTTPClient.prototype.getGlobalProperties = function getGlobalProperties(host) {
|
|
134
134
|
const options = _.cloneDeep(this.requestOptions);
|
|
135
|
-
let url = createGlobalPropertiesUrl(
|
|
135
|
+
let url = createGlobalPropertiesUrl(host);
|
|
136
136
|
options.url = url;
|
|
137
137
|
return requestUtils.sendRequest({ method: 'get', options });
|
|
138
138
|
};
|
|
@@ -166,6 +166,25 @@ HTTPClient.prototype.sendSnapshot = function sendSnapshot(requestBody, config) {
|
|
|
166
166
|
options.body = requestBody;
|
|
167
167
|
return requestUtils.sendRequest({ method: 'post', options });
|
|
168
168
|
};
|
|
169
|
+
HTTPClient.prototype.scaServiceIngest = function scaServiceIngest(requestBody, config) {
|
|
170
|
+
const options = _.cloneDeep(this.requestOptions);
|
|
171
|
+
let url = createScaServiceIngestURL(config);
|
|
172
|
+
options.url = url;
|
|
173
|
+
options.body = requestBody;
|
|
174
|
+
return requestUtils.sendRequest({ method: 'post', options });
|
|
175
|
+
};
|
|
176
|
+
HTTPClient.prototype.scaServiceReport = function scaServiceReport(config, reportId) {
|
|
177
|
+
const options = _.cloneDeep(this.requestOptions);
|
|
178
|
+
let url = createScaServiceReportURL(config, reportId);
|
|
179
|
+
options.url = url;
|
|
180
|
+
return requestUtils.sendRequest({ method: 'get', options });
|
|
181
|
+
};
|
|
182
|
+
HTTPClient.prototype.scaServiceReportStatus = function scaServiceReport(config, reportId) {
|
|
183
|
+
const options = _.cloneDeep(this.requestOptions);
|
|
184
|
+
let url = createScaServiceReportStatusURL(config, reportId);
|
|
185
|
+
options.url = url;
|
|
186
|
+
return requestUtils.sendRequest({ method: 'get', options });
|
|
187
|
+
};
|
|
169
188
|
HTTPClient.prototype.getReportById = function getReportById(config, reportId) {
|
|
170
189
|
const options = _.cloneDeep(this.requestOptions);
|
|
171
190
|
if (config.ignoreDev) {
|
|
@@ -301,6 +320,15 @@ const pollForAuthUrl = () => {
|
|
|
301
320
|
function createSnapshotURL(config) {
|
|
302
321
|
return `${config.host}/Contrast/api/ng/sca/organizations/${config.organizationId}/applications/${config.applicationId}/snapshots`;
|
|
303
322
|
}
|
|
323
|
+
function createScaServiceReportURL(config, reportId) {
|
|
324
|
+
return ``;
|
|
325
|
+
}
|
|
326
|
+
function createScaServiceReportStatusURL(config, reportId) {
|
|
327
|
+
return ``;
|
|
328
|
+
}
|
|
329
|
+
function createScaServiceIngestURL(config) {
|
|
330
|
+
return ``;
|
|
331
|
+
}
|
|
304
332
|
const createAppCreateURL = config => {
|
|
305
333
|
return `${config.host}/Contrast/api/ng/sca/organizations/${config.organizationId}/applications/create`;
|
|
306
334
|
};
|
package/dist/common/fail.js
CHANGED
|
@@ -21,11 +21,15 @@ const isSeverityViolation = (severity, reportResults) => {
|
|
|
21
21
|
count += reportResults.high + reportResults.critical;
|
|
22
22
|
break;
|
|
23
23
|
case 'medium':
|
|
24
|
-
count +=
|
|
24
|
+
count +=
|
|
25
|
+
reportResults.medium + reportResults.high + reportResults.critical;
|
|
25
26
|
break;
|
|
26
27
|
case 'low':
|
|
27
28
|
count +=
|
|
28
|
-
reportResults.high +
|
|
29
|
+
reportResults.high +
|
|
30
|
+
reportResults.critical +
|
|
31
|
+
reportResults.medium +
|
|
32
|
+
reportResults.low;
|
|
29
33
|
break;
|
|
30
34
|
case 'note':
|
|
31
35
|
if (reportResults.note == reportResults.total) {
|
|
@@ -45,7 +49,7 @@ const failPipeline = (message = '') => {
|
|
|
45
49
|
i18n.__('snapshotFailureHeader') +
|
|
46
50
|
' *********************************\n' +
|
|
47
51
|
i18n.__(message));
|
|
48
|
-
process.exit(
|
|
52
|
+
process.exit(2);
|
|
49
53
|
};
|
|
50
54
|
const parseSeverity = severity => {
|
|
51
55
|
const severities = ['NOTE', 'LOW', 'MEDIUM', 'HIGH', 'CRITICAL'];
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.isCorrectNodeVersion = exports.findLatestCLIVersion = void 0;
|
|
6
|
+
exports.isCorrectNodeVersion = exports.findLatestCLIVersion = exports.getLatestVersion = void 0;
|
|
7
7
|
const constants_1 = require("../constants/constants");
|
|
8
8
|
const boxen_1 = __importDefault(require("boxen"));
|
|
9
9
|
const chalk_1 = __importDefault(require("chalk"));
|
|
@@ -19,16 +19,22 @@ const getLatestVersion = async (config) => {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
catch (e) {
|
|
22
|
-
return;
|
|
22
|
+
return undefined;
|
|
23
23
|
}
|
|
24
24
|
};
|
|
25
|
+
exports.getLatestVersion = getLatestVersion;
|
|
25
26
|
async function findLatestCLIVersion(config) {
|
|
26
27
|
const isCI = process.env.CONTRAST_CODESEC_CI
|
|
27
|
-
? JSON.parse(process.env.CONTRAST_CODESEC_CI)
|
|
28
|
+
? JSON.parse(process.env.CONTRAST_CODESEC_CI.toLowerCase())
|
|
28
29
|
: false;
|
|
29
30
|
if (!isCI) {
|
|
30
|
-
let latestCLIVersion = await getLatestVersion(config);
|
|
31
|
-
latestCLIVersion
|
|
31
|
+
let latestCLIVersion = await (0, exports.getLatestVersion)(config);
|
|
32
|
+
if (latestCLIVersion === undefined) {
|
|
33
|
+
config.set('numOfRuns', 0);
|
|
34
|
+
console.log('Failed to retrieve latest version info. Continuing execution.');
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
latestCLIVersion = latestCLIVersion.substring(8).replace('\n', '');
|
|
32
38
|
if (semver_1.default.lt(constants_1.APP_VERSION, latestCLIVersion)) {
|
|
33
39
|
const updateAvailableMessage = `Update available ${chalk_1.default.yellow(constants_1.APP_VERSION)} → ${chalk_1.default.green(latestCLIVersion)}`;
|
|
34
40
|
const npmUpdateAvailableCommand = `Run ${chalk_1.default.cyan('npm i @contrast/contrast -g')} to update via npm`;
|
|
@@ -12,7 +12,7 @@ const MEDIUM = 'MEDIUM';
|
|
|
12
12
|
const HIGH = 'HIGH';
|
|
13
13
|
const CRITICAL = 'CRITICAL';
|
|
14
14
|
const APP_NAME = 'contrast';
|
|
15
|
-
const APP_VERSION = '1.0.
|
|
15
|
+
const APP_VERSION = '1.0.13';
|
|
16
16
|
const TIMEOUT = 120000;
|
|
17
17
|
const HIGH_COLOUR = '#ff9900';
|
|
18
18
|
const CRITICAL_COLOUR = '#e35858';
|
|
@@ -20,7 +20,7 @@ const en_locales = () => {
|
|
|
20
20
|
unauthenticatedErrorHeader: '401 error - Unauthenticated',
|
|
21
21
|
unauthenticatedErrorMessage: 'Please check the following keys are correct:\n--organization-id, --api-key or --authorization',
|
|
22
22
|
badRequestErrorHeader: '400 error - Bad Request',
|
|
23
|
-
badRequestErrorMessage: 'Please check
|
|
23
|
+
badRequestErrorMessage: 'Please check your parameters and try again',
|
|
24
24
|
badRequestCatalogueErrorMessage: 'The application name already exists, please use a unique name',
|
|
25
25
|
forbiddenRequestErrorHeader: '403 error - Forbidden',
|
|
26
26
|
forbiddenRequestErrorMessage: 'You do not have permission to access this server.',
|
|
@@ -213,7 +213,7 @@ const en_locales = () => {
|
|
|
213
213
|
scanOptionsFileNameSummary: 'Path of the file you want to scan. If no file is specified, Contrast searches for a .jar, .war, .exe or .zip file in the working directory.',
|
|
214
214
|
scanOptionsVerboseSummary: ' Returns extended information to the terminal.',
|
|
215
215
|
authSuccessMessage: 'Authentication successful',
|
|
216
|
-
runAuthSuccessMessage: "Now you can use CodeSec by Contrast \nRun: \n'contrast scan'
|
|
216
|
+
runAuthSuccessMessage: "Now you can use CodeSec by Contrast \nRun: \n'contrast scan' to run CodeSec’s industry leading SAST scanner \n'contrast audit' to find vulnerabilities in your open source dependencies \n'contrast lambda' to secure your AWS serverless functions\nor 'contrast help' to learn more about the capabilities.",
|
|
217
217
|
authWaitingMessage: 'Waiting for auth...',
|
|
218
218
|
authTimedOutMessage: 'Auth Timed out, try again',
|
|
219
219
|
zipErrorScan: 'We only support zip files for JAVASCRIPT language, please set the flag --language JAVASCRIPT',
|
package/dist/index.js
CHANGED
|
@@ -45,7 +45,7 @@ const start = async () => {
|
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
47
|
config.set('numOfRuns', config.get('numOfRuns') + 1);
|
|
48
|
-
if (config.get('numOfRuns') >=
|
|
48
|
+
if (config.get('numOfRuns') >= 10) {
|
|
49
49
|
await (0, versionChecker_1.findLatestCLIVersion)(config);
|
|
50
50
|
config.set('numOfRuns', 0);
|
|
51
51
|
}
|
package/dist/lambda/lambda.js
CHANGED
|
@@ -23,6 +23,7 @@ const oraWrapper_1 = __importDefault(require("../utils/oraWrapper"));
|
|
|
23
23
|
const analytics_1 = require("./analytics");
|
|
24
24
|
const types_1 = require("./types");
|
|
25
25
|
const constants_2 = require("../constants/constants");
|
|
26
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
26
27
|
const failedStates = [
|
|
27
28
|
'UNSUPPORTED',
|
|
28
29
|
'EXCLUDED',
|
|
@@ -109,6 +110,7 @@ const processLambda = async (argv) => {
|
|
|
109
110
|
}
|
|
110
111
|
await (0, analytics_1.postAnalytics)(endCommandAnalytics).catch((error) => {
|
|
111
112
|
});
|
|
113
|
+
postRunMessage();
|
|
112
114
|
if (errorMsg) {
|
|
113
115
|
process.exit(1);
|
|
114
116
|
}
|
|
@@ -191,3 +193,8 @@ const handleLambdaHelp = () => {
|
|
|
191
193
|
printHelpMessage();
|
|
192
194
|
process.exit(0);
|
|
193
195
|
};
|
|
196
|
+
const postRunMessage = () => {
|
|
197
|
+
console.log('\n' + chalk_1.default.underline.bold('Other Codesec Features:'));
|
|
198
|
+
console.log("'contrast scan' to run CodeSec’s industry leading SAST scanner");
|
|
199
|
+
console.log("'contrast audit' to find vulnerabilities in your open source dependencies\n");
|
|
200
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const commonApi = require('../../utils/commonApi');
|
|
3
|
+
const { APP_VERSION } = require('../../constants/constants');
|
|
4
|
+
const requestUtils = require('../../utils/requestUtils');
|
|
5
|
+
const scaTreeUpload = async (analysis, config) => {
|
|
6
|
+
const requestBody = {
|
|
7
|
+
applicationId: config.applicationId,
|
|
8
|
+
dependencyTree: analysis,
|
|
9
|
+
organizationId: config.organizationId,
|
|
10
|
+
language: 'NODE',
|
|
11
|
+
tool: {
|
|
12
|
+
name: 'Contrast Codesec',
|
|
13
|
+
version: APP_VERSION
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
const client = commonApi.getHttpClient(config);
|
|
17
|
+
const reportID = await client
|
|
18
|
+
.scaServiceIngest(requestBody, config)
|
|
19
|
+
.then(res => {
|
|
20
|
+
if (res.statusCode === 201) {
|
|
21
|
+
return res.body.libraryIngestJobId;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
throw new Error(res.statusCode + ` error ingesting dependencies`);
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
.catch(err => {
|
|
28
|
+
throw err;
|
|
29
|
+
});
|
|
30
|
+
let keepChecking = true;
|
|
31
|
+
while (keepChecking) {
|
|
32
|
+
keepChecking = await client
|
|
33
|
+
.scaServiceReportStatus(config, reportID)
|
|
34
|
+
.then(res => {
|
|
35
|
+
console.log(res.body);
|
|
36
|
+
if (res.body.status == 'COMPLETED') {
|
|
37
|
+
client.scaServiceReport(config, reportID).then(res => {
|
|
38
|
+
console.log(res.statusCode);
|
|
39
|
+
console.log(res.body);
|
|
40
|
+
});
|
|
41
|
+
return (keepChecking = false);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
return (keepChecking = true);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
await requestUtils.sleep(5000);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
module.exports = {
|
|
51
|
+
scaTreeUpload
|
|
52
|
+
};
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
const analysis = require('./analysis');
|
|
3
3
|
const i18n = require('i18n');
|
|
4
4
|
const formatMessage = require('../common/formatMessage');
|
|
5
|
+
const scaServiceParser = require('./scaServiceParser');
|
|
5
6
|
const jsAnalysis = async (config, languageFiles) => {
|
|
6
7
|
checkForCorrectFiles(languageFiles);
|
|
7
8
|
if (!config.file.endsWith('/')) {
|
|
@@ -12,6 +13,9 @@ const jsAnalysis = async (config, languageFiles) => {
|
|
|
12
13
|
const buildNodeTree = async (config, files) => {
|
|
13
14
|
let analysis = await readFiles(config, files);
|
|
14
15
|
const rawNode = await parseFiles(config, files, analysis);
|
|
16
|
+
if (config.experimental) {
|
|
17
|
+
return scaServiceParser.parseJS(rawNode);
|
|
18
|
+
}
|
|
15
19
|
return formatMessage.createJavaScriptTSMessage(rawNode);
|
|
16
20
|
};
|
|
17
21
|
const readFiles = async (config, files) => {
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const parseJS = rawNode => {
|
|
3
|
+
let dependencyTree = {};
|
|
4
|
+
let combinedPackageJSONDep = {
|
|
5
|
+
...rawNode.packageJSON?.dependencies,
|
|
6
|
+
...rawNode.packageJSON?.devDependencies
|
|
7
|
+
};
|
|
8
|
+
let analyseLock = chooseLockFile(rawNode);
|
|
9
|
+
if (analyseLock.type === 'yarn') {
|
|
10
|
+
dependencyTree = yarnCreateDepTree(dependencyTree, combinedPackageJSONDep, analyseLock.lockFile, rawNode);
|
|
11
|
+
}
|
|
12
|
+
if (analyseLock.type === 'npm') {
|
|
13
|
+
dependencyTree = npmCreateDepTree(dependencyTree, combinedPackageJSONDep, analyseLock.lockFile, rawNode);
|
|
14
|
+
}
|
|
15
|
+
return dependencyTree;
|
|
16
|
+
};
|
|
17
|
+
const npmCreateDepTree = (dependencyTree, combinedPackageJSONDep, packageLock, rawNode) => {
|
|
18
|
+
for (const [key, value] of Object.entries(packageLock)) {
|
|
19
|
+
dependencyTree[key] = {
|
|
20
|
+
name: key,
|
|
21
|
+
version: getResolvedVersion(key, packageLock),
|
|
22
|
+
group: null,
|
|
23
|
+
isProduction: checkIfInPackageJSON(rawNode.packageJSON.dependencies, key),
|
|
24
|
+
directDependency: checkIfInPackageJSON(combinedPackageJSONDep, key),
|
|
25
|
+
dependencies: createNPMChildDependencies(packageLock, key)
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return dependencyTree;
|
|
29
|
+
};
|
|
30
|
+
const yarnCreateDepTree = (dependencyTree, combinedPackageJSONDep, packageLock, rawNode) => {
|
|
31
|
+
for (const [key, value] of Object.entries(packageLock)) {
|
|
32
|
+
let gav = getNameFromGAV(key);
|
|
33
|
+
let nag = getDepNameWithoutVersion(key);
|
|
34
|
+
dependencyTree[key] = {
|
|
35
|
+
name: gav,
|
|
36
|
+
version: getResolvedVersion(key, packageLock),
|
|
37
|
+
group: null,
|
|
38
|
+
isProduction: checkIfInPackageJSON(rawNode.packageJSON.dependencies, nag),
|
|
39
|
+
directDependency: checkIfInPackageJSON(combinedPackageJSONDep, nag),
|
|
40
|
+
dependencies: createChildDependencies(packageLock, key)
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return dependencyTree;
|
|
44
|
+
};
|
|
45
|
+
const chooseLockFile = rawNode => {
|
|
46
|
+
if (rawNode?.yarn?.yarnLockFile !== undefined) {
|
|
47
|
+
return { lockFile: rawNode?.yarn?.yarnLockFile?.object, type: 'yarn' };
|
|
48
|
+
}
|
|
49
|
+
else if (rawNode.npmLockFile !== undefined) {
|
|
50
|
+
return { lockFile: rawNode?.npmLockFile?.dependencies, type: 'npm' };
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const createKeyName = (dep, version) => {
|
|
57
|
+
return dep + '@' + version;
|
|
58
|
+
};
|
|
59
|
+
const checkIfInPackageJSON = (list, dep) => {
|
|
60
|
+
return Object.keys(list).includes(dep);
|
|
61
|
+
};
|
|
62
|
+
const createChildDependencies = (lockFileDep, currentDep) => {
|
|
63
|
+
let depArray = [];
|
|
64
|
+
if (lockFileDep[currentDep]?.dependencies) {
|
|
65
|
+
for (const [key, value] of Object.entries(lockFileDep[currentDep]?.dependencies)) {
|
|
66
|
+
depArray.push(createKeyName(key, value));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return depArray;
|
|
70
|
+
};
|
|
71
|
+
const createNPMChildDependencies = (lockFileDep, currentDep) => {
|
|
72
|
+
let depArray = [];
|
|
73
|
+
if (lockFileDep[currentDep]?.requires) {
|
|
74
|
+
for (const [key, value] of Object.entries(lockFileDep[currentDep]?.requires)) {
|
|
75
|
+
depArray.push(key);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return depArray;
|
|
79
|
+
};
|
|
80
|
+
const getDepNameWithoutVersion = depKey => {
|
|
81
|
+
let dependency = depKey.split('@');
|
|
82
|
+
if (dependency.length - 1 > 1) {
|
|
83
|
+
return '@' + dependency[1];
|
|
84
|
+
}
|
|
85
|
+
return dependency[0];
|
|
86
|
+
};
|
|
87
|
+
const getNameFromGAV = depKey => {
|
|
88
|
+
let dependency = depKey.split('/');
|
|
89
|
+
if (dependency.length == 2) {
|
|
90
|
+
dependency = getDepNameWithoutVersion(dependency[1]);
|
|
91
|
+
return dependency;
|
|
92
|
+
}
|
|
93
|
+
if (dependency.length == 1) {
|
|
94
|
+
dependency = getDepNameWithoutVersion(depKey);
|
|
95
|
+
return dependency;
|
|
96
|
+
}
|
|
97
|
+
return depKey;
|
|
98
|
+
};
|
|
99
|
+
const getResolvedVersion = (depKey, packageLock) => {
|
|
100
|
+
return packageLock[depKey]?.version;
|
|
101
|
+
};
|
|
102
|
+
module.exports = {
|
|
103
|
+
parseJS,
|
|
104
|
+
checkIfInPackageJSON,
|
|
105
|
+
getNameFromGAV,
|
|
106
|
+
getResolvedVersion,
|
|
107
|
+
chooseLockFile,
|
|
108
|
+
createNPMChildDependencies
|
|
109
|
+
};
|
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const i18n = require('i18n');
|
|
4
|
+
const getRubyDeps = (config, languageFiles) => {
|
|
5
|
+
try {
|
|
6
|
+
checkForCorrectFiles(languageFiles);
|
|
7
|
+
const parsedGem = readAndParseGemfile(config.file);
|
|
8
|
+
const parsedLock = readAndParseGemLockFile(config.file);
|
|
9
|
+
if (config.experimental) {
|
|
10
|
+
const rubyArray = removeRedundantAndPopulateDefinedElements(parsedLock.sources);
|
|
11
|
+
let rubyTree = createRubyTree(rubyArray);
|
|
12
|
+
findChildrenDependencies(rubyTree);
|
|
13
|
+
processRootDependencies(parsedLock.dependencies, rubyTree);
|
|
14
|
+
return rubyTree;
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
return { gemfilesDependanceies: parsedGem, gemfileLock: parsedLock };
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
throw err;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
4
24
|
const readAndParseGemfile = file => {
|
|
5
25
|
const gemFile = fs.readFileSync(file + '/Gemfile', 'utf8');
|
|
6
26
|
const rubyArray = gemFile.split('\n');
|
|
@@ -189,16 +209,89 @@ const buildSourceDependencyWithVersion = (whitespaceRegx, dependencyRegEx, line,
|
|
|
189
209
|
}
|
|
190
210
|
return dependencies;
|
|
191
211
|
};
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
212
|
+
const processRootDependencies = (rootDependencies, rubyTree) => {
|
|
213
|
+
const getParentObjectByName = queryToken => Object.values(rubyTree).filter(({ name }) => name === queryToken);
|
|
214
|
+
for (let parent in rootDependencies) {
|
|
215
|
+
let parentObject = getParentObjectByName(parent);
|
|
216
|
+
if (parentObject[0]) {
|
|
217
|
+
let gav = parentObject[0].group +
|
|
218
|
+
'/' +
|
|
219
|
+
parentObject[0].name +
|
|
220
|
+
'@' +
|
|
221
|
+
parentObject[0].version;
|
|
222
|
+
rubyTree[gav] = parentObject[0];
|
|
223
|
+
rubyTree[gav].directDependency = true;
|
|
224
|
+
}
|
|
198
225
|
}
|
|
199
|
-
|
|
200
|
-
|
|
226
|
+
return rubyTree;
|
|
227
|
+
};
|
|
228
|
+
const createRubyTree = rubyArray => {
|
|
229
|
+
let rubyTree = {};
|
|
230
|
+
for (let x in rubyArray) {
|
|
231
|
+
let version = rubyArray[x].resolved;
|
|
232
|
+
let gav = rubyArray[x].group + '/' + rubyArray[x].name + '@' + version;
|
|
233
|
+
rubyTree[gav] = rubyArray[x];
|
|
234
|
+
rubyTree[gav].directDependency = false;
|
|
235
|
+
rubyTree[gav].version = version;
|
|
236
|
+
if (!rubyTree[gav].dependencies) {
|
|
237
|
+
rubyTree[gav].dependencies = [];
|
|
238
|
+
}
|
|
239
|
+
delete rubyTree[gav].resolved;
|
|
201
240
|
}
|
|
241
|
+
return rubyTree;
|
|
242
|
+
};
|
|
243
|
+
const findChildrenDependencies = rubyTree => {
|
|
244
|
+
for (let dep in rubyTree) {
|
|
245
|
+
let unResolvedChildDepsKey = Object.keys(rubyTree[dep].dependencies);
|
|
246
|
+
rubyTree[dep].dependencies = resolveVersionOfChildDependencies(unResolvedChildDepsKey, rubyTree);
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
const resolveVersionOfChildDependencies = (unResolvedChildDepsKey, rubyObject) => {
|
|
250
|
+
const getParentObjectByName = queryToken => Object.values(rubyObject).filter(({ name }) => name === queryToken);
|
|
251
|
+
let resolvedChildrenDependencies = [];
|
|
252
|
+
for (let childDep in unResolvedChildDepsKey) {
|
|
253
|
+
let childDependencyName = unResolvedChildDepsKey[childDep];
|
|
254
|
+
let parent = getParentObjectByName(childDependencyName);
|
|
255
|
+
resolvedChildrenDependencies.push('null/' + childDependencyName + '@' + parent[0].version);
|
|
256
|
+
}
|
|
257
|
+
return resolvedChildrenDependencies;
|
|
258
|
+
};
|
|
259
|
+
const removeRedundantAndPopulateDefinedElements = deps => {
|
|
260
|
+
return deps.map(element => {
|
|
261
|
+
if (element.sourceType === 'GIT') {
|
|
262
|
+
delete element.sourceType;
|
|
263
|
+
delete element.remote;
|
|
264
|
+
delete element.platform;
|
|
265
|
+
element.group = null;
|
|
266
|
+
element.isProduction = true;
|
|
267
|
+
}
|
|
268
|
+
if (element.sourceType === 'GEM') {
|
|
269
|
+
element.group = null;
|
|
270
|
+
element.isProduction = true;
|
|
271
|
+
delete element.sourceType;
|
|
272
|
+
delete element.remote;
|
|
273
|
+
delete element.platform;
|
|
274
|
+
}
|
|
275
|
+
if (element.sourceType === 'PATH') {
|
|
276
|
+
element.group = null;
|
|
277
|
+
element.isProduction = true;
|
|
278
|
+
delete element.platform;
|
|
279
|
+
delete element.sourceType;
|
|
280
|
+
delete element.remote;
|
|
281
|
+
}
|
|
282
|
+
if (element.sourceType === 'BUNDLED WITH') {
|
|
283
|
+
element.group = null;
|
|
284
|
+
element.isProduction = true;
|
|
285
|
+
delete element.sourceType;
|
|
286
|
+
delete element.remote;
|
|
287
|
+
delete element.branch;
|
|
288
|
+
delete element.revision;
|
|
289
|
+
delete element.depthLevel;
|
|
290
|
+
delete element.specs;
|
|
291
|
+
delete element.platform;
|
|
292
|
+
}
|
|
293
|
+
return element;
|
|
294
|
+
});
|
|
202
295
|
};
|
|
203
296
|
const checkForCorrectFiles = languageFiles => {
|
|
204
297
|
if (!languageFiles.includes('Gemfile.lock')) {
|
|
@@ -224,5 +317,9 @@ module.exports = {
|
|
|
224
317
|
getPatchLevel,
|
|
225
318
|
formatSourceArr,
|
|
226
319
|
getSourceArray,
|
|
227
|
-
checkForCorrectFiles
|
|
320
|
+
checkForCorrectFiles,
|
|
321
|
+
removeRedundantAndPopulateDefinedElements,
|
|
322
|
+
createRubyTree,
|
|
323
|
+
findChildrenDependencies,
|
|
324
|
+
processRootDependencies
|
|
228
325
|
};
|
|
@@ -3,7 +3,12 @@ const analysis = require('./analysis');
|
|
|
3
3
|
const { createRubyTSMessage } = require('../common/formatMessage');
|
|
4
4
|
const rubyAnalysis = (config, languageFiles) => {
|
|
5
5
|
const rubyDeps = analysis.getRubyDeps(config, languageFiles.RUBY);
|
|
6
|
-
|
|
6
|
+
if (config.experimental) {
|
|
7
|
+
return rubyDeps;
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
return createRubyTSMessage(rubyDeps);
|
|
11
|
+
}
|
|
7
12
|
};
|
|
8
13
|
module.exports = {
|
|
9
14
|
rubyAnalysis
|
package/dist/scan/scanResults.js
CHANGED
|
@@ -66,7 +66,7 @@ const returnScanResults = async (config, codeArtifactId, newProject, timeout, st
|
|
|
66
66
|
if (requestUtils.millisToSeconds(endTime) > timeout) {
|
|
67
67
|
oraFunctions.failSpinner(startScanSpinner, 'Contrast Scan timed out at the specified ' + timeout + ' seconds.');
|
|
68
68
|
const isCI = process.env.CONTRAST_CODESEC_CI
|
|
69
|
-
? JSON.parse(process.env.CONTRAST_CODESEC_CI)
|
|
69
|
+
? JSON.parse(process.env.CONTRAST_CODESEC_CI.toLowerCase())
|
|
70
70
|
: false;
|
|
71
71
|
if (!isCI) {
|
|
72
72
|
const retry = await retryScanPrompt();
|
|
File without changes
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const { featuresTeamServer } = require('./capabilities');
|
|
3
3
|
const semver = require('semver');
|
|
4
|
-
const { handleResponseErrors } = require('
|
|
5
|
-
const
|
|
4
|
+
const { handleResponseErrors } = require('../common/errorHandling');
|
|
5
|
+
const commonApi = require('./commonApi');
|
|
6
|
+
const { isNil } = require('lodash');
|
|
6
7
|
const getGlobalProperties = async (config) => {
|
|
7
|
-
const client = getHttpClient(config);
|
|
8
|
+
const client = commonApi.getHttpClient(config);
|
|
8
9
|
return client
|
|
9
|
-
.getGlobalProperties(config)
|
|
10
|
+
.getGlobalProperties(config.host)
|
|
10
11
|
.then(res => {
|
|
11
12
|
if (res.statusCode === 200) {
|
|
12
13
|
return res.body;
|
|
@@ -19,6 +20,13 @@ const getGlobalProperties = async (config) => {
|
|
|
19
20
|
console.log(err);
|
|
20
21
|
});
|
|
21
22
|
};
|
|
23
|
+
const getMode = async (config) => {
|
|
24
|
+
const features = await getGlobalProperties(config);
|
|
25
|
+
if (!isNil(features?.mode)) {
|
|
26
|
+
return features.mode;
|
|
27
|
+
}
|
|
28
|
+
return '';
|
|
29
|
+
};
|
|
22
30
|
const getFeatures = version => {
|
|
23
31
|
const featuresEnabled = [];
|
|
24
32
|
featuresTeamServer.forEach(feature => {
|
|
@@ -35,5 +43,6 @@ const isFeatureEnabled = (features, featureName) => {
|
|
|
35
43
|
module.exports = {
|
|
36
44
|
getGlobalProperties,
|
|
37
45
|
getFeatures,
|
|
38
|
-
isFeatureEnabled
|
|
46
|
+
isFeatureEnabled,
|
|
47
|
+
getMode
|
|
39
48
|
};
|