fix: never re-enable SSID pool broadcast (crash guard) + top-bar health chip

Mode 'active' and the advertise toggle could re-enable the SSID-pool
broadcast that segfaults pineapd. active preset now skips ssidpool/enable
(advertise stays false), the advertise endpoint refuses with an
explanation when the pool is disabled, get_ap reports the real pool
state, and the PineAP overview disables the toggle with a notice. Added
a top-bar health chip (PINEAP OK / POOL OFF / PINEAPD DOWN) polled every
15s.
This commit is contained in:
2026-08-18 20:16:41 -05:00
parent 0cd9956c4c
commit d10fba9d1b
6 changed files with 69 additions and 13 deletions
+16 -5
View File
@@ -37,8 +37,7 @@ class PineapModeTest(unittest.TestCase):
status, payload = server.h_pineap_mode_post(ctx({'mode': 'passive'}))
self.assertEqual(status, 200)
self.assertEqual([c[1] for c in calls], [
'hostapd/enable_pineap', 'ssidpool/enable_collect',
'ssidpool/disable'])
'hostapd/enable_pineap', 'ssidpool/enable_collect'])
self.assertEqual(calls[0][2], {'enable': False})
self.assertEqual(payload['mode'], 'passive')
self.assertTrue(payload['collect'])
@@ -46,7 +45,7 @@ class PineapModeTest(unittest.TestCase):
self.assertFalse(payload['karma'])
self.assertFalse(payload['enabled'])
def test_active_enables_response_engine_and_pool_broadcasting(self):
def test_active_enables_response_engine_but_never_pool_broadcast(self):
calls = []
server._daemon_proxy = lambda method, path, body=None, timeout=15: (
calls.append((method, path, body)) or (200, {'success': True}))
@@ -54,12 +53,24 @@ class PineapModeTest(unittest.TestCase):
self.assertEqual(status, 200)
self.assertEqual(calls[0], ('PUT', 'hostapd/enable_pineap', {'enable': True}))
self.assertNotIn('mimic/disable', [c[1] for c in calls])
self.assertEqual(calls[-1], ('POST', 'ssidpool/enable', {'enable': True}))
# The SSID-pool broadcast segfaults pineapd on this firmware: the
# active preset must never call ssidpool/enable.
self.assertNotIn('ssidpool/enable', [c[1] for c in calls])
self.assertEqual(payload['mode'], 'active')
self.assertTrue(payload['advertise'])
self.assertFalse(payload['advertise'])
self.assertTrue(payload['karma'])
self.assertTrue(payload['enabled'])
def test_advertise_refuses_when_pool_disabled(self):
server._uci_section = lambda name: {'disable': '1'}
calls = []
server._daemon_proxy = lambda method, path, body=None, timeout=15: (
calls.append((method, path, body)) or (200, {'success': True}))
status, payload = server.h_pineap_advertise(ctx({'enable': True}))
self.assertEqual(status, 400)
self.assertIn('cannot be re-enabled', payload['error'])
self.assertEqual(calls, [])
def test_advanced_preserves_device_settings(self):
calls = []
server._daemon_proxy = lambda *args, **kwargs: (calls.append(args) or (200, {}))