@cyclonedx/cdxgen 12.3.2 → 12.3.3
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 +6 -0
- package/data/rules/ci-permissions.yaml +132 -0
- package/data/rules/dependency-sources.yaml +65 -5
- package/data/rules/package-integrity.yaml +22 -0
- package/lib/cli/index.js +141 -39
- package/lib/cli/index.poku.js +579 -1
- package/lib/helpers/agentFormulationParser.js +6 -2
- package/lib/helpers/agentFormulationParser.poku.js +42 -0
- package/lib/helpers/analyzer.js +38 -9
- package/lib/helpers/analyzer.poku.js +67 -0
- package/lib/helpers/chromextutils.js +25 -3
- package/lib/helpers/chromextutils.poku.js +68 -0
- package/lib/helpers/ciParsers/githubActions.js +79 -0
- package/lib/helpers/ciParsers/githubActions.poku.js +103 -0
- package/lib/helpers/communityAiConfigParser.js +15 -5
- package/lib/helpers/communityAiConfigParser.poku.js +71 -0
- package/lib/helpers/depsUtils.js +5 -0
- package/lib/helpers/depsUtils.poku.js +55 -0
- package/lib/helpers/display.js +45 -22
- package/lib/helpers/display.poku.js +47 -60
- package/lib/helpers/mcpConfigParser.js +21 -5
- package/lib/helpers/mcpConfigParser.poku.js +39 -2
- package/lib/helpers/propertySanitizer.js +121 -0
- package/lib/helpers/utils.js +951 -40
- package/lib/helpers/utils.poku.js +882 -0
- package/lib/managers/binary.js +16 -0
- package/lib/managers/binary.poku.js +1 -0
- package/lib/managers/docker.js +240 -16
- package/lib/managers/docker.poku.js +1142 -2
- package/lib/server/server.js +7 -4
- package/lib/server/server.poku.js +36 -1
- package/lib/stages/postgen/auditBom.poku.js +644 -2
- package/package.json +2 -1
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/helpers/agentFormulationParser.d.ts.map +1 -1
- package/types/lib/helpers/analyzer.d.ts.map +1 -1
- package/types/lib/helpers/chromextutils.d.ts.map +1 -1
- package/types/lib/helpers/ciParsers/githubActions.d.ts.map +1 -1
- package/types/lib/helpers/communityAiConfigParser.d.ts.map +1 -1
- package/types/lib/helpers/depsUtils.d.ts.map +1 -1
- package/types/lib/helpers/display.d.ts +1 -0
- package/types/lib/helpers/display.d.ts.map +1 -1
- package/types/lib/helpers/mcpConfigParser.d.ts +1 -1
- package/types/lib/helpers/mcpConfigParser.d.ts.map +1 -1
- package/types/lib/helpers/propertySanitizer.d.ts +3 -0
- package/types/lib/helpers/propertySanitizer.d.ts.map +1 -0
- package/types/lib/helpers/utils.d.ts +29 -0
- package/types/lib/helpers/utils.d.ts.map +1 -1
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/managers/docker.d.ts +3 -0
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/server/server.d.ts +1 -0
- package/types/lib/server/server.d.ts.map +1 -1
package/README.md
CHANGED
|
@@ -523,6 +523,12 @@ You can also pass `-t docker` with repository names. Only the `latest` tag would
|
|
|
523
523
|
cdxgen shiftleft/scan-slim -o /tmp/bom.json -t docker
|
|
524
524
|
```
|
|
525
525
|
|
|
526
|
+
For offline or staged scans, point cdxgen at a locally reconstructed root filesystem directory. The container pipeline accepts `-t docker`, `-t rootfs`, or `-t oci-dir` for this mode.
|
|
527
|
+
|
|
528
|
+
```shell
|
|
529
|
+
cdxgen /tmp/remote_target -o /tmp/bom.json -t rootfs
|
|
530
|
+
```
|
|
531
|
+
|
|
526
532
|
You can also pass the .tar file of a container image.
|
|
527
533
|
|
|
528
534
|
```shell
|
|
@@ -642,5 +642,137 @@
|
|
|
642
642
|
"sensitiveOperations": $prop($, 'cdx:github:step:sensitiveOperations'),
|
|
643
643
|
"sensitiveContextRefs": $prop($, 'cdx:github:step:sensitiveContextRefs'),
|
|
644
644
|
"dispatchKinds": $prop($, 'cdx:github:step:dispatchKinds')
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
- id: CI-022
|
|
648
|
+
name: "npm setup action disables build cache despite resolved package distributions"
|
|
649
|
+
description: "Explicitly disabling setup-node caching reduces tamper resistance and reviewability when npm dependencies are resolved from remote package distributions"
|
|
650
|
+
severity: medium
|
|
651
|
+
category: ci-permission
|
|
652
|
+
attack:
|
|
653
|
+
tactics: [TA0005]
|
|
654
|
+
techniques: [T1195.001]
|
|
655
|
+
condition: |
|
|
656
|
+
$auditComponents($)[
|
|
657
|
+
$prop($, 'cdx:github:action:disablesBuildCache') = 'true'
|
|
658
|
+
and $prop($, 'cdx:github:action:buildCacheEcosystem') = 'npm'
|
|
659
|
+
and $count($$.components[
|
|
660
|
+
$startsWith(purl, 'pkg:npm/')
|
|
661
|
+
and (
|
|
662
|
+
$contains($lowercase($nullSafeProp($, 'cdx:npm:manifestSourceType')), 'git')
|
|
663
|
+
or $contains($lowercase($nullSafeProp($, 'cdx:npm:manifestSourceType')), 'url')
|
|
664
|
+
)
|
|
665
|
+
and $count(externalReferences[
|
|
666
|
+
type = 'distribution'
|
|
667
|
+
and (
|
|
668
|
+
$startsWith($lowercase(url), 'git+')
|
|
669
|
+
or $startsWith($lowercase(url), 'http://')
|
|
670
|
+
or $startsWith($lowercase(url), 'https://')
|
|
671
|
+
)
|
|
672
|
+
]) > 0
|
|
673
|
+
]) > 0
|
|
674
|
+
]
|
|
675
|
+
location: |
|
|
676
|
+
{
|
|
677
|
+
"bomRef": $."bom-ref",
|
|
678
|
+
"purl": purl,
|
|
679
|
+
"file": $prop($, 'cdx:github:workflow:file')
|
|
680
|
+
}
|
|
681
|
+
message: "GitHub Action '{{ $prop($, 'cdx:github:action:uses') }}' explicitly disables npm build caching while resolved npm package distributions are present in the BOM"
|
|
682
|
+
mitigation: "Keep setup-node caching enabled unless you have a reviewed exception; disabling cache can weaken integrity checks and provenance review for resolved npm artifacts"
|
|
683
|
+
evidence: |
|
|
684
|
+
{
|
|
685
|
+
"cacheDisableInput": $prop($, 'cdx:github:action:buildCacheDisableInput'),
|
|
686
|
+
"cacheDisableValue": $prop($, 'cdx:github:action:buildCacheDisableValue'),
|
|
687
|
+
"matchingPackages": $$.components[
|
|
688
|
+
$startsWith(purl, 'pkg:npm/')
|
|
689
|
+
and (
|
|
690
|
+
$contains($lowercase($nullSafeProp($, 'cdx:npm:manifestSourceType')), 'git')
|
|
691
|
+
or $contains($lowercase($nullSafeProp($, 'cdx:npm:manifestSourceType')), 'url')
|
|
692
|
+
)
|
|
693
|
+
and $count(externalReferences[
|
|
694
|
+
type = 'distribution'
|
|
695
|
+
and (
|
|
696
|
+
$startsWith($lowercase(url), 'git+')
|
|
697
|
+
or $startsWith($lowercase(url), 'http://')
|
|
698
|
+
or $startsWith($lowercase(url), 'https://')
|
|
699
|
+
)
|
|
700
|
+
]) > 0
|
|
701
|
+
].purl
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
- id: CI-023
|
|
705
|
+
name: "Python setup action disables build cache despite resolved package distributions"
|
|
706
|
+
description: "Explicitly disabling setup-python caching reduces tamper resistance and reviewability when PyPI dependencies are resolved from remote archives or VCS sources"
|
|
707
|
+
severity: medium
|
|
708
|
+
category: ci-permission
|
|
709
|
+
attack:
|
|
710
|
+
tactics: [TA0005]
|
|
711
|
+
techniques: [T1195.001]
|
|
712
|
+
condition: |
|
|
713
|
+
$auditComponents($)[
|
|
714
|
+
$prop($, 'cdx:github:action:disablesBuildCache') = 'true'
|
|
715
|
+
and $prop($, 'cdx:github:action:buildCacheEcosystem') = 'pypi'
|
|
716
|
+
and $count($$.components[
|
|
717
|
+
$startsWith(purl, 'pkg:pypi/')
|
|
718
|
+
and (
|
|
719
|
+
$contains($lowercase($nullSafeProp($, 'cdx:pypi:manifestSourceType')), 'git')
|
|
720
|
+
or $contains($lowercase($nullSafeProp($, 'cdx:pypi:manifestSourceType')), 'url')
|
|
721
|
+
)
|
|
722
|
+
]) > 0
|
|
723
|
+
]
|
|
724
|
+
location: |
|
|
725
|
+
{
|
|
726
|
+
"bomRef": $."bom-ref",
|
|
727
|
+
"purl": purl,
|
|
728
|
+
"file": $prop($, 'cdx:github:workflow:file')
|
|
729
|
+
}
|
|
730
|
+
message: "GitHub Action '{{ $prop($, 'cdx:github:action:uses') }}' explicitly disables Python build caching while resolved PyPI package distributions are present in the BOM"
|
|
731
|
+
mitigation: "Keep setup-python caching enabled when lockfiles resolve remote archives or VCS sources unless you have a reviewed exception"
|
|
732
|
+
evidence: |
|
|
733
|
+
{
|
|
734
|
+
"cacheDisableInput": $prop($, 'cdx:github:action:buildCacheDisableInput'),
|
|
735
|
+
"cacheDisableValue": $prop($, 'cdx:github:action:buildCacheDisableValue'),
|
|
736
|
+
"matchingPackages": $$.components[
|
|
737
|
+
$startsWith(purl, 'pkg:pypi/')
|
|
738
|
+
and (
|
|
739
|
+
$contains($lowercase($nullSafeProp($, 'cdx:pypi:manifestSourceType')), 'git')
|
|
740
|
+
or $contains($lowercase($nullSafeProp($, 'cdx:pypi:manifestSourceType')), 'url')
|
|
741
|
+
)
|
|
742
|
+
].purl
|
|
645
743
|
}
|
|
646
744
|
|
|
745
|
+
- id: CI-024
|
|
746
|
+
name: "Cargo setup action disables build cache despite manifest-declared git dependencies"
|
|
747
|
+
description: "Explicitly disabling Cargo setup caching reduces tamper resistance and reviewability when Cargo manifests rely on git dependencies"
|
|
748
|
+
severity: medium
|
|
749
|
+
category: ci-permission
|
|
750
|
+
attack:
|
|
751
|
+
tactics: [TA0005]
|
|
752
|
+
techniques: [T1195.001]
|
|
753
|
+
condition: |
|
|
754
|
+
$auditComponents($)[
|
|
755
|
+
$prop($, 'cdx:github:action:disablesBuildCache') = 'true'
|
|
756
|
+
and $prop($, 'cdx:github:action:buildCacheEcosystem') = 'cargo'
|
|
757
|
+
and $count($$.components[
|
|
758
|
+
$startsWith(purl, 'pkg:cargo/')
|
|
759
|
+
and $hasProp($, 'cdx:cargo:git')
|
|
760
|
+
]) > 0
|
|
761
|
+
]
|
|
762
|
+
location: |
|
|
763
|
+
{
|
|
764
|
+
"bomRef": $."bom-ref",
|
|
765
|
+
"purl": purl,
|
|
766
|
+
"file": $prop($, 'cdx:github:workflow:file')
|
|
767
|
+
}
|
|
768
|
+
message: "GitHub Action '{{ $prop($, 'cdx:github:action:uses') }}' explicitly disables Cargo build caching while manifest-declared Cargo git dependencies are present in the BOM"
|
|
769
|
+
mitigation: "Keep Cargo setup caching enabled when manifests rely on git dependencies unless you have a reviewed exception"
|
|
770
|
+
evidence: |
|
|
771
|
+
{
|
|
772
|
+
"cacheDisableInput": $prop($, 'cdx:github:action:buildCacheDisableInput'),
|
|
773
|
+
"cacheDisableValue": $prop($, 'cdx:github:action:buildCacheDisableValue'),
|
|
774
|
+
"matchingPackages": $$.components[
|
|
775
|
+
$startsWith(purl, 'pkg:cargo/')
|
|
776
|
+
and $hasProp($, 'cdx:cargo:git')
|
|
777
|
+
].purl
|
|
778
|
+
}
|
|
@@ -2,21 +2,23 @@
|
|
|
2
2
|
# Category: dependency-source
|
|
3
3
|
# Evaluates package manager data for non-registry, local, or mutable sources
|
|
4
4
|
- id: PKG-001
|
|
5
|
-
name: "Install script from
|
|
6
|
-
description: "npm packages with install scripts from git
|
|
5
|
+
name: "Install script from direct manifest source"
|
|
6
|
+
description: "npm packages with install scripts declared from git, URL, or local path sources in the manifest increase supply chain attack surface"
|
|
7
7
|
severity: high
|
|
8
8
|
category: dependency-source
|
|
9
9
|
condition: |
|
|
10
10
|
components[
|
|
11
11
|
$prop($, 'cdx:npm:hasInstallScript') = 'true'
|
|
12
|
-
and $
|
|
12
|
+
and $hasProp($, 'cdx:npm:manifestSourceType')
|
|
13
13
|
]
|
|
14
14
|
location: |
|
|
15
15
|
{ "bomRef": $."bom-ref", "purl": purl }
|
|
16
|
-
message: "npm package '{{ name }}@{{ version }}' executes install script from
|
|
17
|
-
mitigation: "Avoid git
|
|
16
|
+
message: "npm package '{{ name }}@{{ version }}' executes install script from manifest-declared source type(s): {{ $prop($, 'cdx:npm:manifestSourceType') }}"
|
|
17
|
+
mitigation: "Avoid git, URL, or local-path dependencies with lifecycle hooks; use registry-published dependencies or vendor explicitly"
|
|
18
18
|
evidence: |
|
|
19
19
|
{
|
|
20
|
+
"manifestSourceType": $prop($, 'cdx:npm:manifestSourceType'),
|
|
21
|
+
"manifestSource": $prop($, 'cdx:npm:manifestSource'),
|
|
20
22
|
"riskyScripts": $prop($, 'cdx:npm:risky_scripts'),
|
|
21
23
|
"resolvedPath": $prop($, 'cdx:npm:resolvedPath'),
|
|
22
24
|
"isLink": $prop($, 'cdx:npm:isLink')
|
|
@@ -162,3 +164,61 @@
|
|
|
162
164
|
"dependencyKind": $prop($, 'cdx:cargo:dependencyKind'),
|
|
163
165
|
"target": $prop($, 'cdx:cargo:target')
|
|
164
166
|
}
|
|
167
|
+
- id: PKG-009
|
|
168
|
+
name: "Collider package resolved from insecure HTTP origin"
|
|
169
|
+
description: "Collider lock entries that resolve from HTTP origins can be observed or modified in transit before wrap-hash verification occurs"
|
|
170
|
+
severity: medium
|
|
171
|
+
category: dependency-source
|
|
172
|
+
condition: |
|
|
173
|
+
components[
|
|
174
|
+
$prop($, 'cdx:collider:originScheme') = 'http'
|
|
175
|
+
]
|
|
176
|
+
location: |
|
|
177
|
+
{ "bomRef": $."bom-ref", "purl": purl }
|
|
178
|
+
message: "Collider package '{{ name }}@{{ version }}' resolves from insecure origin '{{ $prop($, 'cdx:collider:origin') }}'"
|
|
179
|
+
mitigation: "Prefer HTTPS, trusted file:// repositories, or an authenticated internal mirror for Collider package origins"
|
|
180
|
+
evidence: |
|
|
181
|
+
{
|
|
182
|
+
"origin": $prop($, 'cdx:collider:origin'),
|
|
183
|
+
"originHost": $prop($, 'cdx:collider:originHost'),
|
|
184
|
+
"dependencyKind": $prop($, 'cdx:collider:dependencyKind')
|
|
185
|
+
}
|
|
186
|
+
- id: PKG-010
|
|
187
|
+
name: "Collider origin required sanitization before BOM emission"
|
|
188
|
+
description: "Collider lock origin URLs should not carry credentials, query strings, or fragments because those values may embed secrets or unstable signed URLs"
|
|
189
|
+
severity: low
|
|
190
|
+
category: dependency-source
|
|
191
|
+
condition: |
|
|
192
|
+
components[
|
|
193
|
+
$prop($, 'cdx:collider:originSanitized') = 'true'
|
|
194
|
+
]
|
|
195
|
+
location: |
|
|
196
|
+
{ "bomRef": $."bom-ref", "purl": purl }
|
|
197
|
+
message: "Collider package '{{ name }}@{{ version }}' had sensitive origin fields stripped before BOM emission"
|
|
198
|
+
mitigation: "Avoid embedding credentials or signed query parameters in Collider repository origin URLs; prefer stable repository base URLs"
|
|
199
|
+
evidence: |
|
|
200
|
+
{
|
|
201
|
+
"origin": $prop($, 'cdx:collider:origin'),
|
|
202
|
+
"originHost": $prop($, 'cdx:collider:originHost'),
|
|
203
|
+
"dependencyKind": $prop($, 'cdx:collider:dependencyKind')
|
|
204
|
+
}
|
|
205
|
+
- id: PKG-011
|
|
206
|
+
name: "Python dependency uses direct manifest source"
|
|
207
|
+
description: "Python dependencies declared via git, direct URL, or local path in requirements or pyproject files bypass normal registry version mediation"
|
|
208
|
+
severity: high
|
|
209
|
+
category: dependency-source
|
|
210
|
+
condition: |
|
|
211
|
+
components[
|
|
212
|
+
$hasProp($, 'cdx:pypi:manifestSourceType')
|
|
213
|
+
]
|
|
214
|
+
location: |
|
|
215
|
+
{ "bomRef": $."bom-ref", "purl": purl }
|
|
216
|
+
message: "Python package '{{ name }}@{{ version }}' is declared from manifest {{ $prop($, 'cdx:pypi:manifestSourceType') }} source '{{ $prop($, 'cdx:pypi:manifestSource') }}'"
|
|
217
|
+
mitigation: "Prefer registry-published releases for production builds, or pin and review direct git/URL/path sources explicitly"
|
|
218
|
+
evidence: |
|
|
219
|
+
{
|
|
220
|
+
"manifestSourceType": $prop($, 'cdx:pypi:manifestSourceType'),
|
|
221
|
+
"manifestSource": $prop($, 'cdx:pypi:manifestSource'),
|
|
222
|
+
"registry": $prop($, 'cdx:pypi:registry'),
|
|
223
|
+
"resolvedFrom": $prop($, 'cdx:pypi:resolved_from')
|
|
224
|
+
}
|
|
@@ -305,3 +305,25 @@
|
|
|
305
305
|
)
|
|
306
306
|
].$prop($, 'cdx:github:step:command')
|
|
307
307
|
}
|
|
308
|
+
|
|
309
|
+
- id: INT-014
|
|
310
|
+
name: "Collider package missing valid wrap hash pin"
|
|
311
|
+
description: "Collider lock entries should carry a SHA-256 wrap_hash so the selected wrap file remains integrity-pinned and reproducible"
|
|
312
|
+
severity: high
|
|
313
|
+
category: package-integrity
|
|
314
|
+
condition: |
|
|
315
|
+
components[
|
|
316
|
+
$hasProp($, 'cdx:collider:dependencyKind')
|
|
317
|
+
and $prop($, 'cdx:collider:hasWrapHash') = 'false'
|
|
318
|
+
]
|
|
319
|
+
location: |
|
|
320
|
+
{ "bomRef": $."bom-ref", "purl": purl }
|
|
321
|
+
message: "Collider package '{{ name }}@{{ version }}' is missing a valid wrap hash integrity pin"
|
|
322
|
+
mitigation: "Recreate collider.lock with valid wrap_hash values and verify the lockfile against the repository before release"
|
|
323
|
+
evidence: |
|
|
324
|
+
{
|
|
325
|
+
"wrapHash": $prop($, 'cdx:collider:wrapHash'),
|
|
326
|
+
"wrapHashInvalid": $prop($, 'cdx:collider:wrapHashInvalid'),
|
|
327
|
+
"origin": $prop($, 'cdx:collider:origin'),
|
|
328
|
+
"dependencyKind": $prop($, 'cdx:collider:dependencyKind')
|
|
329
|
+
}
|
package/lib/cli/index.js
CHANGED
|
@@ -64,6 +64,7 @@ import {
|
|
|
64
64
|
addEvidenceForDotnet,
|
|
65
65
|
addEvidenceForImports,
|
|
66
66
|
addPlugin,
|
|
67
|
+
attachIdentityTools,
|
|
67
68
|
buildGradleCommandArguments,
|
|
68
69
|
buildObjectForCocoaPod,
|
|
69
70
|
buildObjectForGradleModule,
|
|
@@ -88,6 +89,7 @@ import {
|
|
|
88
89
|
executeParallelGradleProperties,
|
|
89
90
|
executePodCommand,
|
|
90
91
|
extractJarArchive,
|
|
92
|
+
extractToolRefs,
|
|
91
93
|
frameworksList,
|
|
92
94
|
generatePixiLockFile,
|
|
93
95
|
getAllFiles,
|
|
@@ -134,6 +136,7 @@ import {
|
|
|
134
136
|
parseCloudBuildData,
|
|
135
137
|
parseCmakeLikeFile,
|
|
136
138
|
parseCocoaDependency,
|
|
139
|
+
parseColliderLockData,
|
|
137
140
|
parseComposerJson,
|
|
138
141
|
parseComposerLock,
|
|
139
142
|
parseConanData,
|
|
@@ -329,7 +332,10 @@ const createDefaultParentComponent = (
|
|
|
329
332
|
group: options.projectGroup || "",
|
|
330
333
|
name: compName,
|
|
331
334
|
version: `${options.projectVersion}` || "latest",
|
|
332
|
-
type:
|
|
335
|
+
type:
|
|
336
|
+
type === "container" || compName.endsWith(".tar")
|
|
337
|
+
? "container"
|
|
338
|
+
: "application",
|
|
333
339
|
};
|
|
334
340
|
const ppurl = new PackageURL(
|
|
335
341
|
type,
|
|
@@ -344,6 +350,25 @@ const createDefaultParentComponent = (
|
|
|
344
350
|
return parentComponent;
|
|
345
351
|
};
|
|
346
352
|
|
|
353
|
+
const shouldIncludeNodeModulesDir = (options = {}, baseProjectTypes = []) => {
|
|
354
|
+
if (options.deep) {
|
|
355
|
+
return true;
|
|
356
|
+
}
|
|
357
|
+
const projectTypes = Array.isArray(options.projectType)
|
|
358
|
+
? options.projectType
|
|
359
|
+
: options.projectType
|
|
360
|
+
? [options.projectType]
|
|
361
|
+
: [];
|
|
362
|
+
if (!projectTypes.length) {
|
|
363
|
+
return true;
|
|
364
|
+
}
|
|
365
|
+
return baseProjectTypes.some((projectType) =>
|
|
366
|
+
projectTypes.every((selectedProjectType) =>
|
|
367
|
+
PROJECT_TYPE_ALIASES[projectType]?.includes(selectedProjectType),
|
|
368
|
+
),
|
|
369
|
+
);
|
|
370
|
+
};
|
|
371
|
+
|
|
347
372
|
const determineParentComponent = (options) => {
|
|
348
373
|
let parentComponent;
|
|
349
374
|
if (options.parentComponent && Object.keys(options.parentComponent).length) {
|
|
@@ -1368,17 +1393,21 @@ export async function createJarBom(path, options) {
|
|
|
1368
1393
|
let pkgList = [];
|
|
1369
1394
|
let jarFiles;
|
|
1370
1395
|
let nsMapping = {};
|
|
1371
|
-
|
|
1372
|
-
options
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
if (typeof
|
|
1376
|
-
|
|
1396
|
+
const searchOptions = {
|
|
1397
|
+
...options,
|
|
1398
|
+
exclude: [...(options.exclude || [])],
|
|
1399
|
+
};
|
|
1400
|
+
if (typeof searchOptions.includeNodeModulesDir === "undefined") {
|
|
1401
|
+
searchOptions.includeNodeModulesDir = shouldIncludeNodeModulesDir(options, [
|
|
1402
|
+
"jar",
|
|
1403
|
+
"war",
|
|
1404
|
+
"ear",
|
|
1405
|
+
]);
|
|
1377
1406
|
}
|
|
1378
1407
|
// Exclude certain directories during oci sbom generation
|
|
1379
1408
|
if (hasAnyProjectType(["oci"], options, false)) {
|
|
1380
|
-
|
|
1381
|
-
|
|
1409
|
+
searchOptions.exclude.push("**/android-sdk*/**");
|
|
1410
|
+
searchOptions.exclude.push("**/.sdkman/**");
|
|
1382
1411
|
}
|
|
1383
1412
|
const parentComponent = createDefaultParentComponent(path, "maven", options);
|
|
1384
1413
|
if (options.useGradleCache) {
|
|
@@ -1402,14 +1431,14 @@ export async function createJarBom(path, options) {
|
|
|
1402
1431
|
jarFiles = getAllFiles(
|
|
1403
1432
|
path,
|
|
1404
1433
|
`${options.multiProject ? "**/" : ""}*.[jw]ar`,
|
|
1405
|
-
|
|
1434
|
+
searchOptions,
|
|
1406
1435
|
);
|
|
1407
1436
|
}
|
|
1408
1437
|
// Jenkins plugins
|
|
1409
1438
|
const hpiFiles = getAllFiles(
|
|
1410
1439
|
path,
|
|
1411
1440
|
`${options.multiProject ? "**/" : ""}*.hpi`,
|
|
1412
|
-
|
|
1441
|
+
searchOptions,
|
|
1413
1442
|
);
|
|
1414
1443
|
if (hpiFiles.length) {
|
|
1415
1444
|
jarFiles = jarFiles.concat(hpiFiles);
|
|
@@ -1464,6 +1493,13 @@ export function createBinaryBom(path, options) {
|
|
|
1464
1493
|
const binaryBom = JSON.parse(
|
|
1465
1494
|
readFileSync(binaryBomFile, { encoding: "utf-8" }),
|
|
1466
1495
|
);
|
|
1496
|
+
attachIdentityTools(
|
|
1497
|
+
binaryBom?.components,
|
|
1498
|
+
extractToolRefs(
|
|
1499
|
+
binaryBom?.metadata?.tools,
|
|
1500
|
+
(tool) => tool?.name !== "cdxgen",
|
|
1501
|
+
),
|
|
1502
|
+
);
|
|
1467
1503
|
return {
|
|
1468
1504
|
bomJson: binaryBom,
|
|
1469
1505
|
dependencies: binaryBom.dependencies,
|
|
@@ -1891,6 +1927,10 @@ export async function createJavaBom(path, options) {
|
|
|
1891
1927
|
) {
|
|
1892
1928
|
tools = bomJsonObj.metadata.tools;
|
|
1893
1929
|
}
|
|
1930
|
+
const toolRefs = extractToolRefs(
|
|
1931
|
+
bomJsonObj?.metadata?.tools,
|
|
1932
|
+
(tool) => tool?.name !== "cdxgen",
|
|
1933
|
+
);
|
|
1894
1934
|
if (
|
|
1895
1935
|
bomJsonObj.metadata?.component &&
|
|
1896
1936
|
!Object.keys(parentComponent).length
|
|
@@ -1927,6 +1967,7 @@ export async function createJavaBom(path, options) {
|
|
|
1927
1967
|
name: "SrcFile",
|
|
1928
1968
|
value: srcPomFile,
|
|
1929
1969
|
});
|
|
1970
|
+
attachIdentityTools(acomp, toolRefs);
|
|
1930
1971
|
}
|
|
1931
1972
|
}
|
|
1932
1973
|
pkgList = pkgList.concat(bomJsonObj.components);
|
|
@@ -5416,6 +5457,11 @@ export function createCppBom(path, options) {
|
|
|
5416
5457
|
let parentComponent;
|
|
5417
5458
|
let dependencies = [];
|
|
5418
5459
|
const addedParentComponentsMap = {};
|
|
5460
|
+
const colliderLockFiles = getAllFiles(
|
|
5461
|
+
path,
|
|
5462
|
+
`${options.multiProject ? "**/" : ""}collider.lock`,
|
|
5463
|
+
options,
|
|
5464
|
+
);
|
|
5419
5465
|
const conanLockFiles = getAllFiles(
|
|
5420
5466
|
path,
|
|
5421
5467
|
`${options.multiProject ? "**/" : ""}conan.lock`,
|
|
@@ -5492,6 +5538,39 @@ export function createCppBom(path, options) {
|
|
|
5492
5538
|
}
|
|
5493
5539
|
}
|
|
5494
5540
|
}
|
|
5541
|
+
if (colliderLockFiles.length) {
|
|
5542
|
+
for (const f of colliderLockFiles) {
|
|
5543
|
+
if (DEBUG_MODE) {
|
|
5544
|
+
console.log(`Parsing ${f}`);
|
|
5545
|
+
}
|
|
5546
|
+
const colliderLockData = readFileSync(f, { encoding: "utf-8" });
|
|
5547
|
+
const {
|
|
5548
|
+
pkgList: colliderPkgList,
|
|
5549
|
+
dependencies: colliderDependencies,
|
|
5550
|
+
parentComponentDependencies: parentCompDeps,
|
|
5551
|
+
} = parseColliderLockData(colliderLockData, f);
|
|
5552
|
+
|
|
5553
|
+
if (colliderPkgList.length) {
|
|
5554
|
+
pkgList = pkgList.concat(colliderPkgList);
|
|
5555
|
+
}
|
|
5556
|
+
|
|
5557
|
+
if (Object.keys(colliderDependencies).length) {
|
|
5558
|
+
dependencies = mergeDependencies(
|
|
5559
|
+
dependencies,
|
|
5560
|
+
Object.keys(colliderDependencies).map((dependentBomRef) => ({
|
|
5561
|
+
ref: dependentBomRef,
|
|
5562
|
+
dependsOn: colliderDependencies[dependentBomRef],
|
|
5563
|
+
})),
|
|
5564
|
+
);
|
|
5565
|
+
}
|
|
5566
|
+
|
|
5567
|
+
if (parentCompDeps.length) {
|
|
5568
|
+
parentComponentDependencies = [
|
|
5569
|
+
...new Set(parentComponentDependencies.concat(parentCompDeps)),
|
|
5570
|
+
];
|
|
5571
|
+
}
|
|
5572
|
+
}
|
|
5573
|
+
}
|
|
5495
5574
|
if (cmakeLikeFiles.length) {
|
|
5496
5575
|
for (const f of cmakeLikeFiles) {
|
|
5497
5576
|
if (DEBUG_MODE) {
|
|
@@ -6830,24 +6909,26 @@ export async function createContainerSpecLikeBom(path, options) {
|
|
|
6830
6909
|
export function createPHPBom(path, options) {
|
|
6831
6910
|
let dependencies = [];
|
|
6832
6911
|
let parentComponent = {};
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
6912
|
+
const searchOptions = {
|
|
6913
|
+
...options,
|
|
6914
|
+
includeNodeModulesDir:
|
|
6915
|
+
typeof options.includeNodeModulesDir === "undefined"
|
|
6916
|
+
? shouldIncludeNodeModulesDir(options, ["php"])
|
|
6917
|
+
: options.includeNodeModulesDir,
|
|
6918
|
+
};
|
|
6919
|
+
const composerLockSearchOptions = {
|
|
6920
|
+
...searchOptions,
|
|
6921
|
+
exclude: [...(options.exclude || []), "**/vendor/**"],
|
|
6922
|
+
};
|
|
6837
6923
|
const composerJsonFiles = getAllFiles(
|
|
6838
6924
|
path,
|
|
6839
6925
|
`${options.multiProject ? "**/" : ""}composer.json`,
|
|
6840
|
-
|
|
6926
|
+
searchOptions,
|
|
6841
6927
|
);
|
|
6842
|
-
if (!options.exclude) {
|
|
6843
|
-
options.exclude = [];
|
|
6844
|
-
}
|
|
6845
|
-
// Ignore vendor directories for lock files
|
|
6846
|
-
options.exclude.push("**/vendor/**");
|
|
6847
6928
|
let composerLockFiles = getAllFiles(
|
|
6848
6929
|
path,
|
|
6849
6930
|
`${options.multiProject ? "**/" : ""}composer.lock`,
|
|
6850
|
-
|
|
6931
|
+
composerLockSearchOptions,
|
|
6851
6932
|
);
|
|
6852
6933
|
let pkgList = [];
|
|
6853
6934
|
const composerJsonMode = composerJsonFiles.length;
|
|
@@ -6910,7 +6991,7 @@ export function createPHPBom(path, options) {
|
|
|
6910
6991
|
composerLockFiles = getAllFiles(
|
|
6911
6992
|
path,
|
|
6912
6993
|
`${options.multiProject ? "**/" : ""}composer.lock`,
|
|
6913
|
-
|
|
6994
|
+
composerLockSearchOptions,
|
|
6914
6995
|
);
|
|
6915
6996
|
if (composerLockFiles.length) {
|
|
6916
6997
|
// Look for any root composer.json to capture the parentComponent
|
|
@@ -8058,6 +8139,7 @@ export async function createMultiXBom(pathList, options) {
|
|
|
8058
8139
|
binPaths,
|
|
8059
8140
|
executables,
|
|
8060
8141
|
sharedLibs,
|
|
8142
|
+
tools,
|
|
8061
8143
|
} = await getOSPackages(
|
|
8062
8144
|
options.allLayersExplodedDir,
|
|
8063
8145
|
options.exportData?.inspectData?.Config,
|
|
@@ -8088,6 +8170,13 @@ export async function createMultiXBom(pathList, options) {
|
|
|
8088
8170
|
if (allTypes?.length) {
|
|
8089
8171
|
options.allOSComponentTypes = allTypes;
|
|
8090
8172
|
}
|
|
8173
|
+
if (tools?.length) {
|
|
8174
|
+
options.tools = (
|
|
8175
|
+
Array.isArray(options.tools)
|
|
8176
|
+
? options.tools
|
|
8177
|
+
: options.tools?.components || []
|
|
8178
|
+
).concat(tools);
|
|
8179
|
+
}
|
|
8091
8180
|
components = components.concat(osPackages);
|
|
8092
8181
|
components = components.concat(executables);
|
|
8093
8182
|
components = components.concat(sharedLibs);
|
|
@@ -9162,6 +9251,11 @@ export async function createXBom(path, options) {
|
|
|
9162
9251
|
`${options.multiProject ? "**/" : ""}conan.lock`,
|
|
9163
9252
|
options,
|
|
9164
9253
|
);
|
|
9254
|
+
const colliderLockFiles = getAllFiles(
|
|
9255
|
+
path,
|
|
9256
|
+
`${options.multiProject ? "**/" : ""}collider.lock`,
|
|
9257
|
+
options,
|
|
9258
|
+
);
|
|
9165
9259
|
const conanFiles = getAllFiles(
|
|
9166
9260
|
path,
|
|
9167
9261
|
`${options.multiProject ? "**/" : ""}conanfile.txt`,
|
|
@@ -9178,6 +9272,7 @@ export async function createXBom(path, options) {
|
|
|
9178
9272
|
options,
|
|
9179
9273
|
);
|
|
9180
9274
|
if (
|
|
9275
|
+
colliderLockFiles.length ||
|
|
9181
9276
|
conanLockFiles.length ||
|
|
9182
9277
|
conanFiles.length ||
|
|
9183
9278
|
cmakeListFiles.length ||
|
|
@@ -9347,6 +9442,10 @@ export async function createBom(path, options) {
|
|
|
9347
9442
|
}
|
|
9348
9443
|
let exportData;
|
|
9349
9444
|
let isContainerMode = false;
|
|
9445
|
+
const isLocalDirectoryInput =
|
|
9446
|
+
!options.projectType?.includes("universal") &&
|
|
9447
|
+
safeExistsSync(path) &&
|
|
9448
|
+
lstatSync(path).isDirectory();
|
|
9350
9449
|
// Docker and image archive support
|
|
9351
9450
|
// TODO: Support any source archive
|
|
9352
9451
|
if (path.endsWith(".tar") || path.endsWith(".tar.gz")) {
|
|
@@ -9359,6 +9458,22 @@ export async function createBom(path, options) {
|
|
|
9359
9458
|
return {};
|
|
9360
9459
|
}
|
|
9361
9460
|
isContainerMode = true;
|
|
9461
|
+
} else if (
|
|
9462
|
+
isLocalDirectoryInput &&
|
|
9463
|
+
(hasAnyProjectType(["oci-dir"], options, false) ||
|
|
9464
|
+
hasAnyProjectType(["oci"], options, false))
|
|
9465
|
+
) {
|
|
9466
|
+
isContainerMode = true;
|
|
9467
|
+
exportData = {
|
|
9468
|
+
inspectData: undefined,
|
|
9469
|
+
lastWorkingDir: "",
|
|
9470
|
+
allLayersDir: path,
|
|
9471
|
+
allLayersExplodedDir: path,
|
|
9472
|
+
};
|
|
9473
|
+
if (safeExistsSync(join(path, "all-layers"))) {
|
|
9474
|
+
exportData.allLayersExplodedDir = join(path, "all-layers");
|
|
9475
|
+
}
|
|
9476
|
+
exportData.pkgPathList = getPkgPathList(exportData, undefined);
|
|
9362
9477
|
} else if (
|
|
9363
9478
|
(options.projectType &&
|
|
9364
9479
|
!options.projectType?.includes("universal") &&
|
|
@@ -9386,21 +9501,6 @@ export async function createBom(path, options) {
|
|
|
9386
9501
|
console.log(path, "doesn't appear to be a valid container image.");
|
|
9387
9502
|
}
|
|
9388
9503
|
}
|
|
9389
|
-
} else if (
|
|
9390
|
-
!options.projectType?.includes("universal") &&
|
|
9391
|
-
hasAnyProjectType(["oci-dir"], options, false)
|
|
9392
|
-
) {
|
|
9393
|
-
isContainerMode = true;
|
|
9394
|
-
exportData = {
|
|
9395
|
-
inspectData: undefined,
|
|
9396
|
-
lastWorkingDir: "",
|
|
9397
|
-
allLayersDir: path,
|
|
9398
|
-
allLayersExplodedDir: path,
|
|
9399
|
-
};
|
|
9400
|
-
if (safeExistsSync(join(path, "all-layers"))) {
|
|
9401
|
-
exportData.allLayersDir = join(path, "all-layers");
|
|
9402
|
-
}
|
|
9403
|
-
exportData.pkgPathList = getPkgPathList(exportData, undefined);
|
|
9404
9504
|
}
|
|
9405
9505
|
if (isContainerMode) {
|
|
9406
9506
|
options.multiProject = true;
|
|
@@ -9680,6 +9780,7 @@ export async function submitBom(args, bomContents) {
|
|
|
9680
9780
|
// See issue #1963 regarding CRLF hardening
|
|
9681
9781
|
return await got(serverUrl, {
|
|
9682
9782
|
method: "PUT",
|
|
9783
|
+
followRedirect: false,
|
|
9683
9784
|
https: {
|
|
9684
9785
|
rejectUnauthorized: !args.skipDtTlsCheck,
|
|
9685
9786
|
},
|
|
@@ -9705,11 +9806,12 @@ export async function submitBom(args, bomContents) {
|
|
|
9705
9806
|
try {
|
|
9706
9807
|
return await got(serverUrl, {
|
|
9707
9808
|
method: "POST",
|
|
9809
|
+
followRedirect: false,
|
|
9708
9810
|
https: {
|
|
9709
9811
|
rejectUnauthorized: !args.skipDtTlsCheck,
|
|
9710
9812
|
},
|
|
9711
9813
|
headers: {
|
|
9712
|
-
"X-Api-Key": args.apiKey,
|
|
9814
|
+
"X-Api-Key": (args.apiKey || "").replace(/[\r\n]/g, ""),
|
|
9713
9815
|
"Content-Type": "application/json",
|
|
9714
9816
|
"user-agent": `@CycloneDX/cdxgen ${CDXGEN_VERSION}`,
|
|
9715
9817
|
},
|