com.metaeffekt.artifact.enrichment.matching.NvdVulnerabilitiesFromCpeEnrichment Maven / Gradle / Ivy
/*
* 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.matching;
import com.metaeffekt.artifact.analysis.utils.LazySupplier;
import com.metaeffekt.artifact.enrichment.configurations.NvdFromCpeCveFromCpeEnrichmentConfiguration;
import com.metaeffekt.mirror.contents.base.VulnerabilityContextInventory;
import com.metaeffekt.mirror.contents.store.VulnerabilityTypeIdentifier;
import com.metaeffekt.mirror.contents.store.VulnerabilityTypeStore;
import com.metaeffekt.mirror.download.documentation.DocRelevantMethods;
import com.metaeffekt.mirror.download.documentation.EnricherMetadata;
import com.metaeffekt.mirror.download.documentation.InventoryEnrichmentPhase;
import com.metaeffekt.mirror.query.NvdCveIndexQuery;
import lombok.extern.slf4j.Slf4j;
import org.metaeffekt.core.inventory.processor.model.Artifact;
import org.metaeffekt.core.inventory.processor.model.Inventory;
import java.io.File;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* The NVD CVE from CPE enrichment step is responsible for linking vulnerabilities from the National Vulnerability
* Database (NVD) to specific products (artifacts) identified in an inventory.
* The process works by utilizing Common Platform Enumerations (CPEs) to identify which vulnerabilities (CVE entries)
* affect each product based on its known CPEs.
*
* What Happens During This Step
* When this step begins, the system processes each product (artifact) in the inventory by first identifying its CPEs.
* These CPEs are derived using the product's attributes and version information.
* In case the CPE version does not match the artifact version, an algorithm is used to combine them in a meaningful way
* or pick one of the two as the query version.
* The CPEs are then used as queries to look up vulnerabilities from the NVD:
* For each product, the system performs a query to retrieve a list of vulnerabilities that specifically match the
* product's CPE and version.
* Once the query is executed, the system retrieves vulnerabilities and performs a secondary, more detailed version
* comparison match against the product/CPE version to ensure only accurate matches are considered.
* Along with this, the system also stores the CPEs and other data like version ranges that led to each vulnerability
* match as metadata for the product, allowing for traceability in later steps.
* Finally, all identified vulnerabilities are stored in the inventory, linked to their respective products.
*/
@Slf4j
@EnricherMetadata(
name = "NVD CVE from CPE", phase = InventoryEnrichmentPhase.VULNERABILITY_MATCHING,
intermediateFileSuffix = "nvd-cve-from-cpe", mavenPropertyName = "nvdMatchCveFromCpeEnrichment"
)
public class NvdVulnerabilitiesFromCpeEnrichment extends VulnerabilitiesFromCpeEnrichment {
protected LazySupplier vulnerabilityQuery;
public NvdVulnerabilitiesFromCpeEnrichment(File baseMirrorDirectory) {
super(new NvdFromCpeCveFromCpeEnrichmentConfiguration());
this.vulnerabilityQuery = new LazySupplier<>(() -> new NvdCveIndexQuery(baseMirrorDirectory));
}
@Override
public NvdFromCpeCveFromCpeEnrichmentConfiguration getConfiguration() {
return (NvdFromCpeCveFromCpeEnrichmentConfiguration) super.configuration;
}
@Override
protected NvdCveIndexQuery getVulnerabilityQuery() {
return vulnerabilityQuery.get();
}
@Override
protected VulnerabilityTypeIdentifier> getVulnerabilitySource() {
return VulnerabilityTypeStore.CVE;
}
@Override
@DocRelevantMethods({"VulnerabilitiesFromCpeEnrichment#enrichVulnerabilitiesForCpe", "VulnerabilitiesFromCpeEnrichment#queryVulnerabilitiesForArtifact"})
protected void performEnrichment(Inventory inventory) {
final AtomicInteger progress = new AtomicInteger(0);
final List artifacts = inventory.getArtifacts();
final VulnerabilityContextInventory vInventory = VulnerabilityContextInventory.fromInventory(inventory);
for (final Artifact artifact : artifacts) {
super.executor.submit(() -> {
final int currentElement = progress.incrementAndGet();
if (currentElement % 100 == 0 && currentElement > 0) {
log.info("Collecting CVE from CPE for artifact [{} / {}]", currentElement, inventory.getArtifacts().size());
}
super.enrichVulnerabilitiesForCpe(vInventory, artifact);
});
}
super.executor.setSize(16);
super.executor.setLogEveryPercent(10);
super.executor.start();
try {
executor.join();
} catch (InterruptedException e) {
throw new RuntimeException("Failed to join executor while waiting for NVD CVE from CPE enrichment to finish.", e);
}
vInventory.writeBack();
}
}