| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.netbeans.modules.cloud.oracle.adm; |
| |
| import com.oracle.bmc.adm.ApplicationDependencyManagementClient; |
| import com.oracle.bmc.adm.model.ApplicationDependency; |
| import com.oracle.bmc.adm.model.ApplicationDependencyVulnerabilitySummary; |
| import com.oracle.bmc.adm.model.CreateVulnerabilityAuditDetails; |
| import com.oracle.bmc.adm.model.SortOrder; |
| import com.oracle.bmc.adm.model.Vulnerability; |
| import com.oracle.bmc.adm.model.VulnerabilityAudit; |
| import com.oracle.bmc.adm.model.VulnerabilityAudit.LifecycleState; |
| import com.oracle.bmc.adm.model.VulnerabilityAuditConfiguration; |
| import com.oracle.bmc.adm.model.VulnerabilityAuditSummary; |
| import com.oracle.bmc.adm.requests.CreateVulnerabilityAuditRequest; |
| import com.oracle.bmc.adm.requests.ListApplicationDependencyVulnerabilitiesRequest; |
| import com.oracle.bmc.adm.requests.ListVulnerabilityAuditsRequest; |
| import com.oracle.bmc.adm.responses.CreateVulnerabilityAuditResponse; |
| import com.oracle.bmc.adm.responses.ListApplicationDependencyVulnerabilitiesResponse; |
| import com.oracle.bmc.adm.responses.ListVulnerabilityAuditsResponse; |
| import com.oracle.bmc.model.BmcException; |
| import java.io.IOException; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| import javax.swing.event.ChangeEvent; |
| import javax.swing.event.ChangeListener; |
| import org.netbeans.api.editor.mimelookup.MimeRegistration; |
| import org.netbeans.api.editor.mimelookup.MimeRegistrations; |
| import org.netbeans.api.lsp.Diagnostic; |
| import org.netbeans.api.progress.ProgressHandle; |
| import org.netbeans.api.project.Project; |
| import org.netbeans.api.project.ProjectUtils; |
| import org.netbeans.modules.cloud.oracle.OCIManager; |
| import org.netbeans.modules.project.dependency.ArtifactSpec; |
| import org.netbeans.modules.project.dependency.Dependency; |
| import org.netbeans.modules.project.dependency.DependencyResult; |
| import org.netbeans.modules.project.dependency.ProjectDependencies; |
| import org.netbeans.modules.project.dependency.Scopes; |
| import org.netbeans.modules.project.dependency.SourceLocation; |
| import org.netbeans.spi.lsp.ErrorProvider; |
| import org.openide.DialogDisplayer; |
| import org.openide.NotifyDescriptor; |
| import org.openide.filesystems.FileObject; |
| import org.openide.util.Exceptions; |
| import org.openide.util.Lookup; |
| import org.openide.util.NbBundle; |
| import org.openide.util.RequestProcessor; |
| |
| /** |
| * |
| * @author Petr Pisl |
| */ |
| @NbBundle.Messages({ |
| "# {0} - project name", |
| "MSG_Audit_Pass=Vulnerability audit for project {0} is done.\nNo vulnerability was found.", |
| "# {0} - project name", |
| "MSG_Audit_Failed_One=Vulnerability audit for project {0} is done.\nOne vulnerability was found.\nThe vulnerability is listed in Problems window.", |
| "# {0} - project name", |
| "# {1} - number of vulnerabilities", |
| "MSG_Audit_Failed_More=Vulnerability audit for project {0} is done.\n{1} vulnerabilities were found.\nThe vulnerabilities are listed in Problems window.", |
| "# {0} - project name", |
| "MSG_CreatingAuditFailed=Creating Vulnerablity audit for project {0} failed.", |
| "# {0} - project name", |
| "MSG_ListingAuditFailed=Obtaining newly created vulnerablity audit for project {0} failed.", |
| "MSG_ListingVulnerabilitiesFailed=Obtaining vulnerabilities for newly created audit failed.", |
| "# {0} - project name", |
| "MSG_AuditIsRunning=Audit of {0} project is running ...", |
| "MSG_NotAvailable=Not available", |
| "MSG_Diagnostic=Vulnerability\n" |
| + " Cvss V2 Score: %s\n" |
| + " Cvss V3 Score: %s\n" |
| + " Caused by dependence: %s" |
| }) |
| |
| @MimeRegistrations({ |
| @MimeRegistration(mimeType = "text/x-maven-pom+xml", service = ErrorProvider.class), |
| @MimeRegistration(mimeType = "text/x-gradle+x-groovy", service = ErrorProvider.class) |
| }) |
| |
| public class VulnerabilityWorker implements ErrorProvider{ |
| private static final RequestProcessor SOURCE_REFRESH_PROCESSOR = new RequestProcessor(VulnerabilityWorker.class.getName()); |
| |
| private static final Logger LOG = Logger.getLogger(VulnerabilityWorker.class.getName()); |
| |
| // PENDING: should be customizable from project configuration somehow. |
| private static final String GOV_DETAIL_URL = "https://nvd.nist.gov/vuln/detail/"; |
| |
| // @GuardedBy(self) |
| private static final HashMap<Project, CacheItem> cache = new HashMap(); |
| |
| // @GuardedBy(class) |
| private static VulnerabilityWorker instance; |
| |
| /** |
| * Cached information + watcher over the project file data. Will watch for dependency change event, |
| * that is fired e.g. after project reload, and will REPLACE ITSELF in the cache + fire |
| * event that causes LSP to re-evaluate errors for the affected project file(s). |
| */ |
| static class CacheItem { |
| private final Project project; |
| private final DependencyResult dependencyResult; |
| private final VulnerabilityReport report; |
| |
| /** |
| * Maps GAV -> dependency. |
| */ |
| private Map<String, Dependency> dependencyMap; |
| |
| // @GuardedBy(this) |
| private ChangeListener depChange; |
| |
| // @GuardedBy(this) |
| private RequestProcessor.Task pendingRefresh; |
| |
| public CacheItem(Project project, DependencyResult dependency, VulnerabilityReport report) { |
| this.project = project; |
| this.dependencyResult = dependency; |
| this.report = report; |
| } |
| |
| public DependencyResult getDependency() { |
| return dependencyResult; |
| } |
| |
| public VulnerabilityAuditSummary getAudit() { |
| return report.summary; |
| } |
| |
| public List<ApplicationDependencyVulnerabilitySummary> getVulnerabilities() { |
| return report.items; |
| } |
| |
| public Map<String, Dependency> getDependencyMap() { |
| if (dependencyMap == null) { |
| dependencyMap = new HashMap(); |
| buildDependecyMap(dependencyResult.getRoot(), dependencyMap); |
| } |
| return dependencyMap; |
| } |
| |
| private void buildDependecyMap(Dependency dependency, Map<String, Dependency> result) { |
| String gav = createGAV(dependency.getArtifact()); |
| if (result.putIfAbsent(gav, dependency) == null) { |
| dependency.getChildren().forEach((childDependency) -> { |
| buildDependecyMap(childDependency, result); |
| }); |
| } |
| } |
| |
| public Set<FileObject> getProblematicFiles() { |
| if (getAudit().getIsSuccess()) { |
| return Collections.EMPTY_SET; |
| } |
| Set<FileObject> result = new HashSet(); |
| for (ApplicationDependencyVulnerabilitySummary v: getVulnerabilities()){ |
| List<Vulnerability> vulnerabilities = v.getVulnerabilities(); |
| if (!vulnerabilities.isEmpty()) { |
| Dependency dep = getDependencyMap().get(v.getGav()); |
| if (dep != null) { |
| try { |
| SourceLocation declarationRange = this.dependencyResult.getDeclarationRange(dep, null); |
| if (declarationRange == null) { |
| declarationRange = this.dependencyResult.getDeclarationRange(dep, DependencyResult.PART_CONTAINER); |
| } |
| if(declarationRange != null && declarationRange.getFile() != null) { |
| result.add(declarationRange.getFile()); |
| } |
| } catch (IOException ex) { |
| // expected, ignore. |
| } |
| } |
| } |
| } |
| return result; |
| } |
| |
| void refreshDependencies(RequestProcessor.Task t) { |
| DependencyResult dr = ProjectDependencies.findDependencies(project, ProjectDependencies.newQuery(Scopes.RUNTIME)); |
| LOG.log(Level.FINER, "{0} - dependencies refreshed", this); |
| synchronized (this) { |
| if (pendingRefresh != t) { |
| return; |
| } |
| } |
| synchronized (this) { |
| if (depChange != null) { |
| dependencyResult.removeChangeListener(depChange); |
| } |
| } |
| CacheItem novy = new CacheItem( project, dr, report); |
| if (LOG.isLoggable(Level.FINER)) { |
| LOG.log(Level.FINER, "{0} - trying to replace for {1}", new Object[] { this, novy }); |
| } |
| if (replaceCacheItem(this, novy)) { |
| novy.startListening(); |
| Diagnostic.ReporterControl reporter = Diagnostic.findReporterControl(Lookup.getDefault(), project.getProjectDirectory()); |
| Set<FileObject> allFiles = new HashSet<>(); |
| allFiles.addAll(getProblematicFiles()); |
| allFiles.addAll(novy.getProblematicFiles()); |
| if (LOG.isLoggable(Level.FINER)) { |
| LOG.log(Level.FINER, "{0} - refreshing files: {1}", new Object[] { this, allFiles }); |
| } |
| reporter.diagnosticChanged(novy.getProblematicFiles(), null); |
| } |
| } |
| |
| void scheduleDependencyRefresh(ChangeEvent e) { |
| synchronized (this) { |
| if (pendingRefresh != null) { |
| pendingRefresh.cancel(); |
| } |
| |
| RequestProcessor.Task[] task = new RequestProcessor.Task[1]; |
| if (LOG.isLoggable(Level.FINER)) { |
| LOG.log(Level.FINER, "{0} - scheduling refresh for {1}", new Object[] { this, project }); |
| } |
| pendingRefresh = task[0] = SOURCE_REFRESH_PROCESSOR.post(() -> { |
| synchronized (this) { |
| refreshDependencies(task[0]); |
| } |
| }); |
| } |
| } |
| |
| SourceLocation getDependencyRange(Dependency d) throws IOException { |
| return getDependencyRange(d, null); |
| } |
| |
| void startListening() { |
| synchronized (this) { |
| if (depChange == null) { |
| dependencyResult.addChangeListener(depChange = this::scheduleDependencyRefresh); |
| LOG.log(Level.FINER, "{0} - start listen for dependencies", this); |
| } |
| } |
| } |
| |
| SourceLocation getDependencyRange(Dependency d, String part) throws IOException { |
| startListening(); |
| return dependencyResult.getDeclarationRange(d, part); |
| } |
| |
| public List<Diagnostic> getDiagnosticsForFile(FileObject file) { |
| if (LOG.isLoggable(Level.FINER)) { |
| LOG.log(Level.FINER, "{0} getDiagnostics called for {1}", new Object[] { this, file }); |
| } |
| if (getVulnerabilities() == null || getVulnerabilities().isEmpty()) { |
| return null; |
| } |
| |
| List<Diagnostic> result = new ArrayList(); |
| for (ApplicationDependencyVulnerabilitySummary v: getVulnerabilities()){ |
| List<Vulnerability> vulnerabilities = v.getVulnerabilities(); |
| if (!vulnerabilities.isEmpty()) { |
| startListening(); |
| Dependency dependency = getDependencyMap().get(v.getGav()); |
| SourceLocation declarationRange = null; |
| |
| if (dependency != null) { |
| try { |
| declarationRange = getDependencyRange(dependency); |
| } catch (IOException ex) { |
| Exceptions.printStackTrace(ex); |
| } |
| } |
| // display the vulnerabilities that were never mapped on the dependency container's line. |
| // also display the vulnerabilities that we KNOW about, but do can not map them back to the project file, i.e. |
| // plugin-introduced dependencies (gradle). |
| if (declarationRange == null && (dependency != null || !report.mappedVulnerabilities.contains(v.getGav()))) { |
| try { |
| if (LOG.isLoggable(Level.FINER)) { |
| LOG.log(Level.FINER, "{0} getDiagnostics called for {1}", new Object[] { this, file }); |
| } |
| |
| declarationRange = getDependencyRange(dependency, DependencyResult.PART_CONTAINER); |
| if (declarationRange != null) { |
| // discard end location, since it could span a whole section |
| declarationRange = new SourceLocation(declarationRange.getFile(), |
| declarationRange.getStartOffset(), declarationRange.getStartOffset(), null); |
| } |
| } catch (IOException ex) { |
| // ignore |
| } |
| } |
| |
| if (declarationRange != null && declarationRange.hasPosition() && declarationRange.getFile().equals(file)) { |
| final SourceLocation fDeclarationRange = declarationRange; |
| for(Vulnerability vulnerability: vulnerabilities) { |
| String message = String.format(Bundle.MSG_Diagnostic(), |
| formatCvssScore(vulnerability.getCvssV2Score()), |
| formatCvssScore(vulnerability.getCvssV3Score()), |
| createGAV(dependency.getArtifact())); |
| Diagnostic.Builder builder = Diagnostic.Builder.create(() -> fDeclarationRange.getStartOffset(), () -> fDeclarationRange.getEndOffset(), message); |
| builder.setSeverity(Diagnostic.Severity.Warning).setCode(vulnerability.getId()); |
| try { |
| builder.setCodeDescription(new URL(GOV_DETAIL_URL + vulnerability.getId())); |
| } catch (MalformedURLException ex) { |
| // perhaps should not happen at all |
| LOG.log(Level.INFO, "Could not link to vulnerability: {0}", vulnerability.getId()); |
| } |
| result.add(builder.build()); |
| } |
| } |
| } |
| } |
| return result; |
| } |
| |
| private String formatCvssScore(Float value) { |
| if (value != null) { |
| return String.format("%.2f", value); |
| } |
| return Bundle.MSG_NotAvailable(); |
| } |
| } |
| |
| private static boolean replaceCacheItem(CacheItem old, CacheItem novy) { |
| synchronized (cache) { |
| CacheItem registered = cache.get(old.project); |
| if (registered != old) { |
| return false; |
| } |
| cache.put(novy.project, novy); |
| } |
| return true; |
| } |
| |
| private VulnerabilityWorker() { |
| } |
| |
| public static VulnerabilityWorker getInstance() { |
| synchronized (VulnerabilityWorker.class) { |
| if (instance == null) { |
| instance = new VulnerabilityWorker(); |
| |
| } |
| } |
| return instance; |
| } |
| |
| public void findVulnerability(Project project, boolean forceAudit) { |
| LOG.log(Level.FINER, "Trying to obtain audit for project {0}, force:{1}", new Object[] { project, forceAudit }); |
| final String projectDisplayName = ProjectUtils.getInformation(project).getDisplayName(); |
| KnowledgeBaseItem kbItem = getKnowledgeBaseForProject(project); |
| if (kbItem == null) { |
| return; |
| } |
| |
| // remove from the cache old values |
| ProgressHandle progressHandle = ProgressHandle.createHandle(Bundle.MSG_AuditIsRunning(projectDisplayName)); |
| progressHandle.start(); |
| try { |
| doFindVulnerability(project, kbItem.compartmentId, kbItem.getKey().getValue(), |
| projectDisplayName, progressHandle, forceAudit); |
| } finally { |
| progressHandle.finish(); |
| kbItem.refresh(); |
| } |
| } |
| |
| public void doFindVulnerability(Project project, String compartmentId, String knowledgeBaseId, String projectDisplayName, |
| ProgressHandle progressHandle, boolean forceAudit) { |
| DependencyResult dr = ProjectDependencies.findDependencies(project, ProjectDependencies.newQuery(Scopes.RUNTIME)); |
| List<ApplicationDependency> result = new ArrayList(); |
| convert(dr.getRoot(), new HashMap<>(), result); |
| |
| CacheItem cacheItem = null; |
| VulnerabilityReport savedAudit = null; |
| |
| if (!forceAudit) { |
| try { |
| savedAudit = AuditCache.getInstance().loadAudit(knowledgeBaseId); |
| } catch (IOException ex) { |
| LOG.log(Level.WARNING, "Could not load cached audit data", ex); |
| } |
| } |
| |
| boolean auditDone = false; |
| |
| if (!forceAudit && savedAudit == null) { |
| // attempt to find an active most recent audit: |
| try (ApplicationDependencyManagementClient admClient |
| = new ApplicationDependencyManagementClient(OCIManager.getDefault().getConfigProvider())) { |
| ListVulnerabilityAuditsRequest request = ListVulnerabilityAuditsRequest |
| .builder() |
| .compartmentId(compartmentId) |
| .knowledgeBaseId(knowledgeBaseId) |
| .lifecycleState(LifecycleState.Active) |
| .sortBy(ListVulnerabilityAuditsRequest.SortBy.TimeCreated) |
| .sortOrder(SortOrder.Desc).build(); |
| ListVulnerabilityAuditsResponse response = admClient.listVulnerabilityAudits(request); |
| if (!response.getVulnerabilityAuditCollection().getItems().isEmpty()) { |
| VulnerabilityAuditSummary summary = response.getVulnerabilityAuditCollection().getItems().get(0); |
| cacheItem = fetchVulnerabilityItems(project, admClient, dr, summary, projectDisplayName); |
| savedAudit = new VulnerabilityReport(cacheItem.getAudit(), cacheItem.getVulnerabilities()); |
| } |
| } catch (BmcException ex) { |
| LOG.log(Level.FINE, "Unable to list newest audit for knowledgebase {0}, compartment {1}", new Object[] { |
| knowledgeBaseId, compartmentId |
| }); |
| } |
| } |
| |
| if (savedAudit == null && forceAudit) { |
| try (ApplicationDependencyManagementClient admClient |
| = new ApplicationDependencyManagementClient(OCIManager.getDefault().getConfigProvider())) { |
| final VulnerabilityAuditConfiguration auditConfiguration = VulnerabilityAuditConfiguration |
| .builder() |
| .maxPermissibleCvssV2Score(1f) |
| .maxPermissibleCvssV3Score(1f) |
| .exclusions(Collections.unmodifiableList(Collections.EMPTY_LIST)) |
| .build(); |
| final CreateVulnerabilityAuditDetails auditDetails = CreateVulnerabilityAuditDetails |
| .builder() |
| .compartmentId(compartmentId) |
| .knowledgeBaseId(knowledgeBaseId) |
| .displayName(projectDisplayName.replaceAll("[^A-Za-z0-9-_]", "_")) // remove offending characters |
| .buildType(VulnerabilityAudit.BuildType.Maven) |
| .configuration(auditConfiguration) |
| .applicationDependencies(result) |
| .build(); |
| CreateVulnerabilityAuditResponse response = admClient.createVulnerabilityAudit(CreateVulnerabilityAuditRequest |
| .builder() |
| .createVulnerabilityAuditDetails(auditDetails) |
| .build()); |
| if (response.get__httpStatusCode__() != 201 && response.get__httpStatusCode__() != 200) { |
| ErrorUtils.processError(response, Bundle.MSG_CreatingAuditFailed(projectDisplayName)); |
| return; |
| } |
| // audit is ok |
| cacheItem = waitToAuditFinish(project, admClient, dr, response.getVulnerabilityAudit(), projectDisplayName); |
| auditDone = true; |
| } catch (BmcException exc) { |
| ErrorUtils.processError(exc, compartmentId); |
| return; |
| } finally { |
| progressHandle.finish(); |
| } |
| } else if (savedAudit != null) { |
| cacheItem = new CacheItem(project, dr, savedAudit); |
| } |
| |
| if (cacheItem != null) { |
| synchronized (cache) { |
| cache.put(project, cacheItem); |
| } |
| |
| Set<FileObject> problematicFiles = new HashSet(); |
| problematicFiles.addAll(cacheItem.getProblematicFiles()); |
| |
| String message; |
| if (cacheItem.getAudit().getIsSuccess()) { |
| message = Bundle.MSG_Audit_Pass(projectDisplayName); |
| problematicFiles.addAll(dr.getDependencyFiles()); |
| } else if(cacheItem.getAudit().getVulnerableArtifactsCount() == 1) { |
| message = Bundle.MSG_Audit_Failed_One(projectDisplayName); |
| } else { |
| message = Bundle.MSG_Audit_Failed_More(projectDisplayName, cacheItem.getAudit().getVulnerableArtifactsCount()); |
| } |
| if (auditDone) { |
| DialogDisplayer.getDefault().notifyLater( |
| new NotifyDescriptor.Message(message)); |
| } |
| Diagnostic.ReporterControl reporter = Diagnostic.findReporterControl(Lookup.getDefault(), project.getProjectDirectory()); |
| reporter.diagnosticChanged(problematicFiles, null); |
| } |
| } |
| |
| public static KnowledgeBaseItem getKnowledgeBaseForProject(Project project) { |
| ProjectVulnerability vs = project.getLookup().lookup(ProjectVulnerability.class); |
| return vs != null ? vs.getProjectKnowledgeBase() : null; |
| } |
| |
| private int convert(Dependency dependency, Map<String, Integer> gavIndex, List<ApplicationDependency> result) { |
| String gav = createGAV(dependency.getArtifact()); |
| Integer n = gavIndex.get(gav); |
| if (n != null) { |
| return n; |
| } |
| gavIndex.put(gav, n = gavIndex.size() + 1); |
| ApplicationDependency.Builder builder = ApplicationDependency.builder(); |
| builder.gav(gav); |
| builder.nodeId(Integer.toString(n)); |
| |
| List<String> childrenNodeIds = new ArrayList(dependency.getChildren().size()); |
| for (Dependency childDependency : dependency.getChildren()) { |
| int cid = convert(childDependency, gavIndex, result); |
| childrenNodeIds.add(Integer.toString(cid)); |
| } |
| builder.applicationDependencyNodeIds(childrenNodeIds); |
| result.add(builder.build()); |
| return n; |
| } |
| |
| private static String createGAV(ArtifactSpec artifact) { |
| StringBuffer sb = new StringBuffer(); |
| sb.append(artifact.getGroupId()).append(':'); |
| sb.append(artifact.getArtifactId()).append(':'); |
| sb.append(artifact.getVersionSpec()); |
| return sb.toString(); |
| } |
| |
| private CacheItem waitToAuditFinish(Project project, ApplicationDependencyManagementClient client, |
| DependencyResult dr, VulnerabilityAudit audit, String projectName) { |
| ListVulnerabilityAuditsRequest request = ListVulnerabilityAuditsRequest.builder() |
| .knowledgeBaseId(audit.getKnowledgeBaseId()).id(audit.getId()).build(); |
| VulnerabilityAuditSummary auditSummary; |
| boolean first = true; |
| do { |
| if (first) { |
| first = false; |
| } else { |
| try { |
| Thread.sleep(1000); |
| } catch (InterruptedException ex) { |
| Exceptions.printStackTrace(ex); |
| } |
| } |
| ListVulnerabilityAuditsResponse response = client.listVulnerabilityAudits(request); |
| if (response.get__httpStatusCode__() != 200) { |
| ErrorUtils.processError(response, Bundle.MSG_ListingAuditFailed(projectName)); |
| return null; |
| } |
| List<VulnerabilityAuditSummary> items = response.getVulnerabilityAuditCollection().getItems(); |
| auditSummary = items.get(0); |
| } while (auditSummary.getLifecycleState() == VulnerabilityAudit.LifecycleState.Creating); |
| return fetchVulnerabilityItems(project, client, dr, auditSummary, projectName); |
| } |
| |
| private CacheItem fetchVulnerabilityItems(Project project, ApplicationDependencyManagementClient client, |
| DependencyResult dr, VulnerabilityAuditSummary auditSummary, String projectName) { |
| List<ApplicationDependencyVulnerabilitySummary> items = new ArrayList<>(); |
| if (auditSummary.getVulnerableArtifactsCount() > 0) { |
| String nextPage = null; |
| do { |
| ListApplicationDependencyVulnerabilitiesRequest.Builder b = ListApplicationDependencyVulnerabilitiesRequest.builder().vulnerabilityAuditId(auditSummary.getId()); |
| if (nextPage != null) { |
| b.page(nextPage); |
| } |
| ListApplicationDependencyVulnerabilitiesRequest advRequest = b.build(); |
| ListApplicationDependencyVulnerabilitiesResponse vulners = client.listApplicationDependencyVulnerabilities(advRequest); |
| if (vulners.get__httpStatusCode__() == 200) { |
| vulners.getApplicationDependencyVulnerabilityCollection().getItems().stream().filter(v -> !v.getVulnerabilities().isEmpty()) |
| .forEach(v -> items.add(v)); |
| } else { |
| ErrorUtils.processError(vulners, Bundle.MSG_ListingVulnerabilitiesFailed()); |
| return null; |
| } |
| nextPage = vulners.getOpcNextPage(); |
| } while (nextPage != null); |
| } |
| // Make an initial scan for the dependency locations in the Dependency report. |
| Set<String> mapped = new HashSet<>(); |
| VulnerabilityReport report = new VulnerabilityReport(auditSummary, items); |
| CacheItem cache = new CacheItem(project, dr, report); |
| for (ApplicationDependencyVulnerabilitySummary v : items) { |
| List<Vulnerability> vulnerabilities = v.getVulnerabilities(); |
| if (!vulnerabilities.isEmpty()) { |
| Dependency dependency = cache.getDependencyMap().get(v.getGav()); |
| if (dependency != null) { |
| mapped.add(v.getGav()); |
| } |
| } |
| } |
| report.setMappedVulnerabilities(mapped); |
| |
| try { |
| AuditCache.getInstance().cacheAuditResults(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(), |
| projectName |
| }); |
| LOG.log(Level.WARNING, "The exception was: ", ex); |
| } |
| return cache; |
| } |
| |
| @Override |
| public List<? extends Diagnostic> computeErrors(Context context) { |
| List<Diagnostic> result = new ArrayList(); |
| Collection<CacheItem> items; |
| |
| synchronized (cache) { |
| items = new ArrayList<>(cache.values()); |
| } |
| for (CacheItem cacheItem : items) { |
| List<Diagnostic> diagnostics = cacheItem.getDiagnosticsForFile(context.file()); |
| if (diagnostics != null) { |
| result.addAll(cacheItem.getDiagnosticsForFile(context.file())); |
| } |
| } |
| return result; |
| } |
| } |