from __future__ import annotations from typing import Any SECRET_HINTS = ( "token", "password", "secret", "key", "authorization", "credential", "cookie", ) def redact_value(value: Any, key: str = "", secrets: tuple[str, ...] = ()) -> Any: lowered = key.lower() if any(part in lowered for part in SECRET_HINTS): return "***" if isinstance(value, dict): return { str(item_key): redact_value(item_value, str(item_key), secrets) for item_key, item_value in value.items() } if isinstance(value, list): return [redact_value(item, key, secrets) for item in value] text = str(value) if value is not None and not isinstance(value, (int, float, bool)) else value if isinstance(text, str): return redact_text(text, secrets) return value def redact_text(text: str, secrets: tuple[str, ...] = ()) -> str: redacted = text for secret in secrets: if secret: redacted = redacted.replace(secret, "***") return redacted