[core] Anchor legacy redaction regex to avoid false-positive warnings

The unanchored leading \w* could match fields like 'monkey:' (via the
'key' fragment), naming a non-sensitive field in the deprecation
warning. Restrict the fragment to either start the name or follow '_',
so warnings only fire when there's an actual sensitive-shaped field
the author can migrate.
This commit is contained in:
J. Nick Koston
2026-05-26 22:46:41 -05:00
parent 14a5ee87fe
commit 4c6437b825
2 changed files with 16 additions and 3 deletions
+4 -3
View File
@@ -1424,10 +1424,11 @@ def command_config(args: ArgsProtocol, config: ConfigType) -> int | None:
# 2026.12.0 once canonical sensitive fields are tagged. The lookahead skips
# values that already render themselves: ``\033[8m`` (SensitiveStr wrap),
# ``!secret`` (preserves the user-friendly tag), ``!lambda`` (multi-line
# block; first line is structural). Un-anchored on purpose to match the
# prior regex; leading ``\w*`` captures the full field name for warnings.
# block; first line is structural). The fragment must either start the
# field name or follow ``_`` so the warning names a real field; this avoids
# false positives like ``monkey:`` matching the ``key`` fragment.
_LEGACY_REDACTION_RE = re.compile(
r"(?P<key>\w*(?:password|key|psk|ssid))\: "
r"(?P<key>\b(?:\w+_)?(?:password|key|psk|ssid))\: "
r"(?!\\033\[8m|!secret\b|!lambda\b)(?P<val>.+)"
)
_LEGACY_REDACTION_REMOVAL = "2026.12.0"
+12
View File
@@ -424,6 +424,18 @@ def test_redact_with_legacy_fallback__does_not_match_fragment_in_middle(
assert not any("legacy substring" in rec.message for rec in caplog.records)
def test_redact_with_legacy_fallback__does_not_match_fragment_as_suffix(
caplog: pytest.LogCaptureFixture,
) -> None:
"""Fragment must start the name or follow ``_``; ``monkey:`` shouldn't
fire a 'legacy heuristic' warning because there's no sensitive field
here — the user has nothing to migrate."""
with caplog.at_level(logging.WARNING, logger="esphome.__main__"):
out = _redact_with_legacy_fallback("monkey: 1234\n")
assert "\\033[8m" not in out
assert not any("legacy substring" in rec.message for rec in caplog.records)
def test_command_config__invokes_legacy_fallback_when_redacting(
tmp_path: Path, capfd: CaptureFixture[str]
) -> None: