42 lines
1.6 KiB
Python
42 lines
1.6 KiB
Python
import importlib.util
|
|
from pathlib import Path
|
|
import subprocess
|
|
from unittest.mock import Mock
|
|
|
|
import pytest
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
SPEC = importlib.util.spec_from_file_location("runner_installer", ROOT / "install-runner-hardening.py")
|
|
installer = importlib.util.module_from_spec(SPEC)
|
|
SPEC.loader.exec_module(installer)
|
|
|
|
|
|
def test_image_preflight_checks_nonroot_openssh_without_network_or_credentials(monkeypatch):
|
|
run = Mock()
|
|
monkeypatch.setattr(installer, "run", run)
|
|
installer.prepare_image(ROOT)
|
|
build, probe = [call.args for call in run.call_args_list]
|
|
assert build[:2] == ("docker", "build")
|
|
assert "--pull=false" in build and "--network=none" in build
|
|
assert probe[:3] == ("docker", "run", "--rm")
|
|
assert probe[probe.index("--network") + 1] == "none"
|
|
assert probe[probe.index("--user") + 1] == "10001:10001"
|
|
assert "--read-only" in probe
|
|
assert "id -un" in probe[-1] and "ssh -G -F /dev/null" in probe[-1]
|
|
assert "--volume" not in probe and "-v" not in probe
|
|
|
|
|
|
def test_missing_passwd_or_broken_ssh_aborts_preflight(monkeypatch):
|
|
monkeypatch.setattr(installer, "run", Mock(side_effect=["", subprocess.CalledProcessError(255, "ssh")]))
|
|
with pytest.raises(subprocess.CalledProcessError):
|
|
installer.prepare_image(ROOT)
|
|
|
|
|
|
def test_compose_selects_image_with_real_nonroot_account():
|
|
dockerfile = (ROOT / "Dockerfile").read_text()
|
|
assert "addgroup -g 10001 runner" in dockerfile
|
|
assert "adduser -D -H -u 10001 -G runner" in dockerfile
|
|
assert "USER 10001:10001" in dockerfile
|
|
assert installer.RUNNER_IMAGE in (ROOT / "compose.yaml").read_text()
|