@trustify-da/trustify-da-javascript-client 0.3.0-ea.243eaef → 0.3.0-ea.24dd325
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -8
- package/dist/package.json +0 -3
- package/dist/src/analysis.d.ts +40 -19
- package/dist/src/analysis.js +41 -5
- package/dist/src/cli.js +95 -17
- package/dist/src/config.d.ts +120 -0
- package/dist/src/config.js +260 -0
- package/dist/src/index.d.ts +22 -21
- package/dist/src/index.js +15 -13
- package/dist/src/license/index.d.ts +2 -2
- package/dist/src/license/index.js +9 -6
- package/dist/src/license/licenses_api.d.ts +2 -2
- package/dist/src/license/licenses_api.js +1 -1
- package/dist/src/providers/base_javascript.js +1 -1
- package/dist/src/providers/rust_cargo.js +3 -3
- package/dist/src/remediate.d.ts +102 -3
- package/dist/src/remediate.js +162 -58
- package/dist/src/remediation.d.ts +15 -14
- package/dist/src/remediation.js +27 -38
- package/dist/src/tools.d.ts +9 -11
- package/dist/src/tools.js +10 -12
- package/dist/src/updaters/maven_updater.d.ts +40 -8
- package/dist/src/updaters/maven_updater.js +26 -3
- package/dist/src/updaters/toml_updater.d.ts +42 -13
- package/dist/src/updaters/toml_updater.js +36 -4
- package/dist/src/workspace.d.ts +2 -1
- package/dist/src/workspace.js +2 -1
- package/package.json +1 -4
|
@@ -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
|
+
}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
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
|
|
@@ -64,6 +62,7 @@ export type Options = {
|
|
|
64
62
|
TRUSTIFY_DA_YARN_PATH?: string | undefined;
|
|
65
63
|
TRUSTIFY_DA_WORKSPACE_DIR?: string | undefined;
|
|
66
64
|
TRUSTIFY_DA_LICENSE_CHECK?: string | undefined;
|
|
65
|
+
licenseCheck?: boolean | undefined;
|
|
67
66
|
MATCH_MANIFEST_VERSIONS?: string | undefined;
|
|
68
67
|
TRUSTIFY_DA_SOURCE?: string | undefined;
|
|
69
68
|
TRUSTIFY_DA_TOKEN?: string | undefined;
|
|
@@ -106,10 +105,10 @@ export type SbomResult = {
|
|
|
106
105
|
* Get component analysis report for a manifest content.
|
|
107
106
|
* @param {string} manifest - path to the manifest
|
|
108
107
|
* @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>}
|
|
108
|
+
* @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>}
|
|
110
109
|
* @throws {Error} if no matching provider, failed to get create content, or backend request failed
|
|
111
110
|
*/
|
|
112
|
-
declare function componentAnalysis(manifest: string, opts?: Options): Promise<
|
|
111
|
+
declare function componentAnalysis(manifest: string, opts?: Options): Promise<import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport>;
|
|
113
112
|
/**
|
|
114
113
|
* @overload
|
|
115
114
|
* @param {string} manifest
|
|
@@ -124,21 +123,21 @@ declare function stackAnalysis(manifest: string, html: true, opts?: Options | un
|
|
|
124
123
|
* @param {string} manifest
|
|
125
124
|
* @param {false} html
|
|
126
125
|
* @param {Options} [opts={}]
|
|
127
|
-
* @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>}
|
|
126
|
+
* @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>}
|
|
128
127
|
* @throws {Error}
|
|
129
128
|
*/
|
|
130
|
-
declare function stackAnalysis(manifest: string, html: false, opts?: Options | undefined): Promise<
|
|
129
|
+
declare function stackAnalysis(manifest: string, html: false, opts?: Options | undefined): Promise<import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport>;
|
|
131
130
|
/**
|
|
132
131
|
* Get stack analysis report for a manifest file.
|
|
133
132
|
* @overload
|
|
134
133
|
* @param {string} manifest - path for the manifest
|
|
135
134
|
* @param {boolean} [html=false] - true will return a html string, false will return AnalysisReport object.
|
|
136
135
|
* @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>}
|
|
136
|
+
* @returns {Promise<string|import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>}
|
|
138
137
|
* @throws {Error} if manifest inaccessible, no matching provider, failed to get create content,
|
|
139
138
|
* or backend request failed
|
|
140
139
|
*/
|
|
141
|
-
declare function stackAnalysis(manifest: string, html?: boolean | undefined, opts?: Options | undefined): Promise<string |
|
|
140
|
+
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
141
|
/**
|
|
143
142
|
* @overload
|
|
144
143
|
* @param {string} workspaceRoot
|
|
@@ -169,14 +168,14 @@ declare function stackAnalysisBatch(workspaceRoot: string, html: true, opts?: (O
|
|
|
169
168
|
* @param {string} workspaceRoot
|
|
170
169
|
* @param {false} html
|
|
171
170
|
* @param {Options & { batchMetadata: true }} opts
|
|
172
|
-
* @returns {Promise<{ analysis: Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>, metadata: BatchAnalysisMetadata }>}
|
|
171
|
+
* @returns {Promise<{ analysis: Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>, metadata: BatchAnalysisMetadata }>}
|
|
173
172
|
* @throws {Error}
|
|
174
173
|
*/
|
|
175
174
|
declare function stackAnalysisBatch(workspaceRoot: string, html: false, opts: Options & {
|
|
176
175
|
batchMetadata: true;
|
|
177
176
|
}): Promise<{
|
|
178
177
|
analysis: {
|
|
179
|
-
[x: string]:
|
|
178
|
+
[x: string]: import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport;
|
|
180
179
|
};
|
|
181
180
|
metadata: BatchAnalysisMetadata;
|
|
182
181
|
}>;
|
|
@@ -185,13 +184,13 @@ declare function stackAnalysisBatch(workspaceRoot: string, html: false, opts: Op
|
|
|
185
184
|
* @param {string} workspaceRoot
|
|
186
185
|
* @param {false} html
|
|
187
186
|
* @param {Options & { batchMetadata?: false }} [opts={}]
|
|
188
|
-
* @returns {Promise<Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>>}
|
|
187
|
+
* @returns {Promise<Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>>}
|
|
189
188
|
* @throws {Error}
|
|
190
189
|
*/
|
|
191
190
|
declare function stackAnalysisBatch(workspaceRoot: string, html: false, opts?: (Options & {
|
|
192
191
|
batchMetadata?: false;
|
|
193
192
|
}) | undefined): Promise<{
|
|
194
|
-
[x: string]:
|
|
193
|
+
[x: string]: import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport;
|
|
195
194
|
}>;
|
|
196
195
|
/**
|
|
197
196
|
* Get stack analysis for all workspace packages/crates (batch).
|
|
@@ -203,14 +202,14 @@ declare function stackAnalysisBatch(workspaceRoot: string, html: false, opts?: (
|
|
|
203
202
|
* @param {string} workspaceRoot - Path to workspace root (containing lock file and workspace config)
|
|
204
203
|
* @param {boolean} [html=false] - true returns HTML, false returns JSON report
|
|
205
204
|
* @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 }>}
|
|
205
|
+
* @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
206
|
* @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
207
|
*/
|
|
209
208
|
declare function stackAnalysisBatch(workspaceRoot: string, html?: boolean | undefined, opts?: Options | undefined): Promise<string | {
|
|
210
|
-
[x: string]:
|
|
209
|
+
[x: string]: import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport;
|
|
211
210
|
} | {
|
|
212
211
|
analysis: string | {
|
|
213
|
-
[x: string]:
|
|
212
|
+
[x: string]: import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport;
|
|
214
213
|
};
|
|
215
214
|
metadata: BatchAnalysisMetadata;
|
|
216
215
|
}>;
|
|
@@ -228,11 +227,11 @@ declare function imageAnalysis(imageRefs: Array<string>, html: true, opts?: Opti
|
|
|
228
227
|
* @param {Array<string>} imageRefs
|
|
229
228
|
* @param {false} html
|
|
230
229
|
* @param {Options} [opts={}]
|
|
231
|
-
* @returns {Promise<Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>>}
|
|
230
|
+
* @returns {Promise<Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>>}
|
|
232
231
|
* @throws {Error}
|
|
233
232
|
*/
|
|
234
233
|
declare function imageAnalysis(imageRefs: Array<string>, html: false, opts?: Options | undefined): Promise<{
|
|
235
|
-
[x: string]:
|
|
234
|
+
[x: string]: import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport;
|
|
236
235
|
}>;
|
|
237
236
|
/**
|
|
238
237
|
* Get image analysis report for a set of OCI image references.
|
|
@@ -240,12 +239,12 @@ declare function imageAnalysis(imageRefs: Array<string>, html: false, opts?: Opt
|
|
|
240
239
|
* @param {Array<string>} imageRefs - OCI image references
|
|
241
240
|
* @param {boolean} [html=false] - true will return a html string, false will return AnalysisReport
|
|
242
241
|
* @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>>}
|
|
242
|
+
* @returns {Promise<string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>>}
|
|
244
243
|
* @throws {Error} if manifest inaccessible, no matching provider, failed to get create content,
|
|
245
244
|
* or backend request failed
|
|
246
245
|
*/
|
|
247
246
|
declare function imageAnalysis(imageRefs: Array<string>, html?: boolean | undefined, opts?: Options | undefined): Promise<string | {
|
|
248
|
-
[x: string]:
|
|
247
|
+
[x: string]: import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport;
|
|
249
248
|
}>;
|
|
250
249
|
/**
|
|
251
250
|
* Validates the Exhort token.
|
|
@@ -268,3 +267,5 @@ import { resolveBatchMetadata } from './batch_opts.js';
|
|
|
268
267
|
export { discoverMavenModules, discoverGradleSubprojects, discoverGoWorkspaceModules, discoverUvWorkspaceMembers, discoverWorkspacePackages, discoverWorkspaceCrates, validatePackageJson, resolveWorkspaceDiscoveryIgnore, filterManifestPathsByDiscoveryIgnore, resolveContinueOnError, resolveBatchMetadata };
|
|
269
268
|
export { getProjectLicense, findLicenseFilePath, identifyLicense, getLicenseDetails, licensesFromReport, normalizeLicensesResponse, runLicenseCheck, getCompatibility } from "./license/index.js";
|
|
270
269
|
export { generateReport, generateDeduplicationKey } from "./remediation_report.js";
|
|
270
|
+
export { loadConfig, mergeConfig, resolveConfig, CONFIG_FILENAMES } from "./config.js";
|
|
271
|
+
export { runRemediation, findManifests } from "./remediate.js";
|
package/dist/src/index.js
CHANGED
|
@@ -17,6 +17,8 @@ export { ImageRef } from "./oci_image/images.js";
|
|
|
17
17
|
export { getProjectLicense, findLicenseFilePath, identifyLicense, getLicenseDetails, licensesFromReport, normalizeLicensesResponse, runLicenseCheck, getCompatibility } from "./license/index.js";
|
|
18
18
|
export { extractRemediations } from "./remediation.js";
|
|
19
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';
|
|
20
22
|
export default { componentAnalysis, stackAnalysis, stackAnalysisBatch, imageAnalysis, validateToken, generateSbom };
|
|
21
23
|
export { discoverMavenModules, discoverGradleSubprojects, discoverGoWorkspaceModules, discoverUvWorkspaceMembers, discoverWorkspacePackages, discoverWorkspaceCrates, validatePackageJson, resolveWorkspaceDiscoveryIgnore, filterManifestPathsByDiscoveryIgnore, resolveContinueOnError, resolveBatchMetadata, };
|
|
22
24
|
/**
|
|
@@ -50,6 +52,7 @@ export { discoverMavenModules, discoverGradleSubprojects, discoverGoWorkspaceMod
|
|
|
50
52
|
* TRUSTIFY_DA_YARN_PATH?: string | undefined,
|
|
51
53
|
* TRUSTIFY_DA_WORKSPACE_DIR?: string | undefined,
|
|
52
54
|
* TRUSTIFY_DA_LICENSE_CHECK?: string | undefined,
|
|
55
|
+
* licenseCheck?: boolean | undefined,
|
|
53
56
|
* MATCH_MANIFEST_VERSIONS?: string | undefined,
|
|
54
57
|
* TRUSTIFY_DA_SOURCE?: string | undefined,
|
|
55
58
|
* TRUSTIFY_DA_TOKEN?: string | undefined,
|
|
@@ -97,10 +100,8 @@ function readAndPrintVersionFromPackageJson() {
|
|
|
97
100
|
logOptionsAndEnvironmentsVariables("trustify-da-javascript-client analysis started, version: ", getPackageVersion());
|
|
98
101
|
}
|
|
99
102
|
/**
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* 1. Environment Variable
|
|
103
|
-
* 2. (key,value) from opts object
|
|
103
|
+
* Selects the Trustify DA backend URL from opts.TRUSTIFY_DA_BACKEND_URL, then environment
|
|
104
|
+
* variable TRUSTIFY_DA_BACKEND_URL. Options take precedence over environment variables.
|
|
104
105
|
* If TRUSTIFY_DA_BACKEND_URL is not set, the function will throw an error.
|
|
105
106
|
* @param {{TRUSTIFY_DA_DEBUG?: string | undefined; TRUSTIFY_DA_BACKEND_URL?: string | undefined}} [opts={}]
|
|
106
107
|
* @return {string} - The selected Trustify DA backend URL
|
|
@@ -131,7 +132,7 @@ export function selectTrustifyDABackend(opts = {}) {
|
|
|
131
132
|
* @param {string} manifest
|
|
132
133
|
* @param {false} html
|
|
133
134
|
* @param {Options} [opts={}]
|
|
134
|
-
* @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>}
|
|
135
|
+
* @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>}
|
|
135
136
|
* @throws {Error}
|
|
136
137
|
*/
|
|
137
138
|
/**
|
|
@@ -140,7 +141,7 @@ export function selectTrustifyDABackend(opts = {}) {
|
|
|
140
141
|
* @param {string} manifest - path for the manifest
|
|
141
142
|
* @param {boolean} [html=false] - true will return a html string, false will return AnalysisReport object.
|
|
142
143
|
* @param {Options} [opts={}] - optional various options to pass along the application
|
|
143
|
-
* @returns {Promise<string|import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>}
|
|
144
|
+
* @returns {Promise<string|import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>}
|
|
144
145
|
* @throws {Error} if manifest inaccessible, no matching provider, failed to get create content,
|
|
145
146
|
* or backend request failed
|
|
146
147
|
*/
|
|
@@ -154,7 +155,7 @@ async function stackAnalysis(manifest, html = false, opts = {}) {
|
|
|
154
155
|
* Get component analysis report for a manifest content.
|
|
155
156
|
* @param {string} manifest - path to the manifest
|
|
156
157
|
* @param {Options} [opts={}] - optional various options to pass along the application
|
|
157
|
-
* @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>}
|
|
158
|
+
* @returns {Promise<import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>}
|
|
158
159
|
* @throws {Error} if no matching provider, failed to get create content, or backend request failed
|
|
159
160
|
*/
|
|
160
161
|
async function componentAnalysis(manifest, opts = {}) {
|
|
@@ -179,7 +180,7 @@ async function componentAnalysis(manifest, opts = {}) {
|
|
|
179
180
|
* @param {Array<string>} imageRefs
|
|
180
181
|
* @param {false} html
|
|
181
182
|
* @param {Options} [opts={}]
|
|
182
|
-
* @returns {Promise<Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>>}
|
|
183
|
+
* @returns {Promise<Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>>}
|
|
183
184
|
* @throws {Error}
|
|
184
185
|
*/
|
|
185
186
|
/**
|
|
@@ -188,7 +189,7 @@ async function componentAnalysis(manifest, opts = {}) {
|
|
|
188
189
|
* @param {Array<string>} imageRefs - OCI image references
|
|
189
190
|
* @param {boolean} [html=false] - true will return a html string, false will return AnalysisReport
|
|
190
191
|
* @param {Options} [opts={}] - optional various options to pass along the application
|
|
191
|
-
* @returns {Promise<string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>>}
|
|
192
|
+
* @returns {Promise<string|Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>>}
|
|
192
193
|
* @throws {Error} if manifest inaccessible, no matching provider, failed to get create content,
|
|
193
194
|
* or backend request failed
|
|
194
195
|
*/
|
|
@@ -197,7 +198,8 @@ async function imageAnalysis(imageRefs, html = false, opts = {}) {
|
|
|
197
198
|
return await analysis.requestImages(imageRefs, theUrl, html, opts);
|
|
198
199
|
}
|
|
199
200
|
/**
|
|
200
|
-
* Max concurrent SBOM generations for batch workspace analysis.
|
|
201
|
+
* Max concurrent SBOM generations for batch workspace analysis. Options override environment;
|
|
202
|
+
* environment overrides the default of 10.
|
|
201
203
|
* @param {Options} opts
|
|
202
204
|
* @returns {number}
|
|
203
205
|
* @private
|
|
@@ -440,7 +442,7 @@ function batchError(message, wantMetadata, metadata) {
|
|
|
440
442
|
* @param {string} workspaceRoot
|
|
441
443
|
* @param {false} html
|
|
442
444
|
* @param {Options & { batchMetadata: true }} opts
|
|
443
|
-
* @returns {Promise<{ analysis: Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>, metadata: BatchAnalysisMetadata }>}
|
|
445
|
+
* @returns {Promise<{ analysis: Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>, metadata: BatchAnalysisMetadata }>}
|
|
444
446
|
* @throws {Error}
|
|
445
447
|
*/
|
|
446
448
|
/**
|
|
@@ -448,7 +450,7 @@ function batchError(message, wantMetadata, metadata) {
|
|
|
448
450
|
* @param {string} workspaceRoot
|
|
449
451
|
* @param {false} html
|
|
450
452
|
* @param {Options & { batchMetadata?: false }} [opts={}]
|
|
451
|
-
* @returns {Promise<Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport>>}
|
|
453
|
+
* @returns {Promise<Object.<string, import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport>>}
|
|
452
454
|
* @throws {Error}
|
|
453
455
|
*/
|
|
454
456
|
/**
|
|
@@ -461,7 +463,7 @@ function batchError(message, wantMetadata, metadata) {
|
|
|
461
463
|
* @param {string} workspaceRoot - Path to workspace root (containing lock file and workspace config)
|
|
462
464
|
* @param {boolean} [html=false] - true returns HTML, false returns JSON report
|
|
463
465
|
* @param {Options} [opts={}] - `batchConcurrency`, discovery ignores, `continueOnError` (default true), `batchMetadata` (default false)
|
|
464
|
-
* @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 }>}
|
|
466
|
+
* @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 }>}
|
|
465
467
|
* @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.
|
|
466
468
|
*/
|
|
467
469
|
async function stackAnalysisBatch(workspaceRoot, html = false, opts = {}) {
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
* @param {string} manifestPath - path to manifest
|
|
7
7
|
* @param {string} url - the backend url to send the request to
|
|
8
8
|
* @param {import('../index.js').Options} [opts={}]
|
|
9
|
-
* @param {import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport} [analysisResult] - analysis result that includes licenses array from backend
|
|
9
|
+
* @param {import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport} [analysisResult] - analysis result that includes licenses array from backend
|
|
10
10
|
* @returns {Promise<{ projectLicense: { manifest: Object|null, file: Object|null, mismatch: boolean }, incompatibleDependencies: Array<{ purl: string, licenses: string[], category?: string, reason: string }>, error?: string }>}
|
|
11
11
|
*/
|
|
12
|
-
export function runLicenseCheck(sbomContent: string, manifestPath: string, url: string, opts?: import("../index.js").Options, analysisResult?:
|
|
12
|
+
export function runLicenseCheck(sbomContent: string, manifestPath: string, url: string, opts?: import("../index.js").Options, analysisResult?: import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport): Promise<{
|
|
13
13
|
projectLicense: {
|
|
14
14
|
manifest: Object | null;
|
|
15
15
|
file: Object | null;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* License resolution and dependency license compatibility for component analysis.
|
|
3
3
|
*/
|
|
4
|
-
import { getProjectLicense, findLicenseFilePath, identifyLicense } from './project_license.js';
|
|
5
|
-
import { licensesFromReport, getLicenseDetails } from './licenses_api.js';
|
|
6
4
|
import { getCompatibility } from './license_utils.js';
|
|
5
|
+
import { licensesFromReport, getLicenseDetails } from './licenses_api.js';
|
|
6
|
+
import { getProjectLicense, findLicenseFilePath, identifyLicense } from './project_license.js';
|
|
7
7
|
export { getProjectLicense, findLicenseFilePath, identifyLicense } from './project_license.js';
|
|
8
8
|
export { licensesFromReport, normalizeLicensesResponse, getLicenseDetails } from './licenses_api.js';
|
|
9
9
|
export { getCompatibility } from './license_utils.js';
|
|
@@ -15,7 +15,7 @@ export { getCompatibility } from './license_utils.js';
|
|
|
15
15
|
* @param {string} manifestPath - path to manifest
|
|
16
16
|
* @param {string} url - the backend url to send the request to
|
|
17
17
|
* @param {import('../index.js').Options} [opts={}]
|
|
18
|
-
* @param {import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport} [analysisResult] - analysis result that includes licenses array from backend
|
|
18
|
+
* @param {import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport} [analysisResult] - analysis result that includes licenses array from backend
|
|
19
19
|
* @returns {Promise<{ projectLicense: { manifest: Object|null, file: Object|null, mismatch: boolean }, incompatibleDependencies: Array<{ purl: string, licenses: string[], category?: string, reason: string }>, error?: string }>}
|
|
20
20
|
*/
|
|
21
21
|
export async function runLicenseCheck(sbomContent, manifestPath, url, opts = {}, analysisResult = null) {
|
|
@@ -39,10 +39,12 @@ export async function runLicenseCheck(sbomContent, manifestPath, url, opts = {},
|
|
|
39
39
|
// Fetch detailed license info from backend (avoid duplicate calls if same license)
|
|
40
40
|
const licenseDetailsCache = new Map();
|
|
41
41
|
async function getDetails(spdxId) {
|
|
42
|
-
if (!spdxId || !url)
|
|
42
|
+
if (!spdxId || !url) {
|
|
43
43
|
return null;
|
|
44
|
-
|
|
44
|
+
}
|
|
45
|
+
if (licenseDetailsCache.has(spdxId)) {
|
|
45
46
|
return licenseDetailsCache.get(spdxId);
|
|
47
|
+
}
|
|
46
48
|
try {
|
|
47
49
|
const details = await getLicenseDetails(spdxId, { ...opts, TRUSTIFY_DA_BACKEND_URL: url });
|
|
48
50
|
licenseDetailsCache.set(spdxId, details);
|
|
@@ -81,8 +83,9 @@ export async function runLicenseCheck(sbomContent, manifestPath, url, opts = {},
|
|
|
81
83
|
const incompatibleDependencies = [];
|
|
82
84
|
for (const purl of purls) {
|
|
83
85
|
const entry = licenseByPurl.get(purl);
|
|
84
|
-
if (!entry)
|
|
86
|
+
if (!entry) {
|
|
85
87
|
continue;
|
|
88
|
+
}
|
|
86
89
|
const status = getCompatibility(projectCategory, entry.category);
|
|
87
90
|
if (status === 'incompatible') {
|
|
88
91
|
const reason = entry.category?.toUpperCase() === 'UNKNOWN'
|
|
@@ -24,11 +24,11 @@ export function normalizeLicensesResponse(data: unknown, purls?: string[]): Map<
|
|
|
24
24
|
* Build license map from an analysis report that already includes license data (result.licenses).
|
|
25
25
|
* Use this when the dependency analysis response already contains the licenses array to avoid a second request.
|
|
26
26
|
*
|
|
27
|
-
* @param {import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport} analysisReport - full analysis JSON
|
|
27
|
+
* @param {import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport} analysisReport - full analysis JSON
|
|
28
28
|
* @param {string[]} [purls] - optional list of purls to restrict to
|
|
29
29
|
* @returns {Map<string, { licenses: string[], category?: string }>}
|
|
30
30
|
*/
|
|
31
|
-
export function licensesFromReport(analysisReport:
|
|
31
|
+
export function licensesFromReport(analysisReport: import("@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts").AnalysisReport, purls?: string[]): Map<string, {
|
|
32
32
|
licenses: string[];
|
|
33
33
|
category?: string;
|
|
34
34
|
}>;
|
|
@@ -86,7 +86,7 @@ export function normalizeLicensesResponse(data, purls = []) {
|
|
|
86
86
|
* Build license map from an analysis report that already includes license data (result.licenses).
|
|
87
87
|
* Use this when the dependency analysis response already contains the licenses array to avoid a second request.
|
|
88
88
|
*
|
|
89
|
-
* @param {import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport').AnalysisReport} analysisReport - full analysis JSON
|
|
89
|
+
* @param {import('@trustify-da/trustify-da-api-model/model/v5/AnalysisReport.ts').AnalysisReport} analysisReport - full analysis JSON
|
|
90
90
|
* @param {string[]} [purls] - optional list of purls to restrict to
|
|
91
91
|
* @returns {Map<string, { licenses: string[], category?: string }>}
|
|
92
92
|
*/
|
|
@@ -532,7 +532,7 @@ export default class Base_javascript {
|
|
|
532
532
|
}
|
|
533
533
|
}
|
|
534
534
|
// Try to find the command in the following order:
|
|
535
|
-
// 1. Custom path from environment
|
|
535
|
+
// 1. Custom path from opts/environment (via getCustomPath)
|
|
536
536
|
// 2. Local node_modules/.bin
|
|
537
537
|
// 3. Global installation
|
|
538
538
|
let cmd = this.#cmd;
|
|
@@ -280,7 +280,7 @@ function parseCargoLockHashes(manifestDir, opts = {}) {
|
|
|
280
280
|
}
|
|
281
281
|
}
|
|
282
282
|
catch (error) {
|
|
283
|
-
console.warn(
|
|
283
|
+
console.warn(`Failed to parse Cargo.lock at ${lockPath} for hashes: ${error.message}. SBOM will be generated without hashes.`);
|
|
284
284
|
}
|
|
285
285
|
return hashMap;
|
|
286
286
|
}
|
|
@@ -441,7 +441,7 @@ function addTransitiveDeps(sbom, metadata, packageId, ignoredDeps, visited, hash
|
|
|
441
441
|
let depPurl = depPackage.source == null
|
|
442
442
|
? toPathDepPurl(depPackage.name, depPackage.version)
|
|
443
443
|
: toPurl(depPackage.name, depPackage.version);
|
|
444
|
-
let hashes = hashMap
|
|
444
|
+
let hashes = hashMap.get(`${depPackage.name}@${depPackage.version}`);
|
|
445
445
|
sbom.addDependency(sourcePurl, depPurl, undefined, hashes);
|
|
446
446
|
addTransitiveDeps(sbom, metadata, depId, ignoredDeps, visited, hashMap);
|
|
447
447
|
}
|
|
@@ -473,7 +473,7 @@ function addDirectDeps(sbom, metadata, packageId, parentPurl, ignoredDeps, hashM
|
|
|
473
473
|
let depPurl = depPackage.source == null
|
|
474
474
|
? toPathDepPurl(depPackage.name, depPackage.version)
|
|
475
475
|
: toPurl(depPackage.name, depPackage.version);
|
|
476
|
-
let hashes = hashMap
|
|
476
|
+
let hashes = hashMap.get(`${depPackage.name}@${depPackage.version}`);
|
|
477
477
|
sbom.addDependency(parentPurl, depPurl, undefined, hashes);
|
|
478
478
|
}
|
|
479
479
|
}
|