diff --git a/apiserver/src/main/java/org/dependencytrack/policy/vulnerability/SyncVulnPolicyBundleActivity.java b/apiserver/src/main/java/org/dependencytrack/policy/vulnerability/SyncVulnPolicyBundleActivity.java index dd1a4f41cc..50996b7a47 100644 --- a/apiserver/src/main/java/org/dependencytrack/policy/vulnerability/SyncVulnPolicyBundleActivity.java +++ b/apiserver/src/main/java/org/dependencytrack/policy/vulnerability/SyncVulnPolicyBundleActivity.java @@ -259,7 +259,12 @@ private List parseAndValidatePolicies(BundleFile bundleFile final var entries = zipFile.entries(); while (entries.hasMoreElements()) { final ZipEntry zipEntry = entries.nextElement(); - if (!POLICY_FILE_NAME_PATTERN.matcher(zipEntry.getName()).matches()) { + if (zipEntry.isDirectory()) { + continue; + } + + final String fileName = Path.of(zipEntry.getName()).getFileName().toString(); + if (!POLICY_FILE_NAME_PATTERN.matcher(fileName).matches()) { LOGGER.debug("Skipping file '{}': Unexpected file name pattern", zipEntry.getName()); continue; } diff --git a/apiserver/src/test/java/org/dependencytrack/policy/vulnerability/SyncVulnPolicyBundleActivityTest.java b/apiserver/src/test/java/org/dependencytrack/policy/vulnerability/SyncVulnPolicyBundleActivityTest.java index 71a5f72865..c3aac9e54c 100644 --- a/apiserver/src/test/java/org/dependencytrack/policy/vulnerability/SyncVulnPolicyBundleActivityTest.java +++ b/apiserver/src/test/java/org/dependencytrack/policy/vulnerability/SyncVulnPolicyBundleActivityTest.java @@ -455,6 +455,34 @@ void shouldPreferBasicAuthOverBearerToken() throws Exception { .withHeader("Authorization", WireMock.equalTo("Basic dXNlcjpwYXNz"))); } + @Test + void shouldProcessPoliciesInSubdirectories() throws Exception { + final UUID bundleUuid = UUID.randomUUID(); + final Path bundlePath = Files.createTempFile(tempDir, "test-bundle-", ".zip"); + try (final var fos = Files.newOutputStream(bundlePath); + final var zos = new java.util.zip.ZipOutputStream(fos)) { + zos.putNextEntry(new java.util.zip.ZipEntry("my-bundle/policy-0.yaml")); + zos.write(VALID_POLICY.getBytes(java.nio.charset.StandardCharsets.UTF_8)); + } + + wireMock.stubFor(WireMock.get("/bundle.zip") + .willReturn(WireMock.aResponse() + .withStatus(200) + .withBody(Files.readAllBytes(bundlePath)))); + + final var activity = createActivity(wireMock.baseUrl() + "/bundle.zip"); + activity.execute(mock(ActivityContext.class), createActivityArg(bundleUuid)); + + final VulnPolicyBundleRow bundle = withJdbiHandle( + handle -> handle.attach(VulnerabilityPolicyDao.class).getBundleByUuid(bundleUuid)); + assertThat(bundle).isNotNull(); + + final List policies = withJdbiHandle( + handle -> handle.attach(VulnerabilityPolicyDao.class).getAllByBundleId(bundle.id())); + assertThat(policies).singleElement().satisfies(policy -> + assertThat(policy.name()).isEqualTo("Valid")); + } + private static SyncVulnPolicyBundleActivity createActivity(String bundleUrl) { final Config config = new SmallRyeConfigBuilder() .withDefaultValue("dt.vulnerability.policy.bundle.url", bundleUrl)