[Bugfix][Frontend] Keep credentials out of the Rust frontend launch log (#53738)

Signed-off-by: mhuzaifa3 <mhuzaifa3@outlook.com>

Moe Huzaifa committed Aug 25, 2026 at 11:32 UTC 3e833933dcaa8456ce8eb0541b8df06ffa8d06a3
4 files changed +60 -6
tests/entrypoints/launchers/api_server/test_api_server_process_manager.py
+49
@@ -401,3 +401,52 @@ def test_gather_actual_addresses_child_crash_before_report():
401 manager.shutdown()
402 time.sleep(0.2)
403 sock.close()
404 +
405 +
406 +def test_rust_frontend_launch_log_redacts_credentials(monkeypatch, caplog):
407 + """The Rust frontend command carries every non-default arg as JSON.
408 + Credentials must not reach the log line."""
409 + import subprocess as subprocess_mod
410 +
411 + from vllm.entrypoints.launchers.cli_args import make_arg_parser
412 + from vllm.utils.argparse_utils import FlexibleArgumentParser
413 + from vllm.v1.utils import RustFrontendProcessManager
414 +
415 + hf_token = "hf_TESTTOKEN123"
416 + api_key = "sk-TESTKEY456"
417 + args = make_arg_parser(FlexibleArgumentParser()).parse_args(
418 + ["--model", "org/model", "--hf-token", hf_token, "--api-key", api_key]
419 + )
420 +
421 + class _FakeProc:
422 + pid = 4321
423 + returncode = 0
424 +
425 + def poll(self):
426 + return 0
427 +
428 + def wait(self, timeout=None):
429 + return 0
430 +
431 + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
432 + try:
433 + monkeypatch.setattr(subprocess_mod, "Popen", lambda *a, **kw: _FakeProc())
434 + with caplog.at_level("INFO", logger="vllm.v1.utils"):
435 + RustFrontendProcessManager(
436 + binary_path="/nonexistent/vllm-rs",
437 + sock=sock,
438 + args=args,
439 + input_address="ipc:///tmp/in",
440 + output_address="ipc:///tmp/out",
441 + engine_start_index=0,
442 + engine_count=1,
443 + data_parallel_size=1,
444 + )
445 + finally:
446 + sock.close()
447 +
448 + message = caplog.text
449 + assert "Launching Rust frontend:" in message
450 + assert hf_token not in message
451 + assert api_key not in message
452 + assert '"hf_token": "***"' in message
tests/entrypoints/serve/utils/test_api_utils.py
+3 -3
@@ -8,8 +8,8 @@ import pytest
8 from vllm.entrypoints.openai.engine.protocol import StreamOptions
9 from vllm.entrypoints.serve.utils import api_utils
10 from vllm.entrypoints.serve.utils.api_utils import (
11 - _redact_sensitive_args,
11 get_max_tokens,
12 + redact_sensitive_args,
13 should_include_usage,
14 )
15
@@ -121,7 +121,7 @@ class TestRedactSensitiveArgs:
121
122 def test_redact_replaces_sensitive_values_only(self):
123 args = {"api_key": self.API_KEY, "hf_token": "hf_secret", "other": "visible"}
124 - redacted = _redact_sensitive_args(args)
124 + redacted = redact_sensitive_args(args)
125 assert redacted == {
126 "api_key": "***",
127 "hf_token": "***",
@@ -136,7 +136,7 @@ class TestRedactSensitiveArgs:
136
137 def test_no_sensitive_fields_returns_original(self):
138 args = {"model_tag": "org/model", "other": "visible"}
139 - assert _redact_sensitive_args(args) is args
139 + assert redact_sensitive_args(args) is args
140
141 def test_api_key_not_in_log(self, monkeypatch, caplog):
142 non_default = {
vllm/entrypoints/serve/utils/api_utils.py
+2 -2
@@ -271,7 +271,7 @@ def jsonify_non_default_args(
271 _SENSITIVE_ARG_FIELDS = frozenset({"api_key", "hf_token"})
272
273
274 -def _redact_sensitive_args(args: dict[str, Any]) -> dict[str, Any]:
274 +def redact_sensitive_args(args: dict[str, Any]) -> dict[str, Any]:
275 """Return a copy of `args` with sensitive values redacted for logging."""
276 if not any(key in _SENSITIVE_ARG_FIELDS for key in args):
277 return args
@@ -283,7 +283,7 @@ def _redact_sensitive_args(args: dict[str, Any]) -> dict[str, Any]:
283
284 def log_non_default_args(args: Namespace | EngineArgs):
285 non_default_args = get_non_default_args(args)
286 - logger.info("non-default args: %s", _redact_sensitive_args(non_default_args))
286 + logger.info("non-default args: %s", redact_sensitive_args(non_default_args))
287
288
289 def should_include_usage(
vllm/v1/utils.py
+6 -1
@@ -389,7 +389,12 @@ class RustFrontendProcessManager:
389 args_json = json.dumps(args_dict, sort_keys=True)
390 cmd.extend(["--args-json", args_json])
391
392 - logger.info("Launching Rust frontend: %s", " ".join(cmd))
392 + # The subprocess needs the real values, but the log must not carry
393 + # credentials such as api_key or hf_token.
394 + from vllm.entrypoints.serve.utils.api_utils import redact_sensitive_args
395 +
396 + redacted_json = json.dumps(redact_sensitive_args(args_dict), sort_keys=True)
397 + logger.info("Launching Rust frontend: %s", " ".join(cmd[:-1] + [redacted_json]))
398 self._proc = subprocess.Popen(cmd, pass_fds=(fd,))
399
400 # Create a process wrapper with a sentinel fd for monitoring