@trustify-da/trustify-da-javascript-client 0.3.0-ea.61444d4 → 0.3.0-ea.62b88e5

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 (59) hide show
  1. package/README.md +22 -8
  2. package/dist/package.json +6 -5
  3. package/dist/src/analysis.d.ts +40 -19
  4. package/dist/src/analysis.js +41 -5
  5. package/dist/src/cli.js +95 -17
  6. package/dist/src/config.d.ts +120 -0
  7. package/dist/src/config.js +260 -0
  8. package/dist/src/cyclone_dx_sbom.d.ts +13 -0
  9. package/dist/src/cyclone_dx_sbom.js +39 -1
  10. package/dist/src/index.d.ts +23 -23
  11. package/dist/src/index.js +23 -39
  12. package/dist/src/license/index.d.ts +2 -2
  13. package/dist/src/license/index.js +9 -6
  14. package/dist/src/license/licenses_api.d.ts +2 -2
  15. package/dist/src/license/licenses_api.js +1 -1
  16. package/dist/src/package_version.d.ts +8 -0
  17. package/dist/src/package_version.js +31 -0
  18. package/dist/src/providers/base_java.d.ts +53 -0
  19. package/dist/src/providers/base_java.js +64 -17
  20. package/dist/src/providers/base_javascript.d.ts +54 -0
  21. package/dist/src/providers/base_javascript.js +106 -4
  22. package/dist/src/providers/golang_gomodules.js +6 -5
  23. package/dist/src/providers/java_gradle.d.ts +48 -0
  24. package/dist/src/providers/java_gradle.js +204 -20
  25. package/dist/src/providers/java_maven.d.ts +28 -8
  26. package/dist/src/providers/java_maven.js +104 -10
  27. package/dist/src/providers/javascript_bun.d.ts +12 -0
  28. package/dist/src/providers/javascript_bun.js +42 -1
  29. package/dist/src/providers/javascript_npm.d.ts +13 -0
  30. package/dist/src/providers/javascript_npm.js +40 -1
  31. package/dist/src/providers/javascript_pnpm.d.ts +13 -0
  32. package/dist/src/providers/javascript_pnpm.js +47 -1
  33. package/dist/src/providers/javascript_yarn.d.ts +12 -0
  34. package/dist/src/providers/javascript_yarn.js +75 -2
  35. package/dist/src/providers/manifest.js +6 -3
  36. package/dist/src/providers/processors/yarn_berry_processor.d.ts +5 -1
  37. package/dist/src/providers/processors/yarn_berry_processor.js +3 -2
  38. package/dist/src/providers/processors/yarn_classic_processor.d.ts +5 -1
  39. package/dist/src/providers/processors/yarn_classic_processor.js +8 -6
  40. package/dist/src/providers/python_uv.js +6 -0
  41. package/dist/src/providers/requirements_parser.js +1 -1
  42. package/dist/src/providers/rust_cargo.js +34 -52
  43. package/dist/src/remediate.d.ts +90 -4
  44. package/dist/src/remediate.js +153 -58
  45. package/dist/src/remediation.d.ts +54 -30
  46. package/dist/src/remediation.js +92 -53
  47. package/dist/src/remediation_report.d.ts +3 -20
  48. package/dist/src/remediation_report.js +37 -16
  49. package/dist/src/sbom.d.ts +11 -0
  50. package/dist/src/sbom.js +10 -0
  51. package/dist/src/tools.d.ts +9 -11
  52. package/dist/src/tools.js +34 -13
  53. package/dist/src/updaters/maven_updater.d.ts +40 -8
  54. package/dist/src/updaters/maven_updater.js +26 -3
  55. package/dist/src/updaters/toml_updater.d.ts +42 -13
  56. package/dist/src/updaters/toml_updater.js +36 -4
  57. package/dist/src/workspace.d.ts +2 -1
  58. package/dist/src/workspace.js +2 -1
  59. package/package.json +7 -6
@@ -0,0 +1,260 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { load as yamlLoad } from 'js-yaml';
4
+ /**
5
+ * @typedef {{
6
+ * 'group-by'?: 'dependency' | 'bundle',
7
+ * exclude?: string[],
8
+ * labels?: string[],
9
+ * 'branch-prefix'?: string,
10
+ * [key: string]: unknown
11
+ * }} RemediationConfig
12
+ */
13
+ /** @typedef {{ critical?: number, high?: number, 'license-conflicts'?: number, [key: string]: unknown }} FailOnConfig */
14
+ /** @typedef {{ 'fail-on'?: FailOnConfig, [key: string]: unknown }} CheckConfig */
15
+ /** @typedef {{ format?: string, targets?: string[], [key: string]: unknown }} SbomConfig */
16
+ /**
17
+ * @typedef {{
18
+ * 'backend-url'?: string,
19
+ * providers?: string[] | string,
20
+ * sources?: string[] | string,
21
+ * remediation?: RemediationConfig,
22
+ * check?: CheckConfig,
23
+ * sbom?: SbomConfig,
24
+ * [key: string]: unknown
25
+ * }} FileConfig
26
+ */
27
+ /**
28
+ * @typedef {{
29
+ * backendUrl: string | null,
30
+ * backendUrlSource: 'cli' | 'environment' | 'file' | 'default',
31
+ * providers: string[],
32
+ * sources: string[],
33
+ * groupBy: string,
34
+ * remediation: object,
35
+ * check: object,
36
+ * sbom: object
37
+ * }} ResolvedConfig
38
+ */
39
+ /** Config file names discovered by walking up the directory tree, in precedence order. */
40
+ export const CONFIG_FILENAMES = ['.trustify-da.yml', '.trustify-da.yaml'];
41
+ function isMapping(value) {
42
+ if (value == null || typeof value !== 'object' || Array.isArray(value)) {
43
+ return false;
44
+ }
45
+ const prototype = Object.getPrototypeOf(value);
46
+ return prototype === Object.prototype || prototype == null;
47
+ }
48
+ function assertMapping(value, field, source) {
49
+ if (!isMapping(value)) {
50
+ throw new Error(`Invalid config file ${source}: ${field} must be a mapping`);
51
+ }
52
+ }
53
+ function assertString(value, field, source) {
54
+ if (typeof value !== 'string') {
55
+ throw new Error(`Invalid config file ${source}: ${field} must be a string`);
56
+ }
57
+ }
58
+ function assertStringArray(value, field, source) {
59
+ if (!Array.isArray(value) || value.some(item => typeof item !== 'string')) {
60
+ throw new Error(`Invalid config file ${source}: ${field} must be an array of strings`);
61
+ }
62
+ }
63
+ function assertStringOrArray(value, field, source) {
64
+ if (typeof value !== 'string') {
65
+ assertStringArray(value, field, source);
66
+ }
67
+ }
68
+ /**
69
+ * Validates all fields in the initial configuration schema. Unknown fields are preserved.
70
+ * @param {unknown} config
71
+ * @param {string} [source]
72
+ * @returns {FileConfig}
73
+ */
74
+ function validateConfig(config, source = '<config>') {
75
+ assertMapping(config, 'root', source);
76
+ if (config['backend-url'] !== undefined) {
77
+ assertString(config['backend-url'], 'backend-url', source);
78
+ }
79
+ if (config.providers !== undefined) {
80
+ assertStringOrArray(config.providers, 'providers', source);
81
+ }
82
+ if (config.sources !== undefined) {
83
+ assertStringOrArray(config.sources, 'sources', source);
84
+ }
85
+ if (config.remediation !== undefined) {
86
+ assertMapping(config.remediation, 'remediation', source);
87
+ const remediation = config.remediation;
88
+ if (remediation['group-by'] !== undefined && !['dependency', 'bundle'].includes(remediation['group-by'])) {
89
+ throw new Error(`Invalid config file ${source}: remediation.group-by must be dependency or bundle`);
90
+ }
91
+ if (remediation.exclude !== undefined) {
92
+ assertStringArray(remediation.exclude, 'remediation.exclude', source);
93
+ }
94
+ if (remediation.labels !== undefined) {
95
+ assertStringArray(remediation.labels, 'remediation.labels', source);
96
+ }
97
+ if (remediation['branch-prefix'] !== undefined) {
98
+ assertString(remediation['branch-prefix'], 'remediation.branch-prefix', source);
99
+ }
100
+ }
101
+ if (config.check !== undefined) {
102
+ assertMapping(config.check, 'check', source);
103
+ if (config.check['fail-on'] !== undefined) {
104
+ assertMapping(config.check['fail-on'], 'check.fail-on', source);
105
+ for (const field of ['critical', 'high', 'license-conflicts']) {
106
+ const value = config.check['fail-on'][field];
107
+ if (value !== undefined && (typeof value !== 'number' || !Number.isFinite(value))) {
108
+ throw new Error(`Invalid config file ${source}: check.fail-on.${field} must be a finite number`);
109
+ }
110
+ }
111
+ }
112
+ }
113
+ if (config.sbom !== undefined) {
114
+ assertMapping(config.sbom, 'sbom', source);
115
+ if (config.sbom.format !== undefined) {
116
+ assertString(config.sbom.format, 'sbom.format', source);
117
+ }
118
+ if (config.sbom.targets !== undefined) {
119
+ assertStringArray(config.sbom.targets, 'sbom.targets', source);
120
+ }
121
+ }
122
+ return config;
123
+ }
124
+ /**
125
+ * Walks up from `startPath` looking for a `.trustify-da.yml` (or `.yaml`) file,
126
+ * similar to how `.eslintrc` discovery works. If `startPath` points at a file,
127
+ * discovery begins in its containing directory. Within a directory, `.yml` takes
128
+ * precedence over `.yaml`.
129
+ * @param {string} startPath - manifest file or directory to start the search from
130
+ * @returns {string | null} absolute path to the config file, or null if none found
131
+ */
132
+ function findConfigFile(startPath) {
133
+ let dir = path.resolve(startPath || '.');
134
+ try {
135
+ if (fs.statSync(dir).isFile()) {
136
+ dir = path.dirname(dir);
137
+ }
138
+ }
139
+ catch {
140
+ // startPath may not exist yet — walk up from its resolved location anyway
141
+ }
142
+ // Walk up until the filesystem root (where dirname(dir) === dir)
143
+ for (;;) {
144
+ for (const name of CONFIG_FILENAMES) {
145
+ const candidate = path.join(dir, name);
146
+ try {
147
+ if (fs.statSync(candidate).isFile()) {
148
+ return candidate;
149
+ }
150
+ }
151
+ catch {
152
+ // Ignore inaccessible or disappearing candidates and continue discovery.
153
+ }
154
+ }
155
+ const parent = path.dirname(dir);
156
+ if (parent === dir) {
157
+ return null;
158
+ }
159
+ dir = parent;
160
+ }
161
+ }
162
+ /**
163
+ * Discovers and parses `.trustify-da.yml` by walking up from `startPath`.
164
+ * A missing config file is not an error — an empty object is returned so callers
165
+ * can fall back to defaults.
166
+ * @param {string} [startPath] - manifest file or directory to start the search from
167
+ * @returns {FileConfig} the parsed config object, or `{}` when no file is found
168
+ * @throws {Error} when the config file exists but contains malformed YAML
169
+ */
170
+ export function loadConfig(startPath) {
171
+ const configPath = findConfigFile(startPath);
172
+ if (!configPath) {
173
+ return {};
174
+ }
175
+ const content = fs.readFileSync(configPath, 'utf-8');
176
+ let doc;
177
+ try {
178
+ doc = yamlLoad(content);
179
+ }
180
+ catch (err) {
181
+ throw new Error(`Failed to parse config file ${configPath}: ${err.message}`);
182
+ }
183
+ return doc == null ? {} : validateConfig(doc, configPath);
184
+ }
185
+ /**
186
+ * Normalizes a providers/sources value to an array of trimmed strings. Accepts
187
+ * either a YAML array (`[redhat, osv]`) or a comma-separated string (`redhat,osv`).
188
+ * @param {string[] | string | undefined | null} value
189
+ * @returns {string[]}
190
+ */
191
+ function toArray(value) {
192
+ if (Array.isArray(value)) {
193
+ return value.filter(v => typeof v === 'string' && v.trim()).map(v => v.trim());
194
+ }
195
+ if (typeof value === 'string') {
196
+ return value.split(',').map(v => v.trim()).filter(Boolean);
197
+ }
198
+ return [];
199
+ }
200
+ /**
201
+ * Returns the first argument that is neither undefined nor null.
202
+ * @param {...unknown} values
203
+ * @returns {unknown}
204
+ */
205
+ function first(...values) {
206
+ return values.find(v => v != null);
207
+ }
208
+ /**
209
+ * Merges config sources with precedence: CLI flag > environment variable
210
+ * (`TRUSTIFY_DA_*`) > config file > hardcoded default. Providers and sources are
211
+ * normalized to arrays regardless of whether the source used a YAML array or a
212
+ * comma-separated string.
213
+ * @param {FileConfig} [fileConfig={}] - values parsed from `.trustify-da.yml`
214
+ * @param {{ providers?: string, sources?: string, groupBy?: string, backendUrl?: string }} [cliFlags={}]
215
+ * @param {{ [key: string]: string | undefined }} [envVars={}] - typically `process.env`
216
+ * @returns {ResolvedConfig} the resolved, typed config object
217
+ */
218
+ export function mergeConfig(fileConfig = {}, cliFlags = {}, envVars = {}) {
219
+ const file = validateConfig(fileConfig || {});
220
+ const cli = cliFlags || {};
221
+ const env = envVars || {};
222
+ let backendUrl = null;
223
+ let backendUrlSource = 'default';
224
+ if (cli.backendUrl != null) {
225
+ backendUrl = cli.backendUrl;
226
+ backendUrlSource = 'cli';
227
+ }
228
+ else if (env.TRUSTIFY_DA_BACKEND_URL != null) {
229
+ backendUrl = env.TRUSTIFY_DA_BACKEND_URL;
230
+ backendUrlSource = 'environment';
231
+ }
232
+ else if (file['backend-url'] != null) {
233
+ backendUrl = file['backend-url'];
234
+ backendUrlSource = 'file';
235
+ }
236
+ const groupBy = first(cli.groupBy, env.TRUSTIFY_DA_GROUP_BY, file.remediation?.['group-by']) ?? 'dependency';
237
+ if (!['dependency', 'bundle'].includes(groupBy)) {
238
+ throw new Error(`Invalid group-by value "${groupBy}". Expected dependency or bundle.`);
239
+ }
240
+ return {
241
+ backendUrl,
242
+ backendUrlSource,
243
+ providers: toArray(first(cli.providers, env.TRUSTIFY_DA_PROVIDERS, file.providers)),
244
+ sources: toArray(first(cli.sources, env.TRUSTIFY_DA_SOURCES, file.sources)),
245
+ groupBy,
246
+ remediation: file.remediation ?? {},
247
+ check: file.check ?? {},
248
+ sbom: file.sbom ?? {},
249
+ };
250
+ }
251
+ /**
252
+ * Loads and merges the project configuration for a target path.
253
+ * @param {string} [startPath] - manifest file or directory to start discovery from
254
+ * @param {{ providers?: string, sources?: string, groupBy?: string, backendUrl?: string }} [cliFlags={}] - explicit options
255
+ * @param {{ [key: string]: string | undefined }} [envVars={}] - typically `process.env`
256
+ * @returns {ResolvedConfig} the resolved, typed config object
257
+ */
258
+ export function resolveConfig(startPath, cliFlags = {}, envVars = {}) {
259
+ return mergeConfig(loadConfig(startPath), cliFlags, envVars);
260
+ }
@@ -26,6 +26,19 @@ export default class CycloneDxSbom {
26
26
  alg: string;
27
27
  content: string;
28
28
  }>): CycloneDxSbom;
29
+ /**
30
+ * Attach hashes to already-added components by matching their PURL. This is a
31
+ * post-processing step so ecosystem-specific hash sources (e.g. Maven reading
32
+ * the local .m2 cache) can enrich the SBOM without threading their concern
33
+ * through the shared dependency-tree parser. Components without a matching
34
+ * entry, or whose hashes are already set, are left untouched.
35
+ * @param {Map<string, Array<{alg: string, content: string}>>} hashMap - PURL→hashes map
36
+ * @return {CycloneDxSbom} the updated SBOM
37
+ */
38
+ attachHashes(hashMap: Map<string, Array<{
39
+ alg: string;
40
+ content: string;
41
+ }>>): CycloneDxSbom;
29
42
  /** @param {{}} opts - various options, settings and configuration of application.
30
43
  * @return String CycloneDx Sbom json object in a string format
31
44
  */
@@ -1,5 +1,12 @@
1
1
  import { EOL } from "os";
2
2
  import { PackageURL } from "packageurl-js";
3
+ import { getPackageVersion } from "./package_version.js";
4
+ /**
5
+ * This client's version, read once at module load, used to populate
6
+ * metadata.tools.components[].version in the generated SBOM.
7
+ * @type {string|undefined}
8
+ */
9
+ const PACKAGE_VERSION = getPackageVersion();
3
10
  /**
4
11
  *
5
12
  * @param component {PackageURL}
@@ -135,6 +142,30 @@ export default class CycloneDxSbom {
135
142
  }
136
143
  return this;
137
144
  }
145
+ /**
146
+ * Attach hashes to already-added components by matching their PURL. This is a
147
+ * post-processing step so ecosystem-specific hash sources (e.g. Maven reading
148
+ * the local .m2 cache) can enrich the SBOM without threading their concern
149
+ * through the shared dependency-tree parser. Components without a matching
150
+ * entry, or whose hashes are already set, are left untouched.
151
+ * @param {Map<string, Array<{alg: string, content: string}>>} hashMap - PURL→hashes map
152
+ * @return {CycloneDxSbom} the updated SBOM
153
+ */
154
+ attachHashes(hashMap) {
155
+ if (!hashMap || hashMap.size === 0) {
156
+ return this;
157
+ }
158
+ for (const component of this.components) {
159
+ if (component.hashes) {
160
+ continue;
161
+ }
162
+ const hashes = hashMap.get(component.purl);
163
+ if (hashes && hashes.length > 0) {
164
+ component.hashes = hashes;
165
+ }
166
+ }
167
+ return this;
168
+ }
138
169
  /** @param {{}} opts - various options, settings and configuration of application.
139
170
  * @return String CycloneDx Sbom json object in a string format
140
171
  */
@@ -144,11 +175,18 @@ export default class CycloneDxSbom {
144
175
  const rootPurl = this.rootComponent?.purl;
145
176
  this.sbomObject = {
146
177
  "bomFormat": "CycloneDX",
147
- "specVersion": "1.4",
178
+ "specVersion": "1.6",
148
179
  "version": 1,
149
180
  "metadata": {
150
181
  "timestamp": new Date(),
151
182
  "component": this.rootComponent,
183
+ "tools": {
184
+ "components": [{
185
+ "type": "application",
186
+ "name": "trustify-da-javascript-client",
187
+ "version": PACKAGE_VERSION
188
+ }]
189
+ },
152
190
  "properties": new Array()
153
191
  },
154
192
  "components": this.components.filter(c => c.purl !== rootPurl),
@@ -1,8 +1,6 @@
1
1
  /**
2
- * This function is used to determine the Trustify DA backend URL.
3
- * The TRUSTIFY_DA_BACKEND_URL is evaluated in the following order and selected when it finds it first:
4
- * 1. Environment Variable
5
- * 2. (key,value) from opts object
2
+ * Selects the Trustify DA backend URL from opts.TRUSTIFY_DA_BACKEND_URL, then environment
3
+ * variable TRUSTIFY_DA_BACKEND_URL. Options take precedence over environment variables.
6
4
  * If TRUSTIFY_DA_BACKEND_URL is not set, the function will throw an error.
7
5
  * @param {{TRUSTIFY_DA_DEBUG?: string | undefined; TRUSTIFY_DA_BACKEND_URL?: string | undefined}} [opts={}]
8
6
  * @return {string} - The selected Trustify DA backend URL
@@ -24,7 +22,6 @@ export function selectTrustifyDABackend(opts?: {
24
22
  export function generateSbom(manifestPath: string, opts?: Options): Promise<object>;
25
23
  export { parseImageRef } from "./oci_image/utils.js";
26
24
  export { ImageRef } from "./oci_image/images.js";
27
- export { extractRemediations } from "./remediation.js";
28
25
  declare namespace _default {
29
26
  export { componentAnalysis };
30
27
  export { stackAnalysis };
@@ -64,11 +61,11 @@ export type Options = {
64
61
  TRUSTIFY_DA_YARN_PATH?: string | undefined;
65
62
  TRUSTIFY_DA_WORKSPACE_DIR?: string | undefined;
66
63
  TRUSTIFY_DA_LICENSE_CHECK?: string | undefined;
64
+ licenseCheck?: boolean | undefined;
67
65
  MATCH_MANIFEST_VERSIONS?: string | undefined;
68
66
  TRUSTIFY_DA_SOURCE?: string | undefined;
69
67
  TRUSTIFY_DA_TOKEN?: string | undefined;
70
68
  TRUSTIFY_DA_TELEMETRY_ID?: string | undefined;
71
- TRUSTIFY_DA_WORKSPACE_DIR?: string | undefined;
72
69
  batchConcurrency?: number | undefined;
73
70
  TRUSTIFY_DA_BATCH_CONCURRENCY?: string | undefined;
74
71
  workspaceDiscoveryIgnore?: string[] | undefined;
@@ -106,10 +103,10 @@ export type SbomResult = {
106
103
  * Get component analysis report for a manifest content.
107
104
  * @param {string} manifest - path to the manifest
108
105
  * @param {Options} [opts={}] - optional various options to pass along the application
109
- * @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>}
106
+ * @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>}
110
107
  * @throws {Error} if no matching provider, failed to get create content, or backend request failed
111
108
  */
112
- declare function componentAnalysis(manifest: string, opts?: Options): Promise<any>;
109
+ declare function componentAnalysis(manifest: string, opts?: Options): Promise<import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport>;
113
110
  /**
114
111
  * @overload
115
112
  * @param {string} manifest
@@ -124,21 +121,21 @@ declare function stackAnalysis(manifest: string, html: true, opts?: Options | un
124
121
  * @param {string} manifest
125
122
  * @param {false} html
126
123
  * @param {Options} [opts={}]
127
- * @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>}
124
+ * @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>}
128
125
  * @throws {Error}
129
126
  */
130
- declare function stackAnalysis(manifest: string, html: false, opts?: Options | undefined): Promise<any>;
127
+ declare function stackAnalysis(manifest: string, html: false, opts?: Options | undefined): Promise<import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport>;
131
128
  /**
132
129
  * Get stack analysis report for a manifest file.
133
130
  * @overload
134
131
  * @param {string} manifest - path for the manifest
135
132
  * @param {boolean} [html=false] - true will return a html string, false will return AnalysisReport object.
136
133
  * @param {Options} [opts={}] - optional various options to pass along the application
137
- * @returns {Promise<string|import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>}
134
+ * @returns {Promise<string|import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>}
138
135
  * @throws {Error} if manifest inaccessible, no matching provider, failed to get create content,
139
136
  * or backend request failed
140
137
  */
141
- declare function stackAnalysis(manifest: string, html?: boolean | undefined, opts?: Options | undefined): Promise<string | any>;
138
+ declare function stackAnalysis(manifest: string, html?: boolean | undefined, opts?: Options | undefined): Promise<string | import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport>;
142
139
  /**
143
140
  * @overload
144
141
  * @param {string} workspaceRoot
@@ -169,14 +166,14 @@ declare function stackAnalysisBatch(workspaceRoot: string, html: true, opts?: (O
169
166
  * @param {string} workspaceRoot
170
167
  * @param {false} html
171
168
  * @param {Options & { batchMetadata: true }} opts
172
- * @returns {Promise<{ analysis: Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>, metadata: BatchAnalysisMetadata }>}
169
+ * @returns {Promise<{ analysis: Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>, metadata: BatchAnalysisMetadata }>}
173
170
  * @throws {Error}
174
171
  */
175
172
  declare function stackAnalysisBatch(workspaceRoot: string, html: false, opts: Options & {
176
173
  batchMetadata: true;
177
174
  }): Promise<{
178
175
  analysis: {
179
- [x: string]: any;
176
+ [x: string]: import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport;
180
177
  };
181
178
  metadata: BatchAnalysisMetadata;
182
179
  }>;
@@ -185,13 +182,13 @@ declare function stackAnalysisBatch(workspaceRoot: string, html: false, opts: Op
185
182
  * @param {string} workspaceRoot
186
183
  * @param {false} html
187
184
  * @param {Options & { batchMetadata?: false }} [opts={}]
188
- * @returns {Promise<Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>>}
185
+ * @returns {Promise<Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>>}
189
186
  * @throws {Error}
190
187
  */
191
188
  declare function stackAnalysisBatch(workspaceRoot: string, html: false, opts?: (Options & {
192
189
  batchMetadata?: false;
193
190
  }) | undefined): Promise<{
194
- [x: string]: any;
191
+ [x: string]: import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport;
195
192
  }>;
196
193
  /**
197
194
  * Get stack analysis for all workspace packages/crates (batch).
@@ -203,14 +200,14 @@ declare function stackAnalysisBatch(workspaceRoot: string, html: false, opts?: (
203
200
  * @param {string} workspaceRoot - Path to workspace root (containing lock file and workspace config)
204
201
  * @param {boolean} [html=false] - true returns HTML, false returns JSON report
205
202
  * @param {Options} [opts={}] - `batchConcurrency`, discovery ignores, `continueOnError` (default true), `batchMetadata` (default false)
206
- * @returns {Promise<string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>|{ analysis: string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>, metadata: BatchAnalysisMetadata }>}
203
+ * @returns {Promise<string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>|{ analysis: string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>, metadata: BatchAnalysisMetadata }>}
207
204
  * @throws {Error} if workspace root invalid, no manifests found, no packages pass validation, no SBOMs produced, or backend request failed. When `opts.batchMetadata` is set, `error.batchMetadata` may be set on thrown errors.
208
205
  */
209
206
  declare function stackAnalysisBatch(workspaceRoot: string, html?: boolean | undefined, opts?: Options | undefined): Promise<string | {
210
- [x: string]: any;
207
+ [x: string]: import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport;
211
208
  } | {
212
209
  analysis: string | {
213
- [x: string]: any;
210
+ [x: string]: import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport;
214
211
  };
215
212
  metadata: BatchAnalysisMetadata;
216
213
  }>;
@@ -228,11 +225,11 @@ declare function imageAnalysis(imageRefs: Array<string>, html: true, opts?: Opti
228
225
  * @param {Array<string>} imageRefs
229
226
  * @param {false} html
230
227
  * @param {Options} [opts={}]
231
- * @returns {Promise<Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>>}
228
+ * @returns {Promise<Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>>}
232
229
  * @throws {Error}
233
230
  */
234
231
  declare function imageAnalysis(imageRefs: Array<string>, html: false, opts?: Options | undefined): Promise<{
235
- [x: string]: any;
232
+ [x: string]: import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport;
236
233
  }>;
237
234
  /**
238
235
  * Get image analysis report for a set of OCI image references.
@@ -240,12 +237,12 @@ declare function imageAnalysis(imageRefs: Array<string>, html: false, opts?: Opt
240
237
  * @param {Array<string>} imageRefs - OCI image references
241
238
  * @param {boolean} [html=false] - true will return a html string, false will return AnalysisReport
242
239
  * @param {Options} [opts={}] - optional various options to pass along the application
243
- * @returns {Promise<string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>>}
240
+ * @returns {Promise<string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>>}
244
241
  * @throws {Error} if manifest inaccessible, no matching provider, failed to get create content,
245
242
  * or backend request failed
246
243
  */
247
244
  declare function imageAnalysis(imageRefs: Array<string>, html?: boolean | undefined, opts?: Options | undefined): Promise<string | {
248
- [x: string]: any;
245
+ [x: string]: import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport;
249
246
  }>;
250
247
  /**
251
248
  * Validates the Exhort token.
@@ -267,4 +264,7 @@ import { resolveContinueOnError } from './batch_opts.js';
267
264
  import { resolveBatchMetadata } from './batch_opts.js';
268
265
  export { discoverMavenModules, discoverGradleSubprojects, discoverGoWorkspaceModules, discoverUvWorkspaceMembers, discoverWorkspacePackages, discoverWorkspaceCrates, validatePackageJson, resolveWorkspaceDiscoveryIgnore, filterManifestPathsByDiscoveryIgnore, resolveContinueOnError, resolveBatchMetadata };
269
266
  export { getProjectLicense, findLicenseFilePath, identifyLicense, getLicenseDetails, licensesFromReport, normalizeLicensesResponse, runLicenseCheck, getCompatibility } from "./license/index.js";
267
+ export { extractRemediations, maxSeverity } from "./remediation.js";
270
268
  export { generateReport, generateDeduplicationKey } from "./remediation_report.js";
269
+ export { loadConfig, mergeConfig, resolveConfig, CONFIG_FILENAMES } from "./config.js";
270
+ export { runRemediation, findManifests } from "./remediate.js";
package/dist/src/index.js CHANGED
@@ -1,23 +1,24 @@
1
+ import fs from 'node:fs';
1
2
  import path from "node:path";
2
3
  import { EOL } from "os";
3
4
  import pLimit from 'p-limit';
4
- import { availableProviders, match } from './provider.js';
5
5
  import analysis from './analysis.js';
6
- import fs from 'node:fs';
7
- import { getCustom } from "./tools.js";
8
6
  import { resolveBatchMetadata, resolveContinueOnError } from './batch_opts.js';
9
- import { discoverMavenModules } from './providers/java_maven.js';
10
- import { discoverGradleSubprojects } from './providers/java_gradle.js';
7
+ import { getPackageVersion } from './package_version.js';
8
+ import { availableProviders, match } from './provider.js';
11
9
  import { discoverGoWorkspaceModules } from './providers/golang_gomodules.js';
10
+ import { discoverGradleSubprojects } from './providers/java_gradle.js';
11
+ import { discoverMavenModules } from './providers/java_maven.js';
12
12
  import { discoverUvWorkspaceMembers } from './providers/python_uv.js';
13
+ import { getCustom } from "./tools.js";
13
14
  import { discoverWorkspaceCrates, discoverWorkspacePackages, filterManifestPathsByDiscoveryIgnore, resolveWorkspaceDiscoveryIgnore, validatePackageJson, } from './workspace.js';
14
- import.meta.dirname;
15
- import * as url from 'url';
16
15
  export { parseImageRef } from "./oci_image/utils.js";
17
16
  export { ImageRef } from "./oci_image/images.js";
18
17
  export { getProjectLicense, findLicenseFilePath, identifyLicense, getLicenseDetails, licensesFromReport, normalizeLicensesResponse, runLicenseCheck, getCompatibility } from "./license/index.js";
19
- export { extractRemediations } from "./remediation.js";
18
+ export { extractRemediations, maxSeverity } from "./remediation.js";
20
19
  export { generateReport, generateDeduplicationKey } from './remediation_report.js';
20
+ export { loadConfig, mergeConfig, resolveConfig, CONFIG_FILENAMES } from './config.js';
21
+ export { runRemediation, findManifests } from './remediate.js';
21
22
  export default { componentAnalysis, stackAnalysis, stackAnalysisBatch, imageAnalysis, validateToken, generateSbom };
22
23
  export { discoverMavenModules, discoverGradleSubprojects, discoverGoWorkspaceModules, discoverUvWorkspaceMembers, discoverWorkspacePackages, discoverWorkspaceCrates, validatePackageJson, resolveWorkspaceDiscoveryIgnore, filterManifestPathsByDiscoveryIgnore, resolveContinueOnError, resolveBatchMetadata, };
23
24
  /**
@@ -51,11 +52,11 @@ export { discoverMavenModules, discoverGradleSubprojects, discoverGoWorkspaceMod
51
52
  * TRUSTIFY_DA_YARN_PATH?: string | undefined,
52
53
  * TRUSTIFY_DA_WORKSPACE_DIR?: string | undefined,
53
54
  * TRUSTIFY_DA_LICENSE_CHECK?: string | undefined,
55
+ * licenseCheck?: boolean | undefined,
54
56
  * MATCH_MANIFEST_VERSIONS?: string | undefined,
55
57
  * TRUSTIFY_DA_SOURCE?: string | undefined,
56
58
  * TRUSTIFY_DA_TOKEN?: string | undefined,
57
59
  * TRUSTIFY_DA_TELEMETRY_ID?: string | undefined,
58
- * TRUSTIFY_DA_WORKSPACE_DIR?: string | undefined,
59
60
  * batchConcurrency?: number | undefined,
60
61
  * TRUSTIFY_DA_BATCH_CONCURRENCY?: string | undefined,
61
62
  * workspaceDiscoveryIgnore?: string[] | undefined,
@@ -95,29 +96,11 @@ function logOptionsAndEnvironmentsVariables(alongsideText, valueToBePrinted) {
95
96
  * @private
96
97
  */
97
98
  function readAndPrintVersionFromPackageJson() {
98
- let dirName;
99
- // new ESM way in nodeJS ( since node version 22 ) to bring module directory.
100
- dirName = import.meta.dirname;
101
- // old ESM way in nodeJS ( before node versions 22.00 to bring module directory)
102
- if (!dirName) {
103
- dirName = url.fileURLToPath(new URL('.', import.meta.url));
104
- }
105
- try {
106
- if (__dirname) {
107
- dirName = __dirname;
108
- }
109
- }
110
- catch (e) {
111
- console.log("__dirname is not defined, continue with fileUrlPath");
112
- }
113
- let packageJson = JSON.parse(fs.readFileSync(path.join(dirName, "..", "package.json")).toString());
114
- logOptionsAndEnvironmentsVariables("trustify-da-javascript-client analysis started, version: ", packageJson.version);
99
+ logOptionsAndEnvironmentsVariables("trustify-da-javascript-client analysis started, version: ", getPackageVersion());
115
100
  }
116
101
  /**
117
- * This function is used to determine the Trustify DA backend URL.
118
- * The TRUSTIFY_DA_BACKEND_URL is evaluated in the following order and selected when it finds it first:
119
- * 1. Environment Variable
120
- * 2. (key,value) from opts object
102
+ * Selects the Trustify DA backend URL from opts.TRUSTIFY_DA_BACKEND_URL, then environment
103
+ * variable TRUSTIFY_DA_BACKEND_URL. Options take precedence over environment variables.
121
104
  * If TRUSTIFY_DA_BACKEND_URL is not set, the function will throw an error.
122
105
  * @param {{TRUSTIFY_DA_DEBUG?: string | undefined; TRUSTIFY_DA_BACKEND_URL?: string | undefined}} [opts={}]
123
106
  * @return {string} - The selected Trustify DA backend URL
@@ -148,7 +131,7 @@ export function selectTrustifyDABackend(opts = {}) {
148
131
  * @param {string} manifest
149
132
  * @param {false} html
150
133
  * @param {Options} [opts={}]
151
- * @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>}
134
+ * @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>}
152
135
  * @throws {Error}
153
136
  */
154
137
  /**
@@ -157,7 +140,7 @@ export function selectTrustifyDABackend(opts = {}) {
157
140
  * @param {string} manifest - path for the manifest
158
141
  * @param {boolean} [html=false] - true will return a html string, false will return AnalysisReport object.
159
142
  * @param {Options} [opts={}] - optional various options to pass along the application
160
- * @returns {Promise<string|import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>}
143
+ * @returns {Promise<string|import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>}
161
144
  * @throws {Error} if manifest inaccessible, no matching provider, failed to get create content,
162
145
  * or backend request failed
163
146
  */
@@ -171,7 +154,7 @@ async function stackAnalysis(manifest, html = false, opts = {}) {
171
154
  * Get component analysis report for a manifest content.
172
155
  * @param {string} manifest - path to the manifest
173
156
  * @param {Options} [opts={}] - optional various options to pass along the application
174
- * @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>}
157
+ * @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>}
175
158
  * @throws {Error} if no matching provider, failed to get create content, or backend request failed
176
159
  */
177
160
  async function componentAnalysis(manifest, opts = {}) {
@@ -196,7 +179,7 @@ async function componentAnalysis(manifest, opts = {}) {
196
179
  * @param {Array<string>} imageRefs
197
180
  * @param {false} html
198
181
  * @param {Options} [opts={}]
199
- * @returns {Promise<Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>>}
182
+ * @returns {Promise<Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>>}
200
183
  * @throws {Error}
201
184
  */
202
185
  /**
@@ -205,7 +188,7 @@ async function componentAnalysis(manifest, opts = {}) {
205
188
  * @param {Array<string>} imageRefs - OCI image references
206
189
  * @param {boolean} [html=false] - true will return a html string, false will return AnalysisReport
207
190
  * @param {Options} [opts={}] - optional various options to pass along the application
208
- * @returns {Promise<string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>>}
191
+ * @returns {Promise<string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>>}
209
192
  * @throws {Error} if manifest inaccessible, no matching provider, failed to get create content,
210
193
  * or backend request failed
211
194
  */
@@ -214,7 +197,8 @@ async function imageAnalysis(imageRefs, html = false, opts = {}) {
214
197
  return await analysis.requestImages(imageRefs, theUrl, html, opts);
215
198
  }
216
199
  /**
217
- * Max concurrent SBOM generations for batch workspace analysis. Env/opts override default 10.
200
+ * Max concurrent SBOM generations for batch workspace analysis. Options override environment;
201
+ * environment overrides the default of 10.
218
202
  * @param {Options} opts
219
203
  * @returns {number}
220
204
  * @private
@@ -457,7 +441,7 @@ function batchError(message, wantMetadata, metadata) {
457
441
  * @param {string} workspaceRoot
458
442
  * @param {false} html
459
443
  * @param {Options & { batchMetadata: true }} opts
460
- * @returns {Promise<{ analysis: Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>, metadata: BatchAnalysisMetadata }>}
444
+ * @returns {Promise<{ analysis: Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>, metadata: BatchAnalysisMetadata }>}
461
445
  * @throws {Error}
462
446
  */
463
447
  /**
@@ -465,7 +449,7 @@ function batchError(message, wantMetadata, metadata) {
465
449
  * @param {string} workspaceRoot
466
450
  * @param {false} html
467
451
  * @param {Options & { batchMetadata?: false }} [opts={}]
468
- * @returns {Promise<Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>>}
452
+ * @returns {Promise<Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>>}
469
453
  * @throws {Error}
470
454
  */
471
455
  /**
@@ -478,7 +462,7 @@ function batchError(message, wantMetadata, metadata) {
478
462
  * @param {string} workspaceRoot - Path to workspace root (containing lock file and workspace config)
479
463
  * @param {boolean} [html=false] - true returns HTML, false returns JSON report
480
464
  * @param {Options} [opts={}] - `batchConcurrency`, discovery ignores, `continueOnError` (default true), `batchMetadata` (default false)
481
- * @returns {Promise<string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>|{ analysis: string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>, metadata: BatchAnalysisMetadata }>}
465
+ * @returns {Promise<string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>|{ analysis: string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>, metadata: BatchAnalysisMetadata }>}
482
466
  * @throws {Error} if workspace root invalid, no manifests found, no packages pass validation, no SBOMs produced, or backend request failed. When `opts.batchMetadata` is set, `error.batchMetadata` may be set on thrown errors.
483
467
  */
484
468
  async function stackAnalysisBatch(workspaceRoot, html = false, opts = {}) {