@contrast/contrast 3.2.0 → 3.2.2
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/auth/auth.js +4 -4
- package/dist/constants/constants.js +1 -1
- package/dist/constants/locales.js +1 -0
- package/dist/index.js +1 -7
- package/dist/sarif/generateSarif.js +43 -10
- package/dist/sarif/help.js +1 -4
- package/dist/sarif/sarifHelper.js +16 -0
- package/dist/sarif/sarifRequests.js +21 -5
- package/dist/utils/paramsUtil/paramHandler.js +15 -0
- package/package.json +1 -2
- package/dist/sarif/sarifClient.js +0 -33
- package/dist/sarif/sarifWriter.js +0 -199
package/dist/auth/auth.js
CHANGED
|
@@ -2,7 +2,7 @@ import { v4 as uuidv4 } from 'uuid';
|
|
|
2
2
|
import i18n from 'i18n';
|
|
3
3
|
import { failSpinner, returnOra, startSpinner, succeedSpinner } from '../utils/oraWrapper.js';
|
|
4
4
|
import { en_locales } from '../constants/locales.js';
|
|
5
|
-
import { AUTH_UI_URL,
|
|
5
|
+
import { AUTH_UI_URL, TIMEOUT } from '../constants/constants.js';
|
|
6
6
|
import { setConfigValues } from '../utils/getConfig.js';
|
|
7
7
|
import commandLineUsage from 'command-line-usage';
|
|
8
8
|
import { commonMessageFormatter } from '../common/errorHandling.js';
|
|
@@ -11,12 +11,12 @@ import { commandLineDefinitions } from '../cliConstants.js';
|
|
|
11
11
|
import { pollForAuth } from './authRequests.js';
|
|
12
12
|
import open from 'open';
|
|
13
13
|
import { logDebug, logInfo } from '../common/logging.js';
|
|
14
|
+
import { checkDeprecatedHost } from '../utils/paramsUtil/paramHandler.js';
|
|
14
15
|
const messages = en_locales();
|
|
15
16
|
export const processAuth = async (argv, config) => {
|
|
16
17
|
const authParams = await getCommandLineArgsCustom(config, 'auth', argv, commandLineDefinitions.authOptionDefinitions);
|
|
17
|
-
if (authParams.host
|
|
18
|
-
|
|
19
|
-
process.exit(0);
|
|
18
|
+
if (authParams.host) {
|
|
19
|
+
checkDeprecatedHost(authParams);
|
|
20
20
|
}
|
|
21
21
|
if (authParams.help) {
|
|
22
22
|
logInfo(authUsageGuide);
|
|
@@ -17,7 +17,7 @@ export const HIGH = 'HIGH';
|
|
|
17
17
|
export const CRITICAL = 'CRITICAL';
|
|
18
18
|
// App
|
|
19
19
|
export const APP_NAME = 'contrast';
|
|
20
|
-
const APP_VERSION = '3.2.
|
|
20
|
+
const APP_VERSION = '3.2.2';
|
|
21
21
|
export const TIMEOUT = 120000;
|
|
22
22
|
export const CRITICAL_PRIORITY = 1;
|
|
23
23
|
export const HIGH_PRIORITY = 2;
|
|
@@ -249,6 +249,7 @@ export const en_locales = () => {
|
|
|
249
249
|
auditServicesMessageForTS: 'View your vulnerable library list or full dependency tree in Contrast:',
|
|
250
250
|
auditReportFailureMessage: 'Unable to generate library report',
|
|
251
251
|
auditSCAAnalysisBegins: 'Contrast SCA audit started',
|
|
252
|
+
sarifAnalysis: 'Sarif analysis started...',
|
|
252
253
|
auditSCAAnalysisComplete: 'Contrast audit complete',
|
|
253
254
|
commonHelpHeader: 'Need More Help? NEW users',
|
|
254
255
|
commonHelpEnterpriseHeader: 'Existing Contrast Licensed user?',
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { localConfig } from './utils/getConfig.js';
|
|
3
|
-
import { APP_NAME,
|
|
3
|
+
import { APP_NAME, getAppVersion } from './constants/constants.js';
|
|
4
4
|
import commandLineArgs from 'command-line-args';
|
|
5
5
|
import { commandLineDefinitions } from './cliConstants.js';
|
|
6
6
|
import { findLatestCLIVersion, isCorrectNodeVersion } from './common/versionChecker.js';
|
|
@@ -17,8 +17,6 @@ import { processAssess } from './assess/index.js';
|
|
|
17
17
|
import { processSarif } from './sarif/generateSarif.js';
|
|
18
18
|
import { logInfo } from './common/logging.js';
|
|
19
19
|
import { generateYamlConfiguration } from './generateYaml/index.js';
|
|
20
|
-
import i18n from 'i18n';
|
|
21
|
-
import { exit } from 'process';
|
|
22
20
|
const config = localConfig(APP_NAME, getAppVersion());
|
|
23
21
|
const getMainOption = () => {
|
|
24
22
|
const mainOptions = commandLineArgs(commandLineDefinitions.mainDefinition, {
|
|
@@ -61,10 +59,6 @@ const start = async () => {
|
|
|
61
59
|
if (command === 'auth') {
|
|
62
60
|
return await processAuth(argvMain, config);
|
|
63
61
|
}
|
|
64
|
-
if (config.get('host') === CE_URL) {
|
|
65
|
-
logInfo(i18n.__('codeSecEoL'));
|
|
66
|
-
exit(0);
|
|
67
|
-
}
|
|
68
62
|
if (command === 'lambda') {
|
|
69
63
|
return await processLambda(argvMain);
|
|
70
64
|
}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { getSarifConfig } from './sarifConfig.js';
|
|
2
|
-
import { writeSarif } from './
|
|
3
|
-
import { logInfo } from '../common/logging.js';
|
|
2
|
+
import { convertSeverityInput, writeSarif } from './sarifHelper.js';
|
|
3
|
+
import { logDebug, logInfo } from '../common/logging.js';
|
|
4
4
|
import { sarifUsageGuide } from './help.js';
|
|
5
|
-
import {
|
|
5
|
+
import { createSarifReportId, sarifReport, sarifStatus } from './sarifRequests.js';
|
|
6
|
+
import { got } from 'got';
|
|
7
|
+
import { sleep } from '../utils/requestUtils.js';
|
|
8
|
+
import { handleTimeout } from '../utils/commonApi.js';
|
|
9
|
+
import { performance } from 'perf_hooks';
|
|
10
|
+
import { failSpinner, returnOra, startSpinner, succeedSpinner } from '../utils/oraWrapper.js';
|
|
11
|
+
import i18n from 'i18n';
|
|
6
12
|
// This filename could be set by a customer
|
|
7
13
|
// Defaulted to be ingested in a GH workflow
|
|
8
14
|
const outputFileName = 'contrast.sarif';
|
|
@@ -11,15 +17,42 @@ export const processSarif = async (contrastConf, argvMain) => {
|
|
|
11
17
|
printHelpMessage();
|
|
12
18
|
process.exit(0);
|
|
13
19
|
}
|
|
20
|
+
const startTime = performance.now();
|
|
14
21
|
let config = await getSarifConfig(contrastConf, 'sarif', argvMain);
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
if (!config.applicationId) {
|
|
23
|
+
throw new Error(`Unable to generate sarif file without application ID.`);
|
|
24
|
+
}
|
|
25
|
+
const reportSpinner = returnOra(i18n.__('sarifAnalysis'));
|
|
26
|
+
startSpinner(reportSpinner);
|
|
27
|
+
await generateSarif(config, reportSpinner, startTime);
|
|
28
|
+
};
|
|
29
|
+
export const generateSarif = async (config, reportSpinner, startTime) => {
|
|
30
|
+
let severities = [];
|
|
31
|
+
if (config.severity) {
|
|
32
|
+
severities = convertSeverityInput(config.severity);
|
|
33
|
+
}
|
|
34
|
+
const response = await createSarifReportId(config, severities);
|
|
35
|
+
if (response.body.success === true) {
|
|
36
|
+
const reportId = response.body.uuid;
|
|
37
|
+
logDebug(config, `Async sarif endpoint hit successfully - ${response.body.messages}`);
|
|
38
|
+
let doPoll = true;
|
|
39
|
+
while (doPoll) {
|
|
40
|
+
await sleep(5000);
|
|
41
|
+
const statusRes = await sarifStatus(config, reportId);
|
|
42
|
+
if (statusRes.body.status === 'ACTIVE') {
|
|
43
|
+
doPoll = false;
|
|
44
|
+
let data = await sarifReport(config, reportId);
|
|
45
|
+
writeSarif(outputFileName, data.body);
|
|
46
|
+
succeedSpinner(reportSpinner, 'contrast.sarif file generated successfully');
|
|
47
|
+
}
|
|
48
|
+
// defaulting timeout to 30 minutes
|
|
49
|
+
handleTimeout(startTime, 1800, reportSpinner);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
logDebug(config, response.body.messages);
|
|
54
|
+
failSpinner(reportSpinner, 'Unable to generate contrast.sarif');
|
|
20
55
|
}
|
|
21
|
-
writeSarif(outputFileName, sarifData);
|
|
22
|
-
logInfo('contrast.sarif file generated successfully');
|
|
23
56
|
};
|
|
24
57
|
const printHelpMessage = () => {
|
|
25
58
|
logInfo(sarifUsageGuide);
|
package/dist/sarif/help.js
CHANGED
|
@@ -45,8 +45,5 @@ export const sarifUsageGuide = commandLineUsage([
|
|
|
45
45
|
{
|
|
46
46
|
header: __('constantsAdvancedOptions'),
|
|
47
47
|
optionList: commandLineDefinitions.sarifAdvancedOptionDefinitionsForHelp
|
|
48
|
-
}
|
|
49
|
-
commonHelpLinks()[0],
|
|
50
|
-
commonHelpLinks()[1],
|
|
51
|
-
commonHelpLinks()[2]
|
|
48
|
+
}
|
|
52
49
|
]);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
export const writeSarif = (outputFileName, sarifData) => {
|
|
3
|
+
if (outputFileName) {
|
|
4
|
+
fs.writeFileSync(outputFileName, JSON.stringify(sarifData, null, 2), 'utf8');
|
|
5
|
+
}
|
|
6
|
+
else {
|
|
7
|
+
console.log(sarifData);
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
export const SEVERITIES = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW', 'NOTE'];
|
|
11
|
+
export const convertSeverityInput = severity => {
|
|
12
|
+
const index = SEVERITIES.indexOf(severity.toUpperCase());
|
|
13
|
+
if (index === -1)
|
|
14
|
+
return SEVERITIES;
|
|
15
|
+
return SEVERITIES.slice(0, index + 1);
|
|
16
|
+
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { buildBaseRequestOptions, ErrorType } from '../common/baseRequest.js';
|
|
2
2
|
import { got } from 'got';
|
|
3
|
-
const
|
|
4
|
-
return `${config.host}/Contrast/api/ng/organizations/${config.organizationId}/applications/${config.applicationId}/sarif`;
|
|
3
|
+
export const createSarifReportUrl = (config) => {
|
|
4
|
+
return `${config.host}/Contrast/api/ng/organizations/${config.organizationId}/applications/${config.applicationId}/sarif/async`;
|
|
5
5
|
};
|
|
6
|
-
export
|
|
6
|
+
export const createSarifReportId = (config, severities) => {
|
|
7
7
|
const options = buildBaseRequestOptions(config, ErrorType.GENERIC);
|
|
8
|
-
options.url =
|
|
8
|
+
options.url = createSarifReportUrl(config);
|
|
9
9
|
options.json = {
|
|
10
10
|
metadataFilters: config.metadata ? config.metadata : [],
|
|
11
11
|
// User can specify minimum severity, if none will include all
|
|
@@ -14,4 +14,20 @@ export function getSarifVulns(config, severities) {
|
|
|
14
14
|
toolTypes: config.toolType ? [config.toolType] : ['SCA', 'ASSESS']
|
|
15
15
|
};
|
|
16
16
|
return got.post(options);
|
|
17
|
-
}
|
|
17
|
+
};
|
|
18
|
+
export const sarifStatusUrl = (config, reportUuid) => {
|
|
19
|
+
return `${config.host}/Contrast/api/ng/organizations/${config.organizationId}/reports/${reportUuid}/status`;
|
|
20
|
+
};
|
|
21
|
+
export const sarifStatus = (config, reportId) => {
|
|
22
|
+
const options = buildBaseRequestOptions(config, ErrorType.GENERIC);
|
|
23
|
+
options.url = sarifStatusUrl(config, reportId);
|
|
24
|
+
return got.get(options);
|
|
25
|
+
};
|
|
26
|
+
export const getSarifDataUrl = (config, reportUuid) => {
|
|
27
|
+
return `${config.host}/Contrast/api/ng/${config.organizationId}/reports/${reportUuid}/download`;
|
|
28
|
+
};
|
|
29
|
+
export const sarifReport = async (config, reportId) => {
|
|
30
|
+
const options = buildBaseRequestOptions(config, ErrorType.GENERIC);
|
|
31
|
+
options.url = getSarifDataUrl(config, reportId);
|
|
32
|
+
return await got.post(options);
|
|
33
|
+
};
|
|
@@ -4,17 +4,32 @@ import { configStoreGetAuth } from './configStoreParams.js';
|
|
|
4
4
|
import i18n from 'i18n';
|
|
5
5
|
import { validateAuthParams, validateFingerprintParams } from '../validationCheck.js';
|
|
6
6
|
import { logInfo } from '../../common/logging.js';
|
|
7
|
+
import { CE_URL } from '../../constants/constants.js';
|
|
8
|
+
import { exit } from 'process';
|
|
9
|
+
/**
|
|
10
|
+
* Checks if the host is the deprecated CE_URL and exits if it is
|
|
11
|
+
* @param {Object} authParams - Auth parameters object containing host property
|
|
12
|
+
*/
|
|
13
|
+
export function checkDeprecatedHost(authParams) {
|
|
14
|
+
if (authParams.host === CE_URL) {
|
|
15
|
+
logInfo(i18n.__('codeSecEoL'));
|
|
16
|
+
exit(1);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
7
19
|
export function getAuth(params) {
|
|
8
20
|
let commandLineAuthParamsAuth = commandGetAuth(params);
|
|
9
21
|
let envVariableParamsAuth = envGetAuth();
|
|
10
22
|
let configStoreParamsAuth = configStoreGetAuth();
|
|
11
23
|
if (validateAuthParams(commandLineAuthParamsAuth)) {
|
|
24
|
+
checkDeprecatedHost(commandLineAuthParamsAuth);
|
|
12
25
|
return commandLineAuthParamsAuth;
|
|
13
26
|
}
|
|
14
27
|
else if (validateAuthParams(envVariableParamsAuth)) {
|
|
28
|
+
checkDeprecatedHost(envVariableParamsAuth);
|
|
15
29
|
return envVariableParamsAuth;
|
|
16
30
|
}
|
|
17
31
|
else if (validateAuthParams(configStoreParamsAuth)) {
|
|
32
|
+
checkDeprecatedHost(configStoreParamsAuth);
|
|
18
33
|
return configStoreParamsAuth;
|
|
19
34
|
}
|
|
20
35
|
else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contrast/contrast",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.2",
|
|
4
4
|
"description": "Contrast Security's command line tool",
|
|
5
5
|
"exports": "./dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -77,7 +77,6 @@
|
|
|
77
77
|
"js-yaml": "4.1.0",
|
|
78
78
|
"lodash-es": "4.17.21",
|
|
79
79
|
"log-symbols": "4.1.0",
|
|
80
|
-
"node-sarif-builder": "^3.1.0",
|
|
81
80
|
"open": "8.4.2",
|
|
82
81
|
"ora": "6.3.1",
|
|
83
82
|
"pkginfo": "0.4.1",
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { getSarifVulns } from './sarifRequests.js';
|
|
2
|
-
export const sarifVulns = async (config) => {
|
|
3
|
-
let severities = [];
|
|
4
|
-
if (config.severity) {
|
|
5
|
-
severities = convertSeverityInput(config.severity);
|
|
6
|
-
}
|
|
7
|
-
const response = await getSarifVulns(config, severities);
|
|
8
|
-
if (response.statusCode === 200) {
|
|
9
|
-
console.log('Retrieved SARIF data');
|
|
10
|
-
return JSON.stringify(response.body, null, 2);
|
|
11
|
-
}
|
|
12
|
-
else {
|
|
13
|
-
console.log(`Error retrieving SARIF data`);
|
|
14
|
-
return '';
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
export function convertSeverityInput(severity) {
|
|
18
|
-
const severities = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW', 'NOTE'];
|
|
19
|
-
switch (severity.toUpperCase()) {
|
|
20
|
-
case 'CRITICAL':
|
|
21
|
-
return severities.slice(0, 1);
|
|
22
|
-
case 'HIGH':
|
|
23
|
-
return severities.slice(0, 2);
|
|
24
|
-
case 'MEDIUM':
|
|
25
|
-
return severities.slice(0, 3);
|
|
26
|
-
case 'LOW':
|
|
27
|
-
return severities.slice(0, 4);
|
|
28
|
-
case 'NOTE':
|
|
29
|
-
return severities;
|
|
30
|
-
default:
|
|
31
|
-
return severities;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
import { SarifBuilder, SarifRunBuilder, SarifResultBuilder, SarifRuleBuilder } from 'node-sarif-builder';
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
export const mapSeverity = contrastSeverity => {
|
|
4
|
-
switch (contrastSeverity.toLowerCase()) {
|
|
5
|
-
case 'critical':
|
|
6
|
-
return 'error';
|
|
7
|
-
case 'high':
|
|
8
|
-
return 'warning';
|
|
9
|
-
case 'medium':
|
|
10
|
-
return 'note';
|
|
11
|
-
case 'low':
|
|
12
|
-
return 'note';
|
|
13
|
-
case 'note':
|
|
14
|
-
return 'note';
|
|
15
|
-
default:
|
|
16
|
-
return 'note';
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
export const getFileFromTSDescription = description => {
|
|
20
|
-
const regex = /\(([^)]+):\d*\)/;
|
|
21
|
-
const match = regex.exec(description);
|
|
22
|
-
return match ? match[1] : 'NOT AVAILABLE';
|
|
23
|
-
};
|
|
24
|
-
export const getLineFromTSDescription = description => {
|
|
25
|
-
const regex = /\(.*:(\d*)\)/;
|
|
26
|
-
const match = regex.exec(description);
|
|
27
|
-
return match ? parseInt(match[1]) : 1;
|
|
28
|
-
};
|
|
29
|
-
export const getLogicalLocationFromTSDescription = description => {
|
|
30
|
-
const regex = /(.*)\([^]+:\d*\)/;
|
|
31
|
-
const match = regex.exec(description);
|
|
32
|
-
return match ? match[1] + '()' : 'NOT AVAILABLE';
|
|
33
|
-
};
|
|
34
|
-
export const generateIastSarifRun = traces => {
|
|
35
|
-
const sarifRunBuilderIast = new SarifRunBuilder().initSimple({
|
|
36
|
-
toolDriverName: 'contrast-assess',
|
|
37
|
-
toolDriverVersion: '1.0.0',
|
|
38
|
-
url: 'https://contrastsecurity.com' // Url of your analyzer tool
|
|
39
|
-
});
|
|
40
|
-
if (traces.length === 0) {
|
|
41
|
-
return sarifRunBuilderIast;
|
|
42
|
-
}
|
|
43
|
-
for (const trace of traces) {
|
|
44
|
-
let extractedString = null;
|
|
45
|
-
if (trace.trace.sink && trace.trace.sink.label) {
|
|
46
|
-
extractedString = getFileFromTSDescription(trace.trace.sink.label);
|
|
47
|
-
}
|
|
48
|
-
const sarifResultBuilder = new SarifResultBuilder().initSimple({
|
|
49
|
-
ruleId: trace.trace.rule_title,
|
|
50
|
-
messageText: trace.trace.title,
|
|
51
|
-
level: mapSeverity(trace.trace.severity)
|
|
52
|
-
});
|
|
53
|
-
const sarifRuleBuilder = new SarifRuleBuilder().initSimple({
|
|
54
|
-
ruleId: trace.trace.rule_title,
|
|
55
|
-
shortDescriptionText: trace.trace.title,
|
|
56
|
-
fullDescriptionText: trace.trace.title
|
|
57
|
-
});
|
|
58
|
-
sarifRunBuilderIast.addRule(sarifRuleBuilder);
|
|
59
|
-
if (extractedString) {
|
|
60
|
-
sarifResultBuilder.setLocationArtifactUri({ uri: extractedString });
|
|
61
|
-
}
|
|
62
|
-
if (trace.trace.request) {
|
|
63
|
-
sarifResultBuilder.result.webRequest = {
|
|
64
|
-
target: trace.trace.request.uri,
|
|
65
|
-
method: trace.trace.request.method,
|
|
66
|
-
protocol: trace.trace.request.protocol,
|
|
67
|
-
version: trace.trace.request.version
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
sarifResultBuilder.result.provenance = {
|
|
71
|
-
firstDetectionTimeUtc: new Date(trace.trace.discovered).toISOString(),
|
|
72
|
-
lastDetectionTimeUtc: new Date(trace.trace.last_time_seen).toISOString()
|
|
73
|
-
};
|
|
74
|
-
sarifResultBuilder.result.properties = {
|
|
75
|
-
vulnerability_id: trace.trace.uuid,
|
|
76
|
-
contrast_severity: trace.trace.severity,
|
|
77
|
-
contrast_status: trace.trace.status,
|
|
78
|
-
contrast_substatus: trace.trace.sub_status
|
|
79
|
-
};
|
|
80
|
-
// Add stack trace
|
|
81
|
-
sarifResultBuilder.result.codeFlows = [
|
|
82
|
-
{
|
|
83
|
-
threadFlows: trace.events.map(event => {
|
|
84
|
-
return {
|
|
85
|
-
locations: [
|
|
86
|
-
{
|
|
87
|
-
location: {
|
|
88
|
-
physicalLocation: {
|
|
89
|
-
artifactLocation: {
|
|
90
|
-
uri: getFileFromTSDescription(event.stacktraces[0].description)
|
|
91
|
-
},
|
|
92
|
-
region: {
|
|
93
|
-
startLine: getLineFromTSDescription(event.stacktraces[0].description)
|
|
94
|
-
}
|
|
95
|
-
},
|
|
96
|
-
logicalLocations: [
|
|
97
|
-
{
|
|
98
|
-
fullyQualifiedName: getLogicalLocationFromTSDescription(event.stacktraces[0].description)
|
|
99
|
-
}
|
|
100
|
-
]
|
|
101
|
-
},
|
|
102
|
-
stack: {
|
|
103
|
-
frames: event.stacktraces
|
|
104
|
-
.filter(stacktrace => getFileFromTSDescription(stacktrace.description) !==
|
|
105
|
-
'NOT AVAILABLE')
|
|
106
|
-
.map(stacktrace => {
|
|
107
|
-
return {
|
|
108
|
-
location: {
|
|
109
|
-
physicalLocation: {
|
|
110
|
-
artifactLocation: {
|
|
111
|
-
uri: getFileFromTSDescription(stacktrace.description)
|
|
112
|
-
},
|
|
113
|
-
region: {
|
|
114
|
-
startLine: getLineFromTSDescription(stacktrace.description)
|
|
115
|
-
}
|
|
116
|
-
},
|
|
117
|
-
logicalLocations: [
|
|
118
|
-
{
|
|
119
|
-
fullyQualifiedName: getLogicalLocationFromTSDescription(stacktrace.description)
|
|
120
|
-
}
|
|
121
|
-
]
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
})
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
]
|
|
128
|
-
};
|
|
129
|
-
}),
|
|
130
|
-
properties: {
|
|
131
|
-
routeSignature: trace.routes[0] ? trace.routes[0].signature : ''
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
];
|
|
135
|
-
sarifResultBuilder.result.locations = [];
|
|
136
|
-
sarifResultBuilder.result.locations.push({
|
|
137
|
-
physicalLocation: {
|
|
138
|
-
artifactLocation: {
|
|
139
|
-
uri: getFileFromTSDescription(trace.trace.sink.label)
|
|
140
|
-
},
|
|
141
|
-
region: {
|
|
142
|
-
startLine: getLineFromTSDescription(trace.trace.sink.label)
|
|
143
|
-
}
|
|
144
|
-
},
|
|
145
|
-
logicalLocations: [
|
|
146
|
-
{
|
|
147
|
-
fullyQualifiedName: getLogicalLocationFromTSDescription(trace.trace.sink.label)
|
|
148
|
-
}
|
|
149
|
-
]
|
|
150
|
-
});
|
|
151
|
-
sarifRunBuilderIast.addResult(sarifResultBuilder);
|
|
152
|
-
}
|
|
153
|
-
return sarifRunBuilderIast;
|
|
154
|
-
};
|
|
155
|
-
export const generateScaSarifRun = cveList => {
|
|
156
|
-
const sarifRunBuilderSca = new SarifRunBuilder().initSimple({
|
|
157
|
-
toolDriverName: 'contrast-sca',
|
|
158
|
-
toolDriverVersion: '1.0.0',
|
|
159
|
-
url: 'https://contrastsecurity.com' // Url of your analyzer tool
|
|
160
|
-
});
|
|
161
|
-
if (cveList.length === 0) {
|
|
162
|
-
return sarifRunBuilderSca;
|
|
163
|
-
}
|
|
164
|
-
for (const cve of cveList) {
|
|
165
|
-
const sarifResultBuilder = new SarifResultBuilder().initSimple({
|
|
166
|
-
ruleId: cve.name,
|
|
167
|
-
messageText: cve.description,
|
|
168
|
-
level: mapSeverity(cve.severityToUse)
|
|
169
|
-
});
|
|
170
|
-
sarifResultBuilder.setLocationArtifactUri({ uri: cve.library.file_name });
|
|
171
|
-
sarifResultBuilder.result.properties = {
|
|
172
|
-
contrast_severity: cve.severityToUse,
|
|
173
|
-
library_version: cve.library.version,
|
|
174
|
-
cvss_score: cve.cvss_3_severity_value,
|
|
175
|
-
vector: cve.cvss_3_vector
|
|
176
|
-
};
|
|
177
|
-
sarifRunBuilderSca.addResult(sarifResultBuilder);
|
|
178
|
-
}
|
|
179
|
-
return sarifRunBuilderSca;
|
|
180
|
-
};
|
|
181
|
-
export const writeCombinedSarif = (traces, cveList, outputFileName) => {
|
|
182
|
-
const sarifBuilder = new SarifBuilder();
|
|
183
|
-
const sarifRunBuilderIast = generateIastSarifRun(traces);
|
|
184
|
-
sarifBuilder.addRun(sarifRunBuilderIast);
|
|
185
|
-
const sarifRunBuilderSca = generateScaSarifRun(cveList);
|
|
186
|
-
sarifBuilder.addRun(sarifRunBuilderSca);
|
|
187
|
-
const sarifJsonString = sarifBuilder.buildSarifJsonString({
|
|
188
|
-
indent: true
|
|
189
|
-
}); // indent:true if you like
|
|
190
|
-
writeSarif(outputFileName, sarifJsonString);
|
|
191
|
-
};
|
|
192
|
-
export const writeSarif = (outputFileName, sarifData) => {
|
|
193
|
-
if (outputFileName) {
|
|
194
|
-
fs.writeFileSync(outputFileName, sarifData);
|
|
195
|
-
}
|
|
196
|
-
else {
|
|
197
|
-
console.log(sarifData);
|
|
198
|
-
}
|
|
199
|
-
};
|