0eb899afb9
Notifications: - Add shared http_base, redact, and SSRF hardening modules - Refactor dispatcher, queue, receiver and per-provider clients (telegram, discord, email, matrix, ntfy, slack, webhook) to use the shared base, with bounded queue and redacted error logs - Tests for ssrf, redact, http_base, queue bounds, dispatcher aggregation, telegram media partition, email and matrix clients Frontend: - Settings: log level / log format selectors now use IconGridSelect with per-option icons and i18n descriptions - Minor providers page and entity-cache store updates Tooling: - Document code-review-graph MCP usage in CLAUDE.md - Ignore .code-review-graph/, register .mcp.json
75 lines
2.1 KiB
Python
75 lines
2.1 KiB
Python
"""Secret-redaction helper regression tests.
|
|
|
|
Locks in the patterns that surface from real provider error paths:
|
|
Telegram bot URLs in aiohttp.ClientError messages, Authorization Bearer
|
|
tokens in Matrix/ntfy responses, Discord/Slack webhook tokens, URL
|
|
userinfo, and common ?token= query params.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from notify_bridge_core.notifications.redact import redact, redact_exc
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"raw,expected_substr,not_in",
|
|
[
|
|
(
|
|
"Cannot connect to host api.telegram.org/bot1234567:AABBCC-secret-token/sendMessage",
|
|
"api.telegram.org/bot***",
|
|
"AABBCC-secret-token",
|
|
),
|
|
(
|
|
"Authorization: Bearer ey.JhbGciOiJIUzI1NiJ9.payload.sig",
|
|
"Bearer ***",
|
|
"ey.JhbGciOiJIUzI1NiJ9",
|
|
),
|
|
(
|
|
"POST https://discord.com/api/webhooks/12345/abcdefg-token failed",
|
|
"discord.com/api/webhooks/12345/***",
|
|
"abcdefg-token",
|
|
),
|
|
(
|
|
"POST https://hooks.slack.com/services/T01/B02/zzzzz failed",
|
|
"hooks.slack.com/services/T01/B02/***",
|
|
"zzzzz",
|
|
),
|
|
(
|
|
"fetch http://user:supersecret@example.com/foo",
|
|
"http://***@example.com/foo",
|
|
"supersecret",
|
|
),
|
|
(
|
|
"https://api.example.com/x?token=mytoken123&extra=ok",
|
|
"token=***",
|
|
"mytoken123",
|
|
),
|
|
],
|
|
)
|
|
def test_redact_known_secrets(raw: str, expected_substr: str, not_in: str) -> None:
|
|
out = redact(raw)
|
|
assert expected_substr in out
|
|
assert not_in not in out
|
|
|
|
|
|
def test_redact_idempotent() -> None:
|
|
once = redact("Bearer abcdefghij1234567890")
|
|
twice = redact(once)
|
|
assert once == twice
|
|
|
|
|
|
def test_redact_exc_returns_str() -> None:
|
|
err = RuntimeError("Bearer abcdefghij1234567890")
|
|
out = redact_exc(err)
|
|
assert isinstance(out, str)
|
|
assert "Bearer ***" in out
|
|
assert "abcdefghij1234567890" not in out
|
|
|
|
|
|
def test_redact_handles_non_string() -> None:
|
|
# Coercion path should not raise.
|
|
out = redact(12345) # type: ignore[arg-type]
|
|
assert out == "12345"
|