Summary
Add encryption round-trip and decryption-failure tests for the channel bot token encryption that already shipped without dedicated test coverage.
Background
Trinity stores bot/auth tokens for three external channels in encrypted form via services.credential_encryption.CredentialEncryptionService (AES-256-GCM):
The encryption code itself is well-tested via the services.credential_encryption test suite. What's missing: per-channel integration tests that verify the round-trip through each *ChannelOperations class — encrypt-on-write, decrypt-on-read, decryption-failure handling, and the plaintext fallback path (slack_channels.py:47-49).
This was discovered during #453 investigation (see project memory project_453_slack_encryption.md) — Telegram and WhatsApp tables have no encryption-specific test files. Slack-002 (slack_channels.py) also lacks them.
Scope
For each of the three already-shipped encrypted-token storage modules, add a unit test file covering:
tests/unit/test_telegram_token_encryption.py (NEW)
- Round-trip:
create_binding → raw column read → assert JSON envelope → get_decrypted_bot_token returns plaintext
- Decryption failure: tamper with envelope →
_decrypt_token returns None, no exception leaks to caller
- Re-encryption on update: second
create_binding for same agent_name updates the encrypted blob
tests/unit/test_whatsapp_token_encryption.py (NEW)
- Same coverage for
WhatsAppChannelOperations._encrypt_auth_token / _decrypt_auth_token
- Twilio-specific:
account_sid stays plaintext (it's not a credential), only auth_token_encrypted is encrypted
tests/unit/test_slack_workspaces_encryption.py (NEW)
- Round-trip for
SlackChannelOperations._encrypt_token / _decrypt_token
- Plaintext fallback path at
slack_channels.py:47-49 — assert that a row with raw xoxb-* bot_token returns the token via _decrypt_token (current behavior — preserves graceful handling for legacy plaintext rows)
- Verify the warning is logged
Out of scope
Acceptance Criteria
Effort estimate
~2 hours. Mostly mechanical — copy the test pattern from tests/unit/test_slack_token_encryption.py (added in #453) and adapt for each channel's class.
References
Summary
Add encryption round-trip and decryption-failure tests for the channel bot token encryption that already shipped without dedicated test coverage.
Background
Trinity stores bot/auth tokens for three external channels in encrypted form via
services.credential_encryption.CredentialEncryptionService(AES-256-GCM):telegram_bindings.bot_token_encrypted—db/telegram_channels.pywhatsapp_bindings.auth_token_encrypted—db/whatsapp_channels.pyslack_workspaces.bot_token(encrypted-blob-in-text-column) —db/slack_channels.pyslack_link_connections.slack_bot_token—db/slack.py(will be encrypted as part of fix(security): Encrypt Slack and Telegram bot tokens at rest (Invariant #13) #453)The encryption code itself is well-tested via the
services.credential_encryptiontest suite. What's missing: per-channel integration tests that verify the round-trip through each*ChannelOperationsclass — encrypt-on-write, decrypt-on-read, decryption-failure handling, and the plaintext fallback path (slack_channels.py:47-49).This was discovered during #453 investigation (see project memory
project_453_slack_encryption.md) — Telegram and WhatsApp tables have no encryption-specific test files. Slack-002 (slack_channels.py) also lacks them.Scope
For each of the three already-shipped encrypted-token storage modules, add a unit test file covering:
tests/unit/test_telegram_token_encryption.py(NEW)create_binding→ raw column read → assert JSON envelope →get_decrypted_bot_tokenreturns plaintext_decrypt_tokenreturnsNone, no exception leaks to callercreate_bindingfor same agent_name updates the encrypted blobtests/unit/test_whatsapp_token_encryption.py(NEW)WhatsAppChannelOperations._encrypt_auth_token/_decrypt_auth_tokenaccount_sidstays plaintext (it's not a credential), onlyauth_token_encryptedis encryptedtests/unit/test_slack_workspaces_encryption.py(NEW)SlackChannelOperations._encrypt_token/_decrypt_tokenslack_channels.py:47-49— assert that a row with rawxoxb-*bot_token returns the token via_decrypt_token(current behavior — preserves graceful handling for legacy plaintext rows)Out of scope
slack_link_connections(db/slack.py) — this module is getting encryption added as part of fix(security): Encrypt Slack and Telegram bot tokens at rest (Invariant #13) #453, and its tests are part of that PRAcceptance Criteria
test_telegram_token_encryption.pycovers round-trip + decryption-failure (≥3 tests)test_whatsapp_token_encryption.pycovers round-trip + decryption-failure (≥3 tests)test_slack_workspaces_encryption.pycovers round-trip + decryption-failure + plaintext-fallback (≥4 tests)CREDENTIAL_ENCRYPTION_KEYtest fixture pattern (look at how the newdb/slack.pytests do it in fix(security): Encrypt Slack and Telegram bot tokens at rest (Invariant #13) #453's PR for reference)tests/registry.json) updated with the three new entriesEffort estimate
~2 hours. Mostly mechanical — copy the test pattern from
tests/unit/test_slack_token_encryption.py(added in #453) and adapt for each channel's class.References
project_453_slack_encryption.md)src/backend/services/credential_encryption.py(AES-256-GCM, JSON envelope)tests/unit/test_slack_token_encryption.pylooks like after fix(security): Encrypt Slack and Telegram bot tokens at rest (Invariant #13) #453 landsdocs/memory/architecture.md