test(channels): every hint that unmasks a secret-shaped key is listed (#1544)

#1544 made a hand-written hint's secret flag authoritative over SECRET_KEY_RE.
That was needed: token_ttl_s and websocket_requires_token were being stripped
from GET values, and every save flipped the stored token requirement to false.
It also makes the hint table the one place a key the regex calls secret can be
sent to the browser unmasked. Email and WebSocket each pin their own secret
set. A new test pins the union across every channel's hints (today the three
WebSocket keys), so the next exemption, Feishu's included, has to be edited
into a reviewed list. A mutant marking token_issue_secret non-secret fails
it with four others.

Also: #1544 moved the fallback-derivation test's second case from websocket
to telegram. telegram needs the optional python-telegram-bot SDK, so on an
install without it the case failed ('should expose default_config()')
instead of skipping as the file's other adapter-loading tests do.
This commit is contained in:
Haozhe Wu committed 2026-09-24 18:50:37 +08:00
1 parent 62842f4f4b
commit 993e3e21fd
1 file changed
+25 -1
+25 -1
View File
@@ -358,7 +358,10 @@ def test_derived_channel_regex_masking_unchanged() -> None:
def test_fallback_derives_types_and_secret_flags(name: str) -> None:
"""Adapters without hand-written hints derive metadata from default_config()."""
config = _section_for(name)
assert config is not None, f"{name} should expose default_config()"
if config is None:
# telegram needs the optional python-telegram-bot SDK; the file's other
# adapter-loading tests skip the same way.
pytest.skip(f"{name} adapter is not loadable in this environment")
hints = channel_field_hints(name)
assert hints, f"{name} fallback should derive at least one field"
by_key = {hint["key"]: hint for hint in hints}
@@ -629,3 +632,24 @@ def test_identifier_fields_stay_visible(name: str) -> None:
def test_unknown_channel_has_no_hints() -> None:
assert channel_field_hints("definitely_not_a_real_channel") == []
# A hand-written hint is authoritative over SECRET_KEY_RE (#1544), which makes
# it the one place a key the regex calls secret can land in GET ``values``,
# unmasked, in the browser. Every such exemption is listed here, so adding one
# -- Feishu's hints are next -- is a reviewed edit, not a flag in a table.
_AUDITED_NON_SECRETS = {
("websocket", "token_issue_path"), # a URL path
("websocket", "token_ttl_s"), # an integer lifetime
("websocket", "websocket_requires_token"), # a boolean switch
}
def test_every_hint_that_unmasks_a_secret_shaped_key_is_audited() -> None:
unmasked = {
(name, hint["key"])
for name, hints in _config_meta.FIELD_HINTS.items()
for hint in hints
if not hint["secret"] and SECRET_KEY_RE.search(hint["key"])
}
assert unmasked == _AUDITED_NON_SECRETS