From 125a4493929df0ca39741a2c180f39261c0dae99 Mon Sep 17 00:00:00 2001 From: Yan Wittmann Date: Mon, 7 Aug 2023 10:52:08 +0200 Subject: [PATCH 1/3] Added Assessment inventory merger that creates VMD contexts based on Asset information form multiple inventories Signed-off-by: ywittmann --- .../processor/model/AssetMetaData.java | 4 +- .../report/AssessmentInventoryMerger.java | 156 ++++++++++++++++++ .../processor/writer/InventoryWriter.java | 2 +- .../report/AssessmentInventoryMergerTest.java | 41 +++++ .../AbstractMultipleInputInventoriesMojo.java | 68 ++++++++ .../mojo/AssessmentInventoryMergeMojo.java | 43 +++++ .../inventory/mojo/InventoryMergeMojo.java | 54 +----- 7 files changed, 317 insertions(+), 51 deletions(-) create mode 100644 libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/report/AssessmentInventoryMerger.java create mode 100644 libraries/ae-inventory-processor/src/test/java/org/metaeffekt/core/inventory/processor/report/AssessmentInventoryMergerTest.java create mode 100644 plugins/ae-inventory-maven-plugin/src/main/java/org/metaeffekt/core/maven/inventory/mojo/AbstractMultipleInputInventoriesMojo.java create mode 100644 plugins/ae-inventory-maven-plugin/src/main/java/org/metaeffekt/core/maven/inventory/mojo/AssessmentInventoryMergeMojo.java diff --git a/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/model/AssetMetaData.java b/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/model/AssetMetaData.java index 824fb0b8..84b98868 100644 --- a/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/model/AssetMetaData.java +++ b/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/model/AssetMetaData.java @@ -35,7 +35,9 @@ public AssetMetaData() { * Core attributes to support license data. */ public enum Attribute implements AbstractModelBase.Attribute { - ASSET_ID("Asset Id"); + ASSET_ID("Asset Id"), + ASSESSMENT("Assessment"), + ; private String key; diff --git a/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/report/AssessmentInventoryMerger.java b/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/report/AssessmentInventoryMerger.java new file mode 100644 index 00000000..c1093460 --- /dev/null +++ b/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/report/AssessmentInventoryMerger.java @@ -0,0 +1,156 @@ +/* + * Copyright 2009-2022 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 org.metaeffekt.core.inventory.processor.report; + +import org.apache.commons.lang3.StringUtils; +import org.metaeffekt.core.inventory.processor.model.AssetMetaData; +import org.metaeffekt.core.inventory.processor.model.Inventory; +import org.metaeffekt.core.inventory.processor.reader.InventoryReader; +import org.metaeffekt.core.inventory.processor.writer.InventoryWriter; +import org.metaeffekt.core.util.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class AssessmentInventoryMerger { + + private final static Logger LOG = LoggerFactory.getLogger(AssessmentInventoryMerger.class); + + private List inputInventoryFiles; + private List inputInventories; + + public AssessmentInventoryMerger(List inputInventoryFiles, List inputInventories) { + this.inputInventoryFiles = inputInventoryFiles; + this.inputInventories = inputInventories; + } + + public AssessmentInventoryMerger() { + this.inputInventoryFiles = new ArrayList<>(); + this.inputInventories = new ArrayList<>(); + } + + public Inventory mergeInventories() throws IOException { + final Inventory outputInventory = new Inventory(); + + final List collectedInventories = new ArrayList<>(inputInventories); + final List inventoryFiles = collectInventoryFiles(); + LOG.info("Processing [{}] inventories", collectedInventories.size() + inventoryFiles.size()); + + { + final InventoryReader reader = new InventoryReader(); + for (File inventoryFile : inventoryFiles) { + collectedInventories.add(reader.readInventory(inventoryFile)); + } + } + + final Map> assessmentContextInventoryMap = new HashMap<>(); + final Map assessmentInventoryMap = new HashMap<>(); + + for (Inventory inputInventory : collectedInventories) { + final AssetMetaData assetMetaData = inputInventory.getAssetMetaData().get(0); + + // in this case the assessment context is the asset (assessment by asset case) + final String assetName = assetMetaData.get("Name"); + final String assessmentContext = formatNormalizedAssessmentContextName(assetName); + LOG.info("Processing inventory with asset [{}] and assessment context [{}]", assetName, assessmentContext); + + final List commonInventories = assessmentContextInventoryMap.computeIfAbsent(assessmentContext, a -> new ArrayList<>()); + final int inventoryDisplayIndex = commonInventories.size() + 1; + final String localUniqueAssessmentId = String.format("%s-%03d", assessmentContext, inventoryDisplayIndex); + + assetMetaData.set("Assessment", localUniqueAssessmentId); + assetMetaData.set("Name", assetName.toUpperCase()); + + commonInventories.add(inputInventory); + assessmentInventoryMap.put(localUniqueAssessmentId, inputInventory); + + // contribute asset metadata to output inventory + outputInventory.getAssetMetaData().add(assetMetaData); + } + + // iterate over each asset in the output inventory and add its respective vulnerabilities + for (AssetMetaData assetMetaData : outputInventory.getAssetMetaData()) { + final String localUniqueAssessmentId = assetMetaData.get(AssetMetaData.Attribute.ASSESSMENT); + if (StringUtils.isNotEmpty(localUniqueAssessmentId)) { + final Inventory singleInventory = assessmentInventoryMap.get(localUniqueAssessmentId); + if (singleInventory != null) { + outputInventory.getVulnerabilityMetaData(localUniqueAssessmentId).addAll(singleInventory.getVulnerabilityMetaData()); + } + } + } + + return outputInventory; + } + + protected String formatNormalizedAssessmentContextName(String assetName) { + String assessmentContext = assetName.toUpperCase().replace(" ", "_"); + final int maxAllowedChars = 25; + assessmentContext = assessmentContext.substring(0, Math.min(assessmentContext.length(), maxAllowedChars - InventoryWriter.VULNERABILITY_ASSESSMENT_WORKSHEET_PREFIX.length())); + + // remove trailing "_-" + while (assessmentContext.endsWith("_") || assessmentContext.endsWith("-")) { + assessmentContext = assessmentContext.substring(0, assessmentContext.length() - 1); + } + return assessmentContext; + } + + private List collectInventoryFiles() { + final List inventoryFiles = new ArrayList<>(); + + for (File inputInventory : inputInventoryFiles) { + if (inputInventory.isDirectory()) { + final String[] files = FileUtils.scanDirectoryForFiles(inputInventory, "*.xls"); + for (String file : files) { + inventoryFiles.add(new File(inputInventory, file)); + } + } else { + inventoryFiles.add(inputInventory); + } + } + + return inventoryFiles; + } + + public void addInputInventoryFile(File inputInventory) { + this.inputInventoryFiles.add(inputInventory); + } + + public void setInputInventoryFiles(List inputInventoryFiles) { + this.inputInventoryFiles = inputInventoryFiles; + } + + public List getInputInventoryFiles() { + return inputInventoryFiles; + } + + public void addInputInventory(Inventory inputInventory) { + this.inputInventories.add(inputInventory); + } + + public void setInputInventories(List inputInventories) { + this.inputInventories = inputInventories; + } + + public List getInputInventories() { + return inputInventories; + } +} diff --git a/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/writer/InventoryWriter.java b/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/writer/InventoryWriter.java index efd250b2..f0b66891 100644 --- a/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/writer/InventoryWriter.java +++ b/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/writer/InventoryWriter.java @@ -24,7 +24,7 @@ public class InventoryWriter extends AbstractXlsInventoryWriter { - private final Logger LOG = LoggerFactory.getLogger(getClass()); + private final static Logger LOG = LoggerFactory.getLogger(InventoryWriter.class); public static final String VULNERABILITY_ASSESSMENT_WORKSHEET_PREFIX = "Assessment-"; diff --git a/libraries/ae-inventory-processor/src/test/java/org/metaeffekt/core/inventory/processor/report/AssessmentInventoryMergerTest.java b/libraries/ae-inventory-processor/src/test/java/org/metaeffekt/core/inventory/processor/report/AssessmentInventoryMergerTest.java new file mode 100644 index 00000000..b9ed871c --- /dev/null +++ b/libraries/ae-inventory-processor/src/test/java/org/metaeffekt/core/inventory/processor/report/AssessmentInventoryMergerTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2009-2022 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 org.metaeffekt.core.inventory.processor.report; + +import org.junit.Test; +import org.metaeffekt.core.inventory.processor.model.Inventory; +import org.metaeffekt.core.inventory.processor.writer.InventoryWriter; + +import java.io.File; +import java.io.IOException; + +public class AssessmentInventoryMergerTest { + + @Test + public void sditMergedTest() throws IOException { + final AssessmentInventoryMerger merger = new AssessmentInventoryMerger(); + merger.addInputInventoryFile(new File("/Users/ywittmann/workspace/ref/inventories/00_Other/testing/assessment_merging_S-DIT-007-Merged-Inventories-DK/S-DIT-007-Merged-Inventories-DK/merged")); + + final Inventory merged = merger.mergeInventories(); + new InventoryWriter().writeInventory(merged, new File("/Users/ywittmann/workspace/ref/inventories/00_Other/testing/assessment_merging_S-DIT-007-Merged-Inventories-DK/S-DIT-007-Merged-Inventories-DK/merged.xls")); + } + + @Test + public void normalizeNameTest() { + AssessmentInventoryMerger merger = new AssessmentInventoryMerger(); + System.out.println(merger.formatNormalizedAssessmentContextName("Test-Name-longer-than-25-chars")); + } +} \ No newline at end of file diff --git a/plugins/ae-inventory-maven-plugin/src/main/java/org/metaeffekt/core/maven/inventory/mojo/AbstractMultipleInputInventoriesMojo.java b/plugins/ae-inventory-maven-plugin/src/main/java/org/metaeffekt/core/maven/inventory/mojo/AbstractMultipleInputInventoriesMojo.java new file mode 100644 index 00000000..861ad072 --- /dev/null +++ b/plugins/ae-inventory-maven-plugin/src/main/java/org/metaeffekt/core/maven/inventory/mojo/AbstractMultipleInputInventoriesMojo.java @@ -0,0 +1,68 @@ +package org.metaeffekt.core.maven.inventory.mojo; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Parameter; +import org.metaeffekt.core.util.FileUtils; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * This class is an abstract class that extends the AbstractProjectAwareConfiguredMojo class.
+ * It provides the common functionalities for handling multiple input inventories for maven plugins. + */ +public abstract class AbstractMultipleInputInventoriesMojo extends AbstractProjectAwareConfiguredMojo { + + /** + * The source inventory. + */ + @Parameter(required = false) + protected File sourceInventory; + + /** + * Alternatively to the sourceInventory parameter a directory can be specified. The inventory is scanned for files + * using sourceInventoryIncludes and sourceInventoryExcludes. + */ + @Parameter(required = false) + protected File sourceInventoryBaseDir; + + /** + * Includes based on sourceInventoryBaseDir. + */ + @Parameter(defaultValue = "**/*.xls") + protected String sourceInventoryIncludes; + + /** + * Excludes based on sourceInventoryBaseDir. + */ + @Parameter + protected String sourceInventoryExcludes; + + protected List collectSourceInventories() throws MojoExecutionException { + final List sourceInventories = new ArrayList<>(); + + if (sourceInventory != null) { + if (sourceInventory.exists() && sourceInventory.isFile()) { + sourceInventories.add(sourceInventory); + } else { + throw new MojoExecutionException("The parameter [sourceInventory] is set, but the file does not exist: " + + sourceInventory.getAbsolutePath()); + } + } + + if (sourceInventoryBaseDir != null) { + if (sourceInventoryBaseDir.exists() && sourceInventoryBaseDir.isDirectory()) { + final String[] sourceFiles = FileUtils.scanForFiles(sourceInventoryBaseDir, + sourceInventoryIncludes, sourceInventoryExcludes); + Arrays.stream(sourceFiles).forEach(f -> sourceInventories.add(new File(sourceInventoryBaseDir, f))); + } else { + throw new MojoExecutionException("The parameter [sourceInventoryBaseDir] parameter is set, but the directory does not exist: " + + sourceInventoryBaseDir.getAbsolutePath()); + } + } + + return sourceInventories; + } +} diff --git a/plugins/ae-inventory-maven-plugin/src/main/java/org/metaeffekt/core/maven/inventory/mojo/AssessmentInventoryMergeMojo.java b/plugins/ae-inventory-maven-plugin/src/main/java/org/metaeffekt/core/maven/inventory/mojo/AssessmentInventoryMergeMojo.java new file mode 100644 index 00000000..fbb2c1f4 --- /dev/null +++ b/plugins/ae-inventory-maven-plugin/src/main/java/org/metaeffekt/core/maven/inventory/mojo/AssessmentInventoryMergeMojo.java @@ -0,0 +1,43 @@ +package org.metaeffekt.core.maven.inventory.mojo; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.metaeffekt.core.inventory.processor.model.Inventory; +import org.metaeffekt.core.inventory.processor.report.AssessmentInventoryMerger; +import org.metaeffekt.core.inventory.processor.writer.InventoryWriter; + +import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +@Mojo(name = "merge-inventories-assessment", defaultPhase = LifecyclePhase.PREPARE_PACKAGE) +public class AssessmentInventoryMergeMojo extends AbstractMultipleInputInventoriesMojo { + + @Parameter(required = true) + protected File targetInventory; + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + try { + final List inputInventoryFiles = super.collectSourceInventories(); + + final AssessmentInventoryMerger merger = new AssessmentInventoryMerger(inputInventoryFiles, Collections.emptyList()); + final Inventory mergedInventory = merger.mergeInventories(); + + // create target directory if not existing yet + final File targetParentFile = this.targetInventory.getParentFile(); + if (targetParentFile != null && !this.targetInventory.exists()) { + targetParentFile.mkdirs(); + } + + // write inventory to target location + new InventoryWriter().writeInventory(mergedInventory, this.targetInventory); + } catch (IOException e) { + throw new MojoExecutionException(e.getMessage(), e); + } + } +} diff --git a/plugins/ae-inventory-maven-plugin/src/main/java/org/metaeffekt/core/maven/inventory/mojo/InventoryMergeMojo.java b/plugins/ae-inventory-maven-plugin/src/main/java/org/metaeffekt/core/maven/inventory/mojo/InventoryMergeMojo.java index df0a996b..4491b8f5 100644 --- a/plugins/ae-inventory-maven-plugin/src/main/java/org/metaeffekt/core/maven/inventory/mojo/InventoryMergeMojo.java +++ b/plugins/ae-inventory-maven-plugin/src/main/java/org/metaeffekt/core/maven/inventory/mojo/InventoryMergeMojo.java @@ -8,43 +8,19 @@ import org.metaeffekt.core.inventory.processor.model.Inventory; import org.metaeffekt.core.inventory.processor.reader.InventoryReader; import org.metaeffekt.core.inventory.processor.writer.InventoryWriter; -import org.metaeffekt.core.util.FileUtils; import java.io.File; import java.io.IOException; -import java.util.*; +import java.util.HashSet; +import java.util.List; +import java.util.Set; /** * Merges inventories. Reference inventories are usually the target inventory. Otherwise this Mojo is intended to * be applied to inventories from the extraction process, only. */ @Mojo(name = "merge-inventories", defaultPhase = LifecyclePhase.PREPARE_PACKAGE) -public class InventoryMergeMojo extends AbstractProjectAwareConfiguredMojo { - - /** - * The source inventory. - */ - @Parameter(required = false) - protected File sourceInventory; - - /** - * Alternatively to the sourceInventory parameter a directory can be specified. The inventory is scanned for files - * using sourceInventoryIncludes and sourceInventoryExcludes. - */ - @Parameter(required = false) - protected File sourceInventoryBaseDir; - - /** - * Includes based on sourceInventoryBaseDir. - */ - @Parameter(defaultValue = "**/*.xls") - protected String sourceInventoryIncludes; - - /** - * Excludes based on sourceInventoryBaseDir. - */ - @Parameter - protected String sourceInventoryExcludes; +public class InventoryMergeMojo extends AbstractMultipleInputInventoriesMojo { /** * Boolean indicating whether to include the default artifact excluded attributes. @@ -83,27 +59,7 @@ public class InventoryMergeMojo extends AbstractProjectAwareConfiguredMojo { public void execute() throws MojoExecutionException, MojoFailureException { try { - final List sourceInventories = new ArrayList<>(); - - if (sourceInventory != null) { - if (sourceInventory.exists() && sourceInventory.isFile()) { - sourceInventories.add(sourceInventory); - } else { - throw new MojoExecutionException("The parameter [sourceInventory] is set, but the file does not exist: " + - sourceInventory.getAbsolutePath()); - } - } - - if (sourceInventoryBaseDir != null) { - if (sourceInventoryBaseDir.exists() && sourceInventoryBaseDir.isDirectory()) { - final String[] sourceFiles = FileUtils.scanForFiles(sourceInventoryBaseDir, - sourceInventoryIncludes, sourceInventoryExcludes); - Arrays.stream(sourceFiles).forEach(f -> sourceInventories.add(new File(sourceInventoryBaseDir, f))); - } else { - throw new MojoExecutionException("The parameter [sourceInventoryBaseDir] parameter is set, but the directory does not exist: " + - sourceInventoryBaseDir.getAbsolutePath()); - } - } + final List sourceInventories = super.collectSourceInventories(); // if the target does not exist we initiate a new inventory final Inventory targetInventory = this.targetInventory.exists() ? From 45b2a8f04fab3e40d27312295bbc983de4d750d6 Mon Sep 17 00:00:00 2001 From: Yan Wittmann Date: Mon, 7 Aug 2023 11:39:13 +0200 Subject: [PATCH 2/3] Added test cases for assessment merger. Fixed macro for generating assessment report. Signed-off-by: ywittmann --- .../processor/model/AssetMetaData.java | 2 + .../report/AssessmentInventoryMerger.java | 30 +++-- .../report/AssessmentReportAdapter.java | 2 +- .../macros/assessment-report.vm | 1 - .../report/AssessmentInventoryMergerTest.java | 123 ++++++++++++++++-- 5 files changed, 138 insertions(+), 20 deletions(-) diff --git a/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/model/AssetMetaData.java b/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/model/AssetMetaData.java index 84b98868..e0af391e 100644 --- a/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/model/AssetMetaData.java +++ b/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/model/AssetMetaData.java @@ -36,6 +36,8 @@ public AssetMetaData() { */ public enum Attribute implements AbstractModelBase.Attribute { ASSET_ID("Asset Id"), + NAME("Name"), + VERSION("Version"), ASSESSMENT("Assessment"), ; diff --git a/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/report/AssessmentInventoryMerger.java b/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/report/AssessmentInventoryMerger.java index c1093460..2212b85f 100644 --- a/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/report/AssessmentInventoryMerger.java +++ b/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/report/AssessmentInventoryMerger.java @@ -26,10 +26,7 @@ import java.io.File; import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; public class AssessmentInventoryMerger { @@ -51,25 +48,38 @@ public AssessmentInventoryMerger() { public Inventory mergeInventories() throws IOException { final Inventory outputInventory = new Inventory(); - final List collectedInventories = new ArrayList<>(inputInventories); + final Map collectedInventories = new LinkedHashMap<>(); + inputInventories.forEach(i -> collectedInventories.put(i, null)); + final List inventoryFiles = collectInventoryFiles(); + LOG.info("Processing [{}] inventories", collectedInventories.size() + inventoryFiles.size()); { final InventoryReader reader = new InventoryReader(); for (File inventoryFile : inventoryFiles) { - collectedInventories.add(reader.readInventory(inventoryFile)); + collectedInventories.put(reader.readInventory(inventoryFile), inventoryFile); } } final Map> assessmentContextInventoryMap = new HashMap<>(); final Map assessmentInventoryMap = new HashMap<>(); - for (Inventory inputInventory : collectedInventories) { + for (Map.Entry inputInventoryWithFile : collectedInventories.entrySet()) { + final Inventory inputInventory = inputInventoryWithFile.getKey(); + final File inputInventoryFile = inputInventoryWithFile.getValue(); + + if (inputInventory.getAssetMetaData().size() != 1) { + throw new IllegalStateException("Inventory must contain exactly one asset meta data entry" + (inputInventoryFile != null ? " in file [" + inputInventoryFile.getAbsolutePath() + "]" : "")); + } + final AssetMetaData assetMetaData = inputInventory.getAssetMetaData().get(0); // in this case the assessment context is the asset (assessment by asset case) - final String assetName = assetMetaData.get("Name"); + final String assetName = assetMetaData.get(AssetMetaData.Attribute.NAME); + if (StringUtils.isEmpty(assetName)) { + throw new IllegalStateException("Asset name must not be empty on asset meta data" + (inputInventoryFile != null ? " in file [" + inputInventoryFile.getAbsolutePath() + "]" : "")); + } final String assessmentContext = formatNormalizedAssessmentContextName(assetName); LOG.info("Processing inventory with asset [{}] and assessment context [{}]", assetName, assessmentContext); @@ -77,8 +87,8 @@ public Inventory mergeInventories() throws IOException { final int inventoryDisplayIndex = commonInventories.size() + 1; final String localUniqueAssessmentId = String.format("%s-%03d", assessmentContext, inventoryDisplayIndex); - assetMetaData.set("Assessment", localUniqueAssessmentId); - assetMetaData.set("Name", assetName.toUpperCase()); + assetMetaData.set(AssetMetaData.Attribute.ASSESSMENT, localUniqueAssessmentId); + assetMetaData.set(AssetMetaData.Attribute.NAME, assetName.toUpperCase()); commonInventories.add(inputInventory); assessmentInventoryMap.put(localUniqueAssessmentId, inputInventory); diff --git a/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/report/AssessmentReportAdapter.java b/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/report/AssessmentReportAdapter.java index 64860e13..7c2b6dfc 100644 --- a/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/report/AssessmentReportAdapter.java +++ b/libraries/ae-inventory-processor/src/main/java/org/metaeffekt/core/inventory/processor/report/AssessmentReportAdapter.java @@ -69,7 +69,7 @@ public VulnerabilityCounts countVulnerabilities(AssetMetaData assetMetaData, boo break; } - boolean isAssessed = vulnerabilityMetaData.isStatus(STATUS_VALUE_APPLICABLE) || + final boolean isAssessed = vulnerabilityMetaData.isStatus(STATUS_VALUE_APPLICABLE) || vulnerabilityMetaData.isStatus(STATUS_VALUE_NOTAPPLICABLE) || vulnerabilityMetaData.isStatus(STATUS_VALUE_VOID); diff --git a/libraries/ae-inventory-processor/src/main/resources/META-INF/templates/en/assessment-report/macros/assessment-report.vm b/libraries/ae-inventory-processor/src/main/resources/META-INF/templates/en/assessment-report/macros/assessment-report.vm index a50c757d..236201d6 100644 --- a/libraries/ae-inventory-processor/src/main/resources/META-INF/templates/en/assessment-report/macros/assessment-report.vm +++ b/libraries/ae-inventory-processor/src/main/resources/META-INF/templates/en/assessment-report/macros/assessment-report.vm @@ -29,7 +29,6 @@ #foreach ($asset in $assets) #set($counts = $assessmentReportAdapter.countVulnerabilities($asset, $useModifiedSeverity)) -$counts $report.xmlEscapeString($asset.get("Name")) $counts.criticalCounter diff --git a/libraries/ae-inventory-processor/src/test/java/org/metaeffekt/core/inventory/processor/report/AssessmentInventoryMergerTest.java b/libraries/ae-inventory-processor/src/test/java/org/metaeffekt/core/inventory/processor/report/AssessmentInventoryMergerTest.java index b9ed871c..7c358bfe 100644 --- a/libraries/ae-inventory-processor/src/test/java/org/metaeffekt/core/inventory/processor/report/AssessmentInventoryMergerTest.java +++ b/libraries/ae-inventory-processor/src/test/java/org/metaeffekt/core/inventory/processor/report/AssessmentInventoryMergerTest.java @@ -15,27 +15,134 @@ */ package org.metaeffekt.core.inventory.processor.report; +import org.assertj.core.api.Assertions; import org.junit.Test; +import org.metaeffekt.core.inventory.processor.model.AssetMetaData; import org.metaeffekt.core.inventory.processor.model.Inventory; -import org.metaeffekt.core.inventory.processor.writer.InventoryWriter; +import org.metaeffekt.core.inventory.processor.model.VulnerabilityMetaData; -import java.io.File; import java.io.IOException; public class AssessmentInventoryMergerTest { @Test - public void sditMergedTest() throws IOException { + public void mergeTwoInventoriesSuccessfullyTest() throws IOException { final AssessmentInventoryMerger merger = new AssessmentInventoryMerger(); - merger.addInputInventoryFile(new File("/Users/ywittmann/workspace/ref/inventories/00_Other/testing/assessment_merging_S-DIT-007-Merged-Inventories-DK/S-DIT-007-Merged-Inventories-DK/merged")); + + { + final Inventory inputInventory = new Inventory(); + merger.addInputInventory(inputInventory); + + final AssetMetaData amd = new AssetMetaData(); + inputInventory.getAssetMetaData().add(amd); + amd.set(AssetMetaData.Attribute.ASSET_ID, "some id"); + amd.set(AssetMetaData.Attribute.NAME, "some id"); + + final VulnerabilityMetaData vmd = new VulnerabilityMetaData(); + inputInventory.getVulnerabilityMetaData().add(vmd); + vmd.set(VulnerabilityMetaData.Attribute.NAME, "CVE-2018-1234"); + } + + { + final Inventory inputInventory = new Inventory(); + merger.addInputInventory(inputInventory); + + final AssetMetaData amd = new AssetMetaData(); + inputInventory.getAssetMetaData().add(amd); + amd.set(AssetMetaData.Attribute.ASSET_ID, "some other id"); + amd.set(AssetMetaData.Attribute.NAME, "some other id"); + + final VulnerabilityMetaData vmd = new VulnerabilityMetaData(); + inputInventory.getVulnerabilityMetaData().add(vmd); + vmd.set(VulnerabilityMetaData.Attribute.NAME, "CVE-2020-4321"); + } + + final Inventory merged = merger.mergeInventories(); + + Assertions.assertThat(merged.getAssetMetaData()).hasSize(2); + Assertions.assertThat(merged.getVulnerabilityMetaData("SOME_ID-001")).hasSize(1); + Assertions.assertThat(merged.getVulnerabilityMetaData("SOME_OTHER_ID-001")).hasSize(1); + Assertions.assertThat(merged.getVulnerabilityMetaData("SOME_ID-001").iterator().next().get(VulnerabilityMetaData.Attribute.NAME)).isEqualTo("CVE-2018-1234"); + Assertions.assertThat(merged.getVulnerabilityMetaData("SOME_OTHER_ID-001").iterator().next().get(VulnerabilityMetaData.Attribute.NAME)).isEqualTo("CVE-2020-4321"); + } + + @Test + public void mergeTwoInventoriesFailReasonsTest() { + final AssessmentInventoryMerger merger = new AssessmentInventoryMerger(); + + final Inventory inputInventory = new Inventory(); + merger.addInputInventory(inputInventory); + + final VulnerabilityMetaData vmd = new VulnerabilityMetaData(); + inputInventory.getVulnerabilityMetaData().add(vmd); + vmd.set(VulnerabilityMetaData.Attribute.NAME, "CVE-2018-1234"); + + Assertions.assertThatThrownBy(merger::mergeInventories) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("exactly one asset"); + + final AssetMetaData amd = new AssetMetaData(); + inputInventory.getAssetMetaData().add(amd); + + Assertions.assertThatThrownBy(merger::mergeInventories) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("name must not be empty"); + + inputInventory.getAssetMetaData().add(amd); + amd.set(AssetMetaData.Attribute.ASSET_ID, "some id"); + amd.set(AssetMetaData.Attribute.NAME, "some id"); + + Assertions.assertThatThrownBy(merger::mergeInventories) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("exactly one asset"); + } + + @Test + public void mergeInventoriesWithDuplicateAssetsTest() throws IOException { + final AssessmentInventoryMerger merger = new AssessmentInventoryMerger(); + + // First inventory + { + final Inventory inputInventory = new Inventory(); + merger.addInputInventory(inputInventory); + + final AssetMetaData amd = new AssetMetaData(); + inputInventory.getAssetMetaData().add(amd); + amd.set(AssetMetaData.Attribute.ASSET_ID, "duplicate id"); + amd.set(AssetMetaData.Attribute.NAME, "duplicate id"); + + final VulnerabilityMetaData vmd = new VulnerabilityMetaData(); + inputInventory.getVulnerabilityMetaData().add(vmd); + vmd.set(VulnerabilityMetaData.Attribute.NAME, "CVE-2018-1234"); + } + + // Second inventory with duplicate asset + { + final Inventory inputInventory = new Inventory(); + merger.addInputInventory(inputInventory); + + final AssetMetaData amd = new AssetMetaData(); + inputInventory.getAssetMetaData().add(amd); + amd.set(AssetMetaData.Attribute.ASSET_ID, "duplicate id"); + amd.set(AssetMetaData.Attribute.NAME, "duplicate id"); + + final VulnerabilityMetaData vmd = new VulnerabilityMetaData(); + inputInventory.getVulnerabilityMetaData().add(vmd); + vmd.set(VulnerabilityMetaData.Attribute.NAME, "CVE-2020-4321"); + } final Inventory merged = merger.mergeInventories(); - new InventoryWriter().writeInventory(merged, new File("/Users/ywittmann/workspace/ref/inventories/00_Other/testing/assessment_merging_S-DIT-007-Merged-Inventories-DK/S-DIT-007-Merged-Inventories-DK/merged.xls")); + + Assertions.assertThat(merged.getAssetMetaData()).hasSize(2); + Assertions.assertThat(merged.getVulnerabilityMetaData("DUPLICATE_ID-001")).hasSize(1); + Assertions.assertThat(merged.getVulnerabilityMetaData("DUPLICATE_ID-002")).hasSize(1); + Assertions.assertThat(merged.getVulnerabilityMetaData("DUPLICATE_ID-001").iterator().next().get(VulnerabilityMetaData.Attribute.NAME)).isEqualTo("CVE-2018-1234"); + Assertions.assertThat(merged.getVulnerabilityMetaData("DUPLICATE_ID-002").iterator().next().get(VulnerabilityMetaData.Attribute.NAME)).isEqualTo("CVE-2020-4321"); } @Test public void normalizeNameTest() { - AssessmentInventoryMerger merger = new AssessmentInventoryMerger(); - System.out.println(merger.formatNormalizedAssessmentContextName("Test-Name-longer-than-25-chars")); + final AssessmentInventoryMerger merger = new AssessmentInventoryMerger(); + Assertions.assertThat(merger.formatNormalizedAssessmentContextName("Test-Name-longer-than-25-chars")).isEqualTo("TEST-NAME-LONG"); } -} \ No newline at end of file +} From 9888a555c10d58826150b85a106b311a26a0d195 Mon Sep 17 00:00:00 2001 From: Yan Wittmann Date: Mon, 7 Aug 2023 13:52:41 +0200 Subject: [PATCH 3/3] Removed comments Signed-off-by: ywittmann --- .../processor/report/AssessmentInventoryMergerTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/ae-inventory-processor/src/test/java/org/metaeffekt/core/inventory/processor/report/AssessmentInventoryMergerTest.java b/libraries/ae-inventory-processor/src/test/java/org/metaeffekt/core/inventory/processor/report/AssessmentInventoryMergerTest.java index 7c358bfe..02a4095a 100644 --- a/libraries/ae-inventory-processor/src/test/java/org/metaeffekt/core/inventory/processor/report/AssessmentInventoryMergerTest.java +++ b/libraries/ae-inventory-processor/src/test/java/org/metaeffekt/core/inventory/processor/report/AssessmentInventoryMergerTest.java @@ -101,7 +101,6 @@ public void mergeTwoInventoriesFailReasonsTest() { public void mergeInventoriesWithDuplicateAssetsTest() throws IOException { final AssessmentInventoryMerger merger = new AssessmentInventoryMerger(); - // First inventory { final Inventory inputInventory = new Inventory(); merger.addInputInventory(inputInventory); @@ -116,7 +115,6 @@ public void mergeInventoriesWithDuplicateAssetsTest() throws IOException { vmd.set(VulnerabilityMetaData.Attribute.NAME, "CVE-2018-1234"); } - // Second inventory with duplicate asset { final Inventory inputInventory = new Inventory(); merger.addInputInventory(inputInventory);