[core] Tighten legacy redaction regex to avoid mid-word matches

The trailing \w* after the fragment over-matched fields like
key_value_pair: which the prior regex did not catch. Drop it so the
fragment must end the captured field name, preserving the previous
matching scope while still capturing the full field name (via the
leading \w*) for the warning message.
This commit is contained in:
J. Nick Koston
2026-05-26 22:06:25 -05:00
parent 2e53a226a3
commit 27385cee32
2 changed files with 17 additions and 2 deletions

View File

@@ -1427,9 +1427,12 @@ def command_config(args: ArgsProtocol, config: ConfigType) -> int | None:
# in 2026.12.0 once canonical sensitive fields are migrated.
#
# The negative lookahead ``(?!\\033\[8m)`` skips values already wrapped by the
# SensitiveStr representer, so explicit tagging silences the warning.
# SensitiveStr representer, so explicit tagging silences the warning. No
# trailing ``\w*`` after the fragment so the fragment must end the field
# name (preserves the prior regex's matching scope while letting the
# leading ``\w*`` capture the full field name for the warning).
_LEGACY_REDACTION_RE = re.compile(
r"(?P<key>\w*(?:password|key|psk|ssid)\w*)\: (?!\\033\[8m)(?P<val>.+)"
r"(?P<key>\w*(?:password|key|psk|ssid))\: (?!\\033\[8m)(?P<val>.+)"
)
_LEGACY_REDACTION_REMOVAL = "2026.12.0"

View File

@@ -387,6 +387,18 @@ def test_redact_with_legacy_fallback__deduplicates_warnings(
assert len(password_warnings) == 1
def test_redact_with_legacy_fallback__does_not_match_fragment_in_middle(
caplog: pytest.LogCaptureFixture,
) -> None:
"""Fragment must end the field name; embedded matches like
``key_value_pair`` are unrelated to a sensitive key and must not be
redacted (matching the prior regex's scope)."""
with caplog.at_level(logging.WARNING, logger="esphome.__main__"):
out = _redact_with_legacy_fallback("key_value_pair: abc\n")
assert "\\033[8m" not in out
assert not any("legacy substring" in rec.message for rec in caplog.records)
def test_choose_upload_log_host_with_string_default() -> None:
"""Test with a single string default device."""
setup_core()