From b05ffae05195c9fd73e00e446b7d2c11a2f19020 Mon Sep 17 00:00:00 2001 From: liuxianqun Date: Mon, 31 Aug 2026 20:28:08 +0800 Subject: [PATCH] fix: isolate Flow subprocesses from MCP stdin --- src/openadapt_agent/runner.py | 7 ++++++- tests/conftest.py | 4 +++- tests/test_bridge.py | 1 + tests/test_runner.py | 5 +++-- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/openadapt_agent/runner.py b/src/openadapt_agent/runner.py index d46461a..0c1c359 100644 --- a/src/openadapt_agent/runner.py +++ b/src/openadapt_agent/runner.py @@ -501,6 +501,7 @@ def run( try: proc = subprocess.run( cmd, + stdin=subprocess.DEVNULL, capture_output=True, text=True, timeout=self.config.timeout_s, @@ -591,7 +592,11 @@ def certify(self, bundle_dir: Path) -> dict: cmd += ["--config", self.config.deployment_config] try: proc = subprocess.run( - cmd, capture_output=True, text=True, timeout=self.config.timeout_s + cmd, + stdin=subprocess.DEVNULL, + capture_output=True, + text=True, + timeout=self.config.timeout_s, ) except subprocess.TimeoutExpired: return {"certified": None, "detail": "certify timed out"} diff --git a/tests/conftest.py b/tests/conftest.py index 72a9cc7..82701ad 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -67,13 +67,15 @@ def __init__(self, exit_code: int = 0, report: dict | None = None): self.exit_code = exit_code self.report = report self.calls: list[list[str]] = [] + self.stdins: list[object] = [] self.stdout = "stub stdout" self.stderr = "" - def __call__(self, cmd, capture_output=True, text=True, timeout=None): + def __call__(self, cmd, stdin=None, capture_output=True, text=True, timeout=None): import subprocess self.calls.append(list(cmd)) + self.stdins.append(stdin) if "--run-dir" in cmd: run_dir = Path(cmd[cmd.index("--run-dir") + 1]) run_dir.mkdir(parents=True, exist_ok=True) diff --git a/tests/test_bridge.py b/tests/test_bridge.py index 7c6d254..a5e5555 100644 --- a/tests/test_bridge.py +++ b/tests/test_bridge.py @@ -438,6 +438,7 @@ def test_certify_result_is_fixed_copy_unless_protected_export_enabled( cmd = stub.calls[0] assert cmd[1] == "certify" assert cmd[cmd.index("--policy") + 1] == "clinical-write" + assert stub.stdins == [runner_mod.subprocess.DEVNULL] def test_workflow_names_intents_recorded_values_and_paths_never_default_export( diff --git a/tests/test_runner.py b/tests/test_runner.py index 1d1ce7b..cc605cd 100644 --- a/tests/test_runner.py +++ b/tests/test_runner.py @@ -48,6 +48,7 @@ def test_success_mapping(monkeypatch, runner_config, bundle_dir, success_report) assert cmd[0] == "openadapt-flow-stub" and cmd[1] == "run" assert "--params-file" in cmd and "--run-dir" in cmd assert "hello" not in " ".join(cmd) + assert stub.stdins == [subprocess.DEVNULL] def test_halt_maps_to_structured_halt_not_success( @@ -259,7 +260,7 @@ def test_exit_two_is_governed_refusal(monkeypatch, runner_config, bundle_dir): def test_timeout_maps_to_timeout(monkeypatch, runner_config, bundle_dir): - def raise_timeout(cmd, capture_output=True, text=True, timeout=None): + def raise_timeout(cmd, stdin=None, capture_output=True, text=True, timeout=None): raise subprocess.TimeoutExpired(cmd, timeout, output=b"partial", stderr=b"") outcome = _run(monkeypatch, runner_config, raise_timeout, bundle_dir=bundle_dir) @@ -269,7 +270,7 @@ def raise_timeout(cmd, capture_output=True, text=True, timeout=None): def test_missing_cli_maps_to_error(monkeypatch, runner_config, bundle_dir): - def raise_missing(cmd, capture_output=True, text=True, timeout=None): + def raise_missing(cmd, stdin=None, capture_output=True, text=True, timeout=None): raise FileNotFoundError(cmd[0]) outcome = _run(monkeypatch, runner_config, raise_missing, bundle_dir=bundle_dir)