From eeb715c4cd86c3bd5183592c03beac1cc46859d9 Mon Sep 17 00:00:00 2001 From: Matthew Burket Date: Mon, 11 Dec 2023 09:07:54 -0600 Subject: [PATCH] feat: allow use of OpenSCAP result files in task xccdf_result_to_oscal_ar (#1411) * feat: Allow use of OpenSCAP result files in task xccdf_result_to_oscal_ar Before this commit if you wanted to use result files from OpenSCAP in the task xccdf_result_to_oscal_ar you had to extract the `TestResult` element and place it as the root of the XML document, otherwise the resulting OSCAL document would be blank. Thus making it impossible to directly use output from OpenSCAP with the task. With this commit the task will detect that the root element is not `TestResult` and then it will find the `TestResult` element in the XML document. This allows the use of files created by OpenSCAP using the `--results` and `--results-arf` switches. Signed-off-by: Matthew Burket * Add tests for OpenSCAP results files for task xccdf_result_to_oscal_ar_test Signed-off-by: Matthew Burket --------- Signed-off-by: Matthew Burket --- .../input-oscap-arf-results/results_arf.xml | 49 ++++++ .../xccdf/input-oscap-results/results.xml | 39 +++++ .../results_arf.oscal.json | 165 ++++++++++++++++++ .../output-oscap-results/results.oscal.json | 165 ++++++++++++++++++ ...to-oscal-ar-input-oscap-arf-results.config | 4 + ...ult-to-oscal-ar-input-oscap-results.config | 4 + .../tasks/xccdf_result_to_oscal_ar_test.py | 46 +++++ trestle/transforms/implementations/xccdf.py | 7 +- 8 files changed, 478 insertions(+), 1 deletion(-) create mode 100644 tests/data/tasks/xccdf/input-oscap-arf-results/results_arf.xml create mode 100644 tests/data/tasks/xccdf/input-oscap-results/results.xml create mode 100644 tests/data/tasks/xccdf/output-oscap-arf-results/results_arf.oscal.json create mode 100644 tests/data/tasks/xccdf/output-oscap-results/results.oscal.json create mode 100644 tests/data/tasks/xccdf/test-xccdf-result-to-oscal-ar-input-oscap-arf-results.config create mode 100644 tests/data/tasks/xccdf/test-xccdf-result-to-oscal-ar-input-oscap-results.config diff --git a/tests/data/tasks/xccdf/input-oscap-arf-results/results_arf.xml b/tests/data/tasks/xccdf/input-oscap-arf-results/results_arf.xml new file mode 100644 index 000000000..4285d1feb --- /dev/null +++ b/tests/data/tasks/xccdf/input-oscap-arf-results/results_arf.xml @@ -0,0 +1,49 @@ + + + + + + + + OSCAP Scan Result + + kube-c18ler8d06m877hrn7jg-roks8-default-00000319.iks.mycorp + + chroot:///host + OpenSCAP + 1.3.3 + + + + + + + + + + + + + + + + notselected + CCE-83691-6 + + + pass + CCE-27078-5 + + + + + + 74.713684 + + + + + + diff --git a/tests/data/tasks/xccdf/input-oscap-results/results.xml b/tests/data/tasks/xccdf/input-oscap-results/results.xml new file mode 100644 index 000000000..c3bb2a576 --- /dev/null +++ b/tests/data/tasks/xccdf/input-oscap-results/results.xml @@ -0,0 +1,39 @@ + + + + + OSCAP Scan Result + + kube-c18ler8d06m877hrn7jg-roks8-default-00000319.iks.mycorp + + chroot:///host + OpenSCAP + 1.3.3 + + + + + + + + + + + + + + + + notselected + CCE-83691-6 + + + pass + CCE-27078-5 + + + + + 74.713684 + + diff --git a/tests/data/tasks/xccdf/output-oscap-arf-results/results_arf.oscal.json b/tests/data/tasks/xccdf/output-oscap-arf-results/results_arf.oscal.json new file mode 100644 index 000000000..5047ece39 --- /dev/null +++ b/tests/data/tasks/xccdf/output-oscap-arf-results/results_arf.oscal.json @@ -0,0 +1,165 @@ +{ + "results": [ + { + "uuid": "56666738-0f9a-4e38-9aac-c0fad00a5821", + "title": "XCCDF", + "description": "XCCDF Scan Results", + "start": "2021-06-08T02:35:55+00:00", + "end": "2021-06-08T02:35:55+00:00", + "local-definitions": { + "components": [ + { + "uuid": "56666738-0f9a-4e38-9aac-c0fad00a5821", + "type": "Service", + "title": "rhel7", + "description": "rhel7", + "status": { + "state": "operational" + } + } + ], + "inventory-items": [ + { + "uuid": "56666738-0f9a-4e38-9aac-c0fad00a5821", + "description": "inventory", + "props": [ + { + "name": "target", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "kube-c18ler8d06m877hrn7jg-roks8-default-00000319.iks.mycorp" + }, + { + "name": "target_type", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "rhel7" + } + ], + "implemented-components": [ + { + "component-uuid": "56666738-0f9a-4e38-9aac-c0fad00a5821" + } + ] + } + ], + "assessment-assets": { + "components": [ + { + "uuid": "56666738-0f9a-4e38-9aac-c0fad00a5821", + "type": "Validator", + "title": "OpenSCAP", + "description": "OpenSCAP", + "props": [ + { + "name": "scanner_name", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "OpenSCAP" + }, + { + "name": "scanner_version", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "1.3.3" + }, + { + "name": "version", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP" + }, + { + "name": "severity", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "medium" + }, + { + "name": "weight", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "1.000000" + }, + { + "name": "benchmark_id", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "xccdf_org.ssgproject.content_benchmark_RHEL-7" + }, + { + "name": "benchmark_href", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "/content/ssg-rhel7-ds.xml" + }, + { + "name": "id", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "xccdf_org.open-scap_testresult_xccdf_org.ssgproject.content_profile_cis" + } + ], + "status": { + "state": "operational" + } + } + ], + "assessment-platforms": [ + { + "uuid": "56666738-0f9a-4e38-9aac-c0fad00a5821" + } + ] + } + }, + "reviewed-controls": { + "control-selections": [ + {} + ] + }, + "observations": [ + { + "uuid": "56666738-0f9a-4e38-9aac-c0fad00a5821", + "description": "xccdf_org.ssgproject.content_rule_prefer_64bit_os", + "props": [ + { + "name": "idref", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "xccdf_org.ssgproject.content_rule_prefer_64bit_os" + }, + { + "name": "result", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "notselected" + } + ], + "methods": [ + "TEST-AUTOMATED" + ], + "subjects": [ + { + "subject-uuid": "56666738-0f9a-4e38-9aac-c0fad00a5821", + "type": "inventory-item" + } + ], + "collected": "2023-11-30T23:00:03+00:00" + }, + { + "uuid": "56666738-0f9a-4e38-9aac-c0fad00a5821", + "description": "xccdf_org.ssgproject.content_rule_disable_prelink", + "props": [ + { + "name": "idref", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "xccdf_org.ssgproject.content_rule_disable_prelink" + }, + { + "name": "result", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "pass" + } + ], + "methods": [ + "TEST-AUTOMATED" + ], + "subjects": [ + { + "subject-uuid": "56666738-0f9a-4e38-9aac-c0fad00a5821", + "type": "inventory-item" + } + ], + "collected": "2023-11-30T23:00:03+00:00" + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/data/tasks/xccdf/output-oscap-results/results.oscal.json b/tests/data/tasks/xccdf/output-oscap-results/results.oscal.json new file mode 100644 index 000000000..5047ece39 --- /dev/null +++ b/tests/data/tasks/xccdf/output-oscap-results/results.oscal.json @@ -0,0 +1,165 @@ +{ + "results": [ + { + "uuid": "56666738-0f9a-4e38-9aac-c0fad00a5821", + "title": "XCCDF", + "description": "XCCDF Scan Results", + "start": "2021-06-08T02:35:55+00:00", + "end": "2021-06-08T02:35:55+00:00", + "local-definitions": { + "components": [ + { + "uuid": "56666738-0f9a-4e38-9aac-c0fad00a5821", + "type": "Service", + "title": "rhel7", + "description": "rhel7", + "status": { + "state": "operational" + } + } + ], + "inventory-items": [ + { + "uuid": "56666738-0f9a-4e38-9aac-c0fad00a5821", + "description": "inventory", + "props": [ + { + "name": "target", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "kube-c18ler8d06m877hrn7jg-roks8-default-00000319.iks.mycorp" + }, + { + "name": "target_type", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "rhel7" + } + ], + "implemented-components": [ + { + "component-uuid": "56666738-0f9a-4e38-9aac-c0fad00a5821" + } + ] + } + ], + "assessment-assets": { + "components": [ + { + "uuid": "56666738-0f9a-4e38-9aac-c0fad00a5821", + "type": "Validator", + "title": "OpenSCAP", + "description": "OpenSCAP", + "props": [ + { + "name": "scanner_name", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "OpenSCAP" + }, + { + "name": "scanner_version", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "1.3.3" + }, + { + "name": "version", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP" + }, + { + "name": "severity", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "medium" + }, + { + "name": "weight", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "1.000000" + }, + { + "name": "benchmark_id", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "xccdf_org.ssgproject.content_benchmark_RHEL-7" + }, + { + "name": "benchmark_href", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "/content/ssg-rhel7-ds.xml" + }, + { + "name": "id", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "xccdf_org.open-scap_testresult_xccdf_org.ssgproject.content_profile_cis" + } + ], + "status": { + "state": "operational" + } + } + ], + "assessment-platforms": [ + { + "uuid": "56666738-0f9a-4e38-9aac-c0fad00a5821" + } + ] + } + }, + "reviewed-controls": { + "control-selections": [ + {} + ] + }, + "observations": [ + { + "uuid": "56666738-0f9a-4e38-9aac-c0fad00a5821", + "description": "xccdf_org.ssgproject.content_rule_prefer_64bit_os", + "props": [ + { + "name": "idref", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "xccdf_org.ssgproject.content_rule_prefer_64bit_os" + }, + { + "name": "result", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "notselected" + } + ], + "methods": [ + "TEST-AUTOMATED" + ], + "subjects": [ + { + "subject-uuid": "56666738-0f9a-4e38-9aac-c0fad00a5821", + "type": "inventory-item" + } + ], + "collected": "2023-11-30T23:00:03+00:00" + }, + { + "uuid": "56666738-0f9a-4e38-9aac-c0fad00a5821", + "description": "xccdf_org.ssgproject.content_rule_disable_prelink", + "props": [ + { + "name": "idref", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "xccdf_org.ssgproject.content_rule_disable_prelink" + }, + { + "name": "result", + "ns": "https://ibm.github.io/compliance-trestle/schemas/oscal/ar/OpenSCAP", + "value": "pass" + } + ], + "methods": [ + "TEST-AUTOMATED" + ], + "subjects": [ + { + "subject-uuid": "56666738-0f9a-4e38-9aac-c0fad00a5821", + "type": "inventory-item" + } + ], + "collected": "2023-11-30T23:00:03+00:00" + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/data/tasks/xccdf/test-xccdf-result-to-oscal-ar-input-oscap-arf-results.config b/tests/data/tasks/xccdf/test-xccdf-result-to-oscal-ar-input-oscap-arf-results.config new file mode 100644 index 000000000..6bc4d66f6 --- /dev/null +++ b/tests/data/tasks/xccdf/test-xccdf-result-to-oscal-ar-input-oscap-arf-results.config @@ -0,0 +1,4 @@ +[task.xccdf-result-to-oscal-ar] +input-dir = tests/data/tasks/xccdf/input-oscap-arf-results +output-dir = tests/data/tasks/xccdf/output-oscap-arf-results +output-overwrite = true diff --git a/tests/data/tasks/xccdf/test-xccdf-result-to-oscal-ar-input-oscap-results.config b/tests/data/tasks/xccdf/test-xccdf-result-to-oscal-ar-input-oscap-results.config new file mode 100644 index 000000000..6c2b63668 --- /dev/null +++ b/tests/data/tasks/xccdf/test-xccdf-result-to-oscal-ar-input-oscap-results.config @@ -0,0 +1,4 @@ +[task.xccdf-result-to-oscal-ar] +input-dir = tests/data/tasks/xccdf/input-oscap-results +output-dir = tests/data/tasks/xccdf/output-oscap-results +output-overwrite = true diff --git a/tests/trestle/tasks/xccdf_result_to_oscal_ar_test.py b/tests/trestle/tasks/xccdf_result_to_oscal_ar_test.py index 9d7c87018..5bb823654 100644 --- a/tests/trestle/tasks/xccdf_result_to_oscal_ar_test.py +++ b/tests/trestle/tasks/xccdf_result_to_oscal_ar_test.py @@ -48,6 +48,8 @@ def uuid_mock2(self): cf06 = 'tests/data/tasks/xccdf/test-xccdf-result-to-oscal-ar-xml-rhel7.config' cf07 = 'tests/data/tasks/xccdf/test-xccdf-result-to-oscal-ar-xml-ocp4.config' cf08 = 'tests/data/tasks/xccdf/test-xccdf-result-to-oscal-ar-configmaps.config' +cf09 = 'tests/data/tasks/xccdf/test-xccdf-result-to-oscal-ar-input-oscap-results.config' +cf10 = 'tests/data/tasks/xccdf/test-xccdf-result-to-oscal-ar-input-oscap-arf-results.config' def setup_config(path: str): @@ -442,3 +444,47 @@ def test_xccdf_execute_input_configmaps(tmp_path, monkeypatch: MonkeyPatch): f_produced = d_produced / fn result = text_files_equal(f_expected, f_produced) assert result + + +def test_xccdf_execute_input_oscap_result(tmp_path, monkeypatch: MonkeyPatch): + """Test OpenSCAP XCCDF to OSCAL AR.""" + monkeybusiness = MonkeyBusiness() + monkeypatch.setattr(uuid, 'uuid4', monkeybusiness.uuid_mock1) + xccdf.XccdfTransformer.set_timestamp('2023-11-30T23:00:03+00:00') + config = setup_config(cf09) + section = config['task.xccdf-result-to-oscal-ar'] + d_expected = pathlib.Path(section['output-dir']) + d_produced = tmp_path + section['output-dir'] = str(d_produced) + tgt = xccdf_result_to_oscal_ar.XccdfResultToOscalAR(section) + retval = tgt.execute() + assert retval == TaskOutcome.SUCCESS + list_dir = os.listdir(d_produced) + assert len(list_dir) == 1 + for fn in list_dir: + f_expected = d_expected / fn + f_produced = d_produced / fn + result = text_files_equal(f_expected, f_produced) + assert result + + +def test_xccdf_execute_input_oscap_arf_result(tmp_path, monkeypatch: MonkeyPatch): + """Test OpenSCAP ARF to OSCAL AR.""" + monkeybusiness = MonkeyBusiness() + monkeypatch.setattr(uuid, 'uuid4', monkeybusiness.uuid_mock1) + xccdf.XccdfTransformer.set_timestamp('2023-11-30T23:00:03+00:00') + config = setup_config(cf10) + section = config['task.xccdf-result-to-oscal-ar'] + d_expected = pathlib.Path(section['output-dir']) + d_produced = tmp_path + section['output-dir'] = str(d_produced) + tgt = xccdf_result_to_oscal_ar.XccdfResultToOscalAR(section) + retval = tgt.execute() + assert retval == TaskOutcome.SUCCESS + list_dir = os.listdir(d_produced) + assert len(list_dir) == 1 + for fn in list_dir: + f_expected = d_expected / fn + f_produced = d_produced / fn + result = text_files_equal(f_expected, f_produced) + assert result diff --git a/trestle/transforms/implementations/xccdf.py b/trestle/transforms/implementations/xccdf.py index fa4fbf3f6..5afedfece 100644 --- a/trestle/transforms/implementations/xccdf.py +++ b/trestle/transforms/implementations/xccdf.py @@ -199,7 +199,7 @@ def inventory_key(self): @property def ns(self): """Derive namespace.""" - return f'https://ibm.github.io/compliance-trestle/schemas/oscal/ar/{self.scanner_name}' + return f'https://ibm.github.io/compliance-trestle/schemas/oscal/ar/{self.scanner_name}' # noqa: E231 class _XccdfResult(): @@ -317,9 +317,14 @@ def _get_result(self, lev1: Element) -> str: def _parse_xml(self) -> Iterator[RuleUse]: """Parse the stringified XML.""" + ns = { + 'checklist12': 'http://checklists.nist.gov/xccdf/1.2', + } results = self.xccdf_xml root = ElementTree.fromstring(results, forbid_dtd=True) version = self._get_version(root) + if _remove_namespace(root.tag) != 'TestResult': + root = root.find('.//checklist12:TestResult', ns) id_ = self._get_id(root) target = self._get_target(root) target_type = self._get_target_type(root)