From 3f331a21529ac2ffbf73cfe198bd66c07003e9ea Mon Sep 17 00:00:00 2001 From: Svata Dedic Date: Wed, 25 Sep 2024 09:03:40 +0200 Subject: [PATCH 1/2] Support for !!strict modifier for versions --- .../modules/gradle/java/queries/DependencyText.java | 10 +++++++++- .../gradle/java/queries/TextDependencyScanner.java | 4 ++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/java/gradle.java/src/org/netbeans/modules/gradle/java/queries/DependencyText.java b/java/gradle.java/src/org/netbeans/modules/gradle/java/queries/DependencyText.java index 6c18d5c2082c..5d8b172f14a6 100644 --- a/java/gradle.java/src/org/netbeans/modules/gradle/java/queries/DependencyText.java +++ b/java/gradle.java/src/org/netbeans/modules/gradle/java/queries/DependencyText.java @@ -110,6 +110,14 @@ public String toString() { return sb.toString(); } + static String stripStrict(String s) { + if (!s.endsWith("!!")) { + return s; + } else { + return s.substring(0, s.length() - 2); + } + } + public String getContentsOrGav() { if (contents != null) { return contents; @@ -117,7 +125,7 @@ public String getContentsOrGav() { StringBuilder sb = new StringBuilder(); sb.append(group).append(':').append(name); if (version != null && !version.isEmpty()) { - sb.append(':').append(version); + sb.append(":").append(stripStrict(version)); } return sb.toString(); } diff --git a/java/gradle.java/src/org/netbeans/modules/gradle/java/queries/TextDependencyScanner.java b/java/gradle.java/src/org/netbeans/modules/gradle/java/queries/TextDependencyScanner.java index cab60320a249..199ff93d7c06 100644 --- a/java/gradle.java/src/org/netbeans/modules/gradle/java/queries/TextDependencyScanner.java +++ b/java/gradle.java/src/org/netbeans/modules/gradle/java/queries/TextDependencyScanner.java @@ -685,13 +685,13 @@ private DependencyText findDependency(Dependency d) { if (DependencyText.KEYWORD_PROJECT.equals(t.keyword) && t.contents.equals(projectName)) { return t; - } else if (t.keyword == null && t.getContentsOrGav().equals(gav) && scopeMatches(d, t)) { + } else if (t.keyword == null && DependencyText.stripStrict(t.getContentsOrGav()).equals(gav) && scopeMatches(d, t)) { return t; } } for (DependencyText t : dependencies) { - if (t.keyword == null && t.contents != null && t.contents.equals(groupAndName) && scopeMatches(d, t)) { + if (t.keyword == null && t.contents != null && DependencyText.stripStrict(t.contents).equals(groupAndName) && scopeMatches(d, t)) { return t; } } From aece75309744cef3628c551036b37a03b74ffdac Mon Sep 17 00:00:00 2001 From: Svata Dedic Date: Wed, 25 Sep 2024 09:04:38 +0200 Subject: [PATCH 2/2] Cache each project in the knowledgebase separately --- .../modules/cloud/oracle/adm/AuditCache.java | 21 +++++++-- .../cloud/oracle/adm/VulnerabilityWorker.java | 46 ++++++++++++++++--- 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/adm/AuditCache.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/adm/AuditCache.java index 6883ad20e95c..99e5b8673d68 100644 --- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/adm/AuditCache.java +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/adm/AuditCache.java @@ -40,6 +40,9 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectUtils; +import org.openide.filesystems.FileUtil; /** * Caches audit results in NB cache folder. Uses Jackson to serialize the audit summary + @@ -154,10 +157,18 @@ public void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider } } } - public VulnerabilityReport cacheAuditResults(VulnerabilityReport report) throws IOException { + private static String key(Project project, String knowledgeBaseId) { + Project p2 = ProjectUtils.rootOf(project); + String k = "knowledge.segment." + knowledgeBaseId; + if (p2 != project) { + k = k + "." + FileUtil.getRelativePath(p2.getProjectDirectory(), project.getProjectDirectory()).replace('/', '.'); + } + return k; + } + + public VulnerabilityReport cacheAuditResults(Project project, VulnerabilityReport report) throws IOException { Properties segments = loadSegments(); - String k = "knowledge.segment." + report.summary.getKnowledgeBaseId(); - + String k = key(project, report.summary.getKnowledgeBaseId()); File cacheDir = Places.getCacheSubdirectory(CACHE_SUBDIR); Path segPath = cacheDir.toPath().resolve(SEGMENTS_FILE); boolean writeSegment = !Files.exists(segPath); @@ -214,9 +225,9 @@ public VulnerabilityReport cacheAuditResults(VulnerabilityReport report) throws * @param knowledgeBaseId * @return */ - public VulnerabilityReport loadAudit(String knowledgeBaseId) throws IOException { + public VulnerabilityReport loadAudit(Project project, String knowledgeBaseId) throws IOException { Properties segments = loadSegments(); - String k = "knowledge.segment." + knowledgeBaseId; + String k = key(project, knowledgeBaseId); String segName = segments.getProperty(k); if (segName == null) { diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/adm/VulnerabilityWorker.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/adm/VulnerabilityWorker.java index 665015a64572..b3de545fca89 100644 --- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/adm/VulnerabilityWorker.java +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/adm/VulnerabilityWorker.java @@ -70,6 +70,7 @@ import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.NbBundle; @@ -127,6 +128,8 @@ public class VulnerabilityWorker implements ErrorProvider{ // PENDING: should be customizable from project configuration somehow. private static final String GOV_DETAIL_URL = "https://nvd.nist.gov/vuln/detail/"; + private static final String TAG_SUBPROJECT_PATH = "netbeans_cloud_oracle_SubProjectPath"; // NOI18N + // @GuardedBy(self) private static final HashMap cache = new HashMap<>(); @@ -558,6 +561,12 @@ public List getDiagnosticsForFile(FileObject file) { List result = new ArrayList<>(); SourceLocation containerLocation = null; + if (!sourceMapping.files.contains(file)) { + return null; + } + if (dependencyResult.getProject().getProjectDirectory() != file.getParent()) { + return null; + } for (VulnerabilityItem item : this.itemIndex.values()) { boolean unreported = true; @@ -703,6 +712,15 @@ public AuditResult vulnerabilityAudit(Project project, AuditOptions auditOptions kbItem.refresh(); } } + + private static String findSubprojectPath(Project project) { + Project p2 = ProjectUtils.rootOf(project); + if (p2 == project) { + return ""; + } else { + return FileUtil.getRelativePath(p2.getProjectDirectory(), project.getProjectDirectory()).replace('/', '.'); + } + } private AuditResult doFindVulnerability(Project project, String compartmentId, String knowledgeBaseId, String projectDisplayName, AuditOptions auditOptions, ProgressHandle progressHandle, AtomicBoolean remoteCall) throws AuditException { @@ -714,16 +732,15 @@ private AuditResult doFindVulnerability(Project project, String compartmentId, S boolean auditDone = false; DependencyResult dr = null; - + String subprojectPath = findSubprojectPath(project); if (!auditOptions.isForceAuditExecution()) { if (!auditOptions.isDisableCache()) { try { - savedAudit = AuditCache.getInstance().loadAudit(knowledgeBaseId); + savedAudit = AuditCache.getInstance().loadAudit(project, knowledgeBaseId); } catch (IOException ex) { LOG.log(Level.WARNING, "Could not load cached audit data", ex); } } - if (savedAudit == null) { // attempt to find an active most recent audit: remoteCall.set(true); @@ -737,14 +754,30 @@ private AuditResult doFindVulnerability(Project project, String compartmentId, S .knowledgeBaseId(knowledgeBaseId) .lifecycleState(LifecycleState.Active) .sortBy(ListVulnerabilityAuditsRequest.SortBy.TimeCreated) + .limit(200) .sortOrder(SortOrder.Desc).build(); ListVulnerabilityAuditsResponse response = admClient.listVulnerabilityAudits(request); if (!response.getVulnerabilityAuditCollection().getItems().isEmpty()) { - VulnerabilityAuditSummary summary = response.getVulnerabilityAuditCollection().getItems().get(0); + VulnerabilityAuditSummary found = null; + D: while (true) { + for (VulnerabilityAuditSummary summary : response.getVulnerabilityAuditCollection().getItems()) { + String p = summary.getFreeformTags().get(TAG_SUBPROJECT_PATH); + if (subprojectPath.equals(p)) { + found = summary; + break D; + } + } + if (response.getOpcNextPage() == null) { + break; + } + request = ListVulnerabilityAuditsRequest + .builder().copy(request).page(response.getOpcNextPage()).build(); + response = admClient.listVulnerabilityAudits(request); + } progressHandle.progress(Bundle.MSG_AuditCollectDependencies()); dr = ProjectDependencies.findDependencies(project, ProjectDependencies.newQuery(Scopes.RUNTIME)); convert(dr.getRoot(), new HashMap<>(), result); - cacheItem = fetchVulnerabilityItems(project, admClient, dr, summary, projectDisplayName); + cacheItem = fetchVulnerabilityItems(project, admClient, dr, found, projectDisplayName); savedAudit = new VulnerabilityReport(cacheItem.getAudit(), cacheItem.getVulnerabilities()); } } catch (BmcException ex) { @@ -780,6 +813,7 @@ private AuditResult doFindVulnerability(Project project, String compartmentId, S .buildType(VulnerabilityAudit.BuildType.Maven) .configuration(auditConfiguration) .applicationDependencies(result) + .freeformTags(Map.of(TAG_SUBPROJECT_PATH, subprojectPath)) .build(); progressHandle.progress(Bundle.MSG_ExecuteAudit()); CreateVulnerabilityAuditResponse response = admClient.createVulnerabilityAudit(CreateVulnerabilityAuditRequest @@ -977,7 +1011,7 @@ private CacheItem fetchVulnerabilityItems(Project project, ApplicationDependency report.setMappedVulnerabilities(mapped); try { - AuditCache.getInstance().cacheAuditResults(report); + AuditCache.getInstance().cacheAuditResults(project, report); } catch (IOException ex) { LOG.log(Level.WARNING, "Could not cache audit results for knowledgebase {0}, compartment {1}, project {2}", new Object[] { auditSummary.getKnowledgeBaseId(), auditSummary.getCompartmentId(),