Skip to content

Commit 73e6fea

Browse files
committed
autotailor: Add groups override to JSON tailoring
Also fix some small issues.
1 parent 4112838 commit 73e6fea

File tree

4 files changed

+59
-21
lines changed

4 files changed

+59
-21
lines changed

tests/utils/autotailor_integration_test.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ assert_exists 1 '/Benchmark/TestResult/set-value[@idref="xccdf_com.example.www_v
120120
assert_exists 1 '/Benchmark/TestResult/set-value[@idref="xccdf_com.example.www_value_V2" and text()="Some Value"]'
121121
assert_exists 1 '/Benchmark/TestResult/rule-result[@idref="xccdf_com.example.www_rule_R1"]/result[text()="notselected"]'
122122
assert_exists 1 '/Benchmark/TestResult/rule-result[@idref="xccdf_com.example.www_rule_R2"]/result[text()="pass"]'
123-
assert_exists 1 '/Benchmark/TestResult/rule-result[@idref="xccdf_com.example.www_rule_R3"]/result[text()="notchecked"]'
124-
assert_exists 1 '/Benchmark/TestResult/rule-result[@idref="xccdf_com.example.www_rule_R3" and @role="unchecked"]'
123+
assert_exists 1 '/Benchmark/TestResult/rule-result[@idref="xccdf_com.example.www_rule_R3"]/result[text()="notselected"]'
125124
assert_exists 1 '/Benchmark/TestResult/rule-result[@idref="xccdf_com.example.www_rule_R3" and @severity="unknown"]'
126125
assert_exists 1 '/Benchmark/TestResult/rule-result[@idref="xccdf_com.example.www_rule_R4"]/result[text()="notselected"]'
126+
assert_exists 1 '/Benchmark/TestResult/rule-result[@idref="xccdf_com.example.www_rule_R4" and @role="unchecked"]'

tests/utils/custom.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,22 @@
44
"id": "JSON_P1",
55
"title": "JSON Tailored Profile P1",
66
"base_profile_id": "P1",
7+
"groups": {
8+
"G34": {
9+
"evaluate": false
10+
}
11+
},
712
"rules": {
813
"R1": {
914
"evaluate": false
1015
},
1116
"R3": {
1217
"evaluate": true,
13-
"role": "unchecked",
1418
"severity": "unknown"
19+
},
20+
"R4": {
21+
"evaluate": true,
22+
"role": "unchecked"
1523
}
1624
},
1725
"variables": {

tests/utils/data_stream.xml

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -93,20 +93,24 @@
9393
<check-content-ref href="test_single_rule.oval.xml" name="oval:x:def:1"/>
9494
</check>
9595
</Rule>
96-
<Rule selected="false" id="xccdf_com.example.www_rule_R3">
97-
<title>Rule R3</title>
98-
<description>Description</description>
99-
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
100-
<check-content-ref href="test_single_rule.oval.xml" name="oval:x:def:1"/>
101-
</check>
102-
</Rule>
103-
<Rule selected="false" id="xccdf_com.example.www_rule_R4">
104-
<title>Rule R4</title>
105-
<description>Description</description>
106-
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
107-
<check-content-ref href="test_single_rule.oval.xml" name="oval:x:def:1"/>
108-
</check>
109-
</Rule>
110-
</Benchmark>
96+
<Group selected="true" id="xccdf_com.example.www_group_G34">
97+
<title>group R3, R4</title>
98+
<description>description</description>
99+
<Rule selected="false" id="xccdf_com.example.www_rule_R3">
100+
<title>Rule R3</title>
101+
<description>Description</description>
102+
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
103+
<check-content-ref href="test_single_rule.oval.xml" name="oval:x:def:1"/>
104+
</check>
105+
</Rule>
106+
<Rule selected="false" id="xccdf_com.example.www_rule_R4">
107+
<title>Rule R4</title>
108+
<description>Description</description>
109+
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
110+
<check-content-ref href="test_single_rule.oval.xml" name="oval:x:def:1"/>
111+
</check>
112+
</Rule>
113+
</Group>
114+
</Benchmark>
111115
</ds:component>
112116
</ds:data-stream-collection>

utils/autotailor

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import sys
2525
import pathlib
2626
import xml.etree.ElementTree as ET
2727
import xml.dom.minidom
28+
import json
2829

2930

3031
NS = "http://checklists.nist.gov/xccdf/1.2"
@@ -64,6 +65,8 @@ class Tailoring:
6465
self.value_changes = []
6566
self.rules_to_select = []
6667
self.rules_to_unselect = []
68+
self.groups_to_select = []
69+
self.groups_to_unselect = []
6770
self._rule_refinements = collections.defaultdict(dict)
6871
self._value_refinements = collections.defaultdict(dict)
6972

@@ -187,9 +190,23 @@ class Tailoring:
187190
def _full_rule_id(self, string):
188191
return self._full_id(string, "rule")
189192

193+
def _full_group_id(self, string):
194+
return self._full_id(string, "group")
195+
190196
def add_value_change(self, varname, value):
191197
self.value_changes.append((varname, value))
192198

199+
def _add_group_select_operations(self, container_element):
200+
for group_id in self.groups_to_select:
201+
change = ET.SubElement(container_element, "{%s}select" % NS)
202+
change.set("idref", self._full_group_id(group_id))
203+
change.set("selected", "true")
204+
205+
for group_id in self.groups_to_unselect:
206+
change = ET.SubElement(container_element, "{%s}select" % NS)
207+
change.set("idref", self._full_group_id(group_id))
208+
change.set("selected", "false")
209+
193210
def _add_rule_select_operations(self, container_element):
194211
for rule_id in self.rules_to_select:
195212
change = ET.SubElement(container_element, "{%s}select" % NS)
@@ -246,6 +263,7 @@ class Tailoring:
246263
title.set("override", "false")
247264
title.text = self.profile_title
248265

266+
self._add_group_select_operations(profile)
249267
self._add_rule_select_operations(profile)
250268
self._add_value_overrides(profile)
251269
self.rule_refinements_to_xml(profile)
@@ -257,12 +275,12 @@ class Tailoring:
257275
f.write(pretty_xml)
258276

259277
def import_json_tailoring(self, json_tailoring):
260-
import json
261278
with open(json_tailoring, "r") as jf:
262279
all_tailorings = json.load(jf)
263280

264281
if 'profiles' in all_tailorings and all_tailorings['profiles']:
265-
# We currently support tailoring of one profile only
282+
if len(all_tailorings['profiles']) > 1:
283+
raise ValueError("The autotailor tool currently does not support multi-profile JSON tailoring.")
266284
tailoring = all_tailorings['profiles'][0]
267285
else:
268286
raise ValueError("JSON Tailoring does not define any profiles.")
@@ -272,6 +290,14 @@ class Tailoring:
272290
self.profile_id = tailoring.get("id", self.profile_id)
273291
self.profile_title = tailoring.get("title", self.profile_title)
274292

293+
if "groups" in tailoring:
294+
for group_id, props in tailoring["groups"].items():
295+
if "evaluate" in props:
296+
if props["evaluate"]:
297+
self.groups_to_select.append(group_id)
298+
else:
299+
self.groups_to_unselect.append(group_id)
300+
275301
if "rules" in tailoring:
276302
for rule_id, props in tailoring["rules"].items():
277303
if "evaluate" in props:
@@ -304,7 +330,7 @@ def get_parser():
304330
"either its full ID, or the suffix, in which case the "
305331
"'xccdf_<id-namespace>_profile' prefix will be prepended internally.")
306332
parser.add_argument(
307-
"--json-tailoring", metavar="JSON_TAILORING_FILENAME", default="",
333+
"-j", "--json-tailoring", metavar="JSON_TAILORING_FILENAME", default="",
308334
help="JSON Tailoring (https://github.com/ComplianceAsCode/schemas/blob/main/tailoring/schema.json) "
309335
"filename.")
310336
parser.add_argument(

0 commit comments

Comments
 (0)