@trustify-da/trustify-da-javascript-client 0.3.0-ea.dcb2120 → 0.3.0-ea.de62188
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 +1 -1
- package/dist/package.json +25 -22
- package/dist/src/analysis.d.ts +14 -7
- package/dist/src/analysis.js +29 -13
- package/dist/src/cli.js +58 -1
- package/dist/src/cyclone_dx_sbom.d.ts +7 -1
- package/dist/src/cyclone_dx_sbom.js +29 -8
- package/dist/src/index.d.ts +72 -11
- package/dist/src/index.js +76 -7
- package/dist/src/license/index.d.ts +3 -3
- package/dist/src/license/index.js +4 -1
- package/dist/src/license/license_utils.js +4 -1
- package/dist/src/license/licenses_api.d.ts +2 -2
- package/dist/src/oci_image/images.d.ts +1 -1
- package/dist/src/oci_image/images.js +15 -1
- package/dist/src/oci_image/utils.d.ts +5 -5
- package/dist/src/provider.d.ts +4 -3
- package/dist/src/provider.js +8 -2
- package/dist/src/providers/base_java.d.ts +14 -12
- package/dist/src/providers/base_java.js +18 -44
- package/dist/src/providers/base_javascript.d.ts +20 -9
- package/dist/src/providers/base_javascript.js +10 -3
- package/dist/src/providers/base_pyproject.d.ts +22 -32
- package/dist/src/providers/base_pyproject.js +60 -74
- package/dist/src/providers/containerfile_parser.d.ts +5 -0
- package/dist/src/providers/containerfile_parser.js +20 -0
- package/dist/src/providers/golang_gomodules.d.ts +11 -1
- package/dist/src/providers/golang_gomodules.js +65 -8
- package/dist/src/providers/java_gradle.d.ts +19 -0
- package/dist/src/providers/java_gradle.js +116 -2
- package/dist/src/providers/java_gradle_groovy.d.ts +1 -1
- package/dist/src/providers/java_gradle_kotlin.d.ts +1 -1
- package/dist/src/providers/java_maven.d.ts +10 -2
- package/dist/src/providers/java_maven.js +165 -1
- package/dist/src/providers/javascript_bun.d.ts +10 -0
- package/dist/src/providers/javascript_bun.js +100 -0
- package/dist/src/providers/javascript_npm.d.ts +6 -0
- package/dist/src/providers/javascript_npm.js +21 -0
- package/dist/src/providers/javascript_pnpm.js +6 -2
- package/dist/src/providers/marker_evaluator.d.ts +14 -0
- package/dist/src/providers/marker_evaluator.js +191 -0
- package/dist/src/providers/oci_dockerfile.d.ts +51 -0
- package/dist/src/providers/oci_dockerfile.js +177 -0
- package/dist/src/providers/processors/yarn_berry_processor.d.ts +2 -2
- package/dist/src/providers/processors/yarn_berry_processor.js +6 -2
- package/dist/src/providers/processors/yarn_classic_processor.d.ts +2 -2
- package/dist/src/providers/python_controller.d.ts +5 -1
- package/dist/src/providers/python_controller.js +65 -7
- package/dist/src/providers/python_pip.d.ts +5 -0
- package/dist/src/providers/python_pip.js +5 -5
- package/dist/src/providers/python_pip_pyproject.d.ts +61 -0
- package/dist/src/providers/python_pip_pyproject.js +146 -0
- package/dist/src/providers/python_poetry.d.ts +64 -8
- package/dist/src/providers/python_poetry.js +139 -22
- package/dist/src/providers/python_uv.d.ts +20 -1
- package/dist/src/providers/python_uv.js +126 -3
- package/dist/src/providers/rust_cargo.d.ts +6 -2
- package/dist/src/providers/rust_cargo.js +31 -4
- package/dist/src/providers/tree-sitter-containerfile.wasm +0 -0
- package/dist/src/sbom.d.ts +7 -1
- package/dist/src/sbom.js +4 -2
- package/dist/src/tools.d.ts +28 -2
- package/dist/src/tools.js +58 -0
- package/dist/src/updaters/maven_updater.d.ts +26 -0
- package/dist/src/updaters/maven_updater.js +322 -0
- package/dist/src/updaters/toml_updater.d.ts +33 -0
- package/dist/src/updaters/toml_updater.js +244 -0
- package/dist/src/workspace.d.ts +9 -0
- package/dist/src/workspace.js +1 -1
- package/package.json +26 -23
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @typedef {{name: string, version: string, children: string[]}} GraphEntry */
|
|
1
|
+
/** @typedef {{name: string, version: string, children: string[], hashes?: Array<{alg: string, content: string}>}} GraphEntry */
|
|
2
2
|
/** @typedef {{name: string, version: string, dependencies: DepTreeEntry[]}} DepTreeEntry */
|
|
3
3
|
/** @typedef {{directDeps: string[], graph: Map<string, GraphEntry>}} DependencyData */
|
|
4
4
|
/** @typedef {{ecosystem: string, content: string, contentType: string}} Provided */
|
|
@@ -13,7 +13,7 @@ export default class Base_pyproject {
|
|
|
13
13
|
* @param {Object} [opts={}]
|
|
14
14
|
* @returns {boolean}
|
|
15
15
|
*/
|
|
16
|
-
validateLockFile(manifestDir: string, opts?:
|
|
16
|
+
validateLockFile(manifestDir: string, opts?: Object): boolean;
|
|
17
17
|
/**
|
|
18
18
|
* Walk up from manifestDir to find the directory containing the lock file.
|
|
19
19
|
* Follows the same pattern as Base_javascript._findLockFileDir().
|
|
@@ -22,7 +22,7 @@ export default class Base_pyproject {
|
|
|
22
22
|
* @returns {string|null}
|
|
23
23
|
* @protected
|
|
24
24
|
*/
|
|
25
|
-
protected _findLockFileDir(manifestDir: string, opts?:
|
|
25
|
+
protected _findLockFileDir(manifestDir: string, opts?: Object): string | null;
|
|
26
26
|
/**
|
|
27
27
|
* Detect workspace root boundaries.
|
|
28
28
|
* Currently only uv has native workspace support ([tool.uv.workspace] in pyproject.toml).
|
|
@@ -44,13 +44,13 @@ export default class Base_pyproject {
|
|
|
44
44
|
* @param {Object} [opts={}]
|
|
45
45
|
* @returns {Promise<Provided>}
|
|
46
46
|
*/
|
|
47
|
-
provideStack(manifest: string, opts?:
|
|
47
|
+
provideStack(manifest: string, opts?: Object): Promise<Provided>;
|
|
48
48
|
/**
|
|
49
49
|
* @param {string} manifest - path to pyproject.toml
|
|
50
50
|
* @param {Object} [opts={}]
|
|
51
51
|
* @returns {Promise<Provided>}
|
|
52
52
|
*/
|
|
53
|
-
provideComponent(manifest: string, opts?:
|
|
53
|
+
provideComponent(manifest: string, opts?: Object): Promise<Provided>;
|
|
54
54
|
/**
|
|
55
55
|
* @returns {string}
|
|
56
56
|
* @protected
|
|
@@ -61,16 +61,23 @@ export default class Base_pyproject {
|
|
|
61
61
|
* @protected
|
|
62
62
|
*/
|
|
63
63
|
protected _cmdName(): string;
|
|
64
|
+
/**
|
|
65
|
+
* Returns the package manager name (e.g. pip, poetry, uv)
|
|
66
|
+
* @returns {string}
|
|
67
|
+
*/
|
|
68
|
+
packageManagerName(): string;
|
|
64
69
|
/**
|
|
65
70
|
* Resolve dependencies using the tool-specific command and parser.
|
|
71
|
+
*
|
|
66
72
|
* @param {string} manifestDir - directory containing the target pyproject.toml
|
|
67
|
-
* @param {string} workspaceDir - workspace root (where the lock file lives)
|
|
73
|
+
* @param {string} workspaceDir - workspace root (where the lock file lives);
|
|
74
|
+
* only used by providers that need workspace-level resolution (e.g. uv)
|
|
68
75
|
* @param {object} parsed - parsed pyproject.toml
|
|
69
76
|
* @param {Object} opts
|
|
70
77
|
* @returns {Promise<DependencyData>}
|
|
71
78
|
* @protected
|
|
72
79
|
*/
|
|
73
|
-
protected _getDependencyData(manifestDir: string, workspaceDir: string, parsed: object, opts:
|
|
80
|
+
protected _getDependencyData(manifestDir: string, workspaceDir: string, parsed: object, opts: Object): Promise<DependencyData>;
|
|
74
81
|
/**
|
|
75
82
|
* Canonicalize a Python package name per PEP 503.
|
|
76
83
|
* @param {string} name
|
|
@@ -100,26 +107,14 @@ export default class Base_pyproject {
|
|
|
100
107
|
*/
|
|
101
108
|
protected _getIgnoredDeps(manifestPath: string): Set<string>;
|
|
102
109
|
/**
|
|
103
|
-
*
|
|
110
|
+
* Compute the set of graph nodes reachable from direct deps, excluding ignored.
|
|
104
111
|
* @param {Map<string, GraphEntry>} graph
|
|
105
|
-
* @param {string[]} directDeps
|
|
112
|
+
* @param {string[]} directDeps
|
|
106
113
|
* @param {Set<string>} ignoredDeps
|
|
107
|
-
* @
|
|
108
|
-
* @returns {DepTreeEntry[]}
|
|
109
|
-
* @protected
|
|
110
|
-
*/
|
|
111
|
-
protected _buildDependencyTree(graph: Map<string, GraphEntry>, directDeps: string[], ignoredDeps: Set<string>, includeTransitive: boolean): DepTreeEntry[];
|
|
112
|
-
/**
|
|
113
|
-
* Recursively collect transitive dependencies.
|
|
114
|
-
* @param {Map<string, GraphEntry>} graph
|
|
115
|
-
* @param {string[]} childKeys
|
|
116
|
-
* @param {DepTreeEntry[]} result - mutated in place
|
|
117
|
-
* @param {Set<string>} ignoredDeps
|
|
118
|
-
* @param {Set<string>} visited
|
|
119
|
-
* @returns {void}
|
|
114
|
+
* @returns {Set<string>}
|
|
120
115
|
* @protected
|
|
121
116
|
*/
|
|
122
|
-
protected
|
|
117
|
+
protected _reachableNodes(graph: Map<string, GraphEntry>, directDeps: string[], ignoredDeps: Set<string>): Set<string>;
|
|
123
118
|
/**
|
|
124
119
|
* @param {string} name
|
|
125
120
|
* @param {string} version
|
|
@@ -127,15 +122,6 @@ export default class Base_pyproject {
|
|
|
127
122
|
* @protected
|
|
128
123
|
*/
|
|
129
124
|
protected _toPurl(name: string, version: string): PackageURL;
|
|
130
|
-
/**
|
|
131
|
-
* Recursively add a dependency and its transitive deps to the SBOM.
|
|
132
|
-
* @param {PackageURL} source
|
|
133
|
-
* @param {DepTreeEntry} dep
|
|
134
|
-
* @param {Sbom} sbom
|
|
135
|
-
* @returns {void}
|
|
136
|
-
* @private
|
|
137
|
-
*/
|
|
138
|
-
private _addAllDependencies;
|
|
139
125
|
/**
|
|
140
126
|
* Create SBOM json string for a pyproject.toml project.
|
|
141
127
|
* @param {string} manifest - path to pyproject.toml
|
|
@@ -150,6 +136,10 @@ export type GraphEntry = {
|
|
|
150
136
|
name: string;
|
|
151
137
|
version: string;
|
|
152
138
|
children: string[];
|
|
139
|
+
hashes?: Array<{
|
|
140
|
+
alg: string;
|
|
141
|
+
content: string;
|
|
142
|
+
}>;
|
|
153
143
|
};
|
|
154
144
|
export type DepTreeEntry = {
|
|
155
145
|
name: string;
|
|
@@ -7,9 +7,10 @@ import Sbom from '../sbom.js';
|
|
|
7
7
|
import { getCustom } from '../tools.js';
|
|
8
8
|
const ecosystem = 'pip';
|
|
9
9
|
const IGNORE_MARKERS = ['exhortignore', 'trustify-da-ignore'];
|
|
10
|
+
const NO_SCOPE = undefined;
|
|
10
11
|
const DEFAULT_ROOT_NAME = 'default-pip-root';
|
|
11
12
|
const DEFAULT_ROOT_VERSION = '0.0.0';
|
|
12
|
-
/** @typedef {{name: string, version: string, children: string[]}} GraphEntry */
|
|
13
|
+
/** @typedef {{name: string, version: string, children: string[], hashes?: Array<{alg: string, content: string}>}} GraphEntry */
|
|
13
14
|
/** @typedef {{name: string, version: string, dependencies: DepTreeEntry[]}} DepTreeEntry */
|
|
14
15
|
/** @typedef {{directDeps: string[], graph: Map<string, GraphEntry>}} DependencyData */
|
|
15
16
|
/** @typedef {{ecosystem: string, content: string, contentType: string}} Provided */
|
|
@@ -144,10 +145,19 @@ export default class Base_pyproject {
|
|
|
144
145
|
_cmdName() {
|
|
145
146
|
throw new TypeError('_cmdName must be implemented');
|
|
146
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* Returns the package manager name (e.g. pip, poetry, uv)
|
|
150
|
+
* @returns {string}
|
|
151
|
+
*/
|
|
152
|
+
packageManagerName() {
|
|
153
|
+
return this._cmdName();
|
|
154
|
+
}
|
|
147
155
|
/**
|
|
148
156
|
* Resolve dependencies using the tool-specific command and parser.
|
|
157
|
+
*
|
|
149
158
|
* @param {string} manifestDir - directory containing the target pyproject.toml
|
|
150
|
-
* @param {string} workspaceDir - workspace root (where the lock file lives)
|
|
159
|
+
* @param {string} workspaceDir - workspace root (where the lock file lives);
|
|
160
|
+
* only used by providers that need workspace-level resolution (e.g. uv)
|
|
151
161
|
* @param {object} parsed - parsed pyproject.toml
|
|
152
162
|
* @param {Object} opts
|
|
153
163
|
* @returns {Promise<DependencyData>}
|
|
@@ -218,64 +228,29 @@ export default class Base_pyproject {
|
|
|
218
228
|
return ignored;
|
|
219
229
|
}
|
|
220
230
|
/**
|
|
221
|
-
*
|
|
222
|
-
* @param {Map<string, GraphEntry>} graph
|
|
223
|
-
* @param {string[]} directDeps - canonical names of direct deps
|
|
224
|
-
* @param {Set<string>} ignoredDeps
|
|
225
|
-
* @param {boolean} includeTransitive
|
|
226
|
-
* @returns {DepTreeEntry[]}
|
|
227
|
-
* @protected
|
|
228
|
-
*/
|
|
229
|
-
_buildDependencyTree(graph, directDeps, ignoredDeps, includeTransitive) {
|
|
230
|
-
let result = [];
|
|
231
|
-
for (let key of directDeps) {
|
|
232
|
-
if (ignoredDeps.has(key)) {
|
|
233
|
-
continue;
|
|
234
|
-
}
|
|
235
|
-
let entry = graph.get(key);
|
|
236
|
-
if (!entry) {
|
|
237
|
-
continue;
|
|
238
|
-
}
|
|
239
|
-
let depTree = [];
|
|
240
|
-
if (includeTransitive) {
|
|
241
|
-
let visited = new Set();
|
|
242
|
-
visited.add(key);
|
|
243
|
-
this._collectTransitive(graph, entry.children, depTree, ignoredDeps, visited);
|
|
244
|
-
}
|
|
245
|
-
result.push({ name: entry.name, version: entry.version, dependencies: depTree });
|
|
246
|
-
}
|
|
247
|
-
result.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()));
|
|
248
|
-
return result;
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* Recursively collect transitive dependencies.
|
|
231
|
+
* Compute the set of graph nodes reachable from direct deps, excluding ignored.
|
|
252
232
|
* @param {Map<string, GraphEntry>} graph
|
|
253
|
-
* @param {string[]}
|
|
254
|
-
* @param {DepTreeEntry[]} result - mutated in place
|
|
233
|
+
* @param {string[]} directDeps
|
|
255
234
|
* @param {Set<string>} ignoredDeps
|
|
256
|
-
* @
|
|
257
|
-
* @returns {void}
|
|
235
|
+
* @returns {Set<string>}
|
|
258
236
|
* @protected
|
|
259
237
|
*/
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
238
|
+
_reachableNodes(graph, directDeps, ignoredDeps) {
|
|
239
|
+
let reachable = new Set();
|
|
240
|
+
let queue = directDeps.filter(k => !ignoredDeps.has(k) && graph.has(k));
|
|
241
|
+
while (queue.length > 0) {
|
|
242
|
+
let key = queue.shift();
|
|
243
|
+
if (reachable.has(key)) {
|
|
264
244
|
continue;
|
|
265
245
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if (!entry) {
|
|
272
|
-
continue;
|
|
246
|
+
reachable.add(key);
|
|
247
|
+
for (let child of graph.get(key).children) {
|
|
248
|
+
if (!ignoredDeps.has(child) && graph.has(child) && !reachable.has(child)) {
|
|
249
|
+
queue.push(child);
|
|
250
|
+
}
|
|
273
251
|
}
|
|
274
|
-
let childDeps = [];
|
|
275
|
-
this._collectTransitive(graph, entry.children, childDeps, ignoredDeps, visited);
|
|
276
|
-
result.push({ name: entry.name, version: entry.version, dependencies: childDeps });
|
|
277
252
|
}
|
|
278
|
-
|
|
253
|
+
return reachable;
|
|
279
254
|
}
|
|
280
255
|
/**
|
|
281
256
|
* @param {string} name
|
|
@@ -286,21 +261,6 @@ export default class Base_pyproject {
|
|
|
286
261
|
_toPurl(name, version) {
|
|
287
262
|
return new PackageURL('pypi', undefined, name, version, undefined, undefined);
|
|
288
263
|
}
|
|
289
|
-
/**
|
|
290
|
-
* Recursively add a dependency and its transitive deps to the SBOM.
|
|
291
|
-
* @param {PackageURL} source
|
|
292
|
-
* @param {DepTreeEntry} dep
|
|
293
|
-
* @param {Sbom} sbom
|
|
294
|
-
* @returns {void}
|
|
295
|
-
* @private
|
|
296
|
-
*/
|
|
297
|
-
_addAllDependencies(source, dep, sbom) {
|
|
298
|
-
let targetPurl = this._toPurl(dep.name, dep.version);
|
|
299
|
-
sbom.addDependency(source, targetPurl);
|
|
300
|
-
if (dep.dependencies && dep.dependencies.length > 0) {
|
|
301
|
-
dep.dependencies.forEach(child => this._addAllDependencies(this._toPurl(dep.name, dep.version), child, sbom));
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
264
|
/**
|
|
305
265
|
* Create SBOM json string for a pyproject.toml project.
|
|
306
266
|
* @param {string} manifest - path to pyproject.toml
|
|
@@ -316,21 +276,47 @@ export default class Base_pyproject {
|
|
|
316
276
|
let workspaceDir = this._findLockFileDir(manifestDir, opts) || manifestDir;
|
|
317
277
|
let { directDeps, graph } = await this._getDependencyData(manifestDir, workspaceDir, parsed, opts);
|
|
318
278
|
let ignoredDeps = this._getIgnoredDeps(manifest);
|
|
319
|
-
let dependencies = this._buildDependencyTree(graph, directDeps, ignoredDeps, includeTransitive);
|
|
320
279
|
let sbom = new Sbom();
|
|
321
280
|
let rootName = this._getProjectName(parsed) || DEFAULT_ROOT_NAME;
|
|
322
281
|
let rootVersion = this._getProjectVersion(parsed) || DEFAULT_ROOT_VERSION;
|
|
323
282
|
let rootPurl = this._toPurl(rootName, rootVersion);
|
|
324
283
|
let license = this.readLicenseFromManifest(manifest);
|
|
325
284
|
sbom.addRoot(rootPurl, license);
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
285
|
+
if (includeTransitive) {
|
|
286
|
+
let reachable = this._reachableNodes(graph, directDeps, ignoredDeps);
|
|
287
|
+
for (let key of directDeps) {
|
|
288
|
+
if (!reachable.has(key)) {
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
let entry = graph.get(key);
|
|
292
|
+
sbom.addDependency(rootPurl, this._toPurl(entry.name, entry.version), NO_SCOPE, entry.hashes);
|
|
293
|
+
}
|
|
294
|
+
for (let [key, entry] of graph) {
|
|
295
|
+
if (!reachable.has(key)) {
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
let parentPurl = this._toPurl(entry.name, entry.version);
|
|
299
|
+
for (let child of entry.children) {
|
|
300
|
+
if (!reachable.has(child)) {
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
let childEntry = graph.get(child);
|
|
304
|
+
sbom.addDependency(parentPurl, this._toPurl(childEntry.name, childEntry.version), NO_SCOPE, childEntry.hashes);
|
|
305
|
+
}
|
|
329
306
|
}
|
|
330
|
-
|
|
331
|
-
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
for (let key of directDeps) {
|
|
310
|
+
if (ignoredDeps.has(key)) {
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
let entry = graph.get(key);
|
|
314
|
+
if (!entry) {
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
sbom.addDependency(rootPurl, this._toPurl(entry.name, entry.version), NO_SCOPE, entry.hashes);
|
|
332
318
|
}
|
|
333
|
-
}
|
|
319
|
+
}
|
|
334
320
|
return sbom.getAsJsonString(opts);
|
|
335
321
|
}
|
|
336
322
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { Language, Parser, Query } from 'web-tree-sitter';
|
|
3
|
+
const wasmUrl = new URL('./tree-sitter-containerfile.wasm', import.meta.url);
|
|
4
|
+
async function init() {
|
|
5
|
+
await Parser.init();
|
|
6
|
+
const wasmBytes = new Uint8Array(await readFile(wasmUrl));
|
|
7
|
+
return await Language.load(wasmBytes);
|
|
8
|
+
}
|
|
9
|
+
export async function getParser() {
|
|
10
|
+
const language = await init();
|
|
11
|
+
return new Parser().setLanguage(language);
|
|
12
|
+
}
|
|
13
|
+
export async function getFromQuery() {
|
|
14
|
+
const language = await init();
|
|
15
|
+
return new Query(language, '(from_instruction (image_spec) @image)');
|
|
16
|
+
}
|
|
17
|
+
export async function getArgQuery() {
|
|
18
|
+
const language = await init();
|
|
19
|
+
return new Query(language, '(arg_instruction (arg_pair name: (_) @name default: (_) @default))');
|
|
20
|
+
}
|
|
@@ -1,12 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discover all go.mod manifest paths in a Go workspace.
|
|
3
|
+
* Uses `go work edit -json` to get workspace members.
|
|
4
|
+
*
|
|
5
|
+
* @param {string} workspaceRoot - Absolute or relative path to workspace root (must contain go.work)
|
|
6
|
+
* @param {import('../index.js').Options} [opts={}]
|
|
7
|
+
* @returns {Promise<string[]>} Paths to go.mod files (absolute)
|
|
8
|
+
*/
|
|
9
|
+
export function discoverGoWorkspaceModules(workspaceRoot: string, opts?: import("../index.js").Options): Promise<string[]>;
|
|
1
10
|
declare namespace _default {
|
|
2
11
|
export { isSupported };
|
|
3
12
|
export { validateLockFile };
|
|
4
13
|
export { provideComponent };
|
|
5
14
|
export { provideStack };
|
|
6
15
|
export { readLicenseFromManifest };
|
|
16
|
+
export function packageManagerName(): string;
|
|
7
17
|
}
|
|
8
18
|
export default _default;
|
|
9
|
-
export type Provided =
|
|
19
|
+
export type Provided = any;
|
|
10
20
|
export type Package = {
|
|
11
21
|
name: string;
|
|
12
22
|
version: string;
|
|
@@ -4,8 +4,9 @@ import { PackageURL } from 'packageurl-js';
|
|
|
4
4
|
import { readLicenseFile } from '../license/license_utils.js';
|
|
5
5
|
import Sbom from '../sbom.js';
|
|
6
6
|
import { getCustom, getCustomPath, invokeCommand } from "../tools.js";
|
|
7
|
+
import { filterManifestPathsByDiscoveryIgnore, resolveWorkspaceDiscoveryIgnore } from '../workspace.js';
|
|
7
8
|
import { getParser, getRequireQuery } from './gomod_parser.js';
|
|
8
|
-
export default { isSupported, validateLockFile, provideComponent, provideStack, readLicenseFromManifest };
|
|
9
|
+
export default { isSupported, validateLockFile, provideComponent, provideStack, readLicenseFromManifest, packageManagerName() { return 'go'; } };
|
|
9
10
|
/** @typedef {import('../provider').Provider} */
|
|
10
11
|
/** @typedef {import('../provider').Provided} Provided */
|
|
11
12
|
/** @typedef {{name: string, version: string}} Package */
|
|
@@ -328,13 +329,7 @@ function getFinalPackagesVersionsForModule(rows, manifestPath, goBin) {
|
|
|
328
329
|
catch (error) {
|
|
329
330
|
throw new Error('failed to list all modules', { cause: error });
|
|
330
331
|
}
|
|
331
|
-
let finalVersionModules =
|
|
332
|
-
finalVersionsForAllModules.split(getLineSeparatorGolang()).filter(string => string.trim() !== "")
|
|
333
|
-
.filter(string => string.trim().split(" ").length === 2)
|
|
334
|
-
.forEach((dependency) => {
|
|
335
|
-
let dep = dependency.split(" ");
|
|
336
|
-
finalVersionModules[dep[0]] = dep[1];
|
|
337
|
-
});
|
|
332
|
+
let finalVersionModules = parseModuleVersions(finalVersionsForAllModules);
|
|
338
333
|
let finalVersionModulesArray = new Array();
|
|
339
334
|
rows.filter(string => string.trim() !== "").forEach(module => {
|
|
340
335
|
let child = getChildVertexFromEdge(module);
|
|
@@ -395,7 +390,69 @@ function getVersionOfPackage(fullPackage) {
|
|
|
395
390
|
let parts = fullPackage.split("@");
|
|
396
391
|
return parts.length > 1 ? parts[1] : undefined;
|
|
397
392
|
}
|
|
393
|
+
function parseModuleVersions(goListOutput) {
|
|
394
|
+
let modules = {};
|
|
395
|
+
goListOutput.split(getLineSeparatorGolang()).filter(string => string.trim() !== "")
|
|
396
|
+
.forEach((line) => {
|
|
397
|
+
let parts = line.trim().split(" ");
|
|
398
|
+
if (parts.length === 2) {
|
|
399
|
+
modules[parts[0]] = parts[1];
|
|
400
|
+
}
|
|
401
|
+
else if (parts.length >= 4 && parts[2] === "=>") {
|
|
402
|
+
modules[parts[0]] = parts[parts.length - 1];
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
return modules;
|
|
406
|
+
}
|
|
398
407
|
function getLineSeparatorGolang() {
|
|
399
408
|
let reg = /\n|\r\n/;
|
|
400
409
|
return reg;
|
|
401
410
|
}
|
|
411
|
+
/**
|
|
412
|
+
* Discover all go.mod manifest paths in a Go workspace.
|
|
413
|
+
* Uses `go work edit -json` to get workspace members.
|
|
414
|
+
*
|
|
415
|
+
* @param {string} workspaceRoot - Absolute or relative path to workspace root (must contain go.work)
|
|
416
|
+
* @param {import('../index.js').Options} [opts={}]
|
|
417
|
+
* @returns {Promise<string[]>} Paths to go.mod files (absolute)
|
|
418
|
+
*/
|
|
419
|
+
export async function discoverGoWorkspaceModules(workspaceRoot, opts = {}) {
|
|
420
|
+
const root = path.resolve(workspaceRoot);
|
|
421
|
+
const goWork = path.join(root, 'go.work');
|
|
422
|
+
if (!fs.existsSync(goWork)) {
|
|
423
|
+
return [];
|
|
424
|
+
}
|
|
425
|
+
const goBin = getCustomPath('go', opts);
|
|
426
|
+
let output;
|
|
427
|
+
try {
|
|
428
|
+
output = invokeCommand(goBin, ['work', 'edit', '-json', goWork], { cwd: root });
|
|
429
|
+
}
|
|
430
|
+
catch {
|
|
431
|
+
return [];
|
|
432
|
+
}
|
|
433
|
+
let workspace;
|
|
434
|
+
try {
|
|
435
|
+
workspace = JSON.parse(output.toString().trim());
|
|
436
|
+
}
|
|
437
|
+
catch {
|
|
438
|
+
return [];
|
|
439
|
+
}
|
|
440
|
+
const useEntries = workspace.Use || [];
|
|
441
|
+
if (useEntries.length === 0) {
|
|
442
|
+
return [];
|
|
443
|
+
}
|
|
444
|
+
const manifestPaths = [];
|
|
445
|
+
for (const entry of useEntries) {
|
|
446
|
+
const diskPath = entry.DiskPath;
|
|
447
|
+
if (!diskPath) {
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
const moduleDir = path.resolve(root, diskPath);
|
|
451
|
+
const goMod = path.join(moduleDir, 'go.mod');
|
|
452
|
+
if (fs.existsSync(goMod)) {
|
|
453
|
+
manifestPaths.push(goMod);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
const ignorePatterns = resolveWorkspaceDiscoveryIgnore(opts);
|
|
457
|
+
return filterManifestPathsByDiscoveryIgnore(manifestPaths, root, ignorePatterns);
|
|
458
|
+
}
|
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discover all build.gradle[.kts] manifest paths in a Gradle multi-project build.
|
|
3
|
+
* Uses a custom init script to get structured project listing.
|
|
4
|
+
*
|
|
5
|
+
* @param {string} workspaceRoot - Absolute or relative path to workspace root (must contain settings.gradle[.kts])
|
|
6
|
+
* @param {import('../index.js').Options} [opts={}]
|
|
7
|
+
* @returns {Promise<string[]>} Paths to build.gradle[.kts] files (absolute)
|
|
8
|
+
*/
|
|
9
|
+
export function discoverGradleSubprojects(workspaceRoot: string, opts?: import("../index.js").Options): Promise<string[]>;
|
|
10
|
+
/**
|
|
11
|
+
* Parse the structured output from the Gradle init script.
|
|
12
|
+
*
|
|
13
|
+
* @param {string} raw - Raw stdout from gradle
|
|
14
|
+
* @returns {{ path: string, dir: string }[]}
|
|
15
|
+
*/
|
|
16
|
+
export function parseGradleInitScriptOutput(raw: string): {
|
|
17
|
+
path: string;
|
|
18
|
+
dir: string;
|
|
19
|
+
}[];
|
|
1
20
|
/**
|
|
2
21
|
* This class provides common functionality for Groovy and Kotlin DSL files.
|
|
3
22
|
*/
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
1
2
|
import fs from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
2
4
|
import path from 'node:path';
|
|
3
5
|
import { EOL } from 'os';
|
|
4
|
-
import
|
|
6
|
+
import { parse as parseToml } from 'smol-toml';
|
|
5
7
|
import { readLicenseFile } from '../license/license_utils.js';
|
|
6
8
|
import Sbom from '../sbom.js';
|
|
9
|
+
import { invokeCommand } from '../tools.js';
|
|
10
|
+
import { filterManifestPathsByDiscoveryIgnore, resolveWorkspaceDiscoveryIgnore } from '../workspace.js';
|
|
7
11
|
import Base_java, { ecosystem_gradle } from "./base_java.js";
|
|
8
12
|
/** @typedef {import('../provider.js').Provider} */
|
|
9
13
|
/** @typedef {import('../provider.js').Provided} Provided */
|
|
@@ -362,7 +366,7 @@ export default class Java_gradle extends Base_java {
|
|
|
362
366
|
// Read and parse the TOML file
|
|
363
367
|
let pathOfToml = path.join(path.dirname(manifestPath), "gradle", "libs.versions.toml");
|
|
364
368
|
const tomlString = fs.readFileSync(pathOfToml).toString();
|
|
365
|
-
let tomlObject =
|
|
369
|
+
let tomlObject = parseToml(tomlString);
|
|
366
370
|
let groupPlusArtifactObject = tomlObject.libraries[alias];
|
|
367
371
|
let parts = groupPlusArtifactObject.module.split(":");
|
|
368
372
|
let groupId = parts[0];
|
|
@@ -407,3 +411,113 @@ export default class Java_gradle extends Base_java {
|
|
|
407
411
|
return undefined;
|
|
408
412
|
}
|
|
409
413
|
}
|
|
414
|
+
const DEFAULT_GRADLE_DISCOVERY_IGNORE = [
|
|
415
|
+
'**/build/**',
|
|
416
|
+
'**/.gradle/**',
|
|
417
|
+
];
|
|
418
|
+
/** Gradle init script that emits structured project listing. */
|
|
419
|
+
const GRADLE_INIT_SCRIPT = `allprojects {
|
|
420
|
+
task daListProjects {
|
|
421
|
+
doLast {
|
|
422
|
+
println "::DA_PROJECT::\${project.path}::\${project.projectDir}"
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
`;
|
|
427
|
+
/**
|
|
428
|
+
* Discover all build.gradle[.kts] manifest paths in a Gradle multi-project build.
|
|
429
|
+
* Uses a custom init script to get structured project listing.
|
|
430
|
+
*
|
|
431
|
+
* @param {string} workspaceRoot - Absolute or relative path to workspace root (must contain settings.gradle[.kts])
|
|
432
|
+
* @param {import('../index.js').Options} [opts={}]
|
|
433
|
+
* @returns {Promise<string[]>} Paths to build.gradle[.kts] files (absolute)
|
|
434
|
+
*/
|
|
435
|
+
export async function discoverGradleSubprojects(workspaceRoot, opts = {}) {
|
|
436
|
+
const root = path.resolve(workspaceRoot);
|
|
437
|
+
const hasSettings = fs.existsSync(path.join(root, 'settings.gradle'))
|
|
438
|
+
|| fs.existsSync(path.join(root, 'settings.gradle.kts'));
|
|
439
|
+
if (!hasSettings) {
|
|
440
|
+
return [];
|
|
441
|
+
}
|
|
442
|
+
const manifestPaths = [];
|
|
443
|
+
const rootBuildKts = path.join(root, 'build.gradle.kts');
|
|
444
|
+
const rootBuild = path.join(root, 'build.gradle');
|
|
445
|
+
const rootManifest = fs.existsSync(rootBuildKts) ? rootBuildKts : fs.existsSync(rootBuild) ? rootBuild : null;
|
|
446
|
+
if (rootManifest) {
|
|
447
|
+
manifestPaths.push(rootManifest);
|
|
448
|
+
}
|
|
449
|
+
let gradleBin;
|
|
450
|
+
try {
|
|
451
|
+
gradleBin = new Java_gradle().selectToolBinary(rootManifest || rootBuild, opts);
|
|
452
|
+
}
|
|
453
|
+
catch {
|
|
454
|
+
const ignorePatterns = [...resolveWorkspaceDiscoveryIgnore(opts), ...DEFAULT_GRADLE_DISCOVERY_IGNORE];
|
|
455
|
+
return filterManifestPathsByDiscoveryIgnore(manifestPaths, root, ignorePatterns);
|
|
456
|
+
}
|
|
457
|
+
const initScriptPath = path.join(os.tmpdir(), `da-list-projects-${crypto.randomUUID()}.gradle`);
|
|
458
|
+
try {
|
|
459
|
+
fs.writeFileSync(initScriptPath, GRADLE_INIT_SCRIPT);
|
|
460
|
+
let output;
|
|
461
|
+
try {
|
|
462
|
+
output = invokeCommand(gradleBin, [
|
|
463
|
+
'-q', '--no-daemon',
|
|
464
|
+
'--init-script', initScriptPath,
|
|
465
|
+
'daListProjects',
|
|
466
|
+
], { cwd: root });
|
|
467
|
+
}
|
|
468
|
+
catch {
|
|
469
|
+
const ignorePatterns = [...resolveWorkspaceDiscoveryIgnore(opts), ...DEFAULT_GRADLE_DISCOVERY_IGNORE];
|
|
470
|
+
return filterManifestPathsByDiscoveryIgnore(manifestPaths, root, ignorePatterns);
|
|
471
|
+
}
|
|
472
|
+
const projects = parseGradleInitScriptOutput(output.toString());
|
|
473
|
+
for (const proj of projects) {
|
|
474
|
+
if (proj.path === ':') {
|
|
475
|
+
continue;
|
|
476
|
+
}
|
|
477
|
+
const projDir = path.resolve(proj.dir);
|
|
478
|
+
const buildKts = path.join(projDir, 'build.gradle.kts');
|
|
479
|
+
const buildGroovy = path.join(projDir, 'build.gradle');
|
|
480
|
+
if (fs.existsSync(buildKts)) {
|
|
481
|
+
manifestPaths.push(buildKts);
|
|
482
|
+
}
|
|
483
|
+
else if (fs.existsSync(buildGroovy)) {
|
|
484
|
+
manifestPaths.push(buildGroovy);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
finally {
|
|
489
|
+
try {
|
|
490
|
+
fs.unlinkSync(initScriptPath);
|
|
491
|
+
}
|
|
492
|
+
catch { /* ignore */ }
|
|
493
|
+
}
|
|
494
|
+
const ignorePatterns = [...resolveWorkspaceDiscoveryIgnore(opts), ...DEFAULT_GRADLE_DISCOVERY_IGNORE];
|
|
495
|
+
return filterManifestPathsByDiscoveryIgnore(manifestPaths, root, ignorePatterns);
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Parse the structured output from the Gradle init script.
|
|
499
|
+
*
|
|
500
|
+
* @param {string} raw - Raw stdout from gradle
|
|
501
|
+
* @returns {{ path: string, dir: string }[]}
|
|
502
|
+
*/
|
|
503
|
+
export function parseGradleInitScriptOutput(raw) {
|
|
504
|
+
const projects = [];
|
|
505
|
+
for (const rawLine of raw.split('\n')) {
|
|
506
|
+
const line = rawLine.trimEnd();
|
|
507
|
+
if (!line.startsWith('::DA_PROJECT::')) {
|
|
508
|
+
continue;
|
|
509
|
+
}
|
|
510
|
+
const prefix = '::DA_PROJECT::';
|
|
511
|
+
const remainder = line.substring(prefix.length);
|
|
512
|
+
const lastSep = remainder.lastIndexOf('::');
|
|
513
|
+
if (lastSep < 0) {
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
const projPath = remainder.substring(0, lastSep);
|
|
517
|
+
const dir = remainder.substring(lastSep + 2);
|
|
518
|
+
if (projPath && dir) {
|
|
519
|
+
projects.push({ path: projPath, dir });
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
return projects;
|
|
523
|
+
}
|
|
@@ -3,5 +3,5 @@ export default class Java_gradle_groovy extends Java_gradle {
|
|
|
3
3
|
_parseAliasForLibsNotation(alias: any): any;
|
|
4
4
|
_extractDepToBeIgnored(dep: any): any;
|
|
5
5
|
}
|
|
6
|
-
export type Provided =
|
|
6
|
+
export type Provided = any;
|
|
7
7
|
import Java_gradle from './java_gradle.js';
|
|
@@ -7,5 +7,5 @@ export default class Java_gradle_kotlin extends Java_gradle {
|
|
|
7
7
|
_parseAliasForLibsNotation(alias: any): any;
|
|
8
8
|
_extractDepToBeIgnored(dep: any): string | null;
|
|
9
9
|
}
|
|
10
|
-
export type Provided =
|
|
10
|
+
export type Provided = any;
|
|
11
11
|
import Java_gradle from './java_gradle.js';
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discover all pom.xml manifest paths in a Maven multi-module project.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} workspaceRoot - Absolute or relative path to workspace root (must contain pom.xml)
|
|
5
|
+
* @param {object} [opts={}]
|
|
6
|
+
* @returns {Promise<string[]>} Paths to pom.xml files (absolute)
|
|
7
|
+
*/
|
|
8
|
+
export function discoverMavenModules(workspaceRoot: string, opts?: object): Promise<string[]>;
|
|
1
9
|
/** @typedef {import('../provider').Provider} */
|
|
2
10
|
/** @typedef {import('../provider').Provided} Provided */
|
|
3
11
|
/** @typedef {{name: string, version: string}} Package */
|
|
@@ -43,8 +51,8 @@ export default class Java_maven extends Base_java {
|
|
|
43
51
|
createSbomFileFromTextFormat(textGraphList: string, ignoredDeps: [string], opts: any, manifestPath: string): string;
|
|
44
52
|
#private;
|
|
45
53
|
}
|
|
46
|
-
export type Java_maven =
|
|
47
|
-
export type Provided =
|
|
54
|
+
export type Java_maven = any;
|
|
55
|
+
export type Provided = any;
|
|
48
56
|
export type Package = {
|
|
49
57
|
name: string;
|
|
50
58
|
version: string;
|