#!/usr/bin/env python3 """Execute room per-client path commands and delivery against production bodies.""" from pathlib import Path import re import shutil import subprocess import sys import tempfile import unittest from test_replay_reset_integration import extract_braced ROOT = Path(__file__).resolve().parents[1] FIXTURE = ROOT / "test/fixtures/room_client_paths.cpp" CASES = r''' static void roleCases() { for (unsigned permissions = 0; permissions < 256; ++permissions) { for (bool logged_in : {false, true}) { MyMesh mesh; auto& own = mesh.acl.clients[0]; own.permissions = permissions; own.last_activity = logged_in ? 800 : 0; const ClientInfo other = mesh.acl.clients[1]; const uint8_t role = permissions & PERM_ACL_ROLE_MASK; const bool allowed = role == PERM_ACL_READ_ONLY || role == PERM_ACL_READ_WRITE || role == PERM_ACL_ADMIN || (role == PERM_ACL_GUEST && logged_in); mesh.command("set altpath B1,B2"); assert(mesh.general_commands == 0); assert(memcmp(&mesh.acl.clients[1], &other, sizeof(other)) == 0); assert(own.permissions == permissions && !own.permissions_are_explicit); if (allowed) { assert(own.alt_path_len == 2 && own.alt_path[0] == 0xB1 && own.alt_path[1] == 0xB2); assert(mesh.reply() == "> B1,B2"); assert(mesh.acl.saves == (role == PERM_ACL_ADMIN ? 1U : 0U)); } else { assert(own.alt_path_len == OUT_PATH_UNKNOWN && mesh.acl.saves == 0); if (role == PERM_ACL_GUEST) { assert(mesh.sent.empty() && own.last_timestamp == 99 && own.last_activity == 0); mesh.command("set altpath C1", 101); assert(own.alt_path_len == OUT_PATH_UNKNOWN && own.last_activity == 0); assert(mesh.sent.empty() && own.last_timestamp == 99); } else assert(mesh.reply().find("Err") != std::string::npos); } } } MyMesh mesh; char command[] = "get outpath", reply[180]{}; assert(mesh.handleClientPathCommand(nullptr, command, reply)); assert(strstr(reply, "Err") && mesh.acl.saves == 0); puts("256 permission combinations and live reader roles remain self-only passed"); } static void exactAllowlist() { const char* rejected[] = { "get prv.key", "erase", "set password owned", "set radio 915,500,5,8", "get outpathx", "get outpath path extra", "get altpath path", "set outpathx direct", "set altpath path", "get outpath;erase", "set outpath A1;erase", "AA|BB|set outpath direct", "set outpath direct;erase", "set altpath B1,,B2", "set outpath B1,", "set outpath B1,1234", "set outpath +B", "set outpath", }; for (const char* text : rejected) { MyMesh mesh; const ClientInfo before = mesh.acl.clients[0], other = mesh.acl.clients[1]; mesh.command(text); const auto& own = mesh.acl.clients[0]; assert(mesh.general_commands == 0 && mesh.acl.saves == 0); assert(own.permissions == before.permissions && own.out_path_len == before.out_path_len); assert(memcmp(own.out_path, before.out_path, MAX_PATH_SIZE) == 0); assert(own.alt_path_len == before.alt_path_len); assert(memcmp(&mesh.acl.clients[1], &other, sizeof(other)) == 0); assert(mesh.reply().find("Err") != std::string::npos); } MyMesh normalized; normalized.command(" AA| SET outpath B1,B2 \t\r\n"); assert(normalized.acl.clients[0].out_path_len == 2); assert(normalized.reply() == "AA|> B1,B2" && normalized.general_commands == 0); MyMesh chat; chat.command("set outpath B1", 100, 0, 0, TXT_TYPE_PLAIN); assert(chat.post_count == 1 && chat.acl.clients[0].out_path[0] == 0xA1); MyMesh banned; assert(banned.room_access.addBan(&banned.policy_fs, banned.acl.clients[0].id.pub_key) == mesh::RoomAccessPolicy::BanResult::Saved); banned.command("set outpath B1"); assert(banned.sent.empty() && banned.acl.clients[0].out_path[0] == 0xA1); puts("exact allowlist, correlation normalization, chat isolation, and ban gates passed"); } static void pathFormats() { struct Case { const char* command; uint8_t length; const char* response; }; const Case cases[] = { {"set outpath B1,B2", 2, "> B1,B2"}, {"set outpath b100, b200", 0x42, "> B100,B200"}, {"set outpath B10011\tB20022", 0x82, "> B10011,B20022"}, {"set outpath direct", 0, "> direct"}, {"set outpath clear", OUT_PATH_UNKNOWN, "> outpath cleared"}, {"set outpath flood", OUT_PATH_FORCE_FLOOD, "> flood"}, {"set altpath direct", 0, "> direct"}, {"set altpath clear", OUT_PATH_UNKNOWN, "> unknown"}, }; for (const auto& c : cases) { MyMesh mesh; mesh.command(c.command); const bool alt = strstr(c.command, "altpath") != nullptr; assert((alt ? mesh.acl.clients[0].alt_path_len : mesh.acl.clients[0].out_path_len) == c.length); assert(mesh.reply() == c.response); assert(mesh.acl.saves == 0 && !mesh.acl.clients[0].permissions_are_explicit); } MyMesh observed; auto& client = observed.acl.clients[0]; mesh::beginObservedClientPath(client, OUT_PATH_UNKNOWN, ticks + 50); observed.command("get outpath path"); assert(observed.reply() == "> path pending"); observed.command("set outpath path", 101); assert(observed.reply().find("pending") != std::string::npos); const uint8_t route[] = {0x12, 0x34, 0x56, 0x78}; assert(mesh::captureObservedClientPath(client, route, 0x42, ticks)); observed.command("get outpath path", 102); assert(observed.reply() == "> 1234,5678"); assert(client.out_path_len == 1 && client.out_path[0] == 0xA1); observed.command("set outpath path", 103); assert(client.out_path_len == 0x42 && memcmp(client.out_path, route, sizeof(route)) == 0); MyMesh unavailable; unavailable.command("set outpath path"); assert(unavailable.reply().find("no path") != std::string::npos); assert(unavailable.acl.clients[0].out_path[0] == 0xA1); uint8_t path[MAX_PATH_SIZE]; memset(path, 0xAB, sizeof(path)); for (unsigned length = 0; length < 256; ++length) { for (size_t capacity = 0; capacity <= 180; ++capacity) { uint8_t bounded[184]; memset(bounded, 0xCC, sizeof(bounded)); mesh::formatRoomClientPathReply(path, length, (char*)bounded + 2, capacity); assert(bounded[0] == 0xCC && bounded[1] == 0xCC); for (size_t i = 2 + capacity; i < sizeof(bounded); ++i) assert(bounded[i] == 0xCC); if (capacity) assert(memchr(bounded + 2, 0, capacity) != nullptr); } } puts("one-to-three byte paths, route sentinels, observed paths, and bounded formatting passed"); } static void persistenceCases() { for (uint8_t role : {uint8_t(PERM_ACL_GUEST), uint8_t(PERM_ACL_READ_ONLY), uint8_t(PERM_ACL_READ_WRITE), uint8_t(PERM_ACL_ADMIN)}) { for (bool explicit_role : {false, true}) { MyMesh mesh; auto& own = mesh.acl.clients[0]; own.permissions = role; own.permissions_are_explicit = explicit_role; own.last_activity = 900; const uint8_t old_permissions = own.permissions; mesh.command("set outpath B1"); const bool durable = explicit_role || role == PERM_ACL_ADMIN; assert(mesh.acl.saves == unsigned(durable)); assert(own.out_path_is_persistable); assert(own.permissions_are_explicit == explicit_role && own.permissions == old_permissions); if (durable) { assert(mesh.acl.retained[0] && !mesh.acl.retained[1]); assert(mesh.acl.durable[0].out_path[0] == 0xB1); } mesh.command("set outpath B1", 101); assert(mesh.acl.saves == unsigned(durable)); // A no-op does not wear flash. mesh.command("set altpath C1", 102); assert(mesh.acl.saves == (durable ? 2U : 0U)); mesh.command("set altpath C1", 103); assert(mesh.acl.saves == (durable ? 2U : 0U)); } } for (const char* command_text : {"set outpath B1", "set altpath C1"}) { MyMesh mesh; auto& own = mesh.acl.clients[0]; own.permissions = PERM_ACL_ADMIN; own.out_path_is_persistable = true; const ClientInfo before = own; mesh.acl.save_ok = false; mesh.dirty_contacts_expiry = 50000; mesh.contacts_save_failures = 3; char command[80], reply[180]{}; strcpy(command, command_text); assert(mesh.handleClientPathCommand(&own, command, reply)); assert(strstr(reply, "save failed") && mesh.acl.saves == 1); assert(memcmp(&own, &before, sizeof(own)) == 0); assert(mesh.dirty_contacts_expiry == 50000 && mesh.contacts_save_failures == 3); } puts("transient roles stay transient, filtered durability, no-op writes, and save rollback passed"); } static void retryCases() { MyMesh mesh; auto& own = mesh.acl.clients[0]; own.permissions_are_explicit = true; mesh.command("set outpath B1,B2", 100, 0, 777); assert(mesh.acl.saves == 1 && mesh.reply() == "> B1,B2"); mesh.command("set outpath C1", 101); assert(mesh.acl.saves == 2 && own.out_path_len == 1 && own.out_path[0] == 0xC1); mesh.command("set outpath B1,B2", 102, 0, 777); assert(mesh.acl.saves == 2 && own.out_path_len == 1 && own.out_path[0] == 0xC1); assert(mesh.reply() == "> B1,B2"); // Recover the original result without repeating mutation. const size_t before_reject = mesh.sent.size(); mesh.command("set outpath D1", 102); // Equal-time different request is not fresh. mesh.command("set outpath D1", 99); // Old uncached request is not fresh. assert(mesh.acl.saves == 2 && mesh.sent.size() == before_reject && own.out_path[0] == 0xC1); mesh.acl.clients[1].permissions_are_explicit = true; mesh.command("set outpath B1,B2", 100, 1, 777); assert(mesh.acl.saves == 3 && mesh.acl.clients[1].out_path_len == 2); // A prior Admin result must not become readable after the role is demoted. MyMesh demoted; demoted.acl.clients[0].permissions = PERM_ACL_ADMIN; demoted.command("get prv.key", 100, 0, 999); assert(demoted.general_commands == 1 && demoted.reply() == "OK admin"); demoted.acl.clients[0].permissions = PERM_ACL_READ_WRITE; demoted.command("get prv.key", 101, 0, 999); assert(demoted.general_commands == 1 && demoted.reply() != "OK admin"); for (uint8_t role : {uint8_t(PERM_ACL_FILTER_MGR), uint8_t(PERM_ACL_REGION_MGR), uint8_t(7)}) { MyMesh revoked; revoked.command("get outpath", 100, 0, 123); revoked.acl.clients[0].permissions = role; revoked.command("get outpath", 101, 0, 123); assert(revoked.reply().find("Err") != std::string::npos); } puts("cached setters execute once, sender isolation, replay denial, and demotion gates passed"); } static mesh::Packet* packet(MyMesh& mesh, uint8_t flags = TXT_TYPE_CLI_DATA) { mesh::Identity id{}; uint8_t secret[PUB_KEY_SIZE]{}; const uint8_t data[] = {1, 2, 3, 4, uint8_t(flags << 2), 'r', 'e', 'p', 'l', 'y'}; return mesh.createDatagram(PAYLOAD_TYPE_TXT_MSG, id, secret, data, sizeof(data)); } static void alternateCases() { MyMesh mesh; auto& own = mesh.acl.clients[0]; own.alt_path_len = 1; own.alt_path[0] = 0xB1; auto p = packet(mesh); p->radio_reply = true; assert(mesh.sendClientReply(&own, p, 300, 2)); assert(mesh.sent.size() == 2 && mesh.sent[0].retry_enabled && !mesh.sent[1].retry_enabled); assert(mesh.sent[0].path[0] == 0xA1 && mesh.sent[1].path[0] == 0xB1); assert(mesh.sent[0].packet.payload_len == mesh.sent[1].packet.payload_len); assert(memcmp(mesh.sent[0].packet.payload, mesh.sent[1].packet.payload, p->payload_len) == 0); assert(mesh.sent[1].packet.radio_reply && mesh._prefs.direct_retry_enabled == 1); for (unsigned mode = 0; mode < 4; ++mode) { MyMesh single; auto& c = single.acl.clients[0]; if (mode == 0) { c.alt_path_len = 1; memcpy(c.alt_path, c.out_path, MAX_PATH_SIZE); c.alt_path[63] ^= 1; } if (mode == 1) c.alt_path_len = OUT_PATH_FORCE_FLOOD; if (mode == 2) { c.out_path_len = OUT_PATH_UNKNOWN; c.alt_path_len = 1; } if (mode == 3) { c.alt_path_len = 1; c.alt_path[0] = 0xB1; single.fail_allocation = 2; } assert(single.sendClientReply(&c, packet(single), 300, 2)); assert(single.sent.size() == 1 && single.allocations <= 2); assert(single.sent[0].direct == (mode != 2)); } MyMesh failed; auto& c = failed.acl.clients[0]; c.alt_path_len = 1; c.alt_path[0] = 0xB1; failed.send_ok = false; assert(!failed.sendClientReply(&c, packet(failed), 300, 2)); assert(failed.sent.size() == 1 && failed.releases == 1 && failed._prefs.direct_retry_enabled == 1); MyMesh exhausted; exhausted.fail_allocation = 1; exhausted.command("set outpath B1"); assert(exhausted.acl.clients[0].out_path[0] == 0xB1 && exhausted.sent.empty()); MyMesh duplicate; duplicate.acl.clients[0].alt_path_len = 1; duplicate.acl.clients[0].alt_path[0] = 0xB1; duplicate.command("set outpath C1", 100, 0, 123); duplicate.command("set outpath C1", 101, 0, 123); assert(duplicate.sent.size() == 4 && duplicate.acl.saves == 0); assert(duplicate.sent[0].packet.payload_len == duplicate.sent[1].packet.payload_len); assert(memcmp(duplicate.sent[0].packet.payload, duplicate.sent[1].packet.payload, duplicate.sent[0].packet.payload_len) == 0); puts("alternate encrypted copies retain primary retries and tolerate admission or pool failure passed"); } static void pushCases() { MyMesh mesh; auto& c = mesh.acl.clients[0]; c.alt_path_len = 1; c.alt_path[0] = 0xB1; mesh::Identity author{}; memset(author.pub_key, 0x55, PUB_KEY_SIZE); assert(mesh.pushRoomTextToClient(&c, 700, author, "hello room", 22)); assert(mesh.sent.size() == 2 && mesh.retry_replacements == 1 && mesh._num_post_pushes == 1); assert(mesh.sent[0].retry_enabled && !mesh.sent[1].retry_enabled && mesh.retry_timestamp == 700); assert(c.extra.room.push_post_timestamp == 700 && c.extra.room.pending_topic_revision == 22); assert(c.extra.room.pending_ack != 0 && c.extra.room.ack_timeout == ticks + PUSH_TIMEOUT_BASE + 2 * PUSH_ACK_TIMEOUT_FACTOR); assert(mesh.sent[0].packet.radio_reply && mesh.sent[1].packet.radio_reply); assert(memcmp(mesh.sent[0].packet.payload, mesh.sent[1].packet.payload, mesh.sent[0].packet.payload_len) == 0); MyMesh failed; failed.send_ok = false; assert(!failed.pushRoomTextToClient(&failed.acl.clients[0], 700, author, "hello room", 22)); assert(failed.retry_replacements == 0 && failed._num_post_pushes == 0); assert(failed.acl.clients[0].extra.room.pending_ack == 0); puts("actual room post and topic pushes share copies, ACK state, and primary retry ownership passed"); } static void backlog(MyMesh& mesh) { const unsigned indexes[] = {23, 0, 12, 9, 31}; const uint32_t timestamps[] = {100, 200, 300, 400, 500}; for (unsigned index = 0; index < 5; ++index) { auto& post = mesh.posts[indexes[index]]; post.post_timestamp = timestamps[index]; post.author = mesh.acl.clients[index == 1 || index == 3 ? 0 : 1].id; strcpy(post.text, "unread post"); } mesh.acl.clients[0].extra.room.sync_since = 50; } static void catchupRadio() { for (unsigned permissions = 0; permissions < 256; ++permissions) { for (bool active : {false, true}) { MyMesh mesh; backlog(mesh); auto& own = mesh.acl.clients[0]; own.permissions = permissions; own.last_activity = active ? 800 : 0; own.extra.room.post_quota_used = 9; own.extra.room.poll_quota_used = 11; const ClientInfo other = mesh.acl.clients[1]; const uint8_t role = permissions & PERM_ACL_ROLE_MASK; const bool allowed = role == PERM_ACL_READ_ONLY || role == PERM_ACL_READ_WRITE || role == PERM_ACL_ADMIN || (role == PERM_ACL_GUEST && active); mesh.command("room.catchup keep 1"); assert(mesh.general_commands == 0 && own.permissions == permissions && !own.permissions_are_explicit); assert(memcmp(&mesh.acl.clients[1], &other, sizeof(other)) == 0); assert(own.extra.room.post_quota_used == 9 && own.extra.room.poll_quota_used == 11); assert(own.extra.room.sync_since == (allowed ? 300U : 50U)); assert(mesh.acl.saves == (allowed && role == PERM_ACL_ADMIN ? 1U : 0U)); if (allowed) assert(mesh.reply() == "OK - skipped=2 unread=1 since=300"); else if (role == PERM_ACL_GUEST) assert(mesh.sent.empty() && own.last_activity == 0); else assert(mesh.reply().find("Err") != std::string::npos); } } MyMesh mesh; backlog(mesh); auto& own = mesh.acl.clients[0]; own.extra.room.pending_ack = 0x778899; own.extra.room.push_post_timestamp = 100; own.extra.room.ack_timeout = 5000; mesh.command(" AB|GET room.catchup ", 100); assert(mesh.reply() == "AB|> since=50 unread=3"); mesh.command("AB|room.catchup before 1970-01-01T00:05:00Z", 101); assert(mesh.reply() == "AB|OK - skipped=1 unread=2 since=100"); assert(own.extra.room.pending_ack == 0 && mesh.message_cancellations == 1 && mesh.cancelled_timestamp == 100); mesh.command("room.catchup before 4294967295", 102); assert(own.extra.room.sync_since == 500 && mesh.reply() == "OK - skipped=2 unread=0 since=500"); assert(mesh.message_cancellations == 1); // No repeated cancel after the post was cleared. MyMesh evicted; backlog(evicted); evicted.acl.clients[0].extra.room.pending_ack = 55; evicted.acl.clients[0].extra.room.push_post_timestamp = 75; // The retained posts no longer include this one. evicted.command("room.catchup keep 1"); assert(evicted.message_cancellations == 1 && evicted.cancelled_timestamp == 75); MyMesh topic; backlog(topic); topic.acl.clients[0].extra.room.pending_ack = 55; topic.acl.clients[0].extra.room.push_post_timestamp = 100; topic.acl.clients[0].extra.room.pending_topic_revision = 22; topic.command("room.catchup keep 1"); assert(topic.message_cancellations == 0 && topic.acl.clients[0].extra.room.pending_ack == 55 && topic.acl.clients[0].extra.room.pending_topic_revision == 22); puts("actual radio catch-up keeps newest, skips before UTC dates, and only changes own client passed"); } static void catchupRetriesAndDenials() { MyMesh mesh; backlog(mesh); auto& own = mesh.acl.clients[0]; own.permissions_are_explicit = true; mesh.command("AB|room.catchup keep 1", 100, 0, 777); assert(own.extra.room.sync_since == 300 && mesh.acl.saves == 1); const std::string first_reply = mesh.reply(); mesh.command("room.catchup keep 0", 101); assert(own.extra.room.sync_since == 500 && mesh.acl.saves == 2); mesh.command("AB|room.catchup keep 1", 102, 0, 777); assert(own.extra.room.sync_since == 500 && mesh.acl.saves == 2 && mesh.reply() == first_reply); const size_t replies = mesh.sent.size(); mesh.command("room.catchup keep 0", 99); mesh.command("room.catchup keep 2", 102); assert(mesh.sent.size() == replies && own.extra.room.sync_since == 500); own.permissions = PERM_ACL_FILTER_MGR; mesh.command("AB|room.catchup keep 1", 103, 0, 777); assert(mesh.reply().find("Err") != std::string::npos && own.extra.room.sync_since == 500); const char* rejected[] = {"room.catchupx keep 0", "room.catchup", "get room.catchup extra", "room.catchup keep -1", "room.catchup keep 4294967296", "room.catchup keep 1;erase", "room.catchup before 2026-02-29", "room.catchup before 2106-02-08", "room.catchup set 0", "room.catchup skip 1", "AA|BB|room.catchup keep 0", "get room.catchup;erase"}; for (const char* text : rejected) { MyMesh rejected; backlog(rejected); rejected.command(text); assert(rejected.acl.clients[0].extra.room.sync_since == 50 && rejected.general_commands == 0); assert(rejected.reply().find("Err") != std::string::npos && rejected.acl.saves == 0); } MyMesh plain; backlog(plain); plain.command("room.catchup keep 0", 100, 0, 0, TXT_TYPE_PLAIN); assert(plain.post_count == 1 && plain.acl.clients[0].extra.room.sync_since == 50); MyMesh failed; backlog(failed); failed.acl.clients[0].permissions_are_explicit = true; failed.acl.clients[0].extra.room.pending_ack = 0x778899; failed.acl.clients[0].extra.room.push_post_timestamp = 100; failed.acl.clients[0].extra.room.ack_timeout = 5000; const auto before = failed.acl.clients[0].extra.room; failed.acl.save_ok = false; failed.command("room.catchup keep 1"); assert(memcmp(&before, &failed.acl.clients[0].extra.room, sizeof(before)) == 0); assert(failed.reply().find("save failed") != std::string::npos && failed.message_cancellations == 0); puts("catch-up cache executes once, role revocation and invalid families deny, and storage failure rolls back passed"); } static void adminClients() { const std::string target_key(64, '2'); // The fixture identity is repeated byte0x02, which encodes as repeated "02". std::string full_key; for (unsigned byte = 0; byte < PUB_KEY_SIZE; ++byte) full_key += "02"; for (uint8_t target_role : {uint8_t(PERM_ACL_GUEST), uint8_t(PERM_ACL_FILTER_MGR), uint8_t(PERM_ACL_ADMIN)}) { MyMesh mesh; mesh.acl.clients[0].permissions = PERM_ACL_ADMIN; mesh.acl.clients[1].permissions = target_role; const auto permissions = mesh.acl.clients[1].permissions; mesh.command(("room.user " + full_key + " outpath C1,C2").c_str()); assert(mesh.general_commands == 1 && mesh.acl.clients[1].out_path_len == 2); assert(mesh.acl.clients[1].out_path[0] == 0xC1 && mesh.acl.clients[0].out_path[0] == 0xA1); assert(mesh.acl.clients[1].permissions == permissions && !mesh.acl.clients[1].permissions_are_explicit); assert(mesh.acl.saves == (target_role == PERM_ACL_ADMIN ? 1U : 0U)); } for (const std::string& key : {full_key.substr(0, 8), full_key.substr(0, 12), target_key, full_key.substr(0, 62) + "GG", full_key + "00"}) { MyMesh mesh; mesh.acl.clients[0].permissions = PERM_ACL_ADMIN; mesh.command(("room.user " + key + " outpath C1").c_str()); assert(mesh.acl.clients[1].out_path[0] == 0xA2 && mesh.reply().find("Err") != std::string::npos); } MyMesh admin; backlog(admin); admin.acl.clients[0].permissions = PERM_ACL_ADMIN; admin.acl.clients[1].extra.room.sync_since = 50; // Other authors leave all five retained posts unread to the target. for (auto& post : admin.posts) if (post.post_timestamp) memset(post.author.pub_key, 3, PUB_KEY_SIZE); admin.command(("room.user " + full_key + " keep 2").c_str()); assert(admin.acl.clients[1].extra.room.sync_since == 300 && admin.acl.clients[0].extra.room.sync_since == 50); MyMesh user; user.command(("room.user " + full_key + " outpath C1").c_str()); assert(user.general_commands == 0 && user.acl.clients[1].out_path[0] == 0xA2); puts("admin targets full identities without role promotion while ordinary users cannot edit another client passed"); } static void catchupPolls() { MyMesh mesh; backlog(mesh); mesh.command("room.catchup keep 0"); auto& own = mesh.acl.clients[0]; assert(own.extra.room.sync_since == 500); const size_t replies = mesh.sent.size(); mesh.poll(101, 300); assert(own.extra.room.sync_since == 500 && own.last_timestamp == 101); assert(mesh.sent.size() == replies + 1 && mesh.sent.back().packet.getPayloadType() == PAYLOAD_TYPE_ACK); mesh.poll(102, 700); assert(own.extra.room.sync_since == 700 && mesh.sent.size() == replies + 2); mesh.poll(101, 300); // Exact poll retry returns an ACK without rewinding. assert(own.extra.room.sync_since == 700 && own.last_timestamp == 102 && mesh.sent.size() == replies + 3); mesh.poll(103, 0); assert(own.extra.room.sync_since == 700 && mesh.sent.size() == replies + 4); puts("normal keep-alive echoes preserve selected catch-up while forward cursors and exact ACK retries work passed"); } static std::string mailKey(const MyMesh& mesh, unsigned index) { char key[65]; mesh::room_mail_protocol_detail::hex(mesh.acl.clients[index].id.pub_key, key); return key; } static mesh::RoomMailStatus mailStatus(MyMesh& mesh, unsigned index, bool provisioned = true) { metadata_filesystem = &mesh.policy_fs; mesh::RoomMailStatus status; const auto result = mesh::getRoomMailStatus(&mesh.policy_fs, mesh.acl.clients[index].id.pub_key, status); assert(result == (provisioned ? mesh::RoomMailResult::Success : mesh::RoomMailResult::NotFound)); return status; } static uint32_t mailId(const std::string& reply) { unsigned long id = 0; assert(sscanf(reply.c_str(), "OK id=%lu", &id) == 1 && id <= UINT32_MAX && id); return uint32_t(id); } static void mailPlain(MyMesh& mesh, const std::string& command, uint32_t timestamp, unsigned sender = 0) { const size_t before = mesh.sent.size(); mesh.command(command.c_str(), timestamp, sender, 0, TXT_TYPE_PLAIN); if (mesh.sent.size() > before && mesh.sent.back().packet.getPayloadType() == PAYLOAD_TYPE_TXT_MSG) { assert(mesh.sent.back().packet.payload[4] >> 2 == TXT_TYPE_PLAIN); assert(memcmp(mesh.sent.back().recipient, mesh.acl.clients[sender].id.pub_key, PUB_KEY_SIZE) == 0); } } static void mailPlainCommands() { MyMesh mesh; auto& reader = mesh.acl.clients[0]; reader.permissions = PERM_ACL_READ_ONLY; assert(mesh.roomClientChatEnabled(&reader)); mailPlain(mesh, "!mail mode public", 100); assert(mesh.reply() == "OK"); assert(mesh.sent.size() == 2 && mesh.sent[0].packet.getPayloadType() == PAYLOAD_TYPE_ACK); mailPlain(mesh, "!mail delivery mailbox", 101); assert(mailStatus(mesh, 0).settings.mailbox_only && !mesh.roomClientChatEnabled(&reader)); assert(mesh.roomClientChatEnabled(&mesh.acl.clients[1])); mailPlain(mesh, "!mail settings", 102); assert(mesh.reply().find("delivery=mailbox") != std::string::npos); mailPlain(mesh, "!mail bogus", 103); assert(mesh.reply().find("Error ") == 0); mailPlain(mesh, "!mail", 104); assert(mesh.reply().find("Error ") == 0); mailPlain(mesh, "!mail read 0", 105); assert(mesh.reply().find("Error ") == 0); mesh.command("AB|mail delivery chat", 106); assert(mesh.reply() == "AB|OK" && mesh.sent.back().packet.payload[4] >> 2 == TXT_TYPE_CLI_DATA); assert(!mailStatus(mesh, 0).settings.mailbox_only && mesh.roomClientChatEnabled(&reader)); assert(mesh.post_count == 0 && mesh.general_commands == 0 && mesh.acl.saves == 0); assert(reader.permissions == PERM_ACL_READ_ONLY && mesh.acl.clients[1].permissions == PERM_ACL_READ_WRITE); MyMesh ordinary; ordinary.command("dog lost: please call home", 100, 0, 0, TXT_TYPE_PLAIN); ordinary.command("!mailbox is just chat", 101, 0, 0, TXT_TYPE_PLAIN); assert(ordinary.post_count == 2 && ordinary.general_commands == 0); // A saved mailbox-only preference survives cache replacement and blocks // public unread counts without discarding retained chat. mailPlain(mesh, "!mail delivery mailbox", 107); mesh.remote_cli_reply_cache.clear(); assert(!mesh.roomClientChatEnabled(&reader)); backlog(mesh); assert(mesh.getUnsyncedCount(&reader) == 0); assert(mesh.posts[0].post_timestamp != 0); auto corrupt = mesh.policy_fs.get(mesh::ROOM_MAIL_PRIMARY_PATH); corrupt[0] ^= 1; mesh.policy_fs.put(mesh::ROOM_MAIL_PRIMARY_PATH, corrupt); assert(!mesh.roomClientChatEnabled(&reader)); // Corrupt settings fail closed. puts("plain !mail commands privately reply, reserve unknown commands, preserve owner policy and mailbox-only chat admission passed"); } static void mailOwnershipAndDog() { MyMesh mesh; mesh.acl.clients[0].permissions = PERM_ACL_READ_ONLY; mailPlain(mesh, "!mail mode public", 100); mailPlain(mesh, "!mail delivery mailbox", 101); const std::string dog = "dog lost: please call home; set password is ordinary text"; mailPlain(mesh, "!mail send " + mailKey(mesh, 0) + " " + dog, 100, 1); const uint32_t id = mailId(mesh.reply()); assert(mailStatus(mesh, 0).count == 1); assert(mesh.post_count == 0 && mesh.general_commands == 0); mailPlain(mesh, "!mail inbox", 102); assert(mesh.reply().find(std::to_string(id) + "/") != std::string::npos); // A sleeping radio checks later; reading retains the item until explicit ACK. mesh.clock.now += 1800; mailPlain(mesh, "!mail read " + std::to_string(id), 103); assert(mesh.reply().find("text=" + dog) != std::string::npos && mailStatus(mesh, 0).count == 1); mailPlain(mesh, "!mail read " + std::to_string(id), 101, 1); assert(mesh.reply().find(dog) == std::string::npos && mesh.reply() == "Error not found"); mailPlain(mesh, "!mail ack " + std::to_string(id), 102, 1); assert(mesh.reply() == "Error not found" && mailStatus(mesh, 0).count == 1); mailPlain(mesh, "!mail delete " + std::to_string(id), 103, 1); assert(mesh.reply() == "Error not found" && mailStatus(mesh, 0).count == 1); mailPlain(mesh, "!mail mode closed", 104); mailPlain(mesh, "!mail ack " + std::to_string(id), 105); assert(mailStatus(mesh, 0).count == 0); mailPlain(mesh, "!mail ack " + std::to_string(id), 105); assert(mailStatus(mesh, 0).count == 0); mailPlain(mesh, "!mail delete " + std::to_string(id), 106); assert(mesh.reply().find("OK id=") == 0); mailPlain(mesh, "!mail read " + std::to_string(id), 107); assert(mesh.reply() == "Error not found"); assert(mesh.post_count == 0 && mesh.general_commands == 0 && mesh.acl.saves == 0); // Even administrators use their authenticated own inbox in these commands. mesh.acl.clients[1].permissions = PERM_ACL_ADMIN; mailPlain(mesh, "!mail settings", 104, 1); assert(mesh.reply().find("mode=closed") != std::string::npos); assert(mailStatus(mesh, 1, false).count == 0); puts("later dog-lost check and owner-only inbox read ACK delete keep bodies private and treat command-looking body as text passed"); } static void mailModesRolesAndBans() { MyMesh policy; policy.acl.clients[0].permissions = PERM_ACL_READ_ONLY; mailPlain(policy, "!mail mode private", 100); mailPlain(policy, "!mail send " + mailKey(policy, 0) + " forbidden", 100, 1); assert(policy.reply() == "Error permission denied"); mailPlain(policy, "!mail allow " + mailKey(policy, 1), 101); mailPlain(policy, "!mail send " + mailKey(policy, 0) + " allowed", 101, 1); assert(policy.reply().find("OK id=") == 0 && mailStatus(policy, 0).count == 1); mailPlain(policy, "!mail deny " + mailKey(policy, 1), 102); mailPlain(policy, "!mail send " + mailKey(policy, 0) + " denied", 102, 1); assert(policy.reply() == "Error permission denied" && mailStatus(policy, 0).count == 1); mailPlain(policy, "!mail mode public", 103); mailPlain(policy, "!mail send " + mailKey(policy, 0) + " public", 103, 1); assert(policy.reply().find("OK id=") == 0 && mailStatus(policy, 0).count == 2); mailPlain(policy, "!mail mode closed", 104); mailPlain(policy, "!mail send " + mailKey(policy, 0) + " closed", 104, 1); assert(policy.reply() == "Error permission denied" && mailStatus(policy, 0).count == 2); for (uint8_t role : {uint8_t(PERM_ACL_GUEST), uint8_t(PERM_ACL_READ_ONLY), uint8_t(PERM_ACL_READ_WRITE), uint8_t(PERM_ACL_ADMIN), uint8_t(PERM_ACL_FILTER_MGR), uint8_t(PERM_ACL_REGION_MGR)}) { for (bool active : {false, true}) { MyMesh mesh; mesh.acl.clients[0].permissions = role; mesh.acl.clients[0].last_activity = active ? 900 : 0; mailPlain(mesh, "!mail mode public", 100, 1); mesh.sent.clear(); mailPlain(mesh, "!mail send " + mailKey(mesh, 1) + " role test", 100); const bool writer = role == PERM_ACL_READ_WRITE || role == PERM_ACL_ADMIN; assert(mailStatus(mesh, 1).count == (writer ? 1U : 0U)); assert(mesh.post_count == 0 && mesh.general_commands == 0); mailPlain(mesh, "!mail mode private", 101); const bool own = writer || role == PERM_ACL_READ_ONLY || (role == PERM_ACL_GUEST && active); if (own) assert(mailStatus(mesh, 0).settings.mode == mesh::RoomMailMode::Private); else assert(mailStatus(mesh, 0, false).revision == 0); } } MyMesh blocked; mailPlain(blocked, "!mail mode public", 100, 1); assert(blocked.room_access.addBan(&blocked.policy_fs, blocked.acl.clients[1].id.pub_key) == mesh::RoomAccessPolicy::BanResult::Saved); mailPlain(blocked, "!mail send " + mailKey(blocked, 1) + " banned recipient", 100); assert(blocked.reply().find("recipient is blocked") != std::string::npos && mailStatus(blocked, 1).count == 0); assert(blocked.room_access.addBan(&blocked.policy_fs, blocked.acl.clients[0].id.pub_key) == mesh::RoomAccessPolicy::BanResult::Saved); const size_t replies = blocked.sent.size(); mailPlain(blocked, "!mail settings", 101); assert(blocked.sent.size() == replies && blocked.post_count == 0 && blocked.general_commands == 0); puts("private allow deny public closed policies honor writer reader guest roles and sender recipient bans passed"); } static void mailTransportRetries() { MyMesh mesh; mailPlain(mesh, "!mail mode public", 100); const std::string submission = "!mail send " + mailKey(mesh, 0) + " dog lost"; mailPlain(mesh, submission, 100, 1); const uint32_t id = mailId(mesh.reply()); const std::string original = mesh.reply(); mailPlain(mesh, "!mail settings", 101, 1); mailPlain(mesh, submission, 100, 1); assert(mesh.reply() == original && mailStatus(mesh, 0).count == 1 && mesh.acl.clients[1].last_timestamp == 101); const size_t replies = mesh.sent.size(); mailPlain(mesh, submission + " changed", 100, 1); assert(mesh.sent.size() == replies && mailStatus(mesh, 0).count == 1); mesh.acl.clients[1].permissions = PERM_ACL_READ_ONLY; mailPlain(mesh, submission, 100, 1); assert(mesh.reply() == original && mailStatus(mesh, 0).count == 1); mailPlain(mesh, submission + " new", 102, 1); assert(mesh.reply() == "Error permission denied" && mailStatus(mesh, 0).count == 1); // Restore the same persisted files with a new transport cache and replay floor. MyMesh reboot; for (const auto& entry : mesh.policy_fs.files) reboot.policy_fs.put(entry.first.c_str(), *entry.second); mailPlain(reboot, submission, 100, 1); assert(mailId(reboot.reply()) == id && reboot.reply().find("duplicate") != std::string::npos); assert(mailStatus(reboot, 0).count == 1); mailPlain(reboot, "!mail read " + std::to_string(id), 100); assert(reboot.reply().find("text=dog lost") != std::string::npos); reboot.acl.clients[0].permissions = PERM_ACL_FILTER_MGR; const size_t before_revoke = reboot.sent.size(); mailPlain(reboot, "!mail read " + std::to_string(id), 100); assert(reboot.sent.size() == before_revoke || reboot.reply().find("dog lost") == std::string::npos); reboot.acl.clients[0].permissions = PERM_ACL_READ_ONLY; mailPlain(reboot, "!mail ack " + std::to_string(id), 101); assert(mailStatus(reboot, 0).count == 0); reboot.remote_cli_reply_cache.clear(); reboot.acl.clients[1].last_timestamp = 99; mailPlain(reboot, submission, 100, 1); assert(mailId(reboot.reply()) == id && mailStatus(reboot, 0).count == 0); assert(reboot.room_access.addBan(&reboot.policy_fs, reboot.acl.clients[1].id.pub_key) == mesh::RoomAccessPolicy::BanResult::Saved); const size_t before_ban = reboot.sent.size(); mailPlain(reboot, submission, 100, 1); assert(reboot.sent.size() == before_ban && reboot.post_count == 0 && reboot.general_commands == 0); puts("plain transport retries persist once across cache reboot ACK and role or ban changes without exposing revoked mail passed"); } static void mailInputLengths() { MyMesh mesh; mailPlain(mesh, "!mail mode public", 100); const std::string prefix = "mail send " + mailKey(mesh, 0) + " "; const std::string longest = prefix + std::string(mesh::RemoteCliReplyCache::MAX_REPLY_TEXT - prefix.size(), 'x'); char reply[180]{}; assert(mesh.handleRoomMailClientCommand(&mesh.acl.clients[1], longest.c_str(), 800, reply, sizeof(reply))); const uint32_t id = mailId(reply); assert(mailStatus(mesh, 0).count == 1); mesh::RoomMailMessage message; uint8_t bytes[128]; size_t copied = 0; assert(mesh::readRoomMail(&mesh.policy_fs, mesh.acl.clients[0].id.pub_key, id, 0, bytes, sizeof(bytes), copied, message) == mesh::RoomMailResult::Success); assert(message.length == longest.size() - prefix.size() && copied == message.length); assert(std::string(reinterpret_cast(bytes), copied) == longest.substr(prefix.size())); for (const std::string& input : {longest + "x", prefix + std::string(200, 'y'), prefix + std::string(512, 'z')}) { memset(reply, 0, sizeof(reply)); assert(mesh.handleRoomMailClientCommand(&mesh.acl.clients[1], input.c_str(), 801, reply, sizeof(reply))); assert(strstr(reply, "Error command too long") && mailStatus(mesh, 0).count == 1); } mailPlain(mesh, "!" + longest + "x", 100, 1); assert(mesh.reply() == "Error command too long" && mailStatus(mesh, 0).count == 1); assert(mesh.post_count == 0 && mesh.general_commands == 0); puts("mail transport rejects oversized commands without truncating bodies while exact buffer boundary preserves complete text passed"); } int main(int argc, char** argv) { assert(argc == 2); if (!strcmp(argv[1], "roles")) roleCases(); else if (!strcmp(argv[1], "allowlist")) exactAllowlist(); else if (!strcmp(argv[1], "formats")) pathFormats(); else if (!strcmp(argv[1], "persistence")) persistenceCases(); else if (!strcmp(argv[1], "retries")) retryCases(); else if (!strcmp(argv[1], "alternate")) alternateCases(); else if (!strcmp(argv[1], "push")) pushCases(); else if (!strcmp(argv[1], "catchup")) catchupRadio(); else if (!strcmp(argv[1], "catchup-retry")) catchupRetriesAndDenials(); else if (!strcmp(argv[1], "admin-clients")) adminClients(); else if (!strcmp(argv[1], "catchup-poll")) catchupPolls(); else if (!strcmp(argv[1], "mail-plain")) mailPlainCommands(); else if (!strcmp(argv[1], "mail-owner")) mailOwnershipAndDog(); else if (!strcmp(argv[1], "mail-policies")) mailModesRolesAndBans(); else if (!strcmp(argv[1], "mail-retries")) mailTransportRetries(); else if (!strcmp(argv[1], "mail-lengths")) mailInputLengths(); else assert(false); } ''' def production_source(): room = (ROOT / "examples/simple_room_server/MyMesh.cpp").read_text() header = (ROOT / "examples/simple_room_server/MyMesh.h").read_text() acl = (ROOT / "src/helpers/ClientACL.h").read_text() packet = (ROOT / "src/Packet.cpp").read_text() constants = "\n".join(line for line in acl.splitlines() if line.startswith(("#define PERM_ACL_", "#define OUT_PATH_"))) sources = [room, header, (ROOT / "src/Mesh.h").read_text(), (ROOT / "src/helpers/TxtDataHelpers.h").read_text()] for name in ("ROOM_MESSAGE_CACHE_SIZE", "TXT_TYPE_PLAIN", "TXT_TYPE_CLI_DATA", "TXT_TYPE_CLI_COMMAND", "TXT_TYPE_SIGNED_PLAIN", "TXT_ACK_DELAY", "REPLY_DELAY_MILLIS", "REQ_TYPE_KEEP_ALIVE", "SERVER_RESPONSE_DELAY", "LAZY_CONTACTS_WRITE_DELAY", "PUSH_TIMEOUT_BASE", "PUSH_ACK_TIMEOUT_FACTOR", "PUSH_ACK_TIMEOUT_FLOOD", "MAX_UNSYNCED_POSTS", "MAX_POST_TEXT_LEN"): found = None for text in sources: found = re.search(r"^\s*#define\s+" + name + r"\s+.*$", text, re.MULTILINE) if found: break if not found: raise AssertionError("missing production constant " + name) constants += "\n" + found[0] methods = "\n".join(extract_braced(room, signature) for signature in ( "bool MyMesh::roomClientChatEnabled(", "bool MyMesh::handleRoomMailClientCommand(", "bool MyMesh::handleRoomMailText(", "bool MyMesh::handleClientPathCommand(", "bool MyMesh::executeClientPathCommand(", "bool MyMesh::sendClientReply(", "bool MyMesh::handleRoomCatchUpCommand(", "bool MyMesh::applyRoomCatchUpCommand(", "bool MyMesh::setRoomClientPath(", "bool MyMesh::handleRoomManagementCommand(", "uint8_t MyMesh::getUnsyncedCount(", "void MyMesh::onPeerDataRecv(", "bool MyMesh::pushRoomTextToClient(", "void MyMesh::serviceRoomQuotas(", "bool MyMesh::saveFilter(")) replacements = { "@CONSTANTS@": constants, "@STR_HELPER@": extract_braced((ROOT / "src/helpers/TxtDataHelpers.cpp").read_text(), "void StrHelper::strncpy("), "@CLIENT_INFO@": extract_braced(acl, "struct ClientInfo {"), "@POST_INFO@": extract_braced(header, "struct PostInfo {"), "@PACKET_METHODS@": "\n".join(extract_braced(packet, signature) for signature in ( "Packet::Packet()", "bool Packet::isValidPathLen(", "uint8_t Packet::copyPath(", "size_t Packet::writePath(")), "@PRODUCTION_METHODS@": methods, "@TEST_CASES@": CASES, } generated = FIXTURE.read_text() for marker, text in replacements.items(): generated = generated.replace(marker, text) return generated class RoomClientPathTests(unittest.TestCase): @classmethod def build(cls, generated, name): work = Path(cls.directory.name) source = work / (name + ".cpp") source.write_text(generated, encoding="ascii") binary = work / name command = [cls.compiler, "-std=c++17", "-O1", "-Wall", "-Wextra", "-Werror", "-Wno-unused-parameter", "-I" + str(ROOT / "test/fixtures/room_history_store"), "-I" + str(ROOT / "src"), "-I" + str(ROOT / "test/mocks"), str(source), "-o", str(binary)] if sys.platform.startswith("linux"): command[1:1] = ["-fsanitize=address,undefined", "-fno-sanitize-recover=all", "-fno-omit-frame-pointer", "-fno-pie", "-no-pie"] checked = subprocess.run(command, capture_output=True, text=True, timeout=60) if checked.returncode: raise AssertionError(checked.stdout + checked.stderr) return binary @classmethod def setUpClass(cls): cls.compiler = shutil.which("g++") or shutil.which("clang++") if not cls.compiler: raise AssertionError("a host C++17 compiler is required") cls.directory = tempfile.TemporaryDirectory(prefix="room-client-paths-") cls.addClassCleanup(cls.directory.cleanup) cls.generated = production_source() cls.binary = cls.build(cls.generated, "room-paths") def run_case(self, name, expected): checked = subprocess.run([str(self.binary), name], capture_output=True, text=True, timeout=20) self.assertEqual(checked.returncode, 0, checked.stdout + checked.stderr) self.assertIn(expected, checked.stdout) def test_all_roles_only_change_the_authenticated_clients_routes(self): self.run_case("roles", "256 permission combinations and live reader roles remain self-only passed") def test_narrow_allowlist_prefixes_posts_bans_and_command_bypass_attempts(self): self.run_case("allowlist", "exact allowlist, correlation normalization, chat isolation, and ban gates passed") def test_path_widths_observed_routes_and_bounded_formatting(self): self.run_case("formats", "one-to-three byte paths, route sentinels, observed paths, and bounded formatting passed") def test_transient_sessions_filtered_storage_noop_and_rollback(self): self.run_case("persistence", "transient roles stay transient, filtered durability, no-op writes, and save rollback passed") def test_replayed_mutations_cached_results_identity_and_revoked_permissions(self): self.run_case("retries", "cached setters execute once, sender isolation, replay denial, and demotion gates passed") def test_alternate_packet_clones_primary_retries_and_allocation_failures(self): self.run_case("alternate", "alternate encrypted copies retain primary retries and tolerate admission or pool failure passed") def test_actual_post_and_topic_pushes_share_ack_and_retry_state(self): self.run_case("push", "actual room post and topic pushes share copies, ACK state, and primary retry ownership passed") def test_actual_radio_catchup_frames_are_own_only_and_keep_newest(self): self.run_case("catchup", "actual radio catch-up keeps newest, skips before UTC dates, and only changes own client passed") def test_catchup_correlated_retries_revoked_roles_invalid_commands_and_save_failure(self): self.run_case("catchup-retry", "catch-up cache executes once, role revocation and invalid families deny, and storage failure rolls back passed") def test_admin_full_identity_routes_and_catchup_without_promoting_target_role(self): self.run_case("admin-clients", "admin targets full identities without role promotion while ordinary users cannot edit another client passed") def test_actual_general_cli_dispatches_management_after_remote_admin_admission(self): source = (ROOT / "examples/simple_room_server/MyMesh.cpp").read_text() command = extract_braced(source, "void MyMesh::handleCommand(uint32_t sender_timestamp,") self.assertIn("if (handleRoomManagementCommand(command, reply)) return;", command) receive = extract_braced(source, "void MyMesh::onPeerDataRecv(") admin = extract_braced(receive, "if (client->isAdmin()) {") self.assertIn("handleCommand(sender_timestamp,", admin) def test_actual_keepalive_echo_cannot_undo_skip_and_exact_retries_still_ack(self): self.run_case("catchup-poll", "normal keep-alive echoes preserve selected catch-up while forward cursors and exact ACK retries work passed") def test_actual_plain_mail_commands_are_reserved_private_and_save_delivery_policy(self): self.run_case("mail-plain", "plain !mail commands privately reply, reserve unknown commands, preserve owner policy and mailbox-only chat admission passed") def test_actual_owner_only_mail_poll_read_and_durable_ack_for_later_dog_check(self): self.run_case("mail-owner", "later dog-lost check and owner-only inbox read ACK delete keep bodies private and treat command-looking body as text passed") def test_actual_mail_sender_modes_reader_writer_roles_and_bans(self): self.run_case("mail-policies", "private allow deny public closed policies honor writer reader guest roles and sender recipient bans passed") def test_actual_plain_mail_retries_reboot_receipts_and_current_authorization(self): self.run_case("mail-retries", "plain transport retries persist once across cache reboot ACK and role or ban changes without exposing revoked mail passed") def test_actual_mail_input_length_rejection_preserves_complete_accepted_body(self): self.run_case("mail-lengths", "mail transport rejects oversized commands without truncating bodies while exact buffer boundary preserves complete text passed") def test_negative_controls_detect_rollback_cache_authorization_and_retry_regressions(self): controls = ( ("rollback", "memcpy(selected, previous, sizeof(previous));", "(void)previous;", "persistence"), ("cache-permission", "if (cached_retry && !client->isAdmin() && !own_path_allowed) {", "if (false && cached_retry && !client->isAdmin() && !own_path_allowed) {", "retries"), ("alternate-retries", "_prefs.direct_retry_enabled = 0;", "_prefs.direct_retry_enabled = 1;", "alternate"), ("poll-rewind", "if (forceSince > client->extra.room.sync_since) {", "if (forceSince > 0) {", "catchup-poll"), ) for name, before, after, case in controls: with self.subTest(control=name): self.assertEqual(self.generated.count(before), 1, "update the negative control to the production seam") binary = self.build(self.generated.replace(before, after), "negative-" + name) checked = subprocess.run([str(binary), case], capture_output=True, text=True, timeout=20) self.assertNotEqual(checked.returncode, 0, "negative control did not detect " + name) self.assertIn("Assertion", checked.stderr, checked.stdout + checked.stderr) if __name__ == "__main__": unittest.main()