@trustify-da/trustify-da-javascript-client 0.3.0-ea.7ed8d8c → 0.3.0-ea.7ee4047

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.
Files changed (98) hide show
  1. package/README.md +388 -20
  2. package/dist/package.json +39 -26
  3. package/dist/src/analysis.d.ts +58 -20
  4. package/dist/src/analysis.js +134 -78
  5. package/dist/src/batch_opts.d.ts +24 -0
  6. package/dist/src/batch_opts.js +35 -0
  7. package/dist/src/cli.js +427 -12
  8. package/dist/src/config.d.ts +120 -0
  9. package/dist/src/config.js +260 -0
  10. package/dist/src/cyclone_dx_sbom.d.ts +30 -2
  11. package/dist/src/cyclone_dx_sbom.js +95 -9
  12. package/dist/src/index.d.ts +154 -16
  13. package/dist/src/index.js +372 -36
  14. package/dist/src/license/index.d.ts +28 -0
  15. package/dist/src/license/index.js +106 -0
  16. package/dist/src/license/license_utils.d.ts +40 -0
  17. package/dist/src/license/license_utils.js +137 -0
  18. package/dist/src/license/licenses_api.d.ts +34 -0
  19. package/dist/src/license/licenses_api.js +98 -0
  20. package/dist/src/license/project_license.d.ts +20 -0
  21. package/dist/src/license/project_license.js +62 -0
  22. package/dist/src/oci_image/images.d.ts +1 -1
  23. package/dist/src/oci_image/images.js +15 -1
  24. package/dist/src/oci_image/utils.d.ts +5 -5
  25. package/dist/src/oci_image/utils.js +11 -2
  26. package/dist/src/package_version.d.ts +8 -0
  27. package/dist/src/package_version.js +31 -0
  28. package/dist/src/provider.d.ts +16 -3
  29. package/dist/src/provider.js +33 -5
  30. package/dist/src/providers/base_java.d.ts +67 -12
  31. package/dist/src/providers/base_java.js +82 -61
  32. package/dist/src/providers/base_javascript.d.ts +99 -12
  33. package/dist/src/providers/base_javascript.js +244 -28
  34. package/dist/src/providers/base_pyproject.d.ts +158 -0
  35. package/dist/src/providers/base_pyproject.js +322 -0
  36. package/dist/src/providers/containerfile_parser.d.ts +5 -0
  37. package/dist/src/providers/containerfile_parser.js +20 -0
  38. package/dist/src/providers/golang_gomodules.d.ts +30 -13
  39. package/dist/src/providers/golang_gomodules.js +219 -122
  40. package/dist/src/providers/gomod_parser.d.ts +4 -0
  41. package/dist/src/providers/gomod_parser.js +16 -0
  42. package/dist/src/providers/java_gradle.d.ts +73 -0
  43. package/dist/src/providers/java_gradle.js +331 -23
  44. package/dist/src/providers/java_gradle_groovy.d.ts +1 -1
  45. package/dist/src/providers/java_gradle_kotlin.d.ts +1 -1
  46. package/dist/src/providers/java_maven.d.ts +44 -9
  47. package/dist/src/providers/java_maven.js +299 -13
  48. package/dist/src/providers/javascript_bun.d.ts +22 -0
  49. package/dist/src/providers/javascript_bun.js +141 -0
  50. package/dist/src/providers/javascript_npm.d.ts +19 -0
  51. package/dist/src/providers/javascript_npm.js +61 -1
  52. package/dist/src/providers/javascript_pnpm.d.ts +14 -1
  53. package/dist/src/providers/javascript_pnpm.js +55 -5
  54. package/dist/src/providers/javascript_yarn.d.ts +12 -0
  55. package/dist/src/providers/javascript_yarn.js +75 -2
  56. package/dist/src/providers/manifest.d.ts +2 -0
  57. package/dist/src/providers/manifest.js +28 -7
  58. package/dist/src/providers/marker_evaluator.d.ts +14 -0
  59. package/dist/src/providers/marker_evaluator.js +191 -0
  60. package/dist/src/providers/oci_dockerfile.d.ts +51 -0
  61. package/dist/src/providers/oci_dockerfile.js +177 -0
  62. package/dist/src/providers/processors/yarn_berry_processor.d.ts +6 -2
  63. package/dist/src/providers/processors/yarn_berry_processor.js +91 -7
  64. package/dist/src/providers/processors/yarn_classic_processor.d.ts +6 -2
  65. package/dist/src/providers/processors/yarn_classic_processor.js +8 -6
  66. package/dist/src/providers/python_controller.d.ts +5 -1
  67. package/dist/src/providers/python_controller.js +69 -8
  68. package/dist/src/providers/python_pip.d.ts +12 -0
  69. package/dist/src/providers/python_pip.js +18 -8
  70. package/dist/src/providers/python_pip_pyproject.d.ts +61 -0
  71. package/dist/src/providers/python_pip_pyproject.js +146 -0
  72. package/dist/src/providers/python_poetry.d.ts +98 -0
  73. package/dist/src/providers/python_poetry.js +286 -0
  74. package/dist/src/providers/python_uv.d.ts +46 -0
  75. package/dist/src/providers/python_uv.js +275 -0
  76. package/dist/src/providers/requirements_parser.js +6 -9
  77. package/dist/src/providers/rust_cargo.d.ts +56 -0
  78. package/dist/src/providers/rust_cargo.js +682 -0
  79. package/dist/src/providers/tree-sitter-containerfile.wasm +0 -0
  80. package/dist/src/providers/tree-sitter-gomod.wasm +0 -0
  81. package/dist/src/providers/tree-sitter-requirements.wasm +0 -0
  82. package/dist/src/remediate.d.ts +107 -0
  83. package/dist/src/remediate.js +244 -0
  84. package/dist/src/remediation.d.ts +81 -0
  85. package/dist/src/remediation.js +475 -0
  86. package/dist/src/remediation_report.d.ts +23 -0
  87. package/dist/src/remediation_report.js +180 -0
  88. package/dist/src/sbom.d.ts +28 -2
  89. package/dist/src/sbom.js +26 -4
  90. package/dist/src/tools.d.ts +53 -11
  91. package/dist/src/tools.js +147 -13
  92. package/dist/src/updaters/maven_updater.d.ts +58 -0
  93. package/dist/src/updaters/maven_updater.js +345 -0
  94. package/dist/src/updaters/toml_updater.d.ts +62 -0
  95. package/dist/src/updaters/toml_updater.js +276 -0
  96. package/dist/src/workspace.d.ts +71 -0
  97. package/dist/src/workspace.js +257 -0
  98. package/package.json +40 -27
package/dist/package.json CHANGED
@@ -25,7 +25,9 @@
25
25
  "provenance": true
26
26
  },
27
27
  "type": "module",
28
- "bin": "dist/src/cli.js",
28
+ "bin": {
29
+ "trustify-da": "dist/src/cli.js"
30
+ },
29
31
  "main": "dist/src/index.js",
30
32
  "module": "dist/src/index.js",
31
33
  "types": "dist/src/index.d.ts",
@@ -35,47 +37,57 @@
35
37
  "config/**/*"
36
38
  ],
37
39
  "scripts": {
38
- "lint": "eslint src test --ext js",
39
- "lint:fix": "eslint src test --ext js --fix",
40
+ "lint": "eslint src test",
41
+ "lint:fix": "eslint src test --fix",
40
42
  "test": "c8 npm run tests",
41
- "tests": "mocha --config .mocharc.json --grep \".*analysis module.*\" --invert",
43
+ "tests": "mocha --config .mocharc.json",
42
44
  "tests:rep": "mocha --reporter-option maxDiffSize=0 --reporter json > unit-tests-result.json",
45
+ "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 && cp node_modules/tree-sitter-containerfile/tree-sitter-containerfile.wasm src/providers/tree-sitter-containerfile.wasm",
43
46
  "precompile": "rm -rf dist",
44
- "compile": "tsc -p tsconfig.json"
47
+ "compile": "tsc -p tsconfig.json",
48
+ "compile:dev": "tsc -p tsconfig.dev.json",
49
+ "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 && cp node_modules/tree-sitter-containerfile/tree-sitter-containerfile.wasm dist/src/providers/tree-sitter-containerfile.wasm"
45
50
  },
46
51
  "dependencies": {
47
- "@babel/core": "^7.23.2",
48
- "@cyclonedx/cyclonedx-library": "^6.13.0",
52
+ "@yarnpkg/parsers": "^3.1.0",
49
53
  "eslint-import-resolver-typescript": "^4.4.4",
50
- "fast-toml": "^0.5.4",
54
+ "fast-glob": "^3.3.3",
51
55
  "fast-xml-parser": "^5.3.4",
52
56
  "help": "^3.0.2",
53
- "https-proxy-agent": "^7.0.6",
57
+ "https-proxy-agent": "^9.0.0",
58
+ "js-yaml": "^4.1.1",
59
+ "jsonc-parser": "^3.3.1",
60
+ "micromatch": "^4.0.8",
54
61
  "node-fetch": "^3.3.2",
62
+ "p-limit": "^7.3.0",
55
63
  "packageurl-js": "~1.0.2",
64
+ "smol-toml": "^1.6.0",
65
+ "tree-sitter-containerfile": "^0.8.1",
66
+ "tree-sitter-gomod": "github:strum355/tree-sitter-go-mod#56326f2ad478892ace58ff247a97d492a3cbcdda",
56
67
  "tree-sitter-requirements": "github:Strum355/tree-sitter-requirements#d0261ee76b84253997fe70d7d397e78c006c3801",
57
- "web-tree-sitter": "^0.26.6",
68
+ "web-tree-sitter": "^0.26.7",
58
69
  "yargs": "^18.0.0"
59
70
  },
60
71
  "devDependencies": {
61
- "@babel/core": "^7.23.2",
62
- "@trustify-da/trustify-da-api-model": "^2.0.1",
63
- "@types/node": "^20.17.30",
72
+ "@cyclonedx/cyclonedx-library": "^10.2.0",
73
+ "@eslint/js": "^10.0.0",
74
+ "@trustify-da/trustify-da-api-model": "^2.0.12",
75
+ "@types/node": "^25.9.1",
64
76
  "@types/which": "^3.0.4",
65
- "babel-plugin-rewire": "^1.2.0",
77
+ "ajv": "^8.20.0",
66
78
  "c8": "^11.0.0",
67
- "chai": "^4.3.7",
68
- "eslint": "^8.42.0",
79
+ "chai": "^6.2.2",
80
+ "eslint": "^10.4.1",
69
81
  "eslint-import-resolver-typescript": "^4.4.4",
70
- "eslint-plugin-editorconfig": "^4.0.3",
71
- "eslint-plugin-import": "^2.29.1",
82
+ "eslint-plugin-import-x": "^4.16.2",
72
83
  "esmock": "^2.6.2",
73
- "mocha": "^10.2.0",
84
+ "globals": "^17.6.0",
85
+ "mocha": "^11.7.6",
74
86
  "msw": "^2.12.7",
75
- "sinon": "^15.1.2",
76
- "sinon-chai": "^3.7.0",
77
- "typescript": "^5.1.3",
78
- "which": "^5.0.0"
87
+ "sinon": "^22.0.0",
88
+ "sinon-chai": "^4.0.1",
89
+ "typescript": "^6.0.3",
90
+ "which": "^7.0.0"
79
91
  },
80
92
  "mocha": {
81
93
  "check-leaks": false,
@@ -103,12 +115,13 @@
103
115
  "reporter": [
104
116
  "html",
105
117
  "json",
118
+ "lcov",
106
119
  "text"
107
120
  ]
108
121
  },
109
- "eslintIgnore": [
110
- "index.js"
111
- ],
122
+ "overrides": {
123
+ "tree-sitter": "0.22.4"
124
+ },
112
125
  "resolutions": {
113
126
  "@hapi/joi": "17.1.1"
114
127
  }
@@ -1,14 +1,12 @@
1
- /**
2
- * Utility function for fetching vendor tokens
3
- * @param {import("index.js").Options} [opts={}] - optional various options to pass along the application
4
- * @returns {{}}
5
- */
6
- export function getTokenHeaders(opts?: import("index.js").Options): {};
1
+ /** Media type for CycloneDX JSON batch payloads (batch-analysis API). */
2
+ export const CYCLONEDX_JSON_MEDIA_TYPE: "application/vnd.cyclonedx+json";
7
3
  declare namespace _default {
8
4
  export { requestComponent };
9
5
  export { requestStack };
6
+ export { requestStackBatch };
10
7
  export { requestImages };
11
8
  export { validateToken };
9
+ export { appendAnalysisQueryParams };
12
10
  }
13
11
  export default _default;
14
12
  /**
@@ -17,28 +15,62 @@ export default _default;
17
15
  * @param {string} manifest - path for the manifest
18
16
  * @param {string} url - the backend url to send the request to
19
17
  * @param {import("index.js").Options} [opts={}] - optional various options to pass along the application
20
- * @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>}
18
+ * @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>}
21
19
  */
22
- declare function requestComponent(provider: import("./provider").Provider, manifest: string, url: string, opts?: import("index.js").Options): Promise<import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport").AnalysisReport>;
20
+ declare function requestComponent(provider: any, manifest: string, url: string, opts?: any): Promise<import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport>;
23
21
  /**
24
- * Send a stack analysis request and get the report as 'text/html' or 'application/json'.
25
- * @param {import('./provider').Provider} provider - the provided data for constructing the request
26
- * @param {string} manifest - path for the manifest
27
- * @param {string} url - the backend url to send the request to
28
- * @param {boolean} [html=false] - true will return 'text/html', false will return 'application/json'
29
- * @param {import("index.js").Options} [opts={}] - optional various options to pass along the application
30
- * @returns {Promise<string|import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>}
22
+ * @overload
23
+ * @param {import('./provider').Provider} provider
24
+ * @param {string} manifest
25
+ * @param {string} url
26
+ * @param {true} [html]
27
+ * @param {import("index.js").Options} [opts={}]
28
+ * @returns {Promise<string>}
29
+ */
30
+ declare function requestStack(provider: any, manifest: string, url: string, html?: true | undefined, opts?: any): Promise<string>;
31
+ /**
32
+ * @overload
33
+ * @param {import('./provider').Provider} provider
34
+ * @param {string} manifest
35
+ * @param {string} url
36
+ * @param {false} [html]
37
+ * @param {import("index.js").Options} [opts={}]
38
+ * @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>>}
39
+ */
40
+ declare function requestStack(provider: any, manifest: string, url: string, html?: false | undefined, opts?: any): Promise<import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport>;
41
+ /**
42
+ * @overload
43
+ * @param {Object.<string, object>} sbomByPurl
44
+ * @param {string} url
45
+ * @param {true} [html=false]
46
+ * @param {import("index.js").Options} [opts={}]
47
+ * @returns {Promise<string>}
48
+ */
49
+ declare function requestStackBatch(sbomByPurl: {
50
+ [x: string]: object;
51
+ }, url: string, html?: true | undefined, opts?: any): Promise<string>;
52
+ /**
53
+ * @overload
54
+ * @param {Object.<string, object>} sbomByPurl
55
+ * @param {string} url
56
+ * @param {false} [html=false]
57
+ * @param {import("index.js").Options} [opts={}]
58
+ * @returns {Promise<Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>>}
31
59
  */
32
- declare function requestStack(provider: import("./provider").Provider, manifest: string, url: string, html?: boolean, opts?: import("index.js").Options): Promise<string | import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport").AnalysisReport>;
60
+ declare function requestStackBatch(sbomByPurl: {
61
+ [x: string]: object;
62
+ }, url: string, html?: false | undefined, opts?: any): Promise<{
63
+ [x: string]: import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport;
64
+ }>;
33
65
  /**
34
66
  *
35
67
  * @param {Array<string>} imageRefs
36
68
  * @param {string} url
37
69
  * @param {import("index.js").Options} [opts={}] - optional various options to pass along the application
38
- * @returns {Promise<string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>>}
70
+ * @returns {Promise<string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>>}
39
71
  */
40
- declare function requestImages(imageRefs: Array<string>, 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;
72
+ declare function requestImages(imageRefs: Array<string>, url: string, html?: boolean, opts?: any): Promise<string | {
73
+ [x: string]: import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport;
42
74
  }>;
43
75
  /**
44
76
  *
@@ -46,4 +78,10 @@ declare function requestImages(imageRefs: Array<string>, url: string, html?: boo
46
78
  * @param {import("index.js").Options} [opts={}] - optional various options to pass headers for t he validateToken Request
47
79
  * @return {Promise<number>} return the HTTP status Code of the response from the validate token request.
48
80
  */
49
- declare function validateToken(url: any, opts?: import("index.js").Options): Promise<number>;
81
+ declare function validateToken(url: any, opts?: any): Promise<number>;
82
+ /**
83
+ * Append common analysis query parameters (recommend, providers, sources) to a URL.
84
+ * @param {URL} url - the URL object to append query parameters to
85
+ * @param {import("index.js").Options} [opts={}] - options containing parameter overrides
86
+ */
87
+ declare function appendAnalysisQueryParams(url: URL, opts?: any): void;
@@ -1,28 +1,30 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { EOL } from "os";
4
- import { HttpsProxyAgent } from "https-proxy-agent";
4
+ import { runLicenseCheck } from "./license/index.js";
5
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 = "trust-da-token";
9
- const rhdaTelemetryId = "telemetry-anonymous-id";
10
- const rhdaSourceHeader = "trust-da-source";
11
- const rhdaOperationTypeHeader = "trust-da-operation-type";
12
- const rhdaPackageManagerHeader = "trust-da-pkg-manager";
6
+ import { addProxyAgent, getCustom, getTokenHeaders, TRUSTIFY_DA_OPERATION_TYPE_HEADER, TRUSTIFY_DA_PACKAGE_MANAGER_HEADER } from "./tools.js";
7
+ /** Media type for CycloneDX JSON batch payloads (batch-analysis API). */
8
+ export const CYCLONEDX_JSON_MEDIA_TYPE = 'application/vnd.cyclonedx+json';
9
+ export default { requestComponent, requestStack, requestStackBatch, requestImages, validateToken, appendAnalysisQueryParams };
13
10
  /**
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 trustify DA options that may contain proxy configuration
17
- * @returns {RequestInit} The fetch options with proxy agent if applicable
11
+ * @overload
12
+ * @param {import('./provider').Provider} provider
13
+ * @param {string} manifest
14
+ * @param {string} url
15
+ * @param {true} [html]
16
+ * @param {import("index.js").Options} [opts={}]
17
+ * @returns {Promise<string>}
18
+ */
19
+ /**
20
+ * @overload
21
+ * @param {import('./provider').Provider} provider
22
+ * @param {string} manifest
23
+ * @param {string} url
24
+ * @param {false} [html]
25
+ * @param {import("index.js").Options} [opts={}]
26
+ * @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>>}
18
27
  */
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
28
  /**
27
29
  * Send a stack analysis request and get the report as 'text/html' or 'application/json'.
28
30
  * @param {import('./provider').Provider} provider - the provided data for constructing the request
@@ -30,20 +32,23 @@ function addProxyAgent(options, opts) {
30
32
  * @param {string} url - the backend url to send the request to
31
33
  * @param {boolean} [html=false] - true will return 'text/html', false will return 'application/json'
32
34
  * @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>}
35
+ * @returns {Promise<string|import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>}
34
36
  */
35
37
  async function requestStack(provider, manifest, url, html = false, opts = {}) {
36
38
  opts["source-manifest"] = Buffer.from(fs.readFileSync(manifest).toString()).toString('base64');
37
39
  opts["manifest-type"] = path.parse(manifest).base;
38
40
  let provided = await provider.provideStack(manifest, opts); // throws error if content providing failed
41
+ if (provided.batch) {
42
+ return requestStackBatch(JSON.parse(provided.content), url, html, opts);
43
+ }
39
44
  opts["source-manifest"] = "";
40
- opts[rhdaOperationTypeHeader.toUpperCase().replaceAll("-", "_")] = "stack-analysis";
45
+ opts[TRUSTIFY_DA_OPERATION_TYPE_HEADER.toUpperCase().replaceAll("-", "_")] = "stack-analysis";
41
46
  let startTime = new Date();
42
47
  let endTime;
43
48
  if (process.env["TRUSTIFY_DA_DEBUG"] === "true") {
44
49
  console.log("Starting time of sending stack analysis request to the dependency analytics server= " + startTime);
45
50
  }
46
- opts[rhdaPackageManagerHeader.toUpperCase().replaceAll("-", "_")] = provided.ecosystem;
51
+ opts[TRUSTIFY_DA_PACKAGE_MANAGER_HEADER.toUpperCase().replaceAll("-", "_")] = provided.ecosystem;
47
52
  const fetchOptions = addProxyAgent({
48
53
  method: 'POST',
49
54
  headers: {
@@ -53,10 +58,8 @@ async function requestStack(provider, manifest, url, html = false, opts = {}) {
53
58
  },
54
59
  body: provided.content
55
60
  }, 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
- }
61
+ const finalUrl = new URL(`${url}/api/v5/analysis`);
62
+ appendAnalysisQueryParams(finalUrl, opts);
60
63
  let resp = await fetch(finalUrl, fetchOptions);
61
64
  let result;
62
65
  if (resp.status === 200) {
@@ -90,17 +93,20 @@ async function requestStack(provider, manifest, url, html = false, opts = {}) {
90
93
  * @param {string} manifest - path for the manifest
91
94
  * @param {string} url - the backend url to send the request to
92
95
  * @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>}
96
+ * @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>}
94
97
  */
95
98
  async function requestComponent(provider, manifest, url, opts = {}) {
96
99
  opts["source-manifest"] = Buffer.from(fs.readFileSync(manifest).toString()).toString('base64');
97
100
  let provided = await provider.provideComponent(manifest, opts); // throws error if content providing failed
101
+ if (provided.batch) {
102
+ return requestStackBatch(JSON.parse(provided.content), url, false, opts);
103
+ }
98
104
  opts["source-manifest"] = "";
99
- opts[rhdaOperationTypeHeader.toUpperCase().replaceAll("-", "_")] = "component-analysis";
105
+ opts[TRUSTIFY_DA_OPERATION_TYPE_HEADER.toUpperCase().replaceAll("-", "_")] = "component-analysis";
100
106
  if (process.env["TRUSTIFY_DA_DEBUG"] === "true") {
101
107
  console.log("Starting time of sending component analysis request to Trustify DA backend server= " + new Date());
102
108
  }
103
- opts[rhdaPackageManagerHeader.toUpperCase().replaceAll("-", "_")] = provided.ecosystem;
109
+ opts[TRUSTIFY_DA_PACKAGE_MANAGER_HEADER.toUpperCase().replaceAll("-", "_")] = provided.ecosystem;
104
110
  const fetchOptions = addProxyAgent({
105
111
  method: 'POST',
106
112
  headers: {
@@ -110,10 +116,8 @@ async function requestComponent(provider, manifest, url, opts = {}) {
110
116
  },
111
117
  body: provided.content
112
118
  }, 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
- }
119
+ const finalUrl = new URL(`${url}/api/v5/analysis`);
120
+ appendAnalysisQueryParams(finalUrl, opts);
117
121
  let resp = await fetch(finalUrl, fetchOptions);
118
122
  let result;
119
123
  if (resp.status === 200) {
@@ -127,18 +131,89 @@ async function requestComponent(provider, manifest, url, opts = {}) {
127
131
  console.log(JSON.stringify(result, null, 4));
128
132
  console.log("Ending time of sending component analysis request to Trustify DA backend server= " + new Date());
129
133
  }
134
+ const licenseCheckEnabled = typeof opts.licenseCheck === 'boolean'
135
+ ? opts.licenseCheck
136
+ : getCustom('TRUSTIFY_DA_LICENSE_CHECK', 'true', opts) !== 'false';
137
+ if (licenseCheckEnabled) {
138
+ try {
139
+ result.licenseSummary = await runLicenseCheck(provided.content, manifest, url, opts, result);
140
+ }
141
+ catch (licenseErr) {
142
+ result.licenseSummary = { error: licenseErr.message };
143
+ }
144
+ }
130
145
  }
131
146
  else {
132
147
  throw new Error(`Got error response from Trustify DA backend - http return code : ${resp.status}, ex-request-id: ${resp.headers.get("ex-request-id")} error message => ${await resp.text()}`);
133
148
  }
134
149
  return Promise.resolve(result);
135
150
  }
151
+ /**
152
+ * @overload
153
+ * @param {Object.<string, object>} sbomByPurl
154
+ * @param {string} url
155
+ * @param {true} [html=false]
156
+ * @param {import("index.js").Options} [opts={}]
157
+ * @returns {Promise<string>}
158
+ */
159
+ /**
160
+ * @overload
161
+ * @param {Object.<string, object>} sbomByPurl
162
+ * @param {string} url
163
+ * @param {false} [html=false]
164
+ * @param {import("index.js").Options} [opts={}]
165
+ * @returns {Promise<Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>>}
166
+ */
167
+ /**
168
+ * Send a batch stack analysis request for multiple manifests (SBOMs keyed by purl).
169
+ * @param {Object.<string, object>} sbomByPurl - Map of root purl to CycloneDX SBOM object
170
+ * @param {string} url - the backend url
171
+ * @param {boolean} [html=false] - true returns HTML, false returns JSON
172
+ * @param {import("index.js").Options} [opts={}]
173
+ * @returns {Promise<string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>>}
174
+ */
175
+ async function requestStackBatch(sbomByPurl, url, html = false, opts = {}) {
176
+ const finalUrl = new URL(`${url}/api/v5/batch-analysis`);
177
+ appendAnalysisQueryParams(finalUrl, opts);
178
+ const fetchOptions = addProxyAgent({
179
+ method: 'POST',
180
+ headers: {
181
+ 'Accept': html ? 'text/html' : 'application/json',
182
+ 'Content-Type': CYCLONEDX_JSON_MEDIA_TYPE,
183
+ ...getTokenHeaders(opts)
184
+ },
185
+ body: JSON.stringify(sbomByPurl)
186
+ }, opts);
187
+ const resp = await fetch(finalUrl, fetchOptions);
188
+ if (resp.status === 200) {
189
+ let result;
190
+ if (!html) {
191
+ result = await resp.json();
192
+ }
193
+ else {
194
+ result = await resp.text();
195
+ }
196
+ if (process.env["TRUSTIFY_DA_DEBUG"] === "true") {
197
+ const exRequestId = resp.headers.get("ex-request-id");
198
+ if (exRequestId) {
199
+ console.log("Unique Identifier associated with this request - ex-request-id=" + exRequestId);
200
+ }
201
+ console.log("Response body received from Trustify DA backend server : " + EOL + EOL);
202
+ console.log(JSON.stringify(result, null, 4));
203
+ console.log("Ending time of sending batch stack analysis request to Trustify DA backend server= " + new Date());
204
+ }
205
+ return result;
206
+ }
207
+ else {
208
+ throw new Error(`Got error response from Trustify DA backend - http return code : ${resp.status}, ex-request-id: ${resp.headers.get("ex-request-id")} error message => ${await resp.text()}`);
209
+ }
210
+ }
136
211
  /**
137
212
  *
138
213
  * @param {Array<string>} imageRefs
139
214
  * @param {string} url
140
215
  * @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>>}
216
+ * @returns {Promise<string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>>}
142
217
  */
143
218
  async function requestImages(imageRefs, url, html = false, opts = {}) {
144
219
  const imageSboms = {};
@@ -146,19 +221,18 @@ async function requestImages(imageRefs, url, html = false, opts = {}) {
146
221
  const parsedImageRef = parseImageRef(image, opts);
147
222
  imageSboms[parsedImageRef.getPackageURL().toString()] = generateImageSBOM(parsedImageRef, opts);
148
223
  }
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, {
224
+ const finalUrl = new URL(`${url}/api/v5/batch-analysis`);
225
+ appendAnalysisQueryParams(finalUrl, opts);
226
+ const fetchOptions = addProxyAgent({
154
227
  method: 'POST',
155
228
  headers: {
156
229
  'Accept': html ? 'text/html' : 'application/json',
157
- 'Content-Type': 'application/vnd.cyclonedx+json',
230
+ 'Content-Type': CYCLONEDX_JSON_MEDIA_TYPE,
158
231
  ...getTokenHeaders(opts)
159
232
  },
160
233
  body: JSON.stringify(imageSboms),
161
- });
234
+ }, opts);
235
+ const resp = await fetch(finalUrl, fetchOptions);
162
236
  if (resp.status === 200) {
163
237
  let result;
164
238
  if (!html) {
@@ -182,6 +256,24 @@ async function requestImages(imageRefs, url, html = false, opts = {}) {
182
256
  throw new Error(`Got error response from Trustify DA backend - http return code : ${resp.status}, ex-request-id: ${resp.headers.get("ex-request-id")} error message => ${await resp.text()}`);
183
257
  }
184
258
  }
259
+ /**
260
+ * Append common analysis query parameters (recommend, providers, sources) to a URL.
261
+ * @param {URL} url - the URL object to append query parameters to
262
+ * @param {import("index.js").Options} [opts={}] - options containing parameter overrides
263
+ */
264
+ function appendAnalysisQueryParams(url, opts = {}) {
265
+ if (getCustom('TRUSTIFY_DA_RECOMMEND', 'true', opts) === 'false') {
266
+ url.searchParams.append('recommend', 'false');
267
+ }
268
+ const providers = getCustom('TRUSTIFY_DA_PROVIDERS', null, opts);
269
+ if (providers) {
270
+ url.searchParams.append('providers', providers);
271
+ }
272
+ const sources = getCustom('TRUSTIFY_DA_SOURCES', null, opts);
273
+ if (sources) {
274
+ url.searchParams.append('sources', sources);
275
+ }
276
+ }
185
277
  /**
186
278
  *
187
279
  * @param url the backend url to send the request to
@@ -195,7 +287,7 @@ async function validateToken(url, opts = {}) {
195
287
  ...getTokenHeaders(opts),
196
288
  }
197
289
  }, opts);
198
- let resp = await fetch(`${url}/api/v4/token`, fetchOptions);
290
+ let resp = await fetch(`${url}/api/v5/token`, fetchOptions);
199
291
  if (process.env["TRUSTIFY_DA_DEBUG"] === "true") {
200
292
  let exRequestId = resp.headers.get("ex-request-id");
201
293
  if (exRequestId) {
@@ -204,39 +296,3 @@ async function validateToken(url, opts = {}) {
204
296
  }
205
297
  return resp.status;
206
298
  }
207
- /**
208
- *
209
- * @param {string} headerName - the header name to populate in request
210
- * @param headers
211
- * @param {string} optsKey - key in the options object to use the value for
212
- * @param {import("index.js").Options} [opts={}] - options input object to fetch header values from
213
- * @private
214
- */
215
- function setRhdaHeader(headerName, headers, optsKey, opts) {
216
- let rhdaHeaderValue = getCustom(optsKey, null, opts);
217
- if (rhdaHeaderValue) {
218
- headers[headerName] = rhdaHeaderValue;
219
- }
220
- }
221
- /**
222
- * Utility function for fetching vendor tokens
223
- * @param {import("index.js").Options} [opts={}] - optional various options to pass along the application
224
- * @returns {{}}
225
- */
226
- export function getTokenHeaders(opts = {}) {
227
- let headers = {};
228
- setRhdaHeader(rhdaTokenHeader, headers, 'TRUSTIFY_DA_TOKEN', opts);
229
- setRhdaHeader(rhdaSourceHeader, headers, 'TRUSTIFY_DA_SOURCE', opts);
230
- setRhdaHeader(rhdaOperationTypeHeader, headers, rhdaOperationTypeHeader.toUpperCase().replaceAll("-", "_"), opts);
231
- setRhdaHeader(rhdaPackageManagerHeader, headers, rhdaPackageManagerHeader.toUpperCase().replaceAll("-", "_"), opts);
232
- setRhdaHeader(rhdaTelemetryId, headers, 'TRUSTIFY_DA_TELEMETRY_ID', opts);
233
- if (getCustom("TRUSTIFY_DA_DEBUG", null, opts) === "true") {
234
- console.log("Headers Values to be sent to Trustify DA backend:" + EOL);
235
- for (const headerKey in headers) {
236
- if (!headerKey.match(RegexNotToBeLogged)) {
237
- console.log(`${headerKey}: ${headers[headerKey]}`);
238
- }
239
- }
240
- }
241
- return headers;
242
- }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Whether to skip failed manifests and continue (default), or fail on first SBOM/validation error.
3
+ * `opts.continueOnError` overrides; env `TRUSTIFY_DA_CONTINUE_ON_ERROR=false` disables continuation.
4
+ *
5
+ * @param {{ continueOnError?: boolean, TRUSTIFY_DA_CONTINUE_ON_ERROR?: string, [key: string]: unknown }} [opts={}]
6
+ * @returns {boolean} true = collect errors (default), false = fail-fast
7
+ */
8
+ export function resolveContinueOnError(opts?: {
9
+ continueOnError?: boolean;
10
+ TRUSTIFY_DA_CONTINUE_ON_ERROR?: string;
11
+ [key: string]: unknown;
12
+ }): boolean;
13
+ /**
14
+ * When true, `stackAnalysisBatch` returns `{ analysis, metadata }` instead of the backend response only.
15
+ * `opts.batchMetadata` overrides; env `TRUSTIFY_DA_BATCH_METADATA=true` enables.
16
+ *
17
+ * @param {{ batchMetadata?: boolean, TRUSTIFY_DA_BATCH_METADATA?: string, [key: string]: unknown }} [opts={}]
18
+ * @returns {boolean}
19
+ */
20
+ export function resolveBatchMetadata(opts?: {
21
+ batchMetadata?: boolean;
22
+ TRUSTIFY_DA_BATCH_METADATA?: string;
23
+ [key: string]: unknown;
24
+ }): boolean;
@@ -0,0 +1,35 @@
1
+ import { getCustom } from './tools.js';
2
+ /**
3
+ * Whether to skip failed manifests and continue (default), or fail on first SBOM/validation error.
4
+ * `opts.continueOnError` overrides; env `TRUSTIFY_DA_CONTINUE_ON_ERROR=false` disables continuation.
5
+ *
6
+ * @param {{ continueOnError?: boolean, TRUSTIFY_DA_CONTINUE_ON_ERROR?: string, [key: string]: unknown }} [opts={}]
7
+ * @returns {boolean} true = collect errors (default), false = fail-fast
8
+ */
9
+ export function resolveContinueOnError(opts = {}) {
10
+ if (typeof opts.continueOnError === 'boolean') {
11
+ return opts.continueOnError;
12
+ }
13
+ const v = getCustom('TRUSTIFY_DA_CONTINUE_ON_ERROR', null, opts);
14
+ if (v != null && String(v).trim() !== '') {
15
+ return String(v).toLowerCase() !== 'false';
16
+ }
17
+ return true;
18
+ }
19
+ /**
20
+ * When true, `stackAnalysisBatch` returns `{ analysis, metadata }` instead of the backend response only.
21
+ * `opts.batchMetadata` overrides; env `TRUSTIFY_DA_BATCH_METADATA=true` enables.
22
+ *
23
+ * @param {{ batchMetadata?: boolean, TRUSTIFY_DA_BATCH_METADATA?: string, [key: string]: unknown }} [opts={}]
24
+ * @returns {boolean}
25
+ */
26
+ export function resolveBatchMetadata(opts = {}) {
27
+ if (typeof opts.batchMetadata === 'boolean') {
28
+ return opts.batchMetadata;
29
+ }
30
+ const v = getCustom('TRUSTIFY_DA_BATCH_METADATA', null, opts);
31
+ if (v != null && String(v).trim() !== '') {
32
+ return String(v).toLowerCase() === 'true';
33
+ }
34
+ return false;
35
+ }