Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Gradle] Resolve gradle module from npm package #1368

Merged
merged 4 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/repotests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -450,9 +450,10 @@ jobs:
- name: repotests expo
run: |
cd repotests/expo-test && npm ci && cd ../..
CDXGEN_DEBUG_MODE=debug GRADLE_ARGS_DEPENDENCIES="--configuration releaseRuntimeClasspath" bin/cdxgen.js -p -t gradle repostests/expo-test -o bomresults/bom-expo.json
CDXGEN_DEBUG_MODE=debug GRADLE_MULTI_THREADED=true GRADLE_ARGS_DEPENDENCIES="--configuration releaseRuntimeClasspath" GRADLE_SKIP_MODULES=root,expo-modules-core\$android-annotation,expo-modules-core\$android-annotation-processor bin/cdxgen.js -p -t gradle repostests/expo-test -o bomresults/bom-expo-multi.json
GRADLE_ARGS_DEPENDENCIES="--configuration releaseRuntimeClasspath" bin/cdxgen.js -p -t gradle repotests/expo-test -o bomresults/bom-expo.json
GRADLE_ARGS_DEPENDENCIES="--configuration releaseRuntimeClasspath" GRADLE_MULTI_THREADED=true GRADLE_SKIP_MODULES=root bin/cdxgen.js -p -t gradle repotests/expo-test -o bomresults/bom-expo-multi.json
custom-json-diff -i bomresults/bom-expo.json bomresults/bom-expo-multi.json -o bomresults/diff-expo
GRADLE_ARGS_DEPENDENCIES="--configuration releaseRuntimeClasspath" GRADLE_MULTI_THREADED=true GRADLE_SKIP_MODULES=root GRADLE_RESOLVE_FROM_NODE=true bin/cdxgen.js -p -t gradle repotests/expo-test -o bomresults/bom-expo-npm.json
shell: bash
- name: jenkins plugins
run: |
Expand Down
1 change: 1 addition & 0 deletions docs/ENV.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ The following environment variables are available to configure the bom generatio
| GRADLE_HOME | Specify gradle home |
| GRADLE_CMD | Set to override gradle command |
| GRADLE_DEPENDENCY_TASK | By default cdxgen use the task "dependencies" to collect packages. Set to override the task name. |
| GRADLE_RESOLVE_FROM_NODE | If some of your gradle modules are included from node (eg when using expo or react-native), set this to true to use the npm-packages as your dependencies. The big advantage of this, is that the generated purls will be of actually known components (eg in OSS Index) instead of generic names for the packages. |
| GRADLE_SKIP_MODULES | Comma-separated list of modules to skip during the "dependencies" task. This can be useful if you have modules that would fail the gradle build, eg when they do not have dependencies in the given configuration. Use "root" if the top most module should be skipped, use the name (without leading ":") for all others. |
| SBT_CACHE_DIR | Specify sbt cache directory. Useful for class name resolving |
| FETCH_LICENSE | Set this variable to `true` or `1` to fetch license information from the registry. npm and golang |
Expand Down
86 changes: 21 additions & 65 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
addEvidenceForImports,
addPlugin,
buildGradleCommandArguments,
buildObjectForGradleModule,
checksumFile,
cleanupPlugin,
collectGradleDependencies,
Expand Down Expand Up @@ -1627,21 +1628,10 @@ export async function createJavaBom(path, options) {
const allProjectsStr = retMap.projects || [];
const rootProject = retMap.rootProject;
if (rootProject) {
parentComponent = {
name: rootProject,
type: "application",
...retMap.metadata,
};
const parentPurl = new PackageURL(
"maven",
parentComponent.group || "",
parentComponent.name,
parentComponent.version,
{ type: "jar" },
null,
).toString();
parentComponent["purl"] = parentPurl;
parentComponent["bom-ref"] = decodeURIComponent(parentPurl);
parentComponent = await buildObjectForGradleModule(
rootProject,
retMap.metadata,
);
gradleModules.set(rootProject, parentComponent);
}
// Get the sub-project properties and set the root dependencies
Expand Down Expand Up @@ -1674,31 +1664,14 @@ export async function createJavaBom(path, options) {
const rootSubProject = retMap.rootProject;
if (rootSubProject) {
const rspName = rootSubProject.replace(/^:/, "");
const rootSubProjectObj = {
name: rspName,
type: "application",
qualifiers: { type: "jar" },
...retMap.metadata,
};
const rootSubProjectPurl = new PackageURL(
"maven",
rootSubProjectObj.group?.length
? rootSubProjectObj.group
: parentComponent.group,
rootSubProjectObj.name,
retMap.metadata.version && retMap.metadata.version !== "latest"
? retMap.metadata.version
: parentComponent.version,
rootSubProjectObj.qualifiers,
null,
).toString();
rootSubProjectObj["purl"] = rootSubProjectPurl;
const rootSubProjectBomRef = decodeURIComponent(rootSubProjectPurl);
rootSubProjectObj["bom-ref"] = rootSubProjectBomRef;
if (!allProjectsAddedPurls.includes(rootSubProjectPurl)) {
const rootSubProjectObj = await buildObjectForGradleModule(
rspName,
retMap.metadata,
);
if (!allProjectsAddedPurls.includes(rootSubProjectObj["purl"])) {
allProjects.push(rootSubProjectObj);
rootDependsOn.push(rootSubProjectBomRef);
allProjectsAddedPurls.push(rootSubProjectPurl);
rootDependsOn.push(rootSubProjectObj["bom-ref"]);
allProjectsAddedPurls.push(rootSubProjectObj["purl"]);
}
gradleModules.set(rspName, rootSubProjectObj);
}
Expand All @@ -1709,31 +1682,14 @@ export async function createJavaBom(path, options) {
const rootSubProject = retMap.rootProject;
if (rootSubProject) {
const rspName = rootSubProject.replace(/^:/, "");
const rootSubProjectObj = {
name: rspName,
type: "application",
qualifiers: { type: "jar" },
...retMap.metadata,
};
const rootSubProjectPurl = new PackageURL(
"maven",
rootSubProjectObj.group?.length
? rootSubProjectObj.group
: parentComponent.group,
rootSubProjectObj.name,
retMap.metadata.version && retMap.metadata.version !== "latest"
? retMap.metadata.version
: parentComponent.version,
rootSubProjectObj.qualifiers,
null,
).toString();
rootSubProjectObj["purl"] = rootSubProjectPurl;
const rootSubProjectBomRef = decodeURIComponent(rootSubProjectPurl);
rootSubProjectObj["bom-ref"] = rootSubProjectBomRef;
if (!allProjectsAddedPurls.includes(rootSubProjectPurl)) {
const rootSubProjectObj = await buildObjectForGradleModule(
rspName,
retMap.metadata,
);
if (!allProjectsAddedPurls.includes(rootSubProjectObj["purl"])) {
allProjects.push(rootSubProjectObj);
rootDependsOn.push(rootSubProjectBomRef);
allProjectsAddedPurls.push(rootSubProjectPurl);
rootDependsOn.push(rootSubProjectObj["bom-ref"]);
allProjectsAddedPurls.push(rootSubProjectObj["purl"]);
}
gradleModules.set(rspName, rootSubProjectObj);
}
Expand Down Expand Up @@ -1813,7 +1769,7 @@ export async function createJavaBom(path, options) {
gradleDepTask,
]);
for (const sp of allProjects) {
const parsedList = parseGradleDep(
const parsedList = await parseGradleDep(
perProjectOutput.has(sp.name) ? perProjectOutput.get(sp.name) : "",
sp.name,
gradleModules,
Expand Down Expand Up @@ -1881,7 +1837,7 @@ export async function createJavaBom(path, options) {
const sstdout = sresult.stdout;
if (sstdout) {
const cmdOutput = Buffer.from(sstdout).toString();
const parsedList = parseGradleDep(
const parsedList = await parseGradleDep(
cmdOutput,
sp.name,
gradleModules,
Expand Down
107 changes: 60 additions & 47 deletions utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2491,7 +2491,7 @@ export function parseMavenTree(rawOutput, pomFile) {
* @param {map} gradleModules Cache with all gradle modules that have already been read
* @param {string} gradleRootPath Root path where Gradle is to be run when getting module information
*/
export function parseGradleDep(
export async function parseGradleDep(
rawOutput,
rootProjectName = "root",
gradleModules = new Map(),
Expand Down Expand Up @@ -2558,30 +2558,10 @@ export function parseGradleDep(
const rootSubProject = propMap.rootProject;
if (rootSubProject) {
const rspName = rootSubProject.replace(/^:/, "");
const rootSubProjectObj = {
name: rspName,
type: "application",
qualifiers: { type: "jar" },
...propMap.metadata,
};
const rootSubProjectPurl = new PackageURL(
"maven",
rootSubProjectObj.group?.length
? rootSubProjectObj.group
: rootProject.group,
rootSubProjectObj.name,
propMap.metadata.version &&
propMap.metadata.version !== "latest"
? propMap.metadata.version
: rootProject.version,
rootSubProjectObj.qualifiers,
null,
).toString();
rootSubProjectObj["purl"] = rootSubProjectPurl;
const rootSubProjectBomRef =
decodeURIComponent(rootSubProjectPurl);
rootSubProjectObj["bom-ref"] = rootSubProjectBomRef;
gradleModules.set(rspName, rootSubProjectObj);
gradleModules.set(
rspName,
await buildObjectForGradleModule(rspName, propMap.metadata),
);
}
}
}
Expand All @@ -2594,28 +2574,10 @@ export function parseGradleDep(
const rootSubProject = propMap.rootProject;
if (rootSubProject) {
const rspName = rootSubProject.replace(/^:/, "");
const rootSubProjectObj = {
name: rspName,
type: "application",
qualifiers: { type: "jar" },
...propMap.metadata,
};
const rootSubProjectPurl = new PackageURL(
"maven",
rootSubProjectObj.group?.length
? rootSubProjectObj.group
: rootProject.group,
rootSubProjectObj.name,
propMap.metadata.version && propMap.metadata.version !== "latest"
? propMap.metadata.version
: rootProject.version,
rootSubProjectObj.qualifiers,
null,
).toString();
rootSubProjectObj["purl"] = rootSubProjectPurl;
const rootSubProjectBomRef = decodeURIComponent(rootSubProjectPurl);
rootSubProjectObj["bom-ref"] = rootSubProjectBomRef;
gradleModules.set(moduleName, rootSubProjectObj);
gradleModules.set(
rspName,
await buildObjectForGradleModule(rspName, propMap.metadata),
);
}
}
if (gradleModules.has(moduleName)) {
Expand Down Expand Up @@ -10053,6 +10015,57 @@ export function splitOutputByGradleProjects(rawOutput, relevantTasks) {
}
return outputSplitBySubprojects;
}

/**
* Method that handles object creation for gradle modules.
*
* @param {string} name The simple name of the module
* @param {object} metadata Object with all other parsed data for the gradle module
* @returns {object} An object representing the gradle module in SBOM-format
*/
export async function buildObjectForGradleModule(name, metadata) {
let component;
if (["true", "1"].includes(process.env.GRADLE_RESOLVE_FROM_NODE)) {
let tmpDir = metadata.properties.find(
({ name }) => name === "projectDir",
).value;
if (tmpDir.indexOf("node_modules") !== -1) {
do {
const npmPackages = await parsePkgJson(join(tmpDir, "package.json"));
if (npmPackages.length === 1) {
component = npmPackages[0];
component.type = "library";
component.properties = component.properties.concat(
metadata.properties,
);
component.properties.push({ name: "GradleProjectName", value: name });
tmpDir = undefined;
} else {
tmpDir = tmpDir.substring(0, tmpDir.lastIndexOf("/"));
}
} while (tmpDir && tmpDir.indexOf("node_modules") !== -1);
}
}
if (!component) {
component = {
name: name,
type: "application",
...metadata,
};
const purl = new PackageURL(
"maven",
component.group,
component.name,
component.version,
{ type: "jar" },
null,
).toString();
component["purl"] = purl;
component["bom-ref"] = decodeURIComponent(purl);
}
return component;
}

/**
* Method to return the maven command to use.
*
Expand Down
Loading
Loading