@cyclonedx/cdxgen 9.8.10 → 9.9.1
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 +43 -41
- package/analyzer.js +6 -2
- package/bin/cdxgen.js +78 -17
- package/bin/evinse.js +44 -22
- package/bin/verify.js +2 -0
- package/binary.js +20 -2
- package/data/README.md +1 -0
- package/data/frameworks-list.json +146 -0
- package/data/lic-mapping.json +44 -5
- package/data/pypi-pkg-aliases.json +6 -0
- package/display.js +34 -0
- package/docker.js +64 -5
- package/evinser.js +254 -55
- package/index.js +128 -90
- package/package.json +5 -5
- package/server.js +34 -21
- package/utils.js +695 -262
- package/utils.test.js +81 -7
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
cdxgen is a
|
|
5
|
+
cdxgen is a CLI tool, library, [REPL](./ADVANCED.md), and server to create a valid and compliant [CycloneDX][cyclonedx-homepage] Software Bill of Materials (SBOM) containing an aggregate of all project dependencies for C/C++, Node.js, PHP, Python, Ruby, Rust, Java, .Net, Dart, Haskell, Elixir, and Go projects in JSON format. CycloneDX 1.5 is a lightweight SBOM specification that is easily created, human and machine-readable, and simple to parse.
|
|
6
6
|
|
|
7
7
|
When used with plugins, cdxgen could generate an OBOM for Linux docker images and even VMs running Linux or Windows operating systems. cdxgen also includes an evinse tool to generate component evidence and SaaSBOM for some languages.
|
|
8
8
|
|
|
@@ -12,45 +12,45 @@ CycloneDX 1.5 specification is new and unsupported by many downstream tools. Use
|
|
|
12
12
|
|
|
13
13
|
## Why cdxgen?
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Most SBOM tools are like barcode scanners. They can scan a few package manifest and create a list of components only based on these files without any deep inspection. Further, a typical application might have several repos, components, and libraries. Traditional techniques to generate a SBOM per language or package manifest either do not work in enterprise environments or doesn't provide the confidence required for both compliance and automated analysis. So we built cdxgen - the universal polyglot SBOM generator that is both precise and comprehensive!
|
|
16
16
|
|
|
17
17
|
<img src="./docs/why-cdxgen.jpg" alt="why cdxgen" width="256">
|
|
18
18
|
|
|
19
19
|
## Supported languages and package format
|
|
20
20
|
|
|
21
|
-
| Language/Platform | Package format | Transitive dependencies |
|
|
22
|
-
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
|
23
|
-
|
|
|
24
|
-
|
|
|
25
|
-
|
|
|
26
|
-
|
|
|
27
|
-
|
|
|
28
|
-
|
|
|
29
|
-
|
|
|
30
|
-
| .Net | .csproj, packages.config, project.assets.json [3], packages.lock.json, .nupkg, paket.lock | Only for project.assets.json, packages.lock.json, paket.lock |
|
|
31
|
-
|
|
|
32
|
-
|
|
|
33
|
-
|
|
|
34
|
-
|
|
|
35
|
-
|
|
|
36
|
-
|
|
|
37
|
-
|
|
|
38
|
-
| GitHub Actions | .github/workflows/\*.yml | N/A |
|
|
39
|
-
| Linux | All supported languages. Linux OS packages with plugins [5] | Best effort based on lock files |
|
|
40
|
-
| Windows | All supported languages. OS packages with best effort [5] | Best effort based on lock files |
|
|
41
|
-
| Jenkins Plugins | .hpi files | |
|
|
42
|
-
| Helm Charts | .yaml | N/A |
|
|
43
|
-
| Skaffold | .yaml | N/A |
|
|
44
|
-
| kustomization | .yaml | N/A |
|
|
45
|
-
| Tekton tasks | .yaml | N/A |
|
|
46
|
-
| Kubernetes | .yaml | N/A |
|
|
47
|
-
| Maven Cache | $HOME/.m2/repository/\*\*/\*.jar | N/A |
|
|
48
|
-
| SBT Cache | $HOME/.ivy2/cache/\*\*/\*.jar | N/A |
|
|
49
|
-
| Gradle Cache | $HOME/caches/modules-2/files-2.1/\*\*/\*.jar | N/A |
|
|
50
|
-
| Helm Index | $HOME/.cache/helm/repository/\*\*/\*.yaml | N/A |
|
|
51
|
-
| Docker compose | docker-compose\*.yml. Images would also be scanned. | N/A |
|
|
52
|
-
| Google CloudBuild configuration | cloudbuild.yaml | N/A |
|
|
53
|
-
| OpenAPI | openapi\*.json, openapi\*.yaml | N/A |
|
|
21
|
+
| Language/Platform | Package format | Transitive dependencies | Evidence |
|
|
22
|
+
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | -------- |
|
|
23
|
+
| Node.js | npm-shrinkwrap.json, package-lock.json, pnpm-lock.yaml, yarn.lock, rush.js, bower.json, .min.js | Yes except .min.js | Yes |
|
|
24
|
+
| Java | maven (pom.xml [1]), gradle (build.gradle, .kts), scala (sbt), bazel | Yes unless pom.xml is manually parsed due to unavailability of maven or errors | Yes |
|
|
25
|
+
| PHP | composer.lock | Yes | |
|
|
26
|
+
| Python | pyproject.toml, setup.py, requirements.txt [2], Pipfile.lock, poetry.lock, pdm.lock, bdist_wheel, .whl, .egg-info | Yes using the automatic pip install/freeze. When disabled, only with Pipfile.lock and poetry.lock | Yes |
|
|
27
|
+
| Go | binary, go.mod, go.sum, Gopkg.lock | Yes except binary | Yes |
|
|
28
|
+
| Ruby | Gemfile.lock, gemspec | Only for Gemfile.lock | |
|
|
29
|
+
| Rust | binary, Cargo.toml, Cargo.lock | Only for Cargo.lock | |
|
|
30
|
+
| .Net | .csproj, packages.config, project.assets.json [3], packages.lock.json, .nupkg, paket.lock | Only for project.assets.json, packages.lock.json, paket.lock | |
|
|
31
|
+
| Dart | pubspec.lock, pubspec.yaml | Only for pubspec.lock | |
|
|
32
|
+
| Haskell | cabal.project.freeze | Yes | |
|
|
33
|
+
| Elixir | mix.lock | Yes | |
|
|
34
|
+
| C/C++/Objective C/C++11 | conan.lock, conanfile.txt, \*.cmake, CMakeLists.txt, meson.build, codebase without package managers! | Yes only for conan.lock. Best effort basis for cmake without version numbers. | Yes |
|
|
35
|
+
| Clojure | Clojure CLI (deps.edn), Leiningen (project.clj) | Yes unless the files are parsed manually due to lack of clojure cli or leiningen command | |
|
|
36
|
+
| Swift | Package.resolved, Package.swift (swiftpm) | Yes | |
|
|
37
|
+
| Docker / oci image | All supported languages. Linux OS packages with plugins [4] | Best effort based on lock files | Yes |
|
|
38
|
+
| GitHub Actions | .github/workflows/\*.yml | N/A | Yes |
|
|
39
|
+
| Linux | All supported languages. Linux OS packages with plugins [5] | Best effort based on lock files | Yes |
|
|
40
|
+
| Windows | All supported languages. OS packages with best effort [5] | Best effort based on lock files | Yes |
|
|
41
|
+
| Jenkins Plugins | .hpi files | | Yes |
|
|
42
|
+
| Helm Charts | .yaml | N/A | |
|
|
43
|
+
| Skaffold | .yaml | N/A | |
|
|
44
|
+
| kustomization | .yaml | N/A | |
|
|
45
|
+
| Tekton tasks | .yaml | N/A | |
|
|
46
|
+
| Kubernetes | .yaml | N/A | |
|
|
47
|
+
| Maven Cache | $HOME/.m2/repository/\*\*/\*.jar | N/A | |
|
|
48
|
+
| SBT Cache | $HOME/.ivy2/cache/\*\*/\*.jar | N/A | |
|
|
49
|
+
| Gradle Cache | $HOME/caches/modules-2/files-2.1/\*\*/\*.jar | N/A | |
|
|
50
|
+
| Helm Index | $HOME/.cache/helm/repository/\*\*/\*.yaml | N/A | |
|
|
51
|
+
| Docker compose | docker-compose\*.yml. Images would also be scanned. | N/A | |
|
|
52
|
+
| Google CloudBuild configuration | cloudbuild.yaml | N/A | |
|
|
53
|
+
| OpenAPI | openapi\*.json, openapi\*.yaml | N/A | |
|
|
54
54
|
|
|
55
55
|
NOTE:
|
|
56
56
|
|
|
@@ -170,10 +170,7 @@ Options:
|
|
|
170
170
|
faults to true. Pass --no-validate to disable.
|
|
171
171
|
[boolean] [default: true]
|
|
172
172
|
--evidence Generate SBOM with evidence for supported languag
|
|
173
|
-
es.
|
|
174
|
-
--usages-slices-file Path for the usages slice file created by atom.
|
|
175
|
-
--data-flow-slices-file Path for the data-flow slice file created by atom
|
|
176
|
-
.
|
|
173
|
+
es. [boolean] [default: false]
|
|
177
174
|
--spec-version CycloneDX Specification version to use. Defaults
|
|
178
175
|
to 1.5 [default: 1.5]
|
|
179
176
|
--filter Filter components containining this word in purl.
|
|
@@ -181,6 +178,9 @@ Options:
|
|
|
181
178
|
--only Include components only containining this word in
|
|
182
179
|
purl. Useful to generate BOM with first party co
|
|
183
180
|
mponents alone. Multiple values allowed. [array]
|
|
181
|
+
--author The person(s) who created the BOM. Set this value
|
|
182
|
+
if you're intending the modify the BOM and claim
|
|
183
|
+
authorship.[array] [default: "OWASP Foundation"]
|
|
184
184
|
--auto-compositions Automatically set compositions when the BOM was f
|
|
185
185
|
iltered. Defaults to true
|
|
186
186
|
[boolean] [default: true]
|
|
@@ -338,7 +338,7 @@ cdxgen can retain the dependency tree under the `dependencies` attribute for a s
|
|
|
338
338
|
- Gradle
|
|
339
339
|
- Scala SBT
|
|
340
340
|
- Python (requirements.txt, setup.py, pyproject.toml, poetry.lock)
|
|
341
|
-
-
|
|
341
|
+
- .NET (project.assets.json, paket.lock)
|
|
342
342
|
- Go (go.mod)
|
|
343
343
|
|
|
344
344
|
## Environment variables
|
|
@@ -367,6 +367,7 @@ cdxgen can retain the dependency tree under the `dependencies` attribute for a s
|
|
|
367
367
|
| USE_GOSUM | Set to `true` or `1` to generate BOMs for golang projects using go.sum as the dependency source of truth, instead of go.mod |
|
|
368
368
|
| CDXGEN_TIMEOUT_MS | Default timeout for known execution involving maven, gradle or sbt |
|
|
369
369
|
| CDXGEN_SERVER_TIMEOUT_MS | Default timeout in server mode |
|
|
370
|
+
| CDXGEN_MAX_BUFFER | Max buffer for stdout and stderr. Defaults to 100MB |
|
|
370
371
|
| CLJ_CMD | Set to override the clojure cli command |
|
|
371
372
|
| LEIN_CMD | Set to override the leiningen command |
|
|
372
373
|
| SBOM_SIGN_ALGORITHM | Signature algorithm. Some valid values are RS256, RS384, RS512, PS256, PS384, PS512, ES256 etc |
|
|
@@ -377,6 +378,7 @@ cdxgen can retain the dependency tree under the `dependencies` attribute for a s
|
|
|
377
378
|
| CDX_MAVEN_INCLUDE_TEST_SCOPE | Whether test scoped dependencies should be included from Maven projects, Default: true |
|
|
378
379
|
| ASTGEN_IGNORE_DIRS | Comma separated list of directories to ignore while analyzing using babel. The environment variable is also used by atom and astgen. |
|
|
379
380
|
| ASTGEN_IGNORE_FILE_PATTERN | Ignore regex to use |
|
|
381
|
+
| PYPI_URL | Override pypi url. Default: https://pypi.org/pypi/ |
|
|
380
382
|
|
|
381
383
|
## Plugins
|
|
382
384
|
|
|
@@ -394,7 +396,7 @@ sudo npm install -g @cyclonedx/cdxgen-plugins-bin
|
|
|
394
396
|
cdxgen odoo@sha256:4e1e147f0e6714e8f8c5806d2b484075b4076ca50490577cdf9162566086d15e -o /tmp/bom.json
|
|
395
397
|
```
|
|
396
398
|
|
|
397
|
-
You can also pass `-t docker`
|
|
399
|
+
You can also pass `-t docker` with repository names. Only the `latest` tag would be pulled if none was specified.
|
|
398
400
|
|
|
399
401
|
```shell
|
|
400
402
|
cdxgen shiftleft/scan-slim -o /tmp/bom.json -t docker
|
package/analyzer.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { parse } from "@babel/parser";
|
|
2
2
|
import traverse from "@babel/traverse";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import { readdirSync,
|
|
4
|
+
import { readdirSync, lstatSync, readFileSync } from "node:fs";
|
|
5
5
|
import { basename, resolve, isAbsolute, relative } from "node:path";
|
|
6
6
|
|
|
7
7
|
const IGNORE_DIRS = process.env.ASTGEN_IGNORE_DIRS
|
|
@@ -46,7 +46,11 @@ const getAllFiles = (dir, extn, files, result, regex) => {
|
|
|
46
46
|
continue;
|
|
47
47
|
}
|
|
48
48
|
const file = join(dir, files[i]);
|
|
49
|
-
|
|
49
|
+
const fileStat = lstatSync(file);
|
|
50
|
+
if (fileStat.isSymbolicLink()) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (fileStat.isDirectory()) {
|
|
50
54
|
// Ignore directories
|
|
51
55
|
const dirName = basename(file);
|
|
52
56
|
if (
|
package/bin/cdxgen.js
CHANGED
|
@@ -10,10 +10,19 @@ import crypto from "node:crypto";
|
|
|
10
10
|
import { fileURLToPath } from "node:url";
|
|
11
11
|
import globalAgent from "global-agent";
|
|
12
12
|
import process from "node:process";
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
printCallStack,
|
|
15
|
+
printOccurrences,
|
|
16
|
+
printServices,
|
|
17
|
+
printReachables,
|
|
18
|
+
printTable,
|
|
19
|
+
printDependencyTree
|
|
20
|
+
} from "../display.js";
|
|
14
21
|
import { findUpSync } from "find-up";
|
|
15
22
|
import { load as _load } from "js-yaml";
|
|
16
23
|
import { postProcess } from "../postgen.js";
|
|
24
|
+
import { analyzeProject, createEvinseFile, prepareDB } from "../evinser.js";
|
|
25
|
+
import { ATOM_DB } from "../utils.js";
|
|
17
26
|
|
|
18
27
|
// Support for config files
|
|
19
28
|
const configPath = findUpSync([
|
|
@@ -48,7 +57,14 @@ const args = yargs(hideBin(process.argv))
|
|
|
48
57
|
.env("CDXGEN")
|
|
49
58
|
.option("output", {
|
|
50
59
|
alias: "o",
|
|
51
|
-
description: "Output file for bom.xml or bom.json. Default bom.json"
|
|
60
|
+
description: "Output file for bom.xml or bom.json. Default bom.json",
|
|
61
|
+
default: "bom.json"
|
|
62
|
+
})
|
|
63
|
+
.option("evinse-output", {
|
|
64
|
+
description:
|
|
65
|
+
"Create bom with evidence as a separate file. Default bom.json",
|
|
66
|
+
default: "bom.json",
|
|
67
|
+
hidden: true
|
|
52
68
|
})
|
|
53
69
|
.option("type", {
|
|
54
70
|
alias: "t",
|
|
@@ -90,14 +106,17 @@ const args = yargs(hideBin(process.argv))
|
|
|
90
106
|
})
|
|
91
107
|
.option("project-version", {
|
|
92
108
|
description: "Dependency track project version",
|
|
93
|
-
default: ""
|
|
109
|
+
default: "",
|
|
110
|
+
type: "string"
|
|
94
111
|
})
|
|
95
112
|
.option("project-id", {
|
|
96
113
|
description:
|
|
97
|
-
"Dependency track project id. Either provide the id or the project name and version together"
|
|
114
|
+
"Dependency track project id. Either provide the id or the project name and version together",
|
|
115
|
+
type: "string"
|
|
98
116
|
})
|
|
99
117
|
.option("parent-project-id", {
|
|
100
|
-
description: "Dependency track parent project id"
|
|
118
|
+
description: "Dependency track parent project id",
|
|
119
|
+
type: "string"
|
|
101
120
|
})
|
|
102
121
|
.option("required-only", {
|
|
103
122
|
type: "boolean",
|
|
@@ -145,17 +164,32 @@ const args = yargs(hideBin(process.argv))
|
|
|
145
164
|
.option("evidence", {
|
|
146
165
|
type: "boolean",
|
|
147
166
|
default: false,
|
|
148
|
-
description: "Generate SBOM with evidence for supported languages.
|
|
167
|
+
description: "Generate SBOM with evidence for supported languages."
|
|
168
|
+
})
|
|
169
|
+
.option("deps-slices-file", {
|
|
170
|
+
description: "Path for the parsedeps slice file created by atom.",
|
|
171
|
+
default: "deps.slices.json",
|
|
172
|
+
hidden: true
|
|
149
173
|
})
|
|
150
174
|
.option("usages-slices-file", {
|
|
151
|
-
description: "Path for the usages
|
|
175
|
+
description: "Path for the usages slices file created by atom.",
|
|
176
|
+
default: "usages.slices.json",
|
|
177
|
+
hidden: true
|
|
152
178
|
})
|
|
153
179
|
.option("data-flow-slices-file", {
|
|
154
|
-
description: "Path for the data-flow
|
|
180
|
+
description: "Path for the data-flow slices file created by atom.",
|
|
181
|
+
default: "data-flow.slices.json",
|
|
182
|
+
hidden: true
|
|
183
|
+
})
|
|
184
|
+
.option("reachables-slices-file", {
|
|
185
|
+
description: "Path for the reachables slices file created by atom.",
|
|
186
|
+
default: "reachables.slices.json",
|
|
187
|
+
hidden: true
|
|
155
188
|
})
|
|
156
189
|
.option("spec-version", {
|
|
157
190
|
description: "CycloneDX Specification version to use. Defaults to 1.5",
|
|
158
|
-
default: 1.5
|
|
191
|
+
default: 1.5,
|
|
192
|
+
type: "number"
|
|
159
193
|
})
|
|
160
194
|
.option("filter", {
|
|
161
195
|
description:
|
|
@@ -165,8 +199,15 @@ const args = yargs(hideBin(process.argv))
|
|
|
165
199
|
description:
|
|
166
200
|
"Include components only containining this word in purl. Useful to generate BOM with first party components alone. Multiple values allowed."
|
|
167
201
|
})
|
|
202
|
+
.option("author", {
|
|
203
|
+
description:
|
|
204
|
+
"The person(s) who created the BOM. Set this value if you're intending the modify the BOM and claim authorship.",
|
|
205
|
+
default: "OWASP Foundation"
|
|
206
|
+
})
|
|
207
|
+
.completion("completion", "Generate bash/zsh completion")
|
|
168
208
|
.array("filter")
|
|
169
209
|
.array("only")
|
|
210
|
+
.array("author")
|
|
170
211
|
.option("auto-compositions", {
|
|
171
212
|
type: "boolean",
|
|
172
213
|
default: true,
|
|
@@ -213,11 +254,6 @@ if (!args.projectName) {
|
|
|
213
254
|
}
|
|
214
255
|
}
|
|
215
256
|
|
|
216
|
-
// To help dependency track users, we downgrade the spec version to 1.4 automatically
|
|
217
|
-
if (args.serverUrl || args.apiKey) {
|
|
218
|
-
args.specVersion = 1.4;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
257
|
// Support for obom aliases
|
|
222
258
|
if (process.argv[1].includes("obom") && !args.type) {
|
|
223
259
|
args.type = "os";
|
|
@@ -286,9 +322,6 @@ const checkPermissions = (filePath) => {
|
|
|
286
322
|
if (options.requiredOnly || options["filter"] || options["only"]) {
|
|
287
323
|
bomNSData = postProcess(bomNSData, options);
|
|
288
324
|
}
|
|
289
|
-
if (!args.output) {
|
|
290
|
-
args.output = "bom.json";
|
|
291
|
-
}
|
|
292
325
|
if (
|
|
293
326
|
args.output &&
|
|
294
327
|
(typeof args.output === "string" || args.output instanceof String)
|
|
@@ -455,6 +488,34 @@ const checkPermissions = (filePath) => {
|
|
|
455
488
|
console.log("Try running the command with -t <type> or -r argument");
|
|
456
489
|
}
|
|
457
490
|
}
|
|
491
|
+
// Evidence generation
|
|
492
|
+
if (args.evidence) {
|
|
493
|
+
const evinseOptions = {
|
|
494
|
+
_: args._,
|
|
495
|
+
input: options.output,
|
|
496
|
+
output: options.evinseOutput,
|
|
497
|
+
language: options.projectType || "java",
|
|
498
|
+
dbPath: process.env.ATOM_DB || ATOM_DB,
|
|
499
|
+
skipMavenCollector: false,
|
|
500
|
+
force: false,
|
|
501
|
+
withReachables: options.deep,
|
|
502
|
+
usagesSlicesFile: options.usagesSlicesFile,
|
|
503
|
+
dataFlowSlicesFile: options.dataFlowSlicesFile,
|
|
504
|
+
reachablesSlicesFile: options.reachablesSlicesFile
|
|
505
|
+
};
|
|
506
|
+
const dbObjMap = await prepareDB(evinseOptions);
|
|
507
|
+
if (dbObjMap) {
|
|
508
|
+
const sliceArtefacts = await analyzeProject(dbObjMap, evinseOptions);
|
|
509
|
+
const evinseJson = createEvinseFile(sliceArtefacts, evinseOptions);
|
|
510
|
+
bomNSData.bomJson = evinseJson;
|
|
511
|
+
if (args.print && evinseJson) {
|
|
512
|
+
printOccurrences(evinseJson);
|
|
513
|
+
printCallStack(evinseJson);
|
|
514
|
+
printReachables(sliceArtefacts);
|
|
515
|
+
printServices(evinseJson);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
458
519
|
// Perform automatic validation
|
|
459
520
|
if (args.validate) {
|
|
460
521
|
if (!validateBom(bomNSData.bomJson)) {
|
package/bin/evinse.js
CHANGED
|
@@ -3,13 +3,17 @@
|
|
|
3
3
|
// Evinse (Evinse Verification Is Nearly SBOM Evidence)
|
|
4
4
|
import yargs from "yargs";
|
|
5
5
|
import { hideBin } from "yargs/helpers";
|
|
6
|
-
import { join } from "node:path";
|
|
7
6
|
import fs from "node:fs";
|
|
8
|
-
import { homedir, platform as _platform } from "node:os";
|
|
9
7
|
import process from "node:process";
|
|
10
8
|
import { analyzeProject, createEvinseFile, prepareDB } from "../evinser.js";
|
|
11
9
|
import { validateBom } from "../validator.js";
|
|
12
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
printCallStack,
|
|
12
|
+
printOccurrences,
|
|
13
|
+
printServices,
|
|
14
|
+
printReachables
|
|
15
|
+
} from "../display.js";
|
|
16
|
+
import { ATOM_DB } from "../utils.js";
|
|
13
17
|
import { findUpSync } from "find-up";
|
|
14
18
|
import { load as _load } from "js-yaml";
|
|
15
19
|
|
|
@@ -33,22 +37,6 @@ if (configPath) {
|
|
|
33
37
|
}
|
|
34
38
|
}
|
|
35
39
|
|
|
36
|
-
const isWin = _platform() === "win32";
|
|
37
|
-
const isMac = _platform() === "darwin";
|
|
38
|
-
let ATOM_DB = join(homedir(), ".local", "share", ".atomdb");
|
|
39
|
-
if (isWin) {
|
|
40
|
-
ATOM_DB = join(homedir(), "AppData", "Local", ".atomdb");
|
|
41
|
-
} else if (isMac) {
|
|
42
|
-
ATOM_DB = join(homedir(), "Library", "Application Support", ".atomdb");
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (!process.env.ATOM_DB && !fs.existsSync(ATOM_DB)) {
|
|
46
|
-
try {
|
|
47
|
-
fs.mkdirSync(ATOM_DB, { recursive: true });
|
|
48
|
-
} catch (e) {
|
|
49
|
-
// ignore
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
40
|
const args = yargs(hideBin(process.argv))
|
|
53
41
|
.env("EVINSE")
|
|
54
42
|
.option("input", {
|
|
@@ -65,7 +53,18 @@ const args = yargs(hideBin(process.argv))
|
|
|
65
53
|
alias: "l",
|
|
66
54
|
description: "Application language",
|
|
67
55
|
default: "java",
|
|
68
|
-
choices: [
|
|
56
|
+
choices: [
|
|
57
|
+
"java",
|
|
58
|
+
"jar",
|
|
59
|
+
"js",
|
|
60
|
+
"ts",
|
|
61
|
+
"javascript",
|
|
62
|
+
"py",
|
|
63
|
+
"python",
|
|
64
|
+
"android",
|
|
65
|
+
"c",
|
|
66
|
+
"cpp"
|
|
67
|
+
]
|
|
69
68
|
})
|
|
70
69
|
.option("db-path", {
|
|
71
70
|
description: `Atom slices DB path. Default ${ATOM_DB}`,
|
|
@@ -98,6 +97,12 @@ const args = yargs(hideBin(process.argv))
|
|
|
98
97
|
default: false,
|
|
99
98
|
type: "boolean"
|
|
100
99
|
})
|
|
100
|
+
.option("with-reachables", {
|
|
101
|
+
description:
|
|
102
|
+
"Enable auto-tagged reachable slicing. Requires SBOM generated with --deep mode.",
|
|
103
|
+
default: false,
|
|
104
|
+
type: "boolean"
|
|
105
|
+
})
|
|
101
106
|
.option("usages-slices-file", {
|
|
102
107
|
description: "Use an existing usages slices file.",
|
|
103
108
|
default: "usages.slices.json"
|
|
@@ -106,11 +111,27 @@ const args = yargs(hideBin(process.argv))
|
|
|
106
111
|
description: "Use an existing data-flow slices file.",
|
|
107
112
|
default: "data-flow.slices.json"
|
|
108
113
|
})
|
|
114
|
+
.option("reachables-slices-file", {
|
|
115
|
+
description: "Use an existing reachables slices file.",
|
|
116
|
+
default: "reachables.slices.json"
|
|
117
|
+
})
|
|
109
118
|
.option("print", {
|
|
110
119
|
alias: "p",
|
|
111
120
|
type: "boolean",
|
|
112
121
|
description: "Print the evidences as table"
|
|
113
122
|
})
|
|
123
|
+
.example([
|
|
124
|
+
[
|
|
125
|
+
"$0 -i bom.json -o bom.evinse.json -l java .",
|
|
126
|
+
"Generate a Java SBOM with evidence for the current directory"
|
|
127
|
+
],
|
|
128
|
+
[
|
|
129
|
+
"$0 -i bom.json -o bom.evinse.json -l java --with-reachables .",
|
|
130
|
+
"Generate a Java SBOM with occurrence and reachable evidence for the current directory"
|
|
131
|
+
]
|
|
132
|
+
])
|
|
133
|
+
.completion("completion", "Generate bash/zsh completion")
|
|
134
|
+
.epilogue("for documentation, visit https://cyclonedx.github.io/cdxgen")
|
|
114
135
|
.config(config)
|
|
115
136
|
.scriptName("evinse")
|
|
116
137
|
.version()
|
|
@@ -119,8 +140,8 @@ const args = yargs(hideBin(process.argv))
|
|
|
119
140
|
const evinseArt = `
|
|
120
141
|
███████╗██╗ ██╗██╗███╗ ██╗███████╗███████╗
|
|
121
142
|
██╔════╝██║ ██║██║████╗ ██║██╔════╝██╔════╝
|
|
122
|
-
█████╗ ██║ ██║██║██╔██╗ ██║███████╗█████╗
|
|
123
|
-
██╔══╝ ╚██╗ ██╔╝██║██║╚██╗██║╚════██║██╔══╝
|
|
143
|
+
█████╗ ██║ ██║██║██╔██╗ ██║███████╗█████╗
|
|
144
|
+
██╔══╝ ╚██╗ ██╔╝██║██║╚██╗██║╚════██║██╔══╝
|
|
124
145
|
███████╗ ╚████╔╝ ██║██║ ╚████║███████║███████╗
|
|
125
146
|
╚══════╝ ╚═══╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚══════╝
|
|
126
147
|
`;
|
|
@@ -141,6 +162,7 @@ console.log(evinseArt);
|
|
|
141
162
|
if (args.print) {
|
|
142
163
|
printOccurrences(bomJson);
|
|
143
164
|
printCallStack(bomJson);
|
|
165
|
+
printReachables(sliceArtefacts);
|
|
144
166
|
printServices(bomJson);
|
|
145
167
|
}
|
|
146
168
|
}
|
package/bin/verify.js
CHANGED
|
@@ -24,6 +24,8 @@ const args = yargs(hideBin(process.argv))
|
|
|
24
24
|
default: "public.key",
|
|
25
25
|
description: "Public key in PEM format. Default public.key"
|
|
26
26
|
})
|
|
27
|
+
.completion("completion", "Generate bash/zsh completion")
|
|
28
|
+
.epilogue("for documentation, visit https://cyclonedx.github.io/cdxgen")
|
|
27
29
|
.scriptName("cdx-verify")
|
|
28
30
|
.version()
|
|
29
31
|
.help("h").argv;
|
package/binary.js
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
import { platform as _platform, arch as _arch, tmpdir } from "node:os";
|
|
2
|
-
import {
|
|
1
|
+
import { platform as _platform, arch as _arch, tmpdir, homedir } from "node:os";
|
|
2
|
+
import {
|
|
3
|
+
existsSync,
|
|
4
|
+
mkdirSync,
|
|
5
|
+
mkdtempSync,
|
|
6
|
+
readFileSync,
|
|
7
|
+
rmSync
|
|
8
|
+
} from "node:fs";
|
|
3
9
|
import { join, dirname, basename } from "node:path";
|
|
4
10
|
import { spawnSync } from "node:child_process";
|
|
5
11
|
import { PackageURL } from "packageurl-js";
|
|
@@ -284,6 +290,13 @@ export const getOSPackages = (src) => {
|
|
|
284
290
|
const allTypes = new Set();
|
|
285
291
|
if (TRIVY_BIN) {
|
|
286
292
|
let imageType = "image";
|
|
293
|
+
const trivyCacheDir = join(homedir(), ".cache", "trivy");
|
|
294
|
+
try {
|
|
295
|
+
mkdirSync(join(trivyCacheDir, "db"), { recursive: true });
|
|
296
|
+
mkdirSync(join(trivyCacheDir, "java-db"), { recursive: true });
|
|
297
|
+
} catch (err) {
|
|
298
|
+
// ignore errors
|
|
299
|
+
}
|
|
287
300
|
if (existsSync(src)) {
|
|
288
301
|
imageType = "rootfs";
|
|
289
302
|
}
|
|
@@ -292,12 +305,17 @@ export const getOSPackages = (src) => {
|
|
|
292
305
|
const args = [
|
|
293
306
|
imageType,
|
|
294
307
|
"--skip-db-update",
|
|
308
|
+
"--skip-java-db-update",
|
|
295
309
|
"--offline-scan",
|
|
310
|
+
"--skip-files",
|
|
311
|
+
"**/*.jar",
|
|
296
312
|
"--no-progress",
|
|
297
313
|
"--exit-code",
|
|
298
314
|
"0",
|
|
299
315
|
"--format",
|
|
300
316
|
"cyclonedx",
|
|
317
|
+
"--cache-dir",
|
|
318
|
+
trivyCacheDir,
|
|
301
319
|
"--output",
|
|
302
320
|
bomJsonFile
|
|
303
321
|
];
|
package/data/README.md
CHANGED
|
@@ -18,3 +18,4 @@ Contents of data directory and their purpose.
|
|
|
18
18
|
| spdx.schema.json | jsonschema for validation |
|
|
19
19
|
| vendor-alias.json | List to correct the group names. Used while parsing .jar files |
|
|
20
20
|
| wrapdb-releases.json | Database of all available meson wraps. Generated using contrib/wrapdb.py. |
|
|
21
|
+
| frameworks-list.json | List of string fragments to categorize components into frameworks |
|