diff --git a/application/tests/ccmv4_parser_test.py b/application/tests/ccmv4_parser_test.py new file mode 100644 index 00000000..942f5922 --- /dev/null +++ b/application/tests/ccmv4_parser_test.py @@ -0,0 +1,90 @@ +from pathlib import Path +from tempfile import mkdtemp, mkstemp +import zipfile +from application.utils import spreadsheet as sheet_utils +from application.defs import cre_defs as defs +import unittest +from application import create_app, sqla # type: ignore +from application.database import db +from unittest.mock import patch + +from application.utils.external_project_parsers.parsers import ccmv4 +from application.prompt_client import prompt_client + + +class TestCloudNativeSecurityControlsParser(unittest.TestCase): + def tearDown(self) -> None: + self.app_context.pop() + + def setUp(self) -> None: + self.app = create_app(mode="test") + self.app_context = self.app.app_context() + self.app_context.push() + sqla.create_all() + self.collection = db.Node_collection() + + @patch.object(sheet_utils, "read_spreadsheet") + def test_parse( + self, + mock_read_spreadsheet, + ) -> None: + + for i in range(1, 4): + dbcre = self.collection.add_cre( + cre=defs.CRE(id=f"123-{i}", name=f"CRE-123-{i}") + ) + dbnode = self.collection.add_node( + defs.Standard( + name="NIST 800-53 v5", + section=f"nist80053-{i}{i}", + sectionID=f"nist80053-{i}{i}", + ) + ) + self.collection.add_link(dbcre, dbnode) + mock_read_spreadsheet.return_value = self.csv + + nodes = ccmv4.CloudControlsMatrix().parse( + cache=self.collection, + ph=prompt_client.PromptHandler(database=self.collection), + ) + + expected = [ + defs.Standard( + links=[ + defs.Link(document=defs.CRE(name="CRE-123-1", id="123-1")), + defs.Link(document=defs.CRE(name="CRE-123-2", id="123-2")), + ], + name="Cloud Native Security Controls", + section="asdf:123", + sectionID=123, + version="v4.0", + ), + defs.Standard( + links=[ + defs.Link(document=defs.CRE(name="CRE-123-3", id="123-4")), + defs.Link(document=defs.CRE(name="CRE-123-4", id="123-3")), + ], + name="Cloud Native Security Controls", + section="asdf:124", + sectionID=124, + version="v4.0", + ), + ] + self.assertEqual(len(nodes), 2) + self.assertCountEqual(nodes[0].todict(), expected[0].todict()) + self.assertCountEqual(nodes[1].todict(), expected[1].todict()) + + csv = { + "0.ccmv4": [ + { + "Control ID": 123, + "Control Title": "", + "NIST 800-53 rev 5": "nist80053-11\nnist80053-22", + }, + { + "Control ID": 124, + "Control Title": "asdf2", + "NIST 800-53 rev 5": "nist80053-33\nnist80053-44", + }, + ] + } diff --git a/application/utils/external_project_parsers/parsers/ccmv4.py b/application/utils/external_project_parsers/parsers/ccmv4.py index 551c4fda..9f7b00ee 100644 --- a/application/utils/external_project_parsers/parsers/ccmv4.py +++ b/application/utils/external_project_parsers/parsers/ccmv4.py @@ -33,7 +33,7 @@ def make_nist_map(self, cache: db.Node_collection): return nist_map def get_ccm_file(self) -> Dict[str, Any]: - return sheet_utils.readSpreadsheet( + return sheet_utils.read_spreadsheet( alias="", url="https://docs.google.com/spreadsheets/d/1QDzQy0wt1blGjehyXS3uaHh7k5OOR12AWgAA1DeACyc", ) @@ -54,8 +54,9 @@ def parse(self, cache: db.Node_collection, ph: prompt_client.PromptHandler): ccm = defs.Standard( name=self.name, - section=f'{ccm_mapping.pop("Control ID")}:{ccm_mapping.pop("Control Title")}', + section=f'{ccm_mapping.get("Control ID")}:{ccm_mapping.pop("Control Title")}', subsection="", + sectionID=ccm_mapping.pop("Control ID"), version="v4.0", hyperlink="", )