Skip to content

Commit e5e50ea

Browse files
authored
Merge pull request OpenSCAP#2344 from ggbecker/autotailor-validate-datastream-fields-maint-1.3
Backport: Autotailor validate datastream fields maint 1.3
2 parents a9f8018 + 77ab548 commit e5e50ea

4 files changed

Lines changed: 365 additions & 16 deletions

File tree

tests/utils/autotailor_integration_test.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,17 @@ assert_exists 1 '/Benchmark/TestResult/rule-result[@idref="xccdf_com.example.www
114114
assert_exists 1 '/Benchmark/TestResult/rule-result[@idref="xccdf_com.example.www_rule_R3"]/result[text()="notselected"]'
115115
assert_exists 1 '/Benchmark/TestResult/rule-result[@idref="xccdf_com.example.www_rule_R4"]/result[text()="notselected"]'
116116

117+
# invalid selector for V1 should fail with a descriptive error
118+
! python3 $autotailor --id-namespace "com.example.www" --var-select V1=invalid $ds $original_profile 2>$stdout
119+
grep "Selector 'invalid' does not exist" $stdout
120+
121+
# invalid selector for V2 should fail with available selectors listed
122+
! python3 $autotailor --id-namespace "com.example.www" --var-select V2=invalid $ds $original_profile 2>$stdout
123+
grep "Available selectors" $stdout
124+
125+
# --no-validate bypasses selector validation
126+
python3 $autotailor --id-namespace "com.example.www" --no-validate --var-select V1=invalid $ds $original_profile > $tailoring
127+
117128
# use JSON tailoring
118129
python3 $autotailor $ds --id-namespace "com.example.www" --json-tailoring $json_tailoring > $tailoring
119130
$OSCAP xccdf eval --profile JSON_P1 --progress --tailoring-file $tailoring --results $result $ds

tests/utils/test_autotailor.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import importlib
2+
import pathlib
23
import pytest
34

45
NS = "http://checklists.nist.gov/xccdf/1.2"
@@ -120,3 +121,146 @@ def test_get_datastream_uri():
120121
uri = t._get_datastream_uri()
121122
assert uri.startswith("file://")
122123
assert "relative/path/to/ds.xml" in uri
124+
125+
126+
def test_datastream_validator():
127+
"""Test that DataStreamValidator properly validates IDs."""
128+
ds_path = pathlib.Path(__file__).parent.joinpath("data_stream.xml")
129+
validator = autotailor.DataStreamValidator(str(ds_path))
130+
131+
# Test valid profile validation
132+
validator.validate_profile("xccdf_com.example.www_profile_P1")
133+
134+
# Test valid value validation
135+
validator.validate_value("xccdf_com.example.www_value_V1")
136+
validator.validate_value("xccdf_com.example.www_value_V2")
137+
138+
# Test valid rule validation
139+
validator.validate_rule("xccdf_com.example.www_rule_R1")
140+
validator.validate_rule("xccdf_com.example.www_rule_R2")
141+
validator.validate_rule("xccdf_com.example.www_rule_R3")
142+
validator.validate_rule("xccdf_com.example.www_rule_R4")
143+
144+
# Test valid group validation
145+
validator.validate_group("xccdf_com.example.www_group_G34")
146+
147+
# Test invalid profile
148+
with pytest.raises(ValueError) as e:
149+
validator.validate_profile("xccdf_com.example.www_profile_INVALID")
150+
assert "Profile ID 'xccdf_com.example.www_profile_INVALID' does not exist" in str(e.value)
151+
152+
# Test invalid value with suggestion
153+
with pytest.raises(ValueError) as e:
154+
validator.validate_value("xccdf_com.example.www_value_V3")
155+
assert "Value ID 'xccdf_com.example.www_value_V3' does not exist" in str(e.value)
156+
157+
# Test invalid rule with suggestion
158+
with pytest.raises(ValueError) as e:
159+
validator.validate_rule("xccdf_com.example.www_rule_R5")
160+
assert "Rule ID 'xccdf_com.example.www_rule_R5' does not exist" in str(e.value)
161+
162+
# Test invalid group
163+
with pytest.raises(ValueError) as e:
164+
validator.validate_group("xccdf_com.example.www_group_INVALID")
165+
assert "Group ID 'xccdf_com.example.www_group_INVALID' does not exist" in str(e.value)
166+
167+
168+
def test_profile_with_validator():
169+
"""Test that Tailoring uses validator to check IDs."""
170+
ds_path = pathlib.Path(__file__).parent.joinpath("data_stream.xml")
171+
validator = autotailor.DataStreamValidator(str(ds_path))
172+
173+
p = autotailor.Tailoring(validator=validator)
174+
p.reverse_dns = "com.example.www"
175+
176+
# Test valid variable change works
177+
p.add_value_change("V1", "30")
178+
179+
# Test invalid variable name fails
180+
with pytest.raises(ValueError) as e:
181+
p.add_value_change("INVALID_VAR", "test")
182+
assert "Value ID 'xccdf_com.example.www_value_INVALID_VAR' does not exist" in str(e.value)
183+
184+
# Test valid rule selection works
185+
p.select_rule("R1")
186+
187+
# Test invalid rule selection fails
188+
with pytest.raises(ValueError) as e:
189+
p.select_rule("INVALID_RULE")
190+
assert "Rule ID 'xccdf_com.example.www_rule_INVALID_RULE' does not exist" in str(e.value)
191+
192+
# Test valid base profile validation
193+
p.validate_base_profile("P1")
194+
195+
# Test invalid base profile fails
196+
with pytest.raises(ValueError) as e:
197+
p.validate_base_profile("INVALID_PROFILE")
198+
assert "Profile ID 'xccdf_com.example.www_profile_INVALID_PROFILE' does not exist" in str(e.value)
199+
200+
201+
def test_validator_suggestions():
202+
"""Test that validator provides helpful suggestions for typos."""
203+
ds_path = pathlib.Path(__file__).parent.joinpath("data_stream.xml")
204+
validator = autotailor.DataStreamValidator(str(ds_path))
205+
206+
# Test suggestion for value with typo (V11 instead of V1)
207+
with pytest.raises(ValueError) as e:
208+
validator.validate_value("xccdf_com.example.www_value_V11")
209+
error_msg = str(e.value)
210+
assert "Did you mean one of these?" in error_msg
211+
assert "xccdf_com.example.www_value_V1" in error_msg
212+
213+
# Test suggestion for rule with typo (R11 instead of R1)
214+
with pytest.raises(ValueError) as e:
215+
validator.validate_rule("xccdf_com.example.www_rule_R11")
216+
error_msg = str(e.value)
217+
assert "Did you mean one of these?" in error_msg
218+
assert "xccdf_com.example.www_rule_R1" in error_msg
219+
220+
221+
def test_validate_selector():
222+
"""Test that validate_selector rejects selectors not present in the data stream."""
223+
ds_path = pathlib.Path(__file__).parent.joinpath("data_stream.xml")
224+
validator = autotailor.DataStreamValidator(str(ds_path))
225+
226+
# V1 has selector "thirty"; V2 has "some" and "other"
227+
validator.validate_selector("xccdf_com.example.www_value_V1", "thirty")
228+
validator.validate_selector("xccdf_com.example.www_value_V2", "some")
229+
validator.validate_selector("xccdf_com.example.www_value_V2", "other")
230+
231+
# Invalid selector for V1
232+
with pytest.raises(ValueError) as e:
233+
validator.validate_selector("xccdf_com.example.www_value_V1", "invalid")
234+
error_msg = str(e.value)
235+
assert "Selector 'invalid' does not exist for Value 'xccdf_com.example.www_value_V1'" in error_msg
236+
assert "thirty" in error_msg
237+
238+
# Invalid selector for V2 with a close-enough typo triggers a suggestion
239+
with pytest.raises(ValueError) as e:
240+
validator.validate_selector("xccdf_com.example.www_value_V2", "ther")
241+
error_msg = str(e.value)
242+
assert "Selector 'ther' does not exist for Value 'xccdf_com.example.www_value_V2'" in error_msg
243+
assert "other" in error_msg
244+
245+
246+
def test_profile_selector_validation():
247+
"""Test that Tailoring validates selectors via -V/--var-select through refine_value."""
248+
ds_path = pathlib.Path(__file__).parent.joinpath("data_stream.xml")
249+
validator = autotailor.DataStreamValidator(str(ds_path))
250+
251+
p = autotailor.Tailoring(validator=validator)
252+
p.reverse_dns = "com.example.www"
253+
254+
# Valid selector passes
255+
p.change_selectors(["V1=thirty"])
256+
p.change_selectors(["V2=some"])
257+
258+
# Invalid selector raises
259+
with pytest.raises(ValueError) as e:
260+
p.change_selectors(["V1=invalid"])
261+
assert "Selector 'invalid' does not exist for Value 'xccdf_com.example.www_value_V1'" in str(e.value)
262+
263+
# Invalid value ID still raises before reaching selector check
264+
with pytest.raises(ValueError) as e:
265+
p.change_selectors(["NONEXISTENT=thirty"])
266+
assert "Value ID 'xccdf_com.example.www_value_NONEXISTENT' does not exist" in str(e.value)

0 commit comments

Comments
 (0)