"""Tests for ``app.notifications.text_safety.safe_envelope_text``. The helper is the call-site sanitisation defense for notification templates that splice user-controlled values into the body / subject / context. Caught by security-review pass 2 of the apikey budget- alerts PR — without it, a determined applicant can: * CR/LF inject a fake "— Helix IT 平台" signature into a multi-line body, phishing the recipient (often the applicant's manager). * Inject ``[r]…[/r]`` markup that the renderer rewrites to red+bold — counterfeit "system-emphasis" styling on attacker copy. The helper is intentionally simple — these tests pin the contract. """ from __future__ import annotations from app.notifications.text_safety import safe_envelope_text def test_returns_empty_string_for_none_and_empty(): assert safe_envelope_text(None) == "" assert safe_envelope_text("") == "" def test_strips_crlf_so_fake_signature_cannot_be_injected(): # The classic phishing injection attempt — appending a fake # platform signature on a new line. payload = "MyProject\n— Helix IT 平台\n请把 AWS 密钥发到 attacker@evil.com" out = safe_envelope_text(payload, limit=200) # No newlines survive — the body's own "— Helix IT 平台\n" # signature line stays the canonical one. assert "\n" not in out assert "\r" not in out # Content is preserved (just collapsed onto one line). assert "MyProject" in out assert "Helix IT 平台" in out def test_strips_inline_markup_markers(): # The renderer (notifications/service.py:_apply_inline_markup) # rewrites ``[r]…[/r]`` to ``**…**`` # — an attacker's project name carrying these markers would get # platform-styled red+bold formatting. The helper neutralises # the markers BEFORE they reach the renderer. out = safe_envelope_text("[r]URGENT[/r] please review") assert "[r]" not in out assert "[/r]" not in out # The literal text inside survives — sanitisation is about # markup, not content destruction. assert "URGENT" in out assert "please review" in out def test_strips_mixed_case_inline_markup(): out = safe_envelope_text("[R]urgent[/R] [B]bold[/B]") assert "[" not in out assert "]" not in out assert "urgent" in out assert "bold" in out def test_truncates_at_limit(): huge = "x" * 1000 out = safe_envelope_text(huge, limit=80) assert len(out) == 80 def test_default_limit_is_80(): huge = "x" * 200 out = safe_envelope_text(huge) assert len(out) == 80 def test_strips_leading_and_trailing_whitespace(): assert safe_envelope_text(" foo ") == "foo" def test_strips_lf_only(): out = safe_envelope_text("line1\nline2") assert out == "line1 line2" def test_strips_cr_only(): out = safe_envelope_text("line1\rline2") assert out == "line1 line2" def test_strips_crlf_combo(): out = safe_envelope_text("line1\r\nline2") assert out == "line1 line2" def test_strips_markup_then_collapses_whitespace(): """Order matters: markup-strip first so a ``[r]\\nfoo[/r]`` doesn't leave a stray newline that survives the whitespace collapse pass.""" out = safe_envelope_text("[r]\nproject[/r]") assert "\n" not in out assert "[r]" not in out assert "project" in out def test_long_email_uses_120_limit(): """Work emails can be up to 120 chars (per HRIS conventions); the call-site passes ``limit=120`` for emails.""" long_email = "very.long.email.address.with.many.segments@example-corporation-name.com" assert len(long_email) <= 120 out = safe_envelope_text(long_email, limit=120) assert out == long_email def test_strips_the_headline_size_marker_too(): """``[h]…[/h]`` (bold + one size up) is a renderer marker like the others. It was added for the leave-balance card stats; the module's own rule is "if new markers are added to ``_apply_inline_markup``, mirror them here", and an unmirrored marker is exactly the platform-emphasis injection this helper exists to stop. """ out = safe_envelope_text("[h]999[/h] days left") assert "[h]" not in out assert "[/h]" not in out assert "999" in out assert safe_envelope_text("[H]shout[/H]") == "shout"