com.metaeffekt.artifact.enrichment.other.VulnerabilityOverviewChartGenerator Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2021-2024 the original author or authors.
*
* Licensed 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.metaeffekt.artifact.enrichment.other;
import com.metaeffekt.artifact.analysis.utils.JFreeChartUtils;
import com.metaeffekt.artifact.analysis.utils.StringUtils;
import com.metaeffekt.artifact.analysis.vulnerability.enrichment.vulnerabilitystatus.VulnerabilityStatusHistoryEntry;
import com.metaeffekt.artifact.enrichment.other.vad.VulnerabilityAssessmentDashboard;
import com.metaeffekt.mirror.contents.base.VulnerabilityContextInventory;
import com.metaeffekt.mirror.contents.vulnerability.Vulnerability;
import de.yanwittmann.j2chartjs.chart.DoughnutChart;
import de.yanwittmann.j2chartjs.data.DoughnutPieChartData;
import de.yanwittmann.j2chartjs.dataset.DoughnutPieChartDataset;
import de.yanwittmann.j2chartjs.options.ChartOptions;
import de.yanwittmann.j2chartjs.options.plugins.legend.LegendOption;
import de.yanwittmann.j2chartjs.options.plugins.title.TitleOption;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PiePlot;
import org.jfree.data.general.DefaultPieDataset;
import org.metaeffekt.core.inventory.processor.model.Artifact;
import org.metaeffekt.core.inventory.processor.model.VulnerabilityMetaData;
import org.metaeffekt.core.inventory.processor.report.StatisticsOverviewTable;
import org.metaeffekt.core.inventory.processor.report.configuration.CentralSecurityPolicyConfiguration;
import org.metaeffekt.core.security.cvss.CvssSeverityRanges;
import org.metaeffekt.core.security.cvss.CvssVector;
import org.metaeffekt.core.util.ColorScheme;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.*;
import java.util.List;
import java.util.*;
import static j2html.TagCreator.canvas;
import static j2html.TagCreator.span;
public class VulnerabilityOverviewChartGenerator {
private final static Logger LOG = LoggerFactory.getLogger(VulnerabilityOverviewChartGenerator.class);
private final CentralSecurityPolicyConfiguration securityPolicy;
private final VulnerabilityContextInventory vInventory;
private final List effectiveVulnerabilities;
private final Map> vulnerabilitiesPerArtifact;
/**
* When passing the applyEffectiveCalculations
parameter, the vInventory
passed as
* parameter must not have the
* {@link VulnerabilityContextInventory#calculateEffectiveCvssVectorsForVulnerabilities(CentralSecurityPolicyConfiguration)}
* and
* {@link VulnerabilityContextInventory#applyEffectiveVulnerabilityStatus(CentralSecurityPolicyConfiguration)}
* methods already called, since they will be called by this constructor.
*
* @param vInventory the vulnerability inventory to be used for generating the charts
* @param securityPolicy the security policy to be used for calculating the effective CVSS vectors and vulnerability status
* @param applyEffectiveCalculations whether to bake the effective CVSS vectors and apply the effective vulnerability status
*/
public VulnerabilityOverviewChartGenerator(VulnerabilityContextInventory vInventory, CentralSecurityPolicyConfiguration securityPolicy, boolean applyEffectiveCalculations) {
this.securityPolicy = securityPolicy;
this.vInventory = vInventory;
if (applyEffectiveCalculations) {
LOG.info("Baking effective CVSS vectors");
vInventory.calculateEffectiveCvssVectorsForVulnerabilities(securityPolicy);
LOG.info("Applying effective vulnerability status");
vInventory.applyEffectiveVulnerabilityStatus(securityPolicy);
}
LOG.info("Using calculated values for potential vulnerability filtering");
this.effectiveVulnerabilities = VulnerabilityAssessmentDashboard.getEffectiveVulnerabilitiesAll(vInventory, securityPolicy);
LOG.info("Mapping artifacts to matched vulnerabilities");
this.vulnerabilitiesPerArtifact = Vulnerability.groupVulnerabilitiesByArtifact(effectiveVulnerabilities);
}
public VulnerabilityOverviewChartGenerator(VulnerabilityContextInventory vInventory, CentralSecurityPolicyConfiguration securityPolicy, List effectiveVulnerabilities, Map> vulnerabilitiesPerArtifact) {
this.securityPolicy = securityPolicy;
this.vInventory = vInventory;
this.effectiveVulnerabilities = effectiveVulnerabilities;
this.vulnerabilitiesPerArtifact = vulnerabilitiesPerArtifact;
}
public List generateOverviewCharts() {
final List generatedCharts = new ArrayList<>();
// pre-calculate data for the charts
final Map initialSeverityCategories = new HashMap<>();
final Map contextSeverityCategories = new HashMap<>();
final Map statusPerVulnerability = new HashMap<>();
for (Vulnerability vulnerability : effectiveVulnerabilities) {
final VulnerabilityStatusHistoryEntry latestStatusHistoryEntry = vulnerability.getOrCreateNewVulnerabilityStatus().getLatestActiveStatusHistoryEntry();
final String baseStatus = (latestStatusHistoryEntry != null) ? latestStatusHistoryEntry.getStatus() : null;
final String mappedStatus = CentralSecurityPolicyConfiguration.VULNERABILITY_STATUS_DISPLAY_MAPPER_UNMODIFIED.getMapper().apply(baseStatus);
statusPerVulnerability.put(vulnerability, mappedStatus);
initialSeverityCategories.put(vulnerability, this.securityPolicy.getCvssSeverityRanges().getRange(getOverallScore(vulnerability.getCvssSelectionResult().getSelectedInitialCvss(), 0)));
// see StatisticsOverviewTable for more details on this mapping
if (VulnerabilityMetaData.STATUS_VALUE_NOTAPPLICABLE.equals(baseStatus) || VulnerabilityMetaData.STATUS_VALUE_VOID.equals(baseStatus)) {
contextSeverityCategories.put(vulnerability, this.securityPolicy.getCvssSeverityRanges().getRange(0));
} else {
contextSeverityCategories.put(vulnerability, this.securityPolicy.getCvssSeverityRanges().getRange(getOverallScore(vulnerability.getCvssSelectionResult().getSelectedContextIfAvailableOtherwiseInitial(), 0)));
}
}
final List vulnerabilitiesPotentiallyAffected = filterVulnerabilitiesForStatus(statusPerVulnerability, VulnerabilityMetaData.STATUS_VALUE_IN_REVIEW);
final List vulnerabilitiesReviewed = filterVulnerabilitiesForStatus(statusPerVulnerability, "reviewed"); // "review state" mapper is used here
final Map> vulnerabilitiesByComponent = this.groupVulnerabilitiesByComponent(vulnerabilitiesPerArtifact);
// generate charts
generatedCharts.add(generateOverviewChartCvssSeverityInitial(initialSeverityCategories));
generatedCharts.add(generateOverviewChartVulnerabilityAssessmentStatus(statusPerVulnerability));
generatedCharts.add(generateOverviewChartCvssSeverityContext(contextSeverityCategories));
generatedCharts.add(generateOverviewChartCvssSeverityContextByStatusInReview(contextSeverityCategories, vulnerabilitiesPotentiallyAffected));
generatedCharts.add(generateOverviewChartCvssSeverityContextByStatusApplicable(contextSeverityCategories, vulnerabilitiesReviewed));
generatedCharts.add(generateOverviewChartCvssSeverityContextByComponent(contextSeverityCategories, vulnerabilitiesByComponent));
return generatedCharts;
}
private Map> groupVulnerabilitiesByComponent(Map> vulnerabilitiesPerArtifact) {
final Map> vulnerabilitiesByComponent = new HashMap<>();
for (Map.Entry> entry : vulnerabilitiesPerArtifact.entrySet()) {
final Artifact artifact = entry.getKey();
final List vulnerabilities = entry.getValue();
final String component = artifact.getComponent();
final String effectiveComponent = StringUtils.hasText(component) ? component : (StringUtils.hasText(artifact.getId()) ? artifact.getId() : UUID.randomUUID().toString());
vulnerabilitiesByComponent.computeIfAbsent(effectiveComponent, c -> new ArrayList<>())
.addAll(vulnerabilities);
}
return vulnerabilitiesByComponent;
}
private List filterVulnerabilitiesForStatus(Map statusPerVulnerability, String status) {
final List filteredVulnerabilities = new ArrayList<>();
for (Map.Entry entry : statusPerVulnerability.entrySet()) {
if (entry.getValue().equals(status)) {
filteredVulnerabilities.add(entry.getKey());
}
}
return filteredVulnerabilities;
}
private double getOverallScore(CvssVector vector, double defaultValue) {
if (vector == null) {
return defaultValue;
}
return vector.getBakedScores().getOverallScore();
}
/**
*
* title: Initial CVSS Severity
* id: vulnerabilityOverviewChartCvssSeverityInitial
* file: vulnerability-overview-chart-cvss-severity-initial.svg
* unit: by vulnerability
* notes: uses the `cvssSeverityRanges` on the vector selected by the `initialCvssSelector` + `cvssVersionSelectionPolicy`
*
*
* @return the generated chart based on the metrics above
*/
private VulnerabilityAssessmentDashboard.GeneratedChart generateOverviewChartCvssSeverityInitial(Map initialSeverityCategories) {
return this.generateOverviewChartCvssSeverity(initialSeverityCategories,
"vulnerabilityOverviewChartCvssSeverityInitial", "vulnerability-overview-chart-cvss-severity-initial", "Initial CVSS Severity");
}
/**
*
* title: Context CVSS Severity
* id: vulnerabilityOverviewChartCvssSeverityContext
* file: vulnerability-overview-chart-cvss-severity-context.svg
* unit: by vulnerability
* notes: uses the `cvssSeverityRanges` on the vector selected by the `contextCvssSelector` + `cvssVersionSelectionPolicy`
*
*
* @return the generated chart based on the metrics above
*/
private VulnerabilityAssessmentDashboard.GeneratedChart generateOverviewChartCvssSeverityContext(Map contextSeverityCategories) {
return this.generateOverviewChartCvssSeverity(contextSeverityCategories,
"vulnerabilityOverviewChartCvssSeverityContext", "vulnerability-overview-chart-cvss-severity-context", "Context CVSS Severity");
}
/**
*
* title: Vulnerability Assessment Status
* id: vulnerabilityOverviewChartVulnerabilityStatus
* file: vulnerability-overview-chart-vulnerability-status.svg
* unit: by vulnerability
* notes: uses unmodified as `vulnerabilityStatusDisplayMapperName`
*
*
* @return the generated chart based on the metrics above
*/
private VulnerabilityAssessmentDashboard.GeneratedChart generateOverviewChartVulnerabilityAssessmentStatus(Map statusPerVulnerability) {
final Map countsPerStatus = new LinkedHashMap<>();
for (String status : CentralSecurityPolicyConfiguration.VULNERABILITY_STATUS_DISPLAY_MAPPER_UNMODIFIED.getStatusNames()) {
countsPerStatus.put(status, 0);
}
for (Map.Entry entry : statusPerVulnerability.entrySet()) {
countsPerStatus.put(entry.getValue(), countsPerStatus.getOrDefault(entry.getValue(), 0) + 1);
}
// JFreeChart
final DefaultPieDataset jFreeChartDataset = new DefaultPieDataset<>();
final JFreeChart jFreeChart = ChartFactory.createPieChart("", jFreeChartDataset, true, true, false);
final PiePlot> jFreeChartPlot = (PiePlot>) jFreeChart.getPlot();
JFreeChartUtils.applyDefaultForPieChartPlot(jFreeChartPlot);
jFreeChartPlot.setBackgroundPaint(new Color(255, 255, 255));
jFreeChart.setBackgroundPaint(new Color(255, 255, 255));
for (Map.Entry entry : countsPerStatus.entrySet()) {
JFreeChartUtils.addPieChartData(jFreeChartDataset, jFreeChartPlot, StatisticsOverviewTable.capitalizeWords(entry.getKey()), entry.getValue(), getStatusCategoryColor(entry.getKey().toLowerCase()));
}
// Chart.js
final DoughnutPieChartDataset chartJsChartDataset = new DoughnutPieChartDataset()
.addHoverOffset(3)
.setCutout("35%");
final DoughnutPieChartData chartJsChartData = new DoughnutPieChartData()
.addDataset(chartJsChartDataset);
final DoughnutChart chartJsChart = new DoughnutChart()
.setChartData(chartJsChartData)
.setChartOptions(this.createChartOptionsForOverviewCharts("Vulnerability Assessment Status"));
for (Map.Entry entry : countsPerStatus.entrySet()) {
chartJsChartDataset
.addData(entry.getValue())
.addBackgroundColor(getStatusCategoryColor(entry.getKey().toLowerCase()));
chartJsChartData
.addLabels(StatisticsOverviewTable.capitalizeWords(entry.getKey()));
}
return new VulnerabilityAssessmentDashboard.GeneratedChartBuilder()
.setjFreeChart(jFreeChart)
.setjFreeChartName("vulnerability-overview-chart-vulnerability-status")
.setChartJsChart(chartJsChart)
.setChartJsChartId("vulnerabilityOverviewChartVulnerabilityStatus")
.setCanvasOrParentTag(span().attr("width", "300").attr("height", "300").withStyle("width:300px;height:300px;display:inline-block;").withClass("overview-chart-filterable").with(
canvas().withClass("chart-js-remove-display-block")
))
.setCharJsChartJsVarName("vulnerabilityOverviewChartVulnerabilityStatus")
.createGeneratedChart();
}
/**
*
* title: Context CVSS Severity (by vulnerabilities in review)
* id: vulnerabilityOverviewChartCvssSeverityContextByStatusInReview
* file: vulnerability-overview-chart-cvss-severity-context-by-status-in-review.svg
* unit: by vulnerability
* notes: 1. maps the vulnerability status using `unmodified` as `vulnerabilityStatusDisplayMapperName`
* 2. filters the vulnerabilities to only those with a status `in review`
* 3. for each vulnerability, uses the `cvssSeverityRanges` on the vector selected by the `contextCvssSelector` + `cvssVersionSelectionPolicy`
*
*
* @return the generated chart based on the metrics above
*/
private VulnerabilityAssessmentDashboard.GeneratedChart generateOverviewChartCvssSeverityContextByStatusInReview(Map contextSeverityCategories, List vulnerabilitiesPotentiallyAffected) {
return this.generateOverviewChartCvssSeverityContextByStatus(contextSeverityCategories, vulnerabilitiesPotentiallyAffected,
"vulnerabilityOverviewChartCvssSeverityContextByStatusInReview", "vulnerability-overview-chart-cvss-severity-context-by-status-in-review", "Context CVSS Severity (by vulnerabilities in review)",
ColorScheme.PASTEL_BLUE);
}
/**
*
* title: Context CVSS Severity (by reviewed vulnerabilities)
* id: vulnerabilityOverviewChartCvssSeverityContextByStatusApplicable
* file: vulnerability-overview-chart-cvss-severity-context-by-status-applicable.svg
* unit: by vulnerability
* notes: 1. maps the vulnerability status using `unmodified` as `vulnerabilityStatusDisplayMapperName`
* 2. filters the vulnerabilities to only those with a status `applicable`
* 3. for each vulnerability, uses the `cvssSeverityRanges` on the vector selected by the `contextCvssSelector` + `cvssVersionSelectionPolicy`
*
*
* @return the generated chart based on the metrics above
*/
private VulnerabilityAssessmentDashboard.GeneratedChart generateOverviewChartCvssSeverityContextByStatusApplicable(Map contextSeverityCategories, List vulnerabilitiesReviewed) {
return this.generateOverviewChartCvssSeverityContextByStatus(contextSeverityCategories, vulnerabilitiesReviewed,
"vulnerabilityOverviewChartCvssSeverityContextByStatusApplicable", "vulnerability-overview-chart-cvss-severity-context-by-status-applicable", "Context CVSS Severity (by applicable vulnerabilities)",
ColorScheme.STRONG_DARK_BLUE);
}
/**
*
* title: Context CVSS Severity (by component)
* id: vulnerabilityOverviewChartCvssSeverityContextByComponent
* file: vulnerability-overview-chart-cvss-severity-context-by-component.svg
* unit: by component
* notes: 1. builds a `Map>` using the matching information collected during vulnerability enrichment
* 2. maps all artifact keys with the same component into a `Map>`
* 3. for each vulnerability on each component, uses the `cvssSeverityRanges` on the vector selected by the `contextCvssSelector` + `cvssVersionSelectionPolicy`
* 4. picks the highest severity category on each component
*
*
* @return the generated chart based on the metrics above
*/
private VulnerabilityAssessmentDashboard.GeneratedChart generateOverviewChartCvssSeverityContextByComponent(Map contextSeverityCategories, Map> vulnerabilitiesByComponent) {
final Map countsPerSeverityCategory = new LinkedHashMap<>();
for (Map.Entry> entry : vulnerabilitiesByComponent.entrySet()) {
final String component = entry.getKey();
final List vulnerabilities = entry.getValue();
CvssSeverityRanges.SeverityRange highestSeverityCategory = null;
for (Vulnerability vulnerability : vulnerabilities) {
final CvssSeverityRanges.SeverityRange severityCategory = contextSeverityCategories.get(vulnerability);
if (highestSeverityCategory == null || severityCategory.getIndex() > highestSeverityCategory.getIndex()) {
highestSeverityCategory = severityCategory;
}
}
countsPerSeverityCategory.put(highestSeverityCategory, countsPerSeverityCategory.getOrDefault(highestSeverityCategory, 0) + 1);
}
// JFreeChart
final DefaultPieDataset jFreeChartDataset = new DefaultPieDataset<>();
final JFreeChart jFreeChart = ChartFactory.createPieChart("", jFreeChartDataset, true, true, false);
final PiePlot> jFreeChartPlot = (PiePlot>) jFreeChart.getPlot();
JFreeChartUtils.applyDefaultForPieChartPlot(jFreeChartPlot);
jFreeChartPlot.setBackgroundPaint(new Color(255, 255, 255));
jFreeChart.setBackgroundPaint(new Color(255, 255, 255));
for (Map.Entry entry : countsPerSeverityCategory.entrySet()) {
JFreeChartUtils.addPieChartData(jFreeChartDataset, jFreeChartPlot, entry.getKey().getName(), entry.getValue(), entry.getKey().getColor().getColor());
}
// Chart.js
final DoughnutPieChartDataset chartJsChartDataset = new DoughnutPieChartDataset()
.addHoverOffset(3)
.setCutout("35%");
final DoughnutPieChartData chartJsChartData = new DoughnutPieChartData()
.addDataset(chartJsChartDataset);
final DoughnutChart chartJsChart = new DoughnutChart()
.setChartData(chartJsChartData)
.setChartOptions(this.createChartOptionsForOverviewCharts("Context CVSS Severity (by component)"));
for (Map.Entry entry : countsPerSeverityCategory.entrySet()) {
chartJsChartDataset
.addData(entry.getValue())
.addBackgroundColor(entry.getKey().getColor().getColor());
chartJsChartData
.addLabels(entry.getKey().getName());
}
return new VulnerabilityAssessmentDashboard.GeneratedChartBuilder()
.setjFreeChart(jFreeChart)
.setjFreeChartName("vulnerability-overview-chart-cvss-severity-context-by-component")
.setChartJsChart(chartJsChart)
.setChartJsChartId("vulnerabilityOverviewChartCvssSeverityContextByComponent")
.setCanvasOrParentTag(span().attr("width", "300").attr("height", "300").withStyle("width:300px;height:300px;display:inline-block;").withClass("overview-chart-filterable").with(
canvas().withClass("chart-js-remove-display-block")
))
.setCharJsChartJsVarName("vulnerabilityOverviewChartCvssSeverityContextByComponent")
.createGeneratedChart();
}
private VulnerabilityAssessmentDashboard.GeneratedChart generateOverviewChartCvssSeverity(Map severityCategories,
String chartId, String filename, String title) {
final Map countsPerSeverityCategory = new LinkedHashMap<>();
for (CvssSeverityRanges.SeverityRange range : this.securityPolicy.getCvssSeverityRanges().getRanges()) {
countsPerSeverityCategory.put(range, 0);
}
for (Map.Entry entry : severityCategories.entrySet()) {
countsPerSeverityCategory.put(entry.getValue(), countsPerSeverityCategory.getOrDefault(entry.getValue(), 0) + 1);
}
// JFreeChart
final DefaultPieDataset jFreeChartDataset = new DefaultPieDataset<>();
final JFreeChart jFreeChart = ChartFactory.createPieChart("", jFreeChartDataset, true, true, false);
final PiePlot> jFreeChartPlot = (PiePlot>) jFreeChart.getPlot();
JFreeChartUtils.applyDefaultForPieChartPlot(jFreeChartPlot);
jFreeChartPlot.setBackgroundPaint(new Color(255, 255, 255));
jFreeChart.setBackgroundPaint(new Color(255, 255, 255));
for (Map.Entry entry : countsPerSeverityCategory.entrySet()) {
JFreeChartUtils.addPieChartData(jFreeChartDataset, jFreeChartPlot, entry.getKey().getName(), entry.getValue(), entry.getKey().getColor().getColor());
}
// Chart.js
final DoughnutPieChartDataset chartJsChartDataset = new DoughnutPieChartDataset()
.addHoverOffset(3)
.setCutout("35%");
final DoughnutPieChartData chartJsChartData = new DoughnutPieChartData()
.addDataset(chartJsChartDataset);
final DoughnutChart chartJsChart = new DoughnutChart()
.setChartData(chartJsChartData)
.setChartOptions(this.createChartOptionsForOverviewCharts(title));
for (Map.Entry entry : countsPerSeverityCategory.entrySet()) {
chartJsChartDataset
.addData(entry.getValue())
.addBackgroundColor(entry.getKey().getColor().getColor());
chartJsChartData
.addLabels(entry.getKey().getName());
}
return new VulnerabilityAssessmentDashboard.GeneratedChartBuilder()
.setjFreeChart(jFreeChart)
.setjFreeChartName(filename)
.setChartJsChart(chartJsChart)
.setChartJsChartId(chartId)
.setCanvasOrParentTag(span().attr("width", "300").attr("height", "300").withStyle("width:300px;height:300px;display:inline-block;").withClass("overview-chart-filterable").with(
canvas().withClass("chart-js-remove-display-block")
))
.setCharJsChartJsVarName(chartId)
.createGeneratedChart();
}
private VulnerabilityAssessmentDashboard.GeneratedChart generateOverviewChartCvssSeverityContextByStatus(Map contextSeverityCategories, List filteredVulnerabilities,
String chartId, String filename, String title, ColorScheme centerDotColor) {
final Map countsPerSeverityCategory = new LinkedHashMap<>();
for (CvssSeverityRanges.SeverityRange range : this.securityPolicy.getCvssSeverityRanges().getRanges()) {
countsPerSeverityCategory.put(range, 0);
}
for (Vulnerability vulnerability : filteredVulnerabilities) {
countsPerSeverityCategory.put(contextSeverityCategories.get(vulnerability), countsPerSeverityCategory.getOrDefault(contextSeverityCategories.get(vulnerability), 0) + 1);
}
// JFreeChart
final DefaultPieDataset jFreeChartDataset = new DefaultPieDataset<>();
final JFreeChart jFreeChart = ChartFactory.createPieChart("", jFreeChartDataset, true, true, false);
final PiePlot> jFreeChartPlot = (PiePlot>) jFreeChart.getPlot();
JFreeChartUtils.applyDefaultForPieChartPlot(jFreeChartPlot);
jFreeChartPlot.setBackgroundPaint(new Color(255, 255, 255));
jFreeChart.setBackgroundPaint(new Color(255, 255, 255));
for (Map.Entry entry : countsPerSeverityCategory.entrySet()) {
JFreeChartUtils.addPieChartData(jFreeChartDataset, jFreeChartPlot, entry.getKey().getName(), entry.getValue(), entry.getKey().getColor().getColor());
}
// Chart.js
final DoughnutPieChartDataset chartJsChartDataset = new DoughnutPieChartDataset()
.addHoverOffset(3)
.setCutout("35%");
final DoughnutPieChartData chartJsChartData = new DoughnutPieChartData()
.addDataset(chartJsChartDataset);
final DoughnutChart chartJsChart = new DoughnutChart()
.setChartData(chartJsChartData)
.setChartOptions(this.createChartOptionsForOverviewCharts(title));
for (Map.Entry entry : countsPerSeverityCategory.entrySet()) {
chartJsChartDataset
.addData(entry.getValue())
.addBackgroundColor(entry.getKey().getColor().getColor());
chartJsChartData
.addLabels(entry.getKey().getName());
}
return new VulnerabilityAssessmentDashboard.GeneratedChartBuilder()
.setjFreeChart(jFreeChart)
.setjFreeChartName(filename)
.setChartJsChart(chartJsChart)
.setChartJsChartId(chartId)
.setCanvasOrParentTag(span().attr("width", "300").attr("height", "300").withStyle("width:300px;height:300px;display:inline-block;position:relative;").withClass("overview-chart-filterable").with(
canvas().withClass("chart-js-remove-display-block").withStyle("z-index: 2;position: inherit;"),
span().withClasses("overview-chart-circle", centerDotColor.getCssRootName())
))
.setCharJsChartJsVarName(chartId)
.createGeneratedChart();
}
private ChartOptions createChartOptionsForOverviewCharts(String title) {
return new ChartOptions()
.setResponsive(false)
.setMaintainAspectRatio(false)
.setLegend(new LegendOption().setAlign("top"))
.setTitle(new TitleOption().setDisplay(true).setText(title));
}
public final static Map STATUS_CATEGORY_COLOR_MAPPING = new HashMap() {{
put("in review", ColorScheme.PASTEL_BLUE.getColor());
put("reviewed", ColorScheme.STRONG_DARK_BLUE.getColor());
put("applicable", ColorScheme.STRONG_DARK_BLUE.getColor());
put("not applicable", ColorScheme.STRONG_LIGHT_GREEN.getColor());
put("insignificant", ColorScheme.PASTEL_GRAY.getColor());
put("void", ColorScheme.PASTEL_WHITE.getColor());
put("ineffective", ColorScheme.STRONG_GRAY.getColor());
put("affected", ColorScheme.STRONG_DARK_BLUE.getColor());
put("potentially affected", ColorScheme.PASTEL_BLUE.getColor());
put("potentially vulnerability", ColorScheme.PASTEL_BLUE.getColor());
put("not affected", ColorScheme.PASTEL_GRAY.getColor());
}};
private static Color getStatusCategoryColor(String statusCategory) {
return STATUS_CATEGORY_COLOR_MAPPING.getOrDefault(statusCategory.toLowerCase(), ColorScheme.PASTEL_WHITE.getColor());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy