forked from ComplianceAsCode/content
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstable_profile_ids.py
executable file
·126 lines (91 loc) · 4.18 KB
/
stable_profile_ids.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#!/usr/bin/python3
from __future__ import print_function
import os
import ssg.xml
import ssg.xccdf
import ssg.build_guides
import argparse
import glob
from collections import defaultdict
# Maps shortened benchmark IDs to list of profiles that need to be contained
# in said benchmarks. Delete the predictable prefix of each benchmark ID to get
# the shortened ID. For example xccdf_org.ssgproject.content_benchmark_RHEL-7
# becomes just RHEL-7. Apply the same to profile IDs:
# xccdf_org.ssgproject.content_profile_ospp42 becomes ospp42
STABLE_PROFILE_IDS = {
"FEDORA": ["standard", "ospp", "pci-dss"],
"RHEL-8": ["ospp", "pci-dss"],
}
BENCHMARK_TO_FILE_STEM = {
"FEDORA": "fedora",
"RHEL-8": "rhel8",
"RHEL-9": "rhel9"
}
BENCHMARK_ID_PREFIX = "xccdf_org.ssgproject.content_benchmark_"
PROFILE_ID_PREFIX = "xccdf_org.ssgproject.content_profile_"
def parse_args():
p = argparse.ArgumentParser()
p.add_argument("build_dir", type=str,
help="Directory with the datastreams that will be checked "
"for stable profile IDs. All files matching "
"$BUILD_DIR/ssg-*-ds.xml checked.")
return p.parse_args()
def gather_profiles_from_datastream(path, build_dir, profiles_per_benchmark):
input_tree = ssg.xml.ElementTree.parse(path)
benchmarks = ssg.xccdf.get_benchmark_id_title_map(input_tree)
if len(benchmarks) == 0:
raise RuntimeError(
"Expected input file '%s' to contain at least 1 xccdf:Benchmark. "
"No Benchmarks were found!" % (path)
)
benchmark_profile_pairs = ssg.build_guides.get_benchmark_profile_pairs(
input_tree, benchmarks)
for bench_id, profile_id, title in benchmark_profile_pairs:
bench_short_id = bench_id[len(BENCHMARK_ID_PREFIX):]
if respective_datastream_absent(bench_short_id, build_dir):
continue
if not bench_id.startswith(BENCHMARK_ID_PREFIX):
raise RuntimeError("Expected benchmark ID '%s' from '%s' to be "
"prefixed with '%s'."
% (bench_id, path, BENCHMARK_ID_PREFIX))
if not profile_id:
# default profile can be skipped, we know for sure that
# it will be present in all benchmarks
continue
if not profile_id.startswith(PROFILE_ID_PREFIX):
raise RuntimeError("Expected profile ID '%s' from '%s' to be "
"prefixed with '%s'."
% (profile_id, path, PROFILE_ID_PREFIX))
profile_id = profile_id[len(PROFILE_ID_PREFIX):]
profiles_per_benchmark[bench_short_id].append(profile_id)
def respective_datastream_absent(bench_id, build_dir):
if bench_id not in BENCHMARK_TO_FILE_STEM:
return True
datastream_filename = "ssg-{stem}-ds.xml".format(stem=BENCHMARK_TO_FILE_STEM[bench_id])
datastream_path = os.path.join(build_dir, datastream_filename)
if not os.path.isfile(datastream_path):
return True
else:
return False
def check_build_dir(build_dir):
profiles_per_benchmark = defaultdict(list)
for path in glob.glob(os.path.join(build_dir, "ssg-*-ds.xml")):
gather_profiles_from_datastream(path, build_dir, profiles_per_benchmark)
for bench_short_id in STABLE_PROFILE_IDS.keys():
if respective_datastream_absent(bench_short_id, build_dir):
continue
if bench_short_id not in profiles_per_benchmark:
raise RuntimeError("Expected benchmark ID '%s' has to be "
"prefixed with '%s'."
% (bench_short_id, BENCHMARK_ID_PREFIX))
for profile_id in STABLE_PROFILE_IDS[bench_short_id]:
if profile_id not in profiles_per_benchmark[bench_short_id]:
raise RuntimeError("Profile '%s' is required to be in the "
"'%s' benchmark. It is a stable profile "
"that can't be renamed or removed!"
% (profile_id, bench_short_id))
def main():
args = parse_args()
check_build_dir(args.build_dir)
if __name__ == "__main__":
main()