feat(cells): Phase 3 tests + Phase 4 UI for cell service-sharing

Phase 3 — tests (50 new, total now 1071):
- test_cell_link_manager: atomicity (WG fail → DNS not called, link not
  persisted), DNS warning non-fatal, inbound_services arg, unknown service
  filtered, update/get permissions, lazy migration of legacy entries
- test_wireguard_manager: subnet overlap rejection (exact, supernet, adjacent
  non-overlapping, different class-A, honours wg0.conf configured network)
- test_firewall_manager: _cell_tag sanitisation, apply_cell_rules emits correct
  ACCEPT/DROP per service + catch-all DROP, clear_cell_rules no-op and exact
  line removal, apply_all_cell_rules iterates with correct args
- test_cells_endpoints: RuntimeError→400, GET /services, GET/PUT permissions
  (200/400/404 paths, service name validation, arg forwarding)

Phase 4 — UI:
- CellNetwork.jsx: replace flat cell list with CellPanel expandable cards;
  add ServiceShareToggle (ARIA switch, saves immediately), InboundServiceBadge
  (read-only), DisconnectConfirmModal (replaces window.confirm); relative
  timestamps; paste validation on blur; WireGuard status merged by public_key
- api.js: add cellLinkAPI.getPermissions, updatePermissions, getServices

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-01 08:45:32 -04:00
parent 0b103ffafb
commit 562d866a65
6 changed files with 1023 additions and 47 deletions
+75
View File
@@ -629,5 +629,80 @@ class TestWireGuardSysctlAndPortCheck(unittest.TestCase):
self.assertEqual(statuses, {})
class TestAddCellPeerSubnetOverlap(unittest.TestCase):
"""Verify that add_cell_peer rejects a vpn_subnet that overlaps the local WG network."""
def setUp(self):
self.test_dir = tempfile.mkdtemp()
self.data_dir = os.path.join(self.test_dir, 'data')
self.config_dir = os.path.join(self.test_dir, 'config')
os.makedirs(self.data_dir, exist_ok=True)
os.makedirs(self.config_dir, exist_ok=True)
patcher = patch.object(WireGuardManager, '_syncconf', return_value=None)
self.mock_sync = patcher.start()
self.addCleanup(patcher.stop)
self.wg = WireGuardManager(self.data_dir, self.config_dir)
# Write a known wg0.conf so _get_configured_network() returns 10.0.0.0/24
self._write_wg_conf(address='10.0.0.1/24')
def tearDown(self):
shutil.rmtree(self.test_dir)
def _write_wg_conf(self, address='10.0.0.1/24', port=51820):
conf = (
f'[Interface]\n'
f'PrivateKey = dummykey\n'
f'Address = {address}\n'
f'ListenPort = {port}\n'
)
cf = self.wg._config_file()
os.makedirs(os.path.dirname(cf), exist_ok=True)
with open(cf, 'w') as f:
f.write(conf)
# Public key is 44 chars ending in '=' — required by validation in add_cell_peer
_CELL_PUBKEY = 'cmVtb3RlcHVia2V5X2Zvcl90ZXN0c193Z3Rlc3QxMiE='
def test_add_cell_peer_overlapping_subnet_returns_false(self):
"""vpn_subnet that exactly matches the local WG network must be rejected."""
# local is 10.0.0.0/24; remote is also 10.0.0.0/24 — clear overlap
ok = self.wg.add_cell_peer(
'remote', self._CELL_PUBKEY, '5.6.7.8:51821', '10.0.0.0/24'
)
self.assertFalse(ok)
def test_add_cell_peer_partially_overlapping_subnet_returns_false(self):
"""A remote subnet that contains the local network (e.g. /16 ⊃ /24) is rejected."""
# 10.0.0.0/16 contains 10.0.0.0/24 → overlaps
ok = self.wg.add_cell_peer(
'remote', self._CELL_PUBKEY, '5.6.7.8:51821', '10.0.0.0/16'
)
self.assertFalse(ok)
def test_add_cell_peer_non_overlapping_subnet_accepted(self):
"""A remote subnet distinct from the local WG network must be accepted."""
# local is 10.0.0.0/24; remote is 10.0.1.0/24 — no overlap
ok = self.wg.add_cell_peer(
'remote', self._CELL_PUBKEY, '5.6.7.8:51821', '10.0.1.0/24'
)
self.assertTrue(ok)
def test_add_cell_peer_no_overlap_different_class_a(self):
"""A completely different address space is accepted."""
# local is 10.0.0.0/24; remote is 192.168.5.0/24 — no overlap
ok = self.wg.add_cell_peer(
'remote', self._CELL_PUBKEY, '5.6.7.8:51821', '192.168.5.0/24'
)
self.assertTrue(ok)
def test_add_cell_peer_overlap_check_uses_configured_network(self):
"""When wg0.conf says 172.16.0.1/12, overlapping that range is rejected."""
self._write_wg_conf(address='172.16.0.1/12')
ok = self.wg.add_cell_peer(
'remote', self._CELL_PUBKEY, '5.6.7.8:51821', '172.16.0.0/12'
)
self.assertFalse(ok)
if __name__ == '__main__':
unittest.main()