Test Failed
Pull Request — master (#7876)
by Matthew
02:14
created

test_controls.test_load_control_from_folder()   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nop 0
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
import pytest
2
import logging
3
import os
4
5
import ssg.controls
6
import ssg.build_yaml
7
from ssg.environment import open_environment
8
from ssg.products import load_product_yaml
9
10
ssg_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
11
data_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "data"))
12
controls_dir = os.path.join(data_dir, "controls_dir")
13
profiles_dir = os.path.join(data_dir, "profiles_dir")
14
15
16
def _load_test(profile):
17
    product_yaml = os.path.join(ssg_root, "products", "rhel8", "product.yml")
18
    build_config_yaml = os.path.join(ssg_root, "build", "build_config.yml")
19
    env_yaml = open_environment(build_config_yaml, product_yaml)
20
    controls_manager = ssg.controls.ControlsManager(controls_dir, env_yaml)
21
    controls_manager.load()
22
    c_r1 = controls_manager.get_control(profile, "R1")
23
    assert c_r1.title == "User session timeout"
24
    assert c_r1.description == "Remote user sessions must be closed after " \
25
                               "a certain period of inactivity."
26
    assert c_r1.automated == "yes"
27
    c_r1_rules = c_r1.selected
28
    assert "sshd_set_idle_timeout" in c_r1_rules
29
    assert "accounts_tmout" in c_r1_rules
30
    assert "var_accounts_tmout=10_min" not in c_r1_rules
31
    assert "var_accounts_tmout" in c_r1.variables
32
    assert c_r1.variables["var_accounts_tmout"] == "10_min"
33
    # abcd is a level-less policy
34
    assert c_r1.levels == ["default"]
35
    assert "vague" in c_r1.notes
36
    c_r2 = controls_manager.get_control(profile, "R2")
37
    assert c_r2.automated == "no"
38
    assert c_r2.note == "This is individual depending on the system " \
39
                        "workload therefore needs to be audited manually."
40
    assert len(c_r2.selected) == 0
41
    assert not c_r2.notes
42
    c_r4 = controls_manager.get_control(profile, "R4")
43
    assert len(c_r4.selected) == 3
44
    c_r4_rules = c_r4.selected
45
    assert "accounts_passwords_pam_faillock_deny_root" in c_r4_rules
46
    assert "accounts_password_pam_minlen" in c_r4_rules
47
    assert "accounts_password_pam_ocredit" in c_r4_rules
48
    assert "var_password_pam_ocredit" in c_r4.variables
49
    assert c_r4.variables["var_password_pam_ocredit"] == "1"
50
51
52
def test_controls_load():
53
    _load_test("abcd")
54
55
56
def test_controls_levels():
57
    product_yaml = os.path.join(ssg_root, "products", "rhel8", "product.yml")
58
    build_config_yaml = os.path.join(ssg_root, "build", "build_config.yml")
59
    env_yaml = open_environment(build_config_yaml, product_yaml)
60
    controls_manager = ssg.controls.ControlsManager(controls_dir, env_yaml)
61
    controls_manager.load()
62
63
    # Default level is the lowest level
64
    c_1 = controls_manager.get_control("abcd-levels", "S1")
65
    assert c_1.levels == ["low"]
66
    c_4 = controls_manager.get_control("abcd-levels", "S4")
67
    assert c_4.levels == ["low"]
68
69
    # Explicit levels
70
    c_2 = controls_manager.get_control("abcd-levels", "S2")
71
    assert c_2.levels == ["low"]
72
73
    c_3 = controls_manager.get_control("abcd-levels", "S3")
74
    assert c_3.levels == ["medium"]
75
76
    c_4a = controls_manager.get_control("abcd-levels", "S4.a")
77
    assert c_4a.levels == ["low"]
78
79
    c_4b = controls_manager.get_control("abcd-levels", "S4.b")
80
    assert c_4b.levels == ["high"]
81
82
    # just the essential controls
83
    low_controls = controls_manager.get_all_controls_of_level(
84
        "abcd-levels", "low")
85
    # essential and more advanced together
86
    medium_controls = controls_manager.get_all_controls_of_level(
87
        "abcd-levels", "medium")
88
    high_controls = controls_manager.get_all_controls_of_level(
89
        "abcd-levels", "high")
90
    all_controls = controls_manager.get_all_controls("abcd-levels")
91
92
    assert len(high_controls) == len(all_controls)
93
    assert len(low_controls) <= len(high_controls)
94
    assert len(low_controls) == 4
95
    assert len(medium_controls) == 5
96
97
    # test overriding of variables in levels
98
    assert c_2.variables["var_password_pam_minlen"] == "1"
99
    assert "var_password_pam_minlen" not in c_3.variables.keys()
100
    assert c_4b.variables["var_password_pam_minlen"] == "2"
101
102
    for c in low_controls:
103
        if "var_password_pam_minlen" in c.variables.keys():
104
            assert c.variables["var_password_pam_minlen"] == "1"
105
106
    for c in medium_controls:
107
        if "var_password_pam_minlen" in c.variables.keys():
108
            assert c.variables["var_password_pam_minlen"] == "1"
109
110
    for c in high_controls:
111
        if "var_password_pam_minlen" in c.variables.keys():
112
            assert c.variables["var_password_pam_minlen"] == "2"
113
114
    # now test if controls of lower level has the variable definition correctly removed
115
    # because it is overriden by higher level controls
116
    s2_high = [c for c in high_controls if c.id == "S2"]
117
    assert len(s2_high) == 1
118
    assert "var_some_variable" not in s2_high[0].variables.keys()
119
    assert "var_password_pam_minlen" not in s2_high[0].variables.keys()
120
    s4b_high = [c for c in high_controls if c.id == "S4.b"]
121
    assert len(s4b_high) == 1
122
    assert s4b_high[0].variables["var_some_variable"] == "3"
123
    assert s4b_high[0].variables["var_password_pam_minlen"] == "2"
124
125
    # check that in low level the variable is correctly placed there in S2
126
    s2_low = [c for c in low_controls if c.id == "S2"]
127
    assert len(s2_low) == 1
128
    assert s2_low[0].variables["var_some_variable"] == "1"
129
    assert s2_low[0].variables["var_password_pam_minlen"] == "1"
130
131
132
def test_controls_load_product():
133
    product_yaml = os.path.join(ssg_root, "products", "rhel8", "product.yml")
134
    build_config_yaml = os.path.join(ssg_root, "build", "build_config.yml")
135
    env_yaml = open_environment(build_config_yaml, product_yaml)
136
137
    controls_manager = ssg.controls.ControlsManager(controls_dir, env_yaml)
138
    controls_manager.load()
139
140
    c_r1 = controls_manager.get_control("abcd", "R1")
141
    assert c_r1.title == "User session timeout"
142
    assert c_r1.description == "Remote user sessions must be closed after " \
143
        "a certain period of inactivity."
144
    assert c_r1.automated == "yes"
145
146
    c_r1_rules = c_r1.selected
147
    assert "sshd_set_idle_timeout" in c_r1_rules
148
    assert "accounts_tmout" in c_r1_rules
149
    assert "var_accounts_tmout=10_min" not in c_r1_rules
150
    assert "var_accounts_tmout" in c_r1.variables
151
    assert c_r1.variables["var_accounts_tmout"] == "10_min"
152
153
154
def test_profile_resolution_inline():
155
    profile_resolution(
156
        ssg.build_yaml.ProfileWithInlinePolicies, "abcd-low-inline")
157
158
159
def test_profile_resolution_extends_inline():
160
    profile_resolution_extends(
161
        ssg.build_yaml.ProfileWithInlinePolicies,
162
        "abcd-low-inline", "abcd-high-inline")
163
164
165
def test_profile_resolution_all_inline():
166
    profile_resolution_all(
167
        ssg.build_yaml.ProfileWithInlinePolicies, "abcd-all-inline")
168
169
170
class DictContainingAnyRule(dict):
171
    def __getitem__(self, key):
172
        rule = ssg.build_yaml.Rule(key)
173
        rule.product = "all"
174
        return rule
175
176
    def __contains__(self, rid):
177
        return True
178
179
180
def profile_resolution(cls, profile_low):
181
    product_yaml = os.path.join(ssg_root, "products", "rhel8", "product.yml")
182
    build_config_yaml = os.path.join(ssg_root, "build", "build_config.yml")
183
    env_yaml = open_environment(build_config_yaml, product_yaml)
184
185
    controls_manager = ssg.controls.ControlsManager(controls_dir, env_yaml)
186
    controls_manager.load()
187
    low_profile_path = os.path.join(profiles_dir, profile_low + ".profile")
188
    profile = cls.from_yaml(low_profile_path, env_yaml)
189
    all_profiles = {"abcd-low": profile}
190
    rules_by_id = DictContainingAnyRule()
191
192
    profile.resolve(all_profiles, rules_by_id, controls_manager=controls_manager)
193
194
    # Profile 'abcd-low' selects controls R1, R2, R3 from 'abcd' policy,
195
    # which should add the following rules to the profile:
196
    selected = profile.get_rule_selectors()
197
    assert "sshd_set_idle_timeout" in selected
198
    assert "accounts_tmout" in selected
199
    assert "configure_crypto_policy" in selected
200
    assert "var_accounts_tmout" in profile.variables
201
202
    # The rule "security_patches_up_to_date" has been selected directly
203
    # by profile selections, not by using controls, so it should be in
204
    # the resolved profile as well.
205
    assert "security_patches_up_to_date" in selected
206
207
208
def profile_resolution_extends(cls, profile_low, profile_high):
209
    product_yaml = os.path.join(ssg_root, "products", "rhel8", "product.yml")
210
    build_config_yaml = os.path.join(ssg_root, "build", "build_config.yml")
211
    env_yaml = open_environment(build_config_yaml, product_yaml)
212
213
    # tests ABCD High profile which is defined as an extension of ABCD Low
214
    controls_manager = ssg.controls.ControlsManager(controls_dir, env_yaml)
215
    controls_manager.load()
216
217
    low_profile_path = os.path.join(profiles_dir, profile_low + ".profile")
218
    low_profile = cls.from_yaml(low_profile_path, env_yaml)
219
    high_profile_path = os.path.join(profiles_dir, profile_high + ".profile")
220
    high_profile = cls.from_yaml(high_profile_path, env_yaml)
221
    all_profiles = {profile_low: low_profile, profile_high: high_profile}
222
    rules_by_id = DictContainingAnyRule()
223
224
    high_profile.resolve(all_profiles, rules_by_id, controls_manager=controls_manager)
225
226
    # Profile 'abcd-high' selects controls R1, R2, R3 from 'abcd' policy,
227
    # which should add the following rules to the profile:
228
    selected = high_profile.get_rule_selectors()
229
    assert "sshd_set_idle_timeout" in selected
230
    assert "accounts_tmout" in selected
231
    assert "configure_crypto_policy" in selected
232
    assert "var_accounts_tmout" in high_profile.variables
233
234
    # The rule "security_patches_up_to_date" has been selected directly by the
235
    # abcd-low profile selections, not by using controls, so it should be
236
    # in the resolved profile as well.
237
    assert "security_patches_up_to_date" in selected
238
239
    assert "accounts_passwords_pam_faillock_deny_root" in selected
240
    assert "accounts_password_pam_minlen" in selected
241
    assert "accounts_password_pam_ocredit" in selected
242
    assert "var_password_pam_ocredit" in high_profile.variables
243
    assert high_profile.variables["var_password_pam_ocredit"] == "2"
244
245
246
def profile_resolution_all(cls, profile_all):
247
    product_yaml = os.path.join(ssg_root, "products", "rhel8", "product.yml")
248
    build_config_yaml = os.path.join(ssg_root, "build", "build_config.yml")
249
    env_yaml = open_environment(build_config_yaml, product_yaml)
250
251
    controls_manager = ssg.controls.ControlsManager(controls_dir, env_yaml)
252
    controls_manager.load()
253
    profile_path = os.path.join(profiles_dir, profile_all + ".profile")
254
    profile = cls.from_yaml(profile_path, env_yaml)
255
    all_profiles = {profile_all: profile}
256
    rules_by_id = DictContainingAnyRule()
257
258
    profile.resolve(all_profiles, rules_by_id, controls_manager=controls_manager)
259
260
    # Profile 'abcd-all' selects all controls from 'abcd' policy,
261
    # which should add the following rules and variables to the profile:
262
    selected = profile.get_rule_selectors()
263
    assert "sshd_set_idle_timeout" in selected
264
    assert "accounts_tmout" in selected
265
    assert "var_accounts_tmout" in profile.variables
266
    assert profile.variables["var_accounts_tmout"] == "10_min"
267
    assert "configure_crypto_policy" in selected
268
    # Rule "systemd_target_multi_user" is only "related_rules"
269
    # therefore it should not appear in the resolved profile.
270
    assert "systemd_target_multi_user" not in selected
271
    assert "accounts_passwords_pam_faillock_deny_root" in selected
272
    assert "accounts_password_pam_minlen" in selected
273
    assert "accounts_password_pam_ocredit" in selected
274
    assert "var_password_pam_ocredit" in profile.variables
275
    assert profile.variables["var_password_pam_ocredit"] == "1"
276
277
    # The rule "security_patches_up_to_date" has been selected directly
278
    # by profile selections, not by using controls, so it should be in
279
    # the resolved profile as well.
280
    assert "security_patches_up_to_date" in selected
281
282
283
def test_load_control_from_folder():
284
    _load_test("jklm")
285