@trustify-da/trustify-da-javascript-client 0.3.0-ea.b8af0f8 → 0.3.0-ea.bdb4511
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 +73 -8
- package/dist/package.json +24 -24
- package/dist/src/analysis.d.ts +7 -7
- package/dist/src/analysis.js +3 -2
- package/dist/src/cli.js +51 -2
- package/dist/src/cyclone_dx_sbom.d.ts +14 -1
- package/dist/src/cyclone_dx_sbom.js +43 -8
- package/dist/src/index.d.ts +81 -10
- package/dist/src/index.js +92 -7
- package/dist/src/license/index.d.ts +3 -3
- package/dist/src/license/index.js +4 -1
- package/dist/src/license/license_utils.js +4 -1
- package/dist/src/license/licenses_api.d.ts +2 -2
- package/dist/src/oci_image/images.d.ts +1 -1
- package/dist/src/oci_image/utils.d.ts +5 -5
- package/dist/src/oci_image/utils.js +11 -2
- package/dist/src/provider.d.ts +4 -3
- package/dist/src/provider.js +9 -1
- package/dist/src/providers/base_java.d.ts +14 -12
- package/dist/src/providers/base_java.js +18 -44
- package/dist/src/providers/base_javascript.d.ts +20 -9
- package/dist/src/providers/base_javascript.js +44 -6
- package/dist/src/providers/base_pyproject.d.ts +158 -0
- package/dist/src/providers/base_pyproject.js +322 -0
- package/dist/src/providers/golang_gomodules.d.ts +23 -13
- package/dist/src/providers/golang_gomodules.js +165 -119
- package/dist/src/providers/gomod_parser.d.ts +4 -0
- package/dist/src/providers/gomod_parser.js +16 -0
- package/dist/src/providers/java_gradle.d.ts +19 -0
- package/dist/src/providers/java_gradle.js +116 -2
- package/dist/src/providers/java_gradle_groovy.d.ts +1 -1
- package/dist/src/providers/java_gradle_kotlin.d.ts +1 -1
- package/dist/src/providers/java_maven.d.ts +10 -2
- package/dist/src/providers/java_maven.js +165 -1
- package/dist/src/providers/javascript_bun.d.ts +10 -0
- package/dist/src/providers/javascript_bun.js +100 -0
- package/dist/src/providers/javascript_npm.d.ts +6 -0
- package/dist/src/providers/javascript_npm.js +21 -0
- package/dist/src/providers/javascript_pnpm.js +6 -2
- package/dist/src/providers/manifest.d.ts +2 -0
- package/dist/src/providers/manifest.js +22 -4
- package/dist/src/providers/marker_evaluator.d.ts +14 -0
- package/dist/src/providers/marker_evaluator.js +191 -0
- package/dist/src/providers/processors/yarn_berry_processor.d.ts +2 -2
- package/dist/src/providers/processors/yarn_berry_processor.js +88 -5
- package/dist/src/providers/processors/yarn_classic_processor.d.ts +2 -2
- package/dist/src/providers/python_controller.d.ts +5 -1
- package/dist/src/providers/python_controller.js +65 -7
- package/dist/src/providers/python_pip.d.ts +5 -0
- package/dist/src/providers/python_pip.js +6 -6
- package/dist/src/providers/python_pip_pyproject.d.ts +61 -0
- package/dist/src/providers/python_pip_pyproject.js +146 -0
- package/dist/src/providers/python_poetry.d.ts +98 -0
- package/dist/src/providers/python_poetry.js +286 -0
- package/dist/src/providers/python_uv.d.ts +46 -0
- package/dist/src/providers/python_uv.js +269 -0
- package/dist/src/providers/rust_cargo.d.ts +6 -2
- package/dist/src/providers/rust_cargo.js +31 -4
- package/dist/src/providers/tree-sitter-gomod.wasm +0 -0
- package/dist/src/sbom.d.ts +14 -1
- package/dist/src/sbom.js +13 -2
- package/dist/src/tools.d.ts +28 -2
- package/dist/src/tools.js +58 -0
- package/dist/src/workspace.d.ts +9 -0
- package/dist/src/workspace.js +1 -1
- package/package.json +25 -25
package/README.md
CHANGED
|
@@ -224,7 +224,8 @@ $ trustify-da-javascript-client license /path/to/package.json
|
|
|
224
224
|
<li><a href="https://www.javascript.com/">JavaScript</a> - <a href="https://pnpm.io/">pnpm</a></li>
|
|
225
225
|
<li><a href="https://www.javascript.com/">JavaScript</a> - <a href="https://classic.yarnpkg.com/">Yarn Classic</a> / <a href="https://yarnpkg.com/">Yarn Berry</a></li>
|
|
226
226
|
<li><a href="https://go.dev/">Golang</a> - <a href="https://go.dev/blog/using-go-modules/">Go Modules</a></li>
|
|
227
|
-
<li><a href="https://www.python.org/">Python</a> - <a href="https://pypi.org/project/pip/">pip Installer</a
|
|
227
|
+
<li><a href="https://www.python.org/">Python</a> - <a href="https://pypi.org/project/pip/">pip Installer</a> (<code>requirements.txt</code>)</li>
|
|
228
|
+
<li><a href="https://www.python.org/">Python</a> - <a href="https://python-poetry.org/">Poetry</a> / <a href="https://docs.astral.sh/uv/">uv</a> (<code>pyproject.toml</code>)</li>
|
|
228
229
|
<li><a href="https://gradle.org/">Gradle (Groovy and Kotlin DSL)</a> - <a href="https://gradle.org/install/">Gradle Installation</a></li>
|
|
229
230
|
<li><a href="https://www.rust-lang.org/">Rust</a> - <a href="https://doc.rust-lang.org/cargo/">Cargo</a></li>
|
|
230
231
|
</ul>
|
|
@@ -287,8 +288,11 @@ Excluding a package from any analysis can be achieved by marking the package for
|
|
|
287
288
|
]
|
|
288
289
|
}
|
|
289
290
|
```
|
|
291
|
+
</li>
|
|
292
|
+
|
|
293
|
+
<li>
|
|
294
|
+
<em>Golang</em> users can add in go.mod a comment with <code>// exhortignore</code> next to the package to be ignored, or to "piggyback" on existing comment ( e.g - <code>// indirect</code>), for example:
|
|
290
295
|
|
|
291
|
-
<em>Golang</em> users can add in go.mod a comment with //exhortignore next to the package to be ignored, or to "piggyback" on existing comment ( e.g - //indirect) , for example:
|
|
292
296
|
```go
|
|
293
297
|
module github.com/trustify-da/SaaSi/deployer
|
|
294
298
|
|
|
@@ -297,7 +301,7 @@ go 1.19
|
|
|
297
301
|
require (
|
|
298
302
|
github.com/gin-gonic/gin v1.9.1
|
|
299
303
|
github.com/google/uuid v1.1.2
|
|
300
|
-
github.com/jessevdk/go-flags v1.5.0 //exhortignore
|
|
304
|
+
github.com/jessevdk/go-flags v1.5.0 // exhortignore
|
|
301
305
|
github.com/kr/pretty v0.3.1
|
|
302
306
|
gopkg.in/yaml.v2 v2.4.0
|
|
303
307
|
k8s.io/apimachinery v0.26.1
|
|
@@ -305,14 +309,20 @@ require (
|
|
|
305
309
|
)
|
|
306
310
|
|
|
307
311
|
require (
|
|
308
|
-
github.com/davecgh/go-spew v1.1.1 // indirect exhortignore
|
|
312
|
+
github.com/davecgh/go-spew v1.1.1 // indirect; exhortignore
|
|
309
313
|
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
|
|
310
|
-
github.com/go-logr/logr v1.2.3 // indirect
|
|
314
|
+
github.com/go-logr/logr v1.2.3 // indirect; exhortignore
|
|
311
315
|
|
|
312
316
|
)
|
|
313
317
|
```
|
|
314
318
|
|
|
319
|
+
<b>NOTE</b>: It is important to format <code>exhortignore</code> markers on indirect dependencies as shown above, otherwise the Go tooling (as well as this library) may incorrectly parse dependencies marked as indirect as being direct dependencies instead.
|
|
320
|
+
</li>
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
<li>
|
|
315
324
|
<em>Python pip</em> users can add in requirements.txt a comment with #exhortignore(or # exhortignore) to the right of the same artifact to be ignored, for example:
|
|
325
|
+
|
|
316
326
|
```properties
|
|
317
327
|
anyio==3.6.2
|
|
318
328
|
asgiref==3.4.1
|
|
@@ -343,11 +353,14 @@ Werkzeug==2.0.3
|
|
|
343
353
|
zipp==3.6.0
|
|
344
354
|
|
|
345
355
|
```
|
|
356
|
+
</li>
|
|
346
357
|
|
|
358
|
+
<li>
|
|
347
359
|
<em>Gradle</em> users can add in build.gradle a comment with //exhortignore next to the package to be ignored:
|
|
360
|
+
|
|
348
361
|
```build.gradle
|
|
349
362
|
plugins {
|
|
350
|
-
id 'java'
|
|
363
|
+
id 'java'
|
|
351
364
|
}
|
|
352
365
|
|
|
353
366
|
group = 'groupName'
|
|
@@ -379,9 +392,31 @@ version = "1.10"
|
|
|
379
392
|
log = "0.4" # trustify-da-ignore
|
|
380
393
|
```
|
|
381
394
|
|
|
382
|
-
All of the 6 above examples are valid for marking a package to be ignored
|
|
383
|
-
</li>
|
|
384
395
|
|
|
396
|
+
<em>Python pyproject.toml</em> users can add a comment with <code>#exhortignore</code> (or <code># trustify-da-ignore</code>) next to the dependency in <code>pyproject.toml</code>.
|
|
397
|
+
|
|
398
|
+
PEP 621 style (<code>[project]</code> dependencies):
|
|
399
|
+
```toml
|
|
400
|
+
[project]
|
|
401
|
+
dependencies = [
|
|
402
|
+
"flask>=2.0.3",
|
|
403
|
+
"requests>=2.25.1",
|
|
404
|
+
"uvicorn>=0.17.0", #exhortignore
|
|
405
|
+
"click>=8.0.4", # trustify-da-ignore
|
|
406
|
+
]
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
Poetry style (<code>[tool.poetry.dependencies]</code>):
|
|
410
|
+
```toml
|
|
411
|
+
[tool.poetry.dependencies]
|
|
412
|
+
flask = "^2.0.3"
|
|
413
|
+
requests = "^2.25.1"
|
|
414
|
+
uvicorn = "^0.17.0" #exhortignore
|
|
415
|
+
click = "^8.0.4" # trustify-da-ignore
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
All of the above examples are valid for marking a package to be ignored
|
|
419
|
+
</li>
|
|
385
420
|
</ul>
|
|
386
421
|
|
|
387
422
|
<h3>Customization</h3>
|
|
@@ -410,6 +445,8 @@ let options = {
|
|
|
410
445
|
'TRUSTIFY_DA_PIP3_PATH' : '/path/to/pip3',
|
|
411
446
|
'TRUSTIFY_DA_PYTHON_PATH' : '/path/to/python',
|
|
412
447
|
'TRUSTIFY_DA_PIP_PATH' : '/path/to/pip',
|
|
448
|
+
'TRUSTIFY_DA_UV_PATH' : '/path/to/uv',
|
|
449
|
+
'TRUSTIFY_DA_POETRY_PATH' : '/path/to/poetry',
|
|
413
450
|
'TRUSTIFY_DA_GRADLE_PATH' : '/path/to/gradle',
|
|
414
451
|
'TRUSTIFY_DA_CARGO_PATH' : '/path/to/cargo',
|
|
415
452
|
// Workspace root for monorepos (Cargo, npm/pnpm/yarn); lock file expected here
|
|
@@ -556,6 +593,16 @@ following keys for setting custom paths for the said executables.
|
|
|
556
593
|
<td>TRUSTIFY_DA_CARGO_PATH</td>
|
|
557
594
|
</tr>
|
|
558
595
|
<tr>
|
|
596
|
+
<td><a href="https://docs.astral.sh/uv/">uv</a></td>
|
|
597
|
+
<td><em>uv</em></td>
|
|
598
|
+
<td>TRUSTIFY_DA_UV_PATH</td>
|
|
599
|
+
</tr>
|
|
600
|
+
<tr>
|
|
601
|
+
<td><a href="https://python-poetry.org/">Poetry</a></td>
|
|
602
|
+
<td><em>poetry</em></td>
|
|
603
|
+
<td>TRUSTIFY_DA_POETRY_PATH</td>
|
|
604
|
+
</tr>
|
|
605
|
+
<tr>
|
|
559
606
|
<td>Workspace root (monorepos)</td>
|
|
560
607
|
<td>—</td>
|
|
561
608
|
<td>workspaceDir / TRUSTIFY_DA_WORKSPACE_DIR</td>
|
|
@@ -608,6 +655,24 @@ TRUSTIFY_DA_GO_MVS_LOGIC_ENABLED=false
|
|
|
608
655
|
|
|
609
656
|
#### Python Support
|
|
610
657
|
|
|
658
|
+
The client supports two Python manifest formats:
|
|
659
|
+
|
|
660
|
+
- **`requirements.txt`** — uses pip/pip3 to resolve dependencies
|
|
661
|
+
- **`pyproject.toml`** — uses [uv](https://docs.astral.sh/uv/) or [Poetry](https://python-poetry.org/) to resolve dependencies
|
|
662
|
+
|
|
663
|
+
##### pyproject.toml
|
|
664
|
+
|
|
665
|
+
For `pyproject.toml` projects, the client detects which tool manages the project by checking for lock files:
|
|
666
|
+
- If `poetry.lock` is present and `[tool.poetry]` is defined, **Poetry** is used (`poetry show --tree` and `poetry show --all`)
|
|
667
|
+
- If `uv.lock` is present, **uv** is used (`uv export --format requirements.txt --frozen --no-hashes`)
|
|
668
|
+
- If neither lock file is found, an error is thrown
|
|
669
|
+
|
|
670
|
+
Both PEP 621 (`[project]` dependencies) and Poetry-style (`[tool.poetry.dependencies]`) are supported.
|
|
671
|
+
|
|
672
|
+
Custom executable paths can be set via `TRUSTIFY_DA_UV_PATH` and `TRUSTIFY_DA_POETRY_PATH`.
|
|
673
|
+
|
|
674
|
+
##### requirements.txt
|
|
675
|
+
|
|
611
676
|
By default, For python support, the api assumes that the package is installed using the pip/pip3 binary on the system PATH, or using the customized
|
|
612
677
|
Binaries passed to environment variables. In any case, If the package is not installed , then an error will be thrown.
|
|
613
678
|
|
package/dist/package.json
CHANGED
|
@@ -35,55 +35,57 @@
|
|
|
35
35
|
"config/**/*"
|
|
36
36
|
],
|
|
37
37
|
"scripts": {
|
|
38
|
-
"lint": "eslint src test
|
|
39
|
-
"lint:fix": "eslint src test --
|
|
38
|
+
"lint": "eslint src test",
|
|
39
|
+
"lint:fix": "eslint src test --fix",
|
|
40
40
|
"test": "c8 npm run tests",
|
|
41
|
-
"tests": "mocha --config .mocharc.json
|
|
41
|
+
"tests": "mocha --config .mocharc.json",
|
|
42
42
|
"tests:rep": "mocha --reporter-option maxDiffSize=0 --reporter json > unit-tests-result.json",
|
|
43
|
-
"pretest": "cp node_modules/tree-sitter-requirements/tree-sitter-requirements.wasm src/providers/tree-sitter-requirements.wasm",
|
|
43
|
+
"pretest": "cp node_modules/tree-sitter-requirements/tree-sitter-requirements.wasm src/providers/tree-sitter-requirements.wasm && cp node_modules/tree-sitter-gomod/tree-sitter-gomod.wasm src/providers/tree-sitter-gomod.wasm",
|
|
44
44
|
"precompile": "rm -rf dist",
|
|
45
45
|
"compile": "tsc -p tsconfig.json",
|
|
46
46
|
"compile:dev": "tsc -p tsconfig.dev.json",
|
|
47
|
-
"postcompile": "cp node_modules/tree-sitter-requirements/tree-sitter-requirements.wasm dist/src/providers/tree-sitter-requirements.wasm"
|
|
47
|
+
"postcompile": "cp node_modules/tree-sitter-requirements/tree-sitter-requirements.wasm dist/src/providers/tree-sitter-requirements.wasm && cp node_modules/tree-sitter-gomod/tree-sitter-gomod.wasm dist/src/providers/tree-sitter-gomod.wasm"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@babel/core": "^7.23.2",
|
|
51
|
-
"@cyclonedx/cyclonedx-library": "^
|
|
51
|
+
"@cyclonedx/cyclonedx-library": "^10.0.0",
|
|
52
52
|
"eslint-import-resolver-typescript": "^4.4.4",
|
|
53
53
|
"fast-glob": "^3.3.3",
|
|
54
|
-
"fast-toml": "^0.5.4",
|
|
55
54
|
"fast-xml-parser": "^5.3.4",
|
|
56
55
|
"help": "^3.0.2",
|
|
57
|
-
"https-proxy-agent": "^
|
|
56
|
+
"https-proxy-agent": "^9.0.0",
|
|
58
57
|
"js-yaml": "^4.1.1",
|
|
58
|
+
"jsonc-parser": "^3.3.1",
|
|
59
59
|
"micromatch": "^4.0.8",
|
|
60
60
|
"node-fetch": "^3.3.2",
|
|
61
|
-
"p-limit": "^
|
|
61
|
+
"p-limit": "^7.3.0",
|
|
62
62
|
"packageurl-js": "~1.0.2",
|
|
63
63
|
"smol-toml": "^1.6.0",
|
|
64
|
+
"tree-sitter-gomod": "github:strum355/tree-sitter-go-mod#56326f2ad478892ace58ff247a97d492a3cbcdda",
|
|
64
65
|
"tree-sitter-requirements": "github:Strum355/tree-sitter-requirements#d0261ee76b84253997fe70d7d397e78c006c3801",
|
|
65
|
-
"web-tree-sitter": "^0.26.
|
|
66
|
+
"web-tree-sitter": "^0.26.7",
|
|
66
67
|
"yargs": "^18.0.0"
|
|
67
68
|
},
|
|
68
69
|
"devDependencies": {
|
|
69
70
|
"@babel/core": "^7.23.2",
|
|
70
|
-
"@trustify-da/trustify-da-api-model": "^2.0.
|
|
71
|
-
"@types/node": "^
|
|
71
|
+
"@trustify-da/trustify-da-api-model": "^2.0.9",
|
|
72
|
+
"@types/node": "^25.9.1",
|
|
72
73
|
"@types/which": "^3.0.4",
|
|
73
74
|
"babel-plugin-rewire": "^1.2.0",
|
|
74
75
|
"c8": "^11.0.0",
|
|
75
|
-
"chai": "^
|
|
76
|
-
"eslint": "^
|
|
76
|
+
"chai": "^6.2.2",
|
|
77
|
+
"@eslint/js": "^10.0.0",
|
|
78
|
+
"eslint": "^10.4.1",
|
|
77
79
|
"eslint-import-resolver-typescript": "^4.4.4",
|
|
78
|
-
"eslint-plugin-
|
|
79
|
-
"
|
|
80
|
+
"eslint-plugin-import-x": "^4.16.2",
|
|
81
|
+
"globals": "^17.6.0",
|
|
80
82
|
"esmock": "^2.6.2",
|
|
81
|
-
"mocha": "^
|
|
83
|
+
"mocha": "^11.7.6",
|
|
82
84
|
"msw": "^2.12.7",
|
|
83
|
-
"sinon": "^
|
|
84
|
-
"sinon-chai": "^
|
|
85
|
-
"typescript": "^
|
|
86
|
-
"which": "^
|
|
85
|
+
"sinon": "^22.0.0",
|
|
86
|
+
"sinon-chai": "^4.0.1",
|
|
87
|
+
"typescript": "^6.0.3",
|
|
88
|
+
"which": "^7.0.0"
|
|
87
89
|
},
|
|
88
90
|
"mocha": {
|
|
89
91
|
"check-leaks": false,
|
|
@@ -111,12 +113,10 @@
|
|
|
111
113
|
"reporter": [
|
|
112
114
|
"html",
|
|
113
115
|
"json",
|
|
116
|
+
"lcov",
|
|
114
117
|
"text"
|
|
115
118
|
]
|
|
116
119
|
},
|
|
117
|
-
"eslintIgnore": [
|
|
118
|
-
"index.js"
|
|
119
|
-
],
|
|
120
120
|
"resolutions": {
|
|
121
121
|
"@hapi/joi": "17.1.1"
|
|
122
122
|
}
|
package/dist/src/analysis.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export default _default;
|
|
|
16
16
|
* @param {import("index.js").Options} [opts={}] - optional various options to pass along the application
|
|
17
17
|
* @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>}
|
|
18
18
|
*/
|
|
19
|
-
declare function requestComponent(provider:
|
|
19
|
+
declare function requestComponent(provider: any, manifest: string, url: string, opts?: any): Promise<any>;
|
|
20
20
|
/**
|
|
21
21
|
* Send a stack analysis request and get the report as 'text/html' or 'application/json'.
|
|
22
22
|
* @param {import('./provider').Provider} provider - the provided data for constructing the request
|
|
@@ -26,7 +26,7 @@ declare function requestComponent(provider: import("./provider").Provider, manif
|
|
|
26
26
|
* @param {import("index.js").Options} [opts={}] - optional various options to pass along the application
|
|
27
27
|
* @returns {Promise<string|import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>}
|
|
28
28
|
*/
|
|
29
|
-
declare function requestStack(provider:
|
|
29
|
+
declare function requestStack(provider: any, manifest: string, url: string, html?: boolean, opts?: any): Promise<string | any>;
|
|
30
30
|
/**
|
|
31
31
|
* Send a batch stack analysis request for multiple manifests (SBOMs keyed by purl).
|
|
32
32
|
* @param {Object.<string, object>} sbomByPurl - Map of root purl to CycloneDX SBOM object
|
|
@@ -36,9 +36,9 @@ declare function requestStack(provider: import("./provider").Provider, manifest:
|
|
|
36
36
|
* @returns {Promise<string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>>}
|
|
37
37
|
*/
|
|
38
38
|
declare function requestStackBatch(sbomByPurl: {
|
|
39
|
+
[x: string]: object;
|
|
40
|
+
}, url: string, html?: boolean, opts?: any): Promise<string | {
|
|
39
41
|
[x: string]: any;
|
|
40
|
-
}, url: string, html?: boolean, opts?: import("index.js").Options): Promise<string | {
|
|
41
|
-
[x: string]: import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport").AnalysisReport;
|
|
42
42
|
}>;
|
|
43
43
|
/**
|
|
44
44
|
*
|
|
@@ -47,8 +47,8 @@ declare function requestStackBatch(sbomByPurl: {
|
|
|
47
47
|
* @param {import("index.js").Options} [opts={}] - optional various options to pass along the application
|
|
48
48
|
* @returns {Promise<string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>>}
|
|
49
49
|
*/
|
|
50
|
-
declare function requestImages(imageRefs: Array<string>, url: string, html?: boolean, opts?:
|
|
51
|
-
[x: string]:
|
|
50
|
+
declare function requestImages(imageRefs: Array<string>, url: string, html?: boolean, opts?: any): Promise<string | {
|
|
51
|
+
[x: string]: any;
|
|
52
52
|
}>;
|
|
53
53
|
/**
|
|
54
54
|
*
|
|
@@ -56,4 +56,4 @@ declare function requestImages(imageRefs: Array<string>, url: string, html?: boo
|
|
|
56
56
|
* @param {import("index.js").Options} [opts={}] - optional various options to pass headers for t he validateToken Request
|
|
57
57
|
* @return {Promise<number>} return the HTTP status Code of the response from the validate token request.
|
|
58
58
|
*/
|
|
59
|
-
declare function validateToken(url: any, opts?:
|
|
59
|
+
declare function validateToken(url: any, opts?: any): Promise<number>;
|
package/dist/src/analysis.js
CHANGED
|
@@ -189,7 +189,7 @@ async function requestImages(imageRefs, url, html = false, opts = {}) {
|
|
|
189
189
|
if (opts['TRUSTIFY_DA_RECOMMENDATIONS_ENABLED'] === 'false') {
|
|
190
190
|
finalUrl.searchParams.append('recommend', 'false');
|
|
191
191
|
}
|
|
192
|
-
const
|
|
192
|
+
const fetchOptions = addProxyAgent({
|
|
193
193
|
method: 'POST',
|
|
194
194
|
headers: {
|
|
195
195
|
'Accept': html ? 'text/html' : 'application/json',
|
|
@@ -197,7 +197,8 @@ async function requestImages(imageRefs, url, html = false, opts = {}) {
|
|
|
197
197
|
...getTokenHeaders(opts)
|
|
198
198
|
},
|
|
199
199
|
body: JSON.stringify(imageSboms),
|
|
200
|
-
});
|
|
200
|
+
}, opts);
|
|
201
|
+
const resp = await fetch(finalUrl, fetchOptions);
|
|
201
202
|
if (resp.status === 200) {
|
|
202
203
|
let result;
|
|
203
204
|
if (!html) {
|
package/dist/src/cli.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
2
3
|
import * as path from "path";
|
|
3
4
|
import yargs from 'yargs';
|
|
4
5
|
import { hideBin } from 'yargs/helpers';
|
|
5
6
|
import { getProjectLicense, getLicenseDetails } from './license/index.js';
|
|
6
|
-
import client, { selectTrustifyDABackend } from './index.js';
|
|
7
|
+
import client, { selectTrustifyDABackend, generateSbom } from './index.js';
|
|
7
8
|
// command for component analysis take manifest type and content
|
|
8
9
|
const component = {
|
|
9
10
|
command: 'component </path/to/manifest>',
|
|
@@ -325,15 +326,63 @@ const license = {
|
|
|
325
326
|
console.log(JSON.stringify(output, null, 2));
|
|
326
327
|
}
|
|
327
328
|
};
|
|
329
|
+
const sbom = {
|
|
330
|
+
command: 'sbom </path/to/manifest> [--output]',
|
|
331
|
+
desc: 'generate a CycloneDX SBOM from a manifest file',
|
|
332
|
+
builder: yargs => yargs.positional('/path/to/manifest', {
|
|
333
|
+
desc: 'manifest path for SBOM generation',
|
|
334
|
+
type: 'string',
|
|
335
|
+
normalize: true,
|
|
336
|
+
}).options({
|
|
337
|
+
output: {
|
|
338
|
+
alias: 'o',
|
|
339
|
+
desc: 'Write SBOM JSON to a file instead of stdout',
|
|
340
|
+
type: 'string',
|
|
341
|
+
normalize: true,
|
|
342
|
+
},
|
|
343
|
+
workspaceDir: {
|
|
344
|
+
alias: 'w',
|
|
345
|
+
desc: 'Workspace root directory (for monorepos; lock file is expected here)',
|
|
346
|
+
type: 'string',
|
|
347
|
+
normalize: true,
|
|
348
|
+
}
|
|
349
|
+
}),
|
|
350
|
+
handler: async (args) => {
|
|
351
|
+
let manifest = args['/path/to/manifest'];
|
|
352
|
+
const opts = args.workspaceDir ? { TRUSTIFY_DA_WORKSPACE_DIR: args.workspaceDir } : {};
|
|
353
|
+
let result;
|
|
354
|
+
try {
|
|
355
|
+
result = await generateSbom(manifest, opts);
|
|
356
|
+
}
|
|
357
|
+
catch (err) {
|
|
358
|
+
console.error(JSON.stringify({ error: `Failed to generate SBOM: ${err.message}` }, null, 2));
|
|
359
|
+
process.exit(1);
|
|
360
|
+
}
|
|
361
|
+
const json = JSON.stringify(result, null, 2);
|
|
362
|
+
if (args.output) {
|
|
363
|
+
try {
|
|
364
|
+
fs.writeFileSync(args.output, json);
|
|
365
|
+
}
|
|
366
|
+
catch (err) {
|
|
367
|
+
console.error(JSON.stringify({ error: `Failed to write output file: ${err.message}` }, null, 2));
|
|
368
|
+
process.exit(1);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
console.log(json);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
};
|
|
328
376
|
// parse and invoke the command
|
|
329
377
|
yargs(hideBin(process.argv))
|
|
330
|
-
.usage(`Usage: ${process.argv[0].includes("node") ? path.parse(process.argv[1]).base : path.parse(process.argv[0]).base} {component|stack|stack-batch|image|validate-token|license}`)
|
|
378
|
+
.usage(`Usage: ${process.argv[0].includes("node") ? path.parse(process.argv[1]).base : path.parse(process.argv[0]).base} {component|stack|stack-batch|image|validate-token|license|sbom}`)
|
|
331
379
|
.command(stack)
|
|
332
380
|
.command(stackBatch)
|
|
333
381
|
.command(component)
|
|
334
382
|
.command(image)
|
|
335
383
|
.command(validateToken)
|
|
336
384
|
.command(license)
|
|
385
|
+
.command(sbom)
|
|
337
386
|
.scriptName('')
|
|
338
387
|
.version(false)
|
|
339
388
|
.demandCommand(1)
|
|
@@ -18,9 +18,14 @@ export default class CycloneDxSbom {
|
|
|
18
18
|
* Adds a dependency relationship between two components in the SBOM
|
|
19
19
|
* @param {PackageURL} sourceRef - The source component (parent)
|
|
20
20
|
* @param {PackageURL} targetRef - The target component (dependency)
|
|
21
|
+
* @param {string} [scope] - Scope of the dependency
|
|
22
|
+
* @param {Array<{alg: string, content: string}>} [targetHashes] - Optional hashes for the target component
|
|
21
23
|
* @return {CycloneDxSbom} The updated SBOM
|
|
22
24
|
*/
|
|
23
|
-
addDependency(sourceRef: PackageURL, targetRef: PackageURL, scope
|
|
25
|
+
addDependency(sourceRef: PackageURL, targetRef: PackageURL, scope?: string, targetHashes?: Array<{
|
|
26
|
+
alg: string;
|
|
27
|
+
content: string;
|
|
28
|
+
}>): CycloneDxSbom;
|
|
24
29
|
/** @param {{}} opts - various options, settings and configuration of application.
|
|
25
30
|
* @return String CycloneDx Sbom json object in a string format
|
|
26
31
|
*/
|
|
@@ -50,6 +55,7 @@ export default class CycloneDxSbom {
|
|
|
50
55
|
version: any;
|
|
51
56
|
scope: any;
|
|
52
57
|
licenses?: any;
|
|
58
|
+
hashes?: any;
|
|
53
59
|
};
|
|
54
60
|
/**
|
|
55
61
|
* This method gets an array of dependencies to be ignored, and remove all of them from CycloneDx Sbom
|
|
@@ -70,6 +76,13 @@ export default class CycloneDxSbom {
|
|
|
70
76
|
* @return {boolean}
|
|
71
77
|
*/
|
|
72
78
|
checkIfPackageInsideDependsOnList(component: any, name: string): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Checks if any entry in the dependsOn list of sourceRef starts with the given purl prefix.
|
|
81
|
+
* @param {PackageURL} sourceRef - The source component
|
|
82
|
+
* @param {string} purlPrefix - The purl prefix to match (e.g. "pkg:npm/minimist@")
|
|
83
|
+
* @return {boolean}
|
|
84
|
+
*/
|
|
85
|
+
checkDependsOnByPurlPrefix(sourceRef: PackageURL, purlPrefix: string): boolean;
|
|
73
86
|
/** Removes the root component from the sbom
|
|
74
87
|
*/
|
|
75
88
|
removeRootComponent(): void;
|
|
@@ -6,10 +6,11 @@ import { PackageURL } from "packageurl-js";
|
|
|
6
6
|
* @param type type of package - application or library
|
|
7
7
|
* @param scope scope of the component - runtime or compile
|
|
8
8
|
* @param licenses optional license string or array of licenses for the component
|
|
9
|
-
* @
|
|
9
|
+
* @param hashes optional array of hash objects for the component, e.g. [{alg: "SHA-256", content: "..."}]
|
|
10
|
+
* @return {{"bom-ref": string, name, purl: string, type, version, scope, licenses?, hashes?}}
|
|
10
11
|
* @private
|
|
11
12
|
*/
|
|
12
|
-
function getComponent(component, type, scope, licenses) {
|
|
13
|
+
function getComponent(component, type, scope, licenses, hashes) {
|
|
13
14
|
let componentObject;
|
|
14
15
|
if (component instanceof PackageURL) {
|
|
15
16
|
if (component.namespace) {
|
|
@@ -40,12 +41,24 @@ function getComponent(component, type, scope, licenses) {
|
|
|
40
41
|
// Add licenses if provided (CycloneDX format). Callers must provide valid SPDX identifiers.
|
|
41
42
|
if (licenses) {
|
|
42
43
|
const licenseArray = Array.isArray(licenses) ? licenses : [licenses];
|
|
43
|
-
|
|
44
|
+
const validLicenses = licenseArray
|
|
45
|
+
.map(lic => {
|
|
44
46
|
if (typeof lic === 'string') {
|
|
45
47
|
return { license: { id: lic } };
|
|
46
48
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
if (typeof lic === 'object' && lic !== null && ('license' in lic || 'expression' in lic)) {
|
|
50
|
+
return lic;
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
})
|
|
54
|
+
.filter(Boolean);
|
|
55
|
+
if (validLicenses.length > 0) {
|
|
56
|
+
componentObject.licenses = validLicenses;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Add hashes if provided (CycloneDX 1.4 format).
|
|
60
|
+
if (hashes && hashes.length > 0) {
|
|
61
|
+
componentObject.hashes = hashes;
|
|
49
62
|
}
|
|
50
63
|
return componentObject;
|
|
51
64
|
}
|
|
@@ -86,16 +99,24 @@ export default class CycloneDxSbom {
|
|
|
86
99
|
* Adds a dependency relationship between two components in the SBOM
|
|
87
100
|
* @param {PackageURL} sourceRef - The source component (parent)
|
|
88
101
|
* @param {PackageURL} targetRef - The target component (dependency)
|
|
102
|
+
* @param {string} [scope] - Scope of the dependency
|
|
103
|
+
* @param {Array<{alg: string, content: string}>} [targetHashes] - Optional hashes for the target component
|
|
89
104
|
* @return {CycloneDxSbom} The updated SBOM
|
|
90
105
|
*/
|
|
91
|
-
addDependency(sourceRef, targetRef, scope) {
|
|
106
|
+
addDependency(sourceRef, targetRef, scope, targetHashes) {
|
|
92
107
|
const sourcePurl = sourceRef.toString();
|
|
93
108
|
const targetPurl = targetRef.toString();
|
|
94
109
|
// Ensure both components exist in the components list
|
|
95
110
|
[sourceRef, targetRef].forEach((ref, index) => {
|
|
96
111
|
const purl = index === 0 ? sourcePurl : targetPurl;
|
|
97
|
-
|
|
98
|
-
|
|
112
|
+
const existingIndex = this.getComponentIndex(purl);
|
|
113
|
+
if (existingIndex < 0) {
|
|
114
|
+
const hashes = index === 1 ? targetHashes : undefined;
|
|
115
|
+
this.components.push(getComponent(ref, "library", scope, undefined, hashes));
|
|
116
|
+
}
|
|
117
|
+
else if (index === 1 && targetHashes && targetHashes.length > 0 && !this.components[existingIndex].hashes) {
|
|
118
|
+
// Update hashes if the component was first seen without them (e.g. as a source)
|
|
119
|
+
this.components[existingIndex].hashes = targetHashes;
|
|
99
120
|
}
|
|
100
121
|
});
|
|
101
122
|
// Ensure source dependency exists
|
|
@@ -242,6 +263,20 @@ export default class CycloneDxSbom {
|
|
|
242
263
|
return false;
|
|
243
264
|
}
|
|
244
265
|
}
|
|
266
|
+
/**
|
|
267
|
+
* Checks if any entry in the dependsOn list of sourceRef starts with the given purl prefix.
|
|
268
|
+
* @param {PackageURL} sourceRef - The source component
|
|
269
|
+
* @param {string} purlPrefix - The purl prefix to match (e.g. "pkg:npm/minimist@")
|
|
270
|
+
* @return {boolean}
|
|
271
|
+
*/
|
|
272
|
+
checkDependsOnByPurlPrefix(sourceRef, purlPrefix) {
|
|
273
|
+
const sourcePurl = sourceRef.toString();
|
|
274
|
+
const depIndex = this.getDependencyIndex(sourcePurl);
|
|
275
|
+
if (depIndex < 0) {
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
return this.dependencies[depIndex].dependsOn.some(dep => dep.startsWith(purlPrefix));
|
|
279
|
+
}
|
|
245
280
|
/** Removes the root component from the sbom
|
|
246
281
|
*/
|
|
247
282
|
removeRootComponent() {
|