diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index 745da7c..fd8db1a 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -16,3 +16,8 @@ jobs:
java-version: '11'
- name: Build with Maven
run: mvn package --file pom.xml
+ - name: 'Upload Artifact'
+ uses: actions/upload-artifact@v3
+ with:
+ name: JAR
+ path: target/linux-sbom-generator-*.jar
diff --git a/pom.xml b/pom.xml
index b53f7cb..2ee808d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,13 +5,13 @@
org.cyclonedx.contrib.com.lmco.efoss.unix.sbom
linux-sbom-generator
- 3.1.0-SNAPSHOT
+ 3.2.0-SNAPSHOT
linux-sbom-generator
Unix SBOM Generator
https://github.com/CycloneDX/cyclonedx-linux-generator
- 5.0.4
+ 7.2.0
2.5.3
1.3
diff --git a/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/AlpineSBomGenerator.java b/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/AlpineSBomGenerator.java
index ac375f8..47c1168 100644
--- a/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/AlpineSBomGenerator.java
+++ b/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/AlpineSBomGenerator.java
@@ -66,7 +66,7 @@ public Bom generateSBom()
detailMap = produceDetailMap(software);
version = getVersion(software);
component = createComponents(software, detailMap, null, null,
- version, null, null);
+ version, null, null, null);
bom.addComponent(addPackageManager(component, PACKAGE_MANAGER));
}
return bom;
diff --git a/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/RedHatSBomGenerator.java b/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/RedHatSBomGenerator.java
index 7327de3..397b4d8 100644
--- a/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/RedHatSBomGenerator.java
+++ b/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/RedHatSBomGenerator.java
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) 2018,2019 Lockheed Martin Corporation.
*
* This work is owned by Lockheed Martin Corporation. Lockheed Martin personnel are permitted to use and
@@ -18,7 +18,11 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.TreeMap;
+import com.github.packageurl.MalformedPackageURLException;
+import com.github.packageurl.PackageURL;
+import com.google.common.base.Splitter;
import org.cyclonedx.model.Bom;
import org.cyclonedx.model.Component;
import org.cyclonedx.model.LicenseChoice;
@@ -28,7 +32,7 @@
/**
* * (U) This class is responsible for generating the Software Bill Of Materials (SBOM) for all
* Oracle Red Hat Linux Operating Systems.
- *
+ *
* @author wrgoff
* @since 24 April 2020
*/
@@ -37,58 +41,84 @@ public class RedHatSBomGenerator extends UnixSBomGenerator
private static final List POSSIBLE_LICENSE_FILES = new ArrayList<>(
List.of("LICENSE.txt",
"LICENSE", "COPYING", "COPYING.LGPL", "PORTING", "Copying"));
-
+
private static final String PACKAGE_MANAGER = "yum";
-
+
// Unix Commands.
private static final String PURL_CMD = "yumdownloader --urls";
private static final String SOFTWARE_DETAIL_CMD = "yum info";
private static final String SOFTWARE_LIST_CMD = "yum list installed";
-
+
+ private String purlNamespace = null;
+
private ProcessBuilder processBuilder = new ProcessBuilder();
-
+
+ public void setPurlNamespace(String ns){
+ this.purlNamespace = ns;
+ }
+
/**
* (U) This method is used to generate the Software Bill Of Materials (SBOM) for all RedHat
* Linux Operating systems.
- *
+ *
* @return Bom The Software Bill Of Materials for this RedHat Linux Operating System.
* @throws SBomException if we are unable to build the SBOM.
*/
- public Bom generateSBom()
- {
- List softwareList = generateListOfSoftware(SOFTWARE_LIST_CMD, ' ',
- "Installed Packages");
-
- Bom bom = new Bom();
-
- if (logger.isDebugEnabled())
- logger.debug("Processing " + softwareList.size() + " software programs.");
-
- Map detailMap = null;
- String version = null;
- String group = null;
- LicenseChoice license = null;
- String purl = null;
- Component component = null;
- for (String software : softwareList)
- {
- if (logger.isDebugEnabled())
- logger.debug("Generating Component (" + software + ")");
- detailMap = produceDetailMap(software);
- version = detailMap.get("Version");
- group = detailMap.get("Release");
- license = processLicense(software, version);
- purl = getPurl(software);
- component = createComponents(software, detailMap, license, group,
- version, purl, detailMap.get("Priority"));
- bom.addComponent(addPackageManager(component, PACKAGE_MANAGER));
- }
- return bom;
+ public Bom generateSBom() {
+ List softwareList = generateListOfSoftware(SOFTWARE_LIST_CMD, ' ',
+ "Installed Packages");
+
+ Bom bom = new Bom();
+
+ if (logger.isDebugEnabled())
+ logger.debug("Processing " + softwareList.size() + " software programs.");
+
+ Map detailMap = null;
+ String version = null;
+ String group = null;
+ LicenseChoice license = null;
+ PackageURL purl = null;
+ Component component = null;
+ String cpe = null;
+ for (String software : softwareList) {
+ if (logger.isDebugEnabled())
+ logger.debug("Generating Component (" + software + ")");
+ detailMap = produceDetailMap(software);
+ version = detailMap.get("Version");
+ group = detailMap.get("Release");
+ license = processLicense(software, version);
+ try {
+ purl = getPurl(software, version);
+
+ // TODO: get arch and distro
+ //purl = getPurl(software,version, arch, distro);
+ } catch (MalformedPackageURLException e) {
+ logger.debug("Can't get purl", e);
+ }
+ cpe = getCpe(detailMap.get("Name"), version);
+
+ try {
+ String downloadUrl = getPackageDownloadUrl(software);
+ if (downloadUrl != null) {
+ detailMap.put("Download-Url", downloadUrl);
+ }
+ } catch(SBomException e){
+ logger.debug("Error getting Download-Url", e);
+ }
+ component = createComponents(software, detailMap, license, group,
+ version, purl, detailMap.get("Priority"), cpe);
+ bom.addComponent(addPackageManager(component, PACKAGE_MANAGER));
+ }
+ return bom;
+ }
+
+ private String getCpe(String pack, String version) {
+ return String.format("cpe:2.3:a:%s:%s:%s:*:*:*:*:*:*:*", pack, pack, version);
}
-
+
/**
* (U) This method is used to attempt to figure out which file is the license file. If any.
- *
+ *
* @param software String value of the software we are attempting to get the license file for.
* @param version String value of the version of the software we are attempting to get the
* license for.
@@ -97,19 +127,19 @@ public Bom generateSBom()
public String getLicenseFileName(String software, String version)
{
File tempFile = null;
-
+
software = software.trim();
-
+
if (software.endsWith(".x86_64"))
software = software.replace(".x86_64", "");
-
+
if (version != null)
software = software + "-" + version.trim();
-
+
if (logger.isDebugEnabled())
logger.debug("Attempting to get license file from " + SOFTWARE_LICENSE_DIR + software +
".");
-
+
for (String fileToTry : POSSIBLE_LICENSE_FILES)
{
tempFile = new File(SOFTWARE_LICENSE_DIR + software, fileToTry);
@@ -118,26 +148,52 @@ public String getLicenseFileName(String software, String version)
}
return null;
}
-
+
+
+ public PackageURL getPurl(String software, String version) throws MalformedPackageURLException {
+ List parts = Splitter.on('.').splitToList(software);
+
+ if (parts.size() == 0) {
+ return this.getPurl(software, version, null, null);
+ }
+ if (parts.size() == 1) {
+ return this.getPurl(parts.get(0), version, null, null);
+ } else {
+ return this.getPurl(parts.get(0), version, parts.get(1), null);
+ }
+ }
+
+ public PackageURL getPurl(String software, String version, String arch, String distro) throws MalformedPackageURLException {
+
+ TreeMap qualifiers = new TreeMap<>();
+ if (arch != null) {
+ qualifiers.put("arch", arch);
+ }
+ if (distro != null) {
+ qualifiers.put("distro", distro);
+ }
+ return new PackageURL(
+ PackageURL.StandardTypes.RPM, purlNamespace, software, version, qualifiers, null);
+ }
+
+
/**
* (U) This method is used to get the Product Uniform Resource Locator (PURL) or as we know it
* the download Uniform Resource Locator (URL).
- *
+ *
* @param software String value of the software to get the PURL for.
* @return String the URL that will be used to download this software product.
* @throws SBomException in the event we are unable to get the PURL from the server.
*/
- public String getPurl(String software)
- {
+ public String getPackageDownloadUrl(String software){
String purl = null;
-
String cmd = PURL_CMD + " " + software;
-
+
processBuilder.command("bash", "-c", cmd);
-
+
if (logger.isDebugEnabled())
logger.debug("Attempting to get PURL for " + software + ".");
-
+
try
{
Process process = processBuilder.start();
@@ -152,10 +208,10 @@ public String getPurl(String software)
}
return purl;
}
-
+
/**
* (U) This method is used to parse the PURL from the output of the command process.
- *
+ *
* @param process Process that is running the YUM command.
* @param software String value of the software, used for debugging purposes.
* @return String the PURL if available.
@@ -164,15 +220,15 @@ public String getPurl(String software)
public String parsePurl(Process process, String software)
{
String purl = null;
-
+
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream())))
{
purl = parsePurlCmdOutput(reader);
-
+
if (purl == null)
logger.warn("No PURL found for software package (" + software + ").");
-
+
int exitVal = process.waitFor();
if (exitVal != 0)
{
@@ -194,11 +250,11 @@ public String parsePurl(Process process, String software)
}
return purl;
}
-
+
/**
* (U) This method is used to parse the Unix Command Output to get the download Uniform Resource
* Locator (URL) also known as the Product Uniform Resource Locator (PURL)
- *
+ *
* @param reader BufferedReader to parse the output form.
* @return String the PURL or download URL that can be used to download the software package.
* @throws SBomException in the event we are unable to parse the command's output.
@@ -232,11 +288,11 @@ else if (line.startsWith("No Match for argument")) // No PURL found.
}
return purl;
}
-
+
/**
* (U) This method is responsible for getting the license (if present) and placing it in the
* LicenseChoice Object passed back.
- *
+ *
* @param software String value of the software we are attempting to get the license for.
* @param version String value of the version of the software we are attempting to get the
* license for.
@@ -246,18 +302,18 @@ private LicenseChoice processLicense(String software, String version)
{
if (logger.isDebugEnabled())
logger.debug("Attempting to get license file for " + software + ".");
-
+
LicenseChoice licenseChoice = null;
-
+
String licenseFile = getLicenseFileName(software, version);
-
+
try
{
if (licenseFile != null)
{
if (logger.isDebugEnabled())
logger.debug("Attempting to process license (" + licenseFile + ")");
-
+
String licenseTxt = new String(Files.readAllBytes(Paths.get(licenseFile)));
licenseChoice = parseLicenseText(licenseTxt, AVAILABLE_LINUX_FLAVORS.REDHAT);
}
@@ -270,11 +326,11 @@ private LicenseChoice processLicense(String software, String version)
}
return licenseChoice;
}
-
+
/**
* (U) This method is used to produce a Detail Map of the Software in question. This will be
* used to create a CycloneDx Component.
- *
+ *
* @param software String value of the component to build the detail map for.
* @return Map containing the key value pairs about the software.
* @throws SBomException in the event we can NOT produce the detail map of the software.
@@ -282,7 +338,7 @@ private LicenseChoice processLicense(String software, String version)
private Map produceDetailMap(String software)
{
String cmd = SOFTWARE_DETAIL_CMD + " " + software;
-
+
return (produceDetailMap(cmd, AVAILABLE_LINUX_FLAVORS.REDHAT));
}
}
diff --git a/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/SBomGenerator.java b/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/SBomGenerator.java
index eb82c80..ec35061 100644
--- a/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/SBomGenerator.java
+++ b/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/SBomGenerator.java
@@ -145,13 +145,13 @@ public static void createBomFile(Bom bom, SBomCommons.AVAILABLE_FORMATS format)
* imageUrl provided.
*/
public static Component createMasterComponent(String imageUrl, String name,
- String group, String version) throws SBomException
+ String group, String version, String cpe) throws SBomException
{
Component master = null;
if ((StringUtils.isValid(imageUrl)) ||
(StringUtils.isValid(name) && ((StringUtils.isValid(version)))))
{
- master = createMasterComponent(imageUrl);
+ master = createMasterComponent(imageUrl,name,group,version, imageUrl ,cpe);
if (StringUtils.isValid(imageUrl))
{
@@ -173,6 +173,11 @@ public static Component createMasterComponent(String imageUrl, String name,
logger.error(error, e);
throw new SBomException(error);
}
+ }else{
+ master.setType(Component.Type.OPERATING_SYSTEM);
+ if(StringUtils.isValid(cpe)){
+ master.setCpe(cpe);
+ }
}
if (StringUtils.isValid(name))
master.setName(name.toLowerCase());
@@ -292,6 +297,7 @@ private static Component createMasterComponent(CommandLine cli) throws SBomExcep
String name = cli.getOptionValue("name");
String group = cli.getOptionValue("group");
String version = cli.getOptionValue("version");
+ String cpe = cli.getOptionValue("cpe");
if ((!StringUtils.isValid(name)) || (!StringUtils.isValid(version)))
{
@@ -301,9 +307,11 @@ private static Component createMasterComponent(CommandLine cli) throws SBomExcep
name = osUtils.getOsVendor();
if (!StringUtils.isValid(version))
version = osUtils.getOsVersion();
+ if (!StringUtils.isValid(cpe))
+ cpe = osUtils.getOsCpe();
}
- master = createMasterComponent(imageUrl, name, group, version);
+ master = createMasterComponent(imageUrl, name, group, version, cpe);
return master;
}
@@ -312,12 +320,17 @@ private static Component createMasterComponent(CommandLine cli) throws SBomExcep
* (U) This method is used to create the master component. It will then fill in
* the image information (if provided).
*
+ *
+ * @param url
+ * @param name
+ * @param group
+ * @param version
* @param imageUrl String value of where to get the docker image from.
* @return Component created, and filled in if the imageUrl is provided.
* @throws SBomException in the event we are unable to pull the image via the
* image URL provided.
*/
- private static Component createMasterComponent(String imageUrl) throws SBomException
+ private static Component createMasterComponent(String url, String name, String group, String version, String imageUrl, String cpe) throws SBomException
{
Component master = new Component();
master.setType(org.cyclonedx.model.Component.Type.CONTAINER);
diff --git a/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/UbuntuSBomGenerator.java b/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/UbuntuSBomGenerator.java
index ba935ae..373db80 100644
--- a/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/UbuntuSBomGenerator.java
+++ b/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/UbuntuSBomGenerator.java
@@ -71,7 +71,7 @@ public Bom generateSBom()
group = detailMap.get("Release");
license = processLicense(software);
component = createComponents(software, detailMap, license, group,
- version, null, detailMap.get("Priority"));
+ version, null, detailMap.get("Priority"), null);
bom.addComponent(addPackageManager(component, PACKAGE_MANAGER));
}
diff --git a/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/UnixSBomGenerator.java b/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/UnixSBomGenerator.java
index 6986c41..b6434ab 100644
--- a/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/UnixSBomGenerator.java
+++ b/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/UnixSBomGenerator.java
@@ -17,6 +17,7 @@
import java.util.List;
import java.util.Map;
+import com.github.packageurl.PackageURL;
import org.apache.log4j.Logger;
import org.cyclonedx.model.AttachmentText;
import org.cyclonedx.model.Component;
@@ -41,7 +42,7 @@ public class UnixSBomGenerator
{
protected enum AVAILABLE_LINUX_FLAVORS
{
- ALPINE, REDHAT, UBUNTU
+ ALPINE, REDHAT, UBUNTU, AL2
}
protected static final Logger logger = Logger.getLogger(UnixSBomGenerator.class.getName());
@@ -90,6 +91,12 @@ public List buildExternalReferences(Map detai
bugs.setType(ExternalReference.Type.ISSUE_TRACKER);
refs.add(bugs);
}
+ if (detailMap.containsKey("Download-Url")){
+ ExternalReference docs = new ExternalReference();
+ docs.setUrl(detailMap.get("Download-Url"));
+ docs.setType(ExternalReference.Type.DISTRIBUTION);
+ refs.add(docs);
+ }
return refs;
}
@@ -122,10 +129,11 @@ else if (priority.equalsIgnoreCase("optional"))
* @param version String value to set the version to.
* @param purl String to set the URL used to pull the software from.
* @param scope String value to help us set the scope of the software.
+ * @param cpe String value for cpe, if relevant
* @return Component Sbom Component created from the supplied inputs.
*/
public Component createComponents(String software, Map detailMap,
- LicenseChoice license, String group, String version, String purl, String scope)
+ LicenseChoice license, String group, String version, PackageURL purl, String scope, String cpe)
{
Component component = new Component();
component.setType(Type.OPERATING_SYSTEM);
@@ -136,7 +144,12 @@ public Component createComponents(String software, Map detailMap
component.setGroup(group);
component.setLicenseChoice(license);
component.setPublisher(detailMap.get("From repo"));
- component.setPurl(purl);
+ if(purl!=null) {
+ component.setPurl(purl);
+ }
+ if(cpe!=null){
+ component.setCpe(cpe);
+ }
component.setScope(buildScope(scope));
component.setVersion(version);
diff --git a/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/utils/OperatingSystemUtils.java b/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/utils/OperatingSystemUtils.java
index db11a16..0fd98d0 100644
--- a/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/utils/OperatingSystemUtils.java
+++ b/src/main/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/utils/OperatingSystemUtils.java
@@ -30,9 +30,9 @@
public class OperatingSystemUtils
{
private static final Logger logger = Logger.getLogger(OperatingSystemUtils.class.getName());
-
+
private static final String OS_RELEASE_FILE = "/etc/os-release";
-
+
private Map osMap = null;
/**
@@ -113,6 +113,25 @@ public String getOsVersion()
return version;
}
+ /**
+ * (U) This method is used to get the operating system's CPE, if it has one defined.
+ *
+ * @return String the operating system CPE.
+ */
+ public String getOsCpe()
+ {
+ String cpe = null;
+
+ if (osMap.containsKey("CPE_NAME"))
+ cpe = osMap.get("CPE_NAME");
+ if (StringUtils.isValid(cpe))
+ cpe = CharMatcher.is('\"').trimFrom(cpe);
+
+ return cpe;
+ }
+
+
+
/**
* (U) This method is used to get the operating system. From the /etc/os-release
* file.
@@ -133,12 +152,14 @@ public Map getOs()
catch (IOException ioe)
{
String error = "Unable to read file(" + OS_RELEASE_FILE + ") to get the " +
- "operating sytem!";
+ "operating system!";
logger.error(error, ioe);
throw new SBomException(error, ioe);
}
return detailMap;
}
+
+
/**
* (U) This method is used to read the contents of the OS file.
@@ -146,7 +167,7 @@ public Map getOs()
* @param content String value read from the file.
* @return Map containing the information about the Operating system.
*/
- public Map readOs(String content)
+ public static Map readOs(String content)
{
Map detailMap = new HashMap<>();
diff --git a/src/test/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/RedHatSBomGeneratorTest.java b/src/test/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/RedHatSBomGeneratorTest.java
index a002a53..2bf8c94 100644
--- a/src/test/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/RedHatSBomGeneratorTest.java
+++ b/src/test/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/RedHatSBomGeneratorTest.java
@@ -18,6 +18,7 @@
import java.util.List;
import java.util.Map;
+import com.github.packageurl.PackageURL;
import org.cyclonedx.model.ExternalReference;
import org.junit.Assert;
import org.junit.jupiter.api.Test;
@@ -116,9 +117,10 @@ void getPurlTest()
Date startDate = DateUtils.rightNowDate();
TestUtils.logTestStart(methodName, watcher.getLogger());
-
- String expected = "https://rhui3.us-west-2.aws.ce.redhat.com/pulp/repos/content/dist/rhel/rhui/server/7/7Server/x86_64/os/Packages/z/zip-3.0-11.el7.x86_64.rpm";
-
+
+ String expectedUrl = "https://rhui3.us-west-2.aws.ce.redhat.com/pulp/repos/content/dist/rhel/rhui/server/7/7Server/x86_64/os/Packages/z/zip-3.0-11.el7.x86_64.rpm";
+ String expected = "pkg:rpm/zip@3.0-11.el7?arch=x64_86";
+
AutoCloseable openMocks = null;
String fileName = "/purl/redhatPurl.txt";
@@ -131,12 +133,12 @@ void getPurlTest()
Mockito.when(pbMock.start()).thenReturn(process);
- String version = generator.getPurl("zip");
+ PackageURL purl = generator.getPurl("zip.x64_86", "3.0-11.el7");
- if (expected.equalsIgnoreCase(version))
- watcher.getLogger().debug("Got expected version (" + version + ")");
+ if (expected.equalsIgnoreCase(purl.toString()))
+ watcher.getLogger().debug("Got expected version (" + purl + ")");
else
- Assert.assertEquals(expected, version);
+ Assert.assertEquals(expected, purl.toString());
}
catch (Exception e)
{
diff --git a/src/test/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/UnixSBomGeneratorTest.java b/src/test/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/UnixSBomGeneratorTest.java
index 73a0914..09688d1 100644
--- a/src/test/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/UnixSBomGeneratorTest.java
+++ b/src/test/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/generator/UnixSBomGeneratorTest.java
@@ -137,7 +137,7 @@ void createComponentsTest()
String version = detailMap.get("Version");
String group = detailMap.get("Release");
Component component = generator.createComponents("zip",
- detailMap, null, group, version, null, detailMap.get("Priority"));
+ detailMap, null, group, version, null, detailMap.get("Priority"), null);
String actualComponentName = component.getName();
String actualComponentVerison = component.getVersion();
diff --git a/src/test/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/utils/OperatingSystemUtilsTest.java b/src/test/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/utils/OperatingSystemUtilsTest.java
index a7b5fd8..8385cc3 100644
--- a/src/test/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/utils/OperatingSystemUtilsTest.java
+++ b/src/test/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/utils/OperatingSystemUtilsTest.java
@@ -12,6 +12,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
+import java.util.HashMap;
import java.util.Map;
import org.apache.commons.io.IOUtils;
@@ -569,6 +570,49 @@ void testOsVersion(String file, String expectedOsVersion)
}
}
+ /**
+ * (U) Convenience method used to test the reading of the CPE from the
+ * "/etc/os-release" file.
+ *
+ * @param file String value of the contents of the
+ * "/etc/os-release" file.
+ * @param expectedCpe String value of the expected CPE.
+ */
+ void testCpe(String file, String expectedCpe)
+ {
+ try (InputStream inputStream = OperatingSystemUtilsTest.class.getResourceAsStream(file))
+ {
+ String osReleaseFileContents = IOUtils.toString(inputStream);
+
+ OperatingSystemUtils osUtils = new OperatingSystemUtils(osReleaseFileContents);
+
+ String actualCpe = osUtils.getOsCpe();
+
+ if (expectedCpe.equalsIgnoreCase(actualCpe))
+ watcher.getLogger().debug("Got expected CPE (" +
+ expectedCpe + ").");
+ else
+ watcher.getLogger().debug("Did NOT get expected CPE!\n" +
+ " Expected: " + expectedCpe + "\n" +
+ " Acutal: " + actualCpe);
+
+ Assert.assertEquals(expectedCpe, actualCpe);
+ }
+ catch (IOException ioe)
+ {
+ String error = "Our test case failed to read the operating system " +
+ "etc/os-release file(" + file + ").";
+ watcher.getLogger().error(error, ioe);
+ Assert.fail("Unable to read /etc/os-release File (" + file + "). ");
+ }
+ catch (Exception e)
+ {
+ String error = "Our test case failed unexpectedly.";
+ watcher.getLogger().error(error, e);
+ Assert.fail(error);
+ }
+ }
+
/**
* (U) This method is used to test the parsing of the Ubuntu Os File.
*/
@@ -589,12 +633,12 @@ void testReadOsUbuntu()
{
try (InputStream inputStream = OperatingSystemUtilsTest.class.getResourceAsStream(file))
{
- String theString = IOUtils.toString(inputStream);
-
- OperatingSystemUtils osUtils = new OperatingSystemUtils();
- Map osMap = osUtils.readOs(theString);
+ String theString = IOUtils.toString(inputStream);
+
+ var opts = readOs(theString);
+ var osUtils = new TestOperatingSystemUtil("Ubuntu", opts);
- String osVendor = osMap.get("NAME");
+ String osVendor = opts.get("NAME");
osVendor = CharMatcher.is('\"').trimFrom(osVendor);
if (expected.equalsIgnoreCase(osVendor))
@@ -623,4 +667,66 @@ void testReadOsUbuntu()
TestUtils.logTestFinish(methodName, startDate, watcher.getLogger());
}
}
+
+ /**
+ * (U) This method is used to test the getting of the OS name from the
+ * os-release file. For Redhat.
+ */
+ @Test
+ void getOsCpeRedhat()
+ {
+ // @formatter:off
+ String methodName = new Object(){}.getClass().getEnclosingMethod().getName();
+ // @formatter:on
+
+ Date startDate = DateUtils.rightNowDate();
+
+ TestUtils.logTestStart(methodName, watcher.getLogger());
+
+ String file = "/osReleaseFiles/redhat-os-release.txt";
+ String expectedCpe = "cpe:/o:redhat:enterprise_linux:8.1:GA";
+ try
+ {
+ testCpe(file, expectedCpe);
+ }
+ finally
+ {
+ TestUtils.logTestFinish(methodName, startDate, watcher.getLogger());
+ }
+ }
+
+ private Map readOs(String content)
+ {
+ Map detailMap = new HashMap<>();
+
+ String[] contents = content.split("\n");
+ String componentDetailName = null;
+ StringBuilder componentDetailValue = new StringBuilder();
+ int index = 0;
+
+ for (String line : contents)
+ {
+ if (line.startsWith(" "))
+ {
+ componentDetailValue.append(line);
+ }
+ else
+ {
+ if (componentDetailName != null)
+ {
+ detailMap.put(componentDetailName, componentDetailValue.toString());
+ componentDetailName = null;
+ componentDetailValue = new StringBuilder();
+ }
+
+ if (line.contains("="))
+ {
+ index = line.indexOf('=');
+ componentDetailName = line.substring(0, index);
+ componentDetailValue.append(line.substring(index + 1).trim());
+ }
+ }
+ }
+ return detailMap;
+ }
}
diff --git a/src/test/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/utils/TestOperatingSystemUtil.java b/src/test/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/utils/TestOperatingSystemUtil.java
new file mode 100644
index 0000000..0ebfbdd
--- /dev/null
+++ b/src/test/java/org/cyclonedx/contrib/com/lmco/efoss/unix/sbom/utils/TestOperatingSystemUtil.java
@@ -0,0 +1,12 @@
+package org.cyclonedx.contrib.com.lmco.efoss.unix.sbom.utils;
+
+import java.util.Map;
+
+public class TestOperatingSystemUtil {
+ private Map osMap = null;
+
+ public TestOperatingSystemUtil(String name, Map testMap)
+ {
+ osMap = testMap;
+ }
+}