#!/usr/bin/env python3 """Regresión del aislamiento de las sesiones del lanzador, sin Docker ni credenciales.""" import json import os from pathlib import Path import subprocess import tempfile import tomllib import unittest ROOT = Path(__file__).resolve().parent.parent class SessionLauncherTests(unittest.TestCase): def setUp(self): artifacts = ROOT / ".artifacts/playwright" artifacts.mkdir(parents=True, exist_ok=True) self.directory = tempfile.TemporaryDirectory(prefix="session-guard-", dir=artifacts) self.root = Path(self.directory.name) self.executable = self.root / "codex-probe" self.executable.write_text("#!/usr/bin/env python3\nimport json,sys\nprint(json.dumps({'args':sys.argv[1:],'stdin':sys.stdin.read()}))\n") self.executable.chmod(0o700) def tearDown(self): self.directory.cleanup() def state(self, domain="localhost", mode=0o600): path = self.root / "session.json" path.write_text(json.dumps({"cookies": [{"name": "metis.sid", "domain": domain, "httpOnly": True, "value": "placeholder-not-a-session"}]})) path.chmod(mode) return path def launch(self, state=None): environment = {**os.environ, "METIS_CODEX_BIN": str(self.executable)} environment.pop("METIS_PLAYWRIGHT_STORAGE_STATE", None) if state is not None: environment["METIS_PLAYWRIGHT_STORAGE_STATE"] = str(state) return subprocess.run(["bash", str(ROOT / "scripts/codex-playwright-wsl.sh"), "mcp", "list", "--json"], input="stdin-check", text=True, capture_output=True, env=environment, cwd=self.root, timeout=15, check=False) def args(self, result): self.assertEqual(result.returncode, 0, result.stderr) payload = json.loads(result.stdout) self.assertEqual(payload["stdin"], "stdin-check") argument = next(item for item in payload["args"] if item.startswith("mcp_servers.playwright.args=")) return tomllib.loads(argument)["mcp_servers"]["playwright"]["args"] def test_default_has_no_session(self): self.assertFalse(any("storage-state" in item or "type=bind" in item for item in self.args(self.launch()))) def test_private_session_is_readonly_and_not_in_arguments(self): state = self.state() args = self.args(self.launch(state.relative_to(ROOT))) self.assertTrue(any("readonly" in item and str(state) in item for item in args)) self.assertEqual(args.count("--storage-state=/tmp/metis-audit-state.json"), 1) self.assertNotIn("placeholder-not-a-session", " ".join(args)) def test_public_permissions_are_rejected(self): result = self.launch(self.state(mode=0o644)) self.assertNotEqual(result.returncode, 0) self.assertIn("privado", result.stderr) def test_remote_cookie_is_rejected(self): result = self.launch(self.state(domain="production.example.test")) self.assertNotEqual(result.returncode, 0) self.assertIn("locales", result.stderr) def test_external_file_is_rejected(self): with tempfile.TemporaryDirectory() as directory: path = Path(directory) / "session.json" path.write_text("{}") path.chmod(0o600) result = self.launch(path) self.assertNotEqual(result.returncode, 0) self.assertIn("privado", result.stderr) def test_missing_session_is_rejected(self): result = self.launch(self.root / "missing.json") self.assertNotEqual(result.returncode, 0) self.assertIn("ausente", result.stderr) if __name__ == "__main__": unittest.main()