Repository: oscal-compass/compliance-trestle
Pull request #1649 (2024-08-08 17:31:51)

fix: make status and mitre column optional
## Types of changes

<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->

- [ ] Hot fix (emergency fix and release)
- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Documentation (change which affects the documentation site)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] Release (`develop` -> `main`)

## Quality assurance (all should be covered).

- [x] My code follows the code style of this project.
- [ ] Documentation for my change is up to date?
- [ ] My PR meets testing requirements.
- [x] All new and existing tests passed.
- [x] All commits are signed-off.

## Summary

## Key links:

- [Sonar coverage](https://sonarcloud.io/dashboard?id=compliance-trestle)

# Before you merge

- Ensure it is a 'squash commit' if not a release.
- Ensure CI is currently passing
- Check sonar. If you are working for a fork a maintainer will reach out, if required.


degenaro: > @degenaro I might be wrong but is there a particular reason for creating 3 different test cases with almost the same steps being executed inside? I think we could reuse the code and just create a function called `test_cis_xlsx_to_oscal_catalog_wo_columns` or something similar and looping over the column values

Thx for the comment. Keeping test cases separate makes them simple and clear. These test cases are provided to insure 100% coverage for the subject under test. There is no real advantage to rolling up into a single test case in terms of time, space or duplication.

Patch:
diff --git a/trestle/tasks/cis_xlsx_to_oscal_catalog.py b/trestle/tasks/cis_xlsx_to_oscal_catalog.py
index cc68c6ae..65788dae 100644
--- a/trestle/tasks/cis_xlsx_to_oscal_catalog.py
+++ b/trestle/tasks/cis_xlsx_to_oscal_catalog.py
@@ -281,19 +281,27 @@ class CisXlsxToOscalCatalog(TaskBase):
 
     def _add_property(self, xlsx_helper: XlsxHelper, props: List[Property], row: int, key: str) -> None:
         """Add property."""
-        name = self._get_normalized_name(key)
-        value = xlsx_helper.get(row, key)
-        if value:
-            props.append(self._create_property(name, value))
+        try:
+            name = self._get_normalized_name(key)
+            value = xlsx_helper.get(row, key)
+            if value:
+                props.append(self._create_property(name, value))
+        except KeyError as e:
+            text = f'key {e} not found.'
+            logger.debug(text)
 
     def _add_property_boolean(self, xlsx_helper: XlsxHelper, props: List[Property], row: int, key: str) -> None:
         """Add property."""
-        name = self._get_normalized_name(key)
-        value = xlsx_helper.get(row, key)
-        if value:
-            props.append(self._create_property(name, 'True'))
-        else:
-            props.append(self._create_property(name, 'False'))
+        try:
+            name = self._get_normalized_name(key)
+            value = xlsx_helper.get(row, key)
+            if value:
+                props.append(self._create_property(name, 'True'))
+            else:
+                props.append(self._create_property(name, 'False'))
+        except KeyError as e:
+            text = f'key {e} not found.'
+            logger.debug(text)
 
     def _add_part(self, xlsx_helper: XlsxHelper, parts: List[Part], id_: str, row: int, key: str) -> None:
         """Add part."""


Test patch:
diff --git a/tests/trestle/tasks/cis_xlsx_to_oscal_catalog_test.py b/tests/trestle/tasks/cis_xlsx_to_oscal_catalog_test.py
index 996a5ba2..cd1b1ec2 100644
--- a/tests/trestle/tasks/cis_xlsx_to_oscal_catalog_test.py
+++ b/tests/trestle/tasks/cis_xlsx_to_oscal_catalog_test.py
@@ -185,6 +185,57 @@ def test_cis_xlsx_to_oscal_catalog_unexpected_section(tmp_path: pathlib.Path):
         assert retval == TaskOutcome.FAILURE
 
 
+def test_cis_xlsx_to_oscal_catalog_no_status(tmp_path: pathlib.Path):
+    """Test no column with name status."""
+    folder = 'tests/data/tasks/cis-xlsx-to-oscal-catalog'
+    file_ = f'{folder}/CIS_RedHat_OpenShift_Container_Platform_Benchmark_v1.2.0-2.snippet.xlsx'
+    wb_hacked = load_workbook(file_)
+    sheet = wb_hacked['Combined Profiles']
+    cell = sheet.cell(1, 5)
+    assert cell.value == 'status'
+    cell.value = 'X'
+    with mock.patch('trestle.tasks.cis_xlsx_to_oscal_catalog.load_workbook') as load_workbook_mock:
+        load_workbook_mock.return_value = wb_hacked
+        section = _get_section(tmp_path, ocp_config)
+        tgt = cis_xlsx_to_oscal_catalog.CisXlsxToOscalCatalog(section)
+        retval = tgt.execute()
+        assert retval == TaskOutcome.SUCCESS
+
+
+def test_cis_xlsx_to_oscal_catalog_no_mitre(tmp_path: pathlib.Path):
+    """Test no column with name mitre."""
+    folder = 'tests/data/tasks/cis-xlsx-to-oscal-catalog'
+    file_ = f'{folder}/CIS_RedHat_OpenShift_Container_Platform_Benchmark_v1.2.0-2.snippet.xlsx'
+    wb_hacked = load_workbook(file_)
+    sheet = wb_hacked['Combined Profiles']
+    cell = sheet.cell(1, 20)
+    assert cell.value == 'MITRE ATT&CK Mappings'
+    cell.value = 'X'
+    with mock.patch('trestle.tasks.cis_xlsx_to_oscal_catalog.load_workbook') as load_workbook_mock:
+        load_workbook_mock.return_value = wb_hacked
+        section = _get_section(tmp_path, ocp_config)
+        tgt = cis_xlsx_to_oscal_catalog.CisXlsxToOscalCatalog(section)
+        retval = tgt.execute()
+        assert retval == TaskOutcome.SUCCESS
+
+
+def test_cis_xlsx_to_oscal_catalog_no_v7_ig1(tmp_path: pathlib.Path):
+    """Test no column with name v7 IG1."""
+    folder = 'tests/data/tasks/cis-xlsx-to-oscal-catalog'
+    file_ = f'{folder}/CIS_RedHat_OpenShift_Container_Platform_Benchmark_v1.2.0-2.snippet.xlsx'
+    wb_hacked = load_workbook(file_)
+    sheet = wb_hacked['Combined Profiles']
+    cell = sheet.cell(1, 14)
+    assert cell.value == 'v7 IG1'
+    cell.value = 'Z'
+    with mock.patch('trestle.tasks.cis_xlsx_to_oscal_catalog.load_workbook') as load_workbook_mock:
+        load_workbook_mock.return_value = wb_hacked
+        section = _get_section(tmp_path, ocp_config)
+        tgt = cis_xlsx_to_oscal_catalog.CisXlsxToOscalCatalog(section)
+        retval = tgt.execute()
+        assert retval == TaskOutcome.SUCCESS
+
+
 def test_cis_xlsx_to_oscal_catalog_execute_rhel(tmp_path: pathlib.Path):
     """Test execute call - rhel."""
     section = _get_section(tmp_path, rhel_config)