@contrast/contrast 2.0.0 → 2.0.2-beta.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/dist/audit/report/reportingFeature.js +7 -0
- package/dist/cliConstants.js +22 -1
- package/dist/commands/audit/help.js +1 -3
- package/dist/commands/audit/processAudit.js +0 -2
- package/dist/commands/github/fingerprintConfig.js +2 -1
- package/dist/commands/github/processFingerprint.js +28 -0
- package/dist/commands/github/projectGroup.js +124 -34
- package/dist/commands/github/repoServices.js +108 -0
- package/dist/common/HTTPClient.js +38 -17
- package/dist/common/baseRequest.js +74 -0
- package/dist/common/errorHandling.js +1 -1
- package/dist/constants/constants.js +1 -1
- package/dist/index.js +4 -0
- package/dist/scaAnalysis/common/auditReport.js +8 -1
- package/dist/scaAnalysis/common/scaServicesUpload.js +3 -1
- package/dist/scaAnalysis/go/goReadDepFile.js +5 -1
- package/dist/scaAnalysis/java/analysis.js +1 -1
- package/dist/scaAnalysis/java/javaBuildDepsParser.js +11 -1
- package/dist/scaAnalysis/legacy/legacyFlow.js +0 -6
- package/dist/scaAnalysis/processServicesFlow.js +49 -10
- package/dist/scaAnalysis/repoMode/mavenParser.js +19 -1
- package/dist/scaAnalysis/scaAnalysis.js +4 -8
- package/dist/scan/autoDetection.js +14 -3
- package/dist/scan/fileUtils.js +33 -19
- package/dist/utils/paramsUtil/paramHandler.js +11 -2
- package/dist/utils/validationCheck.js +5 -1
- package/package.json +6 -3
- package/src/audit/report/reportingFeature.ts +7 -0
- package/src/cliConstants.js +22 -1
- package/src/commands/audit/help.js +1 -3
- package/src/commands/audit/processAudit.js +0 -2
- package/src/commands/github/fingerprintConfig.js +2 -2
- package/src/commands/github/processFingerprint.js +37 -0
- package/src/commands/github/projectGroup.js +146 -39
- package/src/commands/github/repoServices.js +122 -0
- package/src/common/HTTPClient.js +47 -18
- package/src/common/baseRequest.ts +83 -0
- package/src/common/errorHandling.js +2 -2
- package/src/constants/constants.js +1 -1
- package/src/index.ts +5 -0
- package/src/scaAnalysis/common/auditReport.js +8 -1
- package/src/scaAnalysis/common/scaServicesUpload.js +5 -1
- package/src/scaAnalysis/go/goReadDepFile.js +5 -1
- package/src/scaAnalysis/java/analysis.js +1 -1
- package/src/scaAnalysis/java/javaBuildDepsParser.js +17 -1
- package/src/scaAnalysis/legacy/legacyFlow.js +0 -5
- package/src/scaAnalysis/processServicesFlow.js +107 -17
- package/src/scaAnalysis/repoMode/mavenParser.js +24 -1
- package/src/scaAnalysis/scaAnalysis.js +9 -8
- package/src/scan/autoDetection.js +14 -3
- package/src/scan/fileUtils.js +33 -19
- package/src/utils/paramsUtil/paramHandler.js +16 -2
- package/src/utils/validationCheck.js +6 -1
- package/dist/utils/settingsHelper.js +0 -14
- package/src/utils/settingsHelper.js +0 -16
|
@@ -0,0 +1,74 @@
|
|
|
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.buildBaseRequestOptions = exports.gotInstance = void 0;
|
|
7
|
+
const hpagent_1 = require("hpagent");
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const got_1 = __importDefault(require("got"));
|
|
10
|
+
function gotInstance(config) {
|
|
11
|
+
return got_1.default.extend({ retry: { limit: 0 }, ...buildBaseRequestOptions(config) });
|
|
12
|
+
}
|
|
13
|
+
exports.gotInstance = gotInstance;
|
|
14
|
+
function buildBaseRequestOptions(config) {
|
|
15
|
+
const { apiKey, authorization } = config;
|
|
16
|
+
const rejectUnauthorized = !config.certSelfSigned;
|
|
17
|
+
const superApiKey = config.superApiKey;
|
|
18
|
+
const superAuthToken = config.superAuthorization;
|
|
19
|
+
const requestOptions = {
|
|
20
|
+
responseType: 'json',
|
|
21
|
+
forever: true,
|
|
22
|
+
uri: config.host,
|
|
23
|
+
followRedirect: false,
|
|
24
|
+
headers: {
|
|
25
|
+
'Content-Type': 'application/json; charset=utf-8',
|
|
26
|
+
Authorization: authorization,
|
|
27
|
+
'API-Key': apiKey,
|
|
28
|
+
SuperAuthorization: superAuthToken,
|
|
29
|
+
'Super-API-Key': superApiKey,
|
|
30
|
+
'User-Agent': 'contrast-cli-v2'
|
|
31
|
+
},
|
|
32
|
+
agent: getAgent(config)
|
|
33
|
+
};
|
|
34
|
+
requestOptions.https = {
|
|
35
|
+
rejectUnauthorized: rejectUnauthorized
|
|
36
|
+
};
|
|
37
|
+
maybeAddCertsToRequest(config, requestOptions.https);
|
|
38
|
+
return requestOptions;
|
|
39
|
+
}
|
|
40
|
+
exports.buildBaseRequestOptions = buildBaseRequestOptions;
|
|
41
|
+
function getAgent(config) {
|
|
42
|
+
return config.proxy
|
|
43
|
+
? new hpagent_1.HttpsProxyAgent({ proxy: config.proxy })
|
|
44
|
+
: false;
|
|
45
|
+
}
|
|
46
|
+
function maybeAddCertsToRequest(config, https) {
|
|
47
|
+
const caCertFilePath = config.cacert;
|
|
48
|
+
if (caCertFilePath) {
|
|
49
|
+
try {
|
|
50
|
+
https.certificateAuthority = fs_1.default.readFileSync(caCertFilePath);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
throw new Error(`Unable to read CA from ${caCertFilePath}, msg: ${error.message}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const certPath = config.cert;
|
|
57
|
+
if (certPath) {
|
|
58
|
+
try {
|
|
59
|
+
https.certificate = fs_1.default.readFileSync(certPath);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
throw new Error(`Unable to read Certificate PEM file from config option contrast.api.certificate.cert_file='${certPath}', msg: ${error.message}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const keyPath = config.key;
|
|
66
|
+
if (keyPath) {
|
|
67
|
+
try {
|
|
68
|
+
https.key = fs_1.default.readFileSync(keyPath);
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
throw new Error(`Unable to read Key PEM file from config option contrast.api.certificate.key_file='${keyPath}', msg: ${error.message}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -37,7 +37,7 @@ const maxAppError = () => {
|
|
|
37
37
|
process.exit(1);
|
|
38
38
|
};
|
|
39
39
|
const parametersError = () => {
|
|
40
|
-
generalError(`
|
|
40
|
+
generalError(`Credentials not recognized`, 'Check your command & keys again for hidden characters / verify that the credentials are correct.\nFor more information use contrast help.');
|
|
41
41
|
process.exit(1);
|
|
42
42
|
};
|
|
43
43
|
const invalidHostNameError = () => {
|
|
@@ -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 = '2.0.0';
|
|
15
|
+
const APP_VERSION = '2.0.2-beta.0';
|
|
16
16
|
const TIMEOUT = 120000;
|
|
17
17
|
const HIGH_COLOUR = '#ff9900';
|
|
18
18
|
const CRITICAL_COLOUR = '#e35858';
|
package/dist/index.js
CHANGED
|
@@ -17,6 +17,7 @@ const versionChecker_1 = require("./common/versionChecker");
|
|
|
17
17
|
const errorHandling_1 = require("./common/errorHandling");
|
|
18
18
|
const telemetry_1 = require("./telemetry/telemetry");
|
|
19
19
|
const processLearn_1 = require("./commands/learn/processLearn");
|
|
20
|
+
const processFingerprint_1 = require("./commands/github/processFingerprint");
|
|
20
21
|
const { commandLineDefinitions: { mainUsageGuide, mainDefinition } } = cliConstants_1.default;
|
|
21
22
|
const config = (0, getConfig_1.localConfig)(constants_1.APP_NAME, constants_1.APP_VERSION);
|
|
22
23
|
const getMainOption = () => {
|
|
@@ -65,6 +66,9 @@ const start = async () => {
|
|
|
65
66
|
if (command === 'audit') {
|
|
66
67
|
return await (0, processAudit_1.processAudit)(config, argvMain);
|
|
67
68
|
}
|
|
69
|
+
if (command === 'fingerprint') {
|
|
70
|
+
return await (0, processFingerprint_1.processFingerprint)(config, argvMain);
|
|
71
|
+
}
|
|
68
72
|
if (command === 'learn') {
|
|
69
73
|
return (0, processLearn_1.processLearn)();
|
|
70
74
|
}
|
|
@@ -2,11 +2,18 @@
|
|
|
2
2
|
const { getSeverityCounts, printNoVulnFoundMsg } = require('../../audit/report/commonReportingFunctions');
|
|
3
3
|
const common = require('../../common/fail');
|
|
4
4
|
const { printFormattedOutputSca } = require('./commonReportingFunctionsSca');
|
|
5
|
-
const
|
|
5
|
+
const { auditSave } = require('../../audit/save');
|
|
6
|
+
const processAuditReport = async (config, reportModelList, reportId) => {
|
|
6
7
|
let severityCounts = {};
|
|
7
8
|
if (reportModelList !== undefined) {
|
|
8
9
|
severityCounts = formatScaServicesReport(config, reportModelList);
|
|
9
10
|
}
|
|
11
|
+
if (config.save !== undefined) {
|
|
12
|
+
await auditSave(config, reportId);
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
console.log('Use contrast audit --save to generate an SBOM');
|
|
16
|
+
}
|
|
10
17
|
if (config.fail) {
|
|
11
18
|
common.processFail(config, severityCounts);
|
|
12
19
|
}
|
|
@@ -11,8 +11,10 @@ const scaTreeUpload = async (analysis, config, reportSpinner) => {
|
|
|
11
11
|
config.language = config.language === 'JAVASCRIPT' ? 'NODE' : config.language;
|
|
12
12
|
const startTime = performance.now();
|
|
13
13
|
const timeout = commonApi.getTimeout(config);
|
|
14
|
+
const doINeedParent = config.repositoryId && config.language === 'JAVA';
|
|
14
15
|
const requestBody = {
|
|
15
|
-
|
|
16
|
+
parentPom: doINeedParent ? analysis.parentPom : null,
|
|
17
|
+
dependencyTree: doINeedParent ? analysis.dependencyTree : analysis,
|
|
16
18
|
organizationId: config.organizationId,
|
|
17
19
|
language: config.language,
|
|
18
20
|
tool: {
|
|
@@ -5,7 +5,10 @@ const getGoDependencies = config => {
|
|
|
5
5
|
let cmdStdout;
|
|
6
6
|
let cwd = config.file ? config.file.replace('go.mod', '') : process.cwd();
|
|
7
7
|
try {
|
|
8
|
-
cmdStdout = child_process.execSync('go mod graph', {
|
|
8
|
+
cmdStdout = child_process.execSync('go mod graph', {
|
|
9
|
+
cwd: cwd,
|
|
10
|
+
maxBuffer: 50 * 1024 * 1024
|
|
11
|
+
});
|
|
9
12
|
return cmdStdout.toString();
|
|
10
13
|
}
|
|
11
14
|
catch (err) {
|
|
@@ -14,6 +17,7 @@ const getGoDependencies = config => {
|
|
|
14
17
|
'\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.';
|
|
15
18
|
}
|
|
16
19
|
console.log(i18n.__('goReadProjectFile', cwd, `${err.message ? err.message : ''}`));
|
|
20
|
+
process.exit(1);
|
|
17
21
|
}
|
|
18
22
|
};
|
|
19
23
|
module.exports = {
|
|
@@ -24,7 +24,7 @@ const determineProjectTypeAndCwd = (files, config) => {
|
|
|
24
24
|
};
|
|
25
25
|
const buildMaven = (config, projectData, timeout) => {
|
|
26
26
|
let command = 'mvn';
|
|
27
|
-
let args = ['dependency:tree', '-B'];
|
|
27
|
+
let args = ['dependency:tree', '-B', '-Dscope=runtime'];
|
|
28
28
|
if (config.mavenSettingsPath) {
|
|
29
29
|
args.push('-s');
|
|
30
30
|
args.push(config.mavenSettingsPath);
|
|
@@ -119,7 +119,7 @@ const computeRelationToLastElement = element => {
|
|
|
119
119
|
}
|
|
120
120
|
};
|
|
121
121
|
const stripElement = element => {
|
|
122
|
-
|
|
122
|
+
const initialStrippedElement = element
|
|
123
123
|
.replace(/[|]/g, '')
|
|
124
124
|
.replace('+---', '')
|
|
125
125
|
.replace('\\---', '')
|
|
@@ -127,6 +127,16 @@ const stripElement = element => {
|
|
|
127
127
|
.replace('(c)', '')
|
|
128
128
|
.replace('->', '@')
|
|
129
129
|
.replace('(*)', '');
|
|
130
|
+
const splitElements = initialStrippedElement.split(':');
|
|
131
|
+
if (splitElements[2] !== undefined &&
|
|
132
|
+
splitElements[2] !== null &&
|
|
133
|
+
splitElements[2].includes('@')) {
|
|
134
|
+
const splitVersions = splitElements[2].split('@');
|
|
135
|
+
return initialStrippedElement
|
|
136
|
+
.replace(':' + splitVersions[0], '')
|
|
137
|
+
.replace('@', ':');
|
|
138
|
+
}
|
|
139
|
+
return initialStrippedElement;
|
|
130
140
|
};
|
|
131
141
|
const checkVersion = element => {
|
|
132
142
|
let version = element.split(':');
|
|
@@ -18,12 +18,6 @@ const legacyFlow = async (config, messageToSend) => {
|
|
|
18
18
|
await pollForSnapshotCompletion(config, snapshotResponse.id, reportSpinner);
|
|
19
19
|
succeedSpinner(reportSpinner, i18n.__('auditSCAAnalysisComplete'));
|
|
20
20
|
await vulnerabilityReportV2(config, snapshotResponse.id);
|
|
21
|
-
if (config.save !== undefined) {
|
|
22
|
-
await auditSave(config);
|
|
23
|
-
}
|
|
24
|
-
else {
|
|
25
|
-
console.log('\nUse contrast audit --save to generate an SBOM');
|
|
26
|
-
}
|
|
27
21
|
const endTime = performance.now() - startTime;
|
|
28
22
|
const scanDurationMs = endTime - startTime;
|
|
29
23
|
console.log(`----- completed in ${(scanDurationMs / 1000).toFixed(2)}s -----`);
|
|
@@ -1,21 +1,60 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const projectConfig = require('../commands/github/projectGroup');
|
|
3
|
+
const repoService = require('../commands/github/repoServices');
|
|
3
4
|
const scaServicesUpload = require('../scaAnalysis/common/scaServicesUpload');
|
|
4
|
-
const
|
|
5
|
+
const dealWithNoProjectId = async (analysis, config, reportSpinner) => {
|
|
6
|
+
await projectConfig.registerNewProjectGroup(config);
|
|
7
|
+
let projectId = await projectConfig.getProjectIdByOrg(config);
|
|
8
|
+
await projectConfig.registerProjectIdOnCliServices(config, projectId);
|
|
9
|
+
config.projectId = projectId;
|
|
10
|
+
return await scaServicesUpload.scaTreeUpload(analysis, config, reportSpinner);
|
|
11
|
+
};
|
|
12
|
+
const repoProcess = async (analysis, config, reportSpinner) => {
|
|
13
|
+
if (config.debug || config.verbose) {
|
|
14
|
+
console.log('in repository process');
|
|
15
|
+
console.log('repository id: ', config.repositoryId);
|
|
16
|
+
}
|
|
17
|
+
if (config.repositoryId === '') {
|
|
18
|
+
console.log('Failed to retrieve Repository Id');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
let repoInfo = await repoService.retrieveProjectInfoViaRepoId(config);
|
|
22
|
+
repoInfo = repoInfo.find(element => config.fileName === element.path &&
|
|
23
|
+
config.fileName === element.name &&
|
|
24
|
+
config.projectGroupId === element.projectGroupId);
|
|
25
|
+
if (config.projectGroupId &&
|
|
26
|
+
!repoInfo?.projectId &&
|
|
27
|
+
(repoInfo === undefined || repoInfo.length === 0)) {
|
|
28
|
+
console.log('*** has projectGroupId, no projectId and repo has no project found that matches');
|
|
29
|
+
repoInfo = await projectConfig.registerProjectWithGroupProjectId(config);
|
|
30
|
+
console.log('new registered group', repoInfo);
|
|
31
|
+
const language = repoInfo.language === 'JAVASCRIPT' ? 'NODE' : repoInfo.language;
|
|
32
|
+
await projectConfig.registerProjectIdOnCliServices(config, repoInfo.projectId);
|
|
33
|
+
}
|
|
34
|
+
config.projectId = repoInfo.projectId;
|
|
35
|
+
return await scaServicesUpload.scaTreeUpload(analysis, config, reportSpinner);
|
|
36
|
+
};
|
|
37
|
+
const trackProcess = async (analysis, config, reportSpinner) => {
|
|
5
38
|
let projectId = await projectConfig.getProjectIdByOrg(config);
|
|
6
39
|
if (projectId === '') {
|
|
7
|
-
|
|
8
|
-
await projectConfig.registerNewProjectGroup(config);
|
|
9
|
-
projectId = await projectConfig.getProjectIdByOrg(config);
|
|
10
|
-
}
|
|
11
|
-
if (config.track === false || config.track === undefined) {
|
|
12
|
-
return await scaServicesUpload.noProjectUpload(analysis, config, reportSpinner);
|
|
13
|
-
}
|
|
40
|
+
return dealWithNoProjectId(analysis, config, reportSpinner);
|
|
14
41
|
}
|
|
15
|
-
await projectConfig.registerProjectIdOnCliServices(config, projectId);
|
|
16
42
|
config.projectId = projectId;
|
|
43
|
+
await projectConfig.registerProjectIdOnCliServices(config, projectId);
|
|
17
44
|
return await scaServicesUpload.scaTreeUpload(analysis, config, reportSpinner);
|
|
18
45
|
};
|
|
46
|
+
const processUpload = async (analysis, config, reportSpinner) => {
|
|
47
|
+
if (config.repositoryId) {
|
|
48
|
+
return repoProcess(analysis, config, reportSpinner);
|
|
49
|
+
}
|
|
50
|
+
if (config.track) {
|
|
51
|
+
return trackProcess(analysis, config, reportSpinner);
|
|
52
|
+
}
|
|
53
|
+
if (!config.track) {
|
|
54
|
+
return await scaServicesUpload.noProjectUpload(analysis, config, reportSpinner);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
19
57
|
module.exports = {
|
|
20
|
-
processUpload
|
|
58
|
+
processUpload,
|
|
59
|
+
repoProcess
|
|
21
60
|
};
|
|
@@ -56,7 +56,25 @@ const parsePomFile = jsonPomFile => {
|
|
|
56
56
|
};
|
|
57
57
|
dependencyTree[depName] = parsedDependency;
|
|
58
58
|
}
|
|
59
|
-
|
|
59
|
+
const retrieveParent = getParentDependency(jsonPomFile);
|
|
60
|
+
return {
|
|
61
|
+
parentPom: retrieveParent,
|
|
62
|
+
dependencyTree
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
const getParentDependency = jsonPomFile => {
|
|
66
|
+
let parent = {};
|
|
67
|
+
jsonPomFile.project.hasOwnProperty('parent')
|
|
68
|
+
? (parent = buildParent(jsonPomFile.project.parent))
|
|
69
|
+
: (parent = undefined);
|
|
70
|
+
return parent;
|
|
71
|
+
};
|
|
72
|
+
const buildParent = parent => {
|
|
73
|
+
return {
|
|
74
|
+
group: parent[0].groupId[0],
|
|
75
|
+
name: parent[0].artifactId[0],
|
|
76
|
+
version: parent[0].version[0]
|
|
77
|
+
};
|
|
60
78
|
};
|
|
61
79
|
const getVersion = (pomFile, dependencyWithoutVersion) => {
|
|
62
80
|
let parentVersion = pomFile.project.parent[0].version[0];
|
|
@@ -5,7 +5,6 @@ const autoDetection = require('../scan/autoDetection');
|
|
|
5
5
|
const rootFile = require('../audit/languageAnalysisEngine/getProjectRootFilenames');
|
|
6
6
|
const path = require('path');
|
|
7
7
|
const i18n = require('i18n');
|
|
8
|
-
const auditSave = require('../audit/save');
|
|
9
8
|
const { auditUsageGuide } = require('../commands/audit/help');
|
|
10
9
|
const repoMode = require('./repoMode');
|
|
11
10
|
const { dotNetAnalysis } = require('./dotnet');
|
|
@@ -27,6 +26,7 @@ const processSca = async (config) => {
|
|
|
27
26
|
console.log(auditUsageGuide);
|
|
28
27
|
process.exit(0);
|
|
29
28
|
}
|
|
29
|
+
config.repo = config.repositoryId !== undefined;
|
|
30
30
|
const projectStats = await rootFile.getProjectStats(config.file);
|
|
31
31
|
let pathWithFile = projectStats.isFile();
|
|
32
32
|
config.fileName = config.file;
|
|
@@ -34,12 +34,14 @@ const processSca = async (config) => {
|
|
|
34
34
|
? rootFile.getDirectoryFromPathGiven(config.file).concat('/')
|
|
35
35
|
: config.file;
|
|
36
36
|
filesFound = await autoDetection.autoDetectAuditFilesAndLanguages(config.file);
|
|
37
|
+
filesFound = await autoDetection.detectPackageManager(filesFound);
|
|
37
38
|
autoDetection.dealWithMultiJava(filesFound);
|
|
38
39
|
if (filesFound.length > 1 && pathWithFile) {
|
|
39
40
|
filesFound = filesFound.filter(i => Object.values(i)[0].includes(path.basename(config.fileName)));
|
|
40
41
|
}
|
|
41
42
|
let messageToSend = undefined;
|
|
42
43
|
if (filesFound.length === 1) {
|
|
44
|
+
config.packageManager = filesFound[0]?.packageManager;
|
|
43
45
|
switch (Object.keys(filesFound[0])[0]) {
|
|
44
46
|
case JAVA:
|
|
45
47
|
config.language = JAVA;
|
|
@@ -99,13 +101,7 @@ const processSca = async (config) => {
|
|
|
99
101
|
startSpinner(reportSpinner);
|
|
100
102
|
let reportResponse = await processServices.processUpload(messageToSend, config, reportSpinner);
|
|
101
103
|
const reportModelLibraryList = convertGenericToTypedReportModelSca(reportResponse.reportArray);
|
|
102
|
-
auditReport.processAuditReport(config, reportModelLibraryList);
|
|
103
|
-
if (config.save !== undefined) {
|
|
104
|
-
await auditSave.auditSave(config, reportResponse.reportId);
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
console.log('Use contrast audit --save to generate an SBOM');
|
|
108
|
-
}
|
|
104
|
+
await auditReport.processAuditReport(config, reportModelLibraryList, reportResponse.reportId);
|
|
109
105
|
succeedSpinner(reportSpinner, i18n.__('auditSCAAnalysisComplete'));
|
|
110
106
|
const endTime = performance.now() - startTime;
|
|
111
107
|
const scanDurationMs = endTime - startTime;
|
|
@@ -2,13 +2,20 @@
|
|
|
2
2
|
const i18n = require('i18n');
|
|
3
3
|
const fileFinder = require('./fileUtils');
|
|
4
4
|
const { supportedLanguages: { JAVA, GO, PYTHON, RUBY, JAVASCRIPT, NODE, PHP, DOTNET } } = require('../constants/constants');
|
|
5
|
-
const autoDetectFingerprintInfo = async (filePath, depth) => {
|
|
5
|
+
const autoDetectFingerprintInfo = async (filePath, depth, config) => {
|
|
6
6
|
let complexObj = await fileFinder.findAllFiles(filePath, depth);
|
|
7
7
|
let result = [];
|
|
8
8
|
let count = 0;
|
|
9
9
|
complexObj.forEach(i => {
|
|
10
10
|
count++;
|
|
11
|
-
|
|
11
|
+
if (!i.includes('package.json')) {
|
|
12
|
+
result.push({
|
|
13
|
+
filePath: i,
|
|
14
|
+
id: count.toString(),
|
|
15
|
+
repositoryId: config.repositoryId,
|
|
16
|
+
projectGroupId: config.projectGroupId
|
|
17
|
+
});
|
|
18
|
+
}
|
|
12
19
|
});
|
|
13
20
|
return result;
|
|
14
21
|
};
|
|
@@ -26,7 +33,7 @@ const detectPackageManager = async (array) => {
|
|
|
26
33
|
i['language'] = JAVA;
|
|
27
34
|
i['packageManager'] = 'GRADLE';
|
|
28
35
|
}
|
|
29
|
-
if (i.filePath.includes('package.json')) {
|
|
36
|
+
if (i.filePath.includes('package-lock.json')) {
|
|
30
37
|
i['language'] = JAVASCRIPT;
|
|
31
38
|
i['packageManager'] = 'NPM';
|
|
32
39
|
}
|
|
@@ -36,15 +43,19 @@ const detectPackageManager = async (array) => {
|
|
|
36
43
|
}
|
|
37
44
|
if (i.filePath.includes('Pipfile')) {
|
|
38
45
|
i['language'] = PYTHON;
|
|
46
|
+
i['packageManager'] = 'PYPI';
|
|
39
47
|
}
|
|
40
48
|
if (i.filePath.includes('csproj')) {
|
|
41
49
|
i['language'] = DOTNET;
|
|
50
|
+
i['packageManager'] = 'NUGET';
|
|
42
51
|
}
|
|
43
52
|
if (i.filePath.includes('Gemfile')) {
|
|
44
53
|
i['language'] = RUBY;
|
|
54
|
+
i['packageManager'] = 'RUBYGEMS';
|
|
45
55
|
}
|
|
46
56
|
if (i.filePath.includes('go.mod')) {
|
|
47
57
|
i['language'] = GO;
|
|
58
|
+
i['packageManager'] = 'PKG';
|
|
48
59
|
}
|
|
49
60
|
});
|
|
50
61
|
return array;
|
package/dist/scan/fileUtils.js
CHANGED
|
@@ -16,6 +16,7 @@ const findAllFiles = async (filePath, depth = 2) => {
|
|
|
16
16
|
'**/build.gradle',
|
|
17
17
|
'**/build.gradle.kts',
|
|
18
18
|
'**/package.json',
|
|
19
|
+
'**/package-lock.json',
|
|
19
20
|
'**/yarn.lock',
|
|
20
21
|
'**/Pipfile',
|
|
21
22
|
'**/*.csproj',
|
|
@@ -41,79 +42,92 @@ const findFilesJava = async (languagesFound, filePath, depth = 1) => {
|
|
|
41
42
|
cwd: filePath ? filePath : process.cwd()
|
|
42
43
|
});
|
|
43
44
|
if (result.length > 0) {
|
|
44
|
-
|
|
45
|
+
let lockFile = result.find(i => i.includes('pom') || i.includes('gradle'));
|
|
46
|
+
return languagesFound.push({
|
|
47
|
+
JAVA: result,
|
|
48
|
+
language: 'JAVA',
|
|
49
|
+
filePath: lockFile
|
|
50
|
+
});
|
|
45
51
|
}
|
|
46
52
|
return languagesFound;
|
|
47
53
|
};
|
|
48
|
-
const findFilesJavascript = async (languagesFound, filePath) => {
|
|
54
|
+
const findFilesJavascript = async (languagesFound, filePath, depth = 1) => {
|
|
49
55
|
const result = await fg(['**/package.json', '**/yarn.lock', '**/package-lock.json'], {
|
|
50
56
|
dot: false,
|
|
51
|
-
deep:
|
|
57
|
+
deep: depth,
|
|
52
58
|
onlyFiles: true,
|
|
53
59
|
cwd: filePath ? filePath : process.cwd()
|
|
54
60
|
});
|
|
55
61
|
if (result.length > 0) {
|
|
56
|
-
|
|
62
|
+
let lockFile = result.find(i => i.includes('lock'));
|
|
63
|
+
return languagesFound.push({
|
|
64
|
+
JAVASCRIPT: result,
|
|
65
|
+
language: 'JAVASCRIPT',
|
|
66
|
+
filePath: lockFile
|
|
67
|
+
});
|
|
57
68
|
}
|
|
58
69
|
return languagesFound;
|
|
59
70
|
};
|
|
60
|
-
const findFilesPython = async (languagesFound, filePath) => {
|
|
71
|
+
const findFilesPython = async (languagesFound, filePath, depth = 1) => {
|
|
61
72
|
const result = await fg(['**/Pipfile.lock', '**/Pipfile'], {
|
|
62
73
|
dot: false,
|
|
63
|
-
deep:
|
|
74
|
+
deep: depth,
|
|
64
75
|
onlyFiles: true,
|
|
65
76
|
cwd: filePath ? filePath : process.cwd()
|
|
66
77
|
});
|
|
67
78
|
if (result.length > 0) {
|
|
68
|
-
return languagesFound.push({ PYTHON: result });
|
|
79
|
+
return languagesFound.push({ PYTHON: result, filePath: 'Pipfile' });
|
|
69
80
|
}
|
|
70
81
|
return languagesFound;
|
|
71
82
|
};
|
|
72
|
-
const findFilesGo = async (languagesFound, filePath) => {
|
|
83
|
+
const findFilesGo = async (languagesFound, filePath, depth = 1) => {
|
|
73
84
|
const result = await fg(['**/go.mod'], {
|
|
74
85
|
dot: false,
|
|
75
|
-
deep:
|
|
86
|
+
deep: depth,
|
|
76
87
|
onlyFiles: true,
|
|
77
88
|
cwd: filePath ? filePath : process.cwd()
|
|
78
89
|
});
|
|
79
90
|
if (result.length > 0) {
|
|
80
|
-
return languagesFound.push({ GO: result });
|
|
91
|
+
return languagesFound.push({ GO: result, filePath: 'go.mod' });
|
|
81
92
|
}
|
|
82
93
|
return languagesFound;
|
|
83
94
|
};
|
|
84
|
-
const findFilesRuby = async (languagesFound, filePath) => {
|
|
95
|
+
const findFilesRuby = async (languagesFound, filePath, depth = 1) => {
|
|
85
96
|
const result = await fg(['**/Gemfile', '**/Gemfile.lock'], {
|
|
86
97
|
dot: false,
|
|
87
|
-
deep:
|
|
98
|
+
deep: depth,
|
|
88
99
|
onlyFiles: true,
|
|
89
100
|
cwd: filePath ? filePath : process.cwd()
|
|
90
101
|
});
|
|
91
102
|
if (result.length > 0) {
|
|
92
|
-
return languagesFound.push({ RUBY: result });
|
|
103
|
+
return languagesFound.push({ RUBY: result, filePath: 'Gemfile' });
|
|
93
104
|
}
|
|
94
105
|
return languagesFound;
|
|
95
106
|
};
|
|
96
|
-
const findFilesPhp = async (languagesFound, filePath) => {
|
|
107
|
+
const findFilesPhp = async (languagesFound, filePath, depth = 1) => {
|
|
97
108
|
const result = await fg(['**/composer.json', '**/composer.lock'], {
|
|
98
109
|
dot: false,
|
|
99
|
-
deep:
|
|
110
|
+
deep: depth,
|
|
100
111
|
onlyFiles: true,
|
|
101
112
|
cwd: filePath ? filePath : process.cwd()
|
|
102
113
|
});
|
|
103
114
|
if (result.length > 0) {
|
|
104
|
-
return languagesFound.push({ PHP: result });
|
|
115
|
+
return languagesFound.push({ PHP: result, filePath: 'composer.lock' });
|
|
105
116
|
}
|
|
106
117
|
return languagesFound;
|
|
107
118
|
};
|
|
108
|
-
const findFilesDotNet = async (languagesFound, filePath) => {
|
|
119
|
+
const findFilesDotNet = async (languagesFound, filePath, depth = 1) => {
|
|
109
120
|
const result = await fg(['**/*.csproj', '**/packages.lock.json'], {
|
|
110
121
|
dot: false,
|
|
111
|
-
deep:
|
|
122
|
+
deep: depth,
|
|
112
123
|
onlyFiles: true,
|
|
113
124
|
cwd: filePath ? filePath : process.cwd()
|
|
114
125
|
});
|
|
115
126
|
if (result.length > 0) {
|
|
116
|
-
return languagesFound.push({
|
|
127
|
+
return languagesFound.push({
|
|
128
|
+
DOTNET: result,
|
|
129
|
+
filePath: 'packages.lock.json'
|
|
130
|
+
});
|
|
117
131
|
}
|
|
118
132
|
return languagesFound;
|
|
119
133
|
};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
const commandlineAuth = require('./commandlineParams');
|
|
3
3
|
const configStoreParams = require('./configStoreParams');
|
|
4
4
|
const envVariableParams = require('./envVariableParams');
|
|
5
|
-
const { validateAuthParams } = require('../validationCheck');
|
|
5
|
+
const { validateAuthParams, validateFingerprintParams } = require('../validationCheck');
|
|
6
6
|
const i18n = require('i18n');
|
|
7
7
|
const getAuth = params => {
|
|
8
8
|
let commandLineAuthParamsAuth = commandlineAuth.getAuth(params);
|
|
@@ -22,4 +22,13 @@ const getAuth = params => {
|
|
|
22
22
|
process.exit(1);
|
|
23
23
|
}
|
|
24
24
|
};
|
|
25
|
-
|
|
25
|
+
const getFingerprint = params => {
|
|
26
|
+
if (validateFingerprintParams(params)) {
|
|
27
|
+
return params;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
console.log('missing fingerprint params please check repository-url and repository-name');
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
module.exports = { getAuth, getFingerprint };
|
|
@@ -19,8 +19,12 @@ const validateAuthParams = params => {
|
|
|
19
19
|
params.host &&
|
|
20
20
|
params.authorization);
|
|
21
21
|
};
|
|
22
|
+
const validateFingerprintParams = params => {
|
|
23
|
+
return !!(params.repositoryUrl && params.repositoryName);
|
|
24
|
+
};
|
|
22
25
|
module.exports = {
|
|
23
26
|
checkConfigHasRequiredValues: checkConfigHasRequiredValues,
|
|
24
27
|
validateAuthParams: validateAuthParams,
|
|
25
|
-
validateRequiredScanParams: validateRequiredScanParams
|
|
28
|
+
validateRequiredScanParams: validateRequiredScanParams,
|
|
29
|
+
validateFingerprintParams: validateFingerprintParams
|
|
26
30
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contrast/contrast",
|
|
3
|
-
"version": "2.0.0",
|
|
3
|
+
"version": "2.0.2-beta.0",
|
|
4
4
|
"description": "Contrast Security's command line tool",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -61,7 +61,9 @@
|
|
|
61
61
|
"cross-spawn": "^7.0.3",
|
|
62
62
|
"dotenv": "^16.0.0",
|
|
63
63
|
"fast-glob": "^3.2.11",
|
|
64
|
+
"got": "11.8.6",
|
|
64
65
|
"gradle-to-js": "^2.0.1",
|
|
66
|
+
"hpagent": "^1.2.0",
|
|
65
67
|
"i18n": "^0.15.1",
|
|
66
68
|
"js-yaml": "^4.1.0",
|
|
67
69
|
"lodash": "^4.17.21",
|
|
@@ -74,7 +76,7 @@
|
|
|
74
76
|
"string-builder": "^0.1.8",
|
|
75
77
|
"string-multiple-replace": "^1.0.5",
|
|
76
78
|
"tmp": "^0.2.1",
|
|
77
|
-
"xml2js": "^0.
|
|
79
|
+
"xml2js": "^0.5.0",
|
|
78
80
|
"yarn-lockfile": "^1.1.1"
|
|
79
81
|
},
|
|
80
82
|
"devDependencies": {
|
|
@@ -93,8 +95,9 @@
|
|
|
93
95
|
"eslint-plugin-prettier": "^4.2.1",
|
|
94
96
|
"husky": "^3.1.0",
|
|
95
97
|
"jest": "^27.5.1",
|
|
96
|
-
"jest-junit": "^
|
|
98
|
+
"jest-junit": "^16.0.0",
|
|
97
99
|
"mocha": "^10.2.0",
|
|
100
|
+
"nock": "^13.3.0",
|
|
98
101
|
"npm-license-crawler": "^0.2.1",
|
|
99
102
|
"nyc": "^15.1.0",
|
|
100
103
|
"pkg": "^5.6.0",
|
|
@@ -12,6 +12,7 @@ import chalk from 'chalk'
|
|
|
12
12
|
import * as constants from '../../constants/constants'
|
|
13
13
|
import { SeverityCountModel } from './models/severityCountModel'
|
|
14
14
|
import * as common from '../../common/fail'
|
|
15
|
+
import { auditSave } from '../save'
|
|
15
16
|
|
|
16
17
|
export function convertKeysToStandardFormat(config: any, guidance: any) {
|
|
17
18
|
let convertedGuidance = guidance
|
|
@@ -96,6 +97,12 @@ export async function vulnerabilityReportV2(config: any, reportId: string) {
|
|
|
96
97
|
: {}
|
|
97
98
|
)
|
|
98
99
|
|
|
100
|
+
if (config.save !== undefined) {
|
|
101
|
+
await auditSave(config)
|
|
102
|
+
} else {
|
|
103
|
+
console.log('\nUse contrast audit --save to generate an SBOM')
|
|
104
|
+
}
|
|
105
|
+
|
|
99
106
|
if (config.fail) {
|
|
100
107
|
common.processFail(config, output[2])
|
|
101
108
|
}
|