@trustify-da/trustify-da-javascript-client 0.2.4-ea.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +482 -0
  3. package/config/config.properties +1 -0
  4. package/dist/package.json +106 -0
  5. package/dist/src/analysis.d.ts +43 -0
  6. package/dist/src/analysis.js +252 -0
  7. package/dist/src/cli.d.ts +2 -0
  8. package/dist/src/cli.js +102 -0
  9. package/dist/src/cyclone_dx_sbom.d.ts +77 -0
  10. package/dist/src/cyclone_dx_sbom.js +244 -0
  11. package/dist/src/index.d.ts +82 -0
  12. package/dist/src/index.js +194 -0
  13. package/dist/src/oci_image/images.d.ts +99 -0
  14. package/dist/src/oci_image/images.js +263 -0
  15. package/dist/src/oci_image/platform.d.ts +59 -0
  16. package/dist/src/oci_image/platform.js +138 -0
  17. package/dist/src/oci_image/utils.d.ts +42 -0
  18. package/dist/src/oci_image/utils.js +496 -0
  19. package/dist/src/provider.d.ts +29 -0
  20. package/dist/src/provider.js +47 -0
  21. package/dist/src/providers/base_java.d.ts +85 -0
  22. package/dist/src/providers/base_java.js +191 -0
  23. package/dist/src/providers/base_javascript.d.ts +127 -0
  24. package/dist/src/providers/base_javascript.js +350 -0
  25. package/dist/src/providers/golang_gomodules.d.ts +42 -0
  26. package/dist/src/providers/golang_gomodules.js +403 -0
  27. package/dist/src/providers/java_gradle.d.ts +35 -0
  28. package/dist/src/providers/java_gradle.js +399 -0
  29. package/dist/src/providers/java_gradle_groovy.d.ts +7 -0
  30. package/dist/src/providers/java_gradle_groovy.js +19 -0
  31. package/dist/src/providers/java_gradle_kotlin.d.ts +11 -0
  32. package/dist/src/providers/java_gradle_kotlin.js +23 -0
  33. package/dist/src/providers/java_maven.d.ts +52 -0
  34. package/dist/src/providers/java_maven.js +263 -0
  35. package/dist/src/providers/javascript_npm.d.ts +4 -0
  36. package/dist/src/providers/javascript_npm.js +15 -0
  37. package/dist/src/providers/javascript_pnpm.d.ts +5 -0
  38. package/dist/src/providers/javascript_pnpm.js +22 -0
  39. package/dist/src/providers/javascript_yarn.d.ts +11 -0
  40. package/dist/src/providers/javascript_yarn.js +39 -0
  41. package/dist/src/providers/manifest.d.ts +11 -0
  42. package/dist/src/providers/manifest.js +48 -0
  43. package/dist/src/providers/processors/yarn_berry_processor.d.ts +41 -0
  44. package/dist/src/providers/processors/yarn_berry_processor.js +130 -0
  45. package/dist/src/providers/processors/yarn_classic_processor.d.ts +37 -0
  46. package/dist/src/providers/processors/yarn_classic_processor.js +109 -0
  47. package/dist/src/providers/processors/yarn_processor.d.ts +9 -0
  48. package/dist/src/providers/processors/yarn_processor.js +20 -0
  49. package/dist/src/providers/python_controller.d.ts +31 -0
  50. package/dist/src/providers/python_controller.js +406 -0
  51. package/dist/src/providers/python_pip.d.ts +35 -0
  52. package/dist/src/providers/python_pip.js +227 -0
  53. package/dist/src/sbom.d.ts +59 -0
  54. package/dist/src/sbom.js +84 -0
  55. package/dist/src/tools.d.ts +74 -0
  56. package/dist/src/tools.js +159 -0
  57. package/package.json +106 -0
@@ -0,0 +1,227 @@
1
+ import fs from 'node:fs';
2
+ import { EOL } from 'os';
3
+ import { PackageURL } from 'packageurl-js';
4
+ import Sbom from '../sbom.js';
5
+ import { environmentVariableIsPopulated, getCustom, getCustomPath, invokeCommand } from "../tools.js";
6
+ import Python_controller from './python_controller.js';
7
+ export default { isSupported, validateLockFile, provideComponent, provideStack };
8
+ /** @typedef {{name: string, version: string, dependencies: DependencyEntry[]}} DependencyEntry */
9
+ /**
10
+ * @type {string} ecosystem for python-pip is 'pip'
11
+ * @private
12
+ */
13
+ const ecosystem = 'pip';
14
+ /**
15
+ * @param {string} manifestName - the subject manifest name-type
16
+ * @returns {boolean} - return true if `requirements.txt` is the manifest name-type
17
+ */
18
+ function isSupported(manifestName) {
19
+ return 'requirements.txt' === manifestName;
20
+ }
21
+ /**
22
+ * @param {string} manifestDir - the directory where the manifest lies
23
+ */
24
+ function validateLockFile() { return true; }
25
+ /**
26
+ * Provide content and content type for python-pip stack analysis.
27
+ * @param {string} manifest - the manifest path or name
28
+ * @param {{}} [opts={}] - optional various options to pass along the application
29
+ * @returns {Provided}
30
+ */
31
+ function provideStack(manifest, opts = {}) {
32
+ return {
33
+ ecosystem,
34
+ content: createSbomStackAnalysis(manifest, opts),
35
+ contentType: 'application/vnd.cyclonedx+json'
36
+ };
37
+ }
38
+ /**
39
+ * Provide content and content type for python-pip component analysis.
40
+ * @param {string} manifest - path to requirements.txt for component report
41
+ * @param {{}} [opts={}] - optional various options to pass along the application
42
+ * @returns {Provided}
43
+ */
44
+ function provideComponent(manifest, opts = {}) {
45
+ return {
46
+ ecosystem,
47
+ content: getSbomForComponentAnalysis(manifest, opts),
48
+ contentType: 'application/vnd.cyclonedx+json'
49
+ };
50
+ }
51
+ /** @typedef {{name: string, , version: string, dependencies: DependencyEntry[]}} DependencyEntry */
52
+ /**
53
+ *
54
+ * @param {PackageURL}source
55
+ * @param {DependencyEntry} dep
56
+ * @param {Sbom} sbom
57
+ * @private
58
+ */
59
+ function addAllDependencies(source, dep, sbom) {
60
+ let targetPurl = toPurl(dep["name"], dep["version"]);
61
+ sbom.addDependency(source, targetPurl);
62
+ let directDeps = dep["dependencies"];
63
+ if (directDeps !== undefined && directDeps.length > 0) {
64
+ directDeps.forEach((dependency) => { addAllDependencies(toPurl(dep["name"], dep["version"]), dependency, sbom); });
65
+ }
66
+ }
67
+ /**
68
+ *
69
+ * @param nameVersion
70
+ * @return {string}
71
+ */
72
+ function splitToNameVersion(nameVersion) {
73
+ let result = [];
74
+ if (nameVersion.includes("==")) {
75
+ return nameVersion.split("==");
76
+ }
77
+ const regex = /[^\w\s-_]/g;
78
+ let endIndex = nameVersion.search(regex);
79
+ if (endIndex === -1) {
80
+ return [nameVersion.trim()];
81
+ }
82
+ result.push(nameVersion.substring(0, endIndex).trim());
83
+ return result;
84
+ }
85
+ /**
86
+ *
87
+ * @param {string} requirementTxtContent
88
+ * @return {PackageURL []}
89
+ */
90
+ function getIgnoredDependencies(requirementTxtContent) {
91
+ let requirementsLines = requirementTxtContent.split(EOL);
92
+ return requirementsLines
93
+ .filter(line => line.includes("#exhortignore") || line.includes("# exhortignore"))
94
+ .map((line) => line.substring(0, line.indexOf("#")).trim())
95
+ .map((name) => {
96
+ let nameVersion = splitToNameVersion(name);
97
+ if (nameVersion.length === 2) {
98
+ return toPurl(nameVersion[0], nameVersion[1]);
99
+ }
100
+ return toPurl(nameVersion[0], undefined);
101
+ });
102
+ }
103
+ /**
104
+ *
105
+ * @param {string} requirementTxtContent content of requirments.txt in string
106
+ * @param {Sbom} sbom object to filter out from it exhortignore dependencies.
107
+ * @param {{Object}} opts - various options and settings for the application
108
+ * @private
109
+ */
110
+ function handleIgnoredDependencies(requirementTxtContent, sbom, opts = {}) {
111
+ let ignoredDeps = getIgnoredDependencies(requirementTxtContent);
112
+ let matchManifestVersions = getCustom("MATCH_MANIFEST_VERSIONS", "true", opts);
113
+ if (matchManifestVersions === "true") {
114
+ const ignoredDepsVersion = ignoredDeps.filter(dep => dep.version !== undefined);
115
+ sbom.filterIgnoredDepsIncludingVersion(ignoredDepsVersion.map(dep => dep.toString()));
116
+ }
117
+ else {
118
+ // in case of version mismatch, need to parse the name of package from the purl, and remove the package name from sbom according to name only
119
+ // without version
120
+ sbom.filterIgnoredDeps(ignoredDeps);
121
+ }
122
+ }
123
+ /** get python and pip binaries, python3/pip3 get precedence if exists on the system path
124
+ * @param {object}binaries
125
+ * @param {{}} [opts={}]
126
+ */
127
+ function getPythonPipBinaries(binaries, opts) {
128
+ let python = getCustomPath("python3", opts);
129
+ let pip = getCustomPath("pip3", opts);
130
+ try {
131
+ invokeCommand(python, ['--version']);
132
+ invokeCommand(pip, ['--version']);
133
+ }
134
+ catch (error) {
135
+ python = getCustomPath("python", opts);
136
+ pip = getCustomPath("pip", opts);
137
+ try {
138
+ invokeCommand(python, ['--version']);
139
+ invokeCommand(pip, ['--version']);
140
+ }
141
+ catch (error) {
142
+ throw new Error(`Failed checking for python/pip binaries from supplied environment variables`, { cause: error });
143
+ }
144
+ }
145
+ binaries.pip = pip;
146
+ binaries.python = python;
147
+ }
148
+ /**
149
+ *
150
+ * @param binaries
151
+ * @param opts
152
+ * @return {string}
153
+ * @private
154
+ */
155
+ function handlePythonEnvironment(binaries, opts) {
156
+ let createVirtualPythonEnv;
157
+ if (!environmentVariableIsPopulated("TRUSTIFY_DA_PIP_SHOW") && !environmentVariableIsPopulated("TRUSTIFY_DA_PIP_FREEZE")) {
158
+ getPythonPipBinaries(binaries, opts);
159
+ createVirtualPythonEnv = getCustom("TRUSTIFY_DA_PYTHON_VIRTUAL_ENV", "false", opts);
160
+ }
161
+ // bypass invoking python and pip, as we get all information needed to build the dependency tree from these Environment variables.
162
+ else {
163
+ binaries.pip = "pip";
164
+ binaries.python = "python";
165
+ createVirtualPythonEnv = "false";
166
+ }
167
+ return createVirtualPythonEnv;
168
+ }
169
+ const DEFAULT_PIP_ROOT_COMPONENT_NAME = "default-pip-root";
170
+ const DEFAULT_PIP_ROOT_COMPONENT_VERSION = "0.0.0";
171
+ /**
172
+ * Create sbom json string out of a manifest path for stack analysis.
173
+ * @param {string} manifest - path for requirements.txt
174
+ * @param {{}} [opts={}] - optional various options to pass along the application
175
+ * @returns {string} the sbom json string content
176
+ * @private
177
+ */
178
+ function createSbomStackAnalysis(manifest, opts = {}) {
179
+ let binaries = {};
180
+ let createVirtualPythonEnv = handlePythonEnvironment(binaries, opts);
181
+ let pythonController = new Python_controller(createVirtualPythonEnv === "false", binaries.pip, binaries.python, manifest, opts);
182
+ let dependencies = pythonController.getDependencies(true);
183
+ let sbom = new Sbom();
184
+ const rootPurl = toPurl(DEFAULT_PIP_ROOT_COMPONENT_NAME, DEFAULT_PIP_ROOT_COMPONENT_VERSION);
185
+ sbom.addRoot(rootPurl);
186
+ dependencies.forEach(dep => {
187
+ addAllDependencies(rootPurl, dep, sbom);
188
+ });
189
+ let requirementTxtContent = fs.readFileSync(manifest).toString();
190
+ handleIgnoredDependencies(requirementTxtContent, sbom, opts);
191
+ // In python there is no root component, then we must remove the dummy root we added, so the sbom json will be accepted by exhort backend
192
+ // sbom.removeRootComponent()
193
+ return sbom.getAsJsonString(opts);
194
+ }
195
+ /**
196
+ * Create a sbom json string out of a manifest content for component analysis
197
+ * @param {string} manifest - path to requirements.txt
198
+ * @param {{}} [opts={}] - optional various options to pass along the application
199
+ * @returns {string} the sbom json string content
200
+ * @private
201
+ */
202
+ function getSbomForComponentAnalysis(manifest, opts = {}) {
203
+ let binaries = {};
204
+ let createVirtualPythonEnv = handlePythonEnvironment(binaries, opts);
205
+ let pythonController = new Python_controller(createVirtualPythonEnv === "false", binaries.pip, binaries.python, manifest, opts);
206
+ let dependencies = pythonController.getDependencies(false);
207
+ let sbom = new Sbom();
208
+ const rootPurl = toPurl(DEFAULT_PIP_ROOT_COMPONENT_NAME, DEFAULT_PIP_ROOT_COMPONENT_VERSION);
209
+ sbom.addRoot(rootPurl);
210
+ dependencies.forEach(dep => {
211
+ sbom.addDependency(rootPurl, toPurl(dep.name, dep.version));
212
+ });
213
+ let requirementTxtContent = fs.readFileSync(manifest).toString();
214
+ handleIgnoredDependencies(requirementTxtContent, sbom, opts);
215
+ // In python there is no root component, then we must remove the dummy root we added, so the sbom json will be accepted by exhort backend
216
+ // sbom.removeRootComponent()
217
+ return sbom.getAsJsonString(opts);
218
+ }
219
+ /**
220
+ * Returns a PackageUrl For pip dependencies
221
+ * @param name
222
+ * @param version
223
+ * @return {PackageURL}
224
+ */
225
+ function toPurl(name, version) {
226
+ return new PackageURL('pypi', undefined, name, version, undefined, undefined);
227
+ }
@@ -0,0 +1,59 @@
1
+ export default class Sbom {
2
+ sbomModel: CycloneDxSbom;
3
+ /**
4
+ * @param {PackageURL} root - add main/root component for sbom
5
+ * @return Sbom
6
+ */
7
+ addRoot(root: PackageURL): CycloneDxSbom;
8
+ /**
9
+ * @return {{{"bom-ref": string, name, purl: string, type, version}}} root component of sbom.
10
+ */
11
+ getRoot(): {};
12
+ /**
13
+ * This method gets an array of dependencies to be ignored, and remove all of them from sbom
14
+ * @param {Array} dependencies to be removed from sbom
15
+ * @return {Sbom} without ignored dependencies
16
+ */
17
+ filterIgnoredDeps(deps: any): Sbom;
18
+ /**
19
+ * This method gets an array of dependencies with versions( purl string format) to be ignored, and remove all of them from CycloneDx Sbom
20
+ * @param {Array} dependencies to be removed from sbom
21
+ * @return {CycloneDxSbom} without ignored dependencies
22
+ */
23
+ filterIgnoredDepsIncludingVersion(deps: any): CycloneDxSbom;
24
+ /**
25
+ * @param {component} sourceRef current source Component ( Starting from root component by clients)
26
+ * @param {PackageURL} targetRef current dependency to add to Dependencies list of component sourceRef
27
+ * @return Sbom
28
+ */
29
+ addDependency(sourceRef: component, targetRef: PackageURL, scope: any): CycloneDxSbom;
30
+ /**
31
+ * @return String sbom json in a string format
32
+ */
33
+ getAsJsonString(opts?: {}): string;
34
+ /**
35
+ * This method gets a PackageUrl, and returns a Component of Sbom
36
+ * @param purl {PackageURL}
37
+ * @return component
38
+ */
39
+ purlToComponent(purl: PackageURL): {
40
+ "bom-ref": string;
41
+ name: any;
42
+ purl: string;
43
+ type: any;
44
+ version: any;
45
+ scope: any;
46
+ };
47
+ /** This method gets a component object, and a string name, and checks if the name is a substring of the component' purl.
48
+ * @param {} component to search in its dependencies
49
+ * @param {String} name to be checked.
50
+ *
51
+ * @return {boolean}
52
+ */
53
+ checkIfPackageInsideDependsOnList(component: any, name: string): boolean;
54
+ /** Removes the root component from the sbom
55
+ */
56
+ removeRootComponent(): void;
57
+ #private;
58
+ }
59
+ import CycloneDxSbom from "./cyclone_dx_sbom.js";
@@ -0,0 +1,84 @@
1
+ import CycloneDxSbom from "./cyclone_dx_sbom.js";
2
+ export default class Sbom {
3
+ sbomModel;
4
+ #startTime;
5
+ #endTime;
6
+ constructor() {
7
+ if (process.env["TRUSTIFY_DA_DEBUG"] === "true") {
8
+ this.#startTime = new Date();
9
+ console.log("Starting time to create sbom = " + this.#startTime);
10
+ }
11
+ this.sbomModel = new CycloneDxSbom();
12
+ }
13
+ /**
14
+ * @param {PackageURL} root - add main/root component for sbom
15
+ * @return Sbom
16
+ */
17
+ addRoot(root) {
18
+ return this.sbomModel.addRoot(root);
19
+ }
20
+ /**
21
+ * @return {{{"bom-ref": string, name, purl: string, type, version}}} root component of sbom.
22
+ */
23
+ getRoot() {
24
+ return this.sbomModel.getRoot();
25
+ }
26
+ /**
27
+ * This method gets an array of dependencies to be ignored, and remove all of them from sbom
28
+ * @param {Array} dependencies to be removed from sbom
29
+ * @return {Sbom} without ignored dependencies
30
+ */
31
+ filterIgnoredDeps(deps) {
32
+ return this.sbomModel.filterIgnoredDeps(deps);
33
+ }
34
+ /**
35
+ * This method gets an array of dependencies with versions( purl string format) to be ignored, and remove all of them from CycloneDx Sbom
36
+ * @param {Array} dependencies to be removed from sbom
37
+ * @return {CycloneDxSbom} without ignored dependencies
38
+ */
39
+ filterIgnoredDepsIncludingVersion(deps) {
40
+ return this.sbomModel.filterIgnoredDepsIncludingVersion(deps);
41
+ }
42
+ /**
43
+ * @param {component} sourceRef current source Component ( Starting from root component by clients)
44
+ * @param {PackageURL} targetRef current dependency to add to Dependencies list of component sourceRef
45
+ * @return Sbom
46
+ */
47
+ addDependency(sourceRef, targetRef, scope) {
48
+ return this.sbomModel.addDependency(sourceRef, targetRef, scope);
49
+ }
50
+ /**
51
+ * @return String sbom json in a string format
52
+ */
53
+ getAsJsonString(opts = {}) {
54
+ if (process.env["TRUSTIFY_DA_DEBUG"] === "true") {
55
+ this.#endTime = new Date();
56
+ console.log("Ending time to create sbom = " + this.#endTime);
57
+ let time = (this.#endTime - this.#startTime) / 1000;
58
+ console.log("Total time in seconds to create sbom = " + time);
59
+ }
60
+ return this.sbomModel.getAsJsonString(opts);
61
+ }
62
+ /**
63
+ * This method gets a PackageUrl, and returns a Component of Sbom
64
+ * @param purl {PackageURL}
65
+ * @return component
66
+ */
67
+ purlToComponent(purl) {
68
+ return this.sbomModel.purlToComponent(purl);
69
+ }
70
+ /** This method gets a component object, and a string name, and checks if the name is a substring of the component' purl.
71
+ * @param {} component to search in its dependencies
72
+ * @param {String} name to be checked.
73
+ *
74
+ * @return {boolean}
75
+ */
76
+ checkIfPackageInsideDependsOnList(component, name) {
77
+ return this.sbomModel.checkIfPackageInsideDependsOnList(component, name);
78
+ }
79
+ /** Removes the root component from the sbom
80
+ */
81
+ removeRootComponent() {
82
+ return this.sbomModel.removeRootComponent();
83
+ }
84
+ }
@@ -0,0 +1,74 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="packageurl-js/src/package-url" />
3
+ /**
4
+ *
5
+ * @param {string} key to log its value from environment variables and from opts, if it exists
6
+ * @param {{}} [opts={}] different options of application, if key in it, log it.
7
+ * @param {string }defValue default value of key in case there is no option and environment variable values for key
8
+ */
9
+ export function logValueFromObjects(key: string, opts?: {} | undefined, defValue: string): void;
10
+ /**
11
+ * Utility function will return the value for key from the environment variables,
12
+ * if not present will return the value for key from the opts objects only if it's a string,
13
+ * if not present, or not string will return the default value supplied which default to null.
14
+ * @param {string} key the key to look for in the environment variables and the opts object
15
+ * @param {string|null} [def=null] the value to return if nothing else found
16
+ * @param {{}} [opts={}] the options object to look for the key in if not found in environment
17
+ * @returns {string|null} the value of the key found in the environment, options object, or the
18
+ * default supplied
19
+ */
20
+ export function getCustom(key: string, def?: string | null | undefined, opts?: {} | undefined): string | null;
21
+ /**
22
+ * Utility function for looking up custom variable for a binary path.
23
+ * Will look in the environment variables (1) or in opts (2) for a key with TRUSTIFY_DA_x_PATH, x is an
24
+ * uppercase version of passed name to look for. The name will also be returned if nothing else was
25
+ * found.
26
+ * @param name the binary name to look for, will be returned as value in nothing else found
27
+ * @param {{}} [opts={}] the options object to look for the key in if not found in environment
28
+ * @returns {string|null} the value of the key found in the environment, options object, or the
29
+ * original name supplied
30
+ */
31
+ export function getCustomPath(name: any, opts?: {} | undefined): string | null;
32
+ /**
33
+ * Utility function for determining whether wrappers for build tools such as gradlew/mvnw should be
34
+ * preferred over invoking the binary directly.
35
+ * @param {string} name - binary for which to search for its wrapper
36
+ * @param {{}} opts - the options object to look for the key in if not found in environment
37
+ * @returns {boolean} whether to prefer the wrapper if exists or not
38
+ */
39
+ export function getWrapperPreference(name: string, opts?: {}): boolean;
40
+ export function environmentVariableIsPopulated(envVariableName: any): boolean;
41
+ /**
42
+ * Utility function for handling spaces in paths on Windows
43
+ * @param {string} path - path to be checked if contains spaces
44
+ * @return {string} a path with all spaces escaped or manipulated so it will be able to be part
45
+ * of commands that will be invoked without errors in os' shell.
46
+ */
47
+ export function handleSpacesInPath(path: string): string;
48
+ /**
49
+ * Utility function for creating Purl String
50
+ * @param name the name of the artifact, can include a namespace(group) or not - namespace/artifactName.
51
+ * @param version the version of the artifact
52
+ * @returns {PackageURL|null} PackageUrl Object ready to be used in SBOM
53
+ */
54
+ export function toPurl(type: any, name: any, version: any): PackageURL | null;
55
+ /**
56
+ * Utility function for creating Purl Object from a Purl String
57
+ * @param strPurl the Purl String
58
+ * @returns {PackageURL|null} PackageUrl Object ready to be used in SBOM
59
+ */
60
+ export function toPurlFromString(strPurl: any): PackageURL | null;
61
+ /**
62
+ *
63
+ * @param {string} cwd - directory for which to find the root of the git repository.
64
+ */
65
+ export function getGitRootDir(cwd: string): string | undefined;
66
+ /** this method invokes command string in a process in a synchronous way.
67
+ * @param {string} bin - the command to be invoked
68
+ * @param {Array<string>} args - the args to pass to the binary
69
+ * @param {import('child_process').ExecFileOptionsWithStringEncoding} [opts={}]
70
+ * @returns {string}
71
+ */
72
+ export function invokeCommand(bin: string, args: Array<string>, opts?: import("child_process").ExecFileOptionsWithStringEncoding | undefined): string;
73
+ export const RegexNotToBeLogged: RegExp;
74
+ import { PackageURL } from "packageurl-js";
@@ -0,0 +1,159 @@
1
+ import { execFileSync } from "child_process";
2
+ import { EOL } from "os";
3
+ import { PackageURL } from "packageurl-js";
4
+ export const RegexNotToBeLogged = /TRUSTIFY_DA_.*_TOKEN|ex-.*-token/;
5
+ /**
6
+ *
7
+ * @param {string} key to log its value from environment variables and from opts, if it exists
8
+ * @param {{}} [opts={}] different options of application, if key in it, log it.
9
+ * @param {string }defValue default value of key in case there is no option and environment variable values for key
10
+ */
11
+ export function logValueFromObjects(key, opts, defValue) {
12
+ if (key in opts) {
13
+ console.log(`value of option with key ${key} = ${opts[key]} ${EOL}`);
14
+ }
15
+ else {
16
+ console.log(`key ${key} doesn't exists on opts object ${EOL}`);
17
+ }
18
+ if (key in process.env) {
19
+ console.log(`value of environment variable ${key} = ${process.env[key]} ${EOL}`);
20
+ }
21
+ else {
22
+ console.log(`environment variable ${key} doesn't exists ${EOL}`);
23
+ }
24
+ console.log(`default value for ${key} = ${defValue} ${EOL}`);
25
+ }
26
+ /**
27
+ * Utility function will return the value for key from the environment variables,
28
+ * if not present will return the value for key from the opts objects only if it's a string,
29
+ * if not present, or not string will return the default value supplied which default to null.
30
+ * @param {string} key the key to look for in the environment variables and the opts object
31
+ * @param {string|null} [def=null] the value to return if nothing else found
32
+ * @param {{}} [opts={}] the options object to look for the key in if not found in environment
33
+ * @returns {string|null} the value of the key found in the environment, options object, or the
34
+ * default supplied
35
+ */
36
+ export function getCustom(key, def = null, opts = {}) {
37
+ if (process.env["TRUSTIFY_DA_DEBUG"] === "true" && !key.match(RegexNotToBeLogged)) {
38
+ logValueFromObjects(key, opts, def);
39
+ }
40
+ return key in process.env ? process.env[key] : key in opts && typeof opts[key] === 'string' ? opts[key] : def;
41
+ }
42
+ /**
43
+ * Utility function for looking up custom variable for a binary path.
44
+ * Will look in the environment variables (1) or in opts (2) for a key with TRUSTIFY_DA_x_PATH, x is an
45
+ * uppercase version of passed name to look for. The name will also be returned if nothing else was
46
+ * found.
47
+ * @param name the binary name to look for, will be returned as value in nothing else found
48
+ * @param {{}} [opts={}] the options object to look for the key in if not found in environment
49
+ * @returns {string|null} the value of the key found in the environment, options object, or the
50
+ * original name supplied
51
+ */
52
+ export function getCustomPath(name, opts = {}) {
53
+ return getCustom(`TRUSTIFY_DA_${name.toUpperCase()}_PATH`, name, opts);
54
+ }
55
+ /**
56
+ * Utility function for determining whether wrappers for build tools such as gradlew/mvnw should be
57
+ * preferred over invoking the binary directly.
58
+ * @param {string} name - binary for which to search for its wrapper
59
+ * @param {{}} opts - the options object to look for the key in if not found in environment
60
+ * @returns {boolean} whether to prefer the wrapper if exists or not
61
+ */
62
+ export function getWrapperPreference(name, opts = {}) {
63
+ return getCustom(`TRUSTIFY_DA_PREFER_${name.toUpperCase()}W`, 'true', opts) === 'true';
64
+ }
65
+ export function environmentVariableIsPopulated(envVariableName) {
66
+ return envVariableName in process.env && process.env[envVariableName].trim() !== "";
67
+ }
68
+ /**
69
+ * Utility function for handling spaces in paths on Windows
70
+ * @param {string} path - path to be checked if contains spaces
71
+ * @return {string} a path with all spaces escaped or manipulated so it will be able to be part
72
+ * of commands that will be invoked without errors in os' shell.
73
+ */
74
+ export function handleSpacesInPath(path) {
75
+ let transformedPath = path;
76
+ // if operating system is windows
77
+ if (hasSpaces(path)) {
78
+ transformedPath = `"${path}"`;
79
+ }
80
+ return transformedPath;
81
+ }
82
+ /**
83
+ *
84
+ * @param {string} path the path to check if contains spaces
85
+ * @return {boolean} returns true if path contains spaces
86
+ * @private
87
+ */
88
+ function hasSpaces(path) {
89
+ return path.trim().includes(" ");
90
+ }
91
+ /**
92
+ * Utility function for creating Purl String
93
+ * @param name the name of the artifact, can include a namespace(group) or not - namespace/artifactName.
94
+ * @param version the version of the artifact
95
+ * @returns {PackageURL|null} PackageUrl Object ready to be used in SBOM
96
+ */
97
+ export function toPurl(type, name, version) {
98
+ let parts = name.split("/");
99
+ var purlNs, purlName;
100
+ if (parts.length === 2) {
101
+ purlNs = parts[0];
102
+ purlName = parts[1];
103
+ }
104
+ else {
105
+ purlName = parts[0];
106
+ }
107
+ return new PackageURL(type, purlNs, purlName, version, undefined, undefined);
108
+ }
109
+ /**
110
+ * Utility function for creating Purl Object from a Purl String
111
+ * @param strPurl the Purl String
112
+ * @returns {PackageURL|null} PackageUrl Object ready to be used in SBOM
113
+ */
114
+ export function toPurlFromString(strPurl) {
115
+ return PackageURL.fromString(strPurl);
116
+ }
117
+ /**
118
+ *
119
+ * @param {string} cwd - directory for which to find the root of the git repository.
120
+ */
121
+ export function getGitRootDir(cwd) {
122
+ try {
123
+ const root = invokeCommand('git', ['rev-parse', '--show-toplevel'], { cwd: cwd });
124
+ return root.toString().trim();
125
+ }
126
+ catch (error) {
127
+ return undefined;
128
+ }
129
+ }
130
+ /** this method invokes command string in a process in a synchronous way.
131
+ * @param {string} bin - the command to be invoked
132
+ * @param {Array<string>} args - the args to pass to the binary
133
+ * @param {import('child_process').ExecFileOptionsWithStringEncoding} [opts={}]
134
+ * @returns {string}
135
+ */
136
+ export function invokeCommand(bin, args, opts = {}) {
137
+ // .bat and .cmd files can't be executed in windows with execFileSync without {shell: true}, so we
138
+ // special case them here to keep the amount of escaping we need to do to a minimum.
139
+ // https://nodejs.org/docs/latest-v20.x/api/child_process.html#spawning-bat-and-cmd-files-on-windows
140
+ // https://github.com/nodejs/node/issues/52681#issuecomment-2076426887
141
+ if (process.platform === 'win32') {
142
+ opts = { ...opts, shell: true };
143
+ args = args.map(arg => handleSpacesInPath(arg));
144
+ bin = handleSpacesInPath(bin);
145
+ }
146
+ opts = {
147
+ ...opts,
148
+ env: {
149
+ ...process.env,
150
+ PATH: process.env.PATH
151
+ }
152
+ };
153
+ // Add maxBuffer option to handle large outputs
154
+ opts = {
155
+ ...opts,
156
+ maxBuffer: 10 * 1024 * 1024 // 10MB buffer
157
+ };
158
+ return execFileSync(bin, args, { ...{ stdio: 'pipe', encoding: 'utf-8' }, ...opts });
159
+ }