6c7b9c2f31
tracker-policy-pr / check-pr (pull_request) Successful in 8s
test / integration-docker (pull_request) Successful in 9s
test / unit (pull_request) Successful in 32s
lint / lint (push) Successful in 46s
test / stage-firecracker-inputs (pull_request) Successful in 2s
test / build-infra (pull_request) Successful in 3m23s
test / integration-firecracker (pull_request) Successful in 1m37s
test / coverage (pull_request) Failing after 1m24s
test / publish-infra (pull_request) Has been skipped
78 lines
3.2 KiB
Python
78 lines
3.2 KiB
Python
"""Unit coverage for the fail-closed macOS rootless-Docker spike."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import unittest
|
|
from pathlib import Path
|
|
from types import SimpleNamespace
|
|
from unittest.mock import patch
|
|
|
|
from bot_bottle.backend.macos_container import rootless_docker
|
|
|
|
|
|
class _Bottle:
|
|
def __init__(self, results: list[SimpleNamespace]) -> None:
|
|
self.results = results
|
|
self.commands: list[str] = []
|
|
|
|
def exec(self, command: str) -> SimpleNamespace:
|
|
self.commands.append(command)
|
|
return self.results.pop(0)
|
|
|
|
|
|
def _result(returncode: int, *, stdout: str = "", stderr: str = "") -> SimpleNamespace:
|
|
return SimpleNamespace(returncode=returncode, stdout=stdout, stderr=stderr)
|
|
|
|
|
|
class TestRootlessDockerStart(unittest.TestCase):
|
|
def test_bootstraps_then_waits_for_guest_local_daemon(self) -> None:
|
|
bottle = _Bottle([_result(0), _result(1), _result(0)])
|
|
with patch.object(rootless_docker.time, "sleep"):
|
|
rootless_docker.start(bottle)
|
|
self.assertIn("rootless-docker-init", bottle.commands[0])
|
|
self.assertEqual(2, bottle.commands.count("docker info >/dev/null 2>&1"))
|
|
|
|
def test_bootstrap_failure_is_fatal_without_privilege_fallback(self) -> None:
|
|
bottle = _Bottle([_result(1, stderr="newuidmap missing")])
|
|
with patch.object(rootless_docker, "die", side_effect=RuntimeError) as die:
|
|
with self.assertRaises(RuntimeError):
|
|
rootless_docker.start(bottle)
|
|
self.assertIn("newuidmap missing", die.call_args.args[0])
|
|
self.assertEqual(1, len(bottle.commands))
|
|
|
|
def test_timeout_reports_guest_log(self) -> None:
|
|
bottle = _Bottle(
|
|
[_result(0)]
|
|
+ [_result(1) for _ in range(rootless_docker.READY_RETRIES)]
|
|
+ [_result(0, stdout="operation not permitted")]
|
|
)
|
|
with patch.object(rootless_docker.time, "sleep"), \
|
|
patch.object(rootless_docker, "die", side_effect=RuntimeError) as die:
|
|
with self.assertRaises(RuntimeError):
|
|
rootless_docker.start(bottle)
|
|
self.assertIn("operation not permitted", die.call_args.args[0])
|
|
|
|
|
|
class TestRootlessDockerImage(unittest.TestCase):
|
|
def test_layers_tooling_without_changing_base_image(self) -> None:
|
|
calls: list[tuple[str, str, str]] = []
|
|
|
|
def build(image: str, context: str, *, dockerfile: str) -> None:
|
|
calls.append((image, context, dockerfile))
|
|
text = Path(dockerfile).read_text(encoding="utf-8")
|
|
self.assertIn("FROM agent:base", text)
|
|
self.assertIn("docker.io uidmap rootlesskit slirp4netns", text)
|
|
self.assertIn("sed -i '/^node:/d' /etc/subuid /etc/subgid", text)
|
|
self.assertEqual(1, text.count("node:100000:65536\\n' >> /etc/subuid"))
|
|
self.assertEqual(1, text.count("node:100000:65536\\n' >> /etc/subgid"))
|
|
self.assertIn("USER node", text)
|
|
self.assertTrue((Path(context) / "rootless-docker-init.sh").is_file())
|
|
|
|
image = rootless_docker.build_image("agent:base", build)
|
|
self.assertEqual("agent:base-rootless-docker", image)
|
|
self.assertEqual("agent:base-rootless-docker", calls[0][0])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|