"""Tests for PII redaction in gateway session context prompts.""" from gateway.session import ( SessionContext, SessionSource, build_session_context_prompt, _hash_id, _hash_sender_id, _hash_chat_id, ) from gateway.config import Platform, HomeChannel # --------------------------------------------------------------------------- # Low-level helpers # --------------------------------------------------------------------------- class TestHashHelpers: def test_hash_id_deterministic(self): assert _hash_id("12345") == _hash_id("12345") def test_hash_id_12_hex_chars(self): h = _hash_id("user-abc") assert len(h) == 12 assert all(c in "0123456789abcdef" for c in h) def test_hash_sender_id_prefix(self): assert _hash_sender_id("12345").startswith("user_") assert len(_hash_sender_id("12345")) == 17 # "user_" + 12 def test_hash_chat_id_preserves_prefix(self): result = _hash_chat_id("telegram:12345") assert result.startswith("telegram:") assert "12345" not in result def test_hash_chat_id_no_prefix(self): result = _hash_chat_id("12345") assert len(result) == 12 assert "12345" not in result # --------------------------------------------------------------------------- # Integration: build_session_context_prompt # --------------------------------------------------------------------------- def _make_context( user_id="user-123", user_name=None, chat_id="telegram:99999", platform=Platform.TELEGRAM, home_channels=None, ): source = SessionSource( platform=platform, chat_id=chat_id, chat_type="dm", user_id=user_id, user_name=user_name, ) return SessionContext( source=source, connected_platforms=[platform], home_channels=home_channels or {}, ) class TestBuildSessionContextPromptRedaction: def test_no_redaction_by_default(self): ctx = _make_context(user_id="user-123") prompt = build_session_context_prompt(ctx) assert "user-123" in prompt def test_user_id_hashed_when_redact_pii(self): ctx = _make_context(user_id="user-123") prompt = build_session_context_prompt(ctx, redact_pii=True) assert "user-123" not in prompt assert "user_" in prompt # hashed ID present def test_user_name_not_redacted(self): ctx = _make_context(user_id="user-123", user_name="Alice") prompt = build_session_context_prompt(ctx, redact_pii=True) assert "Alice" in prompt # user_id should not appear when user_name is present (name takes priority) assert "user-123" not in prompt def test_home_channel_id_hashed(self): hc = { Platform.TELEGRAM: HomeChannel( platform=Platform.TELEGRAM, chat_id="telegram:99999", name="Home Chat", ) } ctx = _make_context(home_channels=hc) prompt = build_session_context_prompt(ctx, redact_pii=True) assert "99999" not in prompt assert "telegram:" in prompt # prefix preserved assert "Home Chat" in prompt # name not redacted def test_home_channel_id_preserved_without_redaction(self): hc = { Platform.TELEGRAM: HomeChannel( platform=Platform.TELEGRAM, chat_id="telegram:99999", name="Home Chat", ) } ctx = _make_context(home_channels=hc) prompt = build_session_context_prompt(ctx, redact_pii=False) assert "99999" in prompt def test_redaction_is_deterministic(self): ctx = _make_context(user_id="+15551234567") prompt1 = build_session_context_prompt(ctx, redact_pii=True) prompt2 = build_session_context_prompt(ctx, redact_pii=True) assert prompt1 == prompt2 def test_different_ids_produce_different_hashes(self): ctx1 = _make_context(user_id="user-A") ctx2 = _make_context(user_id="user-B") p1 = build_session_context_prompt(ctx1, redact_pii=True) p2 = build_session_context_prompt(ctx2, redact_pii=True) assert p1 != p2 def test_discord_ids_not_redacted_even_with_flag(self): """Discord needs real IDs for <@user_id> mentions.""" ctx = _make_context(user_id="123456789", platform=Platform.DISCORD) prompt = build_session_context_prompt(ctx, redact_pii=True) assert "123456789" in prompt def test_whatsapp_ids_redacted(self): ctx = _make_context(user_id="+15551234567", platform=Platform.WHATSAPP) prompt = build_session_context_prompt(ctx, redact_pii=True) assert "+15551234567" not in prompt assert "user_" in prompt def test_signal_ids_redacted(self): ctx = _make_context(user_id="+15551234567", platform=Platform.SIGNAL) prompt = build_session_context_prompt(ctx, redact_pii=True) assert "+15551234567" not in prompt assert "user_" in prompt def test_slack_ids_not_redacted(self): """Slack may need IDs for mentions too.""" ctx = _make_context(user_id="U12345ABC", platform=Platform.SLACK) prompt = build_session_context_prompt(ctx, redact_pii=True) assert "U12345ABC" in prompt