From bae562e60351d5e53dc021fd9bc0b080dd226136 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Thu, 14 Sep 2023 23:36:21 +0100 Subject: [PATCH 01/64] Read OVAL data sources from a configuration file --- .../src/com/suse/oval/config/OVALConfig.java | 38 ++++++ .../suse/oval/config/OVALConfigLoader.java | 23 ++++ .../config/OVALDistributionSourceInfo.java | 35 ++++++ .../com/suse/oval/config/OVALSourceInfo.java | 37 ++++++ java/code/src/com/suse/oval/oval.config.json | 112 ++++++++++++++++++ 5 files changed, 245 insertions(+) create mode 100644 java/code/src/com/suse/oval/config/OVALConfig.java create mode 100644 java/code/src/com/suse/oval/config/OVALConfigLoader.java create mode 100644 java/code/src/com/suse/oval/config/OVALDistributionSourceInfo.java create mode 100644 java/code/src/com/suse/oval/config/OVALSourceInfo.java create mode 100644 java/code/src/com/suse/oval/oval.config.json diff --git a/java/code/src/com/suse/oval/config/OVALConfig.java b/java/code/src/com/suse/oval/config/OVALConfig.java new file mode 100644 index 000000000000..40d57409d372 --- /dev/null +++ b/java/code/src/com/suse/oval/config/OVALConfig.java @@ -0,0 +1,38 @@ +package com.suse.oval.config; + +import com.google.gson.annotations.SerializedName; +import com.suse.oval.OsFamily; + +import java.util.Map; +import java.util.Optional; + +public class OVALConfig { + @SerializedName("sources") + private Map sources; + + public OVALConfig() { + } + + public Map getSources() { + return sources; + } + + public void setSources(Map sources) { + this.sources = sources; + } + + public Optional lookupSourceInfo(OsFamily osFamily, String version) { + OVALDistributionSourceInfo distributionSources = sources.get(osFamily); + if (distributionSources != null) { + return distributionSources.getVersionSourceInfo(version); + } + return Optional.empty(); + } + + @Override + public String toString() { + return "OVALConfig{" + + "sources=" + sources + + '}'; + } +} diff --git a/java/code/src/com/suse/oval/config/OVALConfigLoader.java b/java/code/src/com/suse/oval/config/OVALConfigLoader.java new file mode 100644 index 000000000000..0f3d9c47e7c4 --- /dev/null +++ b/java/code/src/com/suse/oval/config/OVALConfigLoader.java @@ -0,0 +1,23 @@ +package com.suse.oval.config; + +import static com.suse.utils.Json.GSON; + +import com.redhat.rhn.testing.TestUtils; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; + +public class OVALConfigLoader { + public static OVALConfig load() { + URL jsonConfigFile; + try { + jsonConfigFile = TestUtils.findTestData("/com/suse/oval/oval.config.json"); + return GSON.fromJson(new FileReader(new File(jsonConfigFile.toURI())), OVALConfig.class); + } catch (ClassNotFoundException | IOException | URISyntaxException e) { + throw new RuntimeException(e); + } + } +} diff --git a/java/code/src/com/suse/oval/config/OVALDistributionSourceInfo.java b/java/code/src/com/suse/oval/config/OVALDistributionSourceInfo.java new file mode 100644 index 000000000000..887a8b53e1d2 --- /dev/null +++ b/java/code/src/com/suse/oval/config/OVALDistributionSourceInfo.java @@ -0,0 +1,35 @@ +package com.suse.oval.config; + +import com.google.gson.annotations.SerializedName; + +import java.util.Collections; +import java.util.Map; +import java.util.Optional; + +public class OVALDistributionSourceInfo { + @SerializedName("content") + public Map content; + + public OVALDistributionSourceInfo() { + + } + + public Map getContent() { + return content == null ? Collections.emptyMap() : content; + } + + public void setContent(Map content) { + this.content = content; + } + + public Optional getVersionSourceInfo(String version) { + return Optional.ofNullable(getContent().get(version)); + } + + @Override + public String toString() { + return "OVALDistributionSourceInfo{" + + "content=" + content + + '}'; + } +} diff --git a/java/code/src/com/suse/oval/config/OVALSourceInfo.java b/java/code/src/com/suse/oval/config/OVALSourceInfo.java new file mode 100644 index 000000000000..adde02e1baa3 --- /dev/null +++ b/java/code/src/com/suse/oval/config/OVALSourceInfo.java @@ -0,0 +1,37 @@ +package com.suse.oval.config; + +import com.google.gson.annotations.SerializedName; + +public class OVALSourceInfo { + @SerializedName("vulnerability") + private String vulnerabilitiesInfoSource; + @SerializedName("patch") + private String patchInfoSource; + + public OVALSourceInfo() { + } + + public String getVulnerabilitiesInfoSource() { + return vulnerabilitiesInfoSource; + } + + public void setVulnerabilitiesInfoSource(String vulnerabilitiesInfoSource) { + this.vulnerabilitiesInfoSource = vulnerabilitiesInfoSource; + } + + public String getPatchInfoSource() { + return patchInfoSource; + } + + public void setPatchInfoSource(String patchInfoSource) { + this.patchInfoSource = patchInfoSource; + } + + @Override + public String toString() { + return "OVALSourceInfo{" + + "vulnerabilitiesInfoSource='" + vulnerabilitiesInfoSource + '\'' + + ", patchInfoSource='" + patchInfoSource + '\'' + + '}'; + } +} diff --git a/java/code/src/com/suse/oval/oval.config.json b/java/code/src/com/suse/oval/oval.config.json new file mode 100644 index 000000000000..10cb07e89bf1 --- /dev/null +++ b/java/code/src/com/suse/oval/oval.config.json @@ -0,0 +1,112 @@ +{ + "sources": { + "openSUSE_LEAP": { + "content": { + "15.3": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.15.3-affected.xml.gz", + "patch": "" + }, + "15.4": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.15.4-affected.xml.gz", + "patch": "" + }, + "15.5": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.15.5-affected.xml.gz", + "patch": "" + } + } + }, + "SUSE_LINUX_ENTERPRISE_SERVER": { + "content": { + "10": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.server.10-affected.xml.gz", + "patch": "" + }, + "11": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.server.11-affected.xml.gz", + "patch": "" + }, + "12": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.server.12-affected.xml.gz", + "patch": "" + }, + "15": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.server.15-affected.xml.gz", + "patch": "" + } + } + }, + "SUSE_LINUX_ENTERPRISE_DESKTOP": { + "content": { + "10": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.desktop.10.xml.gz", + "patch": "" + }, + "11": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.desktop.11.xml.gz", + "patch": "" + }, + "12": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.desktop.12-affected.xml.gz", + "patch": "" + }, + "15": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.desktop.15-affected.xml.gz", + "patch": "" + } + } + }, + "UBUNTU": { + "content": { + "18.04": { + "vulnerability": "https://security-metadata.canonical.com/oval/com.ubuntu.bionic.cve.oval.xml.bz2", + "patch": "" + }, + "20.04": { + "vulnerability": "https://security-metadata.canonical.com/oval/com.ubuntu.focal.cve.oval.xml.bz2", + "patch": "" + }, + "22.04": { + "vulnerability": "https://security-metadata.canonical.com/oval/com.ubuntu.jammy.cve.oval.xml.bz2", + "patch": "" + } + } + }, + "REDHAT_ENTERPRISE_LINUX": { + "content": { + "7": { + "vulnerability": "https://www.redhat.com/security/data/oval/v2/RHEL7/rhel-7-including-unpatched.oval.xml.bz2", + "patch": "" + }, + "8": { + "vulnerability": "https://www.redhat.com/security/data/oval/v2/RHEL8/rhel-8-including-unpatched.oval.xml.bz2", + "patch": "" + }, + "9": { + "vulnerability": "https://www.redhat.com/security/data/oval/v2/RHEL9/rhel-9-including-unpatched.oval.xml.bz2", + "patch": "" + }, + "10": { + "vulnerability": "https://www.redhat.com/security/data/oval/v2/RHEL10/rhel-10-including-unpatched.oval.xml.bz2", + "patch": "" + } + } + }, + "DEBIAN": { + "content": { + "10": { + "vulnerability": "https://www.debian.org/security/oval/oval-definitions-buster.xml.bz2", + "patch": "" + }, + "11": { + "vulnerability": "https://www.debian.org/security/oval/oval-definitions-bullseye.xml.bz2", + "patch": "" + }, + "12": { + "vulnerability": "https://www.debian.org/security/oval/oval-definitions-bookworm.xml.bz2", + "patch": "" + } + } + } + } +} \ No newline at end of file From 01aeecb94dabd5d599584057510bf80e9d0bcfd1 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Thu, 14 Sep 2023 23:38:26 +0100 Subject: [PATCH 02/64] Implement the downloading of OVALs based on the config file --- .../ovaldownloader/OVALCompressionMethod.java | 14 ++ .../ovaldownloader/OVALDownloadResult.java | 26 ++++ .../oval/ovaldownloader/OVALDownloader.java | 125 ++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 java/code/src/com/suse/oval/ovaldownloader/OVALCompressionMethod.java create mode 100644 java/code/src/com/suse/oval/ovaldownloader/OVALDownloadResult.java create mode 100644 java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java diff --git a/java/code/src/com/suse/oval/ovaldownloader/OVALCompressionMethod.java b/java/code/src/com/suse/oval/ovaldownloader/OVALCompressionMethod.java new file mode 100644 index 000000000000..722445374ce0 --- /dev/null +++ b/java/code/src/com/suse/oval/ovaldownloader/OVALCompressionMethod.java @@ -0,0 +1,14 @@ +package com.suse.oval.ovaldownloader; + +public enum OVALCompressionMethod { + GZIP(".gz"), NOT_COMPRESSED(".xml"), BZIP2(".bz2"); + private final String extension; + + OVALCompressionMethod(String extension) { + this.extension = extension; + } + + String extension() { + return extension; + } +} diff --git a/java/code/src/com/suse/oval/ovaldownloader/OVALDownloadResult.java b/java/code/src/com/suse/oval/ovaldownloader/OVALDownloadResult.java new file mode 100644 index 000000000000..ec42e1bfd710 --- /dev/null +++ b/java/code/src/com/suse/oval/ovaldownloader/OVALDownloadResult.java @@ -0,0 +1,26 @@ +package com.suse.oval.ovaldownloader; + +import java.io.File; +import java.util.Optional; + +public class OVALDownloadResult { + private File vulnerabilityFile; + private File patchFile; + + + public Optional getVulnerabilityFile() { + return Optional.ofNullable(vulnerabilityFile); + } + + public Optional getPatchFile() { + return Optional.ofNullable(patchFile); + } + + public void setVulnerabilityFile(File vulnerabilityFile) { + this.vulnerabilityFile = vulnerabilityFile; + } + + public void setPatchFile(File patchFile) { + this.patchFile = patchFile; + } +} diff --git a/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java b/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java new file mode 100644 index 000000000000..cd78ce62f771 --- /dev/null +++ b/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java @@ -0,0 +1,125 @@ +package com.suse.oval.ovaldownloader; + +import com.suse.oval.OsFamily; +import com.suse.oval.config.OVALConfig; +import com.suse.oval.config.OVALSourceInfo; + +import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.StringUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Objects; +import java.util.Optional; +import java.util.zip.GZIPInputStream; + +public class OVALDownloader { + private static final String DOWNLOAD_PATH = "/var/log/rhn/ovals/"; + private final OVALConfig config; + + public OVALDownloader(OVALConfig config) { + this.config = config; + } + + public OVALDownloadResult download(OsFamily osFamily, String osVersion) throws IOException { + Optional sourceInfoOpt = config.lookupSourceInfo(osFamily, osVersion); + if (sourceInfoOpt.isEmpty()) { + throw new IllegalArgumentException( + String.format( + "OVAL sources for '%s' '%s' is not configured. Please ensure OVAL is configured correctly oval.config.json", + osFamily, osVersion)); + } + + return doDownload(sourceInfoOpt.get()); + } + + public OVALDownloadResult doDownload(OVALSourceInfo sourceInfo) + throws IOException { + OVALDownloadResult result = new OVALDownloadResult(); + + String vulnerabilityInfoSource = sourceInfo.getVulnerabilitiesInfoSource(); + String patchInfoSource = sourceInfo.getPatchInfoSource(); + + if (StringUtils.isNotBlank(vulnerabilityInfoSource)) { + File vulnerabilityFile = downloadOVALFile(vulnerabilityInfoSource); + result.setVulnerabilityFile(vulnerabilityFile); + } + + if (StringUtils.isNotBlank(patchInfoSource)) { + File patchFile = downloadOVALFile(patchInfoSource); + result.setPatchFile(patchFile); + } + + return result; + } + + private File downloadOVALFile(String vulnerabilityInfoSource) throws IOException { + URL vulnerabilityInfoURL = new URL(vulnerabilityInfoSource); + String vulnerabilityInfoOVALFilename = FilenameUtils.getName(vulnerabilityInfoURL.getPath()); + File vulnerabilityFile = + new File(DOWNLOAD_PATH + vulnerabilityInfoOVALFilename); + // Start downloading + FileUtils.copyURLToFile(vulnerabilityInfoURL, vulnerabilityFile, 10_000, 10_000); + + return decompressIfNeeded(vulnerabilityFile); + } + + private File decompressIfNeeded(File file) { + OVALCompressionMethod compressionMethod = getCompressionMethod(file.getName()); + File uncompressedOVALFile; + if (compressionMethod == OVALCompressionMethod.BZIP2) { + uncompressedOVALFile = new File(file.getPath().replace(compressionMethod.extension(), "")); + decompressBzip2(file, uncompressedOVALFile); + } else if (compressionMethod == OVALCompressionMethod.GZIP) { + uncompressedOVALFile = new File(file.getPath().replace(compressionMethod.extension(), "")); + decompressGzip(file, uncompressedOVALFile); + } else if (compressionMethod == OVALCompressionMethod.NOT_COMPRESSED) { + uncompressedOVALFile = file; + } else { + throw new IllegalStateException("Unable to decompress file: " + file.getPath()); + } + + return uncompressedOVALFile; + } + + public OVALCompressionMethod getCompressionMethod(String filename) { + Objects.requireNonNull(filename); + + if (filename.endsWith(".bz2")) { + return OVALCompressionMethod.BZIP2; + } else if (filename.endsWith("gz")) { + return OVALCompressionMethod.GZIP; + } else if (filename.endsWith(".xml")) { + return OVALCompressionMethod.NOT_COMPRESSED; + } else { + throw new IllegalStateException("OVAL file compressed with an unknown compression method"); + } + } + + /** + * Decompress the GZIP {@code archive} into {@code target} file. + */ + private static void decompressGzip(File archive, File target) { + try (GZIPInputStream gis = new GZIPInputStream(new FileInputStream(archive))) { + FileUtils.copyToFile(gis, target); + } catch (IOException e) { + throw new RuntimeException("Failed to decompress GZIP archive", e); + } + } + + /** + * Decompress the BZIP2 {@code archive} into {@code target} file. + */ + private static void decompressBzip2(File archive, File target) { + try (InputStream inputStream = new BZip2CompressorInputStream(new FileInputStream(archive))) { + FileUtils.copyToFile(inputStream, target); + } catch (IOException e) { + throw new RuntimeException("Failed to decompress BZIP2 archive", e); + } + } +} From 44ec0e44019fb5471196dde0e872ba6d93f25d8b Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Thu, 14 Sep 2023 23:39:01 +0100 Subject: [PATCH 03/64] Add taskomatic task for syncing OVAL data --- .../manager/audit/CVEAuditManagerOVAL.java | 83 +++++++++++++++++++ .../rhn/taskomatic/task/OVALDataSync.java | 26 ++++++ schema/spacewalk/common/data/rhnTaskoTask.sql | 3 + .../003-oval-taskomatic.sql | 52 ++++++++++++ 4 files changed, 164 insertions(+) create mode 100644 java/code/src/com/redhat/rhn/taskomatic/task/OVALDataSync.java create mode 100644 schema/spacewalk/upgrade/susemanager-schema-4.4.6-to-susemanager-schema-4.4.7/003-oval-taskomatic.sql diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java index 91d07e944849..84bfe33d5b83 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java @@ -25,11 +25,21 @@ import com.suse.oval.OVALCachingFactory; import com.suse.oval.ShallowSystemPackage; + +import com.suse.oval.OVALCleaner; +import com.suse.oval.OsFamily; +import com.suse.oval.OvalParser; +import com.suse.oval.config.OVALConfigLoader; +import com.suse.oval.ovaldownloader.OVALDownloadResult; +import com.suse.oval.ovaldownloader.OVALDownloader; +import com.suse.oval.ovaltypes.OvalRootType; import com.suse.oval.vulnerablepkgextractor.VulnerablePackage; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; @@ -298,4 +308,77 @@ public static List listImagesByPatchStatus(User user, public static void populateCVEChannels() { CVEAuditManager.populateCVEChannels(); } + + static List productsToSync = new ArrayList<>(); + static { + /*productsToSync.add(new OVALProduct(OsFamily.openSUSE_LEAP, "15.4"));*/ + productsToSync.add(new OVALProduct(OsFamily.openSUSE_LEAP, "15.3")); + productsToSync.add(new OVALProduct(OsFamily.REDHAT_ENTERPRISE_LINUX, "9")); + } + public static void syncOVAL() { + OVALDownloader ovalDownloader = new OVALDownloader(OVALConfigLoader.load()); + for (OVALProduct product : productsToSync) { + LOG.warn("Downloading OVAL for {} {}", product.getOsFamily(), product.getOsVersion()); + OVALDownloadResult downloadResult; + try { + downloadResult = ovalDownloader.download(product.getOsFamily(), product.getOsVersion()); + } + catch (IOException e) { + throw new RuntimeException("Failed to download OVAL data", e); + } + LOG.warn("Downloading finished"); + + LOG.warn("OVAL vulnerability file: " + + downloadResult.getVulnerabilityFile().map(File::getAbsoluteFile).orElse(null)); + LOG.warn("OVAL patch file: " + downloadResult.getPatchFile().map(File::getAbsoluteFile).orElse(null)); + + downloadResult.getVulnerabilityFile().ifPresent(ovalVulnerabilityFile -> { + OvalParser ovalParser = new OvalParser(); + OvalRootType ovalRoot = ovalParser.parse(ovalVulnerabilityFile); + + LOG.warn("Saving Vulnerability OVAL for {} {}", product.getOsFamily(), product.getOsVersion()); + + OVALCleaner.cleanup(ovalRoot, product.getOsFamily(), product.getOsVersion()); + OVALCachingFactory.savePlatformsVulnerablePackages(ovalRoot); + }); + + downloadResult.getPatchFile().ifPresent(patchFile -> { + OvalParser ovalParser = new OvalParser(); + OvalRootType ovalRoot = ovalParser.parse(patchFile); + + LOG.warn("Saving Patch OVAL for {} {}", product.getOsFamily(), product.getOsVersion()); + + OVALCleaner.cleanup(ovalRoot, product.getOsFamily(), product.getOsVersion()); + OVALCachingFactory.savePlatformsVulnerablePackages(ovalRoot); + }); + + LOG.warn("Saving OVAL finished"); + } + } + + public static class OVALProduct { + private OsFamily osFamily; + private String osVersion; + + public OVALProduct(OsFamily osFamily, String osVersion) { + this.osFamily = osFamily; + this.osVersion = osVersion; + } + + public OsFamily getOsFamily() { + return osFamily; + } + + public void setOsFamily(OsFamily osFamily) { + this.osFamily = osFamily; + } + + public String getOsVersion() { + return osVersion; + } + + public void setOsVersion(String osVersion) { + this.osVersion = osVersion; + } + } } diff --git a/java/code/src/com/redhat/rhn/taskomatic/task/OVALDataSync.java b/java/code/src/com/redhat/rhn/taskomatic/task/OVALDataSync.java new file mode 100644 index 000000000000..a71c01e7b862 --- /dev/null +++ b/java/code/src/com/redhat/rhn/taskomatic/task/OVALDataSync.java @@ -0,0 +1,26 @@ +package com.redhat.rhn.taskomatic.task; + +import com.redhat.rhn.manager.audit.CVEAuditManagerOVAL; + +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +public class OVALDataSync extends RhnJavaJob { + @Override + public String getConfigNamespace() { + return "oval_data_sync"; + } + + @Override + public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { + if (log.isDebugEnabled()) { + log.debug("Syncing OVAL data"); + } + + CVEAuditManagerOVAL.syncOVAL(); + + if (log.isDebugEnabled()) { + log.debug("Done syncing OVAL data"); + } + } +} diff --git a/schema/spacewalk/common/data/rhnTaskoTask.sql b/schema/spacewalk/common/data/rhnTaskoTask.sql index 359057c20a8f..68ab76fb68ad 100644 --- a/schema/spacewalk/common/data/rhnTaskoTask.sql +++ b/schema/spacewalk/common/data/rhnTaskoTask.sql @@ -146,4 +146,7 @@ VALUES (sequence_nextval('rhn_tasko_task_id_seq'), 'system-profile-refresh', 'co INSERT INTO rhnTaskoTask (id, name, class) VALUES (sequence_nextval('rhn_tasko_task_id_seq'), 'payg-dimension-computation', 'com.redhat.rhn.taskomatic.task.payg.PaygComputeDimensionsTask'); +INSERT INTO rhnTaskoTask (id, name, class) +VALUES (sequence_nextval('rhn_tasko_task_id_seq'), 'oval-data-sync', 'com.redhat.rhn.taskomatic.task.OVALDataSync'); + commit; diff --git a/schema/spacewalk/upgrade/susemanager-schema-4.4.6-to-susemanager-schema-4.4.7/003-oval-taskomatic.sql b/schema/spacewalk/upgrade/susemanager-schema-4.4.6-to-susemanager-schema-4.4.7/003-oval-taskomatic.sql new file mode 100644 index 000000000000..14c948b3124b --- /dev/null +++ b/schema/spacewalk/upgrade/susemanager-schema-4.4.6-to-susemanager-schema-4.4.7/003-oval-taskomatic.sql @@ -0,0 +1,52 @@ +-- +-- Copyright (c) 2023 SUSE LLC +-- +-- This software is licensed to you under the GNU General Public License, +-- version 2 (GPLv2). There is NO WARRANTY for this software, express or +-- implied, including the implied warranties of MERCHANTABILITY or FITNESS +-- FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 +-- along with this software; if not, see +-- http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. +-- + + +-- Insert task and map to the Java class +INSERT INTO rhnTaskoTask (id, name, class) +SELECT sequence_nextval('rhn_tasko_task_id_seq'), 'oval-data-sync', 'com.redhat.rhn.taskomatic.task.OVALDataSync' +WHERE NOT EXISTS (SELECT 1 + FROM rhnTaskoTask + WHERE name = 'oval-data-sync'); + +-- Insert bunch +INSERT INTO rhnTaskoBunch (id, name, description, org_bunch) +SELECT sequence_nextval('rhn_tasko_bunch_id_seq'), + 'oval-data-sync-bunch', + 'Generate OVAL data required to increase the accuracy of CVE audit queries.', + null +WHERE NOT EXISTS (SELECT 1 + FROM rhnTaskoBunch + WHERE name = 'oval-data-sync-bunch'); + +-- Insert template +INSERT INTO rhnTaskoTemplate (id, bunch_id, task_id, ordering, start_if) +SELECT sequence_nextval('rhn_tasko_template_id_seq'), + (SELECT id FROM rhnTaskoBunch WHERE name = 'oval-data-sync-bunch'), + (SELECT id FROM rhnTaskoTask WHERE name = 'oval-data-sync'), + 0, + null +WHERE NOT EXISTS (SELECT 1 + FROM rhnTaskoTemplate + WHERE bunch_id = (SELECT id FROM rhnTaskoBunch WHERE name = 'oval-data-sync-bunch') + AND task_id = (SELECT id FROM rhnTaskoTask WHERE name = 'oval-data-sync') + AND ordering = 0); + +-- Insert schedule for task (once a day at 11:00 PM) +INSERT INTO rhnTaskoSchedule (id, job_label, bunch_id, active_from, cron_expr) +SELECT sequence_nextval('rhn_tasko_schedule_id_seq'), + 'oval-data-sync-default', + (SELECT id FROM rhnTaskoBunch WHERE name = 'oval-data-sync-bunch'), + current_timestamp, + '0 0 23 ? * *' +WHERE NOT EXISTS (SELECT 1 + FROM rhnTaskoSchedule + WHERE job_label = 'oval-data-sync-default'); \ No newline at end of file From d2bd4d9a488706caea25c4426144d4e9a277f129 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Tue, 22 Aug 2023 19:37:37 +0100 Subject: [PATCH 04/64] Indicate in UI when vulnerability scan was based on OVAL or Channels data --- .../common/db/datasource/xml/oval_queries.xml | 6 ++++ .../rhn/manager/audit/CVEAuditImage.java | 7 +++++ .../rhn/manager/audit/CVEAuditManager.java | 3 +- .../manager/audit/CVEAuditManagerOVAL.java | 30 +++++++++++++++---- .../rhn/manager/audit/CVEAuditServer.java | 26 +++++++++++----- .../rhn/manager/audit/CVEAuditSystem.java | 7 +++++ .../manager/audit/CVEAuditSystemBuilder.java | 18 +++++++++++ .../src/com/suse/oval/OVALCachingFactory.java | 16 ++++++++++ .../css/susemanager/components/cveaudit.less | 10 +++++++ .../src/branding/css/susemanager/index.less | 1 + .../src/manager/audit/cveaudit/cveaudit.tsx | 22 ++++++++++++-- 11 files changed, 130 insertions(+), 16 deletions(-) create mode 100644 web/html/src/branding/css/susemanager/components/cveaudit.less diff --git a/java/code/src/com/redhat/rhn/common/db/datasource/xml/oval_queries.xml b/java/code/src/com/redhat/rhn/common/db/datasource/xml/oval_queries.xml index 0b9e12e368b4..87d8ec86376c 100755 --- a/java/code/src/com/redhat/rhn/common/db/datasource/xml/oval_queries.xml +++ b/java/code/src/com/redhat/rhn/common/db/datasource/xml/oval_queries.xml @@ -29,4 +29,10 @@ AND cve.name = :cve_name; + + + + SELECT 1 FROM suseOVALPlatform plat WHERE starts_with(:cpe, plat.cpe); + + diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditImage.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditImage.java index 87b2840e60f1..007533cf6cc5 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditImage.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditImage.java @@ -27,6 +27,9 @@ public class CVEAuditImage implements CVEAuditSystem { private long id; private String name; private PatchStatus patchStatus; + // If server was scanned wth CVEAuditManager#doAuditSystem instead of CVEAuditManagerOVAL#doAuditSystem then + // it's possible to get false negatives. + private boolean scannedWithOVAL; private Set channels; private Set erratas; @@ -94,5 +97,9 @@ public Set getErratas() { return erratas; } + @Override + public boolean isScannedWithOVAL() { + return scannedWithOVAL; + } } diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManager.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManager.java index aa03c2e8fcd1..d71643b2aa19 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManager.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManager.java @@ -877,7 +877,8 @@ public static List listSystemsByPatchStatus(User user, system.getSystemName(), system.getPatchStatus(), system.getChannels(), - system.getErratas() + system.getErratas(), + false )).collect(Collectors.toList()); } diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java index 84bfe33d5b83..69a2973a493c 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java @@ -98,10 +98,16 @@ public static List listSystemsByPatchStatus(User user, String cv CVEAuditSystemBuilder auditWithChannelsResult = CVEAuditManager.doAuditSystem(clientServer.getId(), resultsBySystem.get(clientServer.getId())); - systemAuditResult = doAuditSystem(cveIdentifier, resultsBySystem.get(clientServer.getId()), - clientServer); - systemAuditResult.setChannels(auditWithChannelsResult.getChannels()); - systemAuditResult.setErratas(auditWithChannelsResult.getErratas()); + if (checkOVALAvailability(clientServer)) { + systemAuditResult = doAuditSystem(cveIdentifier, resultsBySystem.get(clientServer.getId()), clientServer); + systemAuditResult.setChannels(auditWithChannelsResult.getChannels()); + systemAuditResult.setErratas(auditWithChannelsResult.getErratas()); + systemAuditResult.setScannedWithOVAL(true); + } + else { + systemAuditResult = auditWithChannelsResult; + systemAuditResult.setScannedWithOVAL(false); + } if (patchStatuses.contains(systemAuditResult.getPatchStatus())) { result.add(new CVEAuditServer( @@ -109,13 +115,24 @@ public static List listSystemsByPatchStatus(User user, String cv systemAuditResult.getSystemName(), systemAuditResult.getPatchStatus(), systemAuditResult.getChannels(), - systemAuditResult.getErratas())); + systemAuditResult.getErratas(), + systemAuditResult.isScannedWithOVAL())); } } return result; } + /** + * Check if server support OVAL CVE auditing + * + * @param clientServer the server to check + * @return {@code True} + * */ + public static boolean checkOVALAvailability(Server clientServer) { + return OVALCachingFactory.checkOVALAvailability(clientServer.getCpe()); + } + private static boolean isCVEIdentifierUnknown(String cveIdentifier) { return !OVALCachingFactory.canAuditCVE(cveIdentifier) && CVEAuditManager.isCVEIdentifierUnknown(cveIdentifier); } @@ -309,10 +326,11 @@ public static void populateCVEChannels() { CVEAuditManager.populateCVEChannels(); } + // TODO: Sync OVAL of registered clients only static List productsToSync = new ArrayList<>(); static { /*productsToSync.add(new OVALProduct(OsFamily.openSUSE_LEAP, "15.4"));*/ - productsToSync.add(new OVALProduct(OsFamily.openSUSE_LEAP, "15.3")); + productsToSync.add(new OVALProduct(OsFamily.LEAP, "15.3")); productsToSync.add(new OVALProduct(OsFamily.REDHAT_ENTERPRISE_LINUX, "9")); } public static void syncOVAL() { diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditServer.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditServer.java index 07f861d7c276..22852a21c745 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditServer.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditServer.java @@ -29,6 +29,9 @@ public class CVEAuditServer extends SelectableAdapter implements CVEAuditSystem private long id; private String name; private PatchStatus patchStatus; + // If server was scanned wth CVEAuditManager#doAuditSystem instead of CVEAuditManagerOVAL#doAuditSystem then + // it's possible to get false negatives. + private boolean scannedWithOVAL; // LinkedHashSet is used to preserve insertion order when iterating private Set channels; @@ -36,20 +39,23 @@ public class CVEAuditServer extends SelectableAdapter implements CVEAuditSystem /** * Constructor - * @param idIn id - * @param nameIn name - * @param statusIn status - * @param channelsIn channels - * @param erratasIn errata + * + * @param idIn id + * @param nameIn name + * @param statusIn status + * @param channelsIn channels + * @param erratasIn errata + * @param scannedWithOVALIn scannedWithOVAL */ public CVEAuditServer(long idIn, String nameIn, PatchStatus statusIn, Set channelsIn, - Set erratasIn) { + Set erratasIn, boolean scannedWithOVALIn) { this.id = idIn; this.name = nameIn; this.patchStatus = statusIn; this.channels = channelsIn; this.erratas = erratasIn; + this.scannedWithOVAL = scannedWithOVALIn; } /** @@ -110,5 +116,11 @@ public Set getErratas() { return erratas; } - + /** + * @inherit + * */ + @Override + public boolean isScannedWithOVAL() { + return scannedWithOVAL; + } } diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystem.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystem.java index b0d7ac3c9bd8..6f3ec6b62694 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystem.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystem.java @@ -52,6 +52,13 @@ public interface CVEAuditSystem { */ Set getErratas(); + /** + * Returns if the system was scanned with OVAL instead of Channels + * + * @return {@code True} of server was scanned with OVAL and {@code False} otherwise. + */ + boolean isScannedWithOVAL(); + /** * Return the closest channel as {@link String} for CSV file download. * @return closest channel name diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystemBuilder.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystemBuilder.java index 4f14391c4f2b..f9e37b1ac34c 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystemBuilder.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystemBuilder.java @@ -30,6 +30,9 @@ public class CVEAuditSystemBuilder { private long systemID; private String systemName; private PatchStatus patchStatus; + // If system was audited wth CVEAuditManager#doAuditSystem instead of CVEAuditManagerOVAL#doAuditSystem then + // it's possible to get false negatives. + private boolean scannedWithOVAL; // LinkedHashSet is used to preserve insertion order when iterating private Set channels = @@ -181,4 +184,19 @@ public String getPatchAdvisory() { public Long getId() { return systemID; } + + /** + * Returns {@code True} if server was scanned with OVAL and {@code False} otherwise + * */ + public boolean isScannedWithOVAL() { + return scannedWithOVAL; + } + + /** + * Sets scannedWithOVAL + * @param scannedWithOVALIn the value to set + * */ + public void setScannedWithOVAL(boolean scannedWithOVALIn) { + this.scannedWithOVAL = scannedWithOVALIn; + } } diff --git a/java/code/src/com/suse/oval/OVALCachingFactory.java b/java/code/src/com/suse/oval/OVALCachingFactory.java index a34fd82b9b9d..8d9685f6dd94 100644 --- a/java/code/src/com/suse/oval/OVALCachingFactory.java +++ b/java/code/src/com/suse/oval/OVALCachingFactory.java @@ -134,6 +134,22 @@ public static boolean canAuditCVE(String cve) { return !result.isEmpty(); } + /** + * Checks if OVAL is synced for servers with the given {@code cpe} + * + * @param cpe the cpe of servers to check for + * @return {@code True} if OVAL is available for servers with {@code cpe} and {@code False} otherwise. + */ + public static boolean checkOVALAvailability(String cpe) { + SelectMode m = ModeFactory.getMode("oval_queries", "check_oval_availability"); + Map params = new HashMap<>(); + params.put("cpe", cpe); + + DataResult result = m.execute(params); + + return !result.isEmpty(); + } + @Override protected Logger getLogger() { return LOG; diff --git a/web/html/src/branding/css/susemanager/components/cveaudit.less b/web/html/src/branding/css/susemanager/components/cveaudit.less new file mode 100644 index 000000000000..303405afff7c --- /dev/null +++ b/web/html/src/branding/css/susemanager/components/cveaudit.less @@ -0,0 +1,10 @@ +.scan-data-indicator { + padding: 6px 0; + border-radius: 4px; + /* margin: auto; */ + width: fit-content; + min-width: 120px; + text-align: center; + color: white; + font-weight: bolder; +} \ No newline at end of file diff --git a/web/html/src/branding/css/susemanager/index.less b/web/html/src/branding/css/susemanager/index.less index 38b791179bf2..5e118fe97544 100644 --- a/web/html/src/branding/css/susemanager/index.less +++ b/web/html/src/branding/css/susemanager/index.less @@ -24,6 +24,7 @@ @import "./components/date-time-picker.less"; @import "./components/header.less"; @import "./components/address.less"; +@import url(./components/cveaudit.less); // Responsive overrides @import "../base/responsive-rules.less"; diff --git a/web/html/src/manager/audit/cveaudit/cveaudit.tsx b/web/html/src/manager/audit/cveaudit/cveaudit.tsx index ff5ec857ffb8..b048243e529a 100644 --- a/web/html/src/manager/audit/cveaudit/cveaudit.tsx +++ b/web/html/src/manager/audit/cveaudit/cveaudit.tsx @@ -351,7 +351,7 @@ class CVEAudit extends React.Component { /> { @@ -368,7 +368,7 @@ class CVEAudit extends React.Component { /> { @@ -478,6 +478,24 @@ class CVEAudit extends React.Component { } }} /> + { + return ( +
+ {t(row.scannedWithOVAL ? "OVAL" : "Channels")} +
+ ); + }} + /> Date: Tue, 22 Aug 2023 19:38:09 +0100 Subject: [PATCH 05/64] Add Leap 15.2 OVAL sources --- java/code/src/com/suse/oval/oval.config.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/java/code/src/com/suse/oval/oval.config.json b/java/code/src/com/suse/oval/oval.config.json index 10cb07e89bf1..20d7d5c4220a 100644 --- a/java/code/src/com/suse/oval/oval.config.json +++ b/java/code/src/com/suse/oval/oval.config.json @@ -2,6 +2,10 @@ "sources": { "openSUSE_LEAP": { "content": { + "15.2": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.15.2-affected.xml.gz", + "patch": "" + }, "15.3": { "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.15.3-affected.xml.gz", "patch": "" From ddbf4d5c0b7e0c48ee48d5b80c52fe768ac61ad1 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Tue, 5 Sep 2023 20:12:12 +0100 Subject: [PATCH 06/64] Deploy oval.config.json to /usr/share/susemanager/scc/ --- .../com/suse/oval/config/OVALConfigLoader.java | 15 ++++++--------- .../oval.config.json | 0 susemanager-sync-data/susemanager-sync-data.spec | 2 ++ 3 files changed, 8 insertions(+), 9 deletions(-) rename {java/code/src/com/suse/oval => susemanager-sync-data}/oval.config.json (100%) diff --git a/java/code/src/com/suse/oval/config/OVALConfigLoader.java b/java/code/src/com/suse/oval/config/OVALConfigLoader.java index 0f3d9c47e7c4..b7e9c4c03710 100644 --- a/java/code/src/com/suse/oval/config/OVALConfigLoader.java +++ b/java/code/src/com/suse/oval/config/OVALConfigLoader.java @@ -2,22 +2,19 @@ import static com.suse.utils.Json.GSON; -import com.redhat.rhn.testing.TestUtils; - import java.io.File; import java.io.FileReader; import java.io.IOException; -import java.net.URISyntaxException; -import java.net.URL; public class OVALConfigLoader { public static OVALConfig load() { - URL jsonConfigFile; + File jsonConfigFile; try { - jsonConfigFile = TestUtils.findTestData("/com/suse/oval/oval.config.json"); - return GSON.fromJson(new FileReader(new File(jsonConfigFile.toURI())), OVALConfig.class); - } catch (ClassNotFoundException | IOException | URISyntaxException e) { - throw new RuntimeException(e); + jsonConfigFile = new File("/usr/share/susemanager/scc/oval.config.json"); + return GSON.fromJson(new FileReader(jsonConfigFile), OVALConfig.class); + } + catch (IOException e) { + throw new RuntimeException("Failed to load OVAL config file", e); } } } diff --git a/java/code/src/com/suse/oval/oval.config.json b/susemanager-sync-data/oval.config.json similarity index 100% rename from java/code/src/com/suse/oval/oval.config.json rename to susemanager-sync-data/oval.config.json diff --git a/susemanager-sync-data/susemanager-sync-data.spec b/susemanager-sync-data/susemanager-sync-data.spec index db027aff499d..bfdb9d3d497d 100644 --- a/susemanager-sync-data/susemanager-sync-data.spec +++ b/susemanager-sync-data/susemanager-sync-data.spec @@ -40,6 +40,7 @@ mkdir -p %{buildroot}%{_datadir}/susemanager/scc install -m 0644 channel_families.json %{buildroot}%{_datadir}/susemanager/scc/channel_families.json install -m 0644 additional_products.json %{buildroot}%{_datadir}/susemanager/scc/additional_products.json install -m 0644 additional_repositories.json %{buildroot}%{_datadir}/susemanager/scc/additional_repositories.json +install -m 0644 oval.config.json %{buildroot}%{_datadir}/susemanager/scc/oval.config.json %files %defattr(-,root,root,-) @@ -48,5 +49,6 @@ install -m 0644 additional_repositories.json %{buildroot}%{_datadir}/susemana %{_datadir}/susemanager/scc/channel_families.json %{_datadir}/susemanager/scc/additional_products.json %{_datadir}/susemanager/scc/additional_repositories.json +%{_datadir}/susemanager/scc/oval.config.json %changelog From c298db736fa53dd29566d31c9286b1b65d85add5 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Tue, 5 Sep 2023 19:23:23 +0100 Subject: [PATCH 07/64] Add support for SLE Micro OVAL-based CVE auditing --- java/code/src/com/suse/oval/OVALCleaner.java | 6 +++--- java/code/src/com/suse/oval/OsFamily.java | 1 + .../SUSEVulnerablePackageExtractor.java | 18 +++++++++++++++--- .../VulnerablePackagesExtractors.java | 1 + 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/java/code/src/com/suse/oval/OVALCleaner.java b/java/code/src/com/suse/oval/OVALCleaner.java index 0ff91e4096b5..bf3b38f1b547 100644 --- a/java/code/src/com/suse/oval/OVALCleaner.java +++ b/java/code/src/com/suse/oval/OVALCleaner.java @@ -58,9 +58,8 @@ public static void cleanup(OvalRootType root, OsFamily osFamily, String osVersio root.getDefinitions().removeIf(def -> def.getId().contains("unaffected")); } - if (osFamily == OsFamily.DEBIAN || osFamily == OsFamily.SUSE_LINUX_ENTERPRISE_SERVER || - osFamily == OsFamily.SUSE_LINUX_ENTERPRISE_DESKTOP || osFamily == OsFamily.LEAP) { - // For the above OS families, we only need OVAL vulnerability definitions + // Debian OVAL files could contain patch definitions, but we're only interested in vulnerability definitions + if (osFamily == OsFamily.DEBIAN) { root.getDefinitions().removeIf(def -> def.getDefinitionClass() != DefinitionClassEnum.VULNERABILITY); } @@ -89,6 +88,7 @@ private static void fillCves(DefinitionType definition, OsFamily osFamily) { case LEAP: case SUSE_LINUX_ENTERPRISE_SERVER: case SUSE_LINUX_ENTERPRISE_DESKTOP: + case SUSE_LINUX_ENTERPRISE_MICRO: List cves = definition.getMetadata().getAdvisory().map(Advisory::getCveList) .orElse(Collections.emptyList()) diff --git a/java/code/src/com/suse/oval/OsFamily.java b/java/code/src/com/suse/oval/OsFamily.java index db4b4282ea7c..1b95376d68d1 100644 --- a/java/code/src/com/suse/oval/OsFamily.java +++ b/java/code/src/com/suse/oval/OsFamily.java @@ -19,6 +19,7 @@ public enum OsFamily { LEAP("openSUSE Leap", "leap", "opensuse"), SUSE_LINUX_ENTERPRISE_SERVER("SUSE Linux Enterprise Server", "sles", "suse"), SUSE_LINUX_ENTERPRISE_DESKTOP("SUSE Linux Enterprise Desktop", "sled", "suse"), + SUSE_LINUX_ENTERPRISE_MICRO("SUSE Linux Enterprise Micro", "sle-micro", "suse"), REDHAT_ENTERPRISE_LINUX("Red Hat Enterprise Linux", "enterprise_linux", "redhat"), UBUNTU("Ubuntu", "ubuntu", "canonical"), DEBIAN("Debian", "debian", "debian"); diff --git a/java/code/src/com/suse/oval/vulnerablepkgextractor/SUSEVulnerablePackageExtractor.java b/java/code/src/com/suse/oval/vulnerablepkgextractor/SUSEVulnerablePackageExtractor.java index 2f6d9c015d5a..58d662b65de5 100644 --- a/java/code/src/com/suse/oval/vulnerablepkgextractor/SUSEVulnerablePackageExtractor.java +++ b/java/code/src/com/suse/oval/vulnerablepkgextractor/SUSEVulnerablePackageExtractor.java @@ -173,11 +173,22 @@ private Cpe deriveCpe(TestType productTest) { if (osProduct == OsFamily.LEAP) { return deriveOpenSUSELeapCpe(); } + else if (osProduct == OsFamily.SUSE_LINUX_ENTERPRISE_MICRO) { + return deriveSUSEMicroCpe(); + } else { - return deriveSUSEProductCpe(productTest); + return deriveFromProductOVALTest(productTest); } } + private Cpe deriveSUSEMicroCpe() { + return new CpeBuilder() + .withVendor("suse") + .withProduct("sle-micro") + .withVersion(definition.getOsVersion()) + .build(); + } + private Cpe deriveOpenSUSELeapCpe() { return new CpeBuilder() .withVendor("opensuse") @@ -186,7 +197,7 @@ private Cpe deriveOpenSUSELeapCpe() { .build(); } - private Cpe deriveSUSEProductCpe(TestType productTest) { + private Cpe deriveFromProductOVALTest(TestType productTest) { String testComment = productTest.getComment(); String productPart = null; String versionPart = null; @@ -229,7 +240,8 @@ public boolean isValidDefinition(DefinitionType definitionTypeIn) { OsFamily osFamily = definitionTypeIn.getOsFamily(); boolean definitionFromASupportedFamily = osFamily == OsFamily.LEAP || osFamily == OsFamily.SUSE_LINUX_ENTERPRISE_SERVER || - osFamily == OsFamily.SUSE_LINUX_ENTERPRISE_DESKTOP; + osFamily == OsFamily.SUSE_LINUX_ENTERPRISE_DESKTOP || + osFamily == OsFamily.SUSE_LINUX_ENTERPRISE_MICRO; return super.isValidDefinition(definitionTypeIn) && definitionFromASupportedFamily; } diff --git a/java/code/src/com/suse/oval/vulnerablepkgextractor/VulnerablePackagesExtractors.java b/java/code/src/com/suse/oval/vulnerablepkgextractor/VulnerablePackagesExtractors.java index 8bb7917e00b4..47e5817597b1 100644 --- a/java/code/src/com/suse/oval/vulnerablepkgextractor/VulnerablePackagesExtractors.java +++ b/java/code/src/com/suse/oval/vulnerablepkgextractor/VulnerablePackagesExtractors.java @@ -43,6 +43,7 @@ public static VulnerablePackagesExtractor create(DefinitionType definition, OsFa case LEAP: case SUSE_LINUX_ENTERPRISE_SERVER: case SUSE_LINUX_ENTERPRISE_DESKTOP: + case SUSE_LINUX_ENTERPRISE_MICRO: return new SUSEVulnerablePackageExtractor(definition, ovalLookupHelper); case DEBIAN: return new DebianVulnerablePackagesExtractor(definition); From a180ead16e83c2ffc852f3fbe721a39a644a6c0b Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Tue, 5 Sep 2023 19:42:46 +0100 Subject: [PATCH 08/64] Add support for openSUSE Micro OVAL-based CVE auditing --- java/code/src/com/suse/oval/OVALCleaner.java | 1 + java/code/src/com/suse/oval/OsFamily.java | 1 + .../SUSEVulnerablePackageExtractor.java | 12 ++++++++++++ .../VulnerablePackagesExtractors.java | 1 + 4 files changed, 15 insertions(+) diff --git a/java/code/src/com/suse/oval/OVALCleaner.java b/java/code/src/com/suse/oval/OVALCleaner.java index bf3b38f1b547..fe2e607f3365 100644 --- a/java/code/src/com/suse/oval/OVALCleaner.java +++ b/java/code/src/com/suse/oval/OVALCleaner.java @@ -86,6 +86,7 @@ private static void fillCves(DefinitionType definition, OsFamily osFamily) { switch (osFamily) { case REDHAT_ENTERPRISE_LINUX: case LEAP: + case openSUSE_LEAP_MICRO: case SUSE_LINUX_ENTERPRISE_SERVER: case SUSE_LINUX_ENTERPRISE_DESKTOP: case SUSE_LINUX_ENTERPRISE_MICRO: diff --git a/java/code/src/com/suse/oval/OsFamily.java b/java/code/src/com/suse/oval/OsFamily.java index 1b95376d68d1..f01eabdfa325 100644 --- a/java/code/src/com/suse/oval/OsFamily.java +++ b/java/code/src/com/suse/oval/OsFamily.java @@ -17,6 +17,7 @@ public enum OsFamily { LEAP("openSUSE Leap", "leap", "opensuse"), + openSUSE_LEAP_MICRO("openSUSELeap Micro", "leap-micro", "opensuse"), SUSE_LINUX_ENTERPRISE_SERVER("SUSE Linux Enterprise Server", "sles", "suse"), SUSE_LINUX_ENTERPRISE_DESKTOP("SUSE Linux Enterprise Desktop", "sled", "suse"), SUSE_LINUX_ENTERPRISE_MICRO("SUSE Linux Enterprise Micro", "sle-micro", "suse"), diff --git a/java/code/src/com/suse/oval/vulnerablepkgextractor/SUSEVulnerablePackageExtractor.java b/java/code/src/com/suse/oval/vulnerablepkgextractor/SUSEVulnerablePackageExtractor.java index 58d662b65de5..cd87422e22a6 100644 --- a/java/code/src/com/suse/oval/vulnerablepkgextractor/SUSEVulnerablePackageExtractor.java +++ b/java/code/src/com/suse/oval/vulnerablepkgextractor/SUSEVulnerablePackageExtractor.java @@ -173,6 +173,9 @@ private Cpe deriveCpe(TestType productTest) { if (osProduct == OsFamily.LEAP) { return deriveOpenSUSELeapCpe(); } + else if (osProduct == OsFamily.openSUSE_LEAP_MICRO) { + return deriveOpenSUSELeapMicroCpe(); + } else if (osProduct == OsFamily.SUSE_LINUX_ENTERPRISE_MICRO) { return deriveSUSEMicroCpe(); } @@ -181,6 +184,14 @@ else if (osProduct == OsFamily.SUSE_LINUX_ENTERPRISE_MICRO) { } } + private Cpe deriveOpenSUSELeapMicroCpe() { + return new CpeBuilder() + .withVendor("opensuse") + .withProduct("leap-micro") + .withVersion(definition.getOsVersion()) + .build(); + } + private Cpe deriveSUSEMicroCpe() { return new CpeBuilder() .withVendor("suse") @@ -239,6 +250,7 @@ private Cpe deriveFromProductOVALTest(TestType productTest) { public boolean isValidDefinition(DefinitionType definitionTypeIn) { OsFamily osFamily = definitionTypeIn.getOsFamily(); boolean definitionFromASupportedFamily = osFamily == OsFamily.LEAP || + osFamily == OsFamily.openSUSE_LEAP_MICRO || osFamily == OsFamily.SUSE_LINUX_ENTERPRISE_SERVER || osFamily == OsFamily.SUSE_LINUX_ENTERPRISE_DESKTOP || osFamily == OsFamily.SUSE_LINUX_ENTERPRISE_MICRO; diff --git a/java/code/src/com/suse/oval/vulnerablepkgextractor/VulnerablePackagesExtractors.java b/java/code/src/com/suse/oval/vulnerablepkgextractor/VulnerablePackagesExtractors.java index 47e5817597b1..6a6cb2c0e5f1 100644 --- a/java/code/src/com/suse/oval/vulnerablepkgextractor/VulnerablePackagesExtractors.java +++ b/java/code/src/com/suse/oval/vulnerablepkgextractor/VulnerablePackagesExtractors.java @@ -41,6 +41,7 @@ public static VulnerablePackagesExtractor create(DefinitionType definition, OsFa OVALLookupHelper ovalLookupHelper) { switch (osFamily) { case LEAP: + case openSUSE_LEAP_MICRO: case SUSE_LINUX_ENTERPRISE_SERVER: case SUSE_LINUX_ENTERPRISE_DESKTOP: case SUSE_LINUX_ENTERPRISE_MICRO: From f97857af23595082c9048cf651c28eb703d5d20b Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Thu, 7 Sep 2023 23:33:41 +0100 Subject: [PATCH 09/64] Add SLE and Leap Micro OVAL sources --- susemanager-sync-data/oval.config.json | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/susemanager-sync-data/oval.config.json b/susemanager-sync-data/oval.config.json index 20d7d5c4220a..de1918d5d769 100644 --- a/susemanager-sync-data/oval.config.json +++ b/susemanager-sync-data/oval.config.json @@ -20,6 +20,18 @@ } } }, + "openSUSE_LEAP_MICRO": { + "content": { + "5.2": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.micro.5.2-affected.xml.gz", + "patch": "" + }, + "5.3": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.micro.5.3-affected.xml.gz", + "patch": "" + } + } + }, "SUSE_LINUX_ENTERPRISE_SERVER": { "content": { "10": { @@ -60,6 +72,30 @@ } } }, + "SUSE_LINUX_ENTERPRISE_MICRO": { + "content": { + "5.0": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.micro.5.0-affected.xml.gz", + "patch": "" + }, + "5.1": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.micro.5.1-affected.xml.gz", + "patch": "" + }, + "5.2": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.micro.5.2-affected.xml.gz", + "patch": "" + }, + "5.3": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.micro.5.3-affected.xml.gz", + "patch": "" + }, + "5.4": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.micro.5.4-affected.xml.gz", + "patch": "" + } + } + }, "UBUNTU": { "content": { "18.04": { From 914fb48f7e61b154a08f44e661dce87ac46c868f Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sat, 9 Sep 2023 20:51:27 +0100 Subject: [PATCH 10/64] Synchronize OVAL data only for products used by registered clients --- .../com/redhat/rhn/domain/server/Server.java | 66 +++++++++++++++++++ .../rhn/domain/server/ServerConstants.java | 2 + .../manager/audit/CVEAuditManagerOVAL.java | 26 ++++++-- java/code/src/com/suse/oval/OsFamily.java | 49 ++++++++++---- 4 files changed, 125 insertions(+), 18 deletions(-) diff --git a/java/code/src/com/redhat/rhn/domain/server/Server.java b/java/code/src/com/redhat/rhn/domain/server/Server.java index 5f2723187e9d..2b2c52ec92fa 100644 --- a/java/code/src/com/redhat/rhn/domain/server/Server.java +++ b/java/code/src/com/redhat/rhn/domain/server/Server.java @@ -36,6 +36,7 @@ import com.redhat.rhn.domain.rhnpackage.PackageEvr; import com.redhat.rhn.domain.rhnpackage.PackageType; import com.redhat.rhn.domain.user.User; +import com.redhat.rhn.manager.audit.CVEAuditManagerOVAL; import com.redhat.rhn.manager.configuration.ConfigurationManager; import com.redhat.rhn.manager.entitlement.EntitlementManager; import com.redhat.rhn.manager.kickstart.cobbler.CobblerXMLRPCHelper; @@ -44,6 +45,7 @@ import com.suse.manager.model.attestation.ServerCoCoAttestationConfig; import com.suse.manager.model.attestation.ServerCoCoAttestationReport; import com.suse.manager.model.maintenance.MaintenanceSchedule; +import com.suse.oval.OsFamily; import com.suse.utils.Opt; import org.apache.commons.lang3.StringUtils; @@ -63,6 +65,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.Date; +import java.util.EnumSet; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -2431,6 +2434,13 @@ public boolean doesOsSupportPtf() { return ServerConstants.SLES.equals(getOs()); } + boolean isSLES() { + return ServerConstants.SLES.equalsIgnoreCase(getOs()); + } + boolean isSLED() { + return ServerConstants.SLED.equalsIgnoreCase(getOs()); + } + /** * Return true if OS supports Confidential Computing Attestation * @@ -2476,6 +2486,10 @@ boolean isSLES15() { return ServerConstants.SLES.equals(getOs()) && getRelease().startsWith("15"); } + boolean isLeap() { + return ServerConstants.LEAP.equalsIgnoreCase(getOs()); + } + boolean isLeap15() { return ServerConstants.LEAP.equalsIgnoreCase(getOs()) && getRelease().startsWith("15"); } @@ -2494,6 +2508,10 @@ boolean isopenSUSEMicroOS() { return ServerConstants.OPENSUSEMICROOS.equals(getOs()); } + boolean isUbuntu() { + return ServerConstants.UBUNTU.equalsIgnoreCase(getOs()); + } + boolean isUbuntu1804() { return ServerConstants.UBUNTU.equals(getOs()) && getRelease().equals("18.04"); } @@ -2506,6 +2524,10 @@ boolean isUbuntu2204() { return ServerConstants.UBUNTU.equals(getOs()) && getRelease().equals("22.04"); } + boolean isDebian() { + return ServerConstants.DEBIAN.equalsIgnoreCase(getOs()); + } + boolean isDebian12() { return ServerConstants.DEBIAN.equals(getOs()) && getRelease().equals("12"); } @@ -2518,6 +2540,10 @@ boolean isDebian10() { return ServerConstants.DEBIAN.equals(getOs()) && getRelease().equals("10"); } + boolean isRHEL() { + return ServerConstants.RHEL.equals(getOs()); + } + /** * This is supposed to cover all RedHat flavors (incl. RHEL, RES and CentOS Linux) */ @@ -2561,6 +2587,46 @@ boolean isRocky9() { return ServerConstants.ROCKY.equals(getOs()) && getRelease().startsWith("9."); } + /** + * Derives an {@link com.redhat.rhn.manager.audit.CVEAuditManagerOVAL.OVALProduct} object based on the server's + * information, including the operating system name and release version. Used by the OVAL synchronization process + * to identify the installed product and synchronize OVAL data for it. + * + * @return the information of the installed product to synchronize OVAL data for if the product is eligible for + * OVAL synchronization and {@code Optional.empty} otherwise + * (for example product maintainers don't produce OVAL data) + * */ + public Optional toOVALProduct() { + if (isDebian() && OsFamily.DEBIAN.isSupportedRelease(getRelease())) { + return Optional.of(new CVEAuditManagerOVAL.OVALProduct(OsFamily.DEBIAN, getRelease())); + } + else if (isUbuntu() && OsFamily.UBUNTU.isSupportedRelease(getRelease())) { + return Optional.of(new CVEAuditManagerOVAL.OVALProduct(OsFamily.UBUNTU, getRelease())); + } + else if (isLeap() && OsFamily.LEAP.isSupportedRelease(getRelease())) { + return Optional.of(new CVEAuditManagerOVAL.OVALProduct(OsFamily.LEAP, getRelease())); + } + else if (isRHEL() && OsFamily.REDHAT_ENTERPRISE_LINUX.isSupportedRelease(getRelease())) { + return Optional.of(new CVEAuditManagerOVAL.OVALProduct(OsFamily.REDHAT_ENTERPRISE_LINUX, + // Removing the fractional part from the version .e.g. '9.2' to '9' + getRelease().replace("\\..*", ""))); + } + else if (isSLES() && OsFamily.SUSE_LINUX_ENTERPRISE_SERVER.isSupportedRelease(getRelease())) { + return Optional.of(new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_SERVER, getRelease())); + } + else if (isSLED() && OsFamily.SUSE_LINUX_ENTERPRISE_DESKTOP.isSupportedRelease(getRelease())) { + return Optional.of(new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_DESKTOP, getRelease())); + } + else if (isLeapMicro() && OsFamily.openSUSE_LEAP_MICRO.isSupportedRelease(getRelease())) { + return Optional.of(new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_MICRO, getRelease())); + } + else if (isSLEMicro() && OsFamily.SUSE_LINUX_ENTERPRISE_MICRO.isSupportedRelease(getRelease())) { + return Optional.of(new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_MICRO, getRelease())); + } + + return Optional.empty(); + } + /** * Getter for os family * diff --git a/java/code/src/com/redhat/rhn/domain/server/ServerConstants.java b/java/code/src/com/redhat/rhn/domain/server/ServerConstants.java index 1887dc4d4002..f8a10d5d06d6 100644 --- a/java/code/src/com/redhat/rhn/domain/server/ServerConstants.java +++ b/java/code/src/com/redhat/rhn/domain/server/ServerConstants.java @@ -38,6 +38,8 @@ public class ServerConstants { public static final String ALMA = "AlmaLinux"; public static final String AMAZON = "Amazon Linux"; public static final String ROCKY = "Rocky"; + public static final String SLED = "SLED"; + public static final String RHEL = "Red Hat Enterprise Linux"; private ServerConstants() { diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java index 69a2973a493c..3d9709e315cf 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java @@ -20,6 +20,7 @@ import com.redhat.rhn.domain.rhnpackage.PackageEvr; import com.redhat.rhn.domain.server.Server; +import com.redhat.rhn.domain.server.ServerFactory; import com.redhat.rhn.domain.user.User; import com.redhat.rhn.manager.rhnpackage.PackageManager; @@ -326,14 +327,14 @@ public static void populateCVEChannels() { CVEAuditManager.populateCVEChannels(); } - // TODO: Sync OVAL of registered clients only - static List productsToSync = new ArrayList<>(); - static { - /*productsToSync.add(new OVALProduct(OsFamily.openSUSE_LEAP, "15.4"));*/ - productsToSync.add(new OVALProduct(OsFamily.LEAP, "15.3")); - productsToSync.add(new OVALProduct(OsFamily.REDHAT_ENTERPRISE_LINUX, "9")); - } + /** + * Launches the OVAL synchronization process + * */ public static void syncOVAL() { + List productsToSync = getProductsToSync(); + + LOG.warn("Detected {} products eligible for OVAL synchronization", productsToSync.size()); + OVALDownloader ovalDownloader = new OVALDownloader(OVALConfigLoader.load()); for (OVALProduct product : productsToSync) { LOG.warn("Downloading OVAL for {} {}", product.getOsFamily(), product.getOsVersion()); @@ -374,6 +375,17 @@ public static void syncOVAL() { } } + /** + * Identifies the OS products to synchronize OVAL data for. + * */ + private static List getProductsToSync() { + List allServers = ServerFactory.list(false, false); + + return allServers.stream().map(Server::toOVALProduct) + .filter(Optional::isPresent) + .map(Optional::get).collect(Collectors.toList()); + } + public static class OVALProduct { private OsFamily osFamily; private String osVersion; diff --git a/java/code/src/com/suse/oval/OsFamily.java b/java/code/src/com/suse/oval/OsFamily.java index f01eabdfa325..bc041cdc4942 100644 --- a/java/code/src/com/suse/oval/OsFamily.java +++ b/java/code/src/com/suse/oval/OsFamily.java @@ -15,27 +15,54 @@ package com.suse.oval; +import java.util.Arrays; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + public enum OsFamily { - LEAP("openSUSE Leap", "leap", "opensuse"), - openSUSE_LEAP_MICRO("openSUSELeap Micro", "leap-micro", "opensuse"), - SUSE_LINUX_ENTERPRISE_SERVER("SUSE Linux Enterprise Server", "sles", "suse"), - SUSE_LINUX_ENTERPRISE_DESKTOP("SUSE Linux Enterprise Desktop", "sled", "suse"), - SUSE_LINUX_ENTERPRISE_MICRO("SUSE Linux Enterprise Micro", "sle-micro", "suse"), - REDHAT_ENTERPRISE_LINUX("Red Hat Enterprise Linux", "enterprise_linux", "redhat"), - UBUNTU("Ubuntu", "ubuntu", "canonical"), - DEBIAN("Debian", "debian", "debian"); + LEAP("openSUSE Leap", "leap", "opensuse", + oneOf("15.2", "15.3", "15.4", "15.5")), + openSUSE_LEAP_MICRO("openSUSELeap Micro", "leap-micro", "opensuse", + oneOf("5.2", "5.3")), + SUSE_LINUX_ENTERPRISE_SERVER("SUSE Linux Enterprise Server", "sles", "suse", + oneOf("10", "11", "12", "15")), + SUSE_LINUX_ENTERPRISE_DESKTOP("SUSE Linux Enterprise Desktop", "sled", "suse", + oneOf("10", "11", "12", "15")), + SUSE_LINUX_ENTERPRISE_MICRO("SUSE Linux Enterprise Micro", "sle-micro", "suse", + oneOf("5.0", "5.1", "5.2", "5.3")), + REDHAT_ENTERPRISE_LINUX("Red Hat Enterprise Linux", "enterprise_linux", "redhat", + withPrefix("7.", "8.", "9.", "10.")), + UBUNTU("Ubuntu", "ubuntu", "canonical", oneOf("18.04", "20.04", "22.04")), + DEBIAN("Debian", "debian", "debian", oneOf("10", "11", "12")); private final String vendor; private final String fullname; // Should consist of all lower case characters private final String shortname; + private final Pattern legalReleasePattern; - OsFamily(String fullnameIn, String shortnameIn, String vendorIn) { + OsFamily(String fullnameIn, String shortnameIn, String vendorIn, String legalReleaseRegex) { this.fullname = fullnameIn; this.shortname = shortnameIn; this.vendor = vendorIn; + legalReleasePattern = Pattern.compile(legalReleaseRegex); + } + + public boolean isSupportedRelease(String release) { + return legalReleasePattern.matcher(release).matches(); + } + + private static String oneOf(String ... legalReleases) { + return "(" + String.join("|", escapePeriods(legalReleases)) + ")"; + } + + private static String withPrefix(String ... legalReleasePrefixes) { + return "(" + Arrays.stream(escapePeriods(legalReleasePrefixes)) + .map(prefix -> prefix + ".*") + .collect(Collectors.joining("|")) + ")"; } - OsFamily(String fullnameIn, String vendorIn) { - this(fullnameIn, fullnameIn.toLowerCase(), vendorIn); + + private static String[] escapePeriods(String ... strings) { + return Arrays.stream(strings).map(str -> str.replace(".", "\\.")).toArray(String[]::new); } } From 4160040987aee80be9c7b65b67e770d746b18246 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Thu, 14 Sep 2023 17:54:45 +0100 Subject: [PATCH 11/64] Log the products eligible for OVAL synchronization --- .../com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java | 7 ++++++- java/code/src/com/suse/oval/OsFamily.java | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java index 3d9709e315cf..18453d6338f3 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java @@ -333,7 +333,7 @@ public static void populateCVEChannels() { public static void syncOVAL() { List productsToSync = getProductsToSync(); - LOG.warn("Detected {} products eligible for OVAL synchronization", productsToSync.size()); + LOG.warn("Detected {} products eligible for OVAL synchronization: {}", productsToSync.size(), productsToSync); OVALDownloader ovalDownloader = new OVALDownloader(OVALConfigLoader.load()); for (OVALProduct product : productsToSync) { @@ -410,5 +410,10 @@ public String getOsVersion() { public void setOsVersion(String osVersion) { this.osVersion = osVersion; } + + @Override + public String toString() { + return osFamily.fullname() + " " + osVersion; + } } } diff --git a/java/code/src/com/suse/oval/OsFamily.java b/java/code/src/com/suse/oval/OsFamily.java index bc041cdc4942..f13e2251c346 100644 --- a/java/code/src/com/suse/oval/OsFamily.java +++ b/java/code/src/com/suse/oval/OsFamily.java @@ -48,6 +48,10 @@ public enum OsFamily { legalReleasePattern = Pattern.compile(legalReleaseRegex); } + public String fullname() { + return fullname; + } + public boolean isSupportedRelease(String release) { return legalReleasePattern.matcher(release).matches(); } From 03c6bb1fa065cd58997d703d1ed29bd57f62dec4 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Tue, 3 Oct 2023 00:34:00 +0100 Subject: [PATCH 12/64] Translate oval sync task related strings --- .../rhn/frontend/strings/java/StringResource_en_US.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/java/code/src/com/redhat/rhn/frontend/strings/java/StringResource_en_US.xml b/java/code/src/com/redhat/rhn/frontend/strings/java/StringResource_en_US.xml index ec5279a5ca57..a8a5b1944a3d 100644 --- a/java/code/src/com/redhat/rhn/frontend/strings/java/StringResource_en_US.xml +++ b/java/code/src/com/redhat/rhn/frontend/strings/java/StringResource_en_US.xml @@ -8791,6 +8791,9 @@ Alternatively, you will want to download <strong>Incremental Channel Conte CVE Server Channels + + Sync OVAL Data + Refresh mgr-sync data @@ -8833,6 +8836,9 @@ Alternatively, you will want to download <strong>Incremental Channel Conte Generates data required for performing CVE audit queries + + Generate OVAL data required to increase the accuracy of CVE audit queries + Refreshes data about channels, products and subscriptions From 7c2f37683dfe35a697daac69ed9e6566a8ef3558 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Tue, 3 Oct 2023 22:53:45 +0100 Subject: [PATCH 13/64] Test OVAL sources Also, found some dead URLs so I deleted them --- .../manager/audit/CVEAuditManagerOVAL.java | 2 +- java/code/src/com/suse/oval/OsFamily.java | 4 +- .../suse/oval/config/OVALConfigLoader.java | 22 ++- .../suse/oval/config/test/OVALConfigTest.java | 102 +++++++++++++ .../suse/oval/config/test/oval.config.json | 144 ++++++++++++++++++ susemanager-sync-data/oval.config.json | 8 - 6 files changed, 269 insertions(+), 13 deletions(-) create mode 100644 java/code/src/com/suse/oval/config/test/OVALConfigTest.java create mode 100644 java/code/src/com/suse/oval/config/test/oval.config.json diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java index 18453d6338f3..ed39b28f972a 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java @@ -335,7 +335,7 @@ public static void syncOVAL() { LOG.warn("Detected {} products eligible for OVAL synchronization: {}", productsToSync.size(), productsToSync); - OVALDownloader ovalDownloader = new OVALDownloader(OVALConfigLoader.load()); + OVALDownloader ovalDownloader = new OVALDownloader(OVALConfigLoader.loadDefaultConfig()); for (OVALProduct product : productsToSync) { LOG.warn("Downloading OVAL for {} {}", product.getOsFamily(), product.getOsVersion()); OVALDownloadResult downloadResult; diff --git a/java/code/src/com/suse/oval/OsFamily.java b/java/code/src/com/suse/oval/OsFamily.java index f13e2251c346..a60880570d05 100644 --- a/java/code/src/com/suse/oval/OsFamily.java +++ b/java/code/src/com/suse/oval/OsFamily.java @@ -25,13 +25,13 @@ public enum OsFamily { openSUSE_LEAP_MICRO("openSUSELeap Micro", "leap-micro", "opensuse", oneOf("5.2", "5.3")), SUSE_LINUX_ENTERPRISE_SERVER("SUSE Linux Enterprise Server", "sles", "suse", - oneOf("10", "11", "12", "15")), + oneOf("11", "12", "15")), SUSE_LINUX_ENTERPRISE_DESKTOP("SUSE Linux Enterprise Desktop", "sled", "suse", oneOf("10", "11", "12", "15")), SUSE_LINUX_ENTERPRISE_MICRO("SUSE Linux Enterprise Micro", "sle-micro", "suse", oneOf("5.0", "5.1", "5.2", "5.3")), REDHAT_ENTERPRISE_LINUX("Red Hat Enterprise Linux", "enterprise_linux", "redhat", - withPrefix("7.", "8.", "9.", "10.")), + withPrefix("7.", "8.", "9.")), UBUNTU("Ubuntu", "ubuntu", "canonical", oneOf("18.04", "20.04", "22.04")), DEBIAN("Debian", "debian", "debian", oneOf("10", "11", "12")); diff --git a/java/code/src/com/suse/oval/config/OVALConfigLoader.java b/java/code/src/com/suse/oval/config/OVALConfigLoader.java index b7e9c4c03710..1ec77c4dc016 100644 --- a/java/code/src/com/suse/oval/config/OVALConfigLoader.java +++ b/java/code/src/com/suse/oval/config/OVALConfigLoader.java @@ -5,16 +5,34 @@ import java.io.File; import java.io.FileReader; import java.io.IOException; +import java.util.Objects; public class OVALConfigLoader { - public static OVALConfig load() { + private static final String DEFAULT_CONFIG_PATH = "/usr/share/susemanager/scc/oval.config.json"; + private final String configPath; + + public OVALConfigLoader(String configPathIn) { + Objects.requireNonNull(configPathIn); + + this.configPath = configPathIn; + } + + public OVALConfigLoader() { + this(DEFAULT_CONFIG_PATH); + } + + public OVALConfig load() { File jsonConfigFile; try { - jsonConfigFile = new File("/usr/share/susemanager/scc/oval.config.json"); + jsonConfigFile = new File(configPath); return GSON.fromJson(new FileReader(jsonConfigFile), OVALConfig.class); } catch (IOException e) { throw new RuntimeException("Failed to load OVAL config file", e); } } + + public static OVALConfig loadDefaultConfig() { + return new OVALConfigLoader().load(); + } } diff --git a/java/code/src/com/suse/oval/config/test/OVALConfigTest.java b/java/code/src/com/suse/oval/config/test/OVALConfigTest.java new file mode 100644 index 000000000000..5ed8717eeb6b --- /dev/null +++ b/java/code/src/com/suse/oval/config/test/OVALConfigTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2023 SUSE LLC + * + * This software is licensed to you under the GNU General Public License, + * version 2 (GPLv2). There is NO WARRANTY for this software, express or + * implied, including the implied warranties of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 + * along with this software; if not, see + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * Red Hat trademarks are not licensed under GPLv2. No permission is + * granted to use or replicate Red Hat trademarks that are incorporated + * in this software or its documentation. + */ + +package com.suse.oval.config.test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; + +import com.redhat.rhn.testing.TestUtils; + +import com.suse.oval.OsFamily; +import com.suse.oval.config.OVALConfig; +import com.suse.oval.config.OVALConfigLoader; +import com.suse.oval.config.OVALDistributionSourceInfo; +import com.suse.oval.config.OVALSourceInfo; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import wiremock.com.google.common.io.Files; + +public class OVALConfigTest { + + private static OVALConfig config; + + + @BeforeAll + public static void setUp() throws IOException, ClassNotFoundException { + File tempDir = Files.createTempDir(); + File configFile = tempDir.toPath().resolve("oval.config.json").toFile(); + FileUtils.copyURLToFile(TestUtils.findTestData("oval.config.json"), + configFile); + + config = new OVALConfigLoader(configFile.getAbsolutePath()).load(); + } + + @Test + public void testAllSources() throws IOException { + Map sources = config.getSources(); + + List allSources = sources.keySet().stream().flatMap(osFamily -> { + OVALDistributionSourceInfo ovalDistributionSourceInfo = sources.get(osFamily); + return ovalDistributionSourceInfo.getContent().keySet().stream() + .flatMap(version -> { + Optional ovalSourceInfoOpt = + ovalDistributionSourceInfo.getVersionSourceInfo(version); + + OVALSourceInfo ovalSourceInfo = ovalSourceInfoOpt.get(); + + String ovalVulnerabilitiesUrl = ovalSourceInfo.getVulnerabilitiesInfoSource(); + String ovalPatchesUrl = ovalSourceInfo.getPatchInfoSource(); + + List urls = new ArrayList<>(); + if (StringUtils.isNotBlank(ovalVulnerabilitiesUrl)) { + urls.add(ovalVulnerabilitiesUrl); + } + + if (StringUtils.isNotBlank(ovalPatchesUrl)) { + urls.add(ovalPatchesUrl); + } + + return urls.stream(); + }); + }).collect(Collectors.toList()); + + assertFalse(allSources.isEmpty()); + + for (String sourceURL : allSources) { + HttpURLConnection huc = (HttpURLConnection) new URL(sourceURL).openConnection(); + + huc.setRequestMethod("HEAD"); + + int responseCode = huc.getResponseCode(); + + assertEquals(HttpURLConnection.HTTP_OK, responseCode, () -> "Can't connect to URL: " + sourceURL); + } + } +} diff --git a/java/code/src/com/suse/oval/config/test/oval.config.json b/java/code/src/com/suse/oval/config/test/oval.config.json new file mode 100644 index 000000000000..aa07f185588e --- /dev/null +++ b/java/code/src/com/suse/oval/config/test/oval.config.json @@ -0,0 +1,144 @@ +{ + "sources": { + "openSUSE_LEAP": { + "content": { + "15.2": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.15.2-affected.xml.gz", + "patch": "" + }, + "15.3": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.15.3-affected.xml.gz", + "patch": "" + }, + "15.4": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.15.4-affected.xml.gz", + "patch": "" + }, + "15.5": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.15.5-affected.xml.gz", + "patch": "" + } + } + }, + "openSUSE_LEAP_MICRO": { + "content": { + "5.2": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.micro.5.2-affected.xml.gz", + "patch": "" + }, + "5.3": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.micro.5.3-affected.xml.gz", + "patch": "" + } + } + }, + "SUSE_LINUX_ENTERPRISE_SERVER": { + "content": { + "11": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.server.11-affected.xml.gz", + "patch": "" + }, + "12": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.server.12-affected.xml.gz", + "patch": "" + }, + "15": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.server.15-affected.xml.gz", + "patch": "" + } + } + }, + "SUSE_LINUX_ENTERPRISE_DESKTOP": { + "content": { + "10": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.desktop.10.xml.gz", + "patch": "" + }, + "11": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.desktop.11.xml.gz", + "patch": "" + }, + "12": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.desktop.12-affected.xml.gz", + "patch": "" + }, + "15": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.desktop.15-affected.xml.gz", + "patch": "" + } + } + }, + "SUSE_LINUX_ENTERPRISE_MICRO": { + "content": { + "5.0": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.micro.5.0-affected.xml.gz", + "patch": "" + }, + "5.1": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.micro.5.1-affected.xml.gz", + "patch": "" + }, + "5.2": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.micro.5.2-affected.xml.gz", + "patch": "" + }, + "5.3": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.micro.5.3-affected.xml.gz", + "patch": "" + }, + "5.4": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.micro.5.4-affected.xml.gz", + "patch": "" + } + } + }, + "UBUNTU": { + "content": { + "18.04": { + "vulnerability": "https://security-metadata.canonical.com/oval/com.ubuntu.bionic.cve.oval.xml.bz2", + "patch": "" + }, + "20.04": { + "vulnerability": "https://security-metadata.canonical.com/oval/com.ubuntu.focal.cve.oval.xml.bz2", + "patch": "" + }, + "22.04": { + "vulnerability": "https://security-metadata.canonical.com/oval/com.ubuntu.jammy.cve.oval.xml.bz2", + "patch": "" + } + } + }, + "REDHAT_ENTERPRISE_LINUX": { + "content": { + "7": { + "vulnerability": "https://www.redhat.com/security/data/oval/v2/RHEL7/rhel-7-including-unpatched.oval.xml.bz2", + "patch": "" + }, + "8": { + "vulnerability": "https://www.redhat.com/security/data/oval/v2/RHEL8/rhel-8-including-unpatched.oval.xml.bz2", + "patch": "" + }, + "9": { + "vulnerability": "https://www.redhat.com/security/data/oval/v2/RHEL9/rhel-9-including-unpatched.oval.xml.bz2", + "patch": "" + } + } + }, + "DEBIAN": { + "content": { + "10": { + "vulnerability": "https://www.debian.org/security/oval/oval-definitions-buster.xml.bz2", + "patch": "" + }, + "11": { + "vulnerability": "https://www.debian.org/security/oval/oval-definitions-bullseye.xml.bz2", + "patch": "" + }, + "12": { + "vulnerability": "https://www.debian.org/security/oval/oval-definitions-bookworm.xml.bz2", + "patch": "" + } + } + } + } +} \ No newline at end of file diff --git a/susemanager-sync-data/oval.config.json b/susemanager-sync-data/oval.config.json index de1918d5d769..aa07f185588e 100644 --- a/susemanager-sync-data/oval.config.json +++ b/susemanager-sync-data/oval.config.json @@ -34,10 +34,6 @@ }, "SUSE_LINUX_ENTERPRISE_SERVER": { "content": { - "10": { - "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.server.10-affected.xml.gz", - "patch": "" - }, "11": { "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.server.11-affected.xml.gz", "patch": "" @@ -125,10 +121,6 @@ "9": { "vulnerability": "https://www.redhat.com/security/data/oval/v2/RHEL9/rhel-9-including-unpatched.oval.xml.bz2", "patch": "" - }, - "10": { - "vulnerability": "https://www.redhat.com/security/data/oval/v2/RHEL10/rhel-10-including-unpatched.oval.xml.bz2", - "patch": "" } } }, From 51a3a47e7e45d9e53abf4be6baa4c18699094143 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Thu, 26 Oct 2023 21:04:08 +0100 Subject: [PATCH 14/64] Use Leap in oval.config.json --- susemanager-sync-data/oval.config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/susemanager-sync-data/oval.config.json b/susemanager-sync-data/oval.config.json index aa07f185588e..a80fc7971dee 100644 --- a/susemanager-sync-data/oval.config.json +++ b/susemanager-sync-data/oval.config.json @@ -1,6 +1,6 @@ { "sources": { - "openSUSE_LEAP": { + "LEAP": { "content": { "15.2": { "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.15.2-affected.xml.gz", From 529ddd735dbb8034b1690065cdecbb2aa4a613f7 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sun, 18 Feb 2024 17:49:43 +0100 Subject: [PATCH 15/64] Use proper logging when syncing OVAL data --- .../rhn/manager/audit/CVEAuditManagerOVAL.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java index ed39b28f972a..d2c7a4c87e88 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java @@ -333,11 +333,11 @@ public static void populateCVEChannels() { public static void syncOVAL() { List productsToSync = getProductsToSync(); - LOG.warn("Detected {} products eligible for OVAL synchronization: {}", productsToSync.size(), productsToSync); + LOG.debug("Detected {} products eligible for OVAL synchronization: {}", productsToSync.size(), productsToSync); OVALDownloader ovalDownloader = new OVALDownloader(OVALConfigLoader.loadDefaultConfig()); for (OVALProduct product : productsToSync) { - LOG.warn("Downloading OVAL for {} {}", product.getOsFamily(), product.getOsVersion()); + LOG.debug("Downloading OVAL for {} {}", product.getOsFamily(), product.getOsVersion()); OVALDownloadResult downloadResult; try { downloadResult = ovalDownloader.download(product.getOsFamily(), product.getOsVersion()); @@ -345,17 +345,17 @@ public static void syncOVAL() { catch (IOException e) { throw new RuntimeException("Failed to download OVAL data", e); } - LOG.warn("Downloading finished"); + LOG.debug("Downloading finished"); - LOG.warn("OVAL vulnerability file: " + + LOG.debug("OVAL vulnerability file: " + downloadResult.getVulnerabilityFile().map(File::getAbsoluteFile).orElse(null)); - LOG.warn("OVAL patch file: " + downloadResult.getPatchFile().map(File::getAbsoluteFile).orElse(null)); + LOG.debug("OVAL patch file: " + downloadResult.getPatchFile().map(File::getAbsoluteFile).orElse(null)); downloadResult.getVulnerabilityFile().ifPresent(ovalVulnerabilityFile -> { OvalParser ovalParser = new OvalParser(); OvalRootType ovalRoot = ovalParser.parse(ovalVulnerabilityFile); - LOG.warn("Saving Vulnerability OVAL for {} {}", product.getOsFamily(), product.getOsVersion()); + LOG.debug("Saving Vulnerability OVAL for {} {}", product.getOsFamily(), product.getOsVersion()); OVALCleaner.cleanup(ovalRoot, product.getOsFamily(), product.getOsVersion()); OVALCachingFactory.savePlatformsVulnerablePackages(ovalRoot); @@ -365,13 +365,13 @@ public static void syncOVAL() { OvalParser ovalParser = new OvalParser(); OvalRootType ovalRoot = ovalParser.parse(patchFile); - LOG.warn("Saving Patch OVAL for {} {}", product.getOsFamily(), product.getOsVersion()); + LOG.debug("Saving Patch OVAL for {} {}", product.getOsFamily(), product.getOsVersion()); OVALCleaner.cleanup(ovalRoot, product.getOsFamily(), product.getOsVersion()); OVALCachingFactory.savePlatformsVulnerablePackages(ovalRoot); }); - LOG.warn("Saving OVAL finished"); + LOG.debug("Saving OVAL finished"); } } From c53980f87c533f31c9efde959111471b5a71d1cc Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sun, 18 Feb 2024 18:03:17 +0100 Subject: [PATCH 16/64] Rename 'openSUSE_LEAP_MICRO' to 'LEAP_MICRO' - Having enums starting with a capital letter is better for consistency --- java/code/src/com/redhat/rhn/domain/server/Server.java | 2 +- java/code/src/com/suse/oval/OVALCleaner.java | 2 +- java/code/src/com/suse/oval/OsFamily.java | 2 +- java/code/src/com/suse/oval/config/test/OVALConfigTest.java | 4 ++++ java/code/src/com/suse/oval/config/test/oval.config.json | 2 +- .../SUSEVulnerablePackageExtractor.java | 4 ++-- .../vulnerablepkgextractor/VulnerablePackagesExtractors.java | 2 +- susemanager-sync-data/oval.config.json | 2 +- 8 files changed, 12 insertions(+), 8 deletions(-) diff --git a/java/code/src/com/redhat/rhn/domain/server/Server.java b/java/code/src/com/redhat/rhn/domain/server/Server.java index 2b2c52ec92fa..210d5bda985f 100644 --- a/java/code/src/com/redhat/rhn/domain/server/Server.java +++ b/java/code/src/com/redhat/rhn/domain/server/Server.java @@ -2617,7 +2617,7 @@ else if (isSLES() && OsFamily.SUSE_LINUX_ENTERPRISE_SERVER.isSupportedRelease(ge else if (isSLED() && OsFamily.SUSE_LINUX_ENTERPRISE_DESKTOP.isSupportedRelease(getRelease())) { return Optional.of(new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_DESKTOP, getRelease())); } - else if (isLeapMicro() && OsFamily.openSUSE_LEAP_MICRO.isSupportedRelease(getRelease())) { + else if (isLeapMicro() && OsFamily.LEAP_MICRO.isSupportedRelease(getRelease())) { return Optional.of(new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_MICRO, getRelease())); } else if (isSLEMicro() && OsFamily.SUSE_LINUX_ENTERPRISE_MICRO.isSupportedRelease(getRelease())) { diff --git a/java/code/src/com/suse/oval/OVALCleaner.java b/java/code/src/com/suse/oval/OVALCleaner.java index fe2e607f3365..2627b935cefb 100644 --- a/java/code/src/com/suse/oval/OVALCleaner.java +++ b/java/code/src/com/suse/oval/OVALCleaner.java @@ -86,7 +86,7 @@ private static void fillCves(DefinitionType definition, OsFamily osFamily) { switch (osFamily) { case REDHAT_ENTERPRISE_LINUX: case LEAP: - case openSUSE_LEAP_MICRO: + case LEAP_MICRO: case SUSE_LINUX_ENTERPRISE_SERVER: case SUSE_LINUX_ENTERPRISE_DESKTOP: case SUSE_LINUX_ENTERPRISE_MICRO: diff --git a/java/code/src/com/suse/oval/OsFamily.java b/java/code/src/com/suse/oval/OsFamily.java index a60880570d05..1cd51bc427d3 100644 --- a/java/code/src/com/suse/oval/OsFamily.java +++ b/java/code/src/com/suse/oval/OsFamily.java @@ -22,7 +22,7 @@ public enum OsFamily { LEAP("openSUSE Leap", "leap", "opensuse", oneOf("15.2", "15.3", "15.4", "15.5")), - openSUSE_LEAP_MICRO("openSUSELeap Micro", "leap-micro", "opensuse", + LEAP_MICRO("openSUSELeap Micro", "leap-micro", "opensuse", oneOf("5.2", "5.3")), SUSE_LINUX_ENTERPRISE_SERVER("SUSE Linux Enterprise Server", "sles", "suse", oneOf("11", "12", "15")), diff --git a/java/code/src/com/suse/oval/config/test/OVALConfigTest.java b/java/code/src/com/suse/oval/config/test/OVALConfigTest.java index 5ed8717eeb6b..99e53a531a8c 100644 --- a/java/code/src/com/suse/oval/config/test/OVALConfigTest.java +++ b/java/code/src/com/suse/oval/config/test/OVALConfigTest.java @@ -99,4 +99,8 @@ public void testAllSources() throws IOException { assertEquals(HttpURLConnection.HTTP_OK, responseCode, () -> "Can't connect to URL: " + sourceURL); } } + + public void testOsFamilies() { + // TODO: Test that all os families in the config file are in OsFamily enum + } } diff --git a/java/code/src/com/suse/oval/config/test/oval.config.json b/java/code/src/com/suse/oval/config/test/oval.config.json index aa07f185588e..ba012b8f3460 100644 --- a/java/code/src/com/suse/oval/config/test/oval.config.json +++ b/java/code/src/com/suse/oval/config/test/oval.config.json @@ -20,7 +20,7 @@ } } }, - "openSUSE_LEAP_MICRO": { + "LEAP_MICRO": { "content": { "5.2": { "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.micro.5.2-affected.xml.gz", diff --git a/java/code/src/com/suse/oval/vulnerablepkgextractor/SUSEVulnerablePackageExtractor.java b/java/code/src/com/suse/oval/vulnerablepkgextractor/SUSEVulnerablePackageExtractor.java index cd87422e22a6..664d31592879 100644 --- a/java/code/src/com/suse/oval/vulnerablepkgextractor/SUSEVulnerablePackageExtractor.java +++ b/java/code/src/com/suse/oval/vulnerablepkgextractor/SUSEVulnerablePackageExtractor.java @@ -173,7 +173,7 @@ private Cpe deriveCpe(TestType productTest) { if (osProduct == OsFamily.LEAP) { return deriveOpenSUSELeapCpe(); } - else if (osProduct == OsFamily.openSUSE_LEAP_MICRO) { + else if (osProduct == OsFamily.LEAP_MICRO) { return deriveOpenSUSELeapMicroCpe(); } else if (osProduct == OsFamily.SUSE_LINUX_ENTERPRISE_MICRO) { @@ -250,7 +250,7 @@ private Cpe deriveFromProductOVALTest(TestType productTest) { public boolean isValidDefinition(DefinitionType definitionTypeIn) { OsFamily osFamily = definitionTypeIn.getOsFamily(); boolean definitionFromASupportedFamily = osFamily == OsFamily.LEAP || - osFamily == OsFamily.openSUSE_LEAP_MICRO || + osFamily == OsFamily.LEAP_MICRO || osFamily == OsFamily.SUSE_LINUX_ENTERPRISE_SERVER || osFamily == OsFamily.SUSE_LINUX_ENTERPRISE_DESKTOP || osFamily == OsFamily.SUSE_LINUX_ENTERPRISE_MICRO; diff --git a/java/code/src/com/suse/oval/vulnerablepkgextractor/VulnerablePackagesExtractors.java b/java/code/src/com/suse/oval/vulnerablepkgextractor/VulnerablePackagesExtractors.java index 6a6cb2c0e5f1..6dcf1d29939f 100644 --- a/java/code/src/com/suse/oval/vulnerablepkgextractor/VulnerablePackagesExtractors.java +++ b/java/code/src/com/suse/oval/vulnerablepkgextractor/VulnerablePackagesExtractors.java @@ -41,7 +41,7 @@ public static VulnerablePackagesExtractor create(DefinitionType definition, OsFa OVALLookupHelper ovalLookupHelper) { switch (osFamily) { case LEAP: - case openSUSE_LEAP_MICRO: + case LEAP_MICRO: case SUSE_LINUX_ENTERPRISE_SERVER: case SUSE_LINUX_ENTERPRISE_DESKTOP: case SUSE_LINUX_ENTERPRISE_MICRO: diff --git a/susemanager-sync-data/oval.config.json b/susemanager-sync-data/oval.config.json index a80fc7971dee..34e6ce6a8838 100644 --- a/susemanager-sync-data/oval.config.json +++ b/susemanager-sync-data/oval.config.json @@ -20,7 +20,7 @@ } } }, - "openSUSE_LEAP_MICRO": { + "LEAP_MICRO": { "content": { "5.2": { "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.micro.5.2-affected.xml.gz", From d9102ab827de6cb759082d2e1a40d1ca372a60d5 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sun, 18 Feb 2024 20:01:07 +0100 Subject: [PATCH 17/64] Document the OVAL downloader component classes --- .../rhn/taskomatic/task/OVALDataSync.java | 18 +++++ .../ovaldownloader/OVALCompressionMethod.java | 22 ++++- .../ovaldownloader/OVALDownloadResult.java | 29 ++++++- .../oval/ovaldownloader/OVALDownloader.java | 80 +++++++++++++++---- 4 files changed, 129 insertions(+), 20 deletions(-) diff --git a/java/code/src/com/redhat/rhn/taskomatic/task/OVALDataSync.java b/java/code/src/com/redhat/rhn/taskomatic/task/OVALDataSync.java index a71c01e7b862..9c662831b702 100644 --- a/java/code/src/com/redhat/rhn/taskomatic/task/OVALDataSync.java +++ b/java/code/src/com/redhat/rhn/taskomatic/task/OVALDataSync.java @@ -1,3 +1,18 @@ +/* + * Copyright (c) 2023 SUSE LLC + * + * This software is licensed to you under the GNU General Public License, + * version 2 (GPLv2). There is NO WARRANTY for this software, express or + * implied, including the implied warranties of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 + * along with this software; if not, see + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * Red Hat trademarks are not licensed under GPLv2. No permission is + * granted to use or replicate Red Hat trademarks that are incorporated + * in this software or its documentation. + */ + package com.redhat.rhn.taskomatic.task; import com.redhat.rhn.manager.audit.CVEAuditManagerOVAL; @@ -5,6 +20,9 @@ import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; +/** + * Updates OVAL data to power the CVE auditing feature. + * */ public class OVALDataSync extends RhnJavaJob { @Override public String getConfigNamespace() { diff --git a/java/code/src/com/suse/oval/ovaldownloader/OVALCompressionMethod.java b/java/code/src/com/suse/oval/ovaldownloader/OVALCompressionMethod.java index 722445374ce0..92267c4d05db 100644 --- a/java/code/src/com/suse/oval/ovaldownloader/OVALCompressionMethod.java +++ b/java/code/src/com/suse/oval/ovaldownloader/OVALCompressionMethod.java @@ -1,11 +1,29 @@ +/* + * Copyright (c) 2023 SUSE LLC + * + * This software is licensed to you under the GNU General Public License, + * version 2 (GPLv2). There is NO WARRANTY for this software, express or + * implied, including the implied warranties of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 + * along with this software; if not, see + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * Red Hat trademarks are not licensed under GPLv2. No permission is + * granted to use or replicate Red Hat trademarks that are incorporated + * in this software or its documentation. + */ + package com.suse.oval.ovaldownloader; +/** + * The compression method used to compress the OVAL file. + * */ public enum OVALCompressionMethod { GZIP(".gz"), NOT_COMPRESSED(".xml"), BZIP2(".bz2"); private final String extension; - OVALCompressionMethod(String extension) { - this.extension = extension; + OVALCompressionMethod(String extensionIn) { + this.extension = extensionIn; } String extension() { diff --git a/java/code/src/com/suse/oval/ovaldownloader/OVALDownloadResult.java b/java/code/src/com/suse/oval/ovaldownloader/OVALDownloadResult.java index ec42e1bfd710..ed2f962ef178 100644 --- a/java/code/src/com/suse/oval/ovaldownloader/OVALDownloadResult.java +++ b/java/code/src/com/suse/oval/ovaldownloader/OVALDownloadResult.java @@ -1,8 +1,29 @@ +/* + * Copyright (c) 2023 SUSE LLC + * + * This software is licensed to you under the GNU General Public License, + * version 2 (GPLv2). There is NO WARRANTY for this software, express or + * implied, including the implied warranties of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 + * along with this software; if not, see + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * Red Hat trademarks are not licensed under GPLv2. No permission is + * granted to use or replicate Red Hat trademarks that are incorporated + * in this software or its documentation. + */ + package com.suse.oval.ovaldownloader; import java.io.File; import java.util.Optional; +/** + * This class encapsulates the OVAL (XML) files produced by the {@link OVALDownloader} class. + * Usually, OVAL data of Linux distributions is organized in a repository that contains vulnerability and patch + * definitions. The vulnerability definitions are grouped together in the same OVAL (XML) file, and the same thing + * for patch definitions. + * */ public class OVALDownloadResult { private File vulnerabilityFile; private File patchFile; @@ -16,11 +37,11 @@ public Optional getPatchFile() { return Optional.ofNullable(patchFile); } - public void setVulnerabilityFile(File vulnerabilityFile) { - this.vulnerabilityFile = vulnerabilityFile; + public void setVulnerabilityFile(File vulnerabilityFileIn) { + this.vulnerabilityFile = vulnerabilityFileIn; } - public void setPatchFile(File patchFile) { - this.patchFile = patchFile; + public void setPatchFile(File patchFileIn) { + this.patchFile = patchFileIn; } } diff --git a/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java b/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java index cd78ce62f771..cf2628574754 100644 --- a/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java +++ b/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java @@ -1,3 +1,18 @@ +/* + * Copyright (c) 2023 SUSE LLC + * + * This software is licensed to you under the GNU General Public License, + * version 2 (GPLv2). There is NO WARRANTY for this software, express or + * implied, including the implied warranties of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 + * along with this software; if not, see + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * Red Hat trademarks are not licensed under GPLv2. No permission is + * granted to use or replicate Red Hat trademarks that are incorporated + * in this software or its documentation. + */ + package com.suse.oval.ovaldownloader; import com.suse.oval.OsFamily; @@ -17,28 +32,57 @@ import java.util.Objects; import java.util.Optional; import java.util.zip.GZIPInputStream; - +/** + * The OVAL Downloader is responsible for finding OVAL data online, downloading them, and caching them for easy + * access. Each supported distribution maintains an online server containing their OVAL data organized into XML files, + * known as an OVAL repository. The links in these repositories can be adjusted by editing the {@code oval.config.json} + * file. By default, {@code oval.config.json} directs to the official repositories supplied by the distribution + * maintainer to ensure the integrity and consistency of the consumed OVAL data. + * */ public class OVALDownloader { + /** + * The path where downloaded OVAL files will be stored. + * */ private static final String DOWNLOAD_PATH = "/var/log/rhn/ovals/"; + /** + * A configuration object that corresponds to {@code oval.config.json} + * */ private final OVALConfig config; - public OVALDownloader(OVALConfig config) { - this.config = config; + /** + * Default constructor + * + * @param configIn A configuration object that corresponds to {@code oval.config.json} + * */ + public OVALDownloader(OVALConfig configIn) { + this.config = configIn; } + /** + * Download the OVAL data that correspond to the given {@code osFamily} and {@code osVersion} and cache + * them for future access. + * + * @param osFamily the family of the Operating system (OS) to download OVAL data for. + * @param osVersion the version of the Operating system (OS) to download OVAL data for. + * @return {@link OVALDownloadResult} + * */ public OVALDownloadResult download(OsFamily osFamily, String osVersion) throws IOException { Optional sourceInfoOpt = config.lookupSourceInfo(osFamily, osVersion); if (sourceInfoOpt.isEmpty()) { throw new IllegalArgumentException( String.format( - "OVAL sources for '%s' '%s' is not configured. Please ensure OVAL is configured correctly oval.config.json", + "OVAL sources for '%s' '%s' is not configured. Please ensure OVAL is configured " + + "correctly oval.config.json", osFamily, osVersion)); } return doDownload(sourceInfoOpt.get()); } - public OVALDownloadResult doDownload(OVALSourceInfo sourceInfo) + /** + * A helper method for download OVAL data. + * */ + private OVALDownloadResult doDownload(OVALSourceInfo sourceInfo) throws IOException { OVALDownloadResult result = new OVALDownloadResult(); @@ -75,28 +119,34 @@ private File decompressIfNeeded(File file) { if (compressionMethod == OVALCompressionMethod.BZIP2) { uncompressedOVALFile = new File(file.getPath().replace(compressionMethod.extension(), "")); decompressBzip2(file, uncompressedOVALFile); - } else if (compressionMethod == OVALCompressionMethod.GZIP) { + } + else if (compressionMethod == OVALCompressionMethod.GZIP) { uncompressedOVALFile = new File(file.getPath().replace(compressionMethod.extension(), "")); decompressGzip(file, uncompressedOVALFile); - } else if (compressionMethod == OVALCompressionMethod.NOT_COMPRESSED) { + } + else if (compressionMethod == OVALCompressionMethod.NOT_COMPRESSED) { uncompressedOVALFile = file; - } else { + } + else { throw new IllegalStateException("Unable to decompress file: " + file.getPath()); } return uncompressedOVALFile; } - public OVALCompressionMethod getCompressionMethod(String filename) { + private OVALCompressionMethod getCompressionMethod(String filename) { Objects.requireNonNull(filename); if (filename.endsWith(".bz2")) { return OVALCompressionMethod.BZIP2; - } else if (filename.endsWith("gz")) { + } + else if (filename.endsWith("gz")) { return OVALCompressionMethod.GZIP; - } else if (filename.endsWith(".xml")) { + } + else if (filename.endsWith(".xml")) { return OVALCompressionMethod.NOT_COMPRESSED; - } else { + } + else { throw new IllegalStateException("OVAL file compressed with an unknown compression method"); } } @@ -107,7 +157,8 @@ public OVALCompressionMethod getCompressionMethod(String filename) { private static void decompressGzip(File archive, File target) { try (GZIPInputStream gis = new GZIPInputStream(new FileInputStream(archive))) { FileUtils.copyToFile(gis, target); - } catch (IOException e) { + } + catch (IOException e) { throw new RuntimeException("Failed to decompress GZIP archive", e); } } @@ -118,7 +169,8 @@ private static void decompressGzip(File archive, File target) { private static void decompressBzip2(File archive, File target) { try (InputStream inputStream = new BZip2CompressorInputStream(new FileInputStream(archive))) { FileUtils.copyToFile(inputStream, target); - } catch (IOException e) { + } + catch (IOException e) { throw new RuntimeException("Failed to decompress BZIP2 archive", e); } } From 4e7c6da2cd1ff20c49af0715e99d07208424f7e7 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sun, 18 Feb 2024 20:16:58 +0100 Subject: [PATCH 18/64] Refactor and fix checkstyle --- .../com/redhat/rhn/domain/server/Server.java | 13 ++++--- .../manager/audit/CVEAuditManagerOVAL.java | 25 +++++++------ .../manager/audit/CVEAuditSystemBuilder.java | 1 + java/code/src/com/suse/oval/OsFamily.java | 11 ++++++ .../src/com/suse/oval/config/OVALConfig.java | 33 +++++++++++++---- .../suse/oval/config/OVALConfigLoader.java | 32 +++++++++++++++++ .../config/OVALDistributionSourceInfo.java | 35 +++++++++++++++---- .../com/suse/oval/config/OVALSourceInfo.java | 29 +++++++++++---- 8 files changed, 144 insertions(+), 35 deletions(-) diff --git a/java/code/src/com/redhat/rhn/domain/server/Server.java b/java/code/src/com/redhat/rhn/domain/server/Server.java index 210d5bda985f..734338e8ca27 100644 --- a/java/code/src/com/redhat/rhn/domain/server/Server.java +++ b/java/code/src/com/redhat/rhn/domain/server/Server.java @@ -65,7 +65,6 @@ import java.util.Collections; import java.util.Comparator; import java.util.Date; -import java.util.EnumSet; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -2612,16 +2611,20 @@ else if (isRHEL() && OsFamily.REDHAT_ENTERPRISE_LINUX.isSupportedRelease(getRele getRelease().replace("\\..*", ""))); } else if (isSLES() && OsFamily.SUSE_LINUX_ENTERPRISE_SERVER.isSupportedRelease(getRelease())) { - return Optional.of(new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_SERVER, getRelease())); + return Optional.of( + new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_SERVER, getRelease())); } else if (isSLED() && OsFamily.SUSE_LINUX_ENTERPRISE_DESKTOP.isSupportedRelease(getRelease())) { - return Optional.of(new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_DESKTOP, getRelease())); + return Optional.of( + new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_DESKTOP, getRelease())); } else if (isLeapMicro() && OsFamily.LEAP_MICRO.isSupportedRelease(getRelease())) { - return Optional.of(new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_MICRO, getRelease())); + return Optional.of( + new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_MICRO, getRelease())); } else if (isSLEMicro() && OsFamily.SUSE_LINUX_ENTERPRISE_MICRO.isSupportedRelease(getRelease())) { - return Optional.of(new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_MICRO, getRelease())); + return Optional.of( + new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_MICRO, getRelease())); } return Optional.empty(); diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java index d2c7a4c87e88..cfd384e3fd1c 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java @@ -25,11 +25,10 @@ import com.redhat.rhn.manager.rhnpackage.PackageManager; import com.suse.oval.OVALCachingFactory; -import com.suse.oval.ShallowSystemPackage; - import com.suse.oval.OVALCleaner; import com.suse.oval.OsFamily; import com.suse.oval.OvalParser; +import com.suse.oval.ShallowSystemPackage; import com.suse.oval.config.OVALConfigLoader; import com.suse.oval.ovaldownloader.OVALDownloadResult; import com.suse.oval.ovaldownloader.OVALDownloader; @@ -100,7 +99,8 @@ public static List listSystemsByPatchStatus(User user, String cv CVEAuditManager.doAuditSystem(clientServer.getId(), resultsBySystem.get(clientServer.getId())); if (checkOVALAvailability(clientServer)) { - systemAuditResult = doAuditSystem(cveIdentifier, resultsBySystem.get(clientServer.getId()), clientServer); + systemAuditResult = + doAuditSystem(cveIdentifier, resultsBySystem.get(clientServer.getId()), clientServer); systemAuditResult.setChannels(auditWithChannelsResult.getChannels()); systemAuditResult.setErratas(auditWithChannelsResult.getErratas()); systemAuditResult.setScannedWithOVAL(true); @@ -390,25 +390,30 @@ public static class OVALProduct { private OsFamily osFamily; private String osVersion; - public OVALProduct(OsFamily osFamily, String osVersion) { - this.osFamily = osFamily; - this.osVersion = osVersion; + /** + * Default constructor + * @param osFamilyIn the os family + * @param osVersionIn the os version + * */ + public OVALProduct(OsFamily osFamilyIn, String osVersionIn) { + this.osFamily = osFamilyIn; + this.osVersion = osVersionIn; } public OsFamily getOsFamily() { return osFamily; } - public void setOsFamily(OsFamily osFamily) { - this.osFamily = osFamily; + public void setOsFamily(OsFamily osFamilyIn) { + this.osFamily = osFamilyIn; } public String getOsVersion() { return osVersion; } - public void setOsVersion(String osVersion) { - this.osVersion = osVersion; + public void setOsVersion(String osVersionIn) { + this.osVersion = osVersionIn; } @Override diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystemBuilder.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystemBuilder.java index f9e37b1ac34c..7fe6b93abc57 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystemBuilder.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystemBuilder.java @@ -187,6 +187,7 @@ public Long getId() { /** * Returns {@code True} if server was scanned with OVAL and {@code False} otherwise + * @return {@code True} if server was scanned with OVAL and {@code False} otherwise * */ public boolean isScannedWithOVAL() { return scannedWithOVAL; diff --git a/java/code/src/com/suse/oval/OsFamily.java b/java/code/src/com/suse/oval/OsFamily.java index 1cd51bc427d3..c99c95b2e864 100644 --- a/java/code/src/com/suse/oval/OsFamily.java +++ b/java/code/src/com/suse/oval/OsFamily.java @@ -48,10 +48,21 @@ public enum OsFamily { legalReleasePattern = Pattern.compile(legalReleaseRegex); } + /** + * Returns the full name of the OS family. + * + * @return OS family fullname + * */ public String fullname() { return fullname; } + /** + * Checks if the given OS release version is valid for this OS family. + * + * @param release the release version to check + * @return weather the given OS release version is valid for this OS family. + * */ public boolean isSupportedRelease(String release) { return legalReleasePattern.matcher(release).matches(); } diff --git a/java/code/src/com/suse/oval/config/OVALConfig.java b/java/code/src/com/suse/oval/config/OVALConfig.java index 40d57409d372..c044ac981337 100644 --- a/java/code/src/com/suse/oval/config/OVALConfig.java +++ b/java/code/src/com/suse/oval/config/OVALConfig.java @@ -1,8 +1,24 @@ +/* + * Copyright (c) 2023 SUSE LLC + * + * This software is licensed to you under the GNU General Public License, + * version 2 (GPLv2). There is NO WARRANTY for this software, express or + * implied, including the implied warranties of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 + * along with this software; if not, see + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * Red Hat trademarks are not licensed under GPLv2. No permission is + * granted to use or replicate Red Hat trademarks that are incorporated + * in this software or its documentation. + */ + package com.suse.oval.config; -import com.google.gson.annotations.SerializedName; import com.suse.oval.OsFamily; +import com.google.gson.annotations.SerializedName; + import java.util.Map; import java.util.Optional; @@ -10,17 +26,22 @@ public class OVALConfig { @SerializedName("sources") private Map sources; - public OVALConfig() { - } - public Map getSources() { return sources; } - public void setSources(Map sources) { - this.sources = sources; + private void setSources(Map sourcesIn) { + this.sources = sourcesIn; } + /** + * Finds the location or URL of the OVAL vulnerability and/or patch files for the given OVAL product + * identified by the given os family and version. + * + * @param osFamily the os family of the OS to find OVAL data for + * @param version the version of the OS to find OVAL data for + * @return the locations of OVAL vulnerability and/or patch files for the given OS + * */ public Optional lookupSourceInfo(OsFamily osFamily, String version) { OVALDistributionSourceInfo distributionSources = sources.get(osFamily); if (distributionSources != null) { diff --git a/java/code/src/com/suse/oval/config/OVALConfigLoader.java b/java/code/src/com/suse/oval/config/OVALConfigLoader.java index 1ec77c4dc016..96a8eeeecbb4 100644 --- a/java/code/src/com/suse/oval/config/OVALConfigLoader.java +++ b/java/code/src/com/suse/oval/config/OVALConfigLoader.java @@ -1,3 +1,18 @@ +/* + * Copyright (c) 2023 SUSE LLC + * + * This software is licensed to you under the GNU General Public License, + * version 2 (GPLv2). There is NO WARRANTY for this software, express or + * implied, including the implied warranties of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 + * along with this software; if not, see + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * Red Hat trademarks are not licensed under GPLv2. No permission is + * granted to use or replicate Red Hat trademarks that are incorporated + * in this software or its documentation. + */ + package com.suse.oval.config; import static com.suse.utils.Json.GSON; @@ -11,16 +26,28 @@ public class OVALConfigLoader { private static final String DEFAULT_CONFIG_PATH = "/usr/share/susemanager/scc/oval.config.json"; private final String configPath; + /** + * Default constructor + * @param configPathIn the path of oval.config.json + * */ public OVALConfigLoader(String configPathIn) { Objects.requireNonNull(configPathIn); this.configPath = configPathIn; } + /** + * Empty constructor + * */ public OVALConfigLoader() { this(DEFAULT_CONFIG_PATH); } + /** + * Reads {@code oval.config.json} from the given path, parses it and return it as a {@link OVALConfig} object. + * + * @return A configuration object that corresponds to {@code oval.config.json} + * */ public OVALConfig load() { File jsonConfigFile; try { @@ -32,6 +59,11 @@ public OVALConfig load() { } } + /** + * Loads the OVAL configuration file from the default path. + * + * @return the default OVAL config object. + * */ public static OVALConfig loadDefaultConfig() { return new OVALConfigLoader().load(); } diff --git a/java/code/src/com/suse/oval/config/OVALDistributionSourceInfo.java b/java/code/src/com/suse/oval/config/OVALDistributionSourceInfo.java index 887a8b53e1d2..82455e5e6827 100644 --- a/java/code/src/com/suse/oval/config/OVALDistributionSourceInfo.java +++ b/java/code/src/com/suse/oval/config/OVALDistributionSourceInfo.java @@ -1,3 +1,18 @@ +/* + * Copyright (c) 2023 SUSE LLC + * + * This software is licensed to you under the GNU General Public License, + * version 2 (GPLv2). There is NO WARRANTY for this software, express or + * implied, including the implied warranties of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 + * along with this software; if not, see + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * Red Hat trademarks are not licensed under GPLv2. No permission is + * granted to use or replicate Red Hat trademarks that are incorporated + * in this software or its documentation. + */ + package com.suse.oval.config; import com.google.gson.annotations.SerializedName; @@ -6,22 +21,28 @@ import java.util.Map; import java.util.Optional; +/** + * Encapsulates information about the supported Linux distributions and their corresponding sources of OVAL data. + * */ public class OVALDistributionSourceInfo { @SerializedName("content") - public Map content; - - public OVALDistributionSourceInfo() { - - } + private Map content; public Map getContent() { return content == null ? Collections.emptyMap() : content; } - public void setContent(Map content) { - this.content = content; + public void setContent(Map contentIn) { + this.content = contentIn; } + /** + * Returns the version source info + * + * @param version the OS version + * + * @return version source info + * */ public Optional getVersionSourceInfo(String version) { return Optional.ofNullable(getContent().get(version)); } diff --git a/java/code/src/com/suse/oval/config/OVALSourceInfo.java b/java/code/src/com/suse/oval/config/OVALSourceInfo.java index adde02e1baa3..682fb64f34c2 100644 --- a/java/code/src/com/suse/oval/config/OVALSourceInfo.java +++ b/java/code/src/com/suse/oval/config/OVALSourceInfo.java @@ -1,30 +1,45 @@ +/* + * Copyright (c) 2023 SUSE LLC + * + * This software is licensed to you under the GNU General Public License, + * version 2 (GPLv2). There is NO WARRANTY for this software, express or + * implied, including the implied warranties of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 + * along with this software; if not, see + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * Red Hat trademarks are not licensed under GPLv2. No permission is + * granted to use or replicate Red Hat trademarks that are incorporated + * in this software or its documentation. + */ + package com.suse.oval.config; import com.google.gson.annotations.SerializedName; +/** + * OVALSourceInfo + * */ public class OVALSourceInfo { @SerializedName("vulnerability") private String vulnerabilitiesInfoSource; @SerializedName("patch") private String patchInfoSource; - public OVALSourceInfo() { - } - public String getVulnerabilitiesInfoSource() { return vulnerabilitiesInfoSource; } - public void setVulnerabilitiesInfoSource(String vulnerabilitiesInfoSource) { - this.vulnerabilitiesInfoSource = vulnerabilitiesInfoSource; + public void setVulnerabilitiesInfoSource(String vulnerabilitiesInfoSourceIn) { + this.vulnerabilitiesInfoSource = vulnerabilitiesInfoSourceIn; } public String getPatchInfoSource() { return patchInfoSource; } - public void setPatchInfoSource(String patchInfoSource) { - this.patchInfoSource = patchInfoSource; + public void setPatchInfoSource(String patchInfoSourceIn) { + this.patchInfoSource = patchInfoSourceIn; } @Override From ae819baf98d5f1663b7dd26c6e99c27e491c8273 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sat, 24 Feb 2024 19:59:17 +0100 Subject: [PATCH 19/64] Use format specifiers instead of concatenation when logging --- .../src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java index cfd384e3fd1c..3dc82ea79a05 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java @@ -347,9 +347,9 @@ public static void syncOVAL() { } LOG.debug("Downloading finished"); - LOG.debug("OVAL vulnerability file: " + + LOG.debug("OVAL vulnerability file: {}", downloadResult.getVulnerabilityFile().map(File::getAbsoluteFile).orElse(null)); - LOG.debug("OVAL patch file: " + downloadResult.getPatchFile().map(File::getAbsoluteFile).orElse(null)); + LOG.debug("OVAL patch file: {}", downloadResult.getPatchFile().map(File::getAbsoluteFile).orElse(null)); downloadResult.getVulnerabilityFile().ifPresent(ovalVulnerabilityFile -> { OvalParser ovalParser = new OvalParser(); From 170d3af9787210b4f7c6328de9efb9d9d1298dd7 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sun, 25 Feb 2024 14:30:48 +0100 Subject: [PATCH 20/64] Remove unused methods --- java/code/src/com/suse/oval/config/OVALConfig.java | 4 ---- .../com/suse/oval/config/OVALDistributionSourceInfo.java | 4 ---- java/code/src/com/suse/oval/config/OVALSourceInfo.java | 8 -------- .../src/com/suse/oval/ovaldownloader/OVALDownloader.java | 1 + 4 files changed, 1 insertion(+), 16 deletions(-) diff --git a/java/code/src/com/suse/oval/config/OVALConfig.java b/java/code/src/com/suse/oval/config/OVALConfig.java index c044ac981337..dd26318d152f 100644 --- a/java/code/src/com/suse/oval/config/OVALConfig.java +++ b/java/code/src/com/suse/oval/config/OVALConfig.java @@ -30,10 +30,6 @@ public Map getSources() { return sources; } - private void setSources(Map sourcesIn) { - this.sources = sourcesIn; - } - /** * Finds the location or URL of the OVAL vulnerability and/or patch files for the given OVAL product * identified by the given os family and version. diff --git a/java/code/src/com/suse/oval/config/OVALDistributionSourceInfo.java b/java/code/src/com/suse/oval/config/OVALDistributionSourceInfo.java index 82455e5e6827..da15e8fd1c86 100644 --- a/java/code/src/com/suse/oval/config/OVALDistributionSourceInfo.java +++ b/java/code/src/com/suse/oval/config/OVALDistributionSourceInfo.java @@ -32,10 +32,6 @@ public Map getContent() { return content == null ? Collections.emptyMap() : content; } - public void setContent(Map contentIn) { - this.content = contentIn; - } - /** * Returns the version source info * diff --git a/java/code/src/com/suse/oval/config/OVALSourceInfo.java b/java/code/src/com/suse/oval/config/OVALSourceInfo.java index 682fb64f34c2..2aeceb178993 100644 --- a/java/code/src/com/suse/oval/config/OVALSourceInfo.java +++ b/java/code/src/com/suse/oval/config/OVALSourceInfo.java @@ -30,18 +30,10 @@ public String getVulnerabilitiesInfoSource() { return vulnerabilitiesInfoSource; } - public void setVulnerabilitiesInfoSource(String vulnerabilitiesInfoSourceIn) { - this.vulnerabilitiesInfoSource = vulnerabilitiesInfoSourceIn; - } - public String getPatchInfoSource() { return patchInfoSource; } - public void setPatchInfoSource(String patchInfoSourceIn) { - this.patchInfoSource = patchInfoSourceIn; - } - @Override public String toString() { return "OVALSourceInfo{" + diff --git a/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java b/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java index cf2628574754..cfca8b306b85 100644 --- a/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java +++ b/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java @@ -42,6 +42,7 @@ public class OVALDownloader { /** * The path where downloaded OVAL files will be stored. + * TODO: Decide on a better location to cache OVAL files * */ private static final String DOWNLOAD_PATH = "/var/log/rhn/ovals/"; /** From 7a9ac7fac0120872c66aa91cca36455ef7002004 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sun, 25 Feb 2024 14:42:10 +0100 Subject: [PATCH 21/64] Refactor Server#toOVALProduct --- .../com/redhat/rhn/domain/server/Server.java | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/java/code/src/com/redhat/rhn/domain/server/Server.java b/java/code/src/com/redhat/rhn/domain/server/Server.java index 734338e8ca27..6457b8587f14 100644 --- a/java/code/src/com/redhat/rhn/domain/server/Server.java +++ b/java/code/src/com/redhat/rhn/domain/server/Server.java @@ -2596,38 +2596,37 @@ boolean isRocky9() { * (for example product maintainers don't produce OVAL data) * */ public Optional toOVALProduct() { - if (isDebian() && OsFamily.DEBIAN.isSupportedRelease(getRelease())) { - return Optional.of(new CVEAuditManagerOVAL.OVALProduct(OsFamily.DEBIAN, getRelease())); + String osRelease = getRelease(); + + CVEAuditManagerOVAL.OVALProduct ovalProduct = null; + if (isDebian() && OsFamily.DEBIAN.isSupportedRelease(osRelease)) { + ovalProduct = new CVEAuditManagerOVAL.OVALProduct(OsFamily.DEBIAN, osRelease); } - else if (isUbuntu() && OsFamily.UBUNTU.isSupportedRelease(getRelease())) { - return Optional.of(new CVEAuditManagerOVAL.OVALProduct(OsFamily.UBUNTU, getRelease())); + else if (isUbuntu() && OsFamily.UBUNTU.isSupportedRelease(osRelease)) { + ovalProduct = new CVEAuditManagerOVAL.OVALProduct(OsFamily.UBUNTU, osRelease); } - else if (isLeap() && OsFamily.LEAP.isSupportedRelease(getRelease())) { - return Optional.of(new CVEAuditManagerOVAL.OVALProduct(OsFamily.LEAP, getRelease())); + else if (isLeap() && OsFamily.LEAP.isSupportedRelease(osRelease)) { + ovalProduct = new CVEAuditManagerOVAL.OVALProduct(OsFamily.LEAP, osRelease); } - else if (isRHEL() && OsFamily.REDHAT_ENTERPRISE_LINUX.isSupportedRelease(getRelease())) { - return Optional.of(new CVEAuditManagerOVAL.OVALProduct(OsFamily.REDHAT_ENTERPRISE_LINUX, + else if (isRHEL() && OsFamily.REDHAT_ENTERPRISE_LINUX.isSupportedRelease(osRelease)) { + ovalProduct = new CVEAuditManagerOVAL.OVALProduct(OsFamily.REDHAT_ENTERPRISE_LINUX, // Removing the fractional part from the version .e.g. '9.2' to '9' - getRelease().replace("\\..*", ""))); + osRelease.replace("\\..*", "")); } - else if (isSLES() && OsFamily.SUSE_LINUX_ENTERPRISE_SERVER.isSupportedRelease(getRelease())) { - return Optional.of( - new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_SERVER, getRelease())); + else if (isSLES() && OsFamily.SUSE_LINUX_ENTERPRISE_SERVER.isSupportedRelease(osRelease)) { + ovalProduct = new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_SERVER, osRelease); } - else if (isSLED() && OsFamily.SUSE_LINUX_ENTERPRISE_DESKTOP.isSupportedRelease(getRelease())) { - return Optional.of( - new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_DESKTOP, getRelease())); + else if (isSLED() && OsFamily.SUSE_LINUX_ENTERPRISE_DESKTOP.isSupportedRelease(osRelease)) { + ovalProduct = new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_DESKTOP, osRelease); } - else if (isLeapMicro() && OsFamily.LEAP_MICRO.isSupportedRelease(getRelease())) { - return Optional.of( - new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_MICRO, getRelease())); + else if (isLeapMicro() && OsFamily.LEAP_MICRO.isSupportedRelease(osRelease)) { + ovalProduct = new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_MICRO, osRelease); } - else if (isSLEMicro() && OsFamily.SUSE_LINUX_ENTERPRISE_MICRO.isSupportedRelease(getRelease())) { - return Optional.of( - new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_MICRO, getRelease())); + else if (isSLEMicro() && OsFamily.SUSE_LINUX_ENTERPRISE_MICRO.isSupportedRelease(osRelease)) { + ovalProduct = new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_MICRO, osRelease); } - return Optional.empty(); + return Optional.ofNullable(ovalProduct); } /** From e783046a5039a92c8d75366f6366313249ab507a Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Thu, 29 Feb 2024 13:33:51 +0100 Subject: [PATCH 22/64] Add changelogs --- java/spacewalk-java.changes.HoussemNasri.oval-downloader | 3 +++ .../susemanager-schema.changes.HoussemNasri.oval-downloader | 1 + .../susemanager-sync-data.changes.HoussemNasri.oval-downloader | 2 ++ web/spacewalk-web.changes.HoussemNasri.oval-downloader | 2 ++ 4 files changed, 8 insertions(+) create mode 100644 java/spacewalk-java.changes.HoussemNasri.oval-downloader create mode 100644 schema/spacewalk/susemanager-schema.changes.HoussemNasri.oval-downloader create mode 100644 susemanager-sync-data/susemanager-sync-data.changes.HoussemNasri.oval-downloader create mode 100644 web/spacewalk-web.changes.HoussemNasri.oval-downloader diff --git a/java/spacewalk-java.changes.HoussemNasri.oval-downloader b/java/spacewalk-java.changes.HoussemNasri.oval-downloader new file mode 100644 index 000000000000..16875a1e51ba --- /dev/null +++ b/java/spacewalk-java.changes.HoussemNasri.oval-downloader @@ -0,0 +1,3 @@ +- Enable the synchronization of OVAL data +- Enable the configuration of OVAL data sources +- Add support for OVAL based cve auditing to SLE & Leap Micro diff --git a/schema/spacewalk/susemanager-schema.changes.HoussemNasri.oval-downloader b/schema/spacewalk/susemanager-schema.changes.HoussemNasri.oval-downloader new file mode 100644 index 000000000000..a794d6bb236f --- /dev/null +++ b/schema/spacewalk/susemanager-schema.changes.HoussemNasri.oval-downloader @@ -0,0 +1 @@ +- Add a new task to handle OVAL data synchronization diff --git a/susemanager-sync-data/susemanager-sync-data.changes.HoussemNasri.oval-downloader b/susemanager-sync-data/susemanager-sync-data.changes.HoussemNasri.oval-downloader new file mode 100644 index 000000000000..a04f40302c4b --- /dev/null +++ b/susemanager-sync-data/susemanager-sync-data.changes.HoussemNasri.oval-downloader @@ -0,0 +1,2 @@ +- Deploy a configuration file named oval.config.json to configure + OVAL data sources diff --git a/web/spacewalk-web.changes.HoussemNasri.oval-downloader b/web/spacewalk-web.changes.HoussemNasri.oval-downloader new file mode 100644 index 000000000000..0847510d51d8 --- /dev/null +++ b/web/spacewalk-web.changes.HoussemNasri.oval-downloader @@ -0,0 +1,2 @@ +- Add a column to the CVE auditing result table to show the data + source (OVAL or channels) used for auditing the system \ No newline at end of file From 42984808545e1fae4a2cfee33984a8d8e7df528e Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Thu, 29 Feb 2024 13:36:30 +0100 Subject: [PATCH 23/64] Revert "Use channel data until full OVAL implementation is ready" This reverts commit 6c86362ce45b6c05250d5c3e421099884c081331. It is ready! --- .../rhn/frontend/xmlrpc/audit/CVEAuditHandler.java | 8 +++----- .../webui/controllers/CVEAuditController.java | 14 +++++--------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/java/code/src/com/redhat/rhn/frontend/xmlrpc/audit/CVEAuditHandler.java b/java/code/src/com/redhat/rhn/frontend/xmlrpc/audit/CVEAuditHandler.java index f8e3f26a08bf..39732ef89f7b 100644 --- a/java/code/src/com/redhat/rhn/frontend/xmlrpc/audit/CVEAuditHandler.java +++ b/java/code/src/com/redhat/rhn/frontend/xmlrpc/audit/CVEAuditHandler.java @@ -20,7 +20,7 @@ import com.redhat.rhn.frontend.xmlrpc.MethodInvalidParamException; import com.redhat.rhn.frontend.xmlrpc.UnknownCVEIdentifierFaultException; import com.redhat.rhn.manager.audit.CVEAuditImage; -import com.redhat.rhn.manager.audit.CVEAuditManager; +import com.redhat.rhn.manager.audit.CVEAuditManagerOVAL; import com.redhat.rhn.manager.audit.CVEAuditServer; import com.redhat.rhn.manager.audit.PatchStatus; import com.redhat.rhn.manager.audit.UnknownCVEIdentifierException; @@ -117,8 +117,7 @@ public List listSystemsByPatchStatus(User loggedInUser, } try { - // TODO: Use CVEAuditManagerOVAL once it's ready - List result = CVEAuditManager.listSystemsByPatchStatus( + List result = CVEAuditManagerOVAL.listSystemsByPatchStatus( loggedInUser, cveIdentifier, patchStatuses); result.sort(Comparator.comparingInt(s -> s.getPatchStatus().getRank())); @@ -210,8 +209,7 @@ public List listImagesByPatchStatus(User loggedInUser, } try { - // TODO: Use CVEAuditManagerOVAL once it's ready - List result = CVEAuditManager.listImagesByPatchStatus( + List result = CVEAuditManagerOVAL.listImagesByPatchStatus( loggedInUser, cveIdentifier, patchStatuses); result.sort(Comparator.comparingInt(i -> i.getPatchStatus().getRank())); diff --git a/java/code/src/com/suse/manager/webui/controllers/CVEAuditController.java b/java/code/src/com/suse/manager/webui/controllers/CVEAuditController.java index 7dcce74c7d48..8ecf54abafce 100644 --- a/java/code/src/com/suse/manager/webui/controllers/CVEAuditController.java +++ b/java/code/src/com/suse/manager/webui/controllers/CVEAuditController.java @@ -25,7 +25,7 @@ import com.redhat.rhn.common.localization.LocalizationService; import com.redhat.rhn.domain.user.User; import com.redhat.rhn.manager.audit.CVEAuditImage; -import com.redhat.rhn.manager.audit.CVEAuditManager; +import com.redhat.rhn.manager.audit.CVEAuditManagerOVAL; import com.redhat.rhn.manager.audit.CVEAuditServer; import com.redhat.rhn.manager.audit.CVEAuditSystem; import com.redhat.rhn.manager.audit.PatchStatus; @@ -142,15 +142,13 @@ public static Object cveAudit(Request req, Response res, User user) { switch (cveAuditRequest.getTarget()) { case SERVER: Set systemSet = RhnSetDecl.SYSTEMS.get(user).getElementValues(); - // TODO: Use CVEAuditManagerOVAL once it's ready - List cveAuditServers = CVEAuditManager + List cveAuditServers = CVEAuditManagerOVAL .listSystemsByPatchStatus(user, cveAuditRequest.cveIdentifier, cveAuditRequest.statuses); cveAuditServers.forEach(serv -> serv.setSelected(systemSet.contains(serv.getId()))); return result(res, ResultJson.success(cveAuditServers), new TypeToken<>() { }); case IMAGE: - // TODO: Use CVEAuditManagerOVAL once it's ready - List cveAuditImages = CVEAuditManager + List cveAuditImages = CVEAuditManagerOVAL .listImagesByPatchStatus(user, cveAuditRequest.cveIdentifier, cveAuditRequest.statuses); return result(res, ResultJson.success(cveAuditImages), new TypeToken<>() { }); @@ -166,15 +164,13 @@ private static List handleRequest(CVEAuditRequest request, User throws UnknownCVEIdentifierException { switch (request.getTarget()) { case SERVER: - // TODO: Use CVEAuditManagerOVAL once it's ready - List cveAuditServers = CVEAuditManager + List cveAuditServers = CVEAuditManagerOVAL .listSystemsByPatchStatus(user, request.cveIdentifier, request.statuses); return cveAuditServers.stream().map(x -> (CVEAuditSystem)x) .collect(Collectors.toList()); case IMAGE: - // TODO: Use CVEAuditManagerOVAL once it's ready - List cveAuditImages = CVEAuditManager + List cveAuditImages = CVEAuditManagerOVAL .listImagesByPatchStatus(user, request.cveIdentifier, request.statuses); return cveAuditImages.stream().map(x -> (CVEAuditSystem)x) From e96be51976062dea6c80475a1007b12d7ecd096e Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sat, 9 Mar 2024 18:59:24 +0100 Subject: [PATCH 24/64] Copyright (c) 2024 --- java/code/src/com/redhat/rhn/taskomatic/task/OVALDataSync.java | 2 +- java/code/src/com/suse/oval/config/OVALConfig.java | 2 +- java/code/src/com/suse/oval/config/OVALConfigLoader.java | 2 +- .../src/com/suse/oval/config/OVALDistributionSourceInfo.java | 2 +- java/code/src/com/suse/oval/config/OVALSourceInfo.java | 2 +- java/code/src/com/suse/oval/config/test/OVALConfigTest.java | 2 +- .../src/com/suse/oval/ovaldownloader/OVALCompressionMethod.java | 2 +- .../src/com/suse/oval/ovaldownloader/OVALDownloadResult.java | 2 +- java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java | 2 +- .../003-oval-taskomatic.sql | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/java/code/src/com/redhat/rhn/taskomatic/task/OVALDataSync.java b/java/code/src/com/redhat/rhn/taskomatic/task/OVALDataSync.java index 9c662831b702..0ba414d9f292 100644 --- a/java/code/src/com/redhat/rhn/taskomatic/task/OVALDataSync.java +++ b/java/code/src/com/redhat/rhn/taskomatic/task/OVALDataSync.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 SUSE LLC + * Copyright (c) 2024 SUSE LLC * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or diff --git a/java/code/src/com/suse/oval/config/OVALConfig.java b/java/code/src/com/suse/oval/config/OVALConfig.java index dd26318d152f..f030188eaf74 100644 --- a/java/code/src/com/suse/oval/config/OVALConfig.java +++ b/java/code/src/com/suse/oval/config/OVALConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 SUSE LLC + * Copyright (c) 2024 SUSE LLC * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or diff --git a/java/code/src/com/suse/oval/config/OVALConfigLoader.java b/java/code/src/com/suse/oval/config/OVALConfigLoader.java index 96a8eeeecbb4..c9bb9e9b84c8 100644 --- a/java/code/src/com/suse/oval/config/OVALConfigLoader.java +++ b/java/code/src/com/suse/oval/config/OVALConfigLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 SUSE LLC + * Copyright (c) 2024 SUSE LLC * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or diff --git a/java/code/src/com/suse/oval/config/OVALDistributionSourceInfo.java b/java/code/src/com/suse/oval/config/OVALDistributionSourceInfo.java index da15e8fd1c86..666c47473d6e 100644 --- a/java/code/src/com/suse/oval/config/OVALDistributionSourceInfo.java +++ b/java/code/src/com/suse/oval/config/OVALDistributionSourceInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 SUSE LLC + * Copyright (c) 2024 SUSE LLC * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or diff --git a/java/code/src/com/suse/oval/config/OVALSourceInfo.java b/java/code/src/com/suse/oval/config/OVALSourceInfo.java index 2aeceb178993..214a76285a30 100644 --- a/java/code/src/com/suse/oval/config/OVALSourceInfo.java +++ b/java/code/src/com/suse/oval/config/OVALSourceInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 SUSE LLC + * Copyright (c) 2024 SUSE LLC * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or diff --git a/java/code/src/com/suse/oval/config/test/OVALConfigTest.java b/java/code/src/com/suse/oval/config/test/OVALConfigTest.java index 99e53a531a8c..443aeef33893 100644 --- a/java/code/src/com/suse/oval/config/test/OVALConfigTest.java +++ b/java/code/src/com/suse/oval/config/test/OVALConfigTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 SUSE LLC + * Copyright (c) 2024 SUSE LLC * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or diff --git a/java/code/src/com/suse/oval/ovaldownloader/OVALCompressionMethod.java b/java/code/src/com/suse/oval/ovaldownloader/OVALCompressionMethod.java index 92267c4d05db..6329f75f55fa 100644 --- a/java/code/src/com/suse/oval/ovaldownloader/OVALCompressionMethod.java +++ b/java/code/src/com/suse/oval/ovaldownloader/OVALCompressionMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 SUSE LLC + * Copyright (c) 2024 SUSE LLC * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or diff --git a/java/code/src/com/suse/oval/ovaldownloader/OVALDownloadResult.java b/java/code/src/com/suse/oval/ovaldownloader/OVALDownloadResult.java index ed2f962ef178..b9a3349df198 100644 --- a/java/code/src/com/suse/oval/ovaldownloader/OVALDownloadResult.java +++ b/java/code/src/com/suse/oval/ovaldownloader/OVALDownloadResult.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 SUSE LLC + * Copyright (c) 2024 SUSE LLC * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or diff --git a/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java b/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java index cfca8b306b85..c984a48af58a 100644 --- a/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java +++ b/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 SUSE LLC + * Copyright (c) 2024 SUSE LLC * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or diff --git a/schema/spacewalk/upgrade/susemanager-schema-4.4.6-to-susemanager-schema-4.4.7/003-oval-taskomatic.sql b/schema/spacewalk/upgrade/susemanager-schema-4.4.6-to-susemanager-schema-4.4.7/003-oval-taskomatic.sql index 14c948b3124b..c9e6744a37e3 100644 --- a/schema/spacewalk/upgrade/susemanager-schema-4.4.6-to-susemanager-schema-4.4.7/003-oval-taskomatic.sql +++ b/schema/spacewalk/upgrade/susemanager-schema-4.4.6-to-susemanager-schema-4.4.7/003-oval-taskomatic.sql @@ -1,5 +1,5 @@ -- --- Copyright (c) 2023 SUSE LLC +-- Copyright (c) 2024 SUSE LLC -- -- This software is licensed to you under the GNU General Public License, -- version 2 (GPLv2). There is NO WARRANTY for this software, express or From 0f1398859299e373fc7b017d7ddb5ef4827f9078 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sat, 9 Mar 2024 19:06:19 +0100 Subject: [PATCH 25/64] Prevent synchronizing OVAL data for the same product twice --- .../manager/audit/CVEAuditManagerOVAL.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java index 3dc82ea79a05..f1c61e55e6a9 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java @@ -331,7 +331,7 @@ public static void populateCVEChannels() { * Launches the OVAL synchronization process * */ public static void syncOVAL() { - List productsToSync = getProductsToSync(); + Set productsToSync = getProductsToSync(); LOG.debug("Detected {} products eligible for OVAL synchronization: {}", productsToSync.size(), productsToSync); @@ -378,12 +378,12 @@ public static void syncOVAL() { /** * Identifies the OS products to synchronize OVAL data for. * */ - private static List getProductsToSync() { + private static Set getProductsToSync() { List allServers = ServerFactory.list(false, false); return allServers.stream().map(Server::toOVALProduct) .filter(Optional::isPresent) - .map(Optional::get).collect(Collectors.toList()); + .map(Optional::get).collect(Collectors.toSet()); } public static class OVALProduct { @@ -416,6 +416,19 @@ public void setOsVersion(String osVersionIn) { this.osVersion = osVersionIn; } + @Override + public boolean equals(Object oIn) { + if (this == oIn) return true; + if (oIn == null || getClass() != oIn.getClass()) return false; + OVALProduct that = (OVALProduct) oIn; + return osFamily == that.osFamily && Objects.equals(osVersion, that.osVersion); + } + + @Override + public int hashCode() { + return Objects.hash(osFamily, osVersion); + } + @Override public String toString() { return osFamily.fullname() + " " + osVersion; From baed757def5013527fa4bfa26538410a39bab853 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sat, 16 Mar 2024 22:14:36 +0100 Subject: [PATCH 26/64] Avoid fetching all servers to detect the set of operating systems they use - We have deployments with more than 10k systems. This would load all of them when we should have a few of different OS flavors. --- .../rhn/domain/server/ServerFactory.java | 15 +++++++ .../domain/server/Server_legacyUser.hbm.xml | 6 +++ .../manager/audit/CVEAuditManagerOVAL.java | 19 ++++++--- .../rhn/manager/audit/OsReleasePair.java | 41 +++++++++++++++++++ 4 files changed, 76 insertions(+), 5 deletions(-) create mode 100644 java/code/src/com/redhat/rhn/manager/audit/OsReleasePair.java diff --git a/java/code/src/com/redhat/rhn/domain/server/ServerFactory.java b/java/code/src/com/redhat/rhn/domain/server/ServerFactory.java index 71a509cfdf7d..767c19f0272f 100644 --- a/java/code/src/com/redhat/rhn/domain/server/ServerFactory.java +++ b/java/code/src/com/redhat/rhn/domain/server/ServerFactory.java @@ -42,6 +42,7 @@ import com.redhat.rhn.frontend.dto.SystemOverview; import com.redhat.rhn.frontend.xmlrpc.ChannelSubscriptionException; import com.redhat.rhn.frontend.xmlrpc.ServerNotInGroupException; +import com.redhat.rhn.manager.audit.OsReleasePair; import com.redhat.rhn.manager.entitlement.EntitlementManager; import com.redhat.rhn.manager.rhnset.RhnSetDecl; import com.redhat.rhn.manager.system.SystemManager; @@ -66,6 +67,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -249,6 +251,19 @@ public static Optional lookupProxyServer(String name) { } } + /** + * List the unique set of pairs of os and release versions used by servers + * + * @return the set of unique pairs of os and release version used by servers + * */ + public static Set listAllServersOsAndRelease() { + List result = SINGLETON.listObjectsByNamedQuery("Server.listAllServersOsAndRelease", + Collections.emptyMap()); + + return result.stream().map(row -> new OsReleasePair((String) row[0], (String) row[1])) + .collect(Collectors.toSet()); + } + /** * Return a map from Salt minion IDs to System IDs. * Map entries are limited to systems that are visible by the specified user. diff --git a/java/code/src/com/redhat/rhn/domain/server/Server_legacyUser.hbm.xml b/java/code/src/com/redhat/rhn/domain/server/Server_legacyUser.hbm.xml index 03aee52ae5fb..977545c6b6a0 100644 --- a/java/code/src/com/redhat/rhn/domain/server/Server_legacyUser.hbm.xml +++ b/java/code/src/com/redhat/rhn/domain/server/Server_legacyUser.hbm.xml @@ -361,6 +361,12 @@ PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" WHERE USP.user_id = :user_id AND USP.server_id = s.id) ]]> + + + + getProductsToSync() { - List allServers = ServerFactory.list(false, false); - - return allServers.stream().map(Server::toOVALProduct) + Set allServersOsAndRelease = ServerFactory.listAllServersOsAndRelease(); + return allServersOsAndRelease.stream().map(osReleasePairIn -> { + Server server = ServerFactory.createServer(); + server.setOs(osReleasePairIn.getOs()); + server.setRelease(osReleasePairIn.getOsRelease()); + return server; + } + ).map(Server::toOVALProduct) .filter(Optional::isPresent) .map(Optional::get).collect(Collectors.toSet()); } @@ -418,8 +423,12 @@ public void setOsVersion(String osVersionIn) { @Override public boolean equals(Object oIn) { - if (this == oIn) return true; - if (oIn == null || getClass() != oIn.getClass()) return false; + if (this == oIn) { + return true; + } + if (oIn == null || getClass() != oIn.getClass()) { + return false; + } OVALProduct that = (OVALProduct) oIn; return osFamily == that.osFamily && Objects.equals(osVersion, that.osVersion); } diff --git a/java/code/src/com/redhat/rhn/manager/audit/OsReleasePair.java b/java/code/src/com/redhat/rhn/manager/audit/OsReleasePair.java new file mode 100644 index 000000000000..583ab68e84c4 --- /dev/null +++ b/java/code/src/com/redhat/rhn/manager/audit/OsReleasePair.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024 SUSE LLC + * + * This software is licensed to you under the GNU General Public License, + * version 2 (GPLv2). There is NO WARRANTY for this software, express or + * implied, including the implied warranties of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 + * along with this software; if not, see + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * Red Hat trademarks are not licensed under GPLv2. No permission is + * granted to use or replicate Red Hat trademarks that are incorporated + * in this software or its documentation. + */ + +package com.redhat.rhn.manager.audit; + +public class OsReleasePair { + private final String os; + private final String osRelease; + + /** + * Default Constructor + * @param osIn the name of the OS + * @param osReleaseIn the OS release version + * */ + public OsReleasePair(String osIn, String osReleaseIn) { + os = osIn; + osRelease = osReleaseIn; + } + + public String getOs() { + return os; + } + + public String getOsRelease() { + return osRelease; + } + + +} From ddcfda1eaf15ff4705f60dc42af9ba24e52fcc6c Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sat, 16 Mar 2024 22:17:55 +0100 Subject: [PATCH 27/64] Log the starting and ending of the OVAL syncing task - Since the task runs once a day by default, using log#info instead of log#debug makes more sense. --- .../src/com/redhat/rhn/taskomatic/task/OVALDataSync.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/java/code/src/com/redhat/rhn/taskomatic/task/OVALDataSync.java b/java/code/src/com/redhat/rhn/taskomatic/task/OVALDataSync.java index 0ba414d9f292..931b38219414 100644 --- a/java/code/src/com/redhat/rhn/taskomatic/task/OVALDataSync.java +++ b/java/code/src/com/redhat/rhn/taskomatic/task/OVALDataSync.java @@ -31,14 +31,10 @@ public String getConfigNamespace() { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { - if (log.isDebugEnabled()) { - log.debug("Syncing OVAL data"); - } + log.info("Syncing OVAL data"); CVEAuditManagerOVAL.syncOVAL(); - if (log.isDebugEnabled()) { - log.debug("Done syncing OVAL data"); - } + log.info("Done syncing OVAL data"); } } From 89dc45a8cf1e8042564819aa4f4b5c2eb2bb15b9 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sat, 16 Mar 2024 22:18:32 +0100 Subject: [PATCH 28/64] Rephrase comment in OVALCleaner --- java/code/src/com/suse/oval/OVALCleaner.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/java/code/src/com/suse/oval/OVALCleaner.java b/java/code/src/com/suse/oval/OVALCleaner.java index 2627b935cefb..f044916a4c04 100644 --- a/java/code/src/com/suse/oval/OVALCleaner.java +++ b/java/code/src/com/suse/oval/OVALCleaner.java @@ -142,10 +142,11 @@ private static void doCleanupObject(ObjectType object, OsFamily osFamily, String } /** - * Debian Ids are not unique among different versions, so it's possible to have OVAL constructs that have the - * same id but different content for different versions of Debian. - *

- * To work around this, we insert the codename of the version into the id string + * Debian Ids are not unique among different versions. For example, it is possible to find an OVAL test with + * {@code id = "1"} in the OVAL file of debian buster and debian bullseye. This would create a conflict between + * the two tests. + * To work around this and to have globally unique IDs for OVAL tests, we insert the codename of the version into + * the id string. */ private static void convertDebianTestRefs(BaseCriteria root, String osVersion) { if (root instanceof CriteriaType) { From 00ae7c04befbbeeacb2058b716fa3694e06a2d47 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sat, 16 Mar 2024 22:55:38 +0100 Subject: [PATCH 29/64] Fix typo in oval.config.json --- java/code/src/com/suse/oval/config/test/oval.config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/code/src/com/suse/oval/config/test/oval.config.json b/java/code/src/com/suse/oval/config/test/oval.config.json index ba012b8f3460..34e6ce6a8838 100644 --- a/java/code/src/com/suse/oval/config/test/oval.config.json +++ b/java/code/src/com/suse/oval/config/test/oval.config.json @@ -1,6 +1,6 @@ { "sources": { - "openSUSE_LEAP": { + "LEAP": { "content": { "15.2": { "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.15.2-affected.xml.gz", From 374bb8e9a70ae1ee064c8b1932e9e38ab5996a14 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sun, 17 Mar 2024 20:28:56 +0100 Subject: [PATCH 30/64] Refactor OVALDownloader - Also deleted OVALCompressionMethod as it is not needed anymore --- .../ovaldownloader/OVALCompressionMethod.java | 32 ------------------- .../oval/ovaldownloader/OVALDownloader.java | 31 ++++-------------- 2 files changed, 7 insertions(+), 56 deletions(-) delete mode 100644 java/code/src/com/suse/oval/ovaldownloader/OVALCompressionMethod.java diff --git a/java/code/src/com/suse/oval/ovaldownloader/OVALCompressionMethod.java b/java/code/src/com/suse/oval/ovaldownloader/OVALCompressionMethod.java deleted file mode 100644 index 6329f75f55fa..000000000000 --- a/java/code/src/com/suse/oval/ovaldownloader/OVALCompressionMethod.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2024 SUSE LLC - * - * This software is licensed to you under the GNU General Public License, - * version 2 (GPLv2). There is NO WARRANTY for this software, express or - * implied, including the implied warranties of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 - * along with this software; if not, see - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * Red Hat trademarks are not licensed under GPLv2. No permission is - * granted to use or replicate Red Hat trademarks that are incorporated - * in this software or its documentation. - */ - -package com.suse.oval.ovaldownloader; - -/** - * The compression method used to compress the OVAL file. - * */ -public enum OVALCompressionMethod { - GZIP(".gz"), NOT_COMPRESSED(".xml"), BZIP2(".bz2"); - private final String extension; - - OVALCompressionMethod(String extensionIn) { - this.extension = extensionIn; - } - - String extension() { - return extension; - } -} diff --git a/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java b/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java index c984a48af58a..9586d768aef4 100644 --- a/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java +++ b/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java @@ -29,7 +29,6 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; -import java.util.Objects; import java.util.Optional; import java.util.zip.GZIPInputStream; /** @@ -115,17 +114,18 @@ private File downloadOVALFile(String vulnerabilityInfoSource) throws IOException } private File decompressIfNeeded(File file) { - OVALCompressionMethod compressionMethod = getCompressionMethod(file.getName()); + String filename = file.getName(); + File uncompressedOVALFile; - if (compressionMethod == OVALCompressionMethod.BZIP2) { - uncompressedOVALFile = new File(file.getPath().replace(compressionMethod.extension(), "")); + if (filename.endsWith(".bz2")) { + uncompressedOVALFile = new File(FilenameUtils.removeExtension(file.getPath())); decompressBzip2(file, uncompressedOVALFile); } - else if (compressionMethod == OVALCompressionMethod.GZIP) { - uncompressedOVALFile = new File(file.getPath().replace(compressionMethod.extension(), "")); + else if (filename.endsWith(".gz")) { + uncompressedOVALFile = new File(FilenameUtils.removeExtension(file.getPath())); decompressGzip(file, uncompressedOVALFile); } - else if (compressionMethod == OVALCompressionMethod.NOT_COMPRESSED) { + else if (filename.endsWith(".xml")) { uncompressedOVALFile = file; } else { @@ -135,23 +135,6 @@ else if (compressionMethod == OVALCompressionMethod.NOT_COMPRESSED) { return uncompressedOVALFile; } - private OVALCompressionMethod getCompressionMethod(String filename) { - Objects.requireNonNull(filename); - - if (filename.endsWith(".bz2")) { - return OVALCompressionMethod.BZIP2; - } - else if (filename.endsWith("gz")) { - return OVALCompressionMethod.GZIP; - } - else if (filename.endsWith(".xml")) { - return OVALCompressionMethod.NOT_COMPRESSED; - } - else { - throw new IllegalStateException("OVAL file compressed with an unknown compression method"); - } - } - /** * Decompress the GZIP {@code archive} into {@code target} file. */ From 8e61f4aa4f9b3ac8a273e4e46f2f5a226166e18c Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sun, 17 Mar 2024 20:41:24 +0100 Subject: [PATCH 31/64] Refactor to avoid code duplication --- .../manager/audit/CVEAuditManagerOVAL.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java index c5a63be5e148..8141ce066282 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java @@ -352,29 +352,28 @@ public static void syncOVAL() { LOG.debug("OVAL patch file: {}", downloadResult.getPatchFile().map(File::getAbsoluteFile).orElse(null)); downloadResult.getVulnerabilityFile().ifPresent(ovalVulnerabilityFile -> { - OvalParser ovalParser = new OvalParser(); - OvalRootType ovalRoot = ovalParser.parse(ovalVulnerabilityFile); - + extractAndSaveOVALData(product, ovalVulnerabilityFile); LOG.debug("Saving Vulnerability OVAL for {} {}", product.getOsFamily(), product.getOsVersion()); - - OVALCleaner.cleanup(ovalRoot, product.getOsFamily(), product.getOsVersion()); - OVALCachingFactory.savePlatformsVulnerablePackages(ovalRoot); }); downloadResult.getPatchFile().ifPresent(patchFile -> { - OvalParser ovalParser = new OvalParser(); - OvalRootType ovalRoot = ovalParser.parse(patchFile); - + extractAndSaveOVALData(product, patchFile); LOG.debug("Saving Patch OVAL for {} {}", product.getOsFamily(), product.getOsVersion()); - - OVALCleaner.cleanup(ovalRoot, product.getOsFamily(), product.getOsVersion()); - OVALCachingFactory.savePlatformsVulnerablePackages(ovalRoot); }); LOG.debug("Saving OVAL finished"); } } + /** + * Extracts OVAL metadata from the given {@code ovalFile}, clean it and save it to the database. + * */ + private static void extractAndSaveOVALData(OVALProduct product, File ovalFile) { + OvalRootType ovalRoot = new OvalParser().parse(ovalFile); + OVALCleaner.cleanup(ovalRoot, product.getOsFamily(), product.getOsVersion()); + OVALCachingFactory.savePlatformsVulnerablePackages(ovalRoot); + } + /** * Identifies the OS products to synchronize OVAL data for. * */ From 518a859ffa1859a2a7100481fe957bb51457bf6d Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sun, 17 Mar 2024 20:52:25 +0100 Subject: [PATCH 32/64] Clarify comments --- .../src/com/redhat/rhn/manager/audit/CVEAuditImage.java | 7 +++++-- .../src/com/redhat/rhn/manager/audit/CVEAuditServer.java | 7 +++++-- .../redhat/rhn/manager/audit/CVEAuditSystemBuilder.java | 7 +++++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditImage.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditImage.java index 007533cf6cc5..ccc563dba297 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditImage.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditImage.java @@ -27,8 +27,11 @@ public class CVEAuditImage implements CVEAuditSystem { private long id; private String name; private PatchStatus patchStatus; - // If server was scanned wth CVEAuditManager#doAuditSystem instead of CVEAuditManagerOVAL#doAuditSystem then - // it's possible to get false negatives. + /** + * Why need this? + * If image was scanned wth CVEAuditManager#doAuditSystem instead of CVEAuditManagerOVAL#doAuditSystem then + * it's possible to get false negatives. + */ private boolean scannedWithOVAL; private Set channels; diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditServer.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditServer.java index 22852a21c745..f97659fb7917 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditServer.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditServer.java @@ -29,8 +29,11 @@ public class CVEAuditServer extends SelectableAdapter implements CVEAuditSystem private long id; private String name; private PatchStatus patchStatus; - // If server was scanned wth CVEAuditManager#doAuditSystem instead of CVEAuditManagerOVAL#doAuditSystem then - // it's possible to get false negatives. + /** + * Why need this? + * If server was scanned wth CVEAuditManager#doAuditSystem instead of CVEAuditManagerOVAL#doAuditSystem then + * it's possible to get false negatives. + */ private boolean scannedWithOVAL; // LinkedHashSet is used to preserve insertion order when iterating diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystemBuilder.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystemBuilder.java index 7fe6b93abc57..7240dd8ae195 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystemBuilder.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystemBuilder.java @@ -30,8 +30,11 @@ public class CVEAuditSystemBuilder { private long systemID; private String systemName; private PatchStatus patchStatus; - // If system was audited wth CVEAuditManager#doAuditSystem instead of CVEAuditManagerOVAL#doAuditSystem then - // it's possible to get false negatives. + /** + * Why need this? + * If server was scanned wth CVEAuditManager#doAuditSystem instead of CVEAuditManagerOVAL#doAuditSystem then + * it's possible to get false negatives. + */ private boolean scannedWithOVAL; // LinkedHashSet is used to preserve insertion order when iterating From 17d3379d6f086cdb36bd82ee04095d2ba6428b9e Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Thu, 11 Apr 2024 21:54:49 +0100 Subject: [PATCH 33/64] Increase connection and read timeouts while downloading OVAL data - Increased it to 15 seconds. --- java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java b/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java index 9586d768aef4..2c30adb0104a 100644 --- a/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java +++ b/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java @@ -108,7 +108,7 @@ private File downloadOVALFile(String vulnerabilityInfoSource) throws IOException File vulnerabilityFile = new File(DOWNLOAD_PATH + vulnerabilityInfoOVALFilename); // Start downloading - FileUtils.copyURLToFile(vulnerabilityInfoURL, vulnerabilityFile, 10_000, 10_000); + FileUtils.copyURLToFile(vulnerabilityInfoURL, vulnerabilityFile, 15_000, 15_000); return decompressIfNeeded(vulnerabilityFile); } From e57ce14b8cfad59a808f8b47049e4d0d910f11df Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Thu, 11 Apr 2024 21:56:28 +0100 Subject: [PATCH 34/64] Store downloaded OVAL files in a cache directory --- .../oval/ovaldownloader/OVALDownloader.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java b/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java index 2c30adb0104a..01942678a4c7 100644 --- a/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java +++ b/java/code/src/com/suse/oval/ovaldownloader/OVALDownloader.java @@ -15,6 +15,9 @@ package com.suse.oval.ovaldownloader; +import com.redhat.rhn.common.conf.Config; +import com.redhat.rhn.common.conf.ConfigDefaults; + import com.suse.oval.OsFamily; import com.suse.oval.config.OVALConfig; import com.suse.oval.config.OVALSourceInfo; @@ -29,6 +32,8 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Optional; import java.util.zip.GZIPInputStream; /** @@ -41,9 +46,8 @@ public class OVALDownloader { /** * The path where downloaded OVAL files will be stored. - * TODO: Decide on a better location to cache OVAL files * */ - private static final String DOWNLOAD_PATH = "/var/log/rhn/ovals/"; + private final String ovalCacheDir; /** * A configuration object that corresponds to {@code oval.config.json} * */ @@ -56,6 +60,17 @@ public class OVALDownloader { * */ public OVALDownloader(OVALConfig configIn) { this.config = configIn; + String mountPoint = Config.get().getString(ConfigDefaults.REPOMD_CACHE_MOUNT_POINT, "/var/cache"); + Path ovalCacheDirPath = Path.of(mountPoint, "rhn", "ovals").toAbsolutePath(); + + try { + Files.createDirectories(ovalCacheDirPath); + ovalCacheDir = ovalCacheDirPath.toAbsolutePath().toString(); + } + catch (IOException eIn) { + throw new RuntimeException("Couldn't create OVAL cache directory", eIn); + } + } /** @@ -105,8 +120,7 @@ private OVALDownloadResult doDownload(OVALSourceInfo sourceInfo) private File downloadOVALFile(String vulnerabilityInfoSource) throws IOException { URL vulnerabilityInfoURL = new URL(vulnerabilityInfoSource); String vulnerabilityInfoOVALFilename = FilenameUtils.getName(vulnerabilityInfoURL.getPath()); - File vulnerabilityFile = - new File(DOWNLOAD_PATH + vulnerabilityInfoOVALFilename); + File vulnerabilityFile = Path.of(ovalCacheDir, vulnerabilityInfoOVALFilename).toFile(); // Start downloading FileUtils.copyURLToFile(vulnerabilityInfoURL, vulnerabilityFile, 15_000, 15_000); From 4f424738134c0a5578ae320c971b86eb3cdc2be0 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sat, 16 Mar 2024 22:05:36 +0100 Subject: [PATCH 35/64] Move the toOVALProduct method to OsReleasePair --- .../com/redhat/rhn/domain/server/Server.java | 45 ------------------- .../manager/audit/CVEAuditManagerOVAL.java | 11 ++--- .../rhn/manager/audit/OsReleasePair.java | 29 ++++++++++++ java/code/src/com/suse/oval/OsFamily.java | 39 +++++++++++----- 4 files changed, 59 insertions(+), 65 deletions(-) diff --git a/java/code/src/com/redhat/rhn/domain/server/Server.java b/java/code/src/com/redhat/rhn/domain/server/Server.java index 6457b8587f14..a70dee1e7972 100644 --- a/java/code/src/com/redhat/rhn/domain/server/Server.java +++ b/java/code/src/com/redhat/rhn/domain/server/Server.java @@ -36,7 +36,6 @@ import com.redhat.rhn.domain.rhnpackage.PackageEvr; import com.redhat.rhn.domain.rhnpackage.PackageType; import com.redhat.rhn.domain.user.User; -import com.redhat.rhn.manager.audit.CVEAuditManagerOVAL; import com.redhat.rhn.manager.configuration.ConfigurationManager; import com.redhat.rhn.manager.entitlement.EntitlementManager; import com.redhat.rhn.manager.kickstart.cobbler.CobblerXMLRPCHelper; @@ -45,7 +44,6 @@ import com.suse.manager.model.attestation.ServerCoCoAttestationConfig; import com.suse.manager.model.attestation.ServerCoCoAttestationReport; import com.suse.manager.model.maintenance.MaintenanceSchedule; -import com.suse.oval.OsFamily; import com.suse.utils.Opt; import org.apache.commons.lang3.StringUtils; @@ -2586,49 +2584,6 @@ boolean isRocky9() { return ServerConstants.ROCKY.equals(getOs()) && getRelease().startsWith("9."); } - /** - * Derives an {@link com.redhat.rhn.manager.audit.CVEAuditManagerOVAL.OVALProduct} object based on the server's - * information, including the operating system name and release version. Used by the OVAL synchronization process - * to identify the installed product and synchronize OVAL data for it. - * - * @return the information of the installed product to synchronize OVAL data for if the product is eligible for - * OVAL synchronization and {@code Optional.empty} otherwise - * (for example product maintainers don't produce OVAL data) - * */ - public Optional toOVALProduct() { - String osRelease = getRelease(); - - CVEAuditManagerOVAL.OVALProduct ovalProduct = null; - if (isDebian() && OsFamily.DEBIAN.isSupportedRelease(osRelease)) { - ovalProduct = new CVEAuditManagerOVAL.OVALProduct(OsFamily.DEBIAN, osRelease); - } - else if (isUbuntu() && OsFamily.UBUNTU.isSupportedRelease(osRelease)) { - ovalProduct = new CVEAuditManagerOVAL.OVALProduct(OsFamily.UBUNTU, osRelease); - } - else if (isLeap() && OsFamily.LEAP.isSupportedRelease(osRelease)) { - ovalProduct = new CVEAuditManagerOVAL.OVALProduct(OsFamily.LEAP, osRelease); - } - else if (isRHEL() && OsFamily.REDHAT_ENTERPRISE_LINUX.isSupportedRelease(osRelease)) { - ovalProduct = new CVEAuditManagerOVAL.OVALProduct(OsFamily.REDHAT_ENTERPRISE_LINUX, - // Removing the fractional part from the version .e.g. '9.2' to '9' - osRelease.replace("\\..*", "")); - } - else if (isSLES() && OsFamily.SUSE_LINUX_ENTERPRISE_SERVER.isSupportedRelease(osRelease)) { - ovalProduct = new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_SERVER, osRelease); - } - else if (isSLED() && OsFamily.SUSE_LINUX_ENTERPRISE_DESKTOP.isSupportedRelease(osRelease)) { - ovalProduct = new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_DESKTOP, osRelease); - } - else if (isLeapMicro() && OsFamily.LEAP_MICRO.isSupportedRelease(osRelease)) { - ovalProduct = new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_MICRO, osRelease); - } - else if (isSLEMicro() && OsFamily.SUSE_LINUX_ENTERPRISE_MICRO.isSupportedRelease(osRelease)) { - ovalProduct = new CVEAuditManagerOVAL.OVALProduct(OsFamily.SUSE_LINUX_ENTERPRISE_MICRO, osRelease); - } - - return Optional.ofNullable(ovalProduct); - } - /** * Getter for os family * diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java index 8141ce066282..225b055f73d9 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java @@ -378,14 +378,9 @@ private static void extractAndSaveOVALData(OVALProduct product, File ovalFile) { * Identifies the OS products to synchronize OVAL data for. * */ private static Set getProductsToSync() { - Set allServersOsAndRelease = ServerFactory.listAllServersOsAndRelease(); - return allServersOsAndRelease.stream().map(osReleasePairIn -> { - Server server = ServerFactory.createServer(); - server.setOs(osReleasePairIn.getOs()); - server.setRelease(osReleasePairIn.getOsRelease()); - return server; - } - ).map(Server::toOVALProduct) + return ServerFactory.listAllServersOsAndRelease() + .stream() + .map(OsReleasePair::toOVALProduct) .filter(Optional::isPresent) .map(Optional::get).collect(Collectors.toSet()); } diff --git a/java/code/src/com/redhat/rhn/manager/audit/OsReleasePair.java b/java/code/src/com/redhat/rhn/manager/audit/OsReleasePair.java index 583ab68e84c4..1e74a931f193 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/OsReleasePair.java +++ b/java/code/src/com/redhat/rhn/manager/audit/OsReleasePair.java @@ -15,6 +15,10 @@ package com.redhat.rhn.manager.audit; +import com.suse.oval.OsFamily; + +import java.util.Optional; + public class OsReleasePair { private final String os; private final String osRelease; @@ -37,5 +41,30 @@ public String getOsRelease() { return osRelease; } + /** + * Derives an {@link com.redhat.rhn.manager.audit.CVEAuditManagerOVAL.OVALProduct} object based on the server's + * information, including the operating system name and release version. Used by the OVAL synchronization process + * to identify the installed product and synchronize OVAL data for it. + * + * @return the information of the installed product to synchronize OVAL data for if the product is eligible for + * OVAL synchronization and {@code Optional.empty} otherwise + * (for example product maintainers don't produce OVAL data) + * */ + public Optional toOVALProduct() { + return OsFamily.fromOsName(os).flatMap(serverOsFamily -> { + String serverOsRelease = getOsRelease(); + if (serverOsFamily == OsFamily.REDHAT_ENTERPRISE_LINUX) { + serverOsRelease = serverOsRelease.replace("\\..*", ""); + } + + CVEAuditManagerOVAL.OVALProduct ovalProduct = null; + if (serverOsFamily.isSupportedRelease(serverOsRelease)) { + ovalProduct = new CVEAuditManagerOVAL.OVALProduct(serverOsFamily, serverOsRelease); + } + + return Optional.ofNullable(ovalProduct); + }); + } + } diff --git a/java/code/src/com/suse/oval/OsFamily.java b/java/code/src/com/suse/oval/OsFamily.java index c99c95b2e864..6766739e2699 100644 --- a/java/code/src/com/suse/oval/OsFamily.java +++ b/java/code/src/com/suse/oval/OsFamily.java @@ -15,35 +15,40 @@ package com.suse.oval; +import com.redhat.rhn.domain.server.Server; + import java.util.Arrays; +import java.util.Optional; import java.util.regex.Pattern; import java.util.stream.Collectors; public enum OsFamily { - LEAP("openSUSE Leap", "leap", "opensuse", + LEAP("openSUSE Leap", "Leap", "opensuse", oneOf("15.2", "15.3", "15.4", "15.5")), - LEAP_MICRO("openSUSELeap Micro", "leap-micro", "opensuse", + LEAP_MICRO("openSUSELeap Micro", "openSUE Leap Micro", "opensuse", oneOf("5.2", "5.3")), - SUSE_LINUX_ENTERPRISE_SERVER("SUSE Linux Enterprise Server", "sles", "suse", + SUSE_LINUX_ENTERPRISE_SERVER("SUSE Linux Enterprise Server", "SLES", "suse", oneOf("11", "12", "15")), - SUSE_LINUX_ENTERPRISE_DESKTOP("SUSE Linux Enterprise Desktop", "sled", "suse", + SUSE_LINUX_ENTERPRISE_DESKTOP("SUSE Linux Enterprise Desktop", "SLED", "suse", oneOf("10", "11", "12", "15")), - SUSE_LINUX_ENTERPRISE_MICRO("SUSE Linux Enterprise Micro", "sle-micro", "suse", + SUSE_LINUX_ENTERPRISE_MICRO("SUSE Linux Enterprise Micro", "SLE Micro", "suse", oneOf("5.0", "5.1", "5.2", "5.3")), - REDHAT_ENTERPRISE_LINUX("Red Hat Enterprise Linux", "enterprise_linux", "redhat", + REDHAT_ENTERPRISE_LINUX("Red Hat Enterprise Linux", "Red Hat Enterprise Linux", "redhat", withPrefix("7.", "8.", "9.")), - UBUNTU("Ubuntu", "ubuntu", "canonical", oneOf("18.04", "20.04", "22.04")), - DEBIAN("Debian", "debian", "debian", oneOf("10", "11", "12")); + UBUNTU("Ubuntu", "Ubuntu", "canonical", oneOf("18.04", "20.04", "22.04")), + DEBIAN("Debian", "Debian", "debian", oneOf("10", "11", "12")); private final String vendor; private final String fullname; - // Should consist of all lower case characters - private final String shortname; + /** + * Should consist of the same values as {@link Server#getOs()} + * */ + private final String os; private final Pattern legalReleasePattern; - OsFamily(String fullnameIn, String shortnameIn, String vendorIn, String legalReleaseRegex) { + OsFamily(String fullnameIn, String osIn, String vendorIn, String legalReleaseRegex) { this.fullname = fullnameIn; - this.shortname = shortnameIn; + this.os = osIn; this.vendor = vendorIn; legalReleasePattern = Pattern.compile(legalReleaseRegex); } @@ -80,4 +85,14 @@ private static String withPrefix(String ... legalReleasePrefixes) { private static String[] escapePeriods(String ... strings) { return Arrays.stream(strings).map(str -> str.replace(".", "\\.")).toArray(String[]::new); } + + /** + * Creates an {@code OsFamily} object from the given os name. + * + * @param osName the os name to convert (it should consist of the same values as {@link Server#getOs()}) + * @return the os family that correspond to the given os name. + * */ + public static Optional fromOsName(String osName) { + return Arrays.stream(values()).filter(osFamily -> osFamily.os.equalsIgnoreCase(osName)).findFirst(); + } } From c3c46e440f68ec1e286c422bbed3d051fb3218ea Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Fri, 12 Apr 2024 00:16:43 +0100 Subject: [PATCH 36/64] Undo OVAL support for ubuntu - Support for ubuntu requires more changes and thus will be added in its own PR. --- java/code/src/com/suse/oval/OsFamily.java | 4 +++- .../com/suse/oval/config/test/oval.config.json | 16 ---------------- susemanager-sync-data/oval.config.json | 16 ---------------- 3 files changed, 3 insertions(+), 33 deletions(-) diff --git a/java/code/src/com/suse/oval/OsFamily.java b/java/code/src/com/suse/oval/OsFamily.java index 6766739e2699..e15ba2f63ce9 100644 --- a/java/code/src/com/suse/oval/OsFamily.java +++ b/java/code/src/com/suse/oval/OsFamily.java @@ -22,6 +22,9 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; +/** + * This enum defines the operating system families for which we can retrieve OVAL data. + * */ public enum OsFamily { LEAP("openSUSE Leap", "Leap", "opensuse", oneOf("15.2", "15.3", "15.4", "15.5")), @@ -35,7 +38,6 @@ public enum OsFamily { oneOf("5.0", "5.1", "5.2", "5.3")), REDHAT_ENTERPRISE_LINUX("Red Hat Enterprise Linux", "Red Hat Enterprise Linux", "redhat", withPrefix("7.", "8.", "9.")), - UBUNTU("Ubuntu", "Ubuntu", "canonical", oneOf("18.04", "20.04", "22.04")), DEBIAN("Debian", "Debian", "debian", oneOf("10", "11", "12")); private final String vendor; diff --git a/java/code/src/com/suse/oval/config/test/oval.config.json b/java/code/src/com/suse/oval/config/test/oval.config.json index 34e6ce6a8838..26c29bd166b4 100644 --- a/java/code/src/com/suse/oval/config/test/oval.config.json +++ b/java/code/src/com/suse/oval/config/test/oval.config.json @@ -92,22 +92,6 @@ } } }, - "UBUNTU": { - "content": { - "18.04": { - "vulnerability": "https://security-metadata.canonical.com/oval/com.ubuntu.bionic.cve.oval.xml.bz2", - "patch": "" - }, - "20.04": { - "vulnerability": "https://security-metadata.canonical.com/oval/com.ubuntu.focal.cve.oval.xml.bz2", - "patch": "" - }, - "22.04": { - "vulnerability": "https://security-metadata.canonical.com/oval/com.ubuntu.jammy.cve.oval.xml.bz2", - "patch": "" - } - } - }, "REDHAT_ENTERPRISE_LINUX": { "content": { "7": { diff --git a/susemanager-sync-data/oval.config.json b/susemanager-sync-data/oval.config.json index 34e6ce6a8838..26c29bd166b4 100644 --- a/susemanager-sync-data/oval.config.json +++ b/susemanager-sync-data/oval.config.json @@ -92,22 +92,6 @@ } } }, - "UBUNTU": { - "content": { - "18.04": { - "vulnerability": "https://security-metadata.canonical.com/oval/com.ubuntu.bionic.cve.oval.xml.bz2", - "patch": "" - }, - "20.04": { - "vulnerability": "https://security-metadata.canonical.com/oval/com.ubuntu.focal.cve.oval.xml.bz2", - "patch": "" - }, - "22.04": { - "vulnerability": "https://security-metadata.canonical.com/oval/com.ubuntu.jammy.cve.oval.xml.bz2", - "patch": "" - } - } - }, "REDHAT_ENTERPRISE_LINUX": { "content": { "7": { From 954c7dd925e68f8bb949352cab582642f033d2cc Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sun, 5 May 2024 17:32:37 +0100 Subject: [PATCH 37/64] Extract the cve from tag in OVAL files - In openSUSE Leap 15.5 OVAL file, I found CVE-2018-1000155 at SUSE which resulted in an exception being thrown when OVAL data is written to the database, because of the length of the CVE (more than 20 characters). --- java/code/src/com/suse/oval/OVALCleaner.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/java/code/src/com/suse/oval/OVALCleaner.java b/java/code/src/com/suse/oval/OVALCleaner.java index f044916a4c04..08abf85552f4 100644 --- a/java/code/src/com/suse/oval/OVALCleaner.java +++ b/java/code/src/com/suse/oval/OVALCleaner.java @@ -33,6 +33,8 @@ import java.util.Collections; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; /** @@ -40,6 +42,7 @@ * OVAL data from multiple sources and make changes to it to have a more predictable format. */ public class OVALCleaner { + private OVALCleaner() { } @@ -82,6 +85,8 @@ private static void doCleanupDefinition(DefinitionType definition, OsFamily osFa } } + private static final Pattern EXTRACT_CVE_REGEX = Pattern.compile(".*(CVE-[0-9]{4}-[0-9]+).*"); + private static void fillCves(DefinitionType definition, OsFamily osFamily) { switch (osFamily) { case REDHAT_ENTERPRISE_LINUX: @@ -93,7 +98,15 @@ private static void fillCves(DefinitionType definition, OsFamily osFamily) { List cves = definition.getMetadata().getAdvisory().map(Advisory::getCveList) .orElse(Collections.emptyList()) - .stream().map(AdvisoryCveType::getCve).collect(Collectors.toList()); + .stream().map(AdvisoryCveType::getCve) + .map(cve -> { + Matcher matcher = EXTRACT_CVE_REGEX.matcher(cve); + if (matcher.find()) { + return matcher.group(1); + } + + return ""; + }).filter(StringUtils::isNotBlank).collect(Collectors.toList()); definition.setCves(cves); break; case DEBIAN: From a9aa82f50dd534327996adc18f78b968a08fd7c7 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sun, 5 May 2024 17:56:22 +0100 Subject: [PATCH 38/64] Display the list of data sources used to scan each client server - Only two possible data sources: OVAL and Channels --- .../rhn/manager/audit/CVEAuditImage.java | 10 +-- .../rhn/manager/audit/CVEAuditManager.java | 2 +- .../manager/audit/CVEAuditManagerOVAL.java | 66 ++++++++++++++----- .../rhn/manager/audit/CVEAuditServer.java | 17 ++--- .../rhn/manager/audit/CVEAuditSystem.java | 9 ++- .../manager/audit/CVEAuditSystemBuilder.java | 27 ++++---- .../rhn/manager/audit/ScanDataSource.java | 30 +++++++++ .../src/manager/audit/cveaudit/cveaudit.tsx | 11 +--- 8 files changed, 103 insertions(+), 69 deletions(-) create mode 100644 java/code/src/com/redhat/rhn/manager/audit/ScanDataSource.java diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditImage.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditImage.java index ccc563dba297..c4295e254b0b 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditImage.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditImage.java @@ -27,12 +27,6 @@ public class CVEAuditImage implements CVEAuditSystem { private long id; private String name; private PatchStatus patchStatus; - /** - * Why need this? - * If image was scanned wth CVEAuditManager#doAuditSystem instead of CVEAuditManagerOVAL#doAuditSystem then - * it's possible to get false negatives. - */ - private boolean scannedWithOVAL; private Set channels; private Set erratas; @@ -101,8 +95,8 @@ public Set getErratas() { } @Override - public boolean isScannedWithOVAL() { - return scannedWithOVAL; + public Set getScanDataSources() { + return Set.of(); } } diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManager.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManager.java index d71643b2aa19..eb462b12b96d 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManager.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManager.java @@ -878,7 +878,7 @@ public static List listSystemsByPatchStatus(User user, system.getPatchStatus(), system.getChannels(), system.getErratas(), - false + Set.of(ScanDataSource.CHANNELS) )).collect(Collectors.toList()); } diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java index 225b055f73d9..231bc471a7b3 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java @@ -41,6 +41,7 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Map; @@ -92,32 +93,50 @@ public static List listSystemsByPatchStatus(User user, String cv Set clients = user.getServers(); for (Server clientServer : clients) { - CVEAuditSystemBuilder systemAuditResult; - // We need this initially to be able to get errata and audit channels information for the OVAL - // implementation. - CVEAuditSystemBuilder auditWithChannelsResult = - CVEAuditManager.doAuditSystem(clientServer.getId(), resultsBySystem.get(clientServer.getId())); + CVEAuditSystemBuilder auditWithChannelsResult = null; + CVEAuditSystemBuilder auditWithOVALResult = null; if (checkOVALAvailability(clientServer)) { - systemAuditResult = + auditWithOVALResult = doAuditSystem(cveIdentifier, resultsBySystem.get(clientServer.getId()), clientServer); - systemAuditResult.setChannels(auditWithChannelsResult.getChannels()); - systemAuditResult.setErratas(auditWithChannelsResult.getErratas()); - systemAuditResult.setScannedWithOVAL(true); + } + + if (checkChannelsDataAvailability(clientServer)) { + auditWithChannelsResult = + CVEAuditManager.doAuditSystem(clientServer.getId(), resultsBySystem.get(clientServer.getId())); + } + + CVEAuditSystemBuilder auditResult; + if (auditWithOVALResult != null && auditWithChannelsResult != null) { + auditWithOVALResult.setChannels(auditWithChannelsResult.getChannels()); + auditWithOVALResult.setErratas(auditWithChannelsResult.getErratas()); + auditWithOVALResult.setScanDataSources(ScanDataSource.OVAL, ScanDataSource.CHANNELS); + auditResult = auditWithOVALResult; + } + else if (auditWithOVALResult != null) { + auditWithOVALResult.setChannels(Collections.emptySet()); + auditWithOVALResult.setErratas(Collections.emptySet()); + auditWithOVALResult.setScanDataSources(ScanDataSource.OVAL); + auditResult = auditWithOVALResult; + } + else if (auditWithChannelsResult != null) { + auditWithChannelsResult.setScanDataSources(ScanDataSource.CHANNELS); + auditResult = auditWithChannelsResult; } else { - systemAuditResult = auditWithChannelsResult; - systemAuditResult.setScannedWithOVAL(false); + auditResult = new CVEAuditSystemBuilder(clientServer.getId()); + // TODO: Maybe we should add an "unknown" patch status type? + auditResult.setPatchStatus(PatchStatus.NOT_AFFECTED); } - if (patchStatuses.contains(systemAuditResult.getPatchStatus())) { + if (patchStatuses.contains(auditResult.getPatchStatus())) { result.add(new CVEAuditServer( - systemAuditResult.getId(), - systemAuditResult.getSystemName(), - systemAuditResult.getPatchStatus(), - systemAuditResult.getChannels(), - systemAuditResult.getErratas(), - systemAuditResult.isScannedWithOVAL())); + auditResult.getId(), + auditResult.getSystemName(), + auditResult.getPatchStatus(), + auditResult.getChannels(), + auditResult.getErratas(), + auditResult.getScanDataSources())); } } @@ -134,6 +153,17 @@ public static boolean checkOVALAvailability(Server clientServer) { return OVALCachingFactory.checkOVALAvailability(clientServer.getCpe()); } + /** + * Check if we have CVE channels data for the OS product installed on the given client server + * + * @param clientServer the server to check + * @return {@code True} + * */ + public static boolean checkChannelsDataAvailability(Server clientServer) { + // TODO: Implement! + return true; + } + private static boolean isCVEIdentifierUnknown(String cveIdentifier) { return !OVALCachingFactory.canAuditCVE(cveIdentifier) && CVEAuditManager.isCVEIdentifierUnknown(cveIdentifier); } diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditServer.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditServer.java index f97659fb7917..c4099529ae9d 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditServer.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditServer.java @@ -29,12 +29,7 @@ public class CVEAuditServer extends SelectableAdapter implements CVEAuditSystem private long id; private String name; private PatchStatus patchStatus; - /** - * Why need this? - * If server was scanned wth CVEAuditManager#doAuditSystem instead of CVEAuditManagerOVAL#doAuditSystem then - * it's possible to get false negatives. - */ - private boolean scannedWithOVAL; + private Set scanDataSources; // LinkedHashSet is used to preserve insertion order when iterating private Set channels; @@ -48,17 +43,17 @@ public class CVEAuditServer extends SelectableAdapter implements CVEAuditSystem * @param statusIn status * @param channelsIn channels * @param erratasIn errata - * @param scannedWithOVALIn scannedWithOVAL + * @param scanDataSourcesIn scan data sources */ public CVEAuditServer(long idIn, String nameIn, PatchStatus statusIn, Set channelsIn, - Set erratasIn, boolean scannedWithOVALIn) { + Set erratasIn, Set scanDataSourcesIn) { this.id = idIn; this.name = nameIn; this.patchStatus = statusIn; this.channels = channelsIn; this.erratas = erratasIn; - this.scannedWithOVAL = scannedWithOVALIn; + this.scanDataSources = scanDataSourcesIn; } /** @@ -123,7 +118,7 @@ public Set getErratas() { * @inherit * */ @Override - public boolean isScannedWithOVAL() { - return scannedWithOVAL; + public Set getScanDataSources() { + return scanDataSources; } } diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystem.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystem.java index 6f3ec6b62694..1da8edd8d029 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystem.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystem.java @@ -53,11 +53,10 @@ public interface CVEAuditSystem { Set getErratas(); /** - * Returns if the system was scanned with OVAL instead of Channels - * - * @return {@code True} of server was scanned with OVAL and {@code False} otherwise. - */ - boolean isScannedWithOVAL(); + * Return the data sources used to scan the system. + * @return the set of data sources + * */ + Set getScanDataSources(); /** * Return the closest channel as {@link String} for CSV file download. diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystemBuilder.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystemBuilder.java index 7240dd8ae195..de32087d773c 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystemBuilder.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditSystemBuilder.java @@ -14,6 +14,8 @@ */ package com.redhat.rhn.manager.audit; +import java.util.Arrays; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Set; @@ -30,12 +32,7 @@ public class CVEAuditSystemBuilder { private long systemID; private String systemName; private PatchStatus patchStatus; - /** - * Why need this? - * If server was scanned wth CVEAuditManager#doAuditSystem instead of CVEAuditManagerOVAL#doAuditSystem then - * it's possible to get false negatives. - */ - private boolean scannedWithOVAL; + private Set scanDataSources = new HashSet<>(); // LinkedHashSet is used to preserve insertion order when iterating private Set channels = @@ -189,18 +186,16 @@ public Long getId() { } /** - * Returns {@code True} if server was scanned with OVAL and {@code False} otherwise - * @return {@code True} if server was scanned with OVAL and {@code False} otherwise + * Returns the list of data sources used to audit the system. + * + * @return list of data sources * */ - public boolean isScannedWithOVAL() { - return scannedWithOVAL; + public Set getScanDataSources() { + return scanDataSources; } - /** - * Sets scannedWithOVAL - * @param scannedWithOVALIn the value to set - * */ - public void setScannedWithOVAL(boolean scannedWithOVALIn) { - this.scannedWithOVAL = scannedWithOVALIn; + + public void setScanDataSources(ScanDataSource... dataSourcesIn) { + scanDataSources = new HashSet<>(Arrays.asList(dataSourcesIn)); } } diff --git a/java/code/src/com/redhat/rhn/manager/audit/ScanDataSource.java b/java/code/src/com/redhat/rhn/manager/audit/ScanDataSource.java new file mode 100644 index 000000000000..fa0c419bf2e5 --- /dev/null +++ b/java/code/src/com/redhat/rhn/manager/audit/ScanDataSource.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 SUSE LLC + * + * This software is licensed to you under the GNU General Public License, + * version 2 (GPLv2). There is NO WARRANTY for this software, express or + * implied, including the implied warranties of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 + * along with this software; if not, see + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * Red Hat trademarks are not licensed under GPLv2. No permission is + * granted to use or replicate Red Hat trademarks that are incorporated + * in this software or its documentation. + */ + +package com.redhat.rhn.manager.audit; + +public enum ScanDataSource { + OVAL("Oval"), CHANNELS("Channels"); + + private final String displayName; + + ScanDataSource(String displayNameIn) { + this.displayName = displayNameIn; + } + + public String getDisplayName() { + return displayName; + } +} diff --git a/web/html/src/manager/audit/cveaudit/cveaudit.tsx b/web/html/src/manager/audit/cveaudit/cveaudit.tsx index b048243e529a..32220dd0e21e 100644 --- a/web/html/src/manager/audit/cveaudit/cveaudit.tsx +++ b/web/html/src/manager/audit/cveaudit/cveaudit.tsx @@ -484,16 +484,7 @@ class CVEAudit extends React.Component { comparator={Utils.sortByText} header={t("Scan Data")} cell={(row, criteria) => { - return ( -

- {t(row.scannedWithOVAL ? "OVAL" : "Channels")} -
- ); + return
{row.scanDataSources.join(", ")}
; }} /> From 13322600ffe087de2fa43473f13509e215811cbc Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sun, 5 May 2024 18:37:28 +0100 Subject: [PATCH 39/64] Change regex to not be vulnerable to polynomial runtime due to backtracking --- java/code/src/com/suse/oval/OVALCleaner.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/code/src/com/suse/oval/OVALCleaner.java b/java/code/src/com/suse/oval/OVALCleaner.java index 08abf85552f4..9fba5d739b99 100644 --- a/java/code/src/com/suse/oval/OVALCleaner.java +++ b/java/code/src/com/suse/oval/OVALCleaner.java @@ -85,7 +85,7 @@ private static void doCleanupDefinition(DefinitionType definition, OsFamily osFa } } - private static final Pattern EXTRACT_CVE_REGEX = Pattern.compile(".*(CVE-[0-9]{4}-[0-9]+).*"); + private static final Pattern EXTRACT_CVE_REGEX = Pattern.compile(".{0,30}(CVE-\\d{4}-\\d+).{0,30}"); private static void fillCves(DefinitionType definition, OsFamily osFamily) { switch (osFamily) { From c4103f0d846b8c14687f14bef2b64a89bc85f3bb Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sat, 11 May 2024 17:02:15 +0100 Subject: [PATCH 40/64] Introduce UI warning for potential inaccuracies in CVE audit results --- .../src/manager/audit/cveaudit/cveaudit.tsx | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/web/html/src/manager/audit/cveaudit/cveaudit.tsx b/web/html/src/manager/audit/cveaudit/cveaudit.tsx index 32220dd0e21e..21c594664bc8 100644 --- a/web/html/src/manager/audit/cveaudit/cveaudit.tsx +++ b/web/html/src/manager/audit/cveaudit/cveaudit.tsx @@ -219,6 +219,21 @@ class CVEAudit extends React.Component { }); }; + getPatchStatusAccuracyWarning = (row) => { + const dataSources: string[] = row.scanDataSources; + if (!dataSources) { + return "Unknown patch status"; + } + + if (dataSources.indexOf("OVAL") === -1) { + return "OVAL data not in sync. Possible false negatives"; + } else if (dataSources.indexOf("CHANNELS") === -1) { + return "Channels not in sync for the given server product. Patches are not available."; + } + + return "If you see this report a bug."; + }; + render() { return ( @@ -346,6 +361,12 @@ class CVEAudit extends React.Component { className={"fa fa-big " + PATCH_STATUS_LABEL[row.patchStatus].className} title={PATCH_STATUS_LABEL[row.patchStatus].description} /> + {row.scanDataSources.length < 2 && ( + + )} )} /> From 8f7e4cd54c3112c28340b52a7ff7a78f56ee2bcc Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sun, 12 May 2024 16:22:57 +0100 Subject: [PATCH 41/64] Implement the check for existence of erratas in server CVE channels - If result is not empty, then server can be CVE audited normally otherwise a warning should be displayed indicating a lack of channels data and thus inaccuracies are expected. --- .../common/db/datasource/xml/oval_queries.xml | 10 ++++++++++ .../manager/audit/CVEAuditManagerOVAL.java | 11 +++++----- .../src/com/suse/oval/OVALCachingFactory.java | 20 +++++++++++++++++-- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/java/code/src/com/redhat/rhn/common/db/datasource/xml/oval_queries.xml b/java/code/src/com/redhat/rhn/common/db/datasource/xml/oval_queries.xml index 87d8ec86376c..a72e6e98e9ba 100755 --- a/java/code/src/com/redhat/rhn/common/db/datasource/xml/oval_queries.xml +++ b/java/code/src/com/redhat/rhn/common/db/datasource/xml/oval_queries.xml @@ -35,4 +35,14 @@ SELECT 1 FROM suseOVALPlatform plat WHERE starts_with(:cpe, plat.cpe); + + + + SELECT 1 + FROM suseCVEServerChannel, + rhnChannelErrata + WHERE suseCVEServerChannel.channel_id = rhnChannelErrata.channel_id + AND server_id = :server_id + + diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java index 231bc471a7b3..015ba3518d54 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java @@ -101,7 +101,7 @@ public static List listSystemsByPatchStatus(User user, String cv doAuditSystem(cveIdentifier, resultsBySystem.get(clientServer.getId()), clientServer); } - if (checkChannelsDataAvailability(clientServer)) { + if (checkChannelsErrataAvailability(clientServer)) { auditWithChannelsResult = CVEAuditManager.doAuditSystem(clientServer.getId(), resultsBySystem.get(clientServer.getId())); } @@ -144,7 +144,7 @@ else if (auditWithChannelsResult != null) { } /** - * Check if server support OVAL CVE auditing + * Check if we have any OVAL vulnerability records for the given client OS in the database. * * @param clientServer the server to check * @return {@code True} @@ -154,14 +154,13 @@ public static boolean checkOVALAvailability(Server clientServer) { } /** - * Check if we have CVE channels data for the OS product installed on the given client server + * Check if we have any erratas assigned to the client's CVE channels. * * @param clientServer the server to check * @return {@code True} * */ - public static boolean checkChannelsDataAvailability(Server clientServer) { - // TODO: Implement! - return true; + public static boolean checkChannelsErrataAvailability(Server clientServer) { + return OVALCachingFactory.checkChannelsErrataAvailability(clientServer.getId()); } private static boolean isCVEIdentifierUnknown(String cveIdentifier) { diff --git a/java/code/src/com/suse/oval/OVALCachingFactory.java b/java/code/src/com/suse/oval/OVALCachingFactory.java index 8d9685f6dd94..2d99374e93c4 100644 --- a/java/code/src/com/suse/oval/OVALCachingFactory.java +++ b/java/code/src/com/suse/oval/OVALCachingFactory.java @@ -135,9 +135,9 @@ public static boolean canAuditCVE(String cve) { } /** - * Checks if OVAL is synced for servers with the given {@code cpe} + * Check if we have any OVAL vulnerability records for the given client OS in the database. * - * @param cpe the cpe of servers to check for + * @param cpe the cpe representing of the OS of servers to check for * @return {@code True} if OVAL is available for servers with {@code cpe} and {@code False} otherwise. */ public static boolean checkOVALAvailability(String cpe) { @@ -150,6 +150,22 @@ public static boolean checkOVALAvailability(String cpe) { return !result.isEmpty(); } + /** + * Check if we have any erratas assigned to the client's CVE channels. + * + * @param serverId the id of the client to check for + * @return {@code True} if the CVE channels of the server contains erratas. and {@code False} otherwise. + * */ + public static boolean checkChannelsErrataAvailability(Long serverId) { + SelectMode m = ModeFactory.getMode("oval_queries", "check_errata_availability"); + Map params = new HashMap<>(); + params.put("server_id", serverId); + + DataResult result = m.execute(params); + + return !result.isEmpty(); + } + @Override protected Logger getLogger() { return LOG; From 21c56b8619c576a14f2bc446dc549dab893236e8 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sun, 12 May 2024 16:32:14 +0100 Subject: [PATCH 42/64] Delete cveaudit.less --- .../branding/css/susemanager/components/cveaudit.less | 10 ---------- web/html/src/branding/css/susemanager/index.less | 1 - 2 files changed, 11 deletions(-) delete mode 100644 web/html/src/branding/css/susemanager/components/cveaudit.less diff --git a/web/html/src/branding/css/susemanager/components/cveaudit.less b/web/html/src/branding/css/susemanager/components/cveaudit.less deleted file mode 100644 index 303405afff7c..000000000000 --- a/web/html/src/branding/css/susemanager/components/cveaudit.less +++ /dev/null @@ -1,10 +0,0 @@ -.scan-data-indicator { - padding: 6px 0; - border-radius: 4px; - /* margin: auto; */ - width: fit-content; - min-width: 120px; - text-align: center; - color: white; - font-weight: bolder; -} \ No newline at end of file diff --git a/web/html/src/branding/css/susemanager/index.less b/web/html/src/branding/css/susemanager/index.less index 5e118fe97544..38b791179bf2 100644 --- a/web/html/src/branding/css/susemanager/index.less +++ b/web/html/src/branding/css/susemanager/index.less @@ -24,7 +24,6 @@ @import "./components/date-time-picker.less"; @import "./components/header.less"; @import "./components/address.less"; -@import url(./components/cveaudit.less); // Responsive overrides @import "../base/responsive-rules.less"; From 998916efe637300df026d952dd789d9349297284 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Tue, 14 May 2024 12:25:48 +0100 Subject: [PATCH 43/64] Remove the "Scan Data" column from the CVE audit page - It doesn't bring much value + UI looks quite overloaded --- web/html/src/manager/audit/cveaudit/cveaudit.tsx | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/web/html/src/manager/audit/cveaudit/cveaudit.tsx b/web/html/src/manager/audit/cveaudit/cveaudit.tsx index 21c594664bc8..db9415d48f16 100644 --- a/web/html/src/manager/audit/cveaudit/cveaudit.tsx +++ b/web/html/src/manager/audit/cveaudit/cveaudit.tsx @@ -372,7 +372,7 @@ class CVEAudit extends React.Component { /> { @@ -389,7 +389,7 @@ class CVEAudit extends React.Component { /> { @@ -499,15 +499,6 @@ class CVEAudit extends React.Component { } }} /> - { - return
{row.scanDataSources.join(", ")}
; - }} - />
Date: Thu, 16 May 2024 12:25:24 +0100 Subject: [PATCH 44/64] Translate strings --- web/html/src/manager/audit/cveaudit/cveaudit.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web/html/src/manager/audit/cveaudit/cveaudit.tsx b/web/html/src/manager/audit/cveaudit/cveaudit.tsx index db9415d48f16..49a9049327a8 100644 --- a/web/html/src/manager/audit/cveaudit/cveaudit.tsx +++ b/web/html/src/manager/audit/cveaudit/cveaudit.tsx @@ -222,16 +222,16 @@ class CVEAudit extends React.Component { getPatchStatusAccuracyWarning = (row) => { const dataSources: string[] = row.scanDataSources; if (!dataSources) { - return "Unknown patch status"; + return t("Unknown patch status"); } if (dataSources.indexOf("OVAL") === -1) { - return "OVAL data not in sync. Possible false negatives"; + return t("OVAL data not in sync. Possible false negatives"); } else if (dataSources.indexOf("CHANNELS") === -1) { - return "Channels not in sync for the given server product. Patches are not available."; + return t("Channels not in sync for the given server product. Patches are not available."); } - return "If you see this report a bug."; + return t("If you see this report a bug."); }; render() { From f666d1be90d8507660aecea61de786957b483dfc Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Thu, 16 May 2024 12:26:32 +0100 Subject: [PATCH 45/64] Log error on invalid CVE scan data sources --- web/html/src/manager/audit/cveaudit/cveaudit.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/html/src/manager/audit/cveaudit/cveaudit.tsx b/web/html/src/manager/audit/cveaudit/cveaudit.tsx index 49a9049327a8..8d1052173950 100644 --- a/web/html/src/manager/audit/cveaudit/cveaudit.tsx +++ b/web/html/src/manager/audit/cveaudit/cveaudit.tsx @@ -231,6 +231,8 @@ class CVEAudit extends React.Component { return t("Channels not in sync for the given server product. Patches are not available."); } + Loggerhead.error(`Invalid scan data sourced: ${dataSources}`); + return t("If you see this report a bug."); }; From 3a5dc43060e6545a81357d5dca5173237b9f8418 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Thu, 16 May 2024 12:41:58 +0100 Subject: [PATCH 46/64] Insert missing data related to the sync OVAL taskomatic task --- schema/spacewalk/common/data/rhnTaskoBunch.sql | 3 +++ schema/spacewalk/common/data/rhnTaskoSchedule.sql | 6 ++++++ schema/spacewalk/common/data/rhnTaskoTemplate.sql | 7 +++++++ 3 files changed, 16 insertions(+) diff --git a/schema/spacewalk/common/data/rhnTaskoBunch.sql b/schema/spacewalk/common/data/rhnTaskoBunch.sql index 8e4e2fa21039..02bd415befe6 100644 --- a/schema/spacewalk/common/data/rhnTaskoBunch.sql +++ b/schema/spacewalk/common/data/rhnTaskoBunch.sql @@ -138,4 +138,7 @@ VALUES (sequence_nextval('rhn_tasko_bunch_id_seq'), 'system-profile-refresh-bunc INSERT INTO rhnTaskoBunch (id, name, description, org_bunch) VALUES (sequence_nextval('rhn_tasko_bunch_id_seq'), 'payg-dimension-computation-bunch', 'Compute the dimensions data required for PAYG billing', null); +INSERT INTO rhnTaskoBunch (id, name, description, org_bunch) +VALUES (sequence_nextval('rhn_tasko_bunch_id_seq'), 'oval-data-sync-bunch', 'Generate OVAL data required to increase the accuracy of CVE audit queries.', null); + commit; diff --git a/schema/spacewalk/common/data/rhnTaskoSchedule.sql b/schema/spacewalk/common/data/rhnTaskoSchedule.sql index 1e9f8529e352..7485a3d44bfe 100644 --- a/schema/spacewalk/common/data/rhnTaskoSchedule.sql +++ b/schema/spacewalk/common/data/rhnTaskoSchedule.sql @@ -188,4 +188,10 @@ VALUES (sequence_nextval('rhn_tasko_schedule_id_seq'), 'system-profile-refresh-d (SELECT id FROM rhnTaskoBunch WHERE name='system-profile-refresh-bunch'), current_timestamp, '0 0 5 ? * SAT#2'); +INSERT INTO rhnTaskoSchedule (id, job_label, bunch_id, active_from, cron_expr) +VALUES (sequence_nextval('rhn_tasko_schedule_id_seq'), + 'oval-data-sync-default', + (SELECT id FROM rhnTaskoBunch WHERE name = 'oval-data-sync-bunch'), + current_timestamp, '0 0 23 ? * *'); + commit; diff --git a/schema/spacewalk/common/data/rhnTaskoTemplate.sql b/schema/spacewalk/common/data/rhnTaskoTemplate.sql index c8429bc89389..9e47c049352b 100644 --- a/schema/spacewalk/common/data/rhnTaskoTemplate.sql +++ b/schema/spacewalk/common/data/rhnTaskoTemplate.sql @@ -322,4 +322,11 @@ INSERT INTO rhnTaskoTemplate (id, bunch_id, task_id, ordering, start_if) 0, null); +INSERT INTO rhnTaskoTemplate (id, bunch_id, task_id, ordering, start_if) + VALUES (sequence_nextval('rhn_tasko_template_id_seq'), + (SELECT id FROM rhnTaskoBunch WHERE name = 'oval-data-sync-bunch'), + (SELECT id FROM rhnTaskoTask WHERE name = 'oval-data-sync'), + 0, + null); + commit; From d9e36a47544dba0fc2bf89223f4b5610f953c6b1 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sun, 19 May 2024 00:21:20 +0100 Subject: [PATCH 47/64] Rephrase CVE auditing related UI messages Co-authored-by: Abid Mehmood --- .../src/manager/audit/cveaudit/cveaudit.tsx | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/web/html/src/manager/audit/cveaudit/cveaudit.tsx b/web/html/src/manager/audit/cveaudit/cveaudit.tsx index 8d1052173950..ca944926c401 100644 --- a/web/html/src/manager/audit/cveaudit/cveaudit.tsx +++ b/web/html/src/manager/audit/cveaudit/cveaudit.tsx @@ -222,18 +222,25 @@ class CVEAudit extends React.Component { getPatchStatusAccuracyWarning = (row) => { const dataSources: string[] = row.scanDataSources; if (!dataSources) { - return t("Unknown patch status"); + console.error("CVE audit data sources were not supplied by server."); + return t("Error, see console"); } - if (dataSources.indexOf("OVAL") === -1) { - return t("OVAL data not in sync. Possible false negatives"); + if (dataSources.length === 0) { + return t("Unknown patch status"); + } else if (dataSources.indexOf("OVAL") === -1) { + return t( + "OVAL data out of sync. Potential missed vulnerabilities" + ); } else if (dataSources.indexOf("CHANNELS") === -1) { - return t("Channels not in sync for the given server product. Patches are not available."); + return t( + "Server product channels out of sync; no patch information available" + ); } - Loggerhead.error(`Invalid scan data sourced: ${dataSources}`); + Loggerhead.error(`Invalid scan data sources: ${dataSources}`); - return t("If you see this report a bug."); + return t("Error, see console"); }; render() { From 161516809b5a684a6042ebae082973824b477782 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sun, 19 May 2024 00:25:31 +0100 Subject: [PATCH 48/64] Fix bug where the system name in the CVE auditing table results not displayed --- .../src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java index 015ba3518d54..c828fcbdc4c8 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java @@ -127,6 +127,8 @@ else if (auditWithChannelsResult != null) { auditResult = new CVEAuditSystemBuilder(clientServer.getId()); // TODO: Maybe we should add an "unknown" patch status type? auditResult.setPatchStatus(PatchStatus.NOT_AFFECTED); + auditResult.setSystemID(clientServer.getId()); + auditResult.setSystemName(clientServer.getName()); } if (patchStatuses.contains(auditResult.getPatchStatus())) { From 44ebb6ed09e3ae790a139f7419d60d902e26ef97 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sun, 19 May 2024 01:06:57 +0100 Subject: [PATCH 49/64] Introduce an "unknown" patch status to be returned when OVAL and Channels metadata not synced --- .../rhn/manager/audit/CVEAuditManagerOVAL.java | 3 +-- .../com/redhat/rhn/manager/audit/PatchStatus.java | 3 ++- .../audit/test/CVEAuditManagerOVALTest.java | 1 + web/html/src/manager/audit/cveaudit/cveaudit.tsx | 14 ++++++++++++-- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java index c828fcbdc4c8..73485a3337c1 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java @@ -125,8 +125,7 @@ else if (auditWithChannelsResult != null) { } else { auditResult = new CVEAuditSystemBuilder(clientServer.getId()); - // TODO: Maybe we should add an "unknown" patch status type? - auditResult.setPatchStatus(PatchStatus.NOT_AFFECTED); + auditResult.setPatchStatus(PatchStatus.UNKNOWN); auditResult.setSystemID(clientServer.getId()); auditResult.setSystemName(clientServer.getName()); } diff --git a/java/code/src/com/redhat/rhn/manager/audit/PatchStatus.java b/java/code/src/com/redhat/rhn/manager/audit/PatchStatus.java index c3d07ae33d4b..2ad2dd78e3f0 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/PatchStatus.java +++ b/java/code/src/com/redhat/rhn/manager/audit/PatchStatus.java @@ -28,7 +28,8 @@ public enum PatchStatus { AFFECTED_FULL_PATCH_APPLICABLE("Affected, full patch available in assigned channel", 4), NOT_AFFECTED("Not affected", 5), PATCHED("Patched", 6), - AFFECTED_PATCH_INAPPLICABLE_SUCCESSOR_PRODUCT("Affected, patch available in a Product Migration target", 7); + AFFECTED_PATCH_INAPPLICABLE_SUCCESSOR_PRODUCT("Affected, patch available in a Product Migration target", 7), + UNKNOWN("Unknown, CVE metadata not available", 8); /** * The lower the more severe diff --git a/java/code/src/com/redhat/rhn/manager/audit/test/CVEAuditManagerOVALTest.java b/java/code/src/com/redhat/rhn/manager/audit/test/CVEAuditManagerOVALTest.java index a2e31c0b49e8..1a686d6fbf04 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/test/CVEAuditManagerOVALTest.java +++ b/java/code/src/com/redhat/rhn/manager/audit/test/CVEAuditManagerOVALTest.java @@ -61,6 +61,7 @@ import java.util.Set; import java.util.stream.Collectors; +// TODO: Test for when patch status is unknown public class CVEAuditManagerOVALTest extends RhnBaseTestCase { public static final String CPE_OPENSUSE_LEAP_15_4 = "cpe:/o:opensuse:leap:15.4"; private OvalParser ovalParser = new OvalParser(); diff --git a/web/html/src/manager/audit/cveaudit/cveaudit.tsx b/web/html/src/manager/audit/cveaudit/cveaudit.tsx index ca944926c401..ce5554c67ea2 100644 --- a/web/html/src/manager/audit/cveaudit/cveaudit.tsx +++ b/web/html/src/manager/audit/cveaudit/cveaudit.tsx @@ -24,6 +24,7 @@ const PATCHED = "PATCHED"; const AFFECTED_PATCH_UNAVAILABLE = "AFFECTED_PATCH_UNAVAILABLE"; const AFFECTED_PATCH_UNAVAILABLE_IN_UYUNI = "AFFECTED_PATCH_UNAVAILABLE_IN_UYUNI"; const AFFECTED_PARTIAL_PATCH_APPLICABLE = "AFFECTED_PARTIAL_PATCH_APPLICABLE"; +const UNKNOWN = "UNKNOWN"; const ALL = [ AFFECTED_PATCH_UNAVAILABLE, @@ -34,6 +35,7 @@ const ALL = [ AFFECTED_FULL_PATCH_APPLICABLE, NOT_AFFECTED, PATCHED, + UNKNOWN, ]; const PATCH_STATUS_LABEL = { AFFECTED_PATCH_INAPPLICABLE: { @@ -88,6 +90,13 @@ const PATCH_STATUS_LABEL = { " but applying the patch will only update some of the vulnerable packages." ), }, + UNKNOWN: { + className: "fa-minus-circle text-secondary", + label: t("Unknown, CVE metadata not available"), + description: t( + "It is not possible to scan the client server for CVE vulnerabilities without channels or OVAL metadata." + ), + }, }; const TARGET_IMAGE = "IMAGE"; const TARGET_SERVER = "SERVER"; @@ -370,7 +379,7 @@ class CVEAudit extends React.Component { className={"fa fa-big " + PATCH_STATUS_LABEL[row.patchStatus].className} title={PATCH_STATUS_LABEL[row.patchStatus].description} /> - {row.scanDataSources.length < 2 && ( + {row.patchStatus !== UNKNOWN && row.scanDataSources.length < 2 && ( { row.patchStatus === PATCHED || row.patchStatus === AFFECTED_PATCH_UNAVAILABLE || row.patchStatus === AFFECTED_PATCH_UNAVAILABLE_IN_UYUNI || - row.patchStatus === AFFECTED_PATCH_UNAVAILABLE + row.patchStatus === AFFECTED_PATCH_UNAVAILABLE || + row.patchStatus === UNKNOWN ) { return t("No action required"); } else if (row.patchStatus === AFFECTED_FULL_PATCH_APPLICABLE) { From 1cc5f0883a90a8510fe79553193038653d802500 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sun, 19 May 2024 23:19:50 +0100 Subject: [PATCH 50/64] Introduce a shell script that synchronizes the oval.config.json file used for testing --- .../config/test/update_oval_config_json.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100755 java/code/src/com/suse/oval/config/test/update_oval_config_json.sh diff --git a/java/code/src/com/suse/oval/config/test/update_oval_config_json.sh b/java/code/src/com/suse/oval/config/test/update_oval_config_json.sh new file mode 100755 index 000000000000..ac538de523fa --- /dev/null +++ b/java/code/src/com/suse/oval/config/test/update_oval_config_json.sh @@ -0,0 +1,18 @@ +# +# Copyright (c) 2024 SUSE LLC +# +# This software is licensed to you under the GNU General Public License, +# version 2 (GPLv2). There is NO WARRANTY for this software, express or +# implied, including the implied warranties of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 +# along with this software; if not, see +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. +# +# Red Hat trademarks are not licensed under GPLv2. No permission is +# granted to use or replicate Red Hat trademarks that are incorporated +# in this software or its documentation. +# + +pushd $(dirname $0) +cp ../../../../../../../../susemanager-sync-data/oval.config.json . +popd \ No newline at end of file From f96ddc02428236f4e6422e72891a357fda6d85e0 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sun, 19 May 2024 23:25:42 +0100 Subject: [PATCH 51/64] Add missing OVAL data sources --- java/code/src/com/suse/oval/OsFamily.java | 4 ++-- .../src/com/suse/oval/config/test/oval.config.json | 12 ++++++++++++ susemanager-sync-data/oval.config.json | 12 ++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/java/code/src/com/suse/oval/OsFamily.java b/java/code/src/com/suse/oval/OsFamily.java index e15ba2f63ce9..27dc33e3326e 100644 --- a/java/code/src/com/suse/oval/OsFamily.java +++ b/java/code/src/com/suse/oval/OsFamily.java @@ -29,13 +29,13 @@ public enum OsFamily { LEAP("openSUSE Leap", "Leap", "opensuse", oneOf("15.2", "15.3", "15.4", "15.5")), LEAP_MICRO("openSUSELeap Micro", "openSUE Leap Micro", "opensuse", - oneOf("5.2", "5.3")), + oneOf("5.2", "5.3", "5.4", "5.5")), SUSE_LINUX_ENTERPRISE_SERVER("SUSE Linux Enterprise Server", "SLES", "suse", oneOf("11", "12", "15")), SUSE_LINUX_ENTERPRISE_DESKTOP("SUSE Linux Enterprise Desktop", "SLED", "suse", oneOf("10", "11", "12", "15")), SUSE_LINUX_ENTERPRISE_MICRO("SUSE Linux Enterprise Micro", "SLE Micro", "suse", - oneOf("5.0", "5.1", "5.2", "5.3")), + oneOf("5.0", "5.1", "5.2", "5.3", "5.4", "5.5")), REDHAT_ENTERPRISE_LINUX("Red Hat Enterprise Linux", "Red Hat Enterprise Linux", "redhat", withPrefix("7.", "8.", "9.")), DEBIAN("Debian", "Debian", "debian", oneOf("10", "11", "12")); diff --git a/java/code/src/com/suse/oval/config/test/oval.config.json b/java/code/src/com/suse/oval/config/test/oval.config.json index 26c29bd166b4..8380b06c4c87 100644 --- a/java/code/src/com/suse/oval/config/test/oval.config.json +++ b/java/code/src/com/suse/oval/config/test/oval.config.json @@ -29,6 +29,14 @@ "5.3": { "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.micro.5.3-affected.xml.gz", "patch": "" + }, + "5.4": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.micro.5.4-affected.xml.gz", + "patch": "" + }, + "5.5": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.micro.5.5-affected.xml.gz", + "patch": "" } } }, @@ -89,6 +97,10 @@ "5.4": { "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.micro.5.4-affected.xml.gz", "patch": "" + }, + "5.5": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.micro.5.5-affected.xml.gz", + "patch": "" } } }, diff --git a/susemanager-sync-data/oval.config.json b/susemanager-sync-data/oval.config.json index 26c29bd166b4..8380b06c4c87 100644 --- a/susemanager-sync-data/oval.config.json +++ b/susemanager-sync-data/oval.config.json @@ -29,6 +29,14 @@ "5.3": { "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.micro.5.3-affected.xml.gz", "patch": "" + }, + "5.4": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.micro.5.4-affected.xml.gz", + "patch": "" + }, + "5.5": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.micro.5.5-affected.xml.gz", + "patch": "" } } }, @@ -89,6 +97,10 @@ "5.4": { "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.micro.5.4-affected.xml.gz", "patch": "" + }, + "5.5": { + "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.micro.5.5-affected.xml.gz", + "patch": "" } } }, From 01567d4a95b60069261f39aa353374294156e558 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Tue, 21 May 2024 12:39:49 +0100 Subject: [PATCH 52/64] Move OVAL config file to a more appropriate directory - The 'scc' directory is not the best place to put this json file since it is not coming from SCC. --- java/code/src/com/suse/oval/config/OVALConfigLoader.java | 2 +- susemanager-sync-data/susemanager-sync-data.spec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/java/code/src/com/suse/oval/config/OVALConfigLoader.java b/java/code/src/com/suse/oval/config/OVALConfigLoader.java index c9bb9e9b84c8..c4e195bfe261 100644 --- a/java/code/src/com/suse/oval/config/OVALConfigLoader.java +++ b/java/code/src/com/suse/oval/config/OVALConfigLoader.java @@ -23,7 +23,7 @@ import java.util.Objects; public class OVALConfigLoader { - private static final String DEFAULT_CONFIG_PATH = "/usr/share/susemanager/scc/oval.config.json"; + private static final String DEFAULT_CONFIG_PATH = "/usr/share/susemanager/oval/oval.config.json"; private final String configPath; /** diff --git a/susemanager-sync-data/susemanager-sync-data.spec b/susemanager-sync-data/susemanager-sync-data.spec index bfdb9d3d497d..1e59494a2249 100644 --- a/susemanager-sync-data/susemanager-sync-data.spec +++ b/susemanager-sync-data/susemanager-sync-data.spec @@ -40,7 +40,7 @@ mkdir -p %{buildroot}%{_datadir}/susemanager/scc install -m 0644 channel_families.json %{buildroot}%{_datadir}/susemanager/scc/channel_families.json install -m 0644 additional_products.json %{buildroot}%{_datadir}/susemanager/scc/additional_products.json install -m 0644 additional_repositories.json %{buildroot}%{_datadir}/susemanager/scc/additional_repositories.json -install -m 0644 oval.config.json %{buildroot}%{_datadir}/susemanager/scc/oval.config.json +install -m 0644 oval.config.json %{buildroot}%{_datadir}/susemanager/oval/oval.config.json %files %defattr(-,root,root,-) From 27d86c724db5867152f109650cf491ff1cde8b06 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Tue, 21 May 2024 12:50:32 +0100 Subject: [PATCH 53/64] Configure OVAL for SLE/Leap Micro 6.0 and Leap 15.6 --- java/code/src/com/suse/oval/OsFamily.java | 6 +++--- .../src/com/suse/oval/config/test/oval.config.json | 12 ++++++++++++ susemanager-sync-data/oval.config.json | 12 ++++++++++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/java/code/src/com/suse/oval/OsFamily.java b/java/code/src/com/suse/oval/OsFamily.java index 27dc33e3326e..91438d4ae3f2 100644 --- a/java/code/src/com/suse/oval/OsFamily.java +++ b/java/code/src/com/suse/oval/OsFamily.java @@ -27,15 +27,15 @@ * */ public enum OsFamily { LEAP("openSUSE Leap", "Leap", "opensuse", - oneOf("15.2", "15.3", "15.4", "15.5")), + oneOf("15.2", "15.3", "15.4", "15.5", "15.6")), LEAP_MICRO("openSUSELeap Micro", "openSUE Leap Micro", "opensuse", - oneOf("5.2", "5.3", "5.4", "5.5")), + oneOf("5.2", "5.3", "5.4", "5.5", "6.0")), SUSE_LINUX_ENTERPRISE_SERVER("SUSE Linux Enterprise Server", "SLES", "suse", oneOf("11", "12", "15")), SUSE_LINUX_ENTERPRISE_DESKTOP("SUSE Linux Enterprise Desktop", "SLED", "suse", oneOf("10", "11", "12", "15")), SUSE_LINUX_ENTERPRISE_MICRO("SUSE Linux Enterprise Micro", "SLE Micro", "suse", - oneOf("5.0", "5.1", "5.2", "5.3", "5.4", "5.5")), + oneOf("5.0", "5.1", "5.2", "5.3", "5.4", "5.5", "6.0")), REDHAT_ENTERPRISE_LINUX("Red Hat Enterprise Linux", "Red Hat Enterprise Linux", "redhat", withPrefix("7.", "8.", "9.")), DEBIAN("Debian", "Debian", "debian", oneOf("10", "11", "12")); diff --git a/java/code/src/com/suse/oval/config/test/oval.config.json b/java/code/src/com/suse/oval/config/test/oval.config.json index 8380b06c4c87..1dd42f1a7756 100644 --- a/java/code/src/com/suse/oval/config/test/oval.config.json +++ b/java/code/src/com/suse/oval/config/test/oval.config.json @@ -17,6 +17,10 @@ "15.5": { "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.15.5-affected.xml.gz", "patch": "" + }, + "15.6": { + "vulnerability": "", + "patch": "" } } }, @@ -37,6 +41,10 @@ "5.5": { "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.micro.5.5-affected.xml.gz", "patch": "" + }, + "6.0": { + "vulnerability": "", + "patch": "" } } }, @@ -101,6 +109,10 @@ "5.5": { "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.micro.5.5-affected.xml.gz", "patch": "" + }, + "6.0": { + "vulnerability": "", + "patch": "" } } }, diff --git a/susemanager-sync-data/oval.config.json b/susemanager-sync-data/oval.config.json index 8380b06c4c87..1dd42f1a7756 100644 --- a/susemanager-sync-data/oval.config.json +++ b/susemanager-sync-data/oval.config.json @@ -17,6 +17,10 @@ "15.5": { "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.15.5-affected.xml.gz", "patch": "" + }, + "15.6": { + "vulnerability": "", + "patch": "" } } }, @@ -37,6 +41,10 @@ "5.5": { "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/opensuse.leap.micro.5.5-affected.xml.gz", "patch": "" + }, + "6.0": { + "vulnerability": "", + "patch": "" } } }, @@ -101,6 +109,10 @@ "5.5": { "vulnerability": "https://ftp.suse.com/pub/projects/security/oval/suse.linux.enterprise.micro.5.5-affected.xml.gz", "patch": "" + }, + "6.0": { + "vulnerability": "", + "patch": "" } } }, From 18c8852e5f33311e4aa50ce60b965264a151c2d4 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Tue, 21 May 2024 12:53:35 +0100 Subject: [PATCH 54/64] Fix linter --- web/html/src/manager/audit/cveaudit/cveaudit.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/html/src/manager/audit/cveaudit/cveaudit.tsx b/web/html/src/manager/audit/cveaudit/cveaudit.tsx index ce5554c67ea2..e37742d2abdc 100644 --- a/web/html/src/manager/audit/cveaudit/cveaudit.tsx +++ b/web/html/src/manager/audit/cveaudit/cveaudit.tsx @@ -231,7 +231,7 @@ class CVEAudit extends React.Component { getPatchStatusAccuracyWarning = (row) => { const dataSources: string[] = row.scanDataSources; if (!dataSources) { - console.error("CVE audit data sources were not supplied by server."); + Loggerhead.error("CVE audit data sources were not supplied by server."); return t("Error, see console"); } From c8387666d5ee7041c8f926361dfe06223ec128a5 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Tue, 28 May 2024 12:08:49 +0100 Subject: [PATCH 55/64] Frontend lint --- web/html/src/manager/audit/cveaudit/cveaudit.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/web/html/src/manager/audit/cveaudit/cveaudit.tsx b/web/html/src/manager/audit/cveaudit/cveaudit.tsx index e37742d2abdc..8ed33054a220 100644 --- a/web/html/src/manager/audit/cveaudit/cveaudit.tsx +++ b/web/html/src/manager/audit/cveaudit/cveaudit.tsx @@ -238,13 +238,9 @@ class CVEAudit extends React.Component { if (dataSources.length === 0) { return t("Unknown patch status"); } else if (dataSources.indexOf("OVAL") === -1) { - return t( - "OVAL data out of sync. Potential missed vulnerabilities" - ); + return t("OVAL data out of sync. Potential missed vulnerabilities"); } else if (dataSources.indexOf("CHANNELS") === -1) { - return t( - "Server product channels out of sync; no patch information available" - ); + return t("Server product channels out of sync; no patch information available"); } Loggerhead.error(`Invalid scan data sources: ${dataSources}`); From 0f128b7f6f4ee1ad98896bad863e5a957282755e Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Tue, 28 May 2024 12:54:25 +0100 Subject: [PATCH 56/64] Clear previous OVAL metadata for platform before inserting the newer data. --- .../common/db/datasource/xml/oval_queries.xml | 7 +++ .../src/com/suse/oval/OVALCachingFactory.java | 61 ++++++++++++------- 2 files changed, 45 insertions(+), 23 deletions(-) diff --git a/java/code/src/com/redhat/rhn/common/db/datasource/xml/oval_queries.xml b/java/code/src/com/redhat/rhn/common/db/datasource/xml/oval_queries.xml index a72e6e98e9ba..29eccb64c4f0 100755 --- a/java/code/src/com/redhat/rhn/common/db/datasource/xml/oval_queries.xml +++ b/java/code/src/com/redhat/rhn/common/db/datasource/xml/oval_queries.xml @@ -45,4 +45,11 @@ AND server_id = :server_id + + + + DELETE FROM suseOVALPlatformVulnerablePackage pvp WHERE pvp.platform_id = (SELECT id FROM suseOVALPlatform plat WHERE plat.cpe = :cpe); + DELETE FROM suseOVALPlatform plat where plat.cpe = :cpe; + + diff --git a/java/code/src/com/suse/oval/OVALCachingFactory.java b/java/code/src/com/suse/oval/OVALCachingFactory.java index 2d99374e93c4..9e395733a600 100644 --- a/java/code/src/com/suse/oval/OVALCachingFactory.java +++ b/java/code/src/com/suse/oval/OVALCachingFactory.java @@ -15,11 +15,14 @@ package com.suse.oval; +import static java.util.stream.Collectors.groupingBy; + import com.redhat.rhn.common.db.datasource.CallableMode; import com.redhat.rhn.common.db.datasource.DataResult; import com.redhat.rhn.common.db.datasource.ModeFactory; import com.redhat.rhn.common.db.datasource.Row; import com.redhat.rhn.common.db.datasource.SelectMode; +import com.redhat.rhn.common.db.datasource.WriteMode; import com.redhat.rhn.common.hibernate.HibernateFactory; import com.suse.oval.manager.OVALLookupHelper; @@ -47,6 +50,11 @@ private OVALCachingFactory() { // Left empty on purpose } + private static void clearOVALMetadataByPlatform(String platformCpe) { + WriteMode mode = ModeFactory.getWriteMode("oval_queries", "clear_oval_metadata_by_platform"); + mode.executeUpdate(Map.of("cpe", platformCpe)); + } + /** * Extracts and save the list of vulnerable packages from {@code rootType} * @@ -57,33 +65,40 @@ public static void savePlatformsVulnerablePackages(OvalRootType rootType) { OVALLookupHelper ovalLookupHelper = new OVALLookupHelper(rootType); - DataResult> batch = new DataResult<>(new ArrayList<>(1000)); - + List productVulnerablePackages = new ArrayList<>(); for (DefinitionType definition : rootType.getDefinitions()) { VulnerablePackagesExtractor vulnerablePackagesExtractor = VulnerablePackagesExtractors.create(definition, rootType.getOsFamily(), ovalLookupHelper); - List extractionResult = vulnerablePackagesExtractor.extract(); - for (ProductVulnerablePackages productVulnerablePackages : extractionResult) { - for (String cve : productVulnerablePackages.getCves()) { - for (VulnerablePackage vulnerablePackage : productVulnerablePackages.getVulnerablePackages()) { - Map params = new HashMap<>(); - params.put("product_name", productVulnerablePackages.getProductCpe()); - params.put("cve_name", cve); - params.put("package_name", vulnerablePackage.getName()); - params.put("fix_version", vulnerablePackage.getFixVersion().orElse(null)); - - batch.add(params); - - if (batch.size() % 1000 == 0) { - mode.getQuery().executeBatchUpdates(batch); - batch.clear(); - commitTransaction(); - - Session session = getSession(); - if (!inTransaction()) { - session.beginTransaction(); - } + productVulnerablePackages.addAll(vulnerablePackagesExtractor.extract()); + } + + // Clear previous OVAL metadata + productVulnerablePackages.stream() + .collect(groupingBy(ProductVulnerablePackages::getProductCpe)) + .keySet().forEach(OVALCachingFactory::clearOVALMetadataByPlatform); + + // Write OVAL metadata in batches + DataResult> batch = new DataResult<>(new ArrayList<>(1000)); + for (ProductVulnerablePackages pvp : productVulnerablePackages) { + for (String cve : pvp.getCves()) { + for (VulnerablePackage vulnerablePackage : pvp.getVulnerablePackages()) { + Map params = new HashMap<>(); + params.put("product_name", pvp.getProductCpe()); + params.put("cve_name", cve); + params.put("package_name", vulnerablePackage.getName()); + params.put("fix_version", vulnerablePackage.getFixVersion().orElse(null)); + + batch.add(params); + + if (batch.size() % 1000 == 0) { + mode.getQuery().executeBatchUpdates(batch); + batch.clear(); + commitTransaction(); + + Session session = getSession(); + if (!inTransaction()) { + session.beginTransaction(); } } } From b0d1d34b157f3174558fc9aa0a740e3b10cbf262 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Thu, 6 Jun 2024 12:18:37 +0100 Subject: [PATCH 57/64] Add an configuration option to enable/disable OVAL metadata usage in CVE auditing --- .../com/redhat/rhn/common/conf/ConfigDefaults.java | 11 +++++++++++ .../redhat/rhn/manager/audit/CVEAuditManagerOVAL.java | 3 ++- java/conf/rhn_java.conf | 3 +++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/java/code/src/com/redhat/rhn/common/conf/ConfigDefaults.java b/java/code/src/com/redhat/rhn/common/conf/ConfigDefaults.java index f41794c02b59..1ed0442aa8e6 100644 --- a/java/code/src/com/redhat/rhn/common/conf/ConfigDefaults.java +++ b/java/code/src/com/redhat/rhn/common/conf/ConfigDefaults.java @@ -235,6 +235,8 @@ public class ConfigDefaults { public static final String MESSAGE_QUEUE_THREAD_POOL_SIZE = "java.message_queue_thread_pool_size"; + public static final String CVE_AUDIT_ENABLE_OVAL_METADATA = "java.cve_audit.enable_oval_metadata"; + /** * Token lifetime in seconds */ @@ -1188,4 +1190,13 @@ public int getRebootDelay() { return rebootDelay; } + + /** + * Check if the usage of OVAL metadata is permitted in scanning systems for CVE vulnerabilities. + * + * @return {@code true} if OVAL usage is permitted and {@code false} otherwise. + * */ + public boolean isOvalEnabledForCveAudit() { + return Config.get().getBoolean(CVE_AUDIT_ENABLE_OVAL_METADATA, false); + } } diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java index 73485a3337c1..4103b7db65b2 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java @@ -18,6 +18,7 @@ import static com.redhat.rhn.manager.audit.CVEAuditManager.SUCCESSOR_PRODUCT_RANK_BOUNDARY; +import com.redhat.rhn.common.conf.ConfigDefaults; import com.redhat.rhn.domain.rhnpackage.PackageEvr; import com.redhat.rhn.domain.server.Server; import com.redhat.rhn.domain.server.ServerFactory; @@ -96,7 +97,7 @@ public static List listSystemsByPatchStatus(User user, String cv CVEAuditSystemBuilder auditWithChannelsResult = null; CVEAuditSystemBuilder auditWithOVALResult = null; - if (checkOVALAvailability(clientServer)) { + if (ConfigDefaults.get().isOvalEnabledForCveAudit() && checkOVALAvailability(clientServer)) { auditWithOVALResult = doAuditSystem(cveIdentifier, resultsBySystem.get(clientServer.getId()), clientServer); } diff --git a/java/conf/rhn_java.conf b/java/conf/rhn_java.conf index eb5b72d28011..01e3a50676fa 100644 --- a/java/conf/rhn_java.conf +++ b/java/conf/rhn_java.conf @@ -267,3 +267,6 @@ java.reboot_delay = 3 # Disable remote commands from UI java.disable_remote_commands_from_ui = false + +# Enable the usage of OVAL metadata in CVE auditing +java.cve_audit.enable_oval_metadata = true \ No newline at end of file From 54372ea0cfd56883bf7ca5b78943c899fa6d01dd Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sat, 29 Jun 2024 18:08:26 +0100 Subject: [PATCH 58/64] Correct the location of the OVAL config file in RPM spec --- susemanager-sync-data/susemanager-sync-data.spec | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/susemanager-sync-data/susemanager-sync-data.spec b/susemanager-sync-data/susemanager-sync-data.spec index 1e59494a2249..d56f3f92a0e0 100644 --- a/susemanager-sync-data/susemanager-sync-data.spec +++ b/susemanager-sync-data/susemanager-sync-data.spec @@ -46,9 +46,10 @@ install -m 0644 oval.config.json %{buildroot}%{_datadir}/susemanager/oval/ova %defattr(-,root,root,-) %dir %{_datadir}/susemanager %dir %{_datadir}/susemanager/scc +%dir %{_datadir}/susemanager/oval %{_datadir}/susemanager/scc/channel_families.json %{_datadir}/susemanager/scc/additional_products.json %{_datadir}/susemanager/scc/additional_repositories.json -%{_datadir}/susemanager/scc/oval.config.json +%{_datadir}/susemanager/oval/oval.config.json %changelog From 9a648639f5fb150ab24a544f5eff62a2badb3b74 Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sat, 29 Jun 2024 20:16:28 +0100 Subject: [PATCH 59/64] Fix sles and sled OVAL product matching --- .../code/src/com/redhat/rhn/manager/audit/OsReleasePair.java | 5 ++++- .../SUSEVulnerablePackageExtractor.java | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/java/code/src/com/redhat/rhn/manager/audit/OsReleasePair.java b/java/code/src/com/redhat/rhn/manager/audit/OsReleasePair.java index 1e74a931f193..e6ee1aef73e2 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/OsReleasePair.java +++ b/java/code/src/com/redhat/rhn/manager/audit/OsReleasePair.java @@ -53,7 +53,10 @@ public String getOsRelease() { public Optional toOVALProduct() { return OsFamily.fromOsName(os).flatMap(serverOsFamily -> { String serverOsRelease = getOsRelease(); - if (serverOsFamily == OsFamily.REDHAT_ENTERPRISE_LINUX) { + if (serverOsFamily == OsFamily.REDHAT_ENTERPRISE_LINUX || + serverOsFamily == OsFamily.SUSE_LINUX_ENTERPRISE_SERVER || + serverOsFamily == OsFamily.SUSE_LINUX_ENTERPRISE_DESKTOP) { + // Removing the minor version part: 15.6 --> 15 serverOsRelease = serverOsRelease.replace("\\..*", ""); } diff --git a/java/code/src/com/suse/oval/vulnerablepkgextractor/SUSEVulnerablePackageExtractor.java b/java/code/src/com/suse/oval/vulnerablepkgextractor/SUSEVulnerablePackageExtractor.java index 664d31592879..0f19b8ff7a0d 100644 --- a/java/code/src/com/suse/oval/vulnerablepkgextractor/SUSEVulnerablePackageExtractor.java +++ b/java/code/src/com/suse/oval/vulnerablepkgextractor/SUSEVulnerablePackageExtractor.java @@ -209,6 +209,9 @@ private Cpe deriveOpenSUSELeapCpe() { } private Cpe deriveFromProductOVALTest(TestType productTest) { + // Example of the content of an OVAL product test: + // Date: Sat, 29 Jun 2024 21:08:53 +0100 Subject: [PATCH 60/64] Fix OVAL's release package regex --- .../SUSEVulnerablePackageExtractor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/code/src/com/suse/oval/vulnerablepkgextractor/SUSEVulnerablePackageExtractor.java b/java/code/src/com/suse/oval/vulnerablepkgextractor/SUSEVulnerablePackageExtractor.java index 0f19b8ff7a0d..757043c39c70 100644 --- a/java/code/src/com/suse/oval/vulnerablepkgextractor/SUSEVulnerablePackageExtractor.java +++ b/java/code/src/com/suse/oval/vulnerablepkgextractor/SUSEVulnerablePackageExtractor.java @@ -42,7 +42,7 @@ */ public class SUSEVulnerablePackageExtractor extends CriteriaTreeBasedExtractor { private static final Pattern RELEASE_PACKAGE_REGEX = Pattern.compile( - "^\\s*(?[-a-zA-Z_0-9]+) is\\s*==\\s*(?[0-9.]+)\\s*$"); + "^\\s*(?[-a-zA-Z_0-9]+) is\\s*(==|>=)\\s*(?[0-9.]+)\\s*$"); private final OVALLookupHelper ovalLookupHelper; /** @@ -219,7 +219,7 @@ private Cpe deriveFromProductOVALTest(TestType productTest) { Matcher matcher = RELEASE_PACKAGE_REGEX.matcher(testComment); if (!matcher.matches()) { - throw new IllegalStateException("Failed to derive CPE from OVAL test"); + throw new IllegalStateException("Failed to derive CPE from OVAL test comment: " + testComment); } String releasePackage = matcher.group("releasePackage"); From 3c7637d5290e9324c41e54c7110141425e4dd4fc Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Mon, 1 Jul 2024 14:24:31 +0100 Subject: [PATCH 61/64] Relocate database migration script --- .../002-oval-taskomatic.sql} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename schema/spacewalk/upgrade/{susemanager-schema-4.4.6-to-susemanager-schema-4.4.7/003-oval-taskomatic.sql => susemanager-schema-5.0.7-to-susemanager-schema-5.0.8/002-oval-taskomatic.sql} (100%) diff --git a/schema/spacewalk/upgrade/susemanager-schema-4.4.6-to-susemanager-schema-4.4.7/003-oval-taskomatic.sql b/schema/spacewalk/upgrade/susemanager-schema-5.0.7-to-susemanager-schema-5.0.8/002-oval-taskomatic.sql similarity index 100% rename from schema/spacewalk/upgrade/susemanager-schema-4.4.6-to-susemanager-schema-4.4.7/003-oval-taskomatic.sql rename to schema/spacewalk/upgrade/susemanager-schema-5.0.7-to-susemanager-schema-5.0.8/002-oval-taskomatic.sql From 34229c52a8edacba44fc789722731da9deb55e7a Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Sun, 7 Jul 2024 23:22:03 +0100 Subject: [PATCH 62/64] Continue syncing other products if OVAL data syncing fails for one --- .../manager/audit/CVEAuditManagerOVAL.java | 48 +++++++++++-------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java index 4103b7db65b2..4a177730a5ef 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java +++ b/java/code/src/com/redhat/rhn/manager/audit/CVEAuditManagerOVAL.java @@ -368,32 +368,42 @@ public static void syncOVAL() { OVALDownloader ovalDownloader = new OVALDownloader(OVALConfigLoader.loadDefaultConfig()); for (OVALProduct product : productsToSync) { - LOG.debug("Downloading OVAL for {} {}", product.getOsFamily(), product.getOsVersion()); - OVALDownloadResult downloadResult; try { - downloadResult = ovalDownloader.download(product.getOsFamily(), product.getOsVersion()); + syncOVALForProduct(product, ovalDownloader); } - catch (IOException e) { - throw new RuntimeException("Failed to download OVAL data", e); + catch (Exception e) { + LOG.error("Failed to sync OVAL for product '{} {}'", + product.getOsFamily().fullname(), product.getOsVersion(), e); } - LOG.debug("Downloading finished"); + } + } + + private static void syncOVALForProduct(OVALProduct product, OVALDownloader ovalDownloader) { + LOG.debug("Downloading OVAL for {} {}", product.getOsFamily(), product.getOsVersion()); + OVALDownloadResult downloadResult; + try { + downloadResult = ovalDownloader.download(product.getOsFamily(), product.getOsVersion()); + } + catch (IOException e) { + throw new RuntimeException("Failed to download OVAL data", e); + } + LOG.debug("Downloading finished"); - LOG.debug("OVAL vulnerability file: {}", - downloadResult.getVulnerabilityFile().map(File::getAbsoluteFile).orElse(null)); - LOG.debug("OVAL patch file: {}", downloadResult.getPatchFile().map(File::getAbsoluteFile).orElse(null)); + LOG.debug("OVAL vulnerability file: {}", + downloadResult.getVulnerabilityFile().map(File::getAbsoluteFile).orElse(null)); + LOG.debug("OVAL patch file: {}", downloadResult.getPatchFile().map(File::getAbsoluteFile).orElse(null)); - downloadResult.getVulnerabilityFile().ifPresent(ovalVulnerabilityFile -> { - extractAndSaveOVALData(product, ovalVulnerabilityFile); - LOG.debug("Saving Vulnerability OVAL for {} {}", product.getOsFamily(), product.getOsVersion()); - }); + downloadResult.getVulnerabilityFile().ifPresent(ovalVulnerabilityFile -> { + extractAndSaveOVALData(product, ovalVulnerabilityFile); + LOG.debug("Saving Vulnerability OVAL for {} {}", product.getOsFamily(), product.getOsVersion()); + }); - downloadResult.getPatchFile().ifPresent(patchFile -> { - extractAndSaveOVALData(product, patchFile); - LOG.debug("Saving Patch OVAL for {} {}", product.getOsFamily(), product.getOsVersion()); - }); + downloadResult.getPatchFile().ifPresent(patchFile -> { + extractAndSaveOVALData(product, patchFile); + LOG.debug("Saving Patch OVAL for {} {}", product.getOsFamily(), product.getOsVersion()); + }); - LOG.debug("Saving OVAL finished"); - } + LOG.debug("Saving OVAL finished"); } /** From 81026c581207012a0c254ed24401c9d6c4db4ada Mon Sep 17 00:00:00 2001 From: HoussemNasri Date: Thu, 11 Jul 2024 01:31:24 +0100 Subject: [PATCH 63/64] Change string#replace by string#replaceFirst - The former does not accept a regex. --- java/code/src/com/redhat/rhn/manager/audit/OsReleasePair.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/code/src/com/redhat/rhn/manager/audit/OsReleasePair.java b/java/code/src/com/redhat/rhn/manager/audit/OsReleasePair.java index e6ee1aef73e2..d991894658ff 100644 --- a/java/code/src/com/redhat/rhn/manager/audit/OsReleasePair.java +++ b/java/code/src/com/redhat/rhn/manager/audit/OsReleasePair.java @@ -57,7 +57,7 @@ public Optional toOVALProduct() { serverOsFamily == OsFamily.SUSE_LINUX_ENTERPRISE_SERVER || serverOsFamily == OsFamily.SUSE_LINUX_ENTERPRISE_DESKTOP) { // Removing the minor version part: 15.6 --> 15 - serverOsRelease = serverOsRelease.replace("\\..*", ""); + serverOsRelease = serverOsRelease.replaceFirst("\\..*$", ""); } CVEAuditManagerOVAL.OVALProduct ovalProduct = null; From 5855da9424872b2bafd493b26492bd43f33b5edd Mon Sep 17 00:00:00 2001 From: Pascal Arlt Date: Thu, 5 Sep 2024 12:11:30 +0200 Subject: [PATCH 64/64] Move schema migration to current dir Signed-off-by: Pascal Arlt --- .../001-oval-taskomatic.sql} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename schema/spacewalk/upgrade/{susemanager-schema-5.0.7-to-susemanager-schema-5.0.8/002-oval-taskomatic.sql => susemanager-schema-5.1.0-to-susemanager-schema-5.1.1/001-oval-taskomatic.sql} (100%) diff --git a/schema/spacewalk/upgrade/susemanager-schema-5.0.7-to-susemanager-schema-5.0.8/002-oval-taskomatic.sql b/schema/spacewalk/upgrade/susemanager-schema-5.1.0-to-susemanager-schema-5.1.1/001-oval-taskomatic.sql similarity index 100% rename from schema/spacewalk/upgrade/susemanager-schema-5.0.7-to-susemanager-schema-5.0.8/002-oval-taskomatic.sql rename to schema/spacewalk/upgrade/susemanager-schema-5.1.0-to-susemanager-schema-5.1.1/001-oval-taskomatic.sql