@cyclonedx/cdxgen 10.3.4 → 10.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -4
- package/analyzer.js +18 -18
- package/bin/cdxgen.js +79 -77
- package/bin/evinse.js +26 -26
- package/bin/repl.js +56 -62
- package/bin/verify.js +9 -9
- package/binary.js +55 -54
- package/cbomutils.js +6 -6
- package/db.js +17 -17
- package/display.js +30 -30
- package/display.test.js +2 -2
- package/docker.js +92 -89
- package/docker.test.js +30 -30
- package/envcontext.js +15 -15
- package/envcontext.test.js +1 -1
- package/evinser.js +94 -93
- package/evinser.test.js +24 -24
- package/index.js +523 -483
- package/package.json +8 -16
- package/piptree.js +6 -6
- package/postgen.js +2 -2
- package/postgen.test.js +5 -5
- package/protobom.js +37 -7
- package/protobom.test.js +6 -6
- package/server.js +16 -16
- package/types/analyzer.d.ts +7 -4
- package/types/binary.d.ts +12 -8
- package/types/cbomutils.d.ts +1 -1
- package/types/db.d.ts +23 -11
- package/types/display.d.ts +1 -1
- package/types/docker.d.ts +52 -32
- package/types/envcontext.d.ts +40 -40
- package/types/evinser.d.ts +3436 -717
- package/types/index.d.ts +66 -40
- package/types/jest.config.d.ts +2 -2
- package/types/piptree.d.ts +6 -2
- package/types/postgen.d.ts +1 -1
- package/types/protobom.d.ts +7 -3
- package/types/protobom.d.ts.map +1 -1
- package/types/server.d.ts +1 -1
- package/types/utils.d.ts +496 -302
- package/types/validator.d.ts +1 -1
- package/utils.js +742 -675
- package/utils.test.js +716 -674
- package/validator.js +20 -17
package/evinser.js
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
import { PackageURL } from "packageurl-js";
|
|
6
|
+
import { Op } from "sequelize";
|
|
7
|
+
import { findCryptoAlgos } from "./cbomutils.js";
|
|
8
|
+
import * as db from "./db.js";
|
|
1
9
|
import {
|
|
2
10
|
DEBUG_MODE,
|
|
3
11
|
collectGradleDependencies,
|
|
@@ -5,16 +13,9 @@ import {
|
|
|
5
13
|
executeAtom,
|
|
6
14
|
getAllFiles,
|
|
7
15
|
getGradleCommand,
|
|
8
|
-
getMavenCommand
|
|
16
|
+
getMavenCommand,
|
|
17
|
+
getTimestamp,
|
|
9
18
|
} from "./utils.js";
|
|
10
|
-
import { findCryptoAlgos } from "./cbomutils.js";
|
|
11
|
-
import { tmpdir } from "node:os";
|
|
12
|
-
import path from "node:path";
|
|
13
|
-
import fs from "node:fs";
|
|
14
|
-
import * as db from "./db.js";
|
|
15
|
-
import { PackageURL } from "packageurl-js";
|
|
16
|
-
import { Op } from "sequelize";
|
|
17
|
-
import process from "node:process";
|
|
18
19
|
const DB_NAME = "evinser.db";
|
|
19
20
|
const typePurlsCache = {};
|
|
20
21
|
|
|
@@ -35,11 +36,11 @@ export const prepareDB = async (options) => {
|
|
|
35
36
|
const bomJsonFile = options.input;
|
|
36
37
|
if (!fs.existsSync(bomJsonFile)) {
|
|
37
38
|
console.log(
|
|
38
|
-
"Bom file doesn't exist. Check if cdxgen was invoked with the correct type argument."
|
|
39
|
+
"Bom file doesn't exist. Check if cdxgen was invoked with the correct type argument.",
|
|
39
40
|
);
|
|
40
41
|
if (!process.env.CDXGEN_DEBUG_MODE) {
|
|
41
42
|
console.log(
|
|
42
|
-
"Set the environment variable CDXGEN_DEBUG_MODE to debug to troubleshoot the issue further."
|
|
43
|
+
"Set the environment variable CDXGEN_DEBUG_MODE to debug to troubleshoot the issue further.",
|
|
43
44
|
);
|
|
44
45
|
}
|
|
45
46
|
return;
|
|
@@ -47,14 +48,14 @@ export const prepareDB = async (options) => {
|
|
|
47
48
|
const bomJson = JSON.parse(fs.readFileSync(bomJsonFile, "utf8"));
|
|
48
49
|
if (bomJson.specVersion < 1.5) {
|
|
49
50
|
console.log(
|
|
50
|
-
"Evinse requires the input SBOM in CycloneDX 1.5 format or above. You can generate one by invoking cdxgen without any --spec-version argument."
|
|
51
|
+
"Evinse requires the input SBOM in CycloneDX 1.5 format or above. You can generate one by invoking cdxgen without any --spec-version argument.",
|
|
51
52
|
);
|
|
52
53
|
process.exit(0);
|
|
53
54
|
}
|
|
54
55
|
const components = bomJson.components || [];
|
|
55
56
|
const { sequelize, Namespaces, Usages, DataFlows } = await db.createOrLoad(
|
|
56
57
|
DB_NAME,
|
|
57
|
-
options.dbPath
|
|
58
|
+
options.dbPath,
|
|
58
59
|
);
|
|
59
60
|
let hasMavenPkgs = false;
|
|
60
61
|
// We need to slice only non-maven packages
|
|
@@ -94,13 +95,13 @@ export const catalogMavenDeps = async (
|
|
|
94
95
|
dirPath,
|
|
95
96
|
purlsJars,
|
|
96
97
|
Namespaces,
|
|
97
|
-
options = {}
|
|
98
|
+
options = {},
|
|
98
99
|
) => {
|
|
99
100
|
let jarNSMapping = undefined;
|
|
100
101
|
if (fs.existsSync(path.join(dirPath, "bom.json.map"))) {
|
|
101
102
|
try {
|
|
102
103
|
const mapData = JSON.parse(
|
|
103
|
-
fs.readFileSync(path.join(dirPath, "bom.json.map"), "utf-8")
|
|
104
|
+
fs.readFileSync(path.join(dirPath, "bom.json.map"), "utf-8"),
|
|
104
105
|
);
|
|
105
106
|
if (mapData && Object.keys(mapData).length) {
|
|
106
107
|
jarNSMapping = mapData;
|
|
@@ -117,7 +118,7 @@ export const catalogMavenDeps = async (
|
|
|
117
118
|
mavenCmd,
|
|
118
119
|
dirPath,
|
|
119
120
|
false,
|
|
120
|
-
options.withDeepJarCollector
|
|
121
|
+
options.withDeepJarCollector,
|
|
121
122
|
);
|
|
122
123
|
}
|
|
123
124
|
if (jarNSMapping) {
|
|
@@ -130,12 +131,12 @@ export const catalogMavenDeps = async (
|
|
|
130
131
|
data: JSON.stringify(
|
|
131
132
|
{
|
|
132
133
|
pom: jarNSMapping[purl].pom,
|
|
133
|
-
namespaces: jarNSMapping[purl].namespaces
|
|
134
|
+
namespaces: jarNSMapping[purl].namespaces,
|
|
134
135
|
},
|
|
135
136
|
null,
|
|
136
|
-
null
|
|
137
|
-
)
|
|
138
|
-
}
|
|
137
|
+
null,
|
|
138
|
+
),
|
|
139
|
+
},
|
|
139
140
|
});
|
|
140
141
|
}
|
|
141
142
|
}
|
|
@@ -143,7 +144,7 @@ export const catalogMavenDeps = async (
|
|
|
143
144
|
|
|
144
145
|
export const catalogGradleDeps = async (dirPath, purlsJars, Namespaces) => {
|
|
145
146
|
console.log(
|
|
146
|
-
"About to collect jar dependencies from the gradle cache. This would take a while ..."
|
|
147
|
+
"About to collect jar dependencies from the gradle cache. This would take a while ...",
|
|
147
148
|
);
|
|
148
149
|
const gradleCmd = getGradleCommand(dirPath, dirPath);
|
|
149
150
|
// collect all jars including from the cache if data-flow mode is enabled
|
|
@@ -151,7 +152,7 @@ export const catalogGradleDeps = async (dirPath, purlsJars, Namespaces) => {
|
|
|
151
152
|
gradleCmd,
|
|
152
153
|
dirPath,
|
|
153
154
|
false,
|
|
154
|
-
true
|
|
155
|
+
true,
|
|
155
156
|
);
|
|
156
157
|
if (jarNSMapping) {
|
|
157
158
|
for (const purl of Object.keys(jarNSMapping)) {
|
|
@@ -163,17 +164,17 @@ export const catalogGradleDeps = async (dirPath, purlsJars, Namespaces) => {
|
|
|
163
164
|
data: JSON.stringify(
|
|
164
165
|
{
|
|
165
166
|
pom: jarNSMapping[purl].pom,
|
|
166
|
-
namespaces: jarNSMapping[purl].namespaces
|
|
167
|
+
namespaces: jarNSMapping[purl].namespaces,
|
|
167
168
|
},
|
|
168
169
|
null,
|
|
169
|
-
null
|
|
170
|
-
)
|
|
171
|
-
}
|
|
170
|
+
null,
|
|
171
|
+
),
|
|
172
|
+
},
|
|
172
173
|
});
|
|
173
174
|
}
|
|
174
175
|
}
|
|
175
176
|
console.log(
|
|
176
|
-
"To speed up successive re-runs, pass the argument --skip-maven-collector to evinse command."
|
|
177
|
+
"To speed up successive re-runs, pass the argument --skip-maven-collector to evinse command.",
|
|
177
178
|
);
|
|
178
179
|
};
|
|
179
180
|
|
|
@@ -181,7 +182,7 @@ export const createAndStoreSlice = async (
|
|
|
181
182
|
purl,
|
|
182
183
|
purlsJars,
|
|
183
184
|
Usages,
|
|
184
|
-
options = {}
|
|
185
|
+
options = {},
|
|
185
186
|
) => {
|
|
186
187
|
const retMap = createSlice(purl, purlsJars[purl], "usages", options);
|
|
187
188
|
let sliceData = undefined;
|
|
@@ -190,8 +191,8 @@ export const createAndStoreSlice = async (
|
|
|
190
191
|
where: { purl },
|
|
191
192
|
defaults: {
|
|
192
193
|
purl,
|
|
193
|
-
data: fs.readFileSync(retMap.slicesFile, "utf-8")
|
|
194
|
-
}
|
|
194
|
+
data: fs.readFileSync(retMap.slicesFile, "utf-8"),
|
|
195
|
+
},
|
|
195
196
|
});
|
|
196
197
|
}
|
|
197
198
|
if (retMap && retMap.tempDir && retMap.tempDir.startsWith(tmpdir())) {
|
|
@@ -204,13 +205,13 @@ export const createSlice = (
|
|
|
204
205
|
purlOrLanguage,
|
|
205
206
|
filePath,
|
|
206
207
|
sliceType = "usages",
|
|
207
|
-
options = {}
|
|
208
|
+
options = {},
|
|
208
209
|
) => {
|
|
209
210
|
if (!filePath) {
|
|
210
211
|
return;
|
|
211
212
|
}
|
|
212
213
|
console.log(
|
|
213
|
-
`Create ${sliceType} slice for ${path.resolve(filePath)}. Please wait
|
|
214
|
+
`Create ${sliceType} slice for ${path.resolve(filePath)}. Please wait ...`,
|
|
214
215
|
);
|
|
215
216
|
const language = purlOrLanguage.startsWith("pkg:")
|
|
216
217
|
? purlToLanguage(purlOrLanguage, filePath)
|
|
@@ -219,7 +220,7 @@ export const createSlice = (
|
|
|
219
220
|
return undefined;
|
|
220
221
|
}
|
|
221
222
|
let sliceOutputDir = fs.mkdtempSync(
|
|
222
|
-
path.join(tmpdir(), `atom-${sliceType}-`)
|
|
223
|
+
path.join(tmpdir(), `atom-${sliceType}-`),
|
|
223
224
|
);
|
|
224
225
|
if (options && options.output) {
|
|
225
226
|
sliceOutputDir =
|
|
@@ -241,7 +242,7 @@ export const createSlice = (
|
|
|
241
242
|
"-o",
|
|
242
243
|
path.resolve(atomFile),
|
|
243
244
|
"--slice-outfile",
|
|
244
|
-
path.resolve(slicesFile)
|
|
245
|
+
path.resolve(slicesFile),
|
|
245
246
|
]);
|
|
246
247
|
// For projects with several layers, slice depth needs to be increased from the default 7 to 15 or 20
|
|
247
248
|
// This would increase the time but would yield more deeper paths
|
|
@@ -254,16 +255,16 @@ export const createSlice = (
|
|
|
254
255
|
const result = executeAtom(filePath, args);
|
|
255
256
|
if (!result || !fs.existsSync(slicesFile)) {
|
|
256
257
|
console.warn(
|
|
257
|
-
`Unable to generate ${sliceType} slice using atom. Check if this is a supported language
|
|
258
|
+
`Unable to generate ${sliceType} slice using atom. Check if this is a supported language.`,
|
|
258
259
|
);
|
|
259
260
|
console.log(
|
|
260
|
-
"Set the environment variable CDXGEN_DEBUG_MODE=debug to troubleshoot."
|
|
261
|
+
"Set the environment variable CDXGEN_DEBUG_MODE=debug to troubleshoot.",
|
|
261
262
|
);
|
|
262
263
|
}
|
|
263
264
|
return {
|
|
264
265
|
tempDir: sliceOutputDir,
|
|
265
266
|
slicesFile,
|
|
266
|
-
atomFile
|
|
267
|
+
atomFile,
|
|
267
268
|
};
|
|
268
269
|
};
|
|
269
270
|
|
|
@@ -311,13 +312,13 @@ export const initFromSbom = (components, language) => {
|
|
|
311
312
|
}
|
|
312
313
|
if (comp.evidence.occurrences) {
|
|
313
314
|
purlLocationMap[comp.purl] = new Set(
|
|
314
|
-
comp.evidence.occurrences.map((v) => v.location)
|
|
315
|
+
comp.evidence.occurrences.map((v) => v.location),
|
|
315
316
|
);
|
|
316
317
|
}
|
|
317
318
|
}
|
|
318
319
|
return {
|
|
319
320
|
purlLocationMap,
|
|
320
|
-
purlImportsMap
|
|
321
|
+
purlImportsMap,
|
|
321
322
|
};
|
|
322
323
|
};
|
|
323
324
|
|
|
@@ -356,14 +357,14 @@ export const analyzeProject = async (dbObjMap, options) => {
|
|
|
356
357
|
) {
|
|
357
358
|
reachablesSlicesFile = options.reachablesSlicesFile;
|
|
358
359
|
reachablesSlice = JSON.parse(
|
|
359
|
-
fs.readFileSync(options.reachablesSlicesFile, "utf-8")
|
|
360
|
+
fs.readFileSync(options.reachablesSlicesFile, "utf-8"),
|
|
360
361
|
);
|
|
361
362
|
} else {
|
|
362
363
|
retMap = createSlice(language, dirPath, "reachables", options);
|
|
363
364
|
if (retMap && retMap.slicesFile && fs.existsSync(retMap.slicesFile)) {
|
|
364
365
|
reachablesSlicesFile = retMap.slicesFile;
|
|
365
366
|
reachablesSlice = JSON.parse(
|
|
366
|
-
fs.readFileSync(retMap.slicesFile, "utf-8")
|
|
367
|
+
fs.readFileSync(retMap.slicesFile, "utf-8"),
|
|
367
368
|
);
|
|
368
369
|
}
|
|
369
370
|
}
|
|
@@ -393,7 +394,7 @@ export const analyzeProject = async (dbObjMap, options) => {
|
|
|
393
394
|
dbObjMap,
|
|
394
395
|
servicesMap,
|
|
395
396
|
purlLocationMap,
|
|
396
|
-
purlImportsMap
|
|
397
|
+
purlImportsMap,
|
|
397
398
|
);
|
|
398
399
|
purlLocationMap = retMap.purlLocationMap;
|
|
399
400
|
servicesMap = retMap.servicesMap;
|
|
@@ -406,7 +407,7 @@ export const analyzeProject = async (dbObjMap, options) => {
|
|
|
406
407
|
) {
|
|
407
408
|
dataFlowSlicesFile = options.dataFlowSlicesFile;
|
|
408
409
|
dataFlowSlice = JSON.parse(
|
|
409
|
-
fs.readFileSync(options.dataFlowSlicesFile, "utf-8")
|
|
410
|
+
fs.readFileSync(options.dataFlowSlicesFile, "utf-8"),
|
|
410
411
|
);
|
|
411
412
|
} else {
|
|
412
413
|
retMap = createSlice(language, dirPath, "data-flow", options);
|
|
@@ -423,7 +424,7 @@ export const analyzeProject = async (dbObjMap, options) => {
|
|
|
423
424
|
dataFlowSlice,
|
|
424
425
|
dbObjMap,
|
|
425
426
|
purlLocationMap,
|
|
426
|
-
purlImportsMap
|
|
427
|
+
purlImportsMap,
|
|
427
428
|
);
|
|
428
429
|
}
|
|
429
430
|
return {
|
|
@@ -437,7 +438,7 @@ export const analyzeProject = async (dbObjMap, options) => {
|
|
|
437
438
|
tempDir: retMap.tempDir,
|
|
438
439
|
userDefinedTypesMap,
|
|
439
440
|
cryptoComponents,
|
|
440
|
-
cryptoGeneratePurls
|
|
441
|
+
cryptoGeneratePurls,
|
|
441
442
|
};
|
|
442
443
|
};
|
|
443
444
|
|
|
@@ -447,7 +448,7 @@ export const parseObjectSlices = async (
|
|
|
447
448
|
dbObjMap,
|
|
448
449
|
servicesMap = {},
|
|
449
450
|
purlLocationMap = {},
|
|
450
|
-
purlImportsMap = {}
|
|
451
|
+
purlImportsMap = {},
|
|
451
452
|
) => {
|
|
452
453
|
if (!usageSlice || !Object.keys(usageSlice).length) {
|
|
453
454
|
return purlLocationMap;
|
|
@@ -458,7 +459,7 @@ export const parseObjectSlices = async (
|
|
|
458
459
|
});
|
|
459
460
|
for (const slice of [
|
|
460
461
|
...(usageSlice.objectSlices || []),
|
|
461
|
-
...(usageSlice.userDefinedTypes || [])
|
|
462
|
+
...(usageSlice.userDefinedTypes || []),
|
|
462
463
|
]) {
|
|
463
464
|
// Skip the library code typically without filename
|
|
464
465
|
if (
|
|
@@ -475,7 +476,7 @@ export const parseObjectSlices = async (
|
|
|
475
476
|
slice,
|
|
476
477
|
dbObjMap,
|
|
477
478
|
purlLocationMap,
|
|
478
|
-
purlImportsMap
|
|
479
|
+
purlImportsMap,
|
|
479
480
|
);
|
|
480
481
|
detectServicesFromUsages(language, slice, servicesMap);
|
|
481
482
|
}
|
|
@@ -483,7 +484,7 @@ export const parseObjectSlices = async (
|
|
|
483
484
|
return {
|
|
484
485
|
purlLocationMap,
|
|
485
486
|
servicesMap,
|
|
486
|
-
userDefinedTypesMap
|
|
487
|
+
userDefinedTypesMap,
|
|
487
488
|
};
|
|
488
489
|
};
|
|
489
490
|
|
|
@@ -505,7 +506,7 @@ export const parseSliceUsages = async (
|
|
|
505
506
|
slice,
|
|
506
507
|
dbObjMap,
|
|
507
508
|
purlLocationMap,
|
|
508
|
-
purlImportsMap
|
|
509
|
+
purlImportsMap,
|
|
509
510
|
) => {
|
|
510
511
|
const fileName = slice.fileName;
|
|
511
512
|
const typesToLookup = new Set();
|
|
@@ -530,7 +531,7 @@ export const parseSliceUsages = async (
|
|
|
530
531
|
[ausage?.targetObj?.isExternal, ausage?.targetObj?.resolvedMethod],
|
|
531
532
|
[ausage?.definedBy?.isExternal, ausage?.definedBy?.typeFullName],
|
|
532
533
|
[ausage?.definedBy?.isExternal, ausage?.definedBy?.resolvedMethod],
|
|
533
|
-
...(ausage?.fields || []).map((f) => [f?.isExternal, f?.typeFullName])
|
|
534
|
+
...(ausage?.fields || []).map((f) => [f?.isExternal, f?.typeFullName]),
|
|
534
535
|
]) {
|
|
535
536
|
if (
|
|
536
537
|
atype[0] !== false &&
|
|
@@ -545,7 +546,7 @@ export const parseSliceUsages = async (
|
|
|
545
546
|
) {
|
|
546
547
|
if (atype[1].includes(":")) {
|
|
547
548
|
typesToLookup.add(
|
|
548
|
-
simplifyType(atype[1].split("::")[0].replace(/:/g, "/"))
|
|
549
|
+
simplifyType(atype[1].split("::")[0].replace(/:/g, "/")),
|
|
549
550
|
);
|
|
550
551
|
}
|
|
551
552
|
addToOverrides(lKeyOverrides, atype[1], fileName, ausageLine);
|
|
@@ -570,7 +571,7 @@ export const parseSliceUsages = async (
|
|
|
570
571
|
lKeyOverrides,
|
|
571
572
|
acall.callName,
|
|
572
573
|
fileName,
|
|
573
|
-
acall.lineNumber
|
|
574
|
+
acall.lineNumber,
|
|
574
575
|
);
|
|
575
576
|
}
|
|
576
577
|
} else if (acall.isExternal == false) {
|
|
@@ -590,13 +591,13 @@ export const parseSliceUsages = async (
|
|
|
590
591
|
lKeyOverrides,
|
|
591
592
|
acall?.resolvedMethod,
|
|
592
593
|
fileName,
|
|
593
|
-
acall.lineNumber
|
|
594
|
+
acall.lineNumber,
|
|
594
595
|
);
|
|
595
596
|
}
|
|
596
597
|
}
|
|
597
598
|
const maybeClassType = getClassTypeFromSignature(
|
|
598
599
|
language,
|
|
599
|
-
acall?.resolvedMethod
|
|
600
|
+
acall?.resolvedMethod,
|
|
600
601
|
);
|
|
601
602
|
typesToLookup.add(maybeClassType);
|
|
602
603
|
if (acall.lineNumber) {
|
|
@@ -604,7 +605,7 @@ export const parseSliceUsages = async (
|
|
|
604
605
|
lKeyOverrides,
|
|
605
606
|
maybeClassType,
|
|
606
607
|
fileName,
|
|
607
|
-
acall.lineNumber
|
|
608
|
+
acall.lineNumber,
|
|
608
609
|
);
|
|
609
610
|
}
|
|
610
611
|
}
|
|
@@ -615,20 +616,20 @@ export const parseSliceUsages = async (
|
|
|
615
616
|
if (acall.lineNumber) {
|
|
616
617
|
if (aparamType.includes(":")) {
|
|
617
618
|
typesToLookup.add(
|
|
618
|
-
simplifyType(aparamType.split("::")[0].replace(/:/g, "/"))
|
|
619
|
+
simplifyType(aparamType.split("::")[0].replace(/:/g, "/")),
|
|
619
620
|
);
|
|
620
621
|
}
|
|
621
622
|
addToOverrides(
|
|
622
623
|
lKeyOverrides,
|
|
623
624
|
aparamType,
|
|
624
625
|
fileName,
|
|
625
|
-
acall.lineNumber
|
|
626
|
+
acall.lineNumber,
|
|
626
627
|
);
|
|
627
628
|
}
|
|
628
629
|
}
|
|
629
630
|
const maybeClassType = getClassTypeFromSignature(
|
|
630
631
|
language,
|
|
631
|
-
aparamType
|
|
632
|
+
aparamType,
|
|
632
633
|
);
|
|
633
634
|
typesToLookup.add(maybeClassType);
|
|
634
635
|
if (acall.lineNumber) {
|
|
@@ -636,7 +637,7 @@ export const parseSliceUsages = async (
|
|
|
636
637
|
lKeyOverrides,
|
|
637
638
|
maybeClassType,
|
|
638
639
|
fileName,
|
|
639
|
-
acall.lineNumber
|
|
640
|
+
acall.lineNumber,
|
|
640
641
|
);
|
|
641
642
|
}
|
|
642
643
|
}
|
|
@@ -680,9 +681,9 @@ export const parseSliceUsages = async (
|
|
|
680
681
|
attributes: ["purl"],
|
|
681
682
|
where: {
|
|
682
683
|
data: {
|
|
683
|
-
[Op.like]: `%${atype}
|
|
684
|
-
}
|
|
685
|
-
}
|
|
684
|
+
[Op.like]: `%${atype}%`,
|
|
685
|
+
},
|
|
686
|
+
},
|
|
686
687
|
});
|
|
687
688
|
}
|
|
688
689
|
if (nsHits && nsHits.length) {
|
|
@@ -706,7 +707,7 @@ export const parseSliceUsages = async (
|
|
|
706
707
|
export const isFilterableType = (
|
|
707
708
|
language,
|
|
708
709
|
userDefinedTypesMap,
|
|
709
|
-
typeFullName
|
|
710
|
+
typeFullName,
|
|
710
711
|
) => {
|
|
711
712
|
if (
|
|
712
713
|
!typeFullName ||
|
|
@@ -720,7 +721,7 @@ export const isFilterableType = (
|
|
|
720
721
|
"<unknownFullName",
|
|
721
722
|
"__builtin",
|
|
722
723
|
"LAMBDA",
|
|
723
|
-
"../"
|
|
724
|
+
"../",
|
|
724
725
|
]) {
|
|
725
726
|
if (typeFullName.startsWith(ab)) {
|
|
726
727
|
return true;
|
|
@@ -811,7 +812,7 @@ export const detectServicesFromUsages = (language, slice, servicesMap = {}) => {
|
|
|
811
812
|
if (language != "php") {
|
|
812
813
|
const tmpEndpoints = extractEndpoints(
|
|
813
814
|
language,
|
|
814
|
-
acall.resolvedMethod
|
|
815
|
+
acall.resolvedMethod,
|
|
815
816
|
);
|
|
816
817
|
if (acall.resolvedMethod.toLowerCase().includes("auth")) {
|
|
817
818
|
authenticated = true;
|
|
@@ -829,7 +830,7 @@ export const detectServicesFromUsages = (language, slice, servicesMap = {}) => {
|
|
|
829
830
|
servicesMap[serviceName] = {
|
|
830
831
|
endpoints: new Set(),
|
|
831
832
|
authenticated,
|
|
832
|
-
xTrustBoundary: authenticated === true ? true : undefined
|
|
833
|
+
xTrustBoundary: authenticated === true ? true : undefined,
|
|
833
834
|
};
|
|
834
835
|
}
|
|
835
836
|
for (const endpoint of endpoints) {
|
|
@@ -849,7 +850,7 @@ export const detectServicesFromUsages = (language, slice, servicesMap = {}) => {
|
|
|
849
850
|
export const detectServicesFromUDT = (
|
|
850
851
|
language,
|
|
851
852
|
userDefinedTypes,
|
|
852
|
-
servicesMap
|
|
853
|
+
servicesMap,
|
|
853
854
|
) => {
|
|
854
855
|
if (
|
|
855
856
|
["python", "py", "c", "cpp", "c++", "php"].includes(language) &&
|
|
@@ -885,7 +886,7 @@ export const detectServicesFromUDT = (
|
|
|
885
886
|
let serviceName = "service";
|
|
886
887
|
if (audt.fileName) {
|
|
887
888
|
serviceName = `${path.basename(
|
|
888
|
-
audt.fileName.replace(".py", "")
|
|
889
|
+
audt.fileName.replace(".py", ""),
|
|
889
890
|
)}-service`;
|
|
890
891
|
}
|
|
891
892
|
if (endpoints && endpoints.length) {
|
|
@@ -893,7 +894,7 @@ export const detectServicesFromUDT = (
|
|
|
893
894
|
servicesMap[serviceName] = {
|
|
894
895
|
endpoints: new Set(),
|
|
895
896
|
authenticated: false,
|
|
896
|
-
xTrustBoundary: undefined
|
|
897
|
+
xTrustBoundary: undefined,
|
|
897
898
|
};
|
|
898
899
|
}
|
|
899
900
|
for (const endpoint of endpoints) {
|
|
@@ -940,7 +941,7 @@ export const extractEndpoints = (language, code) => {
|
|
|
940
941
|
v.length &&
|
|
941
942
|
!v.startsWith(".") &&
|
|
942
943
|
v.includes("/") &&
|
|
943
|
-
!v.startsWith("@")
|
|
944
|
+
!v.startsWith("@"),
|
|
944
945
|
);
|
|
945
946
|
}
|
|
946
947
|
break;
|
|
@@ -959,7 +960,7 @@ export const extractEndpoints = (language, code) => {
|
|
|
959
960
|
v.includes("/") &&
|
|
960
961
|
!v.startsWith("@") &&
|
|
961
962
|
!v.startsWith("application/") &&
|
|
962
|
-
!v.startsWith("text/")
|
|
963
|
+
!v.startsWith("text/"),
|
|
963
964
|
);
|
|
964
965
|
}
|
|
965
966
|
break;
|
|
@@ -989,7 +990,7 @@ export const createEvinseFile = (sliceArtefacts, options) => {
|
|
|
989
990
|
servicesMap,
|
|
990
991
|
dataFlowFrames,
|
|
991
992
|
cryptoComponents,
|
|
992
|
-
cryptoGeneratePurls
|
|
993
|
+
cryptoGeneratePurls,
|
|
993
994
|
} = sliceArtefacts;
|
|
994
995
|
const bomFile = options.input;
|
|
995
996
|
const evinseOutFile = options.output;
|
|
@@ -1004,7 +1005,7 @@ export const createEvinseFile = (sliceArtefacts, options) => {
|
|
|
1004
1005
|
}
|
|
1005
1006
|
delete comp.signature;
|
|
1006
1007
|
const locationOccurrences = Array.from(
|
|
1007
|
-
purlLocationMap[comp.purl] || []
|
|
1008
|
+
purlLocationMap[comp.purl] || [],
|
|
1008
1009
|
).sort();
|
|
1009
1010
|
if (locationOccurrences.length) {
|
|
1010
1011
|
if (!comp.evidence) {
|
|
@@ -1015,7 +1016,7 @@ export const createEvinseFile = (sliceArtefacts, options) => {
|
|
|
1015
1016
|
comp.evidence.occurrences = locationOccurrences
|
|
1016
1017
|
.filter((l) => !!l)
|
|
1017
1018
|
.map((l) => ({
|
|
1018
|
-
location: l
|
|
1019
|
+
location: l,
|
|
1019
1020
|
}));
|
|
1020
1021
|
occEvidencePresent = true;
|
|
1021
1022
|
}
|
|
@@ -1048,7 +1049,7 @@ export const createEvinseFile = (sliceArtefacts, options) => {
|
|
|
1048
1049
|
name: serviceName,
|
|
1049
1050
|
endpoints: Array.from(servicesMap[serviceName].endpoints),
|
|
1050
1051
|
authenticated: servicesMap[serviceName].authenticated,
|
|
1051
|
-
"x-trust-boundary": servicesMap[serviceName].xTrustBoundary
|
|
1052
|
+
"x-trust-boundary": servicesMap[serviceName].xTrustBoundary,
|
|
1052
1053
|
});
|
|
1053
1054
|
}
|
|
1054
1055
|
// Add to existing services
|
|
@@ -1085,38 +1086,38 @@ export const createEvinseFile = (sliceArtefacts, options) => {
|
|
|
1085
1086
|
bomJson.annotations.push({
|
|
1086
1087
|
subjects: [bomJson.serialNumber],
|
|
1087
1088
|
annotator: { component: bomJson.metadata.tools.components[0] },
|
|
1088
|
-
timestamp:
|
|
1089
|
-
text: fs.readFileSync(usagesSlicesFile, "utf8")
|
|
1089
|
+
timestamp: getTimestamp(),
|
|
1090
|
+
text: fs.readFileSync(usagesSlicesFile, "utf8"),
|
|
1090
1091
|
});
|
|
1091
1092
|
}
|
|
1092
1093
|
if (dataFlowSlicesFile && fs.existsSync(dataFlowSlicesFile)) {
|
|
1093
1094
|
bomJson.annotations.push({
|
|
1094
1095
|
subjects: [bomJson.serialNumber],
|
|
1095
1096
|
annotator: { component: bomJson.metadata.tools.components[0] },
|
|
1096
|
-
timestamp:
|
|
1097
|
-
text: fs.readFileSync(dataFlowSlicesFile, "utf8")
|
|
1097
|
+
timestamp: getTimestamp(),
|
|
1098
|
+
text: fs.readFileSync(dataFlowSlicesFile, "utf8"),
|
|
1098
1099
|
});
|
|
1099
1100
|
}
|
|
1100
1101
|
if (reachablesSlicesFile && fs.existsSync(reachablesSlicesFile)) {
|
|
1101
1102
|
bomJson.annotations.push({
|
|
1102
1103
|
subjects: [bomJson.serialNumber],
|
|
1103
1104
|
annotator: { component: bomJson.metadata.tools.components[0] },
|
|
1104
|
-
timestamp:
|
|
1105
|
-
text: fs.readFileSync(reachablesSlicesFile, "utf8")
|
|
1105
|
+
timestamp: getTimestamp(),
|
|
1106
|
+
text: fs.readFileSync(reachablesSlicesFile, "utf8"),
|
|
1106
1107
|
});
|
|
1107
1108
|
}
|
|
1108
1109
|
}
|
|
1109
1110
|
// Increment the version
|
|
1110
1111
|
bomJson.version = (bomJson.version || 1) + 1;
|
|
1111
1112
|
// Set the current timestamp to indicate this is newer
|
|
1112
|
-
bomJson.metadata.timestamp =
|
|
1113
|
+
bomJson.metadata.timestamp = getTimestamp();
|
|
1113
1114
|
delete bomJson.signature;
|
|
1114
1115
|
fs.writeFileSync(evinseOutFile, JSON.stringify(bomJson, null, null));
|
|
1115
1116
|
if (occEvidencePresent || csEvidencePresent || servicesPresent) {
|
|
1116
1117
|
console.log(evinseOutFile, "created successfully.");
|
|
1117
1118
|
} else {
|
|
1118
1119
|
console.log(
|
|
1119
|
-
"Unable to identify component evidence for the input SBOM. Only java, javascript, python, and php projects are supported by evinse."
|
|
1120
|
+
"Unable to identify component evidence for the input SBOM. Only java, javascript, python, and php projects are supported by evinse.",
|
|
1120
1121
|
);
|
|
1121
1122
|
}
|
|
1122
1123
|
if (tempDir && tempDir.startsWith(tmpdir())) {
|
|
@@ -1142,7 +1143,7 @@ export const collectDataFlowFrames = async (
|
|
|
1142
1143
|
dataFlowSlice,
|
|
1143
1144
|
dbObjMap,
|
|
1144
1145
|
purlLocationMap,
|
|
1145
|
-
purlImportsMap
|
|
1146
|
+
purlImportsMap,
|
|
1146
1147
|
) => {
|
|
1147
1148
|
const nodes = dataFlowSlice?.graph?.nodes || [];
|
|
1148
1149
|
// Cache the nodes based on the id to improve lookup
|
|
@@ -1199,9 +1200,9 @@ export const collectDataFlowFrames = async (
|
|
|
1199
1200
|
attributes: ["purl"],
|
|
1200
1201
|
where: {
|
|
1201
1202
|
data: {
|
|
1202
|
-
[Op.like]: `%${typeFullName}
|
|
1203
|
-
}
|
|
1204
|
-
}
|
|
1203
|
+
[Op.like]: `%${typeFullName}%`,
|
|
1204
|
+
},
|
|
1205
|
+
},
|
|
1205
1206
|
});
|
|
1206
1207
|
}
|
|
1207
1208
|
if (nsHits && nsHits.length) {
|
|
@@ -1235,7 +1236,7 @@ export const collectDataFlowFrames = async (
|
|
|
1235
1236
|
function: theNode.parentMethodName || "",
|
|
1236
1237
|
line: theNode.lineNumber || undefined,
|
|
1237
1238
|
column: theNode.columnNumber || undefined,
|
|
1238
|
-
fullFilename: theNode.parentFileName || ""
|
|
1239
|
+
fullFilename: theNode.parentFileName || "",
|
|
1239
1240
|
});
|
|
1240
1241
|
}
|
|
1241
1242
|
referredPurls = Array.from(referredPurls);
|
|
@@ -1298,7 +1299,7 @@ export const collectReachableFrames = (language, reachablesSlice) => {
|
|
|
1298
1299
|
function: fnode.parentMethodName || "",
|
|
1299
1300
|
line: fnode.lineNumber || undefined,
|
|
1300
1301
|
column: fnode.columnNumber || undefined,
|
|
1301
|
-
fullFilename: fnode.parentFileName || ""
|
|
1302
|
+
fullFilename: fnode.parentFileName || "",
|
|
1302
1303
|
});
|
|
1303
1304
|
}
|
|
1304
1305
|
referredPurls = Array.from(referredPurls);
|
|
@@ -1332,14 +1333,14 @@ export const collectReachableFrames = (language, reachablesSlice) => {
|
|
|
1332
1333
|
description: algoObj.description || "",
|
|
1333
1334
|
cryptoProperties: {
|
|
1334
1335
|
assetType: "algorithm",
|
|
1335
|
-
oid: algoObj.oid
|
|
1336
|
-
}
|
|
1336
|
+
oid: algoObj.oid,
|
|
1337
|
+
},
|
|
1337
1338
|
});
|
|
1338
1339
|
}
|
|
1339
1340
|
return {
|
|
1340
1341
|
dataFlowFrames: dfFrames,
|
|
1341
1342
|
cryptoComponents,
|
|
1342
|
-
cryptoGeneratePurls
|
|
1343
|
+
cryptoGeneratePurls,
|
|
1343
1344
|
};
|
|
1344
1345
|
};
|
|
1345
1346
|
|