mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-01 00:27:20 -05:00
refactor: run cores and builds in a sandbox
core_probe starts its worker with only the --env values, the worker clears its own environment before loading the core, and a working bubblewrap runs it with a read-only tree, no network and the user's credentials masked. The record names the isolation used. A timeout kills the whole process group. campaign.py starts core_probe, git, make and romfetch with the allowlist, make inside the same sandbox. --record refuses a folder that is not a checkout root.
This commit is contained in:
1 parent
e5cc1b5255
commit
95ca227bce
5 files changed
+316
-35
No files matched your search
@@ -11,6 +11,7 @@ import argparse
|
||||
import contextlib
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import struct
|
||||
import subprocess
|
||||
@@ -99,6 +100,13 @@ def mednafen_state(sections: dict[str, dict[str, bytes]]) -> bytes:
|
||||
return b"MDFNSVST".ljust(32, b"\0") + body
|
||||
|
||||
|
||||
def checkout(path: Path) -> Path:
|
||||
"""A folder made the root of a git checkout, as --record requires."""
|
||||
path.mkdir(parents=True, exist_ok=True)
|
||||
subprocess.run(["git", "init", "-q", str(path)], check=True)
|
||||
return path
|
||||
|
||||
|
||||
class ParsingTests(unittest.TestCase):
|
||||
def test_assignment(self) -> None:
|
||||
self.assertEqual(core_probe.parse_assignment("a=b=c", "--option"), ("a", "b=c"))
|
||||
@@ -244,7 +252,7 @@ class FakeCoreTests(unittest.TestCase):
|
||||
return code, json.loads(out.getvalue()) if code == 0 else None
|
||||
|
||||
def test_run_record(self) -> None:
|
||||
record_dir = self.tmp / "records"
|
||||
record_dir = checkout(self.tmp / "records")
|
||||
code, record = self.probe(["check", "--core", str(self.core), "--frames", "3",
|
||||
"--vary", f"card.bin={self.cards[0]}", "--vary", f"card.bin={self.cards[1]}",
|
||||
"--vary", f"card.bin={self.cards[2]}", "--vary", "card.bin=",
|
||||
@@ -268,7 +276,8 @@ class FakeCoreTests(unittest.TestCase):
|
||||
self.assertEqual(first["frames"], 3)
|
||||
self.assertEqual(record["emulator"], "fake")
|
||||
self.assertEqual([p.relative_to(record_dir).as_posix()
|
||||
for p in record_dir.rglob("*") if p.is_file()], ["measurements/fake.jsonl"])
|
||||
for p in record_dir.rglob("*") if p.is_file() and ".git" not in p.parts],
|
||||
["measurements/fake.jsonl"])
|
||||
line = json.loads((record_dir / "measurements" / "fake.jsonl").read_text())
|
||||
self.assertEqual(measurement_records.check_line(line), [])
|
||||
# The line is the record the run printed, id included.
|
||||
@@ -281,7 +290,7 @@ class FakeCoreTests(unittest.TestCase):
|
||||
self.assertEqual(list(Draft202012Validator(schema).iter_errors(line)), [])
|
||||
|
||||
def test_second_run_is_appended_beside_the_first(self) -> None:
|
||||
record_dir = self.tmp / "appended"
|
||||
record_dir = checkout(self.tmp / "appended")
|
||||
argv = ["run", "--core", str(self.core), "--frames", "1", "--no-trace", "--max-load", "1000",
|
||||
"--record", str(record_dir), "--subject", "smoke"]
|
||||
self.assertEqual(self.probe(argv)[0], 0)
|
||||
@@ -313,10 +322,80 @@ class FakeCoreTests(unittest.TestCase):
|
||||
self.assertEqual(record["flags"], [])
|
||||
|
||||
def test_busy_machine_refused(self) -> None:
|
||||
refused = checkout(self.tmp / "refused")
|
||||
code, _ = self.probe(["run", "--core", str(self.core), "--frames", "1", "--record",
|
||||
str(self.tmp / "refused"), "--max-load", "-1"])
|
||||
str(refused), "--max-load", "-1"])
|
||||
self.assertEqual(code, 3)
|
||||
self.assertFalse((self.tmp / "refused").exists())
|
||||
self.assertFalse((refused / "measurements").exists())
|
||||
|
||||
def test_record_names_a_checkout_root(self) -> None:
|
||||
# --record measurements wrote measurements/measurements/<emulator>.jsonl.
|
||||
root = checkout(self.tmp / "rooted")
|
||||
(root / "measurements").mkdir()
|
||||
for wrong in (root / "measurements", self.tmp / "plain"):
|
||||
wrong.mkdir(exist_ok=True)
|
||||
err = io.StringIO()
|
||||
with contextlib.redirect_stdout(io.StringIO()), contextlib.redirect_stderr(err):
|
||||
code = core_probe.main(["run", "--core", str(self.core), "--frames", "1", "--no-trace",
|
||||
"--record", str(wrong), "--work-dir", str(self.tmp / "work")])
|
||||
self.assertEqual(code, 2)
|
||||
self.assertIn("not a git checkout root", err.getvalue())
|
||||
self.assertIn("--record .", err.getvalue())
|
||||
self.assertFalse((wrong / "measurements" / "fake.jsonl").exists())
|
||||
self.assertIsNone(core_probe.not_a_checkout_root(root))
|
||||
self.assertIsNone(core_probe.not_a_checkout_root(REPO_ROOT))
|
||||
|
||||
def test_the_core_sees_only_the_env_it_was_given(self) -> None:
|
||||
os.environ["CORE_PROBE_TEST_TAG"] = "from-the-host"
|
||||
os.environ["GITHUB_TOKEN"] = "secret"
|
||||
try:
|
||||
code, record = self.probe(["run", "--core", str(self.core), "--frames", "1",
|
||||
"--no-trace"])
|
||||
finally:
|
||||
del os.environ["CORE_PROBE_TEST_TAG"]
|
||||
del os.environ["GITHUB_TOKEN"]
|
||||
self.assertEqual(code, 0)
|
||||
rep = record["variants"][0]["repetitions"][0]
|
||||
self.assertEqual(rep["logs"][1]["text"], "tag unset")
|
||||
self.assertTrue(rep["isolation"] == "bwrap" or rep["isolation"].startswith("environment only"))
|
||||
|
||||
|
||||
class Sandbox(unittest.TestCase):
|
||||
"""What a core run under bubblewrap can reach."""
|
||||
|
||||
def setUp(self) -> None:
|
||||
if not core_probe.sandbox_argv([])[0]:
|
||||
self.skipTest("no working bwrap on this host")
|
||||
self.tmp = Path(tempfile.mkdtemp(dir=REPO_ROOT / "tmp" / "tests"))
|
||||
self.home = self.tmp / "home"
|
||||
for secret in (".config/gh/hosts.yml", ".ssh/id_ed25519"):
|
||||
(self.home / secret).parent.mkdir(parents=True)
|
||||
(self.home / secret).write_text("secret")
|
||||
(self.home / ".git-credentials").write_text("https://user:secret@github.com")
|
||||
self.out = self.tmp / "out"
|
||||
self.elsewhere = self.tmp / "elsewhere"
|
||||
self.elsewhere.mkdir()
|
||||
|
||||
def tearDown(self) -> None:
|
||||
shutil.rmtree(self.tmp, ignore_errors=True)
|
||||
|
||||
def test_credentials_masked_tree_read_only_network_gone(self) -> None:
|
||||
old_home = os.environ["HOME"]
|
||||
os.environ["HOME"] = str(self.home)
|
||||
try:
|
||||
prefix, isolation = core_probe.sandbox_argv([self.out])
|
||||
finally:
|
||||
os.environ["HOME"] = old_home
|
||||
self.assertEqual(isolation, "bwrap")
|
||||
script = (f'cat {self.home}/.config/gh/hosts.yml {self.home}/.ssh/id_ed25519 '
|
||||
f'{self.home}/.git-credentials 2>/dev/null; echo ok > {self.out}/w; '
|
||||
f'echo no > {self.elsewhere}/w 2>/dev/null; tail -n +3 /proc/net/dev | cut -d: -f1')
|
||||
proc = subprocess.run(prefix + ["/bin/sh", "-c", script], capture_output=True, text=True,
|
||||
check=False, env={})
|
||||
self.assertNotIn("secret", proc.stdout)
|
||||
self.assertEqual((self.out / "w").read_text(), "ok\n")
|
||||
self.assertFalse((self.elsewhere / "w").exists())
|
||||
self.assertEqual(proc.stdout.split(), ["lo"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in new issue
Block a user