From 40734fd326a956fe623921b2d26d016b3c381df3 Mon Sep 17 00:00:00 2001 From: Seb Dangerfield <1449113+sedan07@users.noreply.github.com> Date: Fri, 3 Jan 2025 11:16:15 +0000 Subject: [PATCH] Fix onlyOutdated ungrouped component filtering Fixes: #4510 Signed-off-by: Seb Dangerfield <1449113+sedan07@users.noreply.github.com> --- .../persistence/ComponentQueryManager.java | 2 +- .../resources/v1/ComponentResourceTest.java | 78 +++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/dependencytrack/persistence/ComponentQueryManager.java b/src/main/java/org/dependencytrack/persistence/ComponentQueryManager.java index fa700e321e..9d5b542a4e 100644 --- a/src/main/java/org/dependencytrack/persistence/ComponentQueryManager.java +++ b/src/main/java/org/dependencytrack/persistence/ComponentQueryManager.java @@ -166,7 +166,7 @@ public PaginatedResult getComponents(final Project project, final boolean includ " && !("+ " SELECT FROM org.dependencytrack.model.RepositoryMetaComponent m " + " WHERE m.name == this.name " + - " && m.namespace == this.group " + + " && (m.namespace == this.group || (m.namespace == null && this.group == null)) " + " && m.latestVersion != this.version " + " && this.purl.matches('pkg:' + m.repositoryType.toString().toLowerCase() + '/%') " + " ).isEmpty()"; diff --git a/src/test/java/org/dependencytrack/resources/v1/ComponentResourceTest.java b/src/test/java/org/dependencytrack/resources/v1/ComponentResourceTest.java index ab795d3fa9..7817b84f37 100644 --- a/src/test/java/org/dependencytrack/resources/v1/ComponentResourceTest.java +++ b/src/test/java/org/dependencytrack/resources/v1/ComponentResourceTest.java @@ -121,6 +121,50 @@ private Project prepareProject() throws MalformedPackageURLException { return project; } + /** + * Generate a project with ungrouped dependencies + * @return A project with 10 dependencies: + * @throws MalformedPackageURLException + */ + private Project prepareProjectUngroupedComponents() throws MalformedPackageURLException { + final Project project = qm.createProject("Ungrouped Application", null, null, null, null, null, true, false); + final List directDepencencies = new ArrayList<>(); + // Generate 10 dependencies + for (int i = 0; i < 10; i++) { + Component component = new Component(); + component.setProject(project); + component.setName("component-name-"+i); + component.setVersion(String.valueOf(i)+".0"); + component.setPurl(new PackageURL(RepositoryType.PYPI.toString(), null, "component-name-"+i , String.valueOf(i)+".0", null, null)); + component = qm.createComponent(component, false); + // direct depencencies + if (i < 4) { + // 4 direct depencencies, 6 transitive depencencies + directDepencencies.add("{\"uuid\":\"" + component.getUuid() + "\"}"); + } + // Recent & Outdated + if ((i < 7)) { + final var metaComponent = new RepositoryMetaComponent(); + metaComponent.setRepositoryType(RepositoryType.PYPI); + metaComponent.setName("component-name-"+i); + metaComponent.setLatestVersion(String.valueOf(i+1)+".0"); + metaComponent.setLastCheck(new Date()); + qm.persist(metaComponent); + } else { + final var metaComponent = new RepositoryMetaComponent(); + metaComponent.setRepositoryType(RepositoryType.PYPI); + metaComponent.setName("component-name-"+i); + metaComponent.setLatestVersion(String.valueOf(i)+".0"); + metaComponent.setLastCheck(new Date()); + qm.persist(metaComponent); + } + } + project.setDirectDependencies("[" + String.join(",", directDepencencies.toArray(new String[0])) + "]"); + return project; + } + @Test public void getOutdatedComponentsTest() throws MalformedPackageURLException { final Project project = prepareProject(); @@ -138,6 +182,23 @@ public void getOutdatedComponentsTest() throws MalformedPackageURLException { assertThat(json).hasSize(100); // Default page size is 100 } + @Test + public void getUngroupedOutdatedComponentsTest() throws MalformedPackageURLException { + final Project project = prepareProjectUngroupedComponents(); + + final Response response = jersey.target(V1_COMPONENT + "/project/" + project.getUuid()) + .queryParam("onlyOutdated", true) + .queryParam("onlyDirect", false) + .request() + .header(X_API_KEY, apiKey) + .get(Response.class); + assertThat(response.getStatus()).isEqualTo(HttpStatus.SC_OK); + assertThat(response.getHeaderString(TOTAL_COUNT_HEADER)).isEqualTo("7"); // 7 outdated dependencies, direct and transitive + + final JsonArray json = parseJsonArray(response); + assertThat(json).hasSize(7); + } + @Test public void getOutdatedDirectComponentsTest() throws MalformedPackageURLException { final Project project = prepareProject(); @@ -155,6 +216,23 @@ public void getOutdatedDirectComponentsTest() throws MalformedPackageURLExceptio assertThat(json).hasSize(75); } + @Test + public void getUngroupedOutdatedDirectComponentsTest() throws MalformedPackageURLException { + final Project project = prepareProjectUngroupedComponents(); + + final Response response = jersey.target(V1_COMPONENT + "/project/" + project.getUuid()) + .queryParam("onlyOutdated", true) + .queryParam("onlyDirect", true) + .request() + .header(X_API_KEY, apiKey) + .get(Response.class); + assertThat(response.getStatus()).isEqualTo(HttpStatus.SC_OK); + assertThat(response.getHeaderString(TOTAL_COUNT_HEADER)).isEqualTo("3"); // 3 outdated dependencies + + final JsonArray json = parseJsonArray(response); + assertThat(json).hasSize(3); + } + @Test public void getAllComponentsTest() throws MalformedPackageURLException { final Project project = prepareProject();