/** * blackduck-alert * * Copyright (c) 2020 Synopsys, Inc. * * 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 com.synopsys.integration.alert.provider.blackduck.collector.builder.util; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Supplier; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import com.synopsys.integration.alert.common.message.model.LinkableItem; import com.synopsys.integration.alert.common.util.DataStructureUtils; import com.synopsys.integration.alert.provider.blackduck.collector.builder.MessageBuilderConstants; import com.synopsys.integration.blackduck.api.generated.component.ComponentVersionRemediatingFixesPreviousVulnerabilitiesView; import com.synopsys.integration.blackduck.api.generated.component.ComponentVersionRiskProfileRiskDataCountsView; import com.synopsys.integration.blackduck.api.generated.enumeration.ComponentVersionRiskProfileRiskDataCountsCountTypeType; import com.synopsys.integration.blackduck.api.generated.response.ComponentVersionRemediatingView; import com.synopsys.integration.blackduck.api.generated.view.ComponentVersionView; import com.synopsys.integration.blackduck.api.generated.view.ProjectVersionComponentView; import com.synopsys.integration.blackduck.api.generated.view.ProjectVersionView; import com.synopsys.integration.blackduck.api.generated.view.RiskProfileView; import com.synopsys.integration.blackduck.api.generated.view.VulnerabilityView; import com.synopsys.integration.blackduck.api.manual.throwaway.generated.view.VulnerableComponentView; import com.synopsys.integration.blackduck.service.BlackDuckService; import com.synopsys.integration.blackduck.service.ComponentService; import com.synopsys.integration.blackduck.service.model.ProjectVersionWrapper; import com.synopsys.integration.exception.IntegrationException; public final class VulnerabilityUtil { private VulnerabilityUtil() { } public static List<VulnerabilityView> getVulnerabilitiesForComponent(Logger logger, BlackDuckService blackDuckService, String vulnerableComponentVulnerabilitiesURL) { try { return blackDuckService.getAllResponses(vulnerableComponentVulnerabilitiesURL, VulnerableComponentView.VULNERABILITIES_LINK_RESPONSE.getResponseClass()); } catch (IntegrationException ex) { logger.error("Error getting vulnerabilities ", ex); } return List.of(); } public static List<VulnerableComponentView> getVulnerableComponentViews(BlackDuckService blackDuckService, ProjectVersionWrapper projectVersionWrapper, ProjectVersionComponentView projectVersionComponentView) throws IntegrationException { return blackDuckService.getAllResponses(projectVersionWrapper.getProjectVersionView(), ProjectVersionView.VULNERABLE_COMPONENTS_LINK_RESPONSE).stream() .filter(vulnerableComponentView -> vulnerableComponentView.getComponentName().equals(projectVersionComponentView.getComponentName())) .filter(vulnerableComponentView -> vulnerableComponentView.getComponentVersionName().equals(projectVersionComponentView.getComponentVersionName())) .collect(Collectors.toList()); } public static List<LinkableItem> getRemediationItems(ComponentService componentService, ComponentVersionView componentVersionView) throws IntegrationException { List<LinkableItem> remediationItems = new LinkedList<>(); Optional<ComponentVersionRemediatingView> optionalRemediation = componentService.getRemediationInformation(componentVersionView); if (optionalRemediation.isPresent()) { ComponentVersionRemediatingView remediationOptions = optionalRemediation.get(); createRemediationItem(remediationOptions::getFixesPreviousVulnerabilities, MessageBuilderConstants.LABEL_REMEDIATION_FIX_PREVIOUS).ifPresent(remediationItems::add); createRemediationItem(remediationOptions::getLatestAfterCurrent, MessageBuilderConstants.LABEL_REMEDIATION_LATEST).ifPresent(remediationItems::add); createRemediationItem(remediationOptions::getNoVulnerabilities, MessageBuilderConstants.LABEL_REMEDIATION_CLEAN).ifPresent(remediationItems::add); } return remediationItems; } public static Map<String, VulnerabilityView> createVulnerabilityViewMap(Logger logger, BlackDuckService blackDuckService, Collection<VulnerableComponentView> vulnerableComponentViews) { Set<String> vulnerabilityUrls = new HashSet<>(); Map<String, VulnerabilityView> vulnerabilityViewMap = new HashMap<>(vulnerableComponentViews.size()); for (VulnerableComponentView vulnerableComponent : vulnerableComponentViews) { // in Black Duck 2019.10.0 the vulnerabilities link was changed to be the href Optional<String> href = vulnerableComponent.getHref(); Optional<String> vulnerabilitiesLink = Optional.empty(); if (vulnerableComponent.hasLink(VulnerableComponentView.VULNERABILITIES_LINK)) { vulnerabilitiesLink = vulnerableComponent.getFirstLink(VulnerableComponentView.VULNERABILITIES_LINK); } else if (href.isPresent()) { String hrefLink = href.get(); // check that the href is the vulnerabilities link that we expect if (hrefLink.endsWith(VulnerableComponentView.VULNERABILITIES_LINK)) { vulnerabilitiesLink = href; } } if (vulnerabilitiesLink.isPresent()) { String vulnerableComponentVulnerabilitiesURL = vulnerabilitiesLink.get(); if (!vulnerabilityUrls.contains(vulnerableComponentVulnerabilitiesURL)) { Map<String, VulnerabilityView> vulnerabilitiesForComponent = DataStructureUtils.mapToValues(getVulnerabilitiesForComponent(logger, blackDuckService, vulnerableComponentVulnerabilitiesURL), VulnerabilityView::getName); vulnerabilityViewMap.putAll(vulnerabilitiesForComponent); vulnerabilityUrls.add(vulnerabilitiesLink.get()); } } else { logger.debug("The {} link could not be found for the vulnerable component '{}' version '{}'.", VulnerableComponentView.VULNERABILITIES_LINK, vulnerableComponent.getComponentName(), vulnerableComponent.getComponentVersionName()); } } return vulnerabilityViewMap; } public static LinkableItem createVulnerabilityAttributeItem(String severityValue, LinkableItem vulnerabilityItem) { String capitalizedSeverityValue = StringUtils.capitalize(severityValue.toLowerCase()); String attributeName = String.format("%s %s", capitalizedSeverityValue, vulnerabilityItem.getName()); LinkableItem attributeItem = new LinkableItem(attributeName, vulnerabilityItem.getValue(), vulnerabilityItem.getUrl().orElse(null)); attributeItem.setCollapsible(vulnerabilityItem.isCollapsible()); return attributeItem; } private static Optional<LinkableItem> createRemediationItem(Supplier<ComponentVersionRemediatingFixesPreviousVulnerabilitiesView> getRemediationOption, String remediationLabel) { ComponentVersionRemediatingFixesPreviousVulnerabilitiesView remediatingVersionView = getRemediationOption.get(); if (null != remediatingVersionView) { String versionText = createRemediationVersionText(remediatingVersionView); return Optional.of(new LinkableItem(remediationLabel, versionText, remediatingVersionView.getComponentVersion())); } return Optional.empty(); } private static String createRemediationVersionText(ComponentVersionRemediatingFixesPreviousVulnerabilitiesView remediatingVersionView) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(remediatingVersionView.getName()); if (remediatingVersionView.getVulnerabilityCount() != null && remediatingVersionView.getVulnerabilityCount().intValue() > 0) { stringBuilder.append(" (Vulnerability Count: "); stringBuilder.append(remediatingVersionView.getVulnerabilityCount()); stringBuilder.append(")"); } return stringBuilder.toString(); } public static boolean doesSecurityRiskProfileHaveVulnerabilities(Logger logger, RiskProfileView securityRiskProfile) { logger.debug("Checking if the component still has vulnerabilities..."); int vulnerabilitiesCount = getSumOfRiskCounts(securityRiskProfile.getCounts()); logger.debug("Number of vulnerabilities found: {}", vulnerabilitiesCount); if (vulnerabilitiesCount > 0) { logger.debug("This component still has vulnerabilities"); return true; } return false; } private static int getSumOfRiskCounts(List<ComponentVersionRiskProfileRiskDataCountsView> vulnerabilityCounts) { int count = 0; for (ComponentVersionRiskProfileRiskDataCountsView riskCount : vulnerabilityCounts) { if (!ComponentVersionRiskProfileRiskDataCountsCountTypeType.OK.equals(riskCount.getCountType())) { count += riskCount.getCount().intValue(); } } return count; } }