@trustify-da/trustify-da-javascript-client 0.2.4-ea.13
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/LICENSE +201 -0
- package/README.md +482 -0
- package/config/config.properties +1 -0
- package/dist/package.json +106 -0
- package/dist/src/analysis.d.ts +43 -0
- package/dist/src/analysis.js +252 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +102 -0
- package/dist/src/cyclone_dx_sbom.d.ts +77 -0
- package/dist/src/cyclone_dx_sbom.js +244 -0
- package/dist/src/index.d.ts +82 -0
- package/dist/src/index.js +194 -0
- package/dist/src/oci_image/images.d.ts +99 -0
- package/dist/src/oci_image/images.js +263 -0
- package/dist/src/oci_image/platform.d.ts +59 -0
- package/dist/src/oci_image/platform.js +138 -0
- package/dist/src/oci_image/utils.d.ts +42 -0
- package/dist/src/oci_image/utils.js +496 -0
- package/dist/src/provider.d.ts +29 -0
- package/dist/src/provider.js +47 -0
- package/dist/src/providers/base_java.d.ts +85 -0
- package/dist/src/providers/base_java.js +191 -0
- package/dist/src/providers/base_javascript.d.ts +127 -0
- package/dist/src/providers/base_javascript.js +350 -0
- package/dist/src/providers/golang_gomodules.d.ts +42 -0
- package/dist/src/providers/golang_gomodules.js +403 -0
- package/dist/src/providers/java_gradle.d.ts +35 -0
- package/dist/src/providers/java_gradle.js +399 -0
- package/dist/src/providers/java_gradle_groovy.d.ts +7 -0
- package/dist/src/providers/java_gradle_groovy.js +19 -0
- package/dist/src/providers/java_gradle_kotlin.d.ts +11 -0
- package/dist/src/providers/java_gradle_kotlin.js +23 -0
- package/dist/src/providers/java_maven.d.ts +52 -0
- package/dist/src/providers/java_maven.js +263 -0
- package/dist/src/providers/javascript_npm.d.ts +4 -0
- package/dist/src/providers/javascript_npm.js +15 -0
- package/dist/src/providers/javascript_pnpm.d.ts +5 -0
- package/dist/src/providers/javascript_pnpm.js +22 -0
- package/dist/src/providers/javascript_yarn.d.ts +11 -0
- package/dist/src/providers/javascript_yarn.js +39 -0
- package/dist/src/providers/manifest.d.ts +11 -0
- package/dist/src/providers/manifest.js +48 -0
- package/dist/src/providers/processors/yarn_berry_processor.d.ts +41 -0
- package/dist/src/providers/processors/yarn_berry_processor.js +130 -0
- package/dist/src/providers/processors/yarn_classic_processor.d.ts +37 -0
- package/dist/src/providers/processors/yarn_classic_processor.js +109 -0
- package/dist/src/providers/processors/yarn_processor.d.ts +9 -0
- package/dist/src/providers/processors/yarn_processor.js +20 -0
- package/dist/src/providers/python_controller.d.ts +31 -0
- package/dist/src/providers/python_controller.js +406 -0
- package/dist/src/providers/python_pip.d.ts +35 -0
- package/dist/src/providers/python_pip.js +227 -0
- package/dist/src/sbom.d.ts +59 -0
- package/dist/src/sbom.js +84 -0
- package/dist/src/tools.d.ts +74 -0
- package/dist/src/tools.js +159 -0
- package/package.json +106 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
TRUSTIFY_DA_DEV_MODE=false
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@trustify-da/trustify-da-javascript-client",
|
|
3
|
+
"version": "0.2.4-ea.13",
|
|
4
|
+
"description": "Code-Ready Dependency Analytics JavaScript API.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"homepage": "https://github.com/guacsec/trustify-da-javascript-client#README.md",
|
|
7
|
+
"bugs": "https://github.com/guacsec/trustify-da-javascript-client/issues",
|
|
8
|
+
"repository": "github:guacsec/trustify-da-javascript-client",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"analysis",
|
|
11
|
+
"codeready",
|
|
12
|
+
"exhort",
|
|
13
|
+
"secure",
|
|
14
|
+
"supply-chain",
|
|
15
|
+
"vulnerability"
|
|
16
|
+
],
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">= 18.0.0",
|
|
19
|
+
"npm": ">= 9.0.0"
|
|
20
|
+
},
|
|
21
|
+
"type": "module",
|
|
22
|
+
"bin": "dist/src/cli.js",
|
|
23
|
+
"main": "dist/src/index.js",
|
|
24
|
+
"module": "dist/src/index.js",
|
|
25
|
+
"types": "dist/src/index.d.ts",
|
|
26
|
+
"files": [
|
|
27
|
+
"!*",
|
|
28
|
+
"dist/**/*",
|
|
29
|
+
"config/**/*"
|
|
30
|
+
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"lint": "eslint src test --ext js",
|
|
33
|
+
"lint:fix": "eslint src test --ext js --fix",
|
|
34
|
+
"test": "c8 npm run tests",
|
|
35
|
+
"tests": "mocha --config .mocharc.json --grep \"Integration Tests|.*analysis module.*\" --invert",
|
|
36
|
+
"tests:rep": "mocha --reporter-option maxDiffSize=0 --reporter json > unit-tests-result.json",
|
|
37
|
+
"integration-tests": "mocha --grep \"Integration Tests\"",
|
|
38
|
+
"precompile": "rm -rf dist",
|
|
39
|
+
"compile": "tsc -p tsconfig.json"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@babel/core": "^7.23.2",
|
|
43
|
+
"@cyclonedx/cyclonedx-library": "~1.13.3",
|
|
44
|
+
"fast-toml": "^0.5.4",
|
|
45
|
+
"fast-xml-parser": "^4.5.3",
|
|
46
|
+
"help": "^3.0.2",
|
|
47
|
+
"https-proxy-agent": "^7.0.6",
|
|
48
|
+
"node-fetch": "^2.7.0",
|
|
49
|
+
"packageurl-js": "^1.0.2",
|
|
50
|
+
"yargs": "^17.7.2"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@babel/core": "^7.23.2",
|
|
54
|
+
"@trustify-da/trustify-da-api-model": "^2.0.1",
|
|
55
|
+
"@types/node": "^20.17.30",
|
|
56
|
+
"@types/which": "^3.0.4",
|
|
57
|
+
"babel-plugin-rewire": "^1.2.0",
|
|
58
|
+
"c8": "^8.0.0",
|
|
59
|
+
"chai": "^4.3.7",
|
|
60
|
+
"eslint": "^8.42.0",
|
|
61
|
+
"eslint-plugin-editorconfig": "^4.0.3",
|
|
62
|
+
"eslint-plugin-import": "^2.29.1",
|
|
63
|
+
"esmock": "^2.6.2",
|
|
64
|
+
"mocha": "^10.2.0",
|
|
65
|
+
"msw": "^1.3.2",
|
|
66
|
+
"sinon": "^15.1.2",
|
|
67
|
+
"sinon-chai": "^3.7.0",
|
|
68
|
+
"typescript": "^5.1.3",
|
|
69
|
+
"which": "^5.0.0"
|
|
70
|
+
},
|
|
71
|
+
"mocha": {
|
|
72
|
+
"check-leaks": false,
|
|
73
|
+
"color": true,
|
|
74
|
+
"extension": "js",
|
|
75
|
+
"fail-zero": true,
|
|
76
|
+
"recursive": true,
|
|
77
|
+
"ui": "tdd"
|
|
78
|
+
},
|
|
79
|
+
"c8": {
|
|
80
|
+
"all": true,
|
|
81
|
+
"check-coverage": true,
|
|
82
|
+
"clean": true,
|
|
83
|
+
"include": [
|
|
84
|
+
"src/**"
|
|
85
|
+
],
|
|
86
|
+
"exclude": [
|
|
87
|
+
"src/cli.js",
|
|
88
|
+
"src/index.js",
|
|
89
|
+
"src/analysis.js",
|
|
90
|
+
"src/providers/java_maven.js",
|
|
91
|
+
"src/providers/javascript_npm.js"
|
|
92
|
+
],
|
|
93
|
+
"lines": 82,
|
|
94
|
+
"reporter": [
|
|
95
|
+
"html",
|
|
96
|
+
"json",
|
|
97
|
+
"text"
|
|
98
|
+
]
|
|
99
|
+
},
|
|
100
|
+
"eslintIgnore": [
|
|
101
|
+
"index.js"
|
|
102
|
+
],
|
|
103
|
+
"resolutions": {
|
|
104
|
+
"@hapi/joi": "17.1.1"
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
declare namespace _default {
|
|
2
|
+
export { requestComponent };
|
|
3
|
+
export { requestStack };
|
|
4
|
+
export { requestImages };
|
|
5
|
+
export { validateToken };
|
|
6
|
+
}
|
|
7
|
+
export default _default;
|
|
8
|
+
/**
|
|
9
|
+
* Send a component analysis request and get the report as 'application/json'.
|
|
10
|
+
* @param {import('./provider').Provider} provider - the provided data for constructing the request
|
|
11
|
+
* @param {string} manifest - path for the manifest
|
|
12
|
+
* @param {string} url - the backend url to send the request to
|
|
13
|
+
* @param {import("index.js").Options} [opts={}] - optional various options to pass along the application
|
|
14
|
+
* @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>}
|
|
15
|
+
*/
|
|
16
|
+
declare function requestComponent(provider: import('./provider').Provider, manifest: string, url: string, opts?: import("index.js").Options | undefined): Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>;
|
|
17
|
+
/**
|
|
18
|
+
* Send a stack analysis request and get the report as 'text/html' or 'application/json'.
|
|
19
|
+
* @param {import('./provider').Provider} provider - the provided data for constructing the request
|
|
20
|
+
* @param {string} manifest - path for the manifest
|
|
21
|
+
* @param {string} url - the backend url to send the request to
|
|
22
|
+
* @param {boolean} [html=false] - true will return 'text/html', false will return 'application/json'
|
|
23
|
+
* @param {import("index.js").Options} [opts={}] - optional various options to pass along the application
|
|
24
|
+
* @returns {Promise<string|import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>}
|
|
25
|
+
*/
|
|
26
|
+
declare function requestStack(provider: import('./provider').Provider, manifest: string, url: string, html?: boolean | undefined, opts?: import("index.js").Options | undefined): Promise<string | import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>;
|
|
27
|
+
/**
|
|
28
|
+
*
|
|
29
|
+
* @param {Array<string>} imageRefs
|
|
30
|
+
* @param {string} url
|
|
31
|
+
* @param {import("index.js").Options} [opts={}] - optional various options to pass along the application
|
|
32
|
+
* @returns {Promise<string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>>}
|
|
33
|
+
*/
|
|
34
|
+
declare function requestImages(imageRefs: Array<string>, url: string, html?: boolean, opts?: import("index.js").Options | undefined): Promise<string | {
|
|
35
|
+
[x: string]: import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport;
|
|
36
|
+
}>;
|
|
37
|
+
/**
|
|
38
|
+
*
|
|
39
|
+
* @param url the backend url to send the request to
|
|
40
|
+
* @param {import("index.js").Options} [opts={}] - optional various options to pass headers for t he validateToken Request
|
|
41
|
+
* @return {Promise<number>} return the HTTP status Code of the response from the validate token request.
|
|
42
|
+
*/
|
|
43
|
+
declare function validateToken(url: any, opts?: import("index.js").Options | undefined): Promise<number>;
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { EOL } from "os";
|
|
4
|
+
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
5
|
+
import { generateImageSBOM, parseImageRef } from "./oci_image/utils.js";
|
|
6
|
+
import { RegexNotToBeLogged, getCustom } from "./tools.js";
|
|
7
|
+
export default { requestComponent, requestStack, requestImages, validateToken };
|
|
8
|
+
const rhdaTokenHeader = "rhda-token";
|
|
9
|
+
const rhdaTelemetryId = "rhda-telemetry-id";
|
|
10
|
+
const rhdaSourceHeader = "rhda-source";
|
|
11
|
+
const rhdaOperationTypeHeader = "rhda-operation-type";
|
|
12
|
+
const rhdaPackageManagerHeader = "rhda-pkg-manager";
|
|
13
|
+
/**
|
|
14
|
+
* Adds proxy agent configuration to fetch options if a proxy URL is specified
|
|
15
|
+
* @param {RequestInit} options - The base fetch options
|
|
16
|
+
* @param {import("index.js").Options} opts - The exhort options that may contain proxy configuration
|
|
17
|
+
* @returns {RequestInit} The fetch options with proxy agent if applicable
|
|
18
|
+
*/
|
|
19
|
+
function addProxyAgent(options, opts) {
|
|
20
|
+
const proxyUrl = getCustom('TRUSTIFY_DA_PROXY_URL', null, opts);
|
|
21
|
+
if (proxyUrl) {
|
|
22
|
+
options.agent = new HttpsProxyAgent(proxyUrl);
|
|
23
|
+
}
|
|
24
|
+
return options;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Send a stack analysis request and get the report as 'text/html' or 'application/json'.
|
|
28
|
+
* @param {import('./provider').Provider} provider - the provided data for constructing the request
|
|
29
|
+
* @param {string} manifest - path for the manifest
|
|
30
|
+
* @param {string} url - the backend url to send the request to
|
|
31
|
+
* @param {boolean} [html=false] - true will return 'text/html', false will return 'application/json'
|
|
32
|
+
* @param {import("index.js").Options} [opts={}] - optional various options to pass along the application
|
|
33
|
+
* @returns {Promise<string|import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>}
|
|
34
|
+
*/
|
|
35
|
+
async function requestStack(provider, manifest, url, html = false, opts = {}) {
|
|
36
|
+
opts["source-manifest"] = Buffer.from(fs.readFileSync(manifest).toString()).toString('base64');
|
|
37
|
+
opts["manifest-type"] = path.parse(manifest).base;
|
|
38
|
+
let provided = provider.provideStack(manifest, opts); // throws error if content providing failed
|
|
39
|
+
opts["source-manifest"] = "";
|
|
40
|
+
opts[rhdaOperationTypeHeader.toUpperCase().replaceAll("-", "_")] = "stack-analysis";
|
|
41
|
+
let startTime = new Date();
|
|
42
|
+
let endTime;
|
|
43
|
+
if (process.env["TRUSTIFY_DA_DEBUG"] === "true") {
|
|
44
|
+
console.log("Starting time of sending stack analysis request to exhort server= " + startTime);
|
|
45
|
+
}
|
|
46
|
+
opts[rhdaPackageManagerHeader.toUpperCase().replaceAll("-", "_")] = provided.ecosystem;
|
|
47
|
+
const fetchOptions = addProxyAgent({
|
|
48
|
+
method: 'POST',
|
|
49
|
+
headers: {
|
|
50
|
+
'Accept': html ? 'text/html' : 'application/json',
|
|
51
|
+
'Content-Type': provided.contentType,
|
|
52
|
+
...getTokenHeaders(opts),
|
|
53
|
+
},
|
|
54
|
+
body: provided.content
|
|
55
|
+
}, opts);
|
|
56
|
+
const finalUrl = new URL(`${url}/api/v4/analysis`);
|
|
57
|
+
if (opts['TRUSTIFY_DA_RECOMMENDATIONS_ENABLED'] === 'false') {
|
|
58
|
+
finalUrl.searchParams.append('recommend', 'false');
|
|
59
|
+
}
|
|
60
|
+
let resp = await fetch(finalUrl, fetchOptions);
|
|
61
|
+
let result;
|
|
62
|
+
if (resp.status === 200) {
|
|
63
|
+
if (!html) {
|
|
64
|
+
result = await resp.json();
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
result = await resp.text();
|
|
68
|
+
}
|
|
69
|
+
if (process.env["TRUSTIFY_DA_DEBUG"] === "true") {
|
|
70
|
+
let exRequestId = resp.headers.get("ex-request-id");
|
|
71
|
+
if (exRequestId) {
|
|
72
|
+
console.log("Unique Identifier associated with this request - ex-request-id=" + exRequestId);
|
|
73
|
+
}
|
|
74
|
+
endTime = new Date();
|
|
75
|
+
console.log("Response body received from exhort server : " + EOL + EOL);
|
|
76
|
+
console.log(console.log(JSON.stringify(result, null, 4)));
|
|
77
|
+
console.log("Ending time of sending stack analysis request to exhort server= " + endTime);
|
|
78
|
+
let time = (endTime - startTime) / 1000;
|
|
79
|
+
console.log("Total Time in seconds: " + time);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
throw new Error(`Got error response from exhort backend - http return code : ${resp.status}, error message => ${await resp.text()}`);
|
|
84
|
+
}
|
|
85
|
+
return Promise.resolve(result);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Send a component analysis request and get the report as 'application/json'.
|
|
89
|
+
* @param {import('./provider').Provider} provider - the provided data for constructing the request
|
|
90
|
+
* @param {string} manifest - path for the manifest
|
|
91
|
+
* @param {string} url - the backend url to send the request to
|
|
92
|
+
* @param {import("index.js").Options} [opts={}] - optional various options to pass along the application
|
|
93
|
+
* @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>}
|
|
94
|
+
*/
|
|
95
|
+
async function requestComponent(provider, manifest, url, opts = {}) {
|
|
96
|
+
opts["source-manifest"] = Buffer.from(fs.readFileSync(manifest).toString()).toString('base64');
|
|
97
|
+
let provided = provider.provideComponent(manifest, opts); // throws error if content providing failed
|
|
98
|
+
opts["source-manifest"] = "";
|
|
99
|
+
opts[rhdaOperationTypeHeader.toUpperCase().replaceAll("-", "_")] = "component-analysis";
|
|
100
|
+
if (process.env["TRUSTIFY_DA_DEBUG"] === "true") {
|
|
101
|
+
console.log("Starting time of sending component analysis request to exhort server= " + new Date());
|
|
102
|
+
}
|
|
103
|
+
opts[rhdaPackageManagerHeader.toUpperCase().replaceAll("-", "_")] = provided.ecosystem;
|
|
104
|
+
const fetchOptions = addProxyAgent({
|
|
105
|
+
method: 'POST',
|
|
106
|
+
headers: {
|
|
107
|
+
'Accept': 'application/json',
|
|
108
|
+
'Content-Type': provided.contentType,
|
|
109
|
+
...getTokenHeaders(opts),
|
|
110
|
+
},
|
|
111
|
+
body: provided.content
|
|
112
|
+
}, opts);
|
|
113
|
+
const finalUrl = new URL(`${url}/api/v4/analysis`);
|
|
114
|
+
if (opts['TRUSTIFY_DA_RECOMMENDATIONS_ENABLED'] === 'false') {
|
|
115
|
+
finalUrl.searchParams.append('recommend', 'false');
|
|
116
|
+
}
|
|
117
|
+
let resp = await fetch(finalUrl, fetchOptions);
|
|
118
|
+
let result;
|
|
119
|
+
if (resp.status === 200) {
|
|
120
|
+
result = await resp.json();
|
|
121
|
+
if (process.env["TRUSTIFY_DA_DEBUG"] === "true") {
|
|
122
|
+
let exRequestId = resp.headers.get("ex-request-id");
|
|
123
|
+
if (exRequestId) {
|
|
124
|
+
console.log("Unique Identifier associated with this request - ex-request-id=" + exRequestId);
|
|
125
|
+
}
|
|
126
|
+
console.log("Response body received from exhort server : " + EOL + EOL);
|
|
127
|
+
console.log(JSON.stringify(result, null, 4));
|
|
128
|
+
console.log("Ending time of sending component analysis request to exhort server= " + new Date());
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
throw new Error(`Got error response from exhort backend - http return code : ${resp.status}, ex-request-id: ${resp.headers.get("ex-request-id")} error message => ${await resp.text()}`);
|
|
133
|
+
}
|
|
134
|
+
return Promise.resolve(result);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
*
|
|
138
|
+
* @param {Array<string>} imageRefs
|
|
139
|
+
* @param {string} url
|
|
140
|
+
* @param {import("index.js").Options} [opts={}] - optional various options to pass along the application
|
|
141
|
+
* @returns {Promise<string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>>}
|
|
142
|
+
*/
|
|
143
|
+
async function requestImages(imageRefs, url, html = false, opts = {}) {
|
|
144
|
+
const imageSboms = {};
|
|
145
|
+
for (const image of imageRefs) {
|
|
146
|
+
const parsedImageRef = parseImageRef(image, opts);
|
|
147
|
+
imageSboms[parsedImageRef.getPackageURL().toString()] = generateImageSBOM(parsedImageRef, opts);
|
|
148
|
+
}
|
|
149
|
+
const finalUrl = new URL(`${url}/api/v4/batch-analysis`);
|
|
150
|
+
if (opts['TRUSTIFY_DA_RECOMMENDATIONS_ENABLED'] === 'false') {
|
|
151
|
+
finalUrl.searchParams.append('recommend', 'false');
|
|
152
|
+
}
|
|
153
|
+
const resp = await fetch(finalUrl, {
|
|
154
|
+
method: 'POST',
|
|
155
|
+
headers: {
|
|
156
|
+
'Accept': html ? 'text/html' : 'application/json',
|
|
157
|
+
'Content-Type': 'application/vnd.cyclonedx+json',
|
|
158
|
+
...getTokenHeaders(opts)
|
|
159
|
+
},
|
|
160
|
+
body: JSON.stringify(imageSboms),
|
|
161
|
+
});
|
|
162
|
+
if (resp.status === 200) {
|
|
163
|
+
let result;
|
|
164
|
+
if (!html) {
|
|
165
|
+
result = await resp.json();
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
result = await resp.text();
|
|
169
|
+
}
|
|
170
|
+
if (process.env["TRUSTIFY_DA_DEBUG"] === "true") {
|
|
171
|
+
let exRequestId = resp.headers.get("ex-request-id");
|
|
172
|
+
if (exRequestId) {
|
|
173
|
+
console.log("Unique Identifier associated with this request - ex-request-id=" + exRequestId);
|
|
174
|
+
}
|
|
175
|
+
console.log("Response body received from exhort server : " + EOL + EOL);
|
|
176
|
+
console.log(JSON.stringify(result, null, 4));
|
|
177
|
+
console.log("Ending time of sending component analysis request to exhort server= " + new Date());
|
|
178
|
+
}
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
throw new Error(`Got error response from exhort backend - http return code : ${resp.status}, ex-request-id: ${resp.headers.get("ex-request-id")} error message => ${await resp.text()}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
*
|
|
187
|
+
* @param url the backend url to send the request to
|
|
188
|
+
* @param {import("index.js").Options} [opts={}] - optional various options to pass headers for t he validateToken Request
|
|
189
|
+
* @return {Promise<number>} return the HTTP status Code of the response from the validate token request.
|
|
190
|
+
*/
|
|
191
|
+
async function validateToken(url, opts = {}) {
|
|
192
|
+
const fetchOptions = addProxyAgent({
|
|
193
|
+
method: 'GET',
|
|
194
|
+
headers: {
|
|
195
|
+
...getTokenHeaders(opts),
|
|
196
|
+
}
|
|
197
|
+
}, opts);
|
|
198
|
+
let resp = await fetch(`${url}/api/v4/token`, fetchOptions);
|
|
199
|
+
if (process.env["TRUSTIFY_DA_DEBUG"] === "true") {
|
|
200
|
+
let exRequestId = resp.headers.get("ex-request-id");
|
|
201
|
+
if (exRequestId) {
|
|
202
|
+
console.log("Unique Identifier associated with this request - ex-request-id=" + exRequestId);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return resp.status;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
*
|
|
209
|
+
* @param {string} headerName - the header name to populate in request
|
|
210
|
+
* @param headers
|
|
211
|
+
* @param {import("index.js").Options} [opts={}] - optional various options to pass along the application
|
|
212
|
+
* @private
|
|
213
|
+
*/
|
|
214
|
+
function setRhdaHeader(headerName, headers, opts) {
|
|
215
|
+
let rhdaHeaderValue = getCustom(headerName.toUpperCase().replaceAll("-", "_"), null, opts);
|
|
216
|
+
if (rhdaHeaderValue) {
|
|
217
|
+
headers[headerName] = rhdaHeaderValue;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Utility function for fetching vendor tokens
|
|
222
|
+
* @param {import("index.js").Options} [opts={}] - optional various options to pass along the application
|
|
223
|
+
* @returns {{}}
|
|
224
|
+
*/
|
|
225
|
+
function getTokenHeaders(opts = {}) {
|
|
226
|
+
let supportedTokens = ['snyk', 'oss-index'];
|
|
227
|
+
let headers = {};
|
|
228
|
+
supportedTokens.forEach(vendor => {
|
|
229
|
+
let token = getCustom(`TRUSTIFY_DA_${vendor.replace("-", "_").toUpperCase()}_TOKEN`, null, opts);
|
|
230
|
+
if (token) {
|
|
231
|
+
headers[`ex-${vendor}-token`] = token;
|
|
232
|
+
}
|
|
233
|
+
let user = getCustom(`TRUSTIFY_DA_${vendor.replace("-", "_").toUpperCase()}_USER`, null, opts);
|
|
234
|
+
if (user) {
|
|
235
|
+
headers[`ex-${vendor}-user`] = user;
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
setRhdaHeader(rhdaTokenHeader, headers, opts);
|
|
239
|
+
setRhdaHeader(rhdaSourceHeader, headers, opts);
|
|
240
|
+
setRhdaHeader(rhdaOperationTypeHeader, headers, opts);
|
|
241
|
+
setRhdaHeader(rhdaPackageManagerHeader, headers, opts);
|
|
242
|
+
setRhdaHeader(rhdaTelemetryId, headers, opts);
|
|
243
|
+
if (process.env["TRUSTIFY_DA_DEBUG"] === "true") {
|
|
244
|
+
console.log("Headers Values to be sent to exhort:" + EOL);
|
|
245
|
+
for (const headerKey in headers) {
|
|
246
|
+
if (!headerKey.match(RegexNotToBeLogged)) {
|
|
247
|
+
console.log(`${headerKey}: ${headers[headerKey]}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return headers;
|
|
252
|
+
}
|
package/dist/src/cli.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import yargs from 'yargs';
|
|
4
|
+
import { hideBin } from 'yargs/helpers';
|
|
5
|
+
import exhort from './index.js';
|
|
6
|
+
// command for component analysis take manifest type and content
|
|
7
|
+
const component = {
|
|
8
|
+
command: 'component </path/to/manifest>',
|
|
9
|
+
desc: 'produce component report for manifest path',
|
|
10
|
+
builder: yargs => yargs.positional('/path/to/manifest', {
|
|
11
|
+
desc: 'manifest path for analyzing',
|
|
12
|
+
type: 'string',
|
|
13
|
+
normalize: true,
|
|
14
|
+
}),
|
|
15
|
+
handler: async (args) => {
|
|
16
|
+
let manifestName = args['/path/to/manifest'];
|
|
17
|
+
let res = await exhort.componentAnalysis(manifestName);
|
|
18
|
+
console.log(JSON.stringify(res, null, 2));
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const validateToken = {
|
|
22
|
+
command: 'validate-token <token-provider> [--token-value thevalue]',
|
|
23
|
+
desc: 'Validates input token if authentic and authorized',
|
|
24
|
+
builder: yargs => yargs.positional('token-provider', {
|
|
25
|
+
desc: 'the token provider',
|
|
26
|
+
type: 'string',
|
|
27
|
+
choices: ['snyk', 'oss-index'],
|
|
28
|
+
}).options({
|
|
29
|
+
tokenValue: {
|
|
30
|
+
alias: 'value',
|
|
31
|
+
desc: 'the actual token value to be checked',
|
|
32
|
+
type: 'string',
|
|
33
|
+
}
|
|
34
|
+
}),
|
|
35
|
+
handler: async (args) => {
|
|
36
|
+
let tokenProvider = args['token-provider'].toUpperCase();
|
|
37
|
+
let opts = {};
|
|
38
|
+
if (args['tokenValue'] !== undefined && args['tokenValue'].trim() !== "") {
|
|
39
|
+
let tokenValue = args['tokenValue'].trim();
|
|
40
|
+
opts[`TRUSTIFY_DA_${tokenProvider}_TOKEN`] = tokenValue;
|
|
41
|
+
}
|
|
42
|
+
let res = await exhort.validateToken(opts);
|
|
43
|
+
console.log(res);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
// command for stack analysis takes a manifest path
|
|
47
|
+
const stack = {
|
|
48
|
+
command: 'stack </path/to/manifest> [--html|--summary]',
|
|
49
|
+
desc: 'produce stack report for manifest path',
|
|
50
|
+
builder: yargs => yargs.positional('/path/to/manifest', {
|
|
51
|
+
desc: 'manifest path for analyzing',
|
|
52
|
+
type: 'string',
|
|
53
|
+
normalize: true,
|
|
54
|
+
}).options({
|
|
55
|
+
html: {
|
|
56
|
+
alias: 'r',
|
|
57
|
+
desc: 'Get the report as HTML instead of JSON',
|
|
58
|
+
type: 'boolean',
|
|
59
|
+
conflicts: 'summary'
|
|
60
|
+
},
|
|
61
|
+
summary: {
|
|
62
|
+
alias: 's',
|
|
63
|
+
desc: 'For JSON report, get only the \'summary\'',
|
|
64
|
+
type: 'boolean',
|
|
65
|
+
conflicts: 'html'
|
|
66
|
+
}
|
|
67
|
+
}),
|
|
68
|
+
handler: async (args) => {
|
|
69
|
+
let manifest = args['/path/to/manifest'];
|
|
70
|
+
let html = args['html'];
|
|
71
|
+
let summary = args['summary'];
|
|
72
|
+
let theProvidersSummary = new Map();
|
|
73
|
+
let theProvidersObject = {};
|
|
74
|
+
let res = await exhort.stackAnalysis(manifest, html);
|
|
75
|
+
if (summary) {
|
|
76
|
+
for (let provider in res.providers) {
|
|
77
|
+
if (res.providers[provider].sources !== undefined) {
|
|
78
|
+
for (let source in res.providers[provider].sources) {
|
|
79
|
+
if (res.providers[provider].sources[source].summary) {
|
|
80
|
+
theProvidersSummary.set(source, res.providers[provider].sources[source].summary);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
for (let [provider, providerSummary] of theProvidersSummary) {
|
|
86
|
+
theProvidersObject[provider] = providerSummary;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
console.log(html ? res : JSON.stringify(!html && summary ? theProvidersObject : res, null, 2));
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
// parse and invoke the command
|
|
93
|
+
yargs(hideBin(process.argv))
|
|
94
|
+
.usage(`Usage: ${process.argv[0].includes("node") ? path.parse(process.argv[1]).base : path.parse(process.argv[0]).base} {component|stack|validate-token}`)
|
|
95
|
+
.command(stack)
|
|
96
|
+
.command(component)
|
|
97
|
+
.command(validateToken)
|
|
98
|
+
.scriptName('')
|
|
99
|
+
.version(false)
|
|
100
|
+
.demandCommand(1)
|
|
101
|
+
.wrap(null)
|
|
102
|
+
.parse();
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/// <reference types="packageurl-js/src/package-url" />
|
|
2
|
+
export default class CycloneDxSbom {
|
|
3
|
+
sbomObject: any;
|
|
4
|
+
rootComponent: any;
|
|
5
|
+
components: any[];
|
|
6
|
+
dependencies: any[];
|
|
7
|
+
sourceManifestForAuditTrail: any;
|
|
8
|
+
/**
|
|
9
|
+
* @param {PackageURL} root - add main/root component for sbom
|
|
10
|
+
* @return {CycloneDxSbom} the CycloneDxSbom Sbom Object
|
|
11
|
+
*/
|
|
12
|
+
addRoot(root: PackageURL): CycloneDxSbom;
|
|
13
|
+
/**
|
|
14
|
+
* @return {{{"bom-ref": string, name, purl: string, type, version}}} root component of sbom.
|
|
15
|
+
*/
|
|
16
|
+
getRoot(): {};
|
|
17
|
+
/**
|
|
18
|
+
* Adds a dependency relationship between two components in the SBOM
|
|
19
|
+
* @param {PackageURL} sourceRef - The source component (parent)
|
|
20
|
+
* @param {PackageURL} targetRef - The target component (dependency)
|
|
21
|
+
* @return {CycloneDxSbom} The updated SBOM
|
|
22
|
+
*/
|
|
23
|
+
addDependency(sourceRef: PackageURL, targetRef: PackageURL, scope: any): CycloneDxSbom;
|
|
24
|
+
/** @param {{}} opts - various options, settings and configuration of application.
|
|
25
|
+
* @return String CycloneDx Sbom json object in a string format
|
|
26
|
+
*/
|
|
27
|
+
getAsJsonString(opts: {}): string;
|
|
28
|
+
/**
|
|
29
|
+
*
|
|
30
|
+
* @param {String} dependency - purl string of the component.
|
|
31
|
+
* @return {int} - the index of the dependency in dependencies Array, returns -1 if not found.
|
|
32
|
+
*/
|
|
33
|
+
getDependencyIndex(dependency: string): int;
|
|
34
|
+
/**
|
|
35
|
+
*
|
|
36
|
+
* @param {component} theComponent - Component Object with purl field.
|
|
37
|
+
* @return {int} index of the found component entry, if not found returns -1.
|
|
38
|
+
* @private
|
|
39
|
+
*/
|
|
40
|
+
private getComponentIndex;
|
|
41
|
+
/** This method gets a PackageUrl, and returns a Component of CycloneDx Sbom
|
|
42
|
+
* @param purl {PackageURL}
|
|
43
|
+
* @return component
|
|
44
|
+
*/
|
|
45
|
+
purlToComponent(purl: PackageURL): {
|
|
46
|
+
"bom-ref": string;
|
|
47
|
+
name: any;
|
|
48
|
+
purl: string;
|
|
49
|
+
type: any;
|
|
50
|
+
version: any;
|
|
51
|
+
scope: any;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* This method gets an array of dependencies to be ignored, and remove all of them from CycloneDx Sbom
|
|
55
|
+
* @param {Array[PackageURL]} dependencies to be removed from sbom
|
|
56
|
+
* @return {CycloneDxSbom} without ignored dependencies
|
|
57
|
+
*/
|
|
58
|
+
filterIgnoredDeps(deps: any): CycloneDxSbom;
|
|
59
|
+
/**
|
|
60
|
+
* This method gets an array of dependencies with versions( purl string format) to be ignored, and remove all of them from CycloneDx Sbom
|
|
61
|
+
* @param {Array} dependencies to be removed from sbom
|
|
62
|
+
* @return {CycloneDxSbom} without ignored dependencies
|
|
63
|
+
*/
|
|
64
|
+
filterIgnoredDepsIncludingVersion(deps: any): CycloneDxSbom;
|
|
65
|
+
/** This method gets a component object, and a string name, and checks if the name is a substring of the component' purl.
|
|
66
|
+
* @param {} component to search in its dependencies
|
|
67
|
+
* @param {String} name to be checked.
|
|
68
|
+
*
|
|
69
|
+
* @return {boolean}
|
|
70
|
+
*/
|
|
71
|
+
checkIfPackageInsideDependsOnList(component: any, name: string): boolean;
|
|
72
|
+
/** Removes the root component from the sbom
|
|
73
|
+
*/
|
|
74
|
+
removeRootComponent(): void;
|
|
75
|
+
setSourceManifest(manifestData: any): void;
|
|
76
|
+
}
|
|
77
|
+
import { PackageURL } from "packageurl-js";
|