[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