diff --git a/libs/cli/langgraph_cli/exec.py b/libs/cli/langgraph_cli/exec.py index 32c3d3470..72257b098 100644 --- a/libs/cli/langgraph_cli/exec.py +++ b/libs/cli/langgraph_cli/exec.py @@ -44,11 +44,8 @@ async def subp_exec( on_stdout: Callable[[str], bool | None] | None = None, ) -> tuple[str | None, str | None]: if verbose: - cmd_str = f"+ {cmd} {' '.join(map(str, args))}" - if input: - print(cmd_str, " <\n", "\n".join(filter(None, input.splitlines())), sep="") - else: - print(cmd_str) + # Never echo stdin: it can carry secrets (docker login --password-stdin). + print(f"+ {cmd} {' '.join(map(str, args))}") if wait: await asyncio.sleep(wait) diff --git a/libs/cli/tests/unit_tests/test_exec.py b/libs/cli/tests/unit_tests/test_exec.py new file mode 100644 index 000000000..e17f17eed --- /dev/null +++ b/libs/cli/tests/unit_tests/test_exec.py @@ -0,0 +1,17 @@ +import sys + +from langgraph_cli.exec import subp_exec + + +async def test_verbose_prints_command_but_not_stdin(capsys): + await subp_exec( + sys.executable, + "-c", + "import sys; sys.stdin.read()", + input="registry-push-token\n", + verbose=True, + ) + + out = capsys.readouterr().out + assert out.startswith(f"+ {sys.executable} -c"), out + assert "registry-push-token" not in out, out