From 6de26a1958f2ec9f85d68018ef75a94bf78786b8 Mon Sep 17 00:00:00 2001 From: Jennifer Power Date: Mon, 25 Sep 2023 12:22:00 -0400 Subject: [PATCH] fix: allows inheritance info to be removed when component is unmapped Signed-off-by: Jennifer Power --- tests/trestle/core/crm/exports_reader_test.py | 37 ++++++++++++++++++- trestle/core/crm/export_reader.py | 26 +++++++------ 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/tests/trestle/core/crm/exports_reader_test.py b/tests/trestle/core/crm/exports_reader_test.py index b4e397ca7..7a33929ce 100644 --- a/tests/trestle/core/crm/exports_reader_test.py +++ b/tests/trestle/core/crm/exports_reader_test.py @@ -141,11 +141,13 @@ def test_read_inheritance_markdown_dir(tmp_trestle_dir: pathlib.Path) -> None: reader = exportreader.ExportReader(inheritance_path, orig_ssp) # type: ignore markdown_dict: exportreader.InheritanceViewDict = reader._read_inheritance_markdown_directory() - assert len(markdown_dict) == 2 + assert len(markdown_dict) == 3 assert 'ac-2' in markdown_dict assert len(markdown_dict['ac-2']) == 2 assert expected_appliance_uuid in markdown_dict['ac-2'] + assert len(markdown_dict['ac-2.1']) == 0 + inheritance_info = markdown_dict['ac-2'][expected_appliance_uuid] assert inheritance_info[0][0].provided_uuid == '18ac4e2a-b5f2-46e4-94fa-cc84ab6fe114' @@ -166,6 +168,12 @@ def test_read_inheritance_markdown_dir_with_multiple_leveraged_components(tmp_tr leveraged_statement_names=['Access Control Appliance'] ) + unmapped_text = test_utils.generate_test_inheritance_md( + provided_uuid=example_provided_uuid, + responsibility_uuid=example_responsibility_uuid, + leveraged_statement_names=[const.REPLACE_ME] + ) + this_system_dir = inheritance_path.joinpath('This System') ac_2 = this_system_dir.joinpath('ac-2') ac_2.mkdir(parents=True) @@ -174,6 +182,13 @@ def test_read_inheritance_markdown_dir_with_multiple_leveraged_components(tmp_tr with open(file, 'w') as f: f.write(inheritance_text_2) + ac_2a = this_system_dir.joinpath('ac-2_smt.a') + ac_2a.mkdir(parents=True) + + file = ac_2a / f'{expected_appliance_uuid}.md' + with open(file, 'w') as f: + f.write(unmapped_text) + test_utils.load_from_json(tmp_trestle_dir, 'leveraging_ssp', leveraging_ssp, ossp.SystemSecurityPlan) orig_ssp, _ = ModelUtils.load_model_for_class( @@ -195,6 +210,16 @@ def test_read_inheritance_markdown_dir_with_multiple_leveraged_components(tmp_tr assert len(inheritance_info[0]) == 2 assert len(inheritance_info[1]) == 2 + assert 'ac-2_smt.a' in markdown_dict + assert len(markdown_dict['ac-2_smt.a']) == 2 + + assert expected_appliance_uuid in markdown_dict['ac-2_smt.a'] + inheritance_info = markdown_dict['ac-2_smt.a'][expected_appliance_uuid] + + # Only leveraging from one component + assert len(inheritance_info[0]) == 1 + assert len(inheritance_info[1]) == 1 + def test_update_type_with_by_comp(sample_implemented_requirement: ossp.ImplementedRequirement) -> None: """Test update type with by component.""" @@ -226,3 +251,13 @@ def test_update_type_with_by_comp(sample_implemented_requirement: ossp.Implement assert new_by_comp.component_uuid == test_comp_uuid assert new_by_comp.satisfied is not None assert new_by_comp.satisfied[0].description == 'Updated Description' + + # Test removing the existing inheritance info + test_by_comp_dict: exportreader.ByComponentDict = {} + reader._update_type_with_by_comp(sample_implemented_requirement, test_by_comp_dict) + + new_by_comp = sample_implemented_requirement.by_components[1] # type: ignore + + assert new_by_comp.component_uuid == test_comp_uuid + assert new_by_comp.satisfied is None + assert new_by_comp.inherited is None diff --git a/trestle/core/crm/export_reader.py b/trestle/core/crm/export_reader.py index ae7d827b0..97b9f62bf 100644 --- a/trestle/core/crm/export_reader.py +++ b/trestle/core/crm/export_reader.py @@ -77,8 +77,9 @@ def read_exports_from_markdown(self) -> ossp.SystemSecurityPlan: # Process remaining markdown information that was not in the implemented requirements for control_id, by_comp_dict in markdown_dict.items(): - logging.debug(f'Adding control mapping {control_id} to implemented requirements') - self._add_control_mappings_to_implemented_requirements(control_id, by_comp_dict) + if by_comp_dict: + logging.debug(f'Adding control mapping {control_id} to implemented requirements') + self._add_control_mappings_to_implemented_requirements(control_id, by_comp_dict) self._ssp.control_implementation.implemented_requirements = list(self._implemented_requirements.values()) return self._ssp @@ -124,17 +125,19 @@ def _update_type_with_by_comp(self, with_bycomp: TypeWithByComps, by_comp_dict: by_comp: ossp.ByComponent for by_comp in as_list(with_bycomp.by_components): + # If the by_component uuid exists in the by_comp_dict, then update it + # If not, clear the by_component inheritance information + comp_inheritance_info: Tuple[List[ossp.Inherited], List[ossp.Satisfied]] = ([], []) if by_comp.component_uuid in by_comp_dict: comp_inheritance_info = by_comp_dict[by_comp.component_uuid] - - bycomp_interface = ByComponentInterface(by_comp) - by_comp = bycomp_interface.reconcile_inheritance_by_component( - comp_inheritance_info[0], comp_inheritance_info[1] - ) - # Delete the entry from the by_comp_dict once processed to avoid duplicates del by_comp_dict[by_comp.component_uuid] + bycomp_interface = ByComponentInterface(by_comp) + by_comp = bycomp_interface.reconcile_inheritance_by_component( + comp_inheritance_info[0], comp_inheritance_info[1] + ) + new_by_comp.append(by_comp) # Add any new by_components that were not in the original statement @@ -224,7 +227,8 @@ def _read_inheritance_markdown_directory(self) -> InheritanceViewDict: satisfied.append(leveraged_info.satisfied) by_comp_dict[comp_uuid] = (inherited, satisfied) - # If there is information in the by_component dictionary, then update the markdown dictionary - if by_comp_dict: - markdown_dict[control_dir] = by_comp_dict + + # Add the by_component dictionary to the markdown dictionary for the control directory + markdown_dict[control_dir] = by_comp_dict + return markdown_dict