feat: add network-level kill switch endpoint

This commit is contained in:
2026-05-30 06:32:26 +00:00
parent fed72f8bcd
commit 2aad17f5e0
8 changed files with 460 additions and 1 deletions
+112
View File
@@ -204,6 +204,118 @@ class TestZeroTierMembership:
# Accept errors when no active memberships to kill
assert exc.status_code in (400, 500)
@patch("gatehouse_app.services.network_access_service._end_active_session")
@patch("gatehouse_app.services.network_access_service.zt.deauthorize_member")
def test_network_kill_switch_positive(
self, mock_deauth, mock_end_session,
integration_client, create_test_user, create_test_org,
create_test_membership, integration_app,
):
"""TEST: ZT-10 — Trigger network kill switch.
WHAT: POST /organizations/<id>/networks/<id>/kill-switch.
WHY: Admin needs to kill all device access on a network.
EXPECTED: 200 OK, all active memberships on the network deactivated.
"""
from gatehouse_app.models.zerotier.network_access_request import NetworkAccessRequest
from gatehouse_app.models.zerotier.portal_network import PortalNetwork
from gatehouse_app.models.zerotier.device import Device
from gatehouse_app.extensions import db as _db
from gatehouse_app.utils.constants import ApprovalState
admin = create_test_user(password="AdminPass123!")
org = create_test_org()
create_test_membership(admin["id"], org["id"], OrganizationRole.ADMIN)
with integration_app.app_context():
network = PortalNetwork(
organization_id=org["id"],
name="Kill Test Net",
zerotier_network_id="zt_kill_test",
request_mode="open",
owner_user_id=admin["id"],
)
_db.session.add(network)
_db.session.flush()
network_id = network.id
device = Device(
user_id=admin["id"],
organization_id=org["id"],
node_id="9999999999",
device_nickname="Kill Test Device",
)
_db.session.add(device)
_db.session.flush()
device_id = device.id
req = NetworkAccessRequest(
organization_id=org["id"],
user_id=admin["id"],
device_id=device_id,
portal_network_id=network_id,
status=ApprovalState.APPROVED,
active=True,
)
_db.session.add(req)
_db.session.flush()
req_id = req.id
_db.session.commit()
integration_client.auth.login(email=admin["email"], password="AdminPass123!")
result = integration_client.post(
f"/organizations/{org['id']}/networks/{network_id}/kill-switch",
data={},
)
assert_success(result, "triggered")
with integration_app.app_context():
updated = NetworkAccessRequest.query.get(req_id)
assert updated.active is False
assert updated.status == ApprovalState.SUSPENDED
def test_network_kill_switch_non_admin_negative(
self, integration_client, create_test_user, create_test_org,
create_test_membership, integration_app,
):
"""TEST: ZT-11 — Non-admin cannot trigger network kill switch."""
from gatehouse_app.models.zerotier.portal_network import PortalNetwork
from gatehouse_app.extensions import db as _db
member = create_test_user(password="Pass1234!")
org = create_test_org()
create_test_membership(member["id"], org["id"], OrganizationRole.MEMBER)
with integration_app.app_context():
network = PortalNetwork(
organization_id=org["id"],
name="Locked Net",
zerotier_network_id="zt_locked",
request_mode="open",
owner_user_id=member["id"],
)
_db.session.add(network)
_db.session.commit()
network_id = network.id
integration_client.auth.login(email=member["email"], password="Pass1234!")
with pytest.raises(ApiError) as exc_info:
integration_client.post(
f"/organizations/{org['id']}/networks/{network_id}/kill-switch",
)
assert exc_info.value.status_code == 403
def test_network_kill_switch_unauth_negative(
self, integration_client, create_test_org,
):
"""TEST: ZT-12 — Unauthenticated user cannot trigger network kill switch."""
org = create_test_org()
with pytest.raises(ApiError) as exc_info:
integration_client.post(
f"/organizations/{org['id']}/networks/does-not-matter/kill-switch",
)
assert exc_info.value.status_code == 401
class TestZeroTierJoinNetwork:
"""Test joining a network with a registered device."""