Completed
Push — master ( c97ece...6b05e2 )
by Jan
27s queued 17s
created

test_common.test_firstboot_config()   A

Complexity

Conditions 2

Size

Total Lines 13
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 12
dl 0
loc 13
rs 9.8
c 0
b 0
f 0
cc 2
nop 0
1
#
2
# Copyright (C) 2013  Red Hat, Inc.
3
#
4
# This copyrighted material is made available to anyone wishing to use,
5
# modify, copy, or redistribute it subject to the terms and conditions of
6
# the GNU General Public License v.2, or (at your option) any later version.
7
# This program is distributed in the hope that it will be useful, but WITHOUT
8
# ANY WARRANTY expressed or implied, including the implied warranties of
9
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
10
# Public License for more details.  You should have received a copy of the
11
# GNU General Public License along with this program; if not, write to the
12
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
13
# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
14
# source code or documentation are not subject to the GNU General Public
15
# License and may only be used or replicated with the express permission of
16
# Red Hat, Inc.
17
#
18
# Red Hat Author(s): Vratislav Podzimek <[email protected]>
19
#
20
21
"""Module with unit tests for the common.py module"""
22
23
import os
24
from unittest import mock
25
import shutil
26
27
import pytest
28
import tempfile
29
30
from org_fedora_oscap import common
31
32
TESTING_FILES_PATH = os.path.join(
33
    os.path.dirname(__file__), os.path.pardir, "testing_files")
34
35
@pytest.fixture()
36
def mock_subprocess():
37
    mock_subprocess = mock.Mock()
38
    mock_subprocess.Popen = mock.Mock()
39
    mock_popen = mock.Mock()
40
    mock_communicate = mock.Mock()
41
42
    mock_communicate.return_value = (b"", b"")
43
44
    mock_popen.communicate = mock_communicate
45
    mock_popen.returncode = 0
46
47
    mock_subprocess.Popen.return_value = mock_popen
48
    mock_subprocess.PIPE = mock.Mock()
49
50
    return mock_subprocess
51
52
53
def mock_run_remediate(mock_subprocess, monkeypatch):
54
    mock_utils = mock.Mock()
55
    mock_utils.ensure_dir_exists = mock.Mock()
56
57
    common_module_symbols = common.__dict__
58
59
    monkeypatch.setitem(common_module_symbols, "subprocess", mock_subprocess)
60
    monkeypatch.setitem(common_module_symbols, "utils", mock_utils)
61
62
63
def _run_oscap(mock_subprocess, additional_args):
64
    expected_args = [
65
        "oscap", "xccdf", "eval", "--remediate",
66
        "--results=%s" % common.RESULTS_PATH,
67
        "--report=%s" % common.REPORT_PATH,
68
        "--profile=myprofile",
69
    ]
70
    expected_args.extend(additional_args)
71
72
    kwargs = {
73
        "stdout": mock_subprocess.PIPE,
74
        "stderr": mock_subprocess.PIPE,
75
    }
76
77
    return expected_args, kwargs
78
79
80
def test_oscap_works():
81
    assert common.assert_scanner_works(chroot="/")
82
    with pytest.raises(common.OSCAPaddonError, match="No such file"):
83
        common.assert_scanner_works(chroot="/", executable="i_dont_exist")
84
    with pytest.raises(common.OSCAPaddonError, match="non-zero"):
85
        common.assert_scanner_works(chroot="/", executable="false")
86
87
88
def test_run_oscap_remediate_profile_only(mock_subprocess, monkeypatch):
89
    return run_oscap_remediate_profile(
90
        mock_subprocess, monkeypatch,
91
        ["myprofile", "my_ds.xml"],
92
        ["my_ds.xml"])
93
94
95
def test_run_oscap_remediate_with_ds(mock_subprocess, monkeypatch):
96
    return run_oscap_remediate_profile(
97
        mock_subprocess, monkeypatch,
98
        ["myprofile", "my_ds.xml", "my_ds_id"],
99
        ["--datastream-id=my_ds_id", "my_ds.xml"])
100
101
102
def test_run_oscap_remediate_with_ds_xccdf(mock_subprocess, monkeypatch):
103
    return run_oscap_remediate_profile(
104
        mock_subprocess, monkeypatch,
105
        ["myprofile", "my_ds.xml", "my_ds_id", "my_xccdf_id"],
106
        ["--datastream-id=my_ds_id", "--xccdf-id=my_xccdf_id", "my_ds.xml"])
107
108
109
def run_oscap_remediate_profile(
110
        mock_subprocess, monkeypatch,
111
        anaconda_remediate_args, oscap_remediate_args):
112
    mock_run_remediate(mock_subprocess, monkeypatch)
113
    common.run_oscap_remediate(* anaconda_remediate_args)
114
115
    expected_args = [
116
        "oscap", "xccdf", "eval", "--remediate",
117
        "--results=%s" % common.RESULTS_PATH,
118
        "--report=%s" % common.REPORT_PATH,
119
        "--profile=myprofile",
120
    ]
121
    expected_args.extend(oscap_remediate_args)
122
123
    kwargs = {
124
        "stdout": mock_subprocess.PIPE,
125
        "stderr": mock_subprocess.PIPE,
126
    }
127
128
    # it's impossible to check the preexec_func as it is an internal
129
    # function of the run_oscap_remediate function
130
    for arg in expected_args:
131
        assert arg in mock_subprocess.Popen.call_args[0][0]
132
        mock_subprocess.Popen.call_args[0][0].remove(arg)
133
134
    # nothing else should have been passed
135
    assert not mock_subprocess.Popen.call_args[0][0]
136
137
    for (key, val) in kwargs.items():
138
        assert kwargs[key] == mock_subprocess.Popen.call_args[1].pop(key)
139
140
    # plus the preexec_fn kwarg should have been passed
141
    assert "preexec_fn" in mock_subprocess.Popen.call_args[1]
142
143
144
def test_run_oscap_remediate_create_dir(mock_subprocess, monkeypatch):
145
    mock_run_remediate(mock_subprocess, monkeypatch)
146
    common.run_oscap_remediate("myprofile", "my_ds.xml")
147
148
    common.utils.ensure_dir_exists.assert_called_with(
149
        os.path.dirname(common.RESULTS_PATH))
150
151
152
def test_run_oscap_remediate_create_chroot_dir(mock_subprocess, monkeypatch):
153
    mock_run_remediate(mock_subprocess, monkeypatch)
154
    common.run_oscap_remediate("myprofile", "my_ds.xml", chroot="/mnt/test")
155
156
    chroot_dir = "/mnt/test" + os.path.dirname(common.RESULTS_PATH)
157
    common.utils.ensure_dir_exists.assert_called_with(chroot_dir)
158
159
160
rpm_ssg_file_list = [
161
    "/usr/share/doc/scap-security-guide/Contributors.md",
162
    "/usr/share/doc/scap-security-guide/LICENSE",
163
    "/usr/share/doc/scap-security-guide/README.md",
164
    "/usr/share/man/man8/scap-security-guide.8.gz",
165
    "/usr/share/scap-security-guide/ansible",
166
    "/usr/share/scap-security-guide/ansible/ssg-fedora-role-default.yml",
167
    "/usr/share/scap-security-guide/ansible/ssg-fedora-role-ospp.yml",
168
    "/usr/share/scap-security-guide/ansible/ssg-fedora-role-pci-dss.yml",
169
    "/usr/share/scap-security-guide/ansible/ssg-fedora-role-standard.yml",
170
    "/usr/share/scap-security-guide/bash",
171
    "/usr/share/scap-security-guide/bash/ssg-fedora-role-default.sh",
172
    "/usr/share/scap-security-guide/bash/ssg-fedora-role-ospp.sh",
173
    "/usr/share/scap-security-guide/bash/ssg-fedora-role-pci-dss.sh",
174
    "/usr/share/scap-security-guide/bash/ssg-fedora-role-standard.sh",
175
    "/usr/share/xml/scap/ssg/content",
176
    "/usr/share/xml/scap/ssg/content/ssg-fedora-cpe-dictionary.xml",
177
    "/usr/share/xml/scap/ssg/content/ssg-fedora-cpe-oval.xml",
178
    "/usr/share/xml/scap/ssg/content/ssg-fedora-ds.xml",
179
    "/usr/share/xml/scap/ssg/content/ssg-fedora-ocil.xml",
180
    "/usr/share/xml/scap/ssg/content/ssg-fedora-oval.xml",
181
    "/usr/share/xml/scap/ssg/content/ssg-fedora-xccdf.xml",
182
    ]
183
184
185
def test_extract_ssg_rpm():
186
    temp_path = tempfile.mkdtemp(prefix="rpm")
187
188
    extracted_files = common._extract_rpm(
189
            TESTING_FILES_PATH + "/scap-security-guide.noarch.rpm",
190
            temp_path)
191
192
    assert len(rpm_ssg_file_list) == len(extracted_files)
193
    for rpm_file in rpm_ssg_file_list:
194
        assert temp_path + rpm_file in extracted_files
195
196
    shutil.rmtree(temp_path)
197
198
199
def test_extract_ssg_rpm_ensure_filepath_there():
200
    temp_path = tempfile.mkdtemp(prefix="rpm")
201
202
    extracted_files = common._extract_rpm(
203
            TESTING_FILES_PATH + "/scap-security-guide.noarch.rpm",
204
            temp_path,
205
            ["/usr/share/xml/scap/ssg/content/ssg-fedora-ds.xml"])
206
207
    assert len(rpm_ssg_file_list) == len(extracted_files)
208
    for rpm_file in rpm_ssg_file_list:
209
        assert temp_path + rpm_file in extracted_files
210
211
    shutil.rmtree(temp_path)
212
213
214
def test_extract_ssg_rpm_ensure_filepath_not_there():
215
    temp_path = tempfile.mkdtemp(prefix="rpm")
216
217
    with pytest.raises(common.ExtractionError) as excinfo:
218
        extracted_files = common._extract_rpm(
219
                TESTING_FILES_PATH + "/scap-security-guide.noarch.rpm",
220
                temp_path,
221
                ["/usr/share/xml/scap/ssg/content/ssg-fedora-content.xml"])
222
223
    assert "File '/usr/share/xml/scap/ssg/content/ssg-fedora-content.xml' "\
224
           "not found in the archive" in str(excinfo.value)
225
226
    shutil.rmtree(temp_path)
227
228
229
rpm_tailoring_file_list = [
230
    "/usr/share/xml/scap/ssg-fedora-ds-tailoring/ssg-fedora-ds.xml",
231
    "/usr/share/xml/scap/ssg-fedora-ds-tailoring/tailoring-xccdf.xml",
232
    ]
233
234
235
def test_extract_tailoring_rpm():
236
    temp_path = tempfile.mkdtemp(prefix="rpm")
237
238
    extracted_files = common._extract_rpm(
239
            TESTING_FILES_PATH + "/ssg-fedora-ds-tailoring-1-1.noarch.rpm",
240
            temp_path)
241
242
    assert len(rpm_tailoring_file_list) == len(extracted_files)
243
    for rpm_file in rpm_tailoring_file_list:
244
        assert temp_path + rpm_file in extracted_files
245
246
    shutil.rmtree(temp_path)
247
248
249
def test_extract_tailoring_rpm_ensure_filepath_there():
250
    temp_path = tempfile.mkdtemp(prefix="rpm")
251
252
    extracted_files = common._extract_rpm(
253
            TESTING_FILES_PATH + "/ssg-fedora-ds-tailoring-1-1.noarch.rpm",
254
            temp_path,
255
            ["/usr/share/xml/scap/ssg-fedora-ds-tailoring/ssg-fedora-ds.xml"])
256
257
    assert len(rpm_tailoring_file_list) == len(extracted_files)
258
    for rpm_file in rpm_tailoring_file_list:
259
        assert temp_path + rpm_file in extracted_files
260
261
    shutil.rmtree(temp_path)
262
263
264
def test_extract_tailoring_rpm_ensure_filename_there():
265
    temp_path = tempfile.mkdtemp(prefix="rpm")
266
267
    with pytest.raises(common.ExtractionError) as excinfo:
268
        extracted_files = common._extract_rpm(
269
                TESTING_FILES_PATH + "/ssg-fedora-ds-tailoring-1-1.noarch.rpm",
270
                temp_path,
271
                ["ssg-fedora-ds.xml"])
272
273
    assert "File 'ssg-fedora-ds.xml' not found in the archive" \
274
           in str(excinfo.value)
275
276
    shutil.rmtree(temp_path)
277
278
279
def test_firstboot_config():
280
    config_args = dict(
281
        profile="@PROFILE@",
282
        ds_path="@DS_PATH@",
283
        results_path="@RES_PATH@",
284
        report_path="@REP_PATH",
285
        ds_id="@DS_ID@",
286
        xccdf_id="@XCCDF_ID@",
287
        tailoring_path="@TAIL_PATH@",
288
    )
289
    config_string = common._create_firstboot_config_string(** config_args)
290
    for arg in config_args.values():
291
        assert arg in config_string
292