From 4ae731065837e03745b6f0750dedc4c494114b8a Mon Sep 17 00:00:00 2001 From: eric-intuitem <71850047+eric-intuitem@users.noreply.github.com> Date: Sun, 11 Feb 2024 13:04:07 +0100 Subject: [PATCH 1/2] Add tools for library generation --- tools/README.md | 82 ++++++++++ tools/cmmc-v2.xlsx | Bin 0 -> 29927 bytes tools/convert_framework.py | 312 +++++++++++++++++++++++++++++++++++++ tools/nist-csf-1.1-en.xlsx | Bin 0 -> 25686 bytes 4 files changed, 394 insertions(+) create mode 100644 tools/README.md create mode 100644 tools/cmmc-v2.xlsx create mode 100644 tools/convert_framework.py create mode 100644 tools/nist-csf-1.1-en.xlsx diff --git a/tools/README.md b/tools/README.md new file mode 100644 index 000000000..cb1dad486 --- /dev/null +++ b/tools/README.md @@ -0,0 +1,82 @@ +# Library workbench + +The convert-framework.py script can be used to transform an Excel file to a CISO Assitant library. + +Have a look to the given examples. + +## Usage + +To launch it, open a shell in a command line, and type: + +```bash +python convert-framework.py your_library_file.xlsx +``` + +This will produce a file name your_library_file.yaml + +## Format of Excel files + +This is documented in the header of the python file. Please note the notion of level is not yet implemented in CISO Assistant. + +``` +Conventions: + | means a cell separation, <> means empty cell + The first tab shall be named "library_content" and contain the description of the library in the other tabs + library_urn | + library_version | + library_locale | + library_ref_id | + library_name | + library_description | + library_copyright | + library_provider | + library_packager | + library_dependencies | + framework_ref_id | + framework_name | + framework_description | + security_function_base_urn | | id + threat_base_urn | | id + tab | | levels + tab | | requirements | + tab | | threats | + tab | | security_functions | + + + For levels: + A "levels" tab enumerates levels. If it exists, it shall be placed before the correponding framework. + The first line is a header, with the following possible fields (* for required): + - level(*) + - ref_id(*) + - name + - description + - annotation + For requirements: + If no section_name is given, no upper group is defined, else an upper group (depth 0) with the section name is used. + The first line is a header, with the following possible fields (* for required): + - assessable(*): non-empty (e.g x) if this is a requirement + - depth(*): 1/2/3/... to describe the tree + - ref_id + - name + - description + - level + - maturity + - threats + - security_functions + - annotation + The normal tree order shall be respected + If multiple threats or security_function are given for a requirements, they shall be separated by blank or comma. + They shall be prefixed by the id of the corresponding base_urn and a semicolumn. + For security functions: + The first line is a header, with the following possible fields (* for required): + - depth(*): 1/2/3/.. for requirement groups, empty for a requirement. + - ref_id(*) + - name + - description + - category (policy/process/techncial/physical). + - annotation + A library has a single locale. Translated libraries have the same urns, they are merged during import. + Dependencies are given as a comma or blank separated list of urns. +''' +``` \ No newline at end of file diff --git a/tools/cmmc-v2.xlsx b/tools/cmmc-v2.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..17462d594ec4903a5d61a03575f5fef8f816b86d GIT binary patch literal 29927 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 means empty cell + The first tab shall be named "library_content" and contain the description of the library in the other tabs + library_urn | + library_version | + library_locale | + library_ref_id | + library_name | + library_description | + library_copyright | + library_provider | + library_packager | + library_dependencies | + framework_ref_id | + framework_name | + framework_description | + security_function_base_urn | | id + threat_base_urn | | id + tab | | levels + tab | | requirements | + tab | | threats | + tab | | security_functions | + + + For levels: + A "levels" tab enumerates levels. If it exists, it shall be placed before the correponding framework. + The first line is a header, with the following possible fields (* for required): + - level(*) + - ref_id(*) + - name + - description + - annotation + For requirements: + If no section_name is given, no upper group is defined, else an upper group (depth 0) with the section name is used. + The first line is a header, with the following possible fields (* for required): + - assessable(*): non-empty (e.g x) if this is a requirement + - depth(*): 1/2/3/... to describe the tree + - ref_id + - name + - description + - level + - maturity + - threats + - security_functions + - annotation + The normal tree order shall be respected + If multiple threats or security_function are given for a requirements, they shall be separated by blank or comma. + They shall be prefixed by the id of the corresponding base_urn and a semicolumn. + For security functions: + The first line is a header, with the following possible fields (* for required): + - depth(*): 1/2/3/.. for requirement groups, empty for a requirement. + - ref_id(*) + - name + - description + - category (policy/process/techncial/physical). + - annotation + A library has a single locale. Translated libraries have the same urns, they are merged during import. + Dependencies are given as a comma or blank separated list of urns. +''' + +import openpyxl +import sys +import re +import yaml +from pprint import pprint +from collections import defaultdict + +LIBRARY_VARS = ('library_urn', 'library_version', 'library_locale', 'library_ref_id', 'library_name', 'library_description', + 'framework_urn', 'framework_ref_id', 'framework_name', 'framework_description', 'library_copyright', + 'library_provider', 'library_packager', 'security_function_base_urn', 'threat_base_urn', 'library_dependencies', 'tab') +library_vars = {} +library_vars_dict = defaultdict(dict) +library_vars_dict_reverse = defaultdict(dict) +library_vars_dict_arg = defaultdict(dict) + +if len(sys.argv) <= 1: + print("missing input file parameter") + exit() +input_file_name = sys.argv[1] +ref_name = re.sub(r"\.\w+$", "", input_file_name).lower() +output_file_name = ref_name + ".yaml" + +print("parsing", input_file_name) + +# Define variable to load the dataframe +dataframe = openpyxl.load_workbook(input_file_name) + +requirement_nodes = [] +security_functions = [] +threats = [] + +def error(message): + print("Error:", message) + exit(1) + + +def read_header(row): + i = 0 + header = {} + for v in row: + v = str(v.value).lower() + header[v] = i + i += 1 + return header + + +for tab in dataframe: + print("parsing tab", tab.title) + title = tab.title + if title.lower() == "library_content": + print("...processing content") + for row in tab: + if any([r.value for r in row]): + (v1, v2, v3) = (r.value for r in row[0:3]) + v4 = row[3].value if len(row) > 3 else None + if v1 in LIBRARY_VARS: + library_vars[v1] = v2 + library_vars_dict[v1][str(v2)] = v3 + library_vars_dict_reverse[v1][str(v3)] = v2 + library_vars_dict_arg[v1][v2] = v4 + elif title not in library_vars_dict['tab']: + print(f"Ignored tab: {title}") + elif library_vars_dict['tab'][title] == 'requirements': + print("...processing requirements") + root_nodes_urn = re.sub('framework', 'req_node', library_vars['framework_urn']) + current_node_urn = None + current_depth = 0 + parent_urn = None + parent_for_depth = {} + section = library_vars_dict_arg['tab'][title] + if section: + section_id = section.lower().replace(' ', '-') + current_node_urn = f"{root_nodes_urn}:{section_id}" + parent_for_depth[1]=current_node_urn + requirement_nodes.append({"urn": current_node_urn, "name": section, "assessable": False}) + is_header = True + counter = 0 + for row in tab: + counter += 1 + if is_header: + header = read_header(row) + is_header=False + assert("assessable" in header) + assert("depth" in header) + assert("ref_id" in header) + elif any([c.value for c in row]): + assessable = bool(row[header['assessable']].value) + depth = row[header['depth']].value + ref_id = str(row[header['ref_id']].value).strip() if row[header['ref_id']].value else None + name = row[header['name']].value if 'name' in header else None + description = row[header['description']].value if 'description' in header else None + annotation = row[header['annotation']].value if 'annotation' in header else None + level = row[header['level']].value if 'level' in header else None + maturity = row[header['maturity']].value if 'maturity' in header else None + ref_id_urn = ref_id.lower().replace(' ', '-') if ref_id else \ + name.lower().replace(' ', '-') if name else f"node{counter}" + urn = f"{root_nodes_urn}:{ref_id_urn}" + if depth == current_depth + 1: + parent_for_depth[depth]=current_node_urn + parent_urn = parent_for_depth[depth] + elif depth <= current_depth: + pass + else: + error(f"wrong level in requirement (tab {title})") + current_node_urn = urn + parent_urn = parent_for_depth[depth] + current_depth = depth + req_node = {"urn": urn, "assessable": assessable, "depth": depth} + if parent_urn: + req_node['parent_urn'] = parent_urn + if ref_id: + req_node["ref_id"] = ref_id + if name: + req_node["name"] = name + if description: + req_node["description"] = description + if annotation: + req_node["annotation"] = annotation + if maturity: + req_node["maturity"] = maturity + threats = row[header['threats']].value if 'threats' in header else None + security_functions = row[header['security_functions']].value if 'security_functions' in header else None + threat_urns = [] + function_urns = [] + if threats: + for element in re.split(r'[\s,]+', threats): + parts = re.split(r':', element) + prefix = parts.pop(0) + part_name = ':'.join(parts) + urn_prefix = library_vars_dict_reverse['security_function_base_urn'][prefix] + threat_urns.append(f"{urn_prefix}{part_name}") + if security_functions: + for element in re.split(r'[\s,]+', security_functions): + parts = re.split(r':', element) + prefix = parts.pop(0) + part_name = ':'.join(parts) + urn_prefix = library_vars_dict_reverse['security_function_base_urn'][prefix] + function_urns.append(f"{urn_prefix}{part_name}") + if threat_urns: + req_node["threats"] = threat_urns + if function_urns: + req_node["security_functions"] = function_urns + requirement_nodes.append(req_node) + else: + pass + #print("empty row") + elif library_vars_dict['tab'][title] == 'security_functions': + print("...processing security functions") + current_function = {} + is_header = True + security_functions_base_urn = library_vars['security_function_base_urn'] + for row in tab: + if is_header: + header = read_header(row) + is_header=False + assert("ref_id" in header) + elif any([c.value for c in row]): + ref_id = str(row[header['ref_id']].value).strip() if row[header['ref_id']].value else None + name = row[header['name']].value if 'name' in header else None + description = row[header['description']].value if 'description' in header else None + category = row[header['category']].value if 'category' in header else None + annotation = row[header['annotation']].value if 'annotation' in header else None + ref_id_urn = ref_id.lower().replace(' ', '-') + current_function = {} + current_function['urn'] = f"{security_functions_base_urn}:{ref_id_urn}" + current_function['ref_id'] = ref_id + if name: + current_function['name'] = name + if category: + current_function['category'] = category + if description: + current_function['description'] = description + if annotation: + current_function['annotation'] = annotation + security_functions.append(current_function) + elif library_vars_dict['tab'][title] == 'threats': + print("...processing threats") + current_threat = {} + is_header = True + threat_base_urn = library_vars['threat_base_urn'] + for row in tab: + if is_header: + header = read_header(row) + print(header) + is_header=False + assert("ref_id" in header) + elif any([c.value for c in row]): + ref_id = str(row[header['ref_id']].value).strip() if row[header['ref_id']].value else None + name = row[header['name']].value if 'name' in header else None + description = row[header['description']].value if 'description' in header else None + annotation = row[header['annotation']].value if 'annotation' in header else None + ref_id_urn = ref_id.lower().replace(' ', '-') + current_threat = {} + current_threat['urn'] = f"{threat_base_urn}:{ref_id_urn}" + current_threat['ref_id'] = ref_id + if name: + current_threat['name'] = name + if description: + current_threat['description'] = description + if annotation: + current_threat['annotation'] = annotation + threats.append(current_threat) + + +#pprint(requirement_groups) +#pprint(requirements) +##pprint(security_functions) +##pprint(threats) + +has_framework = 'requirements' in [library_vars_dict['tab'][x] for x in library_vars_dict['tab']] +has_security_functions = 'security_functions' in [library_vars_dict['tab'][x] for x in library_vars_dict['tab']] +has_threats = 'threats' in [library_vars_dict['tab'][x] for x in library_vars_dict['tab']] + +library = { + 'urn': library_vars['library_urn'], + 'locale': library_vars['library_locale'], + 'ref_id': library_vars['library_ref_id'], + 'name': library_vars['library_name'], + 'description': library_vars['library_description'], + 'copyright': library_vars['library_copyright'], + 'version': library_vars['library_version'], + 'provider': library_vars['library_provider'], + 'packager': library_vars['library_packager'], +} + +if 'library_dependencies' in library_vars: + dependencies = [x for x in re.split(r'[\s,]+', library_vars['library_dependencies'])] + library['dependencies'] = dependencies + +library['objects'] = {} + +if has_framework: + library['objects']['framework'] = { + 'urn': library_vars['framework_urn'], + 'ref_id': library_vars['framework_ref_id'], + 'name': library_vars['framework_name'], + 'description': library_vars['framework_description'], + 'requirement_nodes': requirement_nodes + } + +if has_security_functions: + library['objects']['security_functions'] = security_functions + +if has_threats: + library['objects']['threats'] = threats + +print("generating", output_file_name) +with open(output_file_name, 'w', encoding='utf8') as file: + yaml.dump(library, file, sort_keys=False) diff --git a/tools/nist-csf-1.1-en.xlsx b/tools/nist-csf-1.1-en.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..4b88d346b6a59b1c5c0e1314adeda9274ebf123f GIT binary patch literal 25686 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 literal 0 HcmV?d00001 From 47123323ce7be9d853f08ec0837348604dfbf2bf Mon Sep 17 00:00:00 2001 From: eric-intuitem <71850047+eric-intuitem@users.noreply.github.com> Date: Sun, 11 Feb 2024 13:04:34 +0100 Subject: [PATCH 2/2] Update views.py remove forgotten debug line --- backend/core/views.py | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/core/views.py b/backend/core/views.py index dce1894ec..2706cd9c4 100644 --- a/backend/core/views.py +++ b/backend/core/views.py @@ -348,7 +348,6 @@ def quality_check_detail(self, request, pk): @action(detail=True, name="Get treatment plan CSV") def treatment_plan_csv(self, request, pk): - print("coucou") (object_ids_view, _, _) = RoleAssignment.get_accessible_object_ids( Folder.get_root_folder(), request.user, RiskAssessment )