Since we bind `/proc` inside the container, we leak certain information that comes with it. One of this is the kernel command line. None of the decisions done by software running inside the container should depend on the kernel command line on the host, so overwrite the kernel command line by creating a temporary directory and mapping it inside the build- root. For now we default to a simple `root=/dev/osbuild` fake kernel command line. Add a simple check for it as well.
166 lines
4.5 KiB
Python
166 lines
4.5 KiB
Python
#
|
|
# Test for the build root
|
|
#
|
|
|
|
import pathlib
|
|
import os
|
|
import sys
|
|
|
|
from tempfile import TemporaryDirectory
|
|
|
|
import pytest
|
|
|
|
from osbuild.buildroot import BuildRoot
|
|
from osbuild.monitor import LogMonitor, NullMonitor
|
|
from osbuild.pipeline import detect_host_runner
|
|
|
|
from ..test import TestBase
|
|
|
|
|
|
@pytest.fixture(name="tempdir")
|
|
def tempdir_fixture():
|
|
with TemporaryDirectory(prefix="lvm2-") as tmp:
|
|
yield tmp
|
|
|
|
|
|
@pytest.mark.skipif(not TestBase.can_bind_mount(), reason="root only")
|
|
def test_basic(tempdir):
|
|
runner = detect_host_runner()
|
|
libdir = os.path.abspath(os.curdir)
|
|
var = pathlib.Path(tempdir, "var")
|
|
var.mkdir()
|
|
|
|
monitor = NullMonitor(sys.stderr.fileno())
|
|
with BuildRoot("/", runner, libdir, var) as root:
|
|
|
|
r = root.run(["/usr/bin/true"], monitor)
|
|
assert r.returncode == 0
|
|
|
|
# Test we can use `.run` multiple times
|
|
r = root.run(["/usr/bin/true"], monitor)
|
|
assert r.returncode == 0
|
|
|
|
r = root.run(["/usr/bin/false"], monitor)
|
|
assert r.returncode != 0
|
|
|
|
|
|
@pytest.mark.skipif(not TestBase.can_bind_mount(), reason="root only")
|
|
def test_runner_fail(tempdir):
|
|
runner = "org.osbuild.nonexistantrunner"
|
|
libdir = os.path.abspath(os.curdir)
|
|
var = pathlib.Path(tempdir, "var")
|
|
var.mkdir()
|
|
|
|
logfile = os.path.join(tempdir, "log.txt")
|
|
|
|
with BuildRoot("/", runner, libdir, var) as root, \
|
|
open(logfile, "w") as log:
|
|
|
|
monitor = LogMonitor(log.fileno())
|
|
|
|
r = root.run(["/usr/bin/true"], monitor)
|
|
|
|
assert r.returncode == 1
|
|
with open(logfile) as f:
|
|
log = f.read()
|
|
assert log
|
|
assert r.output
|
|
assert log == r.output
|
|
|
|
|
|
@pytest.mark.skipif(not TestBase.can_bind_mount(), reason="root only")
|
|
def test_output(tempdir):
|
|
runner = detect_host_runner()
|
|
libdir = os.path.abspath(os.curdir)
|
|
var = pathlib.Path(tempdir, "var")
|
|
var.mkdir()
|
|
|
|
data = "42. cats are superior to dogs"
|
|
|
|
monitor = NullMonitor(sys.stderr.fileno())
|
|
with BuildRoot("/", runner, libdir, var) as root:
|
|
|
|
r = root.run(["/usr/bin/echo", data], monitor)
|
|
assert r.returncode == 0
|
|
|
|
assert data in r.output.strip()
|
|
|
|
|
|
@pytest.mark.skipif(not TestBase.have_test_data(), reason="no test-data access")
|
|
@pytest.mark.skipif(not TestBase.can_bind_mount(), reason="root only")
|
|
def test_bind_mounts(tempdir):
|
|
runner = detect_host_runner()
|
|
libdir = os.path.abspath(os.curdir)
|
|
var = pathlib.Path(tempdir, "var")
|
|
var.mkdir()
|
|
|
|
rw_data = pathlib.Path(tempdir, "data")
|
|
rw_data.mkdir()
|
|
|
|
scripts = os.path.join(TestBase.locate_test_data(), "scripts")
|
|
|
|
monitor = NullMonitor(sys.stderr.fileno())
|
|
with BuildRoot("/", runner, libdir, var) as root:
|
|
|
|
ro_binds = [f"{scripts}:/scripts"]
|
|
|
|
cmd = ["/scripts/mount_flags.py",
|
|
"/scripts",
|
|
"ro"]
|
|
|
|
r = root.run(cmd, monitor, readonly_binds=ro_binds)
|
|
assert r.returncode == 0
|
|
|
|
cmd = ["/scripts/mount_flags.py",
|
|
"/rw-data",
|
|
"ro"]
|
|
|
|
binds = [f"{rw_data}:/rw-data"]
|
|
r = root.run(cmd, monitor, binds=binds, readonly_binds=ro_binds)
|
|
assert r.returncode == 1
|
|
|
|
|
|
@pytest.mark.skipif(not TestBase.have_test_data(), reason="no test-data access")
|
|
@pytest.mark.skipif(not os.path.exists("/sys/fs/selinux"), reason="no SELinux")
|
|
def test_selinuxfs_ro(tempdir):
|
|
# /sys/fs/selinux must never be writable in the container
|
|
# because RPM and other tools must not assume the policy
|
|
# of the host is the valid policy
|
|
|
|
runner = detect_host_runner()
|
|
libdir = os.path.abspath(os.curdir)
|
|
var = pathlib.Path(tempdir, "var")
|
|
var.mkdir()
|
|
|
|
scripts = os.path.join(TestBase.locate_test_data(), "scripts")
|
|
|
|
monitor = NullMonitor(sys.stderr.fileno())
|
|
with BuildRoot("/", runner, libdir, var) as root:
|
|
|
|
ro_binds = [f"{scripts}:/scripts"]
|
|
|
|
cmd = ["/scripts/mount_flags.py",
|
|
"/sys/fs/selinux",
|
|
"ro"]
|
|
|
|
r = root.run(cmd, monitor, readonly_binds=ro_binds)
|
|
assert r.returncode == 0
|
|
|
|
|
|
@pytest.mark.skipif(not TestBase.can_bind_mount(), reason="root only")
|
|
def test_proc_overrides(tempdir):
|
|
runner = detect_host_runner()
|
|
libdir = os.path.abspath(os.curdir)
|
|
var = pathlib.Path(tempdir, "var")
|
|
var.mkdir()
|
|
|
|
cmdline = "is-this-the-real-world"
|
|
|
|
monitor = NullMonitor(sys.stderr.fileno())
|
|
with BuildRoot("/", runner, libdir, var) as root:
|
|
|
|
root.proc.cmdline = cmdline
|
|
|
|
r = root.run(["cat", "/proc/cmdline"], monitor)
|
|
assert r.returncode == 0
|
|
assert cmdline in r.output.strip()
|