mirror of
https://github.com/usnistgov/macos_security.git
synced 2026-03-04 01:12:00 +00:00
233 lines
7.6 KiB
Python
Executable File
233 lines
7.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# filename: create_guide.py
|
|
# description: Create AsciiDoc guide from YAML
|
|
|
|
import argparse
|
|
import io
|
|
import yaml
|
|
import os
|
|
from string import Template
|
|
from itertools import groupby
|
|
import glob
|
|
|
|
# Convert a list to AsciiDoc
|
|
def ulify(elements):
|
|
string = "\n"
|
|
for s in elements:
|
|
string += "* " + str(s) + "\n"
|
|
return string
|
|
|
|
def group_ulify(elements):
|
|
string = "\n * "
|
|
for s in elements:
|
|
string += str(s) + ", "
|
|
return string[:-2]
|
|
|
|
|
|
# Setup argparse
|
|
parser = argparse.ArgumentParser(
|
|
description='Given a baseline, create an AsciiDoc guide.')
|
|
parser.add_argument("baseline", default=None,
|
|
help="Baseline YAML file used to create the guide.", type=argparse.FileType('rt'))
|
|
parser.add_argument("-o", "--output", default=None,
|
|
help="Output file", type=argparse.FileType('wt'))
|
|
|
|
try:
|
|
results = parser.parse_args()
|
|
output_basename = os.path.basename(results.baseline.name)
|
|
output_filename = os.path.splitext(output_basename)[0]
|
|
if results.output:
|
|
output_file = results.output
|
|
else:
|
|
output_file = open("../build/{}.adoc".format(output_filename), 'w')
|
|
print('Profile YAML:', results.baseline.name)
|
|
print('Output file:', output_file.name)
|
|
except IOError as msg:
|
|
parser.error(str(msg))
|
|
|
|
# Read the profile YAML details
|
|
profile_yaml = yaml.load(results.baseline, Loader=yaml.SafeLoader)
|
|
|
|
# Setup AsciiDoc templates
|
|
with open('../templates/adoc_rule.adoc') as adoc_rule_file:
|
|
adoc_rule_template = Template(adoc_rule_file.read())
|
|
|
|
with open('../templates/adoc_supplemental.adoc') as adoc_supplemental_file:
|
|
adoc_supplemental_template = Template(adoc_supplemental_file.read())
|
|
|
|
with open('../templates/adoc_rule_no_setting.adoc') as adoc_rule_no_setting_file:
|
|
adoc_rule_no_setting_template = Template(adoc_rule_no_setting_file.read())
|
|
|
|
with open('../templates/adoc_section.adoc') as adoc_section_file:
|
|
adoc_section_template = Template(adoc_section_file.read())
|
|
|
|
with open('../templates/adoc_header.adoc') as adoc_header_file:
|
|
adoc_header_template = Template(adoc_header_file.read())
|
|
|
|
with open('../templates/adoc_footer.adoc') as adoc_footer_file:
|
|
adoc_footer_template = Template(adoc_footer_file.read())
|
|
|
|
# Create header
|
|
header_adoc = adoc_header_template.substitute(
|
|
profile_title = profile_yaml['title'],
|
|
description = profile_yaml['description']
|
|
)
|
|
|
|
# Output header
|
|
output_file.write(header_adoc)
|
|
|
|
# Create sections and rules
|
|
for sections in profile_yaml['profile']:
|
|
section_yaml_file=sections['section'].lower() + '.yaml'
|
|
#check for custom section
|
|
if section_yaml_file in glob.glob1('../custom/sections/', '*.yaml'):
|
|
print(f"Custom settings found for section: {sections['section']}")
|
|
override_section = os.path.join('../custom/sections', sections['section'] + '.yaml')
|
|
with open(override_section) as r:
|
|
section_yaml = yaml.load(r, Loader=yaml.SafeLoader)
|
|
else:
|
|
with open('../sections/' + sections['section'] + '.yaml') as s:
|
|
section_yaml = yaml.load(s, Loader=yaml.SafeLoader)
|
|
|
|
# Read section info and output it
|
|
|
|
|
|
section_adoc = adoc_section_template.substitute(
|
|
section_name = section_yaml['name'],
|
|
description = section_yaml['description']
|
|
)
|
|
|
|
output_file.write(section_adoc)
|
|
|
|
|
|
# Read all rules in the section and output them
|
|
|
|
for rule in sections['rules']:
|
|
print(rule)
|
|
rule_path = glob.glob('../rules/*/{}.yaml'.format(rule))
|
|
rule_file = (os.path.basename(rule_path[0]))
|
|
|
|
#check for custom rule
|
|
if rule_file in glob.glob1('../custom/rules/', '*.yaml'):
|
|
print(f"Custom settings found for rule: {rule_file}")
|
|
override_rule = os.path.join('../custom/rules', rule_file)
|
|
with open(override_rule) as r:
|
|
rule_yaml = yaml.load(r, Loader=yaml.SafeLoader)
|
|
else:
|
|
with open(rule_path[0]) as r:
|
|
rule_yaml = yaml.load(r, Loader=yaml.SafeLoader)
|
|
|
|
|
|
|
|
# Determine if the references exist and set accordingly
|
|
try:
|
|
rule_yaml['references']['cci']
|
|
except KeyError:
|
|
cci = 'N/A'
|
|
else:
|
|
cci = ulify(rule_yaml['references']['cci'])
|
|
|
|
try:
|
|
rule_yaml['references']['cce']
|
|
except KeyError:
|
|
cce = 'N/A'
|
|
else:
|
|
cce = ulify(rule_yaml['references']['cce'])
|
|
|
|
try:
|
|
rule_yaml['references']['800-53r4']
|
|
except KeyError:
|
|
nist_80053r4 = 'N/A'
|
|
else:
|
|
#nist_80053r4 = ulify(rule_yaml['references']['800-53r4'])
|
|
nist_80053r4 = rule_yaml['references']['800-53r4']
|
|
|
|
try:
|
|
rule_yaml['references']['disa_stig']
|
|
except KeyError:
|
|
disa_stig = 'N/A'
|
|
else:
|
|
disa_stig = ulify(rule_yaml['references']['disa_stig'])
|
|
|
|
try:
|
|
rule_yaml['references']['srg']
|
|
except KeyError:
|
|
srg = 'N/A'
|
|
else:
|
|
srg = ulify(rule_yaml['references']['srg'])
|
|
|
|
try:
|
|
rule_yaml['fix']
|
|
except KeyError:
|
|
rulefix = "No fix Found"
|
|
else:
|
|
rulefix = rule_yaml['fix']#.replace('|', '\|')
|
|
|
|
try:
|
|
rule_yaml['tags']
|
|
except KeyError:
|
|
tags = 'none'
|
|
else:
|
|
tags = rule_yaml['tags']
|
|
|
|
try:
|
|
result = rule_yaml['result']
|
|
except KeyError:
|
|
result = 'N/A'
|
|
|
|
if "integer" in result:
|
|
result_value=result['integer']
|
|
elif "boolean" in result:
|
|
result_value=result['boolean']
|
|
elif "string" in result:
|
|
result_value=result['string']
|
|
else:
|
|
result_value = 'N/A'
|
|
|
|
# process nist controls for grouping
|
|
nist_80053r4.sort()
|
|
res = [list(i) for j, i in groupby(nist_80053r4, lambda a: a.split('(')[0])]
|
|
nist_controls = ''
|
|
for i in res:
|
|
nist_controls += group_ulify(i)
|
|
|
|
if 'supplemental' in tags:
|
|
rule_adoc = adoc_supplemental_template.substitute(
|
|
rule_title=rule_yaml['title'].replace('|', '\|'),
|
|
rule_id=rule_yaml['id'].replace('|', '\|'),
|
|
rule_discussion=rule_yaml['discussion'],
|
|
)
|
|
# elif ('permanent' in tags) or ('inherent' in tags) or ('n_a' in tags):
|
|
# rule_adoc = adoc_rule_no_setting_template.substitute(
|
|
# rule_title=rule_yaml['title'].replace('|', '\|'),
|
|
# rule_id=rule_yaml['id'].replace('|', '\|'),
|
|
# rule_discussion=rule_yaml['discussion'].replace('|', '\|'),
|
|
# rule_check=rule_yaml['check'], # .replace('|', '\|'),
|
|
# rule_fix=rulefix,
|
|
# rule_80053r4=nist_controls,
|
|
# rule_disa_stig=disa_stig,
|
|
# rule_srg=srg
|
|
# )
|
|
else:
|
|
rule_adoc = adoc_rule_template.substitute(
|
|
rule_title = rule_yaml['title'].replace('|', '\|'),
|
|
rule_id = rule_yaml['id'].replace('|', '\|'),
|
|
rule_discussion = rule_yaml['discussion'].replace('|', '\|'),
|
|
rule_check = rule_yaml['check'],#.replace('|', '\|'),
|
|
rule_fix = rulefix,
|
|
rule_cci = cci,
|
|
rule_80053r4 = nist_controls,
|
|
rule_cce = cce,
|
|
rule_srg = srg,
|
|
rule_result = result_value
|
|
)
|
|
|
|
output_file.write(rule_adoc)
|
|
|
|
# Create footer
|
|
footer_adoc = adoc_footer_template.substitute(
|
|
)
|
|
|
|
# Output footer
|
|
output_file.write(footer_adoc)
|