"""Logging helpers that prevent sensitive values from reaching application logs.""" import logging import re _SENSITIVE_KEY = r"(?:password|passwd|secret|token|authorization|credential|client_secret|corpsecret|code)" _KEY_VALUE_PATTERN = re.compile( rf"(?i)([\"']?{_SENSITIVE_KEY}[\"']?\s*[:=]\s*)([\"']?)([^\s,;\]\}}\"']+)([\"']?)" ) _BEARER_PATTERN = re.compile(r"(?i)(authorization\s*[:=]\s*bearer\s+)[^\s,;]+") _QUERY_PATTERN = re.compile(rf"(?i)([?&]{_SENSITIVE_KEY}=)[^&\s]+") def redact_log_message(message: str) -> str: """Mask common secret formats while keeping enough context for operations.""" masked = _BEARER_PATTERN.sub(r"\1***", message) masked = _QUERY_PATTERN.sub(r"\1***", masked) return _KEY_VALUE_PATTERN.sub(r"\1\2***\4", masked) class SensitiveDataFilter(logging.Filter): """Redact sensitive values after interpolation and before formatter output.""" def filter(self, record: logging.LogRecord) -> bool: record.msg = redact_log_message(record.getMessage()) record.args = () return True