Files
macos_security/scripts/2.0-merge.py
2025-04-17 12:43:36 -04:00

1493 lines
79 KiB
Python
Executable File

#!/usr/bin/env python3
import glob
import json
import os
import re
import shutil
from collections import defaultdict
import yaml
class MyDumper(yaml.Dumper):
def increase_indent(self, flow=False, indentless=False):
return super(MyDumper, self).increase_indent(flow, False)
def str_presenter(dumper, data):
"""configures yaml for dumping multiline strings
Ref: https://stackoverflow.com/questions/8640959/how-can-i-control-what-scalar-form-pyyaml-uses-for-my-data"""
clean_data = data.replace(" \n", "\n")
if clean_data.count("\n") > 0: # check for multiline string
return dumper.represent_scalar("tag:yaml.org,2002:str", clean_data, style="|")
return dumper.represent_scalar("tag:yaml.org,2002:str", clean_data)
yaml.add_representer(str, str_presenter)
yaml.representer.SafeRepresenter.add_representer(str, str_presenter)
def replace_na_with_none(data):
if isinstance(data, dict):
return {key: replace_na_with_none(value) for key, value in data.items()}
elif isinstance(data, list):
return [replace_na_with_none(item) for item in data]
else:
return None if data == "N/A" else data
def remove_none_fields(data, parent_key=None):
if isinstance(data, dict):
# If the current dictionary has a key named 'platforms', leave it unchanged
if parent_key == "platforms":
return data
result = {}
for key, value in data.items():
processed_value = remove_none_fields(value, key) # Pass the key to track parent
if processed_value is not None:
result[key] = processed_value
return result if result else None
elif isinstance(data, list):
# Process each item in the list
processed_list = [remove_none_fields(item, parent_key) for item in data]
# Remove None values and keep only valid items
filtered_list = [item for item in processed_list if item is not None]
return filtered_list if filtered_list else None
else:
# Return the value itself if it's not a dict or list
return data if data is not None else None
def restructure_mobileconfig(rule_yaml):
if "mobileconfig_info" in rule_yaml.keys() and rule_yaml["mobileconfig_info"] is not None:
mobileconfig_info_obj = []
for obj, data in rule_yaml["mobileconfig_info"].items():
payload = {}
payload["PayloadType"] = obj
# generate list of keys for payload content
payload_content = []
for k, v in data.items():
payload_content.append({k: v})
payload["PayloadContent"] = payload_content
mobileconfig_info_obj.append(payload)
return mobileconfig_info_obj
else:
return {}
def restructure_benchmarks(benchmarks, severity):
bmarks = []
for b in benchmarks:
if severity == "" or severity is None:
bmarks.append({"name": b})
elif "stig" in b or "indigo" in b and not severity == "":
bmarks.append({"name": b, "severity": severity})
else:
bmarks.append({"name": b})
return bmarks
def restructure_severity(benchmarks, severity):
severity_list = []
for b in benchmarks:
if "stig" in b or "indigo" in b:
severity_list.append({b: severity})
return severity_list
def get_introduced(payloadtype, key, os):
version = "-1"
for item in payloadtype["payloadkeys"]:
if item["key"] == key:
try:
if os in item["supportedOS"].keys():
version = item["supportedOS"][os]["introduced"]
else:
# try go get introduced from payload parent
if os in payloadtype["payload"]["supportedOS"].keys():
version = payloadtype["payload"]["supportedOS"][os]["introduced"]
except KeyError:
# try go get introduced from payload parent
if os in payloadtype["payload"]["supportedOS"].keys():
version = payloadtype["payload"]["supportedOS"][os]["introduced"]
return version
def correct_result_key(result_dict):
if isinstance(result_dict, str):
return {}
new_result = result_dict.copy()
for k, v in result_dict.items():
if k == "boolean" and isinstance(v, int):
new_result["integer"] = v
new_result.pop("boolean")
return new_result
def remove_lines_containing(text, substring):
lines = text.splitlines()
filtered_lines = [line for line in lines if substring not in line]
return "\n".join(filtered_lines)
def cleanup_fix(fix_text):
new_result = fix_text.strip().replace(" \n", "\n")
if "[source,xml]" in fix_text:
return "", new_result
new_result = remove_lines_containing(new_result, "----")
new_result = remove_lines_containing(new_result, "[source,bash]")
pattern = r"----\n(.*?)\n----(.*)"
match = re.search(pattern, fix_text, re.DOTALL)
note = ""
if match:
code = match.group(1)
note = match.group(2)
return code, note.strip()
else:
return "", new_result
def main():
files_created = []
file_dir = os.path.dirname(os.path.abspath(__file__))
parent_dir = os.path.dirname(file_dir)
original_working_directory = os.getcwd()
os.chdir(file_dir)
build_path = os.path.join(parent_dir, "rules")
# build_path = os.path.join(parent_dir, 'build', 'rules', 'v2.0')
if not (os.path.isdir(build_path)):
try:
os.makedirs(build_path)
except OSError:
print(f"Creation of the directory {build_path} failed")
# load apple device-management profile for referencing
apple_profiles = {}
for apple_profile_file in glob.glob("../_work/apple/mdm/profiles/*.yaml"):
with open(apple_profile_file) as p:
apple_yam = yaml.load(p, Loader=yaml.SafeLoader)
payloadtype = apple_yam["payload"]["payloadtype"]
apple_profiles[payloadtype] = apple_yam
# load odv.json for reference
with open("../includes/odv.json") as o:
odv_json = json.load(o)
# load discussions.yaml for reference
with open("../includes/discussions.yaml") as y:
discussions_yaml = yaml.load(y, Loader=yaml.SafeLoader)
# os_supported = ["sequoia", "sonoma", "ventura", "monterey", "big_sur", "catalina", "ios_18", "ios_17", "ios_16", "visionos_2.0"]
os_supported = ["sequoia", "sonoma", "ventura", "ios_18", "ios_17", "ios_16", "visionos_2.0"]
# for os_list in glob.glob("../_work/*"):
# os_supported.add(os_list.split("/")[2])
all_rules = {}
for os_version in os_supported:
for os_rule in glob.glob("../_work/{}/rules/*/*".format(os_version)):
if "supplemental" in os_rule:
continue
# Initialize list for the OS version if not already done
if os_version not in all_rules:
all_rules[os_version] = []
with open(os_rule) as r:
rule_yam = yaml.load(r, Loader=yaml.SafeLoader)
rule_yaml = replace_na_with_none(rule_yam)
# restructure the mobileconfig object
new_mobileconfig = restructure_mobileconfig(rule_yaml)
rule_yaml["mobileconfig_info"] = new_mobileconfig
if "This is implemented by a Configuration Profile" in rule_yaml["fix"]:
rule_yaml.pop("fix")
all_rules[os_version].append(rule_yaml)
# print(json.dumps(all_rules))
id_to_os = defaultdict(list)
for os_version, rules in all_rules.items():
for rule in rules:
id_to_os[rule["id"]].append(os_version)
new_yaml = {}
duplicates = {id_: os_versions for id_, os_versions in id_to_os.items() if len(os_versions) > 1}
non_duplicates = {id_: os_versions[0] for id_, os_versions in id_to_os.items() if len(os_versions) == 1}
try:
if os.path.isfile(build_path) or os.path.islink(build_path):
os.unlink(build_path)
elif os.path.isdir(build_path):
shutil.rmtree(build_path)
except Exception as e:
print("Failed to delete %s. Reason: %s" % (build_path, e))
if non_duplicates:
for id_, os_versions in non_duplicates.items():
os_ = os_versions
section = id_.split("_")[0]
if section == "system":
section = "system_settings"
section_build_path = os.path.join(parent_dir, "rules", section)
if not (os.path.isdir(section_build_path)):
try:
os.makedirs(section_build_path)
except OSError:
print(f"Creation of the directory {build_path} failed")
with open("../_work/{}/rules/{}/{}.yaml".format(os_, section, id_)) as r:
rule_yam = yaml.load(r, Loader=yaml.SafeLoader)
rule_yaml = replace_na_with_none(rule_yam)
new_mobileconfig = restructure_mobileconfig(rule_yaml)
rule_yaml["mobileconfig_info"] = new_mobileconfig
if "This is implemented by a Configuration Profile" in rule_yaml["fix"]:
rule_yaml.pop("fix")
yaml_file_name = f"{rule_yaml['id']}.yaml"
yaml_full_path = os.path.join(build_path, section, yaml_file_name)
new_yaml = {
"id": rule_yaml["id"],
"title": rule_yaml["title"],
"discussion": rule_yaml["discussion"],
"references": {"nist": {"cce": {os_: rule_yaml["references"]["cce"]}}},
"platforms": {},
"tags": rule_yaml["tags"],
}
if "mobileconfig_info" in rule_yaml:
new_yaml.update({"mobileconfig_info": rule_yaml["mobileconfig_info"]})
if "ddm_info" in rule_yaml:
new_yaml.update({"ddm_info": rule_yaml["ddm_info"]})
if "odv" in rule_yaml:
new_yaml.update({"odv": rule_yaml["odv"]})
if (
os_ == "sequoia"
or os_ == "sonoma"
or os_ == "ventura"
or os_ == "monterey"
or os_ == "big_sur"
or os_ == "catalina"
):
new_yaml["platforms"] = {"macOS": {}}
new_yaml["platforms"]["macOS"].update({os_: {}})
new_yaml["platforms"]["macOS"].update({"check": rule_yaml["check"].strip()})
if "fix" in rule_yaml:
new_yaml["platforms"]["macOS"].update({"fix": rule_yaml["fix"].strip()})
if "result" in rule_yaml:
new_yaml["platforms"]["macOS"].update({"result": rule_yaml["result"]})
new_yaml["platforms"]["macOS"].update({os_: {}})
if "severity" in rule_yaml:
new_yaml["platforms"]["macOS"][os_].update({"severity": rule_yaml["severity"]})
if "cis_lvl1" in rule_yaml["tags"]:
# new_yaml['platforms']['macOS'][os_]['benchmarks'].append("cis_lvl1")
new_yaml["platforms"]["macOS"][os_].update({"benchmarks": ["cis_lvl1"]})
new_yaml["tags"].remove("cis_lvl1")
if "cis_lvl2" in rule_yaml["tags"]:
if "benchmarks" in new_yaml["platforms"]["macOS"][os_]:
new_yaml["platforms"]["macOS"][os_]["benchmarks"].append("cis_lvl2")
else:
new_yaml["platforms"]["macOS"][os_].update({"benchmarks": ["cis_lvl2"]})
new_yaml["tags"].remove("cis_lvl2")
if "stig" in rule_yaml["tags"]:
if "benchmarks" in new_yaml["platforms"]["macOS"][os_]:
new_yaml["platforms"]["macOS"][os_]["benchmarks"].append("disa_stig")
else:
new_yaml["platforms"]["macOS"][os_].update({"benchmarks": ["disa_stig"]})
new_yaml["tags"].remove("stig")
# print(new_yaml)
if "ddm_info" in rule_yaml:
new_yaml.update({"ddm_info": rule_yaml["ddm_info"]})
if "vision" in os_:
new_yaml["tags"].remove("visionos")
new_yaml["platforms"] = {"visionOS": {}}
new_yaml["platforms"]["visionOS"].update({os_: {}})
if "severity" in rule_yaml:
new_yaml["platforms"]["visionOS"][os_].update({"severity": rule_yaml["severity"]})
if "supervised" in rule_yaml:
new_yaml["platforms"]["visionOS"][os_].update({"supervised": rule_yaml["supervised"]})
if os_ == "ios_18" or os_ == "ios_17" or os_ == "ios_16":
new_yaml["tags"].remove("ios")
new_yaml["platforms"] = {"iOS": {}}
new_yaml["platforms"]["iOS"].update({os_: {}})
if "severity" in rule_yaml:
new_yaml["platforms"]["iOS"][os_].update({"severity": rule_yaml["severity"]})
if "supervised" in rule_yaml:
new_yaml["platforms"]["iOS"][os_].update({"supervised": rule_yaml["supervised"]})
if "cis_lvl1_byod" in rule_yaml["tags"]:
new_yaml["platforms"]["iOS"][os_].update({"benchmarks": ["cis_lvl1_byod"]})
new_yaml["tags"].remove("cis_lvl1_byod")
if "cis_lvl2_byod" in rule_yaml["tags"]:
if "benchmarks" in new_yaml["platforms"]["iOS"][os_]:
new_yaml["platforms"]["iOS"][os_]["benchmarks"].append("cis_lvl2_byod")
else:
new_yaml["platforms"]["iOS"][os_].update({"benchmarks": ["cis_lvl2_byod"]})
new_yaml["tags"].remove("cis_lvl2_byod")
if "cis_lvl1_enterprise" in rule_yaml["tags"]:
if "benchmarks" in new_yaml["platforms"]["iOS"][os_]:
new_yaml["platforms"]["iOS"][os_]["benchmarks"].append("cis_lvl1_enterprise")
else:
new_yaml["platforms"]["iOS"][os_].update({"benchmarks": ["cis_lvl1_enterprise"]})
new_yaml["tags"].remove("cis_lvl1_enterprise")
if "cis_lvl2_enterprise" in rule_yaml["tags"]:
if "benchmarks" in new_yaml["platforms"]["iOS"][os_]:
new_yaml["platforms"]["iOS"][os_]["benchmarks"].append("cis_lvl2_enterprise")
else:
new_yaml["platforms"]["iOS"][os_].update({"benchmarks": ["cis_lvl2_enterprise"]})
new_yaml["tags"].remove("cis_lvl2_enterprise")
if "ios_stig" in rule_yaml["tags"]:
if "benchmarks" in new_yaml["platforms"]["iOS"][os_]:
new_yaml["platforms"]["iOS"][os_]["benchmarks"].append("ios_stig")
else:
new_yaml["platforms"]["iOS"][os_].update({"benchmarks": ["ios_stig"]})
new_yaml["tags"].remove("ios_stig")
if "ios_stig_byoad" in rule_yaml["tags"]:
if "benchmarks" in new_yaml["platforms"]["iOS"][os_]:
new_yaml["platforms"]["iOS"][os_]["benchmarks"].append("ios_stig_byoad")
else:
new_yaml["platforms"]["iOS"][os_].update({"benchmarks": ["ios_stig_byoad"]})
new_yaml["tags"].remove("ios_stig_byoad")
if "indigo_base" in rule_yaml["tags"]:
if "benchmarks" in new_yaml["platforms"]["iOS"][os_]:
new_yaml["platforms"]["iOS"][os_]["benchmarks"].append("indigo_base")
else:
new_yaml["platforms"]["iOS"][os_].update({"benchmarks": ["indigo_base"]})
new_yaml["tags"].remove("indigo_base")
if "indigo_high" in rule_yaml["tags"]:
if "benchmarks" in new_yaml["platforms"]["iOS"][os_]:
new_yaml["platforms"]["iOS"][os_]["benchmarks"].append("indigo_high")
else:
new_yaml["platforms"]["iOS"][os_].update({"benchmarks": ["indigo_high"]})
new_yaml["tags"].remove("indigo_high")
if "800-53r5" in rule_yaml["references"]:
new_yaml["references"]["nist"].update({"800-53r5": rule_yaml["references"]["800-53r5"]})
if "800-171r3" in rule_yaml["references"]:
new_yaml["references"]["nist"].update({"800-171r3": rule_yaml["references"]["800-171r3"]})
if "cci" in rule_yaml["references"]:
new_yaml["references"].update({"disa": {}})
new_yaml["references"]["disa"].update({"cci": rule_yaml["references"]["cci"]})
if "srg" in rule_yaml["references"]:
if "disa" in new_yaml["references"]:
new_yaml["references"]["disa"].update({"srg": rule_yaml["references"]["srg"]})
else:
new_yaml["references"].update({"disa": {}})
new_yaml["references"]["disa"].update({"srg": rule_yaml["references"]["srg"]})
if "disa_stig" in rule_yaml["references"]:
if "disa" in new_yaml["references"]:
new_yaml["references"]["disa"].update({"disa_stig": {}})
new_yaml["references"]["disa"]["disa_stig"].update({os_: rule_yaml["references"]["disa_stig"]})
else:
new_yaml["references"].update({"disa": {}})
new_yaml["references"]["disa"].update({"disa_stig": {}})
new_yaml["references"]["disa"]["disa_stig"].update({os_: rule_yaml["references"]["disa_stig"]})
if "sfr" in rule_yaml["references"]:
if "disa" in new_yaml["references"]:
new_yaml["references"]["disa"].update({"sfr": rule_yaml["references"]["sfr"]})
else:
new_yaml["references"].update({"disa": {}})
new_yaml["references"]["disa"].update({"sfr": rule_yaml["references"]["sfr"]})
if "cmmc" in rule_yaml["references"]:
if "disa" in new_yaml["references"]:
new_yaml["references"]["disa"].update({"cmmc": rule_yaml["references"]["cmmc"]})
else:
new_yaml["references"].update({"disa": {}})
new_yaml["references"]["disa"].update({"cmmc": rule_yaml["references"]["cmmc"]})
if "indigo" in rule_yaml["references"]:
if "bsi" in new_yaml["references"]:
new_yaml["references"]["bsi"].update({"indigo": {os_: rule_yaml["references"]["indigo"]}})
else:
new_yaml["references"].update({"bsi": {}})
new_yaml["references"]["bsi"].update({"indigo": {os_: rule_yaml["references"]["indigo"]}})
if "cis" in rule_yaml["references"]:
if "benchmark" in rule_yaml["references"]["cis"]:
if "cis" in new_yaml["references"]:
new_yaml["references"]["cis"].update({"benchmark": {}})
new_yaml["references"]["cis"]["benchmark"].update(
{os_: rule_yaml["references"]["cis"]["benchmark"]}
)
else:
new_yaml["references"].update({"cis": {}})
new_yaml["references"]["cis"].update({"benchmark": {}})
new_yaml["references"]["cis"]["benchmark"].update(
{os_: rule_yaml["references"]["cis"]["benchmark"]}
)
if "controls v8" in rule_yaml["references"]["cis"]:
if "cis" in new_yaml["references"]:
new_yaml["references"]["cis"].update(
{"controls_v8": rule_yaml["references"]["cis"]["controls v8"]}
)
else:
new_yaml["references"].update({"cis": {}})
new_yaml["references"]["cis"]["controls_v8"].update(
rule_yaml["references"]["cis"]["controls v8"]
)
with open(yaml_full_path, "w") as wfile:
# print(replace_na_with_none(new_yaml))
if yaml_full_path not in files_created:
files_created.append(yaml_full_path)
yaml.dump(new_yaml, wfile, Dumper=MyDumper, sort_keys=False, width=float("inf"))
if duplicates:
rules_to_review = []
# print("Duplicate IDs and their associated OS versions:")
for id_, os_versions in duplicates.items():
# print(f"ID: {id_}, OS Versions: {os_versions}")
os_specifics = {}
for os_ in os_versions:
section = id_.split("_")[0]
if section == "system":
section = "system_settings"
section_build_path = os.path.join(parent_dir, "rules", section)
if not (os.path.isdir(section_build_path)):
try:
os.makedirs(section_build_path)
except OSError:
print(f"Creation of the directory {build_path} failed")
with open("../_work/{}/rules/{}/{}.yaml".format(os_, section, id_)) as r:
rule_yam = yaml.load(r, Loader=yaml.SafeLoader)
rule_yaml = replace_na_with_none(rule_yam)
new_mobileconfig = restructure_mobileconfig(rule_yaml)
rule_yaml["mobileconfig_info"] = new_mobileconfig
if "This is implemented by a Configuration Profile" in rule_yaml["fix"]:
rule_yaml.pop("fix")
os_specifics.update({os_: {}})
# if "discussion" in rule_yaml:
# os_specifics[os_].update({"discussion":rule_yaml['discussion'].strip().replace(" \n","\n")})
if "check" in rule_yaml:
os_specifics[os_].update({"check": rule_yaml["check"].strip().replace(" \n", "\n")})
else:
os_specifics[os_].update({"check": ""})
if "result" in rule_yaml:
rule_yaml["result"] = correct_result_key(rule_yaml["result"])
os_specifics[os_].update({"result": rule_yaml["result"]})
else:
os_specifics[os_].update({"result": ""})
if "fix" in rule_yaml:
# fix_code, fix_note = cleanup_fix(rule_yaml['fix'])
# rule_yaml['fix'] = fix_code
os_specifics[os_].update({"fix": rule_yaml["fix"]})
else:
os_specifics[os_].update({"fix": ""})
if "mobileconfig" in rule_yaml:
os_specifics[os_].update({"mobileconfig": rule_yaml["mobileconfig_info"]})
else:
os_specifics[os_].update({"mobileconfig": ""})
yaml_file_name = f"{rule_yaml['id']}.yaml"
yaml_full_path = os.path.join(build_path, section, yaml_file_name)
if os.path.exists(yaml_full_path):
with open(yaml_full_path) as ryam:
update_rule_yam = yaml.load(ryam, Loader=yaml.SafeLoader)
update_rule_yaml = replace_na_with_none(update_rule_yam)
update_rule_yaml["references"]["nist"]["cce"].update({os_: rule_yaml["references"]["cce"]})
if "odv" in rule_yaml:
if "odv" in update_rule_yaml:
for k, v in rule_yaml["odv"].items():
update_rule_yaml["odv"].update({k: v})
else:
update_rule_yaml.update("odv", rule_yaml["odv"])
if "indigo" in rule_yaml["references"]:
if "bsi" in update_rule_yaml["references"]:
if "indigo" in update_rule_yaml["references"]["bsi"]:
update_rule_yaml["references"]["bsi"]["indigo"].update(
{os_: rule_yaml["references"]["indigo"]}
)
else:
update_rule_yaml["references"]["bsi"].update({"indigo": {}})
update_rule_yaml["references"]["bsi"]["indigo"].update(
{os_: rule_yaml["references"]["indigo"]}
)
else:
update_rule_yaml["references"].update({"bsi": {}})
update_rule_yaml["references"]["bsi"].update({"indigo": {}})
update_rule_yaml["references"]["bsi"]["indigo"].update(
{os_: rule_yaml["references"]["indigo"]}
)
if "cis" in rule_yaml["references"]:
if "benchmark" in rule_yaml["references"]["cis"]:
if "cis" in update_rule_yaml["references"]:
if "benchmark" in update_rule_yaml["references"]["cis"]:
update_rule_yaml["references"]["cis"]["benchmark"].update(
{os_: rule_yaml["references"]["cis"]["benchmark"]}
)
else:
update_rule_yaml["references"]["cis"].update({"benchmark": {}})
update_rule_yaml["references"]["cis"]["benchmark"].update(
{os_: rule_yaml["references"]["cis"]["benchmark"]}
)
else:
update_rule_yaml["references"].update({"cis": {}})
update_rule_yaml["references"]["cis"].update({"benchmark": {}})
update_rule_yaml["references"]["cis"]["benchmark"].update(
{os_: rule_yaml["references"]["cis"]["benchmark"]}
)
if "disa_stig" in rule_yaml["references"]:
if "disa" in update_rule_yaml["references"]:
if "disa_stig" in update_rule_yaml["references"]["disa"]:
update_rule_yaml["references"]["disa"]["disa_stig"].update(
{os_: rule_yaml["references"]["disa_stig"]}
)
else:
update_rule_yaml["references"]["disa"].update({"disa_stig": {}})
update_rule_yaml["references"]["disa"]["disa_stig"].update(
{os_: rule_yaml["references"]["disa_stig"]}
)
else:
update_rule_yaml["references"].update({"disa": {}})
update_rule_yaml["references"]["disa"].update({"disa_stig": {}})
update_rule_yaml["references"]["disa"]["disa_stig"].update(
{os_: rule_yaml["references"]["disa_stig"]}
)
for new_tag in rule_yaml["tags"]:
if new_tag in update_rule_yaml["tags"]:
continue
if (
"cis_lvl1" in new_tag
or "cis_lvl2" in new_tag
or "stig" in new_tag
or new_tag == "ios"
or "indigo" in new_tag
or "none" in new_tag
):
continue
if "ios" in new_tag or "visionos" in new_tag:
continue
if (
"800-53r4_low" in new_tag
or "800-53r4_moderate" in new_tag
or "800-53r4_high" in new_tag
):
continue
update_rule_yaml["tags"].append(new_tag)
if os_ == "visionos_2.0" or "ios" in os_:
# print("HELLO")
# print(os_)
if os_ == "visionos_2.0":
# print("hello vision")
update_rule_yaml["platforms"].update({"visionOS": {}})
update_rule_yaml["platforms"]["visionOS"].update({os_: {}})
if "supervised" in rule_yaml:
update_rule_yaml["platforms"]["visionOS"][os_].update(
{"supervised": rule_yaml["supervised"]}
)
# print(update_rule_yaml)
else:
if "iOS" not in update_rule_yaml["platforms"]:
update_rule_yaml["platforms"].update({"iOS": {}})
update_rule_yaml["platforms"]["iOS"].update({os_: {}})
if "severity" in rule_yaml:
update_rule_yaml["platforms"]["iOS"][os_].update(
{"severity": rule_yaml["severity"]}
)
if "supervised" in rule_yaml:
update_rule_yaml["platforms"]["iOS"][os_].update(
{"supervised": rule_yaml["supervised"]}
)
if "cis_lvl1_byod" in rule_yaml["tags"]:
update_rule_yaml["platforms"]["iOS"][os_].update(
{"benchmarks": ["cis_lvl1_byod"]}
)
if "cis_lvl1_byod" in update_rule_yaml["tags"]:
update_rule_yaml["tags"].remove("cis_lvl1_byod")
if "cis_lvl2_byod" in rule_yaml["tags"]:
if "benchmarks" in update_rule_yaml["platforms"]["iOS"][os_]:
update_rule_yaml["platforms"]["iOS"][os_]["benchmarks"].append(
"cis_lvl2_byod"
)
else:
update_rule_yaml["platforms"]["iOS"][os_].update(
{"benchmarks": ["cis_lvl2_byod"]}
)
if "cis_lvl2_byod" in update_rule_yaml["tags"]:
update_rule_yaml["tags"].remove("cis_lvl2_byod")
if "cis_lvl1_enterprise" in rule_yaml["tags"]:
if "benchmarks" in update_rule_yaml["platforms"]["iOS"][os_]:
update_rule_yaml["platforms"]["iOS"][os_]["benchmarks"].append(
"cis_lvl1_enterprise"
)
else:
update_rule_yaml["platforms"]["iOS"][os_].update(
{"benchmarks": ["cis_lvl1_enterprise"]}
)
if "cis_lvl1_enterprise" in update_rule_yaml["tags"]:
update_rule_yaml["tags"].remove("cis_lvl1_enterprise")
if "cis_lvl2_enterprise" in rule_yaml["tags"]:
if "benchmarks" in update_rule_yaml["platforms"]["iOS"][os_]:
update_rule_yaml["platforms"]["iOS"][os_]["benchmarks"].append(
"cis_lvl2_enterprise"
)
else:
update_rule_yaml["platforms"]["iOS"][os_].update(
{"benchmarks": ["cis_lvl2_enterprise"]}
)
if "cis_lvl2_enterprise" in update_rule_yaml["tags"]:
update_rule_yaml["tags"].remove("cis_lvl2_enterprise")
if "ios_stig" in rule_yaml["tags"]:
if "benchmarks" in update_rule_yaml["platforms"]["iOS"][os_]:
update_rule_yaml["platforms"]["iOS"][os_]["benchmarks"].append("ios_stig")
else:
update_rule_yaml["platforms"]["iOS"][os_].update(
{"benchmarks": ["ios_stig"]}
)
if "ios_stig" in update_rule_yaml["tags"]:
update_rule_yaml["tags"].remove("ios_stig")
if "ios_stig_byoad" in rule_yaml["tags"]:
if "benchmarks" in update_rule_yaml["platforms"]["iOS"][os_]:
update_rule_yaml["platforms"]["iOS"][os_]["benchmarks"].append(
"ios_stig_byoad"
)
else:
update_rule_yaml["platforms"]["iOS"][os_].update(
{"benchmarks": ["ios_stig_byoad"]}
)
if "ios_stig_byoad" in update_rule_yaml["tags"]:
update_rule_yaml["tags"].remove("ios_stig_byoad")
if "indigo_base" in rule_yaml["tags"]:
if "benchmarks" in update_rule_yaml["platforms"]["iOS"][os_]:
update_rule_yaml["platforms"]["iOS"][os_]["benchmarks"].append(
"indigo_base"
)
else:
update_rule_yaml["platforms"]["iOS"][os_].update(
{"benchmarks": ["indigo_base"]}
)
if "indigo_base" in update_rule_yaml["tags"]:
update_rule_yaml["tags"].remove("indigo_base")
if "indigo_high" in rule_yaml["tags"]:
if "benchmarks" in update_rule_yaml["platforms"]["iOS"][os_]:
update_rule_yaml["platforms"]["iOS"][os_]["benchmarks"].append(
"indigo_high"
)
else:
update_rule_yaml["platforms"]["iOS"][os_].update(
{"benchmarks": ["indigo_high"]}
)
if "indigo_high" in update_rule_yaml["tags"]:
update_rule_yaml["tags"].remove("indigo_high")
if (
os_ == "sequoia"
or os_ == "sonoma"
or os_ == "ventura"
or os_ == "monterey"
or os_ == "big_sur"
or os_ == "catalina"
):
if "macOS" not in update_rule_yaml["platforms"]:
update_rule_yaml["platforms"].update({"macOS": {}})
update_rule_yaml["platforms"]["macOS"].update({os_: {}})
else:
if os_ not in update_rule_yaml["platforms"]["macOS"]:
update_rule_yaml["platforms"]["macOS"].update({os_: {}})
if "severity" in rule_yaml:
update_rule_yaml["platforms"]["macOS"][os_].update(
{"severity": rule_yaml["severity"]}
)
if "cis_lvl1" in rule_yaml["tags"]:
update_rule_yaml["platforms"]["macOS"][os_].update({"benchmarks": ["cis_lvl1"]})
if "cis_lvl2" in rule_yaml["tags"]:
if "benchmarks" in update_rule_yaml["platforms"]["macOS"][os_]:
update_rule_yaml["platforms"]["macOS"][os_]["benchmarks"].append("cis_lvl2")
else:
update_rule_yaml["platforms"]["macOS"][os_].update({"benchmarks": ["cis_lvl2"]})
if "stig" in rule_yaml["tags"]:
if "benchmarks" in update_rule_yaml["platforms"]["macOS"][os_]:
update_rule_yaml["platforms"]["macOS"][os_]["benchmarks"].append("disa_stig")
else:
update_rule_yaml["platforms"]["macOS"][os_].update(
{"benchmarks": ["disa_stig"]}
)
if "check" not in update_rule_yaml["platforms"]["macOS"]:
if "check" in rule_yaml:
# update_rule_yaml['platforms']['macOS'].update({"check", rule_yaml['check']})
update_rule_yaml["platforms"]["macOS"].update(
{"check": rule_yaml["check"].strip().replace(" \n", "\n")}
)
# update_rule_yaml['platforms']['macOS'].update({"result", rule_yaml['result']})
update_rule_yaml["platforms"]["macOS"].update({"result": rule_yaml["result"]})
if "fix" not in update_rule_yaml["platforms"]["macOS"]:
if "fix" in rule_yaml:
# fix_code, fix_note = cleanup_fix(rule_yaml['fix'])
# rule_yaml['fix'] = fix_code
update_rule_yaml["platforms"]["macOS"].update({"fix": rule_yaml["fix"]})
if "ddm_info" in rule_yaml:
update_rule_yaml.update({"ddm_info": rule_yaml["ddm_info"]})
with open(yaml_full_path, "w") as wfile:
yaml.dump(update_rule_yaml, wfile, Dumper=MyDumper, sort_keys=False, width=float("inf"))
else:
new_yaml = {
"id": rule_yaml["id"],
"title": rule_yaml["title"],
"discussion": rule_yaml["discussion"],
"references": {"nist": {"cce": {os_: rule_yaml["references"]["cce"]}}},
"platforms": {},
"tags": rule_yaml["tags"],
}
if "none" in new_yaml["tags"]:
new_yaml["tags"].remove("none")
if "800-53r4_low" in new_yaml["tags"]:
new_yaml["tags"].remove("800-53r4_low")
if "800-53r4_moderate" in new_yaml["tags"]:
new_yaml["tags"].remove("800-53r4_moderate")
if "800-53r4_high" in new_yaml["tags"]:
new_yaml["tags"].remove("800-53r4_high")
if "mobileconfig_info" in rule_yaml:
new_yaml.update({"mobileconfig_info": rule_yaml["mobileconfig_info"]})
if "ddm_info" in rule_yaml:
new_yaml.update({"ddm_info": rule_yaml["ddm_info"]})
if "odv" in rule_yaml:
new_yaml.update({"odv": rule_yaml["odv"]})
if (
os_ == "sequoia"
or os_ == "sonoma"
or os_ == "ventura"
or os_ == "monterey"
or os_ == "big_sur"
or os_ == "catalina"
):
new_yaml["platforms"] = {"macOS": {}}
new_yaml["platforms"]["macOS"].update({"check": rule_yaml["check"].strip()})
if "result" in rule_yaml:
rule_yaml["result"] = correct_result_key(rule_yaml["result"])
new_yaml["platforms"]["macOS"].update({"result": rule_yaml["result"]})
new_yaml["platforms"]["macOS"].update({os_: {}})
if "severity" in rule_yaml:
new_yaml["platforms"]["macOS"][os_].update({"severity": rule_yaml["severity"]})
if "cis_lvl1" in rule_yaml["tags"]:
# new_yaml['platforms']['macOS'][os_]['benchmarks'].append("cis_lvl1")
new_yaml["platforms"]["macOS"][os_].update({"benchmarks": ["cis_lvl1"]})
new_yaml["tags"].remove("cis_lvl1")
if "cis_lvl2" in rule_yaml["tags"]:
if "benchmarks" in new_yaml["platforms"]["macOS"][os_]:
new_yaml["platforms"]["macOS"][os_]["benchmarks"].append("cis_lvl2")
else:
new_yaml["platforms"]["macOS"][os_].update({"benchmarks": ["cis_lvl2"]})
new_yaml["tags"].remove("cis_lvl2")
if "stig" in rule_yaml["tags"]:
if "benchmarks" in new_yaml["platforms"]["macOS"][os_]:
new_yaml["platforms"]["macOS"][os_]["benchmarks"].append("disa_stig")
else:
new_yaml["platforms"]["macOS"][os_].update({"benchmarks": ["disa_stig"]})
new_yaml["tags"].remove("stig")
# print(new_yaml)
if os_ == "ios_18" or os_ == "ios_17" or os_ == "ios_16":
new_yaml["tags"].remove("ios")
new_yaml["platforms"].update({"iOS": {}})
new_yaml["platforms"]["iOS"].update({os_: {}})
if "severity" in rule_yaml:
new_yaml["platforms"]["iOS"][os_].update({"severity": rule_yaml["severity"]})
if "supervised" in rule_yaml:
new_yaml["platforms"]["iOS"][os_].update({"supervised": rule_yaml["supervised"]})
if "cis_lvl1_byod" in rule_yaml["tags"]:
new_yaml["platforms"]["iOS"][os_].update({"benchmarks": ["cis_lvl1_byod"]})
new_yaml["tags"].remove("cis_lvl1_byod")
if "cis_lvl2_byod" in rule_yaml["tags"]:
if "benchmarks" in new_yaml["platforms"]["iOS"][os_]:
new_yaml["platforms"]["iOS"][os_]["benchmarks"].append("cis_lvl2_byod")
else:
new_yaml["platforms"]["iOS"][os_].update({"benchmarks": ["cis_lvl2_byod"]})
new_yaml["tags"].remove("cis_lvl2_byod")
if "cis_lvl1_enterprise" in rule_yaml["tags"]:
if "benchmarks" in new_yaml["platforms"]["iOS"][os_]:
new_yaml["platforms"]["iOS"][os_]["benchmarks"].append("cis_lvl1_enterprise")
else:
new_yaml["platforms"]["iOS"][os_].update({"benchmarks": ["cis_lvl1_enterprise"]})
new_yaml["tags"].remove("cis_lvl1_enterprise")
if "cis_lvl2_enterprise" in rule_yaml["tags"]:
if "benchmarks" in new_yaml["platforms"]["iOS"][os_]:
new_yaml["platforms"]["iOS"][os_]["benchmarks"].append("cis_lvl2_enterprise")
else:
new_yaml["platforms"]["iOS"][os_].update({"benchmarks": ["cis_lvl2_enterprise"]})
new_yaml["tags"].remove("cis_lvl2_enterprise")
if "ios_stig" in rule_yaml["tags"]:
if "benchmarks" in new_yaml["platforms"]["iOS"][os_]:
new_yaml["platforms"]["iOS"][os_]["benchmarks"].append("ios_stig")
else:
new_yaml["platforms"]["iOS"][os_].update({"benchmarks": ["ios_stig"]})
new_yaml["tags"].remove("ios_stig")
if "ios_stig_byoad" in rule_yaml["tags"]:
if "benchmarks" in new_yaml["platforms"]["iOS"][os_]:
new_yaml["platforms"]["iOS"][os_]["benchmarks"].append("ios_stig_byoad")
else:
new_yaml["platforms"]["iOS"][os_].update({"benchmarks": ["ios_stig_byoad"]})
new_yaml["tags"].remove("ios_stig_byoad")
if "indigo_base" in rule_yaml["tags"]:
if "benchmarks" in new_yaml["platforms"]["iOS"][os_]:
new_yaml["platforms"]["iOS"][os_]["benchmarks"].append("indigo_base")
else:
new_yaml["platforms"]["iOS"][os_].update({"benchmarks": ["indigo_base"]})
new_yaml["tags"].remove("indigo_base")
if "indigo_high" in rule_yaml["tags"]:
if "benchmarks" in new_yaml["platforms"]["iOS"][os_]:
new_yaml["platforms"]["iOS"][os_]["benchmarks"].append("indigo_high")
else:
new_yaml["platforms"]["iOS"][os_].update({"benchmarks": ["indigo_high"]})
new_yaml["tags"].remove("indigo_high")
if os_ == "visionos_2.0":
new_yaml["tags"].remove("visionos")
new_yaml["platforms"].update({"visionOS": {}})
new_yaml["platforms"]["visionOS"].update({os_: {}})
if "supervised" in rule_yaml:
new_yaml["platforms"]["visionOS"][os_].update({"supervised": rule_yaml["supervised"]})
if "800-53r5" in rule_yaml["references"]:
new_yaml["references"]["nist"].update({"800-53r5": rule_yaml["references"]["800-53r5"]})
if "800-171r3" in rule_yaml["references"]:
new_yaml["references"]["nist"].update({"800-171r3": rule_yaml["references"]["800-171r3"]})
if "cci" in rule_yaml["references"]:
new_yaml["references"].update({"disa": {}})
new_yaml["references"]["disa"].update({"cci": rule_yaml["references"]["cci"]})
if "srg" in rule_yaml["references"]:
if "disa" in new_yaml["references"]:
new_yaml["references"]["disa"].update({"srg": rule_yaml["references"]["srg"]})
else:
new_yaml["references"].update({"disa": {}})
new_yaml["references"]["disa"].update({"srg": rule_yaml["references"]["srg"]})
if "disa_stig" in rule_yaml["references"]:
if "disa" in new_yaml["references"]:
new_yaml["references"]["disa"].update({"disa_stig": {}})
new_yaml["references"]["disa"]["disa_stig"].update(
{os_: rule_yaml["references"]["disa_stig"]}
)
else:
new_yaml["references"].update({"disa": {}})
new_yaml["references"]["disa"].update({"disa_stig": {}})
new_yaml["references"]["disa"]["disa_stig"].update(
{os_: rule_yaml["references"]["disa_stig"]}
)
if "sfr" in rule_yaml["references"]:
if "disa" in new_yaml["references"]:
new_yaml["references"]["disa"].update({"sfr": rule_yaml["references"]["sfr"]})
else:
new_yaml["references"].update({"disa": {}})
new_yaml["references"]["disa"].update({"sfr": rule_yaml["references"]["sfr"]})
if "cmmc" in rule_yaml["references"]:
if "disa" in new_yaml["references"]:
new_yaml["references"]["disa"].update({"cmmc": rule_yaml["references"]["cmmc"]})
else:
new_yaml["references"].update({"disa": {}})
new_yaml["references"]["disa"].update({"cmmc": rule_yaml["references"]["cmmc"]})
if "cis" in rule_yaml["references"]:
if "benchmark" in rule_yaml["references"]["cis"]:
if "cis" in new_yaml["references"]:
new_yaml["references"]["cis"].update({"benchmark": {}})
new_yaml["references"]["cis"]["benchmark"].update(
{os_: rule_yaml["references"]["cis"]["benchmark"]}
)
else:
new_yaml["references"].update({"cis": {}})
new_yaml["references"]["cis"].update({"benchmark": {}})
new_yaml["references"]["cis"]["benchmark"].update(
{os_: rule_yaml["references"]["cis"]["benchmark"]}
)
if "controls v8" in rule_yaml["references"]["cis"]:
if "cis" in new_yaml["references"]:
new_yaml["references"]["cis"].update(
{"controls_v8": rule_yaml["references"]["cis"]["controls v8"]}
)
else:
new_yaml["references"].update({"cis": {}})
new_yaml["references"]["cis"]["controls_v8"].update(
rule_yaml["references"]["cis"]["controls v8"]
)
with open(yaml_full_path, "w") as wfile:
yaml.dump(new_yaml, wfile, Dumper=MyDumper, sort_keys=False, width=float("inf"))
# if os_ == "sequoia" or os_ == "sonoma" or os_ == "ventura" or os_ == "monterey" or os_ == "big_sur" or os_ == "catalina":
platforms = list(os_specifics.keys())
# for p in platforms:
# base_os = platforms[0]
# if base_os == "ios_16" or base_os == "ios_17" or base_os == "ios_18" or base_os == "visionos_2.0":
# base_os = p
# if base_os != "ios_16" or base_os != "ios_17" or base_os != "ios_18" or base_os != "visionos_2.0":
# break
base_os = platforms[0]
base_value = os_specifics[base_os]["mobileconfig"]
configprofile_differences = {}
for platform in platforms[1:]:
if os_specifics[platform]["mobileconfig"] != base_value:
configprofile_differences[platform] = os_specifics[platform]["mobileconfig"]
# print(rule_yaml['id'])
# print(configprofile_differences)
# discussion_differences = {}
# base_value = os_specifics[base_os]['discussion']
# for platform in platforms[1:]:
# if os_specifics[platform]['discussion'] != base_value:
# discussion_differences[base_os] = base_value
# discussion_differences[platform] = os_specifics[platform]['discussion']
# if discussion_differences:
# print("+++++++++++++++++++")
# print(rule_yaml['id'])
# print(json.dumps(discussion_differences,indent=4))
# print()
for key in ["check", "fix", "result", "mobileconfig"]:
base_os = platforms[0]
for p in platforms:
base_os = platforms[0]
if base_os == "ios_16" or base_os == "ios_17" or base_os == "ios_18" or base_os == "visionos_2.0":
base_os = p
if base_os != "ios_16" or base_os != "ios_17" or base_os != "ios_18" or base_os != "visionos_2.0":
break
base_value = os_specifics[base_os][key]
differences = {}
for platform in platforms[1:]:
if ("ios" in platform or "vision" in platform and key == "check") or (
"ios" in platform or "vision" in platform and key == "result"
):
continue
if os_specifics[platform][key] != base_value:
# print(rule_yaml['id'])
# print(base_value)
# print(base_os)
differences[platform] = os_specifics[platform][key]
if key == "result":
differences[platform] = os_specifics[platform][key]
with open(yaml_full_path) as ryam:
differences_yam = yaml.load(ryam, Loader=yaml.SafeLoader)
differences_yaml = replace_na_with_none(differences_yam)
if differences:
# print(os_specifics)
for operating_sys, value in os_specifics.items():
if "vision" in operating_sys or "ios" in operating_sys:
continue
if key == "check":
if value["check"] == " " or value["check"] == "":
continue
# print(base_os)
# print(differences)
# print("++++++++++++")
differences_yaml["platforms"]["macOS"][operating_sys].update({"check": value["check"]})
if key == "result":
if value["result"] == " " or value["result"] == "":
continue
# if "result" in differences_yaml['platforms']['macOS']:
# if operating_sys != "sequoia":
differences_yaml["platforms"]["macOS"][operating_sys].update({"result": value["result"]})
if key == "fix":
differences_yaml["platforms"]["macOS"][operating_sys].update({"fix": value["fix"]})
# if key == "mobileconfig":
# differences_yaml['platforms']['macOS'][operating_sys].update({"mobileconfig": value})
if "macOS" in differences_yaml["platforms"]:
if key == "result":
if differences_yaml["id"] not in rules_to_review:
rules_to_review.append(differences_yaml["id"])
# differences_yaml['platforms']['macOS']['result'] = "$OS_VALUE"
if key == "check":
if differences_yaml["id"] not in rules_to_review:
rules_to_review.append(differences_yaml["id"])
# differences_yaml['platforms']['macOS']['check'] = "$OS_VALUE"
if key == "fix":
if differences_yaml["id"] not in rules_to_review:
rules_to_review.append(differences_yaml["id"])
# differences_yaml['platforms']['macOS']['fix'] = "$OS_VALUE"
# if key == "mobileconfig":
# differences_yaml['mobileconfig_info'] = "$OS_VALUE"
if configprofile_differences and key == "mobileconfig":
for operating_sys, value in os_specifics.items():
if operating_sys == "visionos_2.0":
differences_yaml["platforms"]["visionOS"][operating_sys].update(
{"mobileconfig_info": value["mobileconfig"]}
)
elif "ios" in operating_sys:
differences_yaml["platforms"]["iOS"][operating_sys].update(
{"mobileconfig_info": value["mobileconfig"]}
)
elif (
os_ == "sequoia"
or os_ == "sonoma"
or os_ == "ventura"
or os_ == "monterey"
or os_ == "big_sur"
or os_ == "catalina"
):
differences_yaml["platforms"]["macOS"][operating_sys].update(
{"mobileconfig_info": value["mobileconfig"]}
)
# print(differences_yaml['id'])
# print(value['mobileconfig'])
# print(operating_sys)
# differences_yaml['mobileconfig_info'] = "$OS_VALUE"
with open(yaml_full_path, "w") as wfile:
yaml.dump(differences_yaml, wfile, Dumper=MyDumper, sort_keys=False, width=float("inf"))
with open(yaml_full_path, "r") as r_again:
re_order_ya = yaml.load(r_again, Loader=yaml.SafeLoader)
re_order_yam = replace_na_with_none(re_order_ya)
yaml_key_order = [
"id",
"title",
"discussion",
"references",
"platforms",
"odv",
"tags",
"mobileconfig_info",
"ddm_info",
]
ordered_keys = sorted(
re_order_yam.keys(),
key=lambda k: (yaml_key_order.index(k) if k in yaml_key_order else len(yaml_key_order), k),
)
re_order_yam = {key: re_order_yam[key] for key in ordered_keys}
priority_os_order = [
"sequoia",
"sonoma",
"ventura",
"monterey",
"big_sur",
"catalina",
"ios_18",
"ios_17",
"ios_16",
"visionos_2.0",
]
ordered_keys = sorted(
re_order_yam["references"]["nist"]["cce"].keys(),
key=lambda k: (priority_os_order.index(k) if k in priority_os_order else len(priority_os_order), k),
)
re_order_yam["references"]["nist"]["cce"] = {
key: re_order_yam["references"]["nist"]["cce"][key] for key in ordered_keys
}
if "disa" in re_order_yam["references"]:
if "disa_stig" in re_order_yam["references"]["disa"]:
ordered_keys = sorted(
re_order_yam["references"]["disa"]["disa_stig"].keys(),
key=lambda k: (
priority_os_order.index(k) if k in priority_os_order else len(priority_os_order),
k,
),
)
re_order_yam["references"]["disa"]["disa_stig"] = {
key: re_order_yam["references"]["disa"]["disa_stig"][key] for key in ordered_keys
}
if "cis" in re_order_yam["references"]:
if "benchmark" in re_order_yam["references"]["cis"]:
ordered_keys = sorted(
re_order_yam["references"]["cis"]["benchmark"].keys(),
key=lambda k: (
priority_os_order.index(k) if k in priority_os_order else len(priority_os_order),
k,
),
)
re_order_yam["references"]["cis"]["benchmark"] = {
key: re_order_yam["references"]["cis"]["benchmark"][key] for key in ordered_keys
}
priority_macos_order = [
"check",
"result",
"fix",
"sequoia",
"sonoma",
"ventura",
"monterey",
"big_sur",
"catalina",
]
priority_ios_order = ["ios_18", "ios_17", "ios_16"]
platform_order = ["macOS", "iOS", "visionOS"]
# print(re_order_yam)
ordered_keys = sorted(
re_order_yam["platforms"].keys(),
key=lambda k: (platform_order.index(k) if k in platform_order else len(platform_order), k),
)
re_order_yam["platforms"] = {key: re_order_yam["platforms"][key] for key in ordered_keys}
if "macOS" in re_order_yam["platforms"]:
ordered_keys = sorted(
re_order_yam["platforms"]["macOS"].keys(),
key=lambda k: (
priority_macos_order.index(k) if k in priority_macos_order else len(priority_macos_order),
k,
),
)
re_order_yam["platforms"]["macOS"] = {
key: re_order_yam["platforms"]["macOS"][key] for key in ordered_keys
}
if "iOS" in re_order_yam["platforms"]:
ordered_keys = sorted(
re_order_yam["platforms"]["iOS"].keys(),
key=lambda k: (
priority_ios_order.index(k) if k in priority_ios_order else len(priority_ios_order),
k,
),
)
re_order_yam["platforms"]["iOS"] = {key: re_order_yam["platforms"]["iOS"][key] for key in ordered_keys}
if "mobileconfig_info" in re_order_yam:
if re_order_yam["mobileconfig_info"] == None:
re_order_yam.pop("mobileconfig_info")
with open(yaml_full_path, "w") as wfile:
if yaml_full_path not in files_created:
files_created.append(yaml_full_path)
yaml.dump(re_order_yam, wfile, Dumper=MyDumper, sort_keys=False, width=float("inf"))
print("review the following rules across branches for minor differences")
for r in rules_to_review:
print(r)
unknown_keys = []
odv_rules = []
for file in files_created:
with open(file) as newyamlfile:
_yaml = yaml.load(newyamlfile, Loader=yaml.SafeLoader)
if "srg" in _yaml["tags"]:
_yaml["tags"].remove("srg")
if "visionos" in _yaml["tags"]:
_yaml["tags"].remove("visionos")
_yaml = replace_keys_by_path(_yaml)
# update discussions
for d in discussions_yaml:
if _yaml["id"] == d["id"]:
_yaml["discussion"] = d["discussion"]
# move permanent, inherant check/fix info into discussions
if "macOS" in _yaml["platforms"] and "check" in _yaml["platforms"]["macOS"]:
if (
"requirement is NA" in _yaml["platforms"]["macOS"]["check"]
or "inherently" in _yaml["platforms"]["macOS"]["check"]
or "does not meet finding" in _yaml["platforms"]["macOS"]["check"]
or "technology does support this requirement" in _yaml["platforms"]["macOS"]["check"]
or "technology partially supports" in _yaml["platforms"]["macOS"]["check"]
):
check_text = _yaml["platforms"]["macOS"]["check"]
fix_text = _yaml["platforms"]["macOS"]["fix"]
_yaml["platforms"]["macOS"].pop("check")
# _yaml['platforms']['macOS'].pop('fix')
_yaml["discussion"] += f"\nNOTE: {check_text}"
# clean up any redundent checks
for _os in _yaml["platforms"]["macOS"].keys():
if _os == "check" or _os == "fix" or _os == "result":
continue
_yaml["platforms"]["macOS"][_os]["enforcement_info"] = {}
if "check" in _yaml["platforms"]["macOS"][_os]:
if _yaml["platforms"]["macOS"]["check"] == _yaml["platforms"]["macOS"][_os]["check"]:
print(f"{_yaml['id']} - main check matches check of {_os}")
_yaml["platforms"]["macOS"][_os].pop("check")
# if "result" in _yaml['platforms']['macOS'][_os]:
# _yaml['platforms']['macOS'][_os].pop('result')
# move it into compliance object
if "check" in _yaml["platforms"]["macOS"][_os]:
_yaml["platforms"]["macOS"][_os]["enforcement_info"]["check"] = {}
_yaml["platforms"]["macOS"][_os]["enforcement_info"]["check"]["shell"] = _yaml["platforms"][
"macOS"
][_os]["check"]
_yaml["platforms"]["macOS"][_os].pop("check")
if (
"result" in _yaml["platforms"]["macOS"][_os]
and "check" in _yaml["platforms"]["macOS"][_os]["enforcement_info"]
):
_yaml["platforms"]["macOS"][_os]["enforcement_info"]["check"]["result"] = _yaml["platforms"][
"macOS"
][_os]["result"]
_yaml["platforms"]["macOS"][_os].pop("result")
elif "result" in _yaml["platforms"]["macOS"][_os]:
_yaml["platforms"]["macOS"][_os].pop("result")
if "fix" in _yaml["platforms"]["macOS"][_os]:
if _yaml["platforms"]["macOS"]["fix"] == _yaml["platforms"]["macOS"][_os]["fix"]:
print(f"{_yaml['id']} - main fix matches fix of {_os}")
_yaml["platforms"]["macOS"][_os].pop("fix")
# move it into compliance object
if "fix" in _yaml["platforms"]["macOS"][_os]:
fix_code, fix_note = cleanup_fix(_yaml["platforms"]["macOS"][_os]["fix"])
_yaml["platforms"]["macOS"][_os]["enforcement_info"]["fix"] = {}
if fix_code:
_yaml["platforms"]["macOS"][_os]["enforcement_info"]["fix"]["shell"] = fix_code
if fix_note:
_yaml["platforms"]["macOS"][_os]["enforcement_info"]["fix"]["additional_info"] = fix_note
_yaml["platforms"]["macOS"][_os].pop("fix")
if _yaml["platforms"]["macOS"][_os]["enforcement_info"] == {}:
_yaml["platforms"]["macOS"][_os].pop("enforcement_info")
_yaml["platforms"]["macOS"]["enforcement_info"] = {}
if "check" in _yaml["platforms"]["macOS"]:
_yaml["platforms"]["macOS"]["enforcement_info"]["check"] = {}
_yaml["platforms"]["macOS"]["enforcement_info"]["check"]["shell"] = _yaml["platforms"]["macOS"][
"check"
]
_yaml["platforms"]["macOS"].pop("check")
if "result" in _yaml["platforms"]["macOS"]:
_yaml["platforms"]["macOS"]["enforcement_info"]["check"]["result"] = _yaml["platforms"]["macOS"][
"result"
]
_yaml["platforms"]["macOS"].pop("result")
if "fix" in _yaml["platforms"]["macOS"]:
fix_code, fix_note = cleanup_fix(_yaml["platforms"]["macOS"]["fix"])
if "inherently" not in fix_code and "permanent" not in fix_note:
_yaml["platforms"]["macOS"]["enforcement_info"]["fix"] = {}
if fix_code:
_yaml["platforms"]["macOS"]["enforcement_info"]["fix"]["shell"] = fix_code
if fix_note:
_yaml["platforms"]["macOS"]["enforcement_info"]["fix"]["additional_info"] = fix_note
_yaml["platforms"]["macOS"].pop("fix")
if _yaml["platforms"]["macOS"]["enforcement_info"] == {}:
_yaml["platforms"]["macOS"].pop("enforcement_info")
# restructure benchmarks to include severity
for p in _yaml["platforms"].keys():
for o in _yaml["platforms"][p]:
if "benchmarks" in _yaml["platforms"][p][o]:
if "severity" in _yaml["platforms"][p][o]:
s = _yaml["platforms"][p][o]["severity"]
_yaml["platforms"][p][o].pop("severity")
else:
s = ""
_yaml["platforms"][p][o]["benchmarks"] = restructure_benchmarks(
_yaml["platforms"][p][o]["benchmarks"], s
)
elif "severity" in _yaml["platforms"][p][o]:
_yaml["platforms"][p][o].pop("severity")
# restructure benchmarks to include severity
# for p in _yaml['platforms'].keys():
# for o in _yaml['platforms'][p]:
# if "benchmarks" in _yaml['platforms'][p][o]:
# if "severity" in _yaml['platforms'][p][o]:
# s = _yaml['platforms'][p][o]['severity']
# else:
# s = ""
# _yaml['platforms'][p][o]['severity'] = restructure_severity(_yaml['platforms'][p][o]['benchmarks'], s)
# elif "severity" in _yaml['platforms'][p][o]:
# _yaml['platforms'][p][o].pop('severity')
# add the introduced data here
if "mobileconfig_info" in _yaml.keys():
os_list = list(_yaml["platforms"].keys())
for mobileconfig_payload in _yaml["mobileconfig_info"]:
payloadtype = mobileconfig_payload["PayloadType"]
payloadkeys = mobileconfig_payload["PayloadContent"]
# just get first key, since we can't identify multiple introduce versions
payloadkey = next(iter(payloadkeys[0]))
for opsys in os_list:
if payloadtype in apple_profiles.keys():
version = get_introduced(apple_profiles[payloadtype], payloadkey, opsys)
if version == "-1":
unknown_keys.append(payloadkey)
_yaml["platforms"][opsys]["introduced"] = version
else:
unknown_keys.append(payloadkey)
_yaml["platforms"][opsys]["introduced"] = "-1"
for platform in _yaml["platforms"].keys():
for _os in _yaml["platforms"][platform].keys():
if _os == "check" or _os == "fix" or _os == "result" or _os == "introduced":
continue
if (
"mobileconfig_info" in _yaml["platforms"][platform][_os].keys()
and _yaml["mobileconfig_info"] == _yaml["platforms"][platform][_os]["mobileconfig_info"]
):
_yaml["platforms"][platform][_os].pop("mobileconfig_info")
if "odv" in _yaml.keys():
description = _yaml["odv"]["hint"]
datatype = None
validation = None
for r in odv_json:
if r["ruleId"] == _yaml["id"]:
datatype = r["type"]
if "note" in r.keys():
description = r["note"]
if "validation" in r.keys():
validation = r["validation"]
_yaml["odv"]["hint"] = {}
_yaml["odv"]["hint"]["datatype"] = datatype
_yaml["odv"]["hint"]["description"] = description
_yaml["odv"]["hint"]["validation"] = validation
odv_rules.append(_yaml["id"])
with open(file, "w") as nf:
yaml.dump(remove_none_fields(_yaml), nf, Dumper=MyDumper, sort_keys=False, width=float("inf"))
print("\n\nthe following keys are not found in apple git")
for k in unknown_keys:
print(k)
print("\n\nthe following rules have ODVs to update")
for k in odv_rules:
print(k)
def replace_keys_by_path(data, path=None):
if path is None:
path = []
if isinstance(data, dict):
new_data = {}
for k, v in data.items():
current_path = path + [k]
new_k = k
if k == "visionos_2.0":
if path == ["references", "nist", "cce"]:
new_k = "visionos_2"
elif path == ["references", "disa", "disa_stig"]:
new_k = "visionos_2"
elif path == ["platforms", "visionOS"]:
new_k = "2.0"
# else:
# new_k = k # leave as-is
if k == "ios_18":
if path == ["platforms", "iOS"]:
new_k = "18.0"
# else:
# new_k = k # leave as-is
# Determine the replacement key
if k == "ios_16":
if path == ["platforms", "iOS"]:
new_k = "16.0"
# else:
# new_k = k # leave as-is
if k == "ios_17":
if path == ["platforms", "iOS"]:
new_k = "17.0"
# else:
# new_k = k # leave as-is
if k == "ios_18":
if path == ["platforms", "iOS"]:
new_k = "18.0"
# else:
# new_k = k # leave as-is
if k == "ventura":
if path == ["references", "nist", "cce"]:
new_k = "macos_13"
elif path == ["references", "disa", "disa_stig"]:
new_k = "macos_13"
elif path == ["references", "cis", "benchmark"]:
new_k = "macos_13"
elif path == ["platforms", "macOS"]:
new_k = "13.0"
# else:
# new_k = k # leave as-is
if k == "sonoma":
if path == ["references", "nist", "cce"]:
new_k = "macos_14"
elif path == ["references", "disa", "disa_stig"]:
new_k = "macos_14"
elif path == ["references", "cis", "benchmark"]:
new_k = "macos_14"
elif path == ["platforms", "macOS"]:
new_k = "14.0"
# else:
# new_k = k # leave as-is
if k == "sequoia":
if path == ["references", "nist", "cce"]:
new_k = "macos_15"
elif path == ["references", "disa", "disa_stig"]:
new_k = "macos_15"
elif path == ["references", "cis", "benchmark"]:
new_k = "macos_15"
elif path == ["platforms", "macOS"]:
new_k = "15.0"
# else:
# new_k = k # leave as-is
# else:
# new_k = k
new_data[new_k] = replace_keys_by_path(v, current_path)
return new_data
elif isinstance(data, list):
return [replace_keys_by_path(item, path) for item in data]
else:
return data
if __name__ == "__main__":
main()