test: add selinux stage test
This commit is contained in:
parent
83a14886d3
commit
18159eceec
1 changed files with 114 additions and 0 deletions
114
stages/test/test_selinux.py
Normal file
114
stages/test/test_selinux.py
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import os.path
|
||||||
|
from unittest.mock import call, patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
import osbuild.meta
|
||||||
|
import osbuild.testutil
|
||||||
|
from osbuild.testutil.imports import import_module_from_path
|
||||||
|
|
||||||
|
|
||||||
|
def schema_validation_selinux(test_data, implicit_file_contexts=True):
|
||||||
|
name = "org.osbuild.selinux"
|
||||||
|
root = os.path.join(os.path.dirname(__file__), "../..")
|
||||||
|
mod_info = osbuild.meta.ModuleInfo.load(root, "Stage", name)
|
||||||
|
schema = osbuild.meta.Schema(mod_info.get_schema(version="1"), name)
|
||||||
|
|
||||||
|
test_input = {
|
||||||
|
"name": "org.osbuild.selinux",
|
||||||
|
"options": {}
|
||||||
|
}
|
||||||
|
if implicit_file_contexts:
|
||||||
|
test_input["options"]["file_contexts"] = "some-context"
|
||||||
|
|
||||||
|
test_input["options"].update(test_data)
|
||||||
|
return schema.validate(test_input)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("test_data,expected_err", [
|
||||||
|
# good
|
||||||
|
({"labels": {"/usr/bin/cp": "system_u:object_r:install_exec_t:s0"}}, ""),
|
||||||
|
({"force_autorelabel": True}, ""),
|
||||||
|
# bad
|
||||||
|
({"file_contexts": 1234}, "1234 is not of type 'string'"),
|
||||||
|
({"labels": "xxx"}, "'xxx' is not of type 'object'"),
|
||||||
|
({"force_autorelabel": "foo"}, "'foo' is not of type 'boolean'"),
|
||||||
|
])
|
||||||
|
def test_schema_validation_selinux(test_data, expected_err):
|
||||||
|
res = schema_validation_selinux(test_data)
|
||||||
|
if expected_err == "":
|
||||||
|
assert res.valid is True, f"err: {[e.as_dict() for e in res.errors]}"
|
||||||
|
else:
|
||||||
|
assert res.valid is False
|
||||||
|
assert len(res.errors) == 1, [e.as_dict() for e in res.errors]
|
||||||
|
err_msgs = [e.as_dict()["message"] for e in res.errors]
|
||||||
|
assert expected_err in err_msgs[0]
|
||||||
|
|
||||||
|
|
||||||
|
def test_schema_validation_selinux_file_context_required():
|
||||||
|
test_data = {}
|
||||||
|
res = schema_validation_selinux(test_data, implicit_file_contexts=False)
|
||||||
|
assert res.valid is False
|
||||||
|
assert len(res.errors) == 1, [e.as_dict() for e in res.errors]
|
||||||
|
err_msgs = [e.as_dict()["message"] for e in res.errors]
|
||||||
|
assert "'file_contexts' is a required property" in err_msgs[0]
|
||||||
|
|
||||||
|
|
||||||
|
@patch("subprocess.run")
|
||||||
|
def test_selinux_file_contexts(mocked_run, tmp_path):
|
||||||
|
stage_path = os.path.join(os.path.dirname(__file__), "../org.osbuild.selinux")
|
||||||
|
stage = import_module_from_path("stage", stage_path)
|
||||||
|
|
||||||
|
options = {
|
||||||
|
"file_contexts": "etc/selinux/thing",
|
||||||
|
}
|
||||||
|
stage.main(tmp_path, options)
|
||||||
|
|
||||||
|
assert len(mocked_run.call_args_list) == 1
|
||||||
|
assert mocked_run.call_args_list == [
|
||||||
|
call(
|
||||||
|
["setfiles", "-F", "-r", os.fspath(tmp_path),
|
||||||
|
f"{tmp_path}/etc/selinux/thing", os.fspath(tmp_path)], check=True),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@patch("osbuild.util.selinux.setfilecon")
|
||||||
|
@patch("subprocess.run")
|
||||||
|
def test_selinux_labels(mocked_run, mocked_setfilecon, tmp_path):
|
||||||
|
stage_path = os.path.join(os.path.dirname(__file__), "../org.osbuild.selinux")
|
||||||
|
stage = import_module_from_path("stage", stage_path)
|
||||||
|
|
||||||
|
osbuild.testutil.make_fake_input_tree(tmp_path, {
|
||||||
|
"/usr/bin/bootc": "I'm only an imposter",
|
||||||
|
})
|
||||||
|
|
||||||
|
options = {
|
||||||
|
"file_contexts": "etc/selinux/thing",
|
||||||
|
"labels": {
|
||||||
|
"/tree/usr/bin/bootc": "system_u:object_r:install_exec_t:s0",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage.main(tmp_path, options)
|
||||||
|
|
||||||
|
assert len(mocked_run.call_args_list) == 1
|
||||||
|
assert len(mocked_setfilecon.call_args_list) == 1
|
||||||
|
assert mocked_setfilecon.call_args_list == [
|
||||||
|
call(f"{tmp_path}/tree/usr/bin/bootc", "system_u:object_r:install_exec_t:s0"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@patch("subprocess.run")
|
||||||
|
def test_selinux_force_autorelabel(mocked_run, tmp_path): # pylint: disable=unused-argument
|
||||||
|
stage_path = os.path.join(os.path.dirname(__file__), "../org.osbuild.selinux")
|
||||||
|
stage = import_module_from_path("stage", stage_path)
|
||||||
|
|
||||||
|
for enable_autorelabel in [False, True]:
|
||||||
|
options = {
|
||||||
|
"file_contexts": "etc/selinux/thing",
|
||||||
|
"force_autorelabel": enable_autorelabel,
|
||||||
|
}
|
||||||
|
stage.main(tmp_path, options)
|
||||||
|
|
||||||
|
assert (tmp_path / ".autorelabel").exists() == enable_autorelabel
|
||||||
Loading…
Add table
Add a link
Reference in a new issue