Skip to content

Commit 2dacfd1

Browse files
committed
Merge branch 'dev_2.0_oval_disa' into dev_2.0
2 parents a86f63f + 77ecc6c commit 2dacfd1

File tree

2 files changed

+88
-58
lines changed

2 files changed

+88
-58
lines changed

src/mscp/cli.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ def parse_cli() -> None:
302302
"scap",
303303
help="generate xccdf, oval, or scap datastream",
304304
parents=[parent_parser],
305+
formatter_class=SmartFormatter,
305306
add_help=False,
306307
)
307308
scap_parser.set_defaults(func=generate_scap)
@@ -333,6 +334,12 @@ def parse_cli() -> None:
333334
help="list the available keywords that can be used to generate the SCAP content from",
334335
action="store_true",
335336
)
337+
scap_parser.add_argument(
338+
"--disa_stig",
339+
default=None,
340+
help="supply path DISA STIG XCCDF file to generate an OVAL file replacing the title with SRG and Vuln IDs from the DISA STIG",
341+
type=validate_file
342+
)
336343

337344
# local_report_parser: argparse.ArgumentParser = subparsers.add_parser(
338345
# "local_report",

src/mscp/generate/scap.py

Lines changed: 81 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import argparse
55
import sys
66
import time
7+
import re
78
from datetime import datetime
89
from pathlib import Path
910
from xml.sax.saxutils import escape
@@ -35,6 +36,22 @@ def pretty_format_xml(xml_string: str) -> str:
3536
[line for line in pretty_xml_as_string.split("\n") if line.strip()]
3637
)
3738

39+
def disa_stig_rules(stig_id, stig):
40+
newtitle = str()
41+
regex = r"<title>(SRG.*\d)<\/title>.*.{}".format(stig_id)
42+
matches = re.search(regex,stig)
43+
#SRG
44+
if matches:
45+
newtitle = str(matches.group(1))
46+
47+
regex = r"Rule id=\"(.*\S)\" we.*.{}".format(stig_id)
48+
matches = re.search(regex,stig)
49+
#RuleID
50+
if matches:
51+
newtitle = newtitle + ", " + str(matches.group(1).split("_")[0])
52+
53+
# srg-123-456. SV-7891234
54+
return newtitle
3855

3956
@inject_spinner()
4057
def generate_scap(sp: Yaspin, args: argparse.Namespace) -> None:
@@ -147,8 +164,8 @@ def replace_vars(text: str) -> str:
147164
odv_tag = b
148165
except (TypeError, KeyError) as e:
149166
logger.warning(f"Error when looking up ODV for {rule.rule_id}: {e}")
150-
151-
rule._fill_in_odv(b)
167+
newrule = rule.model_copy(deep=True)
168+
newrule._fill_in_odv(b)
152169

153170
xccdfProfiles = (
154171
xccdfProfiles
@@ -243,30 +260,36 @@ def replace_vars(text: str) -> str:
243260
selected_os_benchmark = []
244261
for benchmark, v in benchmark_map.items():
245262
if list(v)[0].lower() == args.os_name.lower():
246-
if args.baseline != "all_rules":
263+
if args.baseline != "all_rules":
247264
if benchmark == args.baseline:
248-
selected_os_benchmark.append(benchmark)
265+
selected_os_benchmark.append(benchmark)
249266
else:
250-
selected_os_benchmark.append(benchmark)
251-
267+
selected_os_benchmark.append(benchmark)
268+
if args.disa_stig and args.oval and args.baseline == "disa_stig":
269+
file = open(args.disa_stig, "r")
270+
stig = file.read()
271+
rule.title = disa_stig_rules(rule.references.get_ref("disa_stig")[0], stig)
252272
if rule.odv is not None:
253273
if args.baseline == "all_rules":
254274
selected_os_benchmark.append("recommended")
255-
for k, _ in rule.odv.items():
275+
276+
for k, _ in rule.odv.items():
277+
newrule = rule.model_copy(deep=True)
256278
if k == "hint":
257279
continue
258280
check_existence = ""
259281
check_value = ""
260-
count_found = False
261-
if k in selected_os_benchmark:
282+
count_found = False
283+
if k in selected_os_benchmark:
262284
check_content = str()
263285
if args.xccdf is None and args.oval is None:
264286
check_content = """<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5"><check-content-ref href="oval.xml" name="oval:mscp:def:{}"/></check>""".format(
265287
oval_counter
266288
)
267-
rule._fill_in_odv(k)
268-
fix_value = "none" if rule.fix is None else escape(rule.fix)
269-
check_value = "none" if rule.check is None else escape(rule.check)
289+
290+
newrule._fill_in_odv(k)
291+
fix_value = "none" if newrule.fix is None else escape(newrule.fix)
292+
check_value = "none" if newrule.check is None else escape(newrule.check)
270293
count_found = False
271294
check_existence = "all_exist"
272295
if " 2> /dev/null" in check_value:
@@ -284,7 +307,7 @@ def replace_vars(text: str) -> str:
284307
"/usr/bin/grep -c ", "/usr/bin/grep "
285308
)
286309
count_found = True
287-
if rule.result_value == 0:
310+
if newrule.result_value == 0:
288311
check_existence = "none_exist"
289312

290313
if "launchctl list" in check_value:
@@ -306,7 +329,7 @@ def replace_vars(text: str) -> str:
306329
count_found = True
307330

308331
check_value = "|".join(new_test)
309-
if rule.result_value == 0:
332+
if newrule.result_value == 0:
310333
check_existence = "none_exist"
311334

312335
if "$CURRENT_USER" in check_value:
@@ -325,68 +348,68 @@ def replace_vars(text: str) -> str:
325348
rule["rule_id"],
326349
k,
327350
rule.severity,
328-
rule["title"],
329-
escape(rule["discussion"]),
351+
newrule["title"],
352+
escape(newrule["discussion"]),
330353
check_value,
331-
rule.result_value,
354+
newrule.result_value,
332355
xccdf_references,
333-
rule["references"].nist.cce,
356+
rule.references.get_ref("cce")[0],
334357
fix_value,
335358
check_content,
336359
)
337360
)
338361

339-
if args.os_name == "macos":
340-
oval_def = (
341-
oval_def
342-
+ """<definition id="oval:mscp:def:{0}" version="1" class="compliance"><metadata><title>{1}</title><reference source="CCE" ref_id="{2}"/><reference source="macos_security" ref_id="{3}_{4}"/><description>{5}</description></metadata><criteria><criterion comment="{3}_{4}" test_ref="oval:mscp:tst:{0}"/></criteria></definition>""".format(
343-
oval_counter,
344-
rule["title"],
345-
rule["references"].nist.cce,
346-
rule["rule_id"],
347-
k,
348-
escape(rule["discussion"]),
362+
if args.os_name == "macos":
363+
oval_def = (
364+
oval_def
365+
+ """<definition id="oval:mscp:def:{0}" version="1" class="compliance"><metadata><title>{1}</title><reference source="CCE" ref_id="{2}"/><reference source="macos_security" ref_id="{3}_{4}"/><description>{5}</description></metadata><criteria><criterion comment="{3}_{4}" test_ref="oval:mscp:tst:{0}"/></criteria></definition>""".format(
366+
oval_counter,
367+
newrule["title"],
368+
rule.references.get_ref("cce")[0],
369+
rule["rule_id"],
370+
k,
371+
escape(newrule["discussion"]),
372+
)
349373
)
350-
)
351374

352-
oval_tests = (
353-
oval_tests
354-
+ """<shellcommand_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" id="oval:mscp:tst:{0}" version="1" comment="{1}_{2}_test" check_existence="{3}" check="all"><object object_ref="oval:mscp:obj:{0}"/><state state_ref="oval:mscp:ste:{0}"/></shellcommand_test>""".format(
355-
oval_counter, rule.rule_id, k, check_existence
375+
oval_tests = (
376+
oval_tests
377+
+ """<shellcommand_test xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" id="oval:mscp:tst:{0}" version="1" comment="{1}_{2}_test" check_existence="{3}" check="all"><object object_ref="oval:mscp:obj:{0}"/><state state_ref="oval:mscp:ste:{0}"/></shellcommand_test>""".format(
378+
oval_counter, rule.rule_id, k, check_existence
379+
)
356380
)
357-
)
358381

359-
oval_objects = (
360-
oval_objects
361-
+ """<shellcommand_object xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" id="oval:mscp:obj:{0}" version="1" comment="{1}_{2}_object"><shell>zsh</shell><command>{3}</command></shellcommand_object>""".format(
362-
oval_counter, rule.rule_id, k, check_value
382+
oval_objects = (
383+
oval_objects
384+
+ """<shellcommand_object xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" id="oval:mscp:obj:{0}" version="1" comment="{1}_{2}_object"><shell>zsh</shell><command>{3}</command></shellcommand_object>""".format(
385+
oval_counter, rule.rule_id, k, check_value
386+
)
363387
)
364-
)
365388

366-
if count_found:
367-
if check_existence != "none_exist":
368-
oval_states = (
369-
oval_states
370-
+ """<shellcommand_state xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" id="oval:mscp:ste:{0}" version="1" comment="{1}_{2}_state"><stdout_line operation="pattern match">.*</stdout_line></shellcommand_state>""".format(
371-
oval_counter, rule.rule_id, k
389+
if count_found:
390+
if check_existence != "none_exist":
391+
oval_states = (
392+
oval_states
393+
+ """<shellcommand_state xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" id="oval:mscp:ste:{0}" version="1" comment="{1}_{2}_state"><stdout_line operation="pattern match">.*</stdout_line></shellcommand_state>""".format(
394+
oval_counter, rule.rule_id, k
395+
)
372396
)
373-
)
397+
else:
398+
oval_states = (
399+
oval_states
400+
+ """<shellcommand_state xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" id="oval:mscp:ste:{0}" version="1" comment="{1}_{2}_state"><stdout_line check_existence="none_exist" /></shellcommand_state>""".format(
401+
oval_counter, rule.rule_id, k
402+
)
403+
)
404+
374405
else:
375406
oval_states = (
376407
oval_states
377-
+ """<shellcommand_state xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" id="oval:mscp:ste:{0}" version="1" comment="{1}_{2}_state"><stdout_line check_existence="none_exist" /></shellcommand_state>""".format(
378-
oval_counter, rule.rule_id, k
408+
+ """<shellcommand_state xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" id="oval:mscp:ste:{0}" version="1" comment="{1}_{2}state"><stdout_line operation="equals">{3}</stdout_line></shellcommand_state>""".format(
409+
oval_counter, rule.rule_id, k, newrule.result_value
379410
)
380411
)
381412

382-
else:
383-
oval_states = (
384-
oval_states
385-
+ """<shellcommand_state xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" id="oval:mscp:ste:{0}" version="1" comment="{1}_{2}state"><stdout_line operation="equals">{3}</stdout_line></shellcommand_state>""".format(
386-
oval_counter, rule.rule_id, k, rule.result_value
387-
)
388-
)
389-
390413
else:
391414
fix_value = "none" if rule.fix is None else escape(rule.fix)
392415
check_value = "none" if rule.check is None else escape(rule.check)
@@ -455,7 +478,7 @@ def replace_vars(text: str) -> str:
455478
check_value,
456479
rule.result_value,
457480
xccdf_references,
458-
rule["references"].nist.cce,
481+
rule.references.get_ref("cce")[0],
459482
fix_value,
460483
check_content,
461484
)
@@ -467,7 +490,7 @@ def replace_vars(text: str) -> str:
467490
+ """<definition id="oval:mscp:def:{0}" version="1" class="compliance"><metadata><title>{1}</title><reference source="CCE" ref_id="{2}"/><reference source="macos_security" ref_id="{3}_{4}"/><description>{5}</description></metadata><criteria><criterion comment="{3}_{4}" test_ref="oval:mscp:tst:{0}"/></criteria></definition>""".format(
468491
oval_counter,
469492
rule["title"],
470-
rule["references"].nist.cce,
493+
rule.references.get_ref("cce")[0],
471494
rule["rule_id"],
472495
"recommended",
473496
escape(rule["discussion"]),

0 commit comments

Comments
 (0)