Files
wehub-resource-sync 25576b0be6
Checks (magui2.0) / python-lint (push) Failing after 1s
Checks (magui2.0) / python-test (push) Failing after 0s
Checks (magui2.0) / frontend-lint (push) Failing after 0s
CodeQL Advanced / Analyze (actions) (push) Failing after 1s
Checks (magui2.0) / python-format (push) Failing after 1s
CodeQL Advanced / Analyze (python) (push) Failing after 0s
Checks (magui2.0) / python-pyright (push) Failing after 1s
Checks (magui2.0) / frontend-format (push) Failing after 1s
Checks (magui2.0) / frontend-typecheck (push) Failing after 0s
Checks (magui2.0) / frontend-test (push) Failing after 2s
CodeQL Advanced / Analyze (javascript-typescript) (push) Failing after 1s
chore: import upstream snapshot with attribution
2026-07-13 12:24:32 +08:00

128 lines
3.8 KiB
Python

"""``_scrub_for_log`` must recursively redact sensitive keys before logging.
The backend logger formats outgoing WebSocket frames as dicts; some carry
per-slot RFB passwords (``browser_address`` messages) or other secrets.
``_scrub_for_log`` walks the structure and replaces values of known-sensitive
keys with ``***REDACTED***`` regardless of nesting depth.
"""
from __future__ import annotations
from typing import Any
from magentic_ui.backend.web.managers.connection import _scrub_for_log
def test_top_level_password_redacted() -> None:
result = _scrub_for_log({"password": "secret-token"})
assert result == {"password": "***REDACTED***"}
def test_nested_password_redacted() -> None:
msg = {"type": "message", "data": {"metadata": {"password": "secret-token"}}}
result = _scrub_for_log(msg)
assert result == {
"type": "message",
"data": {"metadata": {"password": "***REDACTED***"}},
}
def test_deeply_nested_password_redacted() -> None:
msg = {"a": {"b": {"c": {"d": {"password": "secret-token"}}}}}
result = _scrub_for_log(msg)
assert result == {"a": {"b": {"c": {"d": {"password": "***REDACTED***"}}}}}
def test_password_inside_list_of_dicts_redacted() -> None:
msg = {
"items": [
{"password": "a"},
{"password": "b"},
{"other": "c"},
]
}
result = _scrub_for_log(msg)
assert result == {
"items": [
{"password": "***REDACTED***"},
{"password": "***REDACTED***"},
{"other": "c"},
]
}
def test_all_sensitive_keys_redacted() -> None:
msg = {
"password": "p",
"token": "t",
"api_key": "k",
"secret": "s",
"normal": "n",
}
result = _scrub_for_log(msg)
assert result == {
"password": "***REDACTED***",
"token": "***REDACTED***",
"api_key": "***REDACTED***",
"secret": "***REDACTED***",
"normal": "n",
}
def test_case_insensitive_match() -> None:
msg = {"PASSWORD": "x", "Token": "y", "API_KEY": "z"}
result = _scrub_for_log(msg)
assert result == {
"PASSWORD": "***REDACTED***",
"Token": "***REDACTED***",
"API_KEY": "***REDACTED***",
}
def test_non_sensitive_keys_unchanged() -> None:
msg = {"username": "u", "port": 9999, "url": "http://x"}
result = _scrub_for_log(msg)
assert result == msg
def test_primitives_pass_through_unchanged() -> None:
assert _scrub_for_log("hello") == "hello"
assert _scrub_for_log(42) == 42
assert _scrub_for_log(True) is True
assert _scrub_for_log(None) is None
assert _scrub_for_log([1, 2, 3]) == [1, 2, 3]
def test_empty_structures_pass_through() -> None:
assert _scrub_for_log({}) == {}
assert _scrub_for_log([]) == []
def test_real_browser_address_message_redacted() -> None:
"""Repro of the exact message shape the bug produced in logs."""
msg: dict[str, Any] = {
"type": "message",
"data": {
"source": "web_surfer",
"content": [{"type": "text", "text": "Browser ready at noVNC port 59253"}],
"metadata": {
"source": "web_surfer",
"type": "browser_address",
"novnc_port": "59253",
"playwright_port": "51305",
"password": "secret-token",
},
},
}
result = _scrub_for_log(msg)
metadata = result["data"]["metadata"] # type: ignore[index]
assert metadata["password"] == "***REDACTED***"
assert metadata["novnc_port"] == "59253" # unchanged
assert metadata["type"] == "browser_address" # unchanged
def test_original_input_not_mutated() -> None:
msg = {"password": "secret-token"}
_scrub_for_log(msg)
assert msg == {"password": "secret-token"} # original untouched