# Playbook: touch encryption modules safely Encryption stacks (OMEMO, OTR, PGP/OX) are independent and each is gated behind a `configure` option. Edits must respect three things: the gating macro, the bridge file split, and the matching unit-test stubs. See `patterns/encryption.md` for the architectural split. ## 1. Identify the bridge | Stack | Module dir | Bridge file (XMPP side) | |---|---|---| | OMEMO | `src/omemo/` | `src/xmpp/omemo.c` | | OTR | `src/otr/` | (none — in-stream on `src/xmpp/message.c`) | | PGP / OX | `src/pgp/` | `src/xmpp/ox.c` | Outbound calls (cproof → encryption) usually live in the bridge file. Inbound (decrypted message → cproof) usually surfaces in the bridge or directly in `src/xmpp/message.c`. ## 2. Identify the gating macro ```sh grep -n "HAVE_OMEMO\|HAVE_LIBOTR\|HAVE_LIBGPGME" src/xmpp/.c ``` Every call into the encryption module is wrapped: ```c #ifdef HAVE_OMEMO omemo_encrypt_message(jid, plaintext, &ciphertext); #else // graceful fallback or skip #endif ``` When you add a new call, copy the existing guard. Do **not** drop the fallback — the build must succeed with the feature disabled. ## 3. Update the public surface (header) If you add or change an exported function in `src/omemo/omemo.h` / `src/otr/otr.h` / `src/pgp/gpg.h` / `src/pgp/ox.h`, update **two** places: 1. The header itself. 2. The corresponding stub: `tests/unittests/{omemo,otr,pgp}/stub_*.c`. Keep the stub signature byte-for-byte identical to the header. ## 4. Stubs Stubs exist regardless of whether a stack is enabled at runtime — they satisfy the unit-test linker. Three flavours, see `testing/stubs.md`. If a unit test needs to drive the new function, switch the stub to `mock()` and queue with `will_return`. If a unit test needs to assert arguments, switch to `check_expected` and queue with `expect_string` / `expect_value`. ## 5. `test_forced_encryption` `tests/unittests/test_forced_encryption.{c,h}` exercises the policy that refuses plaintext sends when a session is encryption-locked. **Run it after any encryption-policy change.** ## 6. Encryption-aware command tests | Test file | Covers | |---|---| | `test_cmd_otr.c` / `.h` | `/otr` command surface. | | `test_cmd_pgp.c` / `.h` | `/pgp` command surface. | (No `test_cmd_omemo.c` exists at the time of writing — confirm with `ls tests/unittests/test_cmd_*.c` before assuming.) ## 7. Build matrix After changes, build with each encryption flag in turn: ```sh ./configure --disable-omemo make check ./configure --disable-otr make check ./configure --disable-pgp make check ``` (Inside Docker — see `build/docker.md`.) CI does not necessarily run every disable combination; verify locally if your change affects gating logic. ## Conventions - Never strip the `#ifdef HAVE_*` guard "for clarity". The disabled-build must still compile. - Encryption keys / fingerprints persist via the module's own store (`src/ omemo/store.c`, libotr's keystore, gpgme's keyring). Do not invent parallel storage. - Outbound encryption sits between message build and stanza send — see `patterns/xmpp.md` for the flow.