|
1 | 1 | import importlib |
| 2 | +import pathlib |
2 | 3 | import pytest |
3 | 4 |
|
4 | 5 | NS = "http://checklists.nist.gov/xccdf/1.2" |
@@ -120,3 +121,146 @@ def test_get_datastream_uri(): |
120 | 121 | uri = t._get_datastream_uri() |
121 | 122 | assert uri.startswith("file://") |
122 | 123 | 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