Repository navigation
Show Gradle impact paths only through the modules that resolve a dependency (XRAY-100231) #532
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鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
4d67d6c
Build Gradle impact paths per module
Jordanh1996 b5175bf
Add the Gradle multi-module impact-path test fixture
Jordanh1996 d8ce1e3
Guarantee an impact tree for every vulnerable dependency
Jordanh1996 d9ba43f
Address final review of the per-module impact paths
Jordanh1996 450261a
Drop the fallback log line
Jordanh1996 ab70b0d
Make the module impact-path unit tests cover the per-module walk
Jordanh1996 5d405d5
Use ide-plugins-common 2.5.0
Jordanh1996 df39064
Put the plugin's Jackson ahead of the IDE's on the test classpath
Jordanh1996 0ac1238
Reorder the test classpath at configuration time
Jordanh1996 a38518e
Trim doc comments to what each declaration does
Jordanh1996 32ee34f
Build the impact trees in ImpactTreeBuilder
Jordanh1996 53eb4d0
Remove the test classpath reorder and the unneeded Jackson bump
Jordanh1996 47493ee
Drop the module-membership check, which getOrDefault already covers
Jordanh1996 c7e4fa3
Document the direct-path fallback
Jordanh1996 accc8e8
Say why the direct-path fallback exists
Jordanh1996 f0c19b5
Name the crash the direct-path fallback prevents
Jordanh1996 084059e
Call the direct path a fallback
Jordanh1996 f0291ca
Load the plugin's Jackson ahead of the IDE's in tests
Jordanh1996 05f0072
Declare the Jackson version the plugin already resolves
Jordanh1996 9610190
Apply the test Jackson ordering to every test task
Jordanh1996 4cfd8db
Assert the full impact path through moda in the Gradle module test
Jordanh1996 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
86 changes: 86 additions & 0 deletions
86
src/test/java/com/jfrog/ide/idea/scan/GradleModuleImpactPathsTest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| package com.jfrog.ide.idea.scan; | ||
|
|
||
| import com.jfrog.ide.idea.scan.utils.ImpactTreeBuilder; | ||
|
|
||
| import com.jfrog.ide.common.deptree.DepTree; | ||
| import com.jfrog.ide.common.gradle.GradleTreeBuilder; | ||
| import com.jfrog.ide.common.nodes.DependencyNode; | ||
| import com.jfrog.ide.common.nodes.subentities.ImpactTreeNode; | ||
| import org.apache.commons.io.FileUtils; | ||
| import org.apache.commons.lang3.StringUtils; | ||
| import org.jfrog.build.api.util.NullLog; | ||
| import org.junit.Assert; | ||
| import org.junit.Test; | ||
|
|
||
| import java.net.URI; | ||
| import java.net.URL; | ||
| import java.nio.file.Files; | ||
| import java.nio.file.Path; | ||
| import java.nio.file.Paths; | ||
| import java.util.ArrayList; | ||
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| /** | ||
| * A Gradle project where 'moda' gets commons-lang3 through commons-text and 'modb' excludes it. | ||
| */ | ||
| public class GradleModuleImpactPathsTest { | ||
| private static final String EXCLUDED_BY_MODB_COMP_ID = "org.apache.commons:commons-lang3:3.11"; | ||
| private static final String PATH_THROUGH_MODA = "com.example:moda:1.0 -> org.apache.commons:commons-text:1.9 -> " + EXCLUDED_BY_MODB_COMP_ID; | ||
| private static final String GRADLE_DEP_TREE_CLASS = "com.jfrog.GradleDependencyNode"; | ||
|
|
||
| @Test | ||
| public void testImpactPathsNameOnlyTheModuleThatResolvesTheDependency() throws Exception { | ||
| Path projectDir = Files.createTempDirectory("moduleImpactPaths"); | ||
| try { | ||
| DepTree depTree = buildDependencyTree(projectDir); | ||
| Assert.assertTrue("commons-lang3 is expected in the dependency tree", depTree.nodes().containsKey(EXCLUDED_BY_MODB_COMP_ID)); | ||
|
|
||
| DependencyNode vulnerableDependency = new DependencyNode().componentId("gav://" + EXCLUDED_BY_MODB_COMP_ID); | ||
| ImpactTreeBuilder.populateImpactTrees(Map.of(EXCLUDED_BY_MODB_COMP_ID, vulnerableDependency), depTree); | ||
|
|
||
| Assert.assertNotNull("an impact path should have been built for commons-lang3", vulnerableDependency.getImpactTree()); | ||
| List<String> paths = new ArrayList<>(); | ||
| collectPaths(vulnerableDependency.getImpactTree().getRoot(), "", paths); | ||
| Assert.assertEquals("commons-lang3 is only reachable through moda: " + paths, 1, paths.size()); | ||
|
Jordanh1996 marked this conversation as resolved.
|
||
| Assert.assertTrue("the only impact path must go through moda and commons-text: " + paths, paths.get(0).endsWith(PATH_THROUGH_MODA)); | ||
| Assert.assertFalse("modb excludes commons-lang3: " + paths, paths.get(0).contains(":modb:")); | ||
| } finally { | ||
| FileUtils.deleteQuietly(projectDir.toFile()); | ||
| } | ||
| } | ||
|
|
||
| private void collectPaths(ImpactTreeNode node, String prefix, List<String> paths) { | ||
| String path = prefix.isEmpty() ? node.getName() : prefix + " -> " + node.getName(); | ||
| if (node.getChildren().isEmpty()) { | ||
| paths.add(path); | ||
| return; | ||
| } | ||
| node.getChildren().forEach(child -> collectPaths(child, path, paths)); | ||
| } | ||
|
|
||
| private DepTree buildDependencyTree(Path projectDir) throws Exception { | ||
| Path source = Paths.get("src", "test", "resources", "gradle", "moduleImpactPaths").toAbsolutePath().normalize(); | ||
| FileUtils.copyDirectory(source.toFile(), projectDir.toFile()); | ||
| Map<String, String> env = new HashMap<>(System.getenv()); | ||
| env.put("pluginLibDir", copyDepTreePlugin(projectDir).toString()); | ||
| GradleTreeBuilder treeBuilder = new GradleTreeBuilder(projectDir, projectDir.resolve("build.gradle").toString(), env, ""); | ||
| return treeBuilder.buildTree(new NullLog()); | ||
| } | ||
|
|
||
| private Path copyDepTreePlugin(Path projectDir) throws Exception { | ||
| Path libDir = Files.createDirectories(projectDir.resolve("gradle-dep-tree-lib")); | ||
| FileUtils.copyFileToDirectory(gradleDepTreeJar().toFile(), libDir.toFile()); | ||
| return libDir; | ||
| } | ||
|
|
||
| private Path gradleDepTreeJar() throws Exception { | ||
| String resource = "/" + GRADLE_DEP_TREE_CLASS.replace('.', '/') + ".class"; | ||
| URL location = Class.forName(GRADLE_DEP_TREE_CLASS).getResource(resource); | ||
| Assert.assertTrue("'" + GRADLE_DEP_TREE_CLASS + "' is expected to come from a jar, but was loaded from " + location, | ||
| StringUtils.startsWith(location.toString(), "jar:") && StringUtils.contains(location.toString(), "!")); | ||
| String jarUrl = StringUtils.substringBefore(StringUtils.removeStart(location.toString(), "jar:"), "!"); | ||
| return Path.of(URI.create(jarUrl)); | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.