← Files Codex ReplayARCHIVED FILE

tests/test_node_runtime.py

6.22 KB · Oct 2, 2026 · 00:19 UTC

↓ Download file

"""Node runtime discovery under restricted MCP server environments."""

from __future__ import annotations

import json
import os
import sys
import tempfile
import unittest
from pathlib import Path
from unittest import mock

from test_mcp_server import load_server


class NodeRuntimeTests(unittest.TestCase):
    def test_packaged_worker_can_spawn_its_node_wrapper_without_node_on_path(self) -> None:
        server = load_server()
        node_runtime = server._node_runtime()
        with tempfile.TemporaryDirectory() as temporary:
            root = Path(temporary)
            run_directory = root / "run"
            run_directory.mkdir()
            host_bin = root / "host-bin"
            host_bin.mkdir()
            fake_codex = host_bin / "codex"
            fake_codex.write_text(
                "\n".join(
                    [
                        f"#!{sys.executable}",
                        "import json, os, sys",
                        "if sys.argv[1:] == ['--version']:",
                        "    print('codex fixture')",
                        "    raise SystemExit(0)",
                        "sys.stdin.read()",
                        "print(json.dumps({'type': 'thread.started', 'thread_id': 'runtime-thread'}))",
                        "environment = {name: os.environ[name] for name in ('PATH', 'GIT_EXEC_PATH')}",
                        "print(json.dumps({'type': 'item.completed', 'item': {'type': 'agent_message', 'text': json.dumps(environment)}}))",
                        "print(json.dumps({'type': 'turn.completed', 'usage': {'input_tokens': 1, 'output_tokens': 1}}))",
                        "",
                    ]
                ),
                encoding="utf-8",
            )
            fake_codex.chmod(0o700)
            environment = {
                "PATH": str(host_bin),
                "CODEX_MCP_NODE_PATH": node_runtime,
                "CODEX_CLI_PATH": str(fake_codex),
                "GIT_EXEC_PATH": str(root / "host-git-helpers"),
            }
            with mock.patch.dict(os.environ, environment, clear=True):
                result = server._run_worker(
                    {"model": "gpt-5.6-sol", "prompt": "Check the worker runtime."},
                    run_directory=run_directory,
                    working_directory=root,
                    read_only=True,
                    log_label="runtime-test",
                    timeout=10,
                )
                self.assertEqual(os.environ["PATH"], str(host_bin))

            self.assertEqual(result["thread_id"], "runtime-thread")
            child_environment = json.loads(result["finalResponse"])
            self.assertEqual(
                child_environment["PATH"],
                os.pathsep.join([str(host_bin), str(Path(node_runtime).parent)]),
            )
            self.assertEqual(child_environment["GIT_EXEC_PATH"], environment["GIT_EXEC_PATH"])

    def test_uses_codex_runtime_hints_without_path(self) -> None:
        server = load_server()
        with tempfile.TemporaryDirectory() as temporary:
            root = Path(temporary)
            cases = (
                (
                    {"CODEX_BROWSER_USE_NODE_PATH": str(root / "browser-node")},
                    root / "browser-node",
                ),
                (
                    {"CODEX_ELECTRON_RESOURCES_PATH": str(root / "resources")},
                    root / "resources" / "cua_node" / "bin" / "node",
                ),
                (
                    {"CODEX_CLI_PATH": str(root / "cli" / "codex")},
                    root / "cli" / "cua_node" / "bin" / "node",
                ),
            )
            for environment, node in cases:
                with self.subTest(environment=environment):
                    node.parent.mkdir(parents=True, exist_ok=True)
                    node.write_text("#!/bin/sh\nprintf 'v22.0.0\\n'\n", encoding="utf-8")
                    node.chmod(0o700)
                    with mock.patch.dict(os.environ, {"PATH": "", **environment}, clear=True):
                        self.assertEqual(server._node_runtime(), str(node))

    def test_uses_bundled_runtime_without_path(self) -> None:
        server = load_server()
        with tempfile.TemporaryDirectory() as temporary:
            cache_root = Path(temporary)
            node = cache_root / "codex-runtimes/codex-primary-runtime/dependencies/node/bin/node"
            node.parent.mkdir(parents=True)
            node.write_text("#!/bin/sh\nprintf 'v22.0.0\\n'\n", encoding="utf-8")
            node.chmod(0o700)
            with mock.patch.dict(
                os.environ, {"XDG_CACHE_HOME": str(cache_root), "PATH": ""}, clear=True
            ):
                self.assertEqual(server._node_runtime(), str(node))

    def test_uses_homebrew_without_path(self) -> None:
        server = load_server()
        node = Path("/opt/homebrew/bin/node")
        with (
            mock.patch.dict(os.environ, {"PATH": ""}, clear=True),
            mock.patch.object(
                server.Path, "is_file", autospec=True, side_effect=lambda path: path == node
            ),
            mock.patch.object(server.os, "access", return_value=True),
            mock.patch.object(
                server.subprocess, "run", return_value=mock.Mock(returncode=0, stdout="v22.0.0\n")
            ),
        ):
            self.assertEqual(server._node_runtime(), str(node))

    def test_skips_unsupported_fallback_runtime(self) -> None:
        server = load_server()
        with tempfile.TemporaryDirectory() as temporary:
            cache_root = Path(temporary)
            node = cache_root / "codex-runtimes/codex-primary-runtime/dependencies/node/bin/node"
            node.parent.mkdir(parents=True)
            node.write_text("#!/bin/sh\nprintf 'v16.20.0\\n'\n", encoding="utf-8")
            node.chmod(0o700)
            with (
                mock.patch.dict(
                    os.environ, {"XDG_CACHE_HOME": str(cache_root), "PATH": ""}, clear=True
                ),
                mock.patch.object(
                    server.Path, "is_file", autospec=True, side_effect=lambda path: path == node
                ),
                mock.patch.object(server.shutil, "which", return_value="/existing/node"),
            ):
                self.assertEqual(server._node_runtime(), "/existing/node")

SHA-256: 34592733b082a5fa8fa816a27cf1c8f59bb98bd12be9f0d4ef67099f60c4c884