diff --git a/tools/nist-nice/gen_nice.py b/tools/nist-nice/gen_nice.py index b6acec9..065f9b8 100644 --- a/tools/nist-nice/gen_nice.py +++ b/tools/nist-nice/gen_nice.py @@ -3,7 +3,7 @@ # # A simple convertor script to generate galaxies from the MITRE NICE framework # https://niccs.cisa.gov/workforce-development/nice-framework -# Copyright (C) 2024 Jean-Louis Huynen +# Copyright (C) 2024 Jean-Louis Huynen # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -26,8 +26,12 @@ import csv # uuidv4 generated to be concatenated in v5: 1d348708-7cd8-4854-9eac-f93c0dab8cdd -parser = argparse.ArgumentParser(description='Create/update the NICE Framework Taxonomies based on the NICE Framework json file.') -parser.add_argument("-p", "--path", required=True, help="Path to the NICE Framework json file") +parser = argparse.ArgumentParser( + description='Create/update the NICE Framework Taxonomies based on the NICE Framework json file.' +) +parser.add_argument( + "-p", "--path", required=True, help="Path to the NICE Framework json file" +) args = parser.parse_args() @@ -39,11 +43,13 @@ if not os.path.exists(os.path.join(os.path.dirname(__file__), "cybersecurity-opm # create OPM description from OPM csv file as this data is missing from the NICE framework -with open(os.path.join(os.path.dirname(__file__), "cybersecurity-opm.csv"), newline='') as csvfile: +with open( + os.path.join(os.path.dirname(__file__), "cybersecurity-opm.csv"), newline='' +) as csvfile: opm = {} reader = csv.reader(csvfile, delimiter=',', quotechar="\"") for row in reader: - opm[row[0]] = row[1] + opm[row[0]] = row[1] g = ["work_role", "skill", "task", "knowledge", "competency_area", "opm_code"] @@ -56,7 +62,7 @@ galaxies = { "description": "Work roles based on the NIST NICE framework", "uuid": "10a2e9d7-781b-4ff4-bb3e-f0003108fe41", "version": 1, - "icon": 'user' + "icon": 'user', }, "skill": { "namespace": "nist-nice", @@ -65,7 +71,7 @@ galaxies = { "description": "Skills based on the NIST NICE framework", "uuid": "96c5b9e7-5e70-479e-990c-8f1dea06c520", "version": 1, - "icon": 'user' + "icon": 'user', }, "task": { "namespace": "nist-nice", @@ -74,39 +80,39 @@ galaxies = { "description": "Tasks based on the NIST NICE framework", "uuid": "98ba1aa3-d171-49e4-adf1-b7fb5e26a942", "version": 1, - "icon": 'user' + "icon": 'user', }, - "knowledge": { + "knowledge": { "namespace": "nist-nice", "type": "nice-framework-knowledges", "name": "NICE Knowledges", "description": "Knowledge based on the NIST NICE framework", "uuid": "de7e23f2-cef8-44ed-b209-b584f7da58a2", "version": 1, - "icon": 'user' + "icon": 'user', }, - "competency_area": { + "competency_area": { "namespace": "nist-nice", "type": "nice-framework-competency_areas", "name": "NICE Competency areas", "description": "Competency areas based on the NIST NICE framework", "uuid": "e78357aa-01bd-4635-99a1-8eb860fa3bd5", "version": 1, - "icon": 'user' + "icon": 'user', }, - "opm_code": { + "opm_code": { "namespace": "nist-nice", "type": "nice-framework-opm_codes", "name": "OPM codes in cybersecurity", "description": "Office of Personnel Management codes in cybersecurity", "uuid": "2c56dfbc-82a5-48db-aea4-854ede951c65", "version": 1, - "icon": 'user' - } + "icon": 'user', + }, } clusters = { - "work_role": { + "work_role": { 'authors': ["NIST", "Jean-Louis Huynen"], 'category': 'workforce', "type": "nice-framework-work_roles", @@ -115,9 +121,9 @@ clusters = { "uuid": "f81819e1-326b-41a5-89dd-a40d73c5bbbf", 'source': '', 'values': [], - 'version': 1 + 'version': 1, }, - "skill": { + "skill": { 'authors': ["NIST", "Jean-Louis Huynen"], 'category': 'workforce', "type": "nice-framework-skills", @@ -126,9 +132,9 @@ clusters = { "uuid": "2d330f93-fa49-4451-859a-aacc68c63110", 'source': '', 'values': [], - 'version': 1 + 'version': 1, }, - "task": { + "task": { 'authors': ["NIST", "Jean-Louis Huynen"], 'category': 'workforce', "type": "nice-framework-tasks", @@ -137,9 +143,9 @@ clusters = { "uuid": "6bcf78de-a3fb-4636-90bc-95a86817ad65", 'source': '', 'values': [], - 'version': 1 + 'version': 1, }, - "knowledge": { + "knowledge": { 'authors': ["NIST", "Jean-Louis Huynen"], 'category': 'workforce', "type": "nice-framework-knowledges", @@ -148,9 +154,9 @@ clusters = { "uuid": "796e3e82-ca9a-4749-8421-4810ed440755", 'source': '', 'values': [], - 'version': 1 + 'version': 1, }, - "competency_area": { + "competency_area": { 'authors': ["NIST", "Jean-Louis Huynen"], 'category': 'workforce', "type": "nice-framework-competency_areas", @@ -159,9 +165,9 @@ clusters = { "uuid": "91696bc7-ede9-4875-8814-768bd5c99c66", 'source': '', 'values': [], - 'version': 1 + 'version': 1, }, - "opm_code": { + "opm_code": { 'authors': ["OPM", "Jean-Louis Huynen"], 'category': 'workforce', "type": "nice-framework-opm_codes", @@ -170,19 +176,27 @@ clusters = { "uuid": "76772dae-0e98-4d96-8603-6993aea936d1", 'source': 'https://dw.opm.gov/datastandards/referenceData/2273/current', 'values': [], - 'version': 1 - } + 'version': 1, + }, } + def get_relationships(nice_data, external_id): relationships = [] for element in nice_data["response"]["elements"]["relationships"]: if element["source_element_identifier"] == external_id: - relationships.append({ - "dest-uuid": str(uuid.uuid5(uuid.UUID("1d348708-7cd8-4854-9eac-f93c0dab8cdd"), element["dest_element_identifier"])), - "type": "involves" - }) - + relationships.append( + { + "dest-uuid": str( + uuid.uuid5( + uuid.UUID("1d348708-7cd8-4854-9eac-f93c0dab8cdd"), + element["dest_element_identifier"], + ) + ), + "type": "involves", + } + ) + return relationships @@ -203,42 +217,73 @@ with open(args.path) as f: for element in nice_data["response"]["elements"]["elements"]: # Defining a uuidd v5 identifier - uuid_str = str(uuid.uuid5(uuid.UUID("1d348708-7cd8-4854-9eac-f93c0dab8cdd"),element["element_identifier"])) + uuid_str = str( + uuid.uuid5( + uuid.UUID("1d348708-7cd8-4854-9eac-f93c0dab8cdd"), + element["element_identifier"], + ) + ) # generating relationship relationships = get_relationships(nice_data, element["element_identifier"]) if relationships != []: - ctr_rel = ctr_rel + len(relationships) - + ctr_rel = ctr_rel + len(relationships) + # Adding values in corresponding cluster if element["element_type"] in g: if element["element_type"] == "opm_code": - clusters[element["element_type"]]["values"].append({ - "description": opm[element["element_identifier"]], - "uuid": uuid_str, - "value": f'{opm[element["element_identifier"]][0:150]} - {element["element_identifier"]}', - "related": relationships, - }) + clusters[element["element_type"]]["values"].append( + { + "description": opm[element["element_identifier"]], + "uuid": uuid_str, + "value": f'{opm[element["element_identifier"]][0:150]} - {element["element_identifier"]}', + "related": relationships, + } + ) else: - clusters[element["element_type"]]["values"].append({ - "description": element["text"], - "uuid": uuid_str, - "value": element["element_identifier"], - "value": f'{element["text"][0:150]} - {element["element_identifier"]}', - "related": relationships - }) + clusters[element["element_type"]]["values"].append( + { + "description": element["text"], + "uuid": uuid_str, + "value": element["element_identifier"], + "value": f'{element["text"][0:150]} - {element["element_identifier"]}', + "related": relationships, + } + ) # Writing galaxies and clusters for e in g: - with open(os.path.join(os.path.dirname(__file__), '..', '..', 'galaxies', f'nice-framework-{e}s.json'), 'w') as f: + with open( + os.path.join( + os.path.dirname(__file__), + '..', + '..', + 'galaxies', + f'nice-framework-{e}s.json', + ), + 'w', + ) as f: json.dump(galaxies[e], f, indent=2, sort_keys=True, ensure_ascii=False) - f.write('\n') # only needed for the beauty and to be compliant with jq_all_the_things + f.write( + '\n' + ) # only needed for the beauty and to be compliant with jq_all_the_things - with open(os.path.join(os.path.dirname(__file__), '..', '..', 'clusters', f'nice-framework-{e}s.json'), 'w') as f: + with open( + os.path.join( + os.path.dirname(__file__), + '..', + '..', + 'clusters', + f'nice-framework-{e}s.json', + ), + 'w', + ) as f: json.dump(clusters[e], f, indent=2, sort_keys=True, ensure_ascii=False) - f.write('\n') # only needed for the beauty and to be compliant with jq_all_the_things + f.write( + '\n' + ) # only needed for the beauty and to be compliant with jq_all_the_things print(f'{len(g)*2} file created:') for e in g: print(f'- nice-framework-{e}s.json contains {len(clusters[e]["values"])} elements') -print(f' -{ctr_rel} relationships were created') \ No newline at end of file +print(f' -{ctr_rel} relationships were created')