@cyclonedx/cdxgen 12.3.3 → 12.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 +64 -22
- package/bin/audit.js +21 -7
- package/bin/cdxgen.js +238 -116
- package/bin/convert.js +28 -13
- package/bin/hbom.js +490 -0
- package/bin/repl.js +580 -29
- package/bin/validate.js +34 -4
- package/bin/verify.js +40 -5
- package/data/README.md +298 -25
- package/data/component-tags.json +6 -0
- package/data/crypto-oid.json +16 -0
- package/data/predictive-audit-allowlist.json +11 -0
- package/data/queries-darwin.json +12 -1
- package/data/queries-win.json +7 -1
- package/data/queries.json +39 -2
- package/data/rules/ai-agent-governance.yaml +16 -0
- package/data/rules/asar-archives.yaml +150 -0
- package/data/rules/chrome-extensions.yaml +8 -0
- package/data/rules/ci-permissions.yaml +42 -18
- package/data/rules/container-risk.yaml +14 -7
- package/data/rules/dependency-sources.yaml +11 -0
- package/data/rules/hbom-compliance.yaml +325 -0
- package/data/rules/hbom-performance.yaml +307 -0
- package/data/rules/hbom-security.yaml +248 -0
- package/data/rules/host-topology.yaml +165 -0
- package/data/rules/mcp-servers.yaml +18 -3
- package/data/rules/obom-runtime.yaml +907 -22
- package/data/rules/package-integrity.yaml +14 -0
- package/data/rules/rootfs-hardening.yaml +179 -0
- package/data/rules/vscode-extensions.yaml +9 -0
- package/lib/audit/index.js +209 -8
- package/lib/audit/index.poku.js +332 -0
- package/lib/audit/reporters.js +222 -0
- package/lib/audit/targets.js +146 -1
- package/lib/audit/targets.poku.js +186 -0
- package/lib/cli/asar.poku.js +328 -0
- package/lib/cli/index.js +506 -88
- package/lib/cli/index.poku.js +1352 -212
- package/lib/evinser/evinser.js +14 -9
- package/lib/helpers/analyzer.js +1406 -29
- package/lib/helpers/analyzer.poku.js +342 -0
- package/lib/helpers/analyzerScope.js +712 -0
- package/lib/helpers/asarutils.js +1556 -0
- package/lib/helpers/asarutils.poku.js +443 -0
- package/lib/helpers/auditCategories.js +12 -0
- package/lib/helpers/auditCategories.poku.js +32 -0
- package/lib/helpers/cbomutils.js +271 -1
- package/lib/helpers/cbomutils.poku.js +248 -5
- package/lib/helpers/display.js +291 -1
- package/lib/helpers/display.poku.js +149 -0
- package/lib/helpers/evidenceUtils.js +58 -0
- package/lib/helpers/evidenceUtils.poku.js +54 -0
- package/lib/helpers/exportUtils.js +9 -0
- package/lib/helpers/gtfobins.js +142 -8
- package/lib/helpers/gtfobins.poku.js +24 -1
- package/lib/helpers/hbom.js +710 -0
- package/lib/helpers/hbom.poku.js +496 -0
- package/lib/helpers/hbomAnalysis.js +268 -0
- package/lib/helpers/hbomAnalysis.poku.js +249 -0
- package/lib/helpers/hbomLoader.js +35 -0
- package/lib/helpers/hostTopology.js +803 -0
- package/lib/helpers/hostTopology.poku.js +363 -0
- package/lib/helpers/inventoryStats.js +69 -0
- package/lib/helpers/inventoryStats.poku.js +86 -0
- package/lib/helpers/lolbas.js +19 -1
- package/lib/helpers/lolbas.poku.js +23 -0
- package/lib/helpers/osqueryTransform.js +47 -0
- package/lib/helpers/osqueryTransform.poku.js +47 -0
- package/lib/helpers/plugins.js +349 -0
- package/lib/helpers/plugins.poku.js +57 -0
- package/lib/helpers/protobom.js +156 -45
- package/lib/helpers/protobom.poku.js +140 -5
- package/lib/helpers/remote/dependency-track.js +36 -3
- package/lib/helpers/remote/dependency-track.poku.js +44 -0
- package/lib/helpers/source.js +24 -0
- package/lib/helpers/source.poku.js +32 -0
- package/lib/helpers/utils.js +1438 -93
- package/lib/helpers/utils.poku.js +846 -4
- package/lib/managers/binary.e2e.poku.js +367 -0
- package/lib/managers/binary.js +2293 -353
- package/lib/managers/binary.poku.js +1699 -1
- package/lib/managers/docker.js +201 -79
- package/lib/managers/docker.poku.js +337 -12
- package/lib/server/server.js +2 -27
- package/lib/stages/postgen/annotator.js +38 -0
- package/lib/stages/postgen/annotator.poku.js +107 -1
- package/lib/stages/postgen/auditBom.js +121 -18
- package/lib/stages/postgen/auditBom.poku.js +1366 -31
- package/lib/stages/postgen/hostTopologyAudit.poku.js +186 -0
- package/lib/stages/postgen/postgen.js +192 -1
- package/lib/stages/postgen/postgen.poku.js +321 -0
- package/lib/stages/postgen/ruleEngine.js +116 -0
- package/lib/stages/pregen/envAudit.js +14 -3
- package/package.json +23 -21
- package/types/bin/hbom.d.ts +3 -0
- package/types/bin/hbom.d.ts.map +1 -0
- package/types/bin/repl.d.ts.map +1 -1
- package/types/lib/audit/index.d.ts +44 -0
- package/types/lib/audit/index.d.ts.map +1 -1
- package/types/lib/audit/reporters.d.ts +16 -0
- package/types/lib/audit/reporters.d.ts.map +1 -1
- package/types/lib/audit/targets.d.ts.map +1 -1
- package/types/lib/cli/index.d.ts +16 -0
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/evinser/evinser.d.ts +4 -0
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/helpers/analyzer.d.ts +33 -0
- package/types/lib/helpers/analyzer.d.ts.map +1 -1
- package/types/lib/helpers/analyzerScope.d.ts +11 -0
- package/types/lib/helpers/analyzerScope.d.ts.map +1 -0
- package/types/lib/helpers/asarutils.d.ts +34 -0
- package/types/lib/helpers/asarutils.d.ts.map +1 -0
- package/types/lib/helpers/auditCategories.d.ts +5 -0
- package/types/lib/helpers/auditCategories.d.ts.map +1 -1
- package/types/lib/helpers/cbomutils.d.ts +3 -2
- package/types/lib/helpers/cbomutils.d.ts.map +1 -1
- package/types/lib/helpers/display.d.ts.map +1 -1
- package/types/lib/helpers/evidenceUtils.d.ts +8 -0
- package/types/lib/helpers/evidenceUtils.d.ts.map +1 -0
- package/types/lib/helpers/exportUtils.d.ts.map +1 -1
- package/types/lib/helpers/gtfobins.d.ts +8 -0
- package/types/lib/helpers/gtfobins.d.ts.map +1 -1
- package/types/lib/helpers/hbom.d.ts +49 -0
- package/types/lib/helpers/hbom.d.ts.map +1 -0
- package/types/lib/helpers/hbomAnalysis.d.ts +62 -0
- package/types/lib/helpers/hbomAnalysis.d.ts.map +1 -0
- package/types/lib/helpers/hbomLoader.d.ts +7 -0
- package/types/lib/helpers/hbomLoader.d.ts.map +1 -0
- package/types/lib/helpers/hostTopology.d.ts +12 -0
- package/types/lib/helpers/hostTopology.d.ts.map +1 -0
- package/types/lib/helpers/inventoryStats.d.ts +11 -0
- package/types/lib/helpers/inventoryStats.d.ts.map +1 -0
- package/types/lib/helpers/lolbas.d.ts.map +1 -1
- package/types/lib/helpers/osqueryTransform.d.ts +3 -0
- package/types/lib/helpers/osqueryTransform.d.ts.map +1 -1
- package/types/lib/helpers/plugins.d.ts +58 -0
- package/types/lib/helpers/plugins.d.ts.map +1 -0
- package/types/lib/helpers/protobom.d.ts +3 -4
- package/types/lib/helpers/protobom.d.ts.map +1 -1
- package/types/lib/helpers/remote/dependency-track.d.ts +10 -3
- package/types/lib/helpers/remote/dependency-track.d.ts.map +1 -1
- package/types/lib/helpers/source.d.ts.map +1 -1
- package/types/lib/helpers/utils.d.ts +45 -8
- package/types/lib/helpers/utils.d.ts.map +1 -1
- package/types/lib/managers/binary.d.ts +5 -0
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/server/server.d.ts +2 -1
- package/types/lib/server/server.d.ts.map +1 -1
- package/types/lib/stages/postgen/annotator.d.ts.map +1 -1
- package/types/lib/stages/postgen/auditBom.d.ts +26 -1
- package/types/lib/stages/postgen/auditBom.d.ts.map +1 -1
- package/types/lib/stages/postgen/postgen.d.ts +2 -1
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
- package/types/lib/stages/pregen/envAudit.d.ts.map +1 -1
- package/data/spdx-model-v3.0.1.jsonld +0 -15999
|
@@ -241,6 +241,280 @@ it("postProcess passes formulationList from bomNSData into the formulation secti
|
|
|
241
241
|
);
|
|
242
242
|
});
|
|
243
243
|
|
|
244
|
+
it("postProcess downgrades certificate crypto properties for spec version 1.6", () => {
|
|
245
|
+
const bomNSData = {
|
|
246
|
+
bomJson: {
|
|
247
|
+
bomFormat: "CycloneDX",
|
|
248
|
+
specVersion: "1.6",
|
|
249
|
+
components: [
|
|
250
|
+
{
|
|
251
|
+
type: "cryptographic-asset",
|
|
252
|
+
name: "demo-cert",
|
|
253
|
+
cryptoProperties: {
|
|
254
|
+
assetType: "certificate",
|
|
255
|
+
certificateProperties: {
|
|
256
|
+
serialNumber: "1234",
|
|
257
|
+
subjectName: "CN=demo",
|
|
258
|
+
issuerName: "CN=demo",
|
|
259
|
+
notValidBefore: "2024-01-01T00:00:00.000Z",
|
|
260
|
+
notValidAfter: "2034-01-01T00:00:00.000Z",
|
|
261
|
+
certificateFormat: "X.509",
|
|
262
|
+
certificateFileExtension: "crt",
|
|
263
|
+
fingerprint: { alg: "SHA-1", content: "a".repeat(40) },
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
],
|
|
268
|
+
dependencies: [],
|
|
269
|
+
formulation: [
|
|
270
|
+
{
|
|
271
|
+
components: [
|
|
272
|
+
{
|
|
273
|
+
type: "cryptographic-asset",
|
|
274
|
+
name: "formulation-cert",
|
|
275
|
+
cryptoProperties: {
|
|
276
|
+
assetType: "certificate",
|
|
277
|
+
certificateProperties: {
|
|
278
|
+
serialNumber: "5678",
|
|
279
|
+
subjectName: "CN=formulation",
|
|
280
|
+
certificateFileExtension: "pem",
|
|
281
|
+
fingerprint: { alg: "SHA-1", content: "b".repeat(40) },
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
],
|
|
286
|
+
},
|
|
287
|
+
],
|
|
288
|
+
metadata: {
|
|
289
|
+
properties: [],
|
|
290
|
+
tools: {
|
|
291
|
+
components: [{ name: "cdxgen" }],
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
};
|
|
296
|
+
const result = postProcess(bomNSData, { specVersion: 1.6 });
|
|
297
|
+
const componentCert =
|
|
298
|
+
result.bomJson.components[0].cryptoProperties.certificateProperties;
|
|
299
|
+
const formulationCert =
|
|
300
|
+
result.bomJson.formulation[0].components[0].cryptoProperties
|
|
301
|
+
.certificateProperties;
|
|
302
|
+
|
|
303
|
+
assert.deepStrictEqual(componentCert, {
|
|
304
|
+
subjectName: "CN=demo",
|
|
305
|
+
issuerName: "CN=demo",
|
|
306
|
+
notValidBefore: "2024-01-01T00:00:00.000Z",
|
|
307
|
+
notValidAfter: "2034-01-01T00:00:00.000Z",
|
|
308
|
+
certificateFormat: "X.509",
|
|
309
|
+
certificateExtension: "crt",
|
|
310
|
+
});
|
|
311
|
+
assert.deepStrictEqual(formulationCert, {
|
|
312
|
+
subjectName: "CN=formulation",
|
|
313
|
+
certificateExtension: "pem",
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
it("postProcess removes remaining 1.7-only fields from metadata, components, and formulation inventories for spec version 1.6", () => {
|
|
318
|
+
const bomNSData = {
|
|
319
|
+
bomJson: {
|
|
320
|
+
bomFormat: "CycloneDX",
|
|
321
|
+
specVersion: "1.6",
|
|
322
|
+
components: [
|
|
323
|
+
{
|
|
324
|
+
type: "library",
|
|
325
|
+
name: "demo-lib",
|
|
326
|
+
version: "1.0.0",
|
|
327
|
+
isExternal: true,
|
|
328
|
+
patentAssertions: [{ patentNumber: "US-123" }],
|
|
329
|
+
versionRange: "vers:npm/>=1.0.0|<2.0.0",
|
|
330
|
+
},
|
|
331
|
+
],
|
|
332
|
+
dependencies: [],
|
|
333
|
+
formulation: [
|
|
334
|
+
{
|
|
335
|
+
components: [
|
|
336
|
+
{
|
|
337
|
+
type: "library",
|
|
338
|
+
name: "formulation-lib",
|
|
339
|
+
version: "2.0.0",
|
|
340
|
+
isExternal: true,
|
|
341
|
+
versionRange: "vers:npm/>=2.0.0|<3.0.0",
|
|
342
|
+
},
|
|
343
|
+
],
|
|
344
|
+
services: [
|
|
345
|
+
{
|
|
346
|
+
name: "formulation-service",
|
|
347
|
+
patentAssertions: [{ patentNumber: "US-456" }],
|
|
348
|
+
},
|
|
349
|
+
],
|
|
350
|
+
},
|
|
351
|
+
],
|
|
352
|
+
metadata: {
|
|
353
|
+
distributionConstraints: { tlp: "GREEN" },
|
|
354
|
+
component: {
|
|
355
|
+
type: "application",
|
|
356
|
+
name: "demo-app",
|
|
357
|
+
version: "1.0.0",
|
|
358
|
+
isExternal: true,
|
|
359
|
+
versionRange: "vers:npm/>=1.0.0|<2.0.0",
|
|
360
|
+
},
|
|
361
|
+
properties: [],
|
|
362
|
+
tools: {
|
|
363
|
+
components: [{ name: "cdxgen" }],
|
|
364
|
+
},
|
|
365
|
+
},
|
|
366
|
+
services: [
|
|
367
|
+
{
|
|
368
|
+
name: "demo-service",
|
|
369
|
+
patentAssertions: [{ patentNumber: "US-789" }],
|
|
370
|
+
},
|
|
371
|
+
],
|
|
372
|
+
},
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
const result = postProcess(bomNSData, { specVersion: 1.6 });
|
|
376
|
+
const rootComponent = result.bomJson.components[0];
|
|
377
|
+
const formulationComponent = result.bomJson.formulation[0].components[0];
|
|
378
|
+
const rootService = result.bomJson.services[0];
|
|
379
|
+
const formulationService = result.bomJson.formulation[0].services[0];
|
|
380
|
+
const metadataComponent = result.bomJson.metadata.component;
|
|
381
|
+
|
|
382
|
+
assert.strictEqual(
|
|
383
|
+
result.bomJson.metadata.distributionConstraints,
|
|
384
|
+
undefined,
|
|
385
|
+
);
|
|
386
|
+
assert.strictEqual(rootComponent.isExternal, undefined);
|
|
387
|
+
assert.strictEqual(rootComponent.patentAssertions, undefined);
|
|
388
|
+
assert.strictEqual(rootComponent.versionRange, undefined);
|
|
389
|
+
assert.strictEqual(formulationComponent.isExternal, undefined);
|
|
390
|
+
assert.strictEqual(formulationComponent.versionRange, undefined);
|
|
391
|
+
assert.strictEqual(rootService.patentAssertions, undefined);
|
|
392
|
+
assert.strictEqual(formulationService.patentAssertions, undefined);
|
|
393
|
+
assert.strictEqual(metadataComponent.isExternal, undefined);
|
|
394
|
+
assert.strictEqual(metadataComponent.versionRange, undefined);
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
it("postProcess removes remaining 1.6-only fields from metadata, components, and formulation inventories for spec version 1.5", () => {
|
|
398
|
+
const bomNSData = {
|
|
399
|
+
bomJson: {
|
|
400
|
+
bomFormat: "CycloneDX",
|
|
401
|
+
specVersion: "1.5",
|
|
402
|
+
components: [
|
|
403
|
+
{
|
|
404
|
+
type: "library",
|
|
405
|
+
name: "demo-lib",
|
|
406
|
+
version: "1.0.0",
|
|
407
|
+
authors: [{ name: "Alice" }],
|
|
408
|
+
manufacturer: { name: "Acme" },
|
|
409
|
+
omniborId: ["gitoid:blob:sha1:abc"],
|
|
410
|
+
swhid: ["swh:1:rev:def"],
|
|
411
|
+
tags: ["demo"],
|
|
412
|
+
},
|
|
413
|
+
],
|
|
414
|
+
dependencies: [],
|
|
415
|
+
formulation: [
|
|
416
|
+
{
|
|
417
|
+
components: [
|
|
418
|
+
{
|
|
419
|
+
type: "library",
|
|
420
|
+
name: "formulation-lib",
|
|
421
|
+
version: "2.0.0",
|
|
422
|
+
authors: [{ name: "Bob" }],
|
|
423
|
+
manufacturer: { name: "Builder" },
|
|
424
|
+
omniborId: ["gitoid:blob:sha1:ghi"],
|
|
425
|
+
swhid: ["swh:1:dir:jkl"],
|
|
426
|
+
tags: ["workflow"],
|
|
427
|
+
},
|
|
428
|
+
],
|
|
429
|
+
services: [
|
|
430
|
+
{
|
|
431
|
+
name: "formulation-service",
|
|
432
|
+
tags: ["ci"],
|
|
433
|
+
},
|
|
434
|
+
],
|
|
435
|
+
},
|
|
436
|
+
],
|
|
437
|
+
metadata: {
|
|
438
|
+
manufacturer: { name: "BOM Factory" },
|
|
439
|
+
component: {
|
|
440
|
+
type: "application",
|
|
441
|
+
name: "demo-app",
|
|
442
|
+
version: "1.0.0",
|
|
443
|
+
authors: [{ name: "Carol" }],
|
|
444
|
+
manufacturer: { name: "Acme" },
|
|
445
|
+
tags: ["root"],
|
|
446
|
+
},
|
|
447
|
+
properties: [],
|
|
448
|
+
},
|
|
449
|
+
services: [
|
|
450
|
+
{
|
|
451
|
+
name: "demo-service",
|
|
452
|
+
tags: ["runtime"],
|
|
453
|
+
},
|
|
454
|
+
],
|
|
455
|
+
},
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
const result = postProcess(bomNSData, { specVersion: 1.5 });
|
|
459
|
+
const rootComponent = result.bomJson.components[0];
|
|
460
|
+
const formulationComponent = result.bomJson.formulation[0].components[0];
|
|
461
|
+
const rootService = result.bomJson.services[0];
|
|
462
|
+
const formulationService = result.bomJson.formulation[0].services[0];
|
|
463
|
+
const metadataComponent = result.bomJson.metadata.component;
|
|
464
|
+
|
|
465
|
+
assert.strictEqual(result.bomJson.metadata.manufacturer, undefined);
|
|
466
|
+
assert.strictEqual(rootComponent.authors, undefined);
|
|
467
|
+
assert.strictEqual(rootComponent.manufacturer, undefined);
|
|
468
|
+
assert.strictEqual(rootComponent.omniborId, undefined);
|
|
469
|
+
assert.strictEqual(rootComponent.swhid, undefined);
|
|
470
|
+
assert.strictEqual(rootComponent.tags, undefined);
|
|
471
|
+
assert.strictEqual(formulationComponent.authors, undefined);
|
|
472
|
+
assert.strictEqual(formulationComponent.manufacturer, undefined);
|
|
473
|
+
assert.strictEqual(formulationComponent.omniborId, undefined);
|
|
474
|
+
assert.strictEqual(formulationComponent.swhid, undefined);
|
|
475
|
+
assert.strictEqual(formulationComponent.tags, undefined);
|
|
476
|
+
assert.strictEqual(rootService.tags, undefined);
|
|
477
|
+
assert.strictEqual(formulationService.tags, undefined);
|
|
478
|
+
assert.strictEqual(metadataComponent.authors, undefined);
|
|
479
|
+
assert.strictEqual(metadataComponent.manufacturer, undefined);
|
|
480
|
+
assert.strictEqual(metadataComponent.tags, undefined);
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
it("postProcess removes unsupported evidence occurrence details for spec version 1.5", () => {
|
|
484
|
+
const bomNSData = {
|
|
485
|
+
bomJson: {
|
|
486
|
+
bomFormat: "CycloneDX",
|
|
487
|
+
specVersion: "1.5",
|
|
488
|
+
components: [
|
|
489
|
+
{
|
|
490
|
+
type: "file",
|
|
491
|
+
name: "deviceTypeManager.js",
|
|
492
|
+
evidence: {
|
|
493
|
+
occurrences: [
|
|
494
|
+
{
|
|
495
|
+
location: "source/microservices/lib/deviceTypeManager.js",
|
|
496
|
+
line: 11,
|
|
497
|
+
offset: 2,
|
|
498
|
+
symbol: "deviceTypeManager",
|
|
499
|
+
additionalContext: "source-import",
|
|
500
|
+
},
|
|
501
|
+
],
|
|
502
|
+
},
|
|
503
|
+
},
|
|
504
|
+
],
|
|
505
|
+
dependencies: [],
|
|
506
|
+
metadata: { properties: [] },
|
|
507
|
+
},
|
|
508
|
+
};
|
|
509
|
+
const result = postProcess(bomNSData, { specVersion: 1.5 });
|
|
510
|
+
|
|
511
|
+
assert.deepStrictEqual(result.bomJson.components[0].evidence.occurrences, [
|
|
512
|
+
{
|
|
513
|
+
location: "source/microservices/lib/deviceTypeManager.js",
|
|
514
|
+
},
|
|
515
|
+
]);
|
|
516
|
+
});
|
|
517
|
+
|
|
244
518
|
it("postProcess merges formulation-discovered MCP config services into bomJson.services", () => {
|
|
245
519
|
const tmpDir = join(tmpdir(), `cdxgen-postgen-${Date.now()}`);
|
|
246
520
|
mkdirSync(join(tmpDir, ".vscode"), { recursive: true });
|
|
@@ -372,6 +646,53 @@ it("postProcess attaches releaseNotes to cdxgen metadata tool component", () =>
|
|
|
372
646
|
}
|
|
373
647
|
});
|
|
374
648
|
|
|
649
|
+
it("postProcess refreshes unpackaged native file inventory counts from the final BOM", () => {
|
|
650
|
+
const bomNSData = {
|
|
651
|
+
bomJson: {
|
|
652
|
+
bomFormat: "CycloneDX",
|
|
653
|
+
specVersion: "1.7",
|
|
654
|
+
components: [
|
|
655
|
+
{
|
|
656
|
+
name: "demo",
|
|
657
|
+
type: "file",
|
|
658
|
+
properties: [{ name: "internal:is_executable", value: "true" }],
|
|
659
|
+
},
|
|
660
|
+
{
|
|
661
|
+
name: "libdemo.so",
|
|
662
|
+
type: "file",
|
|
663
|
+
properties: [{ name: "internal:is_shared_library", value: "true" }],
|
|
664
|
+
},
|
|
665
|
+
],
|
|
666
|
+
dependencies: [],
|
|
667
|
+
metadata: {
|
|
668
|
+
properties: [
|
|
669
|
+
{ name: "cdx:container:unpackagedExecutableCount", value: "0" },
|
|
670
|
+
{
|
|
671
|
+
name: "cdx:container:unpackagedSharedLibraryCount",
|
|
672
|
+
value: "0",
|
|
673
|
+
},
|
|
674
|
+
],
|
|
675
|
+
tools: {
|
|
676
|
+
components: [
|
|
677
|
+
{ group: "@cyclonedx", name: "cdxgen", version: "test" },
|
|
678
|
+
],
|
|
679
|
+
},
|
|
680
|
+
},
|
|
681
|
+
},
|
|
682
|
+
};
|
|
683
|
+
|
|
684
|
+
const result = postProcess(bomNSData, { specVersion: 1.7 });
|
|
685
|
+
assert.deepStrictEqual(
|
|
686
|
+
result.bomJson.metadata.properties.filter((property) =>
|
|
687
|
+
property.name.startsWith("cdx:container:unpackaged"),
|
|
688
|
+
),
|
|
689
|
+
[
|
|
690
|
+
{ name: "cdx:container:unpackagedExecutableCount", value: "1" },
|
|
691
|
+
{ name: "cdx:container:unpackagedSharedLibraryCount", value: "1" },
|
|
692
|
+
],
|
|
693
|
+
);
|
|
694
|
+
});
|
|
695
|
+
|
|
375
696
|
it("postProcess fails for weak TLP when sensitive property values are present", () => {
|
|
376
697
|
const bomNSData = {
|
|
377
698
|
bomJson: {
|
|
@@ -136,6 +136,24 @@ function normalizeStandardsMetadata(rule) {
|
|
|
136
136
|
return Object.keys(normalized).length ? normalized : undefined;
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
function normalizeDryRunSupport(rule) {
|
|
140
|
+
const rawValue =
|
|
141
|
+
typeof rule?.["dry-run-support"] === "string"
|
|
142
|
+
? rule["dry-run-support"]
|
|
143
|
+
: typeof rule?.dryRunSupport === "string"
|
|
144
|
+
? rule.dryRunSupport
|
|
145
|
+
: undefined;
|
|
146
|
+
if (rawValue !== undefined && !["no", "partial", "full"].includes(rawValue)) {
|
|
147
|
+
if (DEBUG_MODE) {
|
|
148
|
+
console.warn(
|
|
149
|
+
`Rule ${rule?.id || "unknown"} has invalid dry-run-support '${rawValue}'; defaulting to 'partial'`,
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
return "partial";
|
|
153
|
+
}
|
|
154
|
+
return ["no", "partial", "full"].includes(rawValue) ? rawValue : "partial";
|
|
155
|
+
}
|
|
156
|
+
|
|
139
157
|
/**
|
|
140
158
|
* Helper: Check if property exists and equals expected value
|
|
141
159
|
* Usage: $hasProp(component, 'cdx:foo', 'bar')
|
|
@@ -247,6 +265,103 @@ function registerCdxHelpers(expression) {
|
|
|
247
265
|
expression.registerFunction("safeStr", (val) => {
|
|
248
266
|
return val === null || val === undefined ? "" : String(val).trim();
|
|
249
267
|
});
|
|
268
|
+
expression.registerFunction("parseSizeBytes", (val) => {
|
|
269
|
+
if (val === null || val === undefined || val === "") {
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
if (typeof val === "number") {
|
|
273
|
+
return Number.isFinite(val) ? val : null;
|
|
274
|
+
}
|
|
275
|
+
const normalizedValue = String(val).trim();
|
|
276
|
+
if (!normalizedValue) {
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
const matchedValue = normalizedValue.match(
|
|
280
|
+
/^(\d+(?:\.\d+)?)\s*([kmgtpe]?i?b)?$/iu,
|
|
281
|
+
);
|
|
282
|
+
if (!matchedValue) {
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
const numericValue = Number.parseFloat(matchedValue[1]);
|
|
286
|
+
if (!Number.isFinite(numericValue)) {
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
const unit = (matchedValue[2] || "").toLowerCase();
|
|
290
|
+
const unitMap = {
|
|
291
|
+
b: 1,
|
|
292
|
+
kb: 1000,
|
|
293
|
+
kib: 1024,
|
|
294
|
+
mb: 1000 ** 2,
|
|
295
|
+
mib: 1024 ** 2,
|
|
296
|
+
gb: 1000 ** 3,
|
|
297
|
+
gib: 1024 ** 3,
|
|
298
|
+
tb: 1000 ** 4,
|
|
299
|
+
tib: 1024 ** 4,
|
|
300
|
+
pb: 1000 ** 5,
|
|
301
|
+
pib: 1024 ** 5,
|
|
302
|
+
eb: 1000 ** 6,
|
|
303
|
+
eib: 1024 ** 6,
|
|
304
|
+
};
|
|
305
|
+
const multiplier = unitMap[unit || "b"];
|
|
306
|
+
if (!multiplier) {
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
return numericValue * multiplier;
|
|
310
|
+
});
|
|
311
|
+
expression.registerFunction("firstNonEmpty", (...values) => {
|
|
312
|
+
for (const value of values) {
|
|
313
|
+
if (value === null || value === undefined) {
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
if (Array.isArray(value)) {
|
|
317
|
+
const candidate = value
|
|
318
|
+
.map((entry) =>
|
|
319
|
+
entry === null || entry === undefined ? "" : String(entry).trim(),
|
|
320
|
+
)
|
|
321
|
+
.filter(Boolean)
|
|
322
|
+
.join(", ");
|
|
323
|
+
if (candidate) {
|
|
324
|
+
return candidate;
|
|
325
|
+
}
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
const candidate = String(value).trim();
|
|
329
|
+
if (candidate) {
|
|
330
|
+
return candidate;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return "";
|
|
334
|
+
});
|
|
335
|
+
expression.registerFunction("isDarwinSystemPath", (value) => {
|
|
336
|
+
if (typeof value !== "string") {
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
const normalized = value.trim();
|
|
340
|
+
return (
|
|
341
|
+
normalized.startsWith("/bin/") ||
|
|
342
|
+
normalized.startsWith("/sbin/") ||
|
|
343
|
+
normalized.startsWith("/System/") ||
|
|
344
|
+
normalized.startsWith("/usr/bin/") ||
|
|
345
|
+
normalized.startsWith("/usr/libexec/") ||
|
|
346
|
+
normalized.startsWith("/usr/sbin/") ||
|
|
347
|
+
normalized.startsWith("/Library/Apple/System/") ||
|
|
348
|
+
normalized.startsWith("/System/Volumes/Preboot/Cryptexes/")
|
|
349
|
+
);
|
|
350
|
+
});
|
|
351
|
+
expression.registerFunction("isWindowsUserControlledPath", (value) => {
|
|
352
|
+
if (typeof value !== "string") {
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
const normalized = value.trim().replaceAll("/", "\\").toLowerCase();
|
|
356
|
+
return (
|
|
357
|
+
normalized.includes("\\users\\") ||
|
|
358
|
+
normalized.includes("\\programdata\\") ||
|
|
359
|
+
normalized.includes("\\appdata\\") ||
|
|
360
|
+
normalized.includes("\\downloads\\") ||
|
|
361
|
+
normalized.includes("\\desktop\\") ||
|
|
362
|
+
normalized.includes("\\temp\\")
|
|
363
|
+
);
|
|
364
|
+
});
|
|
250
365
|
expression.registerFunction("auditComponents", (bomJson) =>
|
|
251
366
|
getAuditComponents(bomJson),
|
|
252
367
|
);
|
|
@@ -331,6 +446,7 @@ export async function loadRules(rulesDir) {
|
|
|
331
446
|
}
|
|
332
447
|
rule.severity = rule.severity || "medium";
|
|
333
448
|
rule.category = rule.category || "unknown";
|
|
449
|
+
rule.dryRunSupport = normalizeDryRunSupport(rule);
|
|
334
450
|
const attack = normalizeAttackMetadata(rule);
|
|
335
451
|
if (attack.tactics.length || attack.techniques.length) {
|
|
336
452
|
rule.attack = attack;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import process from "node:process";
|
|
2
2
|
|
|
3
|
+
import { recordEnvironmentRead } from "../../helpers/utils.js";
|
|
4
|
+
|
|
3
5
|
const PERMISSION_FLAGS = [
|
|
4
6
|
"--permission",
|
|
5
7
|
"--allow-fs-read",
|
|
@@ -57,8 +59,13 @@ const PERMISSION_FLAG_PATTERNS = PERMISSION_FLAGS.map(
|
|
|
57
59
|
|
|
58
60
|
export function auditEnvironment(env = process.env) {
|
|
59
61
|
const findings = [];
|
|
60
|
-
const
|
|
61
|
-
const
|
|
62
|
+
const envSource = env === process.env ? "process.env" : "env";
|
|
63
|
+
const readEnv = (varName) => {
|
|
64
|
+
recordEnvironmentRead(varName, { source: envSource });
|
|
65
|
+
return env[varName];
|
|
66
|
+
};
|
|
67
|
+
const nodeOptions = readEnv("NODE_OPTIONS") || "";
|
|
68
|
+
const cdxgenNodeOptions = readEnv("CDXGEN_NODE_OPTIONS") || "";
|
|
62
69
|
const hasPermission = PERMISSION_FLAG_PATTERNS.some((re) =>
|
|
63
70
|
re.test(nodeOptions),
|
|
64
71
|
);
|
|
@@ -93,7 +100,7 @@ export function auditEnvironment(env = process.env) {
|
|
|
93
100
|
});
|
|
94
101
|
}
|
|
95
102
|
// NODE_TLS_REJECT_UNAUTHORIZED=0 disables TLS verification; any other value is benign.
|
|
96
|
-
if (
|
|
103
|
+
if (readEnv("NODE_TLS_REJECT_UNAUTHORIZED") === "0") {
|
|
97
104
|
findings.push({
|
|
98
105
|
type: "environment-variable",
|
|
99
106
|
variable: "NODE_TLS_REJECT_UNAUTHORIZED",
|
|
@@ -107,6 +114,7 @@ export function auditEnvironment(env = process.env) {
|
|
|
107
114
|
|
|
108
115
|
for (const varName of RISKY_PRESENCE_VARS) {
|
|
109
116
|
if (env[varName] != null && env[varName] !== "") {
|
|
117
|
+
recordEnvironmentRead(varName, { source: envSource });
|
|
110
118
|
const messages = {
|
|
111
119
|
NODE_PATH:
|
|
112
120
|
"NODE_PATH is set and may cause unexpected modules to be loaded, enabling module-resolution poisoning.",
|
|
@@ -166,6 +174,7 @@ export function auditEnvironment(env = process.env) {
|
|
|
166
174
|
"JDK_JAVA_OPTIONS",
|
|
167
175
|
]) {
|
|
168
176
|
const jvmOptions = env[jvmVar] || "";
|
|
177
|
+
recordEnvironmentRead(jvmVar, { source: envSource });
|
|
169
178
|
if (jvmOptions) {
|
|
170
179
|
for (const pattern of JVM_CODE_EXECUTION_PATTERNS) {
|
|
171
180
|
if (pattern.test(jvmOptions)) {
|
|
@@ -184,6 +193,7 @@ export function auditEnvironment(env = process.env) {
|
|
|
184
193
|
// Proxy interception — informational
|
|
185
194
|
const activeProxy = PROXY_VARS.find((v) => env[v] != null && env[v] !== "");
|
|
186
195
|
if (activeProxy) {
|
|
196
|
+
recordEnvironmentRead(activeProxy, { source: envSource });
|
|
187
197
|
findings.push({
|
|
188
198
|
type: "network-interception",
|
|
189
199
|
variable: activeProxy,
|
|
@@ -197,6 +207,7 @@ export function auditEnvironment(env = process.env) {
|
|
|
197
207
|
// Credential exposure — detect any env var whose name follows a credential-naming convention.
|
|
198
208
|
for (const [varName, varValue] of Object.entries(env)) {
|
|
199
209
|
if (varValue && CREDENTIAL_VAR_PATTERN.test(varName)) {
|
|
210
|
+
recordEnvironmentRead(varName, { source: envSource });
|
|
200
211
|
findings.push({
|
|
201
212
|
type: "credential-exposure",
|
|
202
213
|
variable: varName,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyclonedx/cdxgen",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.4.0",
|
|
4
4
|
"description": "Creates CycloneDX Software Bill of Materials (SBOM) from source or container image",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sbom",
|
|
@@ -91,6 +91,7 @@
|
|
|
91
91
|
"cdxgen-secure": "bin/cdxgen.js",
|
|
92
92
|
"cdxi": "bin/repl.js",
|
|
93
93
|
"evinse": "bin/evinse.js",
|
|
94
|
+
"hbom": "bin/hbom.js",
|
|
94
95
|
"obom": "bin/cdxgen.js",
|
|
95
96
|
"saasbom": "bin/cdxgen.js",
|
|
96
97
|
"spdxgen": "bin/cdxgen.js"
|
|
@@ -105,7 +106,7 @@
|
|
|
105
106
|
"index.cjs"
|
|
106
107
|
],
|
|
107
108
|
"dependencies": {
|
|
108
|
-
"@babel/parser": "7.29.
|
|
109
|
+
"@babel/parser": "7.29.3",
|
|
109
110
|
"@babel/traverse": "7.29.0",
|
|
110
111
|
"@iarna/toml": "2.2.5",
|
|
111
112
|
"@isaacs/string-locale-compare": "1.1.0",
|
|
@@ -131,40 +132,41 @@
|
|
|
131
132
|
"proc-log": "6.1.0",
|
|
132
133
|
"properties-reader": "3.0.1",
|
|
133
134
|
"read-package-json-fast": "5.0.0",
|
|
134
|
-
"semver": "7.
|
|
135
|
+
"semver": "7.8.0",
|
|
135
136
|
"ssri": "13.0.1",
|
|
136
|
-
"tar": "7.5.
|
|
137
|
+
"tar": "7.5.15",
|
|
137
138
|
"treeverse": "3.0.0",
|
|
138
139
|
"uuid": "14.0.0",
|
|
139
140
|
"walk-up-path": "4.0.0",
|
|
140
141
|
"xml-js": "1.6.11",
|
|
141
|
-
"yaml": "2.8.
|
|
142
|
+
"yaml": "2.8.4",
|
|
142
143
|
"yargs": "18.0.0",
|
|
143
144
|
"yoctocolors": "2.1.2"
|
|
144
145
|
},
|
|
145
146
|
"devDependencies": {
|
|
146
|
-
"@biomejs/biome": "2.4.
|
|
147
|
-
"esmock": "2.7.
|
|
147
|
+
"@biomejs/biome": "2.4.15",
|
|
148
|
+
"esmock": "2.7.5",
|
|
148
149
|
"poku": "4.3.0",
|
|
149
|
-
"sinon": "
|
|
150
|
+
"sinon": "22.0.0",
|
|
150
151
|
"typescript": "6.0.3"
|
|
151
152
|
},
|
|
152
153
|
"optionalDependencies": {
|
|
153
154
|
"@appthreat/atom": "2.5.2",
|
|
154
155
|
"@appthreat/atom-parsetools": "1.1.4",
|
|
155
|
-
"@appthreat/cdx-proto": "
|
|
156
|
-
"@bufbuild/protobuf": "2.
|
|
157
|
-
"@cdxgen/
|
|
158
|
-
"@cdxgen/cdxgen-plugins-bin
|
|
159
|
-
"@cdxgen/cdxgen-plugins-bin-darwin-
|
|
160
|
-
"@cdxgen/cdxgen-plugins-bin-
|
|
161
|
-
"@cdxgen/cdxgen-plugins-bin-linux-
|
|
162
|
-
"@cdxgen/cdxgen-plugins-bin-linux-
|
|
163
|
-
"@cdxgen/cdxgen-plugins-bin-linux-
|
|
164
|
-
"@cdxgen/cdxgen-plugins-bin-
|
|
165
|
-
"@cdxgen/cdxgen-plugins-bin-linuxmusl-
|
|
166
|
-
"@cdxgen/cdxgen-plugins-bin-
|
|
167
|
-
"@cdxgen/cdxgen-plugins-bin-windows-
|
|
156
|
+
"@appthreat/cdx-proto": "2.0.1",
|
|
157
|
+
"@bufbuild/protobuf": "2.12.0",
|
|
158
|
+
"@cdxgen/cdx-hbom": "0.5.0",
|
|
159
|
+
"@cdxgen/cdxgen-plugins-bin": "2.1.1",
|
|
160
|
+
"@cdxgen/cdxgen-plugins-bin-darwin-amd64": "2.1.1",
|
|
161
|
+
"@cdxgen/cdxgen-plugins-bin-darwin-arm64": "2.1.1",
|
|
162
|
+
"@cdxgen/cdxgen-plugins-bin-linux-amd64": "2.1.1",
|
|
163
|
+
"@cdxgen/cdxgen-plugins-bin-linux-arm": "2.1.1",
|
|
164
|
+
"@cdxgen/cdxgen-plugins-bin-linux-arm64": "2.1.1",
|
|
165
|
+
"@cdxgen/cdxgen-plugins-bin-linux-ppc64": "2.1.1",
|
|
166
|
+
"@cdxgen/cdxgen-plugins-bin-linuxmusl-amd64": "2.1.1",
|
|
167
|
+
"@cdxgen/cdxgen-plugins-bin-linuxmusl-arm64": "2.1.1",
|
|
168
|
+
"@cdxgen/cdxgen-plugins-bin-windows-amd64": "2.1.1",
|
|
169
|
+
"@cdxgen/cdxgen-plugins-bin-windows-arm64": "2.1.1",
|
|
168
170
|
"body-parser": "2.2.2",
|
|
169
171
|
"compression": "1.8.1",
|
|
170
172
|
"connect": "3.7.0",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hbom.d.ts","sourceRoot":"","sources":["../../bin/hbom.js"],"names":[],"mappings":""}
|
package/types/bin/repl.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../../bin/repl.js"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../../bin/repl.js"],"names":[],"mappings":";AA0WO,kDAmEN"}
|
|
@@ -22,6 +22,50 @@ export function loadInputBoms(options: object): {
|
|
|
22
22
|
source: string;
|
|
23
23
|
bomJson: object;
|
|
24
24
|
}[];
|
|
25
|
+
export function runDirectBomAuditFromBoms(inputBoms: any, options?: {}): Promise<{
|
|
26
|
+
auditMode: string;
|
|
27
|
+
generatedAt: string;
|
|
28
|
+
inputs: any;
|
|
29
|
+
results: {
|
|
30
|
+
auditOptions: {
|
|
31
|
+
bomAuditCategories: any;
|
|
32
|
+
bomAuditMinSeverity: any;
|
|
33
|
+
bomAuditRulesDir: any;
|
|
34
|
+
};
|
|
35
|
+
bomFormat: any;
|
|
36
|
+
findings: any[];
|
|
37
|
+
serialNumber: any;
|
|
38
|
+
source: any;
|
|
39
|
+
specVersion: any;
|
|
40
|
+
status: string;
|
|
41
|
+
summary: {
|
|
42
|
+
findingsBySeverity: {
|
|
43
|
+
critical: number;
|
|
44
|
+
high: number;
|
|
45
|
+
low: number;
|
|
46
|
+
medium: number;
|
|
47
|
+
};
|
|
48
|
+
findingsCount: number;
|
|
49
|
+
maxSeverity: string;
|
|
50
|
+
};
|
|
51
|
+
}[];
|
|
52
|
+
summary: {
|
|
53
|
+
findingsBySeverity: {
|
|
54
|
+
critical: number;
|
|
55
|
+
high: number;
|
|
56
|
+
low: number;
|
|
57
|
+
medium: number;
|
|
58
|
+
};
|
|
59
|
+
inputBomCount: any;
|
|
60
|
+
maxSeverity: string;
|
|
61
|
+
totalFindings: number;
|
|
62
|
+
bomsWithFindings: number;
|
|
63
|
+
};
|
|
64
|
+
tool: {
|
|
65
|
+
name: string;
|
|
66
|
+
version: string;
|
|
67
|
+
};
|
|
68
|
+
}>;
|
|
25
69
|
/**
|
|
26
70
|
* Build low-noise provenance-aware contextual findings from the root BOM target.
|
|
27
71
|
*
|