@cyclonedx/cdxgen 10.7.0 → 10.8.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 +69 -90
- package/bin/cdxgen.js +37 -23
- package/bin/repl.js +10 -2
- package/binary.js +1 -0
- package/data/lic-mapping.json +6 -3
- package/display.js +32 -0
- package/docker.js +76 -10
- package/evinser.js +7 -4
- package/index.js +475 -449
- package/package.json +5 -5
- package/postgen.js +52 -0
- package/server.js +1 -1
- package/types/binary.d.ts.map +1 -1
- package/types/db.d.ts.map +1 -1
- package/types/display.d.ts +1 -0
- package/types/display.d.ts.map +1 -1
- package/types/docker.d.ts +4 -0
- package/types/docker.d.ts.map +1 -1
- package/types/evinser.d.ts +340 -478
- package/types/evinser.d.ts.map +1 -1
- package/types/index.d.ts.map +1 -1
- package/types/postgen.d.ts +1 -0
- package/types/postgen.d.ts.map +1 -1
- package/types/utils.d.ts +38 -0
- package/types/utils.d.ts.map +1 -1
- package/utils.js +218 -26
- package/utils.test.js +226 -8
package/README.md
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
[![SWH][badge-swh]][swh-cdxgen]
|
|
8
8
|
[![Libraries.io dependency status][badge-libraries]][librariesio]
|
|
9
9
|
|
|
10
|
-
|
|
11
10
|
# CycloneDX Generator (cdxgen)
|
|
12
11
|
|
|
13
12
|

|
|
@@ -51,16 +50,6 @@ Sections include:
|
|
|
51
50
|
- [Permissions][docs-permissions]
|
|
52
51
|
- [Support (Enterprise & Community)][docs-support]
|
|
53
52
|
|
|
54
|
-
### Automatic usage detection
|
|
55
|
-
|
|
56
|
-
For node.js projects, lock files are parsed initially, so the SBOM would include all dependencies, including dev ones. An AST parser powered by babel-parser is then used to detect packages that are imported and used by non-test code. Such imported packages would automatically set their scope property to `required` in the resulting SBOM. You can turn off this analysis by passing the argument `--no-babel`. Scope property would then be set based on the `dev` attribute in the lock file.
|
|
57
|
-
|
|
58
|
-
This attribute can be later used for various purposes. For example, [dep-scan][depscan-github] uses this attribute to prioritize vulnerabilities. Unfortunately, tools such as dependency track, do not include this feature and might over-report the CVEs.
|
|
59
|
-
|
|
60
|
-
With the argument `--required-only`, you can limit the SBOM only to include packages with the scope "required", commonly called production or non-dev dependencies. Combine with `--no-babel` to limit this list to only non-dev dependencies based on the `dev` attribute being false in the lock files.
|
|
61
|
-
|
|
62
|
-
For go, `go mod why` command is used to identify required packages. For php, composer lock file is parsed to distinguish required (packages) from optional (packages-dev).
|
|
63
|
-
|
|
64
53
|
## Usage
|
|
65
54
|
|
|
66
55
|
## Installing
|
|
@@ -110,88 +99,68 @@ import { createBom, submitBom } from "npm:@cyclonedx/cdxgen@^9.0.1";
|
|
|
110
99
|
## Getting Help
|
|
111
100
|
|
|
112
101
|
```text
|
|
113
|
-
|
|
102
|
+
cdxgen [command]
|
|
103
|
+
|
|
104
|
+
Commands:
|
|
105
|
+
cdxgen completion Generate bash/zsh completion
|
|
106
|
+
|
|
114
107
|
Options:
|
|
115
|
-
-o, --output Output file. Default bom.json
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
-r, --recurse Recurse mode suitable for mono-repos. Defaults to
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
--
|
|
127
|
-
e scanning C/C++ apps, live OS and oci images.
|
|
128
|
-
[boolean]
|
|
129
|
-
--server-url Dependency track url. Eg: https://deptrack.cyclon
|
|
130
|
-
edx.io
|
|
108
|
+
-o, --output Output file. Default bom.json [default: "bom.json"]
|
|
109
|
+
-t, --type Project type. Please refer to https://cyclonedx.github.io/cdxgen/#/PROJECT_TYPES for supp
|
|
110
|
+
orted languages/platforms. [array]
|
|
111
|
+
--exclude-type Project types to exclude. Please refer to https://cyclonedx.github.io/cdxgen/#/PROJECT_TY
|
|
112
|
+
PES for supported languages/platforms.
|
|
113
|
+
-r, --recurse Recurse mode suitable for mono-repos. Defaults to true. Pass --no-recurse to disable.
|
|
114
|
+
[boolean] [default: true]
|
|
115
|
+
-p, --print Print the SBOM as a table with tree. [boolean]
|
|
116
|
+
-c, --resolve-class Resolve class names for packages. jars only for now. [boolean]
|
|
117
|
+
--deep Perform deep searches for components. Useful while scanning C/C++ apps, live OS and oci i
|
|
118
|
+
mages. [boolean]
|
|
119
|
+
--server-url Dependency track url. Eg: https://deptrack.cyclonedx.io
|
|
131
120
|
--api-key Dependency track api key
|
|
132
121
|
--project-group Dependency track project group
|
|
133
|
-
--project-name Dependency track project name. Default use the
|
|
134
|
-
|
|
135
|
-
--project-
|
|
136
|
-
|
|
137
|
-
--project-id
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
--
|
|
141
|
-
--
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
--
|
|
146
|
-
--
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
.
|
|
151
|
-
--
|
|
152
|
-
--
|
|
153
|
-
--
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
--
|
|
164
|
-
to
|
|
165
|
-
--
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
--
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
c.
|
|
176
|
-
[choices: "appsec", "research", "operational", "threat-modeling", "license-com
|
|
177
|
-
pliance", "generic"] [default: "generic"]
|
|
178
|
-
--exclude Additional glob pattern(s) to ignore [array]
|
|
179
|
-
--include-formulation Generate formulation section using git metadata.
|
|
180
|
-
[boolean] [default: false]
|
|
181
|
-
--include-crypto Include crypto libraries found under formulation.
|
|
182
|
-
[boolean] [default: false]
|
|
183
|
-
--standard The list of standards which may consist of regula
|
|
184
|
-
tions, industry or organizational-specific standa
|
|
185
|
-
rds, maturity models, best practices, or any othe
|
|
186
|
-
r requirements which can be evaluated against or
|
|
187
|
-
attested to.
|
|
188
|
-
[array] [choices: "asvs-4.0.3", "bsimm-v13", "masvs-2.0.0", "nist_ssdf-1.1", "
|
|
189
|
-
pcissc-secure-slc-1.1", "scvs-1.0.0", "ssaf-DRAFT-2023-11"]
|
|
190
|
-
--auto-compositions Automatically set compositions when the BOM was f
|
|
191
|
-
iltered. Defaults to true
|
|
192
|
-
[boolean] [default: true]
|
|
193
|
-
-h, --help Show help [boolean]
|
|
194
|
-
-v, --version Show version number [boolean]
|
|
122
|
+
--project-name Dependency track project name. Default use the directory name
|
|
123
|
+
--project-version Dependency track project version [string] [default: ""]
|
|
124
|
+
--project-id Dependency track project id. Either provide the id or the project name and version togeth
|
|
125
|
+
er [string]
|
|
126
|
+
--parent-project-id Dependency track parent project id [string]
|
|
127
|
+
--required-only Include only the packages with required scope on the SBOM. Would set compositions.aggrega
|
|
128
|
+
te to incomplete unless --no-auto-compositions is passed. [boolean]
|
|
129
|
+
--fail-on-error Fail if any dependency extractor fails. [boolean]
|
|
130
|
+
--no-babel Do not use babel to perform usage analysis for JavaScript/TypeScript projects. [boolean]
|
|
131
|
+
--generate-key-and-sign Generate an RSA public/private key pair and then sign the generated SBOM using JSON Web S
|
|
132
|
+
ignatures. [boolean]
|
|
133
|
+
--server Run cdxgen as a server [boolean]
|
|
134
|
+
--server-host Listen address [default: "127.0.0.1"]
|
|
135
|
+
--server-port Listen port [default: "9090"]
|
|
136
|
+
--install-deps Install dependencies automatically for some projects. Defaults to true but disabled for c
|
|
137
|
+
ontainers and oci scans. Use --no-install-deps to disable this feature. [boolean]
|
|
138
|
+
--validate Validate the generated SBOM using json schema. Defaults to true. Pass --no-validate to di
|
|
139
|
+
sable. [boolean] [default: true]
|
|
140
|
+
--evidence Generate SBOM with evidence for supported languages. [boolean] [default: false]
|
|
141
|
+
--spec-version CycloneDX Specification version to use. Defaults to 1.5 [number] [default: 1.5]
|
|
142
|
+
--filter Filter components containing this word in purl or component.properties.value. Multiple va
|
|
143
|
+
lues allowed. [array]
|
|
144
|
+
--only Include components only containing this word in purl. Useful to generate BOM with first p
|
|
145
|
+
arty components alone. Multiple values allowed. [array]
|
|
146
|
+
--author The person(s) who created the BOM. Set this value if you're intending the modify the BOM
|
|
147
|
+
and claim authorship. [array] [default: "OWASP Foundation"]
|
|
148
|
+
--profile BOM profile to use for generation. Default generic.
|
|
149
|
+
[choices: "appsec", "research", "operational", "threat-modeling", "license-compliance", "generic"] [default: "generic"
|
|
150
|
+
]
|
|
151
|
+
--exclude Additional glob pattern(s) to ignore [array]
|
|
152
|
+
--include-formulation Generate formulation section with git metadata and build tools. Defaults to true. Invoke
|
|
153
|
+
with --no-include-formulation to disable. [boolean] [default: true]
|
|
154
|
+
--include-crypto Include crypto libraries found under formulation. [boolean] [default: false]
|
|
155
|
+
--standard The list of standards which may consist of regulations, industry or organizational-specif
|
|
156
|
+
ic standards, maturity models, best practices, or any other requirements which can be eva
|
|
157
|
+
luated against or attested to.
|
|
158
|
+
[array] [choices: "asvs-4.0.3", "bsimm-v13", "masvs-2.0.0", "nist_ssdf-1.1", "pcissc-secure-slc-1.1", "scvs-1.0.0", "s
|
|
159
|
+
saf-DRAFT-2023-11"]
|
|
160
|
+
--auto-compositions Automatically set compositions when the BOM was filtered. Defaults to true
|
|
161
|
+
[boolean] [default: true]
|
|
162
|
+
-h, --help Show help [boolean]
|
|
163
|
+
-v, --version Show version number [boolean]
|
|
195
164
|
```
|
|
196
165
|
|
|
197
166
|
All boolean arguments accept `--no` prefix to toggle the behavior.
|
|
@@ -473,6 +442,16 @@ if (validationResult) {
|
|
|
473
442
|
}
|
|
474
443
|
```
|
|
475
444
|
|
|
445
|
+
## Automatic usage detection
|
|
446
|
+
|
|
447
|
+
For node.js projects, lock files are parsed initially, so the SBOM would include all dependencies, including dev ones. An AST parser powered by babel-parser is then used to detect packages that are imported and used by non-test code. Such imported packages would automatically set their scope property to `required` in the resulting SBOM. You can turn off this analysis by passing the argument `--no-babel`. Scope property would then be set based on the `dev` attribute in the lock file.
|
|
448
|
+
|
|
449
|
+
This attribute can be later used for various purposes. For example, [dep-scan][depscan-github] uses this attribute to prioritize vulnerabilities. Unfortunately, tools such as dependency track, do not include this feature and might over-report the CVEs.
|
|
450
|
+
|
|
451
|
+
With the argument `--required-only`, you can limit the SBOM only to include packages with the scope "required", commonly called production or non-dev dependencies. Combine with `--no-babel` to limit this list to only non-dev dependencies based on the `dev` attribute being false in the lock files.
|
|
452
|
+
|
|
453
|
+
For go, `go mod why` command is used to identify required packages. For php, composer lock file is parsed to distinguish required (packages) from optional (packages-dev).
|
|
454
|
+
|
|
476
455
|
## Automatic services detection
|
|
477
456
|
|
|
478
457
|
cdxgen can automatically detect names of services from YAML manifests such as docker-compose, Kubernetes, or Skaffold manifests. These would be populated under the `services` attribute in the generated SBOM. With [evinse](./ADVANCED.md), additional services could be detected by parsing common annotations from the source code.
|
package/bin/cdxgen.js
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
printReachables,
|
|
18
18
|
printServices,
|
|
19
19
|
printSponsorBanner,
|
|
20
|
+
printSummary,
|
|
20
21
|
printTable,
|
|
21
22
|
} from "../display.js";
|
|
22
23
|
import { createBom, submitBom } from "../index.js";
|
|
@@ -55,6 +56,10 @@ import { hideBin } from "yargs/helpers";
|
|
|
55
56
|
|
|
56
57
|
const args = yargs(hideBin(process.argv))
|
|
57
58
|
.env("CDXGEN")
|
|
59
|
+
.parserConfiguration({
|
|
60
|
+
"greedy-arrays": false,
|
|
61
|
+
"short-option-groups": false,
|
|
62
|
+
})
|
|
58
63
|
.option("output", {
|
|
59
64
|
alias: "o",
|
|
60
65
|
description: "Output file. Default bom.json",
|
|
@@ -63,7 +68,6 @@ const args = yargs(hideBin(process.argv))
|
|
|
63
68
|
.option("evinse-output", {
|
|
64
69
|
description:
|
|
65
70
|
"Create bom with evidence as a separate file. Default bom.json",
|
|
66
|
-
default: "bom.json",
|
|
67
71
|
hidden: true,
|
|
68
72
|
})
|
|
69
73
|
.option("type", {
|
|
@@ -71,6 +75,10 @@ const args = yargs(hideBin(process.argv))
|
|
|
71
75
|
description:
|
|
72
76
|
"Project type. Please refer to https://cyclonedx.github.io/cdxgen/#/PROJECT_TYPES for supported languages/platforms.",
|
|
73
77
|
})
|
|
78
|
+
.option("exclude-type", {
|
|
79
|
+
description:
|
|
80
|
+
"Project types to exclude. Please refer to https://cyclonedx.github.io/cdxgen/#/PROJECT_TYPES for supported languages/platforms.",
|
|
81
|
+
})
|
|
74
82
|
.option("recurse", {
|
|
75
83
|
alias: "r",
|
|
76
84
|
type: "boolean",
|
|
@@ -238,8 +246,9 @@ const args = yargs(hideBin(process.argv))
|
|
|
238
246
|
})
|
|
239
247
|
.option("include-formulation", {
|
|
240
248
|
type: "boolean",
|
|
241
|
-
default:
|
|
242
|
-
description:
|
|
249
|
+
default: true,
|
|
250
|
+
description:
|
|
251
|
+
"Generate formulation section with git metadata and build tools. Defaults to true. Invoke with --no-include-formulation to disable.",
|
|
243
252
|
})
|
|
244
253
|
.option("include-crypto", {
|
|
245
254
|
type: "boolean",
|
|
@@ -262,10 +271,13 @@ const args = yargs(hideBin(process.argv))
|
|
|
262
271
|
.option("no-banner", {
|
|
263
272
|
type: "boolean",
|
|
264
273
|
default: false,
|
|
274
|
+
hidden: true,
|
|
265
275
|
description:
|
|
266
276
|
"Do not show the donation banner. Set this attribute if you are an active sponsor for OWASP CycloneDX.",
|
|
267
277
|
})
|
|
268
278
|
.completion("completion", "Generate bash/zsh completion")
|
|
279
|
+
.array("type")
|
|
280
|
+
.array("excludeType")
|
|
269
281
|
.array("filter")
|
|
270
282
|
.array("only")
|
|
271
283
|
.array("author")
|
|
@@ -279,6 +291,10 @@ const args = yargs(hideBin(process.argv))
|
|
|
279
291
|
})
|
|
280
292
|
.example([
|
|
281
293
|
["$0 -t java .", "Generate a Java SBOM for the current directory"],
|
|
294
|
+
[
|
|
295
|
+
"$0 -t java -t js .",
|
|
296
|
+
"Generate a SBOM for Java and JavaScript in the current directory",
|
|
297
|
+
],
|
|
282
298
|
["$0 --server", "Run cdxgen as a server"],
|
|
283
299
|
])
|
|
284
300
|
.epilogue("for documentation, visit https://cyclonedx.github.io/cdxgen")
|
|
@@ -369,7 +385,11 @@ const applyAdvancedOptions = (options) => {
|
|
|
369
385
|
process.env.ASTGEN_IGNORE_FILE_PATTERN = "";
|
|
370
386
|
break;
|
|
371
387
|
case "operational":
|
|
372
|
-
|
|
388
|
+
if (options?.projectType) {
|
|
389
|
+
options.projectType.push("os");
|
|
390
|
+
} else {
|
|
391
|
+
options.projectType = ["os"];
|
|
392
|
+
}
|
|
373
393
|
break;
|
|
374
394
|
case "threat-modeling":
|
|
375
395
|
options.deep = true;
|
|
@@ -388,6 +408,8 @@ const applyAdvancedOptions = (options) => {
|
|
|
388
408
|
case "post-build":
|
|
389
409
|
if (
|
|
390
410
|
!options.projectType ||
|
|
411
|
+
(Array.isArray(options.projectType) &&
|
|
412
|
+
options.projectType.length > 1) ||
|
|
391
413
|
![
|
|
392
414
|
"csharp",
|
|
393
415
|
"dotnet",
|
|
@@ -403,7 +425,7 @@ const applyAdvancedOptions = (options) => {
|
|
|
403
425
|
"rust",
|
|
404
426
|
"rust-lang",
|
|
405
427
|
"cargo",
|
|
406
|
-
].includes(options.projectType)
|
|
428
|
+
].includes(options.projectType[0])
|
|
407
429
|
) {
|
|
408
430
|
console.log(
|
|
409
431
|
"PREVIEW: post-build lifecycle SBOM generation is supported only for android, dotnet, go, and Rust projects. Please specify the type using the -t argument.",
|
|
@@ -473,14 +495,8 @@ const checkPermissions = (filePath) => {
|
|
|
473
495
|
options.usagesSlicesFile = `${options.projectName}-usages.json`;
|
|
474
496
|
}
|
|
475
497
|
let bomNSData = (await createBom(filePath, options)) || {};
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
options["filter"] ||
|
|
479
|
-
options["only"] ||
|
|
480
|
-
options.standard
|
|
481
|
-
) {
|
|
482
|
-
bomNSData = postProcess(bomNSData, options);
|
|
483
|
-
}
|
|
498
|
+
// Add extra metadata and annotations with post processing
|
|
499
|
+
bomNSData = postProcess(bomNSData, options);
|
|
484
500
|
if (
|
|
485
501
|
options.output &&
|
|
486
502
|
(typeof options.output === "string" || options.output instanceof String)
|
|
@@ -496,15 +512,7 @@ const checkPermissions = (filePath) => {
|
|
|
496
512
|
fs.writeFileSync(jsonFile, bomNSData.bomJson);
|
|
497
513
|
jsonPayload = bomNSData.bomJson;
|
|
498
514
|
} else {
|
|
499
|
-
jsonPayload = JSON.stringify(
|
|
500
|
-
bomNSData.bomJson,
|
|
501
|
-
null,
|
|
502
|
-
options.deep ||
|
|
503
|
-
["os", "docker", "universal"].includes(options.projectType) ||
|
|
504
|
-
process.env.CI
|
|
505
|
-
? null
|
|
506
|
-
: 2,
|
|
507
|
-
);
|
|
515
|
+
jsonPayload = JSON.stringify(bomNSData.bomJson, null, null);
|
|
508
516
|
fs.writeFileSync(jsonFile, jsonPayload);
|
|
509
517
|
}
|
|
510
518
|
if (
|
|
@@ -643,12 +651,17 @@ const checkPermissions = (filePath) => {
|
|
|
643
651
|
}
|
|
644
652
|
// Evidence generation
|
|
645
653
|
if (options.evidence || options.includeCrypto) {
|
|
654
|
+
// Set the evinse output file to be the same as output file
|
|
655
|
+
if (!options.evinseOutput) {
|
|
656
|
+
options.evinseOutput = options.output;
|
|
657
|
+
}
|
|
646
658
|
const evinserModule = await import("../evinser.js");
|
|
659
|
+
options.projectType = options.projectType || ["java"];
|
|
647
660
|
const evinseOptions = {
|
|
648
661
|
_: args._,
|
|
649
662
|
input: options.output,
|
|
650
663
|
output: options.evinseOutput,
|
|
651
|
-
language: options.projectType
|
|
664
|
+
language: options.projectType,
|
|
652
665
|
dbPath: process.env.ATOM_DB || ATOM_DB,
|
|
653
666
|
skipMavenCollector: false,
|
|
654
667
|
force: false,
|
|
@@ -699,6 +712,7 @@ const checkPermissions = (filePath) => {
|
|
|
699
712
|
protobomModule.writeBinary(bomNSData.bomJson, options.protoBinFile);
|
|
700
713
|
}
|
|
701
714
|
if (options.print && bomNSData.bomJson && bomNSData.bomJson.components) {
|
|
715
|
+
printSummary(bomNSData.bomJson);
|
|
702
716
|
printDependencyTree(bomNSData.bomJson);
|
|
703
717
|
printTable(bomNSData.bomJson);
|
|
704
718
|
// CBOM related print
|
package/bin/repl.js
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
printOSTable,
|
|
14
14
|
printOccurrences,
|
|
15
15
|
printServices,
|
|
16
|
+
printSummary,
|
|
16
17
|
printTable,
|
|
17
18
|
printVulnerabilities,
|
|
18
19
|
} from "../display.js";
|
|
@@ -67,6 +68,7 @@ export const importSbom = (sbomOrPath) => {
|
|
|
67
68
|
bomType = "VDR";
|
|
68
69
|
}
|
|
69
70
|
console.log(`✅ ${bomType} imported successfully from ${sbomOrPath}`);
|
|
71
|
+
printSummary(sbom);
|
|
70
72
|
} catch (e) {
|
|
71
73
|
console.log(`⚠ Unable to import the BOM from ${sbomOrPath} due to ${e}`);
|
|
72
74
|
}
|
|
@@ -161,9 +163,15 @@ cdxgenRepl.defineCommand("search", {
|
|
|
161
163
|
searchStr = `components[group ~> /${searchStr}/i or name ~> /${searchStr}/i or description ~> /${searchStr}/i or publisher ~> /${searchStr}/i or purl ~> /${searchStr}/i]`;
|
|
162
164
|
}
|
|
163
165
|
const expression = jsonata(searchStr);
|
|
164
|
-
|
|
166
|
+
let components = await expression.evaluate(sbom);
|
|
165
167
|
const dexpression = jsonata(dependenciesSearchStr);
|
|
166
|
-
|
|
168
|
+
let dependencies = await dexpression.evaluate(sbom);
|
|
169
|
+
if (components && !Array.isArray(components)) {
|
|
170
|
+
components = [components];
|
|
171
|
+
}
|
|
172
|
+
if (dependencies && !Array.isArray(dependencies)) {
|
|
173
|
+
dependencies = [dependencies];
|
|
174
|
+
}
|
|
167
175
|
if (!components) {
|
|
168
176
|
console.log("No results found!");
|
|
169
177
|
} else {
|
package/binary.js
CHANGED
package/data/lic-mapping.json
CHANGED
|
@@ -17,9 +17,7 @@
|
|
|
17
17
|
"Apache Public License 2.0",
|
|
18
18
|
"Apache Software License - Version 2.0",
|
|
19
19
|
"The Apache License, Version 2.0",
|
|
20
|
-
"BSD or Apache License, Version 2.0",
|
|
21
20
|
"Apache Software License",
|
|
22
|
-
"Apache-2.0 OR MIT",
|
|
23
21
|
"Apache2.0",
|
|
24
22
|
"apache-2-0",
|
|
25
23
|
"APL2",
|
|
@@ -241,7 +239,8 @@
|
|
|
241
239
|
"GNU General Public License v2.0 or later",
|
|
242
240
|
"GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version",
|
|
243
241
|
"GNU GPLv2 or any later version",
|
|
244
|
-
"GPLv2+"
|
|
242
|
+
"GPLv2+",
|
|
243
|
+
"GNU General Public License v2 or later (GPLv2+)"
|
|
245
244
|
]
|
|
246
245
|
},
|
|
247
246
|
{
|
|
@@ -287,6 +286,10 @@
|
|
|
287
286
|
"GNU Affero General Public License v3.0"
|
|
288
287
|
]
|
|
289
288
|
},
|
|
289
|
+
{
|
|
290
|
+
"exp": "MIT-0",
|
|
291
|
+
"names": ["MIT No Attribution License (MIT-0)", "MIT No Attribution"]
|
|
292
|
+
},
|
|
290
293
|
{
|
|
291
294
|
"exp": "MIT",
|
|
292
295
|
"names": [
|
package/display.js
CHANGED
|
@@ -405,3 +405,35 @@ export function printSponsorBanner(options) {
|
|
|
405
405
|
console.log(table(data, config));
|
|
406
406
|
}
|
|
407
407
|
}
|
|
408
|
+
|
|
409
|
+
export const printSummary = (bomJson) => {
|
|
410
|
+
const config = {
|
|
411
|
+
header: {
|
|
412
|
+
alignment: "center",
|
|
413
|
+
content: "BOM summary",
|
|
414
|
+
},
|
|
415
|
+
};
|
|
416
|
+
const metadataProperties = bomJson?.metadata?.properties;
|
|
417
|
+
if (!metadataProperties) {
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
let bomPkgTypes = [];
|
|
421
|
+
let bomPkgNamespaces = [];
|
|
422
|
+
for (const aprop of metadataProperties) {
|
|
423
|
+
if (aprop.name === "cdx:bom:componentTypes") {
|
|
424
|
+
bomPkgTypes = aprop?.value.split("\\n");
|
|
425
|
+
}
|
|
426
|
+
if (aprop.name === "cdx:bom:componentNamespaces") {
|
|
427
|
+
bomPkgNamespaces = aprop?.value.split("\\n");
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
if (!bomPkgTypes.length && !bomPkgNamespaces.length) {
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
let message = `** Package Types (${bomPkgTypes.length}) **\n${bomPkgTypes.join("\n")}`;
|
|
434
|
+
if (bomPkgNamespaces.length) {
|
|
435
|
+
message = `${message}\n\n** Namespaces (${bomPkgNamespaces.length}) **\n${bomPkgNamespaces.join("\n")}`;
|
|
436
|
+
}
|
|
437
|
+
const data = [[message]];
|
|
438
|
+
console.log(table(data, config));
|
|
439
|
+
};
|
package/docker.js
CHANGED
|
@@ -37,6 +37,7 @@ let isDockerRootless = false;
|
|
|
37
37
|
let isContainerd = !!process.env.CONTAINERD_ADDRESS;
|
|
38
38
|
const WIN_LOCAL_TLS = "http://localhost:2375";
|
|
39
39
|
let isWinLocalTLS = false;
|
|
40
|
+
let isNerdctl = undefined;
|
|
40
41
|
|
|
41
42
|
if (
|
|
42
43
|
!process.env.DOCKER_HOST &&
|
|
@@ -49,6 +50,56 @@ if (
|
|
|
49
50
|
isContainerd = true;
|
|
50
51
|
}
|
|
51
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Detect if Rancher desktop is running on a mac.
|
|
55
|
+
*/
|
|
56
|
+
export function detectRancherDesktop() {
|
|
57
|
+
// Detect Rancher desktop and nerdctl on a mac
|
|
58
|
+
if (_platform() === "darwin") {
|
|
59
|
+
const limaHome = join(
|
|
60
|
+
homedir(),
|
|
61
|
+
"Library",
|
|
62
|
+
"Application Support",
|
|
63
|
+
"rancher-desktop",
|
|
64
|
+
"lima",
|
|
65
|
+
);
|
|
66
|
+
const limactl = join(
|
|
67
|
+
"/Applications",
|
|
68
|
+
"Rancher Desktop.app",
|
|
69
|
+
"Contents",
|
|
70
|
+
"Resources",
|
|
71
|
+
"resources",
|
|
72
|
+
"darwin",
|
|
73
|
+
"lima",
|
|
74
|
+
"bin",
|
|
75
|
+
"limactl",
|
|
76
|
+
);
|
|
77
|
+
// Is Rancher Desktop running
|
|
78
|
+
if (existsSync(limactl) || existsSync(limaHome)) {
|
|
79
|
+
const result = spawnSync("rdctl", ["list-settings"], {
|
|
80
|
+
encoding: "utf-8",
|
|
81
|
+
});
|
|
82
|
+
if (result.status !== 0 || result.error) {
|
|
83
|
+
if (
|
|
84
|
+
isNerdctl === undefined &&
|
|
85
|
+
result.stderr?.includes("connection refused")
|
|
86
|
+
) {
|
|
87
|
+
console.warn(
|
|
88
|
+
"Ensure Rancher Desktop is running prior to invoking cdxgen. To start from the command line, type the command 'rdctl start'",
|
|
89
|
+
);
|
|
90
|
+
isNerdctl = false;
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
if (DEBUG_MODE) {
|
|
94
|
+
console.log("Rancher Desktop found!");
|
|
95
|
+
}
|
|
96
|
+
isNerdctl = true;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return isNerdctl;
|
|
101
|
+
}
|
|
102
|
+
|
|
52
103
|
// Cache the registry auth keys
|
|
53
104
|
const registry_auth_keys = {};
|
|
54
105
|
|
|
@@ -288,7 +339,7 @@ const getDefaultOptions = (forRegistry) => {
|
|
|
288
339
|
};
|
|
289
340
|
|
|
290
341
|
export const getConnection = async (options, forRegistry) => {
|
|
291
|
-
if (isContainerd) {
|
|
342
|
+
if (isContainerd || isNerdctl) {
|
|
292
343
|
return undefined;
|
|
293
344
|
}
|
|
294
345
|
if (!dockerConn) {
|
|
@@ -368,10 +419,15 @@ export const getConnection = async (options, forRegistry) => {
|
|
|
368
419
|
"Ensure Docker for Desktop is running as an administrator with 'Exposing daemon on TCP without TLS' setting turned on.",
|
|
369
420
|
opts,
|
|
370
421
|
);
|
|
371
|
-
} else if (_platform() === "darwin") {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
422
|
+
} else if (_platform() === "darwin" && !isNerdctl) {
|
|
423
|
+
if (detectRancherDesktop()) {
|
|
424
|
+
return undefined;
|
|
425
|
+
}
|
|
426
|
+
if (isNerdctl === undefined) {
|
|
427
|
+
console.warn(
|
|
428
|
+
"Ensure Podman Desktop (open-source) or Docker for Desktop (May require subscription) is running.",
|
|
429
|
+
);
|
|
430
|
+
}
|
|
375
431
|
} else {
|
|
376
432
|
console.warn(
|
|
377
433
|
"Ensure docker/podman service or Docker for Desktop is running.",
|
|
@@ -497,11 +553,14 @@ export const parseImageName = (fullImageName) => {
|
|
|
497
553
|
};
|
|
498
554
|
|
|
499
555
|
/**
|
|
500
|
-
* Prefer cli on windows or when using tcp/ssh based host.
|
|
556
|
+
* Prefer cli on windows, nerdctl on mac, or when using tcp/ssh based host.
|
|
501
557
|
*
|
|
502
558
|
* @returns boolean true if we should use the cli. false otherwise
|
|
503
559
|
*/
|
|
504
560
|
const needsCliFallback = () => {
|
|
561
|
+
if (_platform() === "darwin" && detectRancherDesktop()) {
|
|
562
|
+
return true;
|
|
563
|
+
}
|
|
505
564
|
return (
|
|
506
565
|
isWin ||
|
|
507
566
|
(process.env.DOCKER_HOST &&
|
|
@@ -532,7 +591,10 @@ export const getImage = async (fullImageName) => {
|
|
|
532
591
|
return undefined;
|
|
533
592
|
}
|
|
534
593
|
if (needsCliFallback()) {
|
|
535
|
-
|
|
594
|
+
let dockerCmd = process.env.DOCKER_CMD || "docker";
|
|
595
|
+
if (!process.env.DOCKER_CMD && detectRancherDesktop()) {
|
|
596
|
+
dockerCmd = "nerdctl";
|
|
597
|
+
}
|
|
536
598
|
let result = spawnSync(dockerCmd, ["pull", fullImageName], {
|
|
537
599
|
encoding: "utf-8",
|
|
538
600
|
});
|
|
@@ -956,14 +1018,18 @@ export const exportImage = async (fullImageName) => {
|
|
|
956
1018
|
let manifestFile = join(tempDir, "manifest.json");
|
|
957
1019
|
// Windows containers use index.json
|
|
958
1020
|
const manifestIndexFile = join(tempDir, "index.json");
|
|
959
|
-
// On Windows, fallback to invoking cli
|
|
1021
|
+
// On Windows or on mac with Rancher Desktop, fallback to invoking cli
|
|
960
1022
|
if (needsCliFallback()) {
|
|
961
1023
|
const imageTarFile = join(tempDir, "image.tar");
|
|
1024
|
+
let dockerCmd = process.env.DOCKER_CMD || "docker";
|
|
1025
|
+
if (!process.env.DOCKER_CMD && detectRancherDesktop()) {
|
|
1026
|
+
dockerCmd = "nerdctl";
|
|
1027
|
+
}
|
|
962
1028
|
console.log(
|
|
963
|
-
`About to export image ${fullImageName} to ${imageTarFile} using
|
|
1029
|
+
`About to export image ${fullImageName} to ${imageTarFile} using ${dockerCmd} cli`,
|
|
964
1030
|
);
|
|
965
1031
|
const result = spawnSync(
|
|
966
|
-
|
|
1032
|
+
dockerCmd,
|
|
967
1033
|
["save", "-o", imageTarFile, fullImageName],
|
|
968
1034
|
{
|
|
969
1035
|
encoding: "utf-8",
|
package/evinser.js
CHANGED
|
@@ -202,7 +202,7 @@ export const createAndStoreSlice = async (
|
|
|
202
202
|
};
|
|
203
203
|
|
|
204
204
|
export const createSlice = (
|
|
205
|
-
|
|
205
|
+
purlOrLanguages,
|
|
206
206
|
filePath,
|
|
207
207
|
sliceType = "usages",
|
|
208
208
|
options = {},
|
|
@@ -215,9 +215,12 @@ export const createSlice = (
|
|
|
215
215
|
filePath,
|
|
216
216
|
)}. Please wait ...`,
|
|
217
217
|
);
|
|
218
|
-
const
|
|
219
|
-
?
|
|
220
|
-
:
|
|
218
|
+
const firstLanguage = Array.isArray(purlOrLanguages)
|
|
219
|
+
? purlOrLanguages[0]
|
|
220
|
+
: purlOrLanguages;
|
|
221
|
+
const language = firstLanguage.startsWith("pkg:")
|
|
222
|
+
? purlToLanguage(firstLanguage, filePath)
|
|
223
|
+
: firstLanguage;
|
|
221
224
|
if (!language) {
|
|
222
225
|
return undefined;
|
|
223
226
|
}
|