What We’re Testing
Exit nodes allow a machine in the tailnet to route all internet-bound traffic from other peers through itself. The org-level allow_exit_nodes boolean in the org_settings table controls whether this capability is permitted.
Backend — handlers/org-management.ts, action update_org_settings:
- Endpoint:
POST /api/org-managementwithaction: "update_org_settings",org_id,allow_exit_nodes - Authorization:
isOrgAdminrequired - DB column:
org_settings.allow_exit_nodes(boolean, defaultfalse) - Write path: If a row exists for the org, it issues
UPDATE org_settings SET allow_exit_nodes = ?, updated_at = NOW() WHERE org_id = ?. If no row exists, it inserts one with the provided value. - Response:
{ "updated": true }
Frontend — SettingsPage.tsx:
- The “Network Features” card contains an Exit Nodes toggle (Switch component).
- The switch reads
settings?.allow_exit_nodes ?? falsefrom theorg_settingsCRUD fetch. - On toggle, it calls
updateSettings({ allow_exit_nodes: v }), which issuesPATCH /api/db/org_settingswitheq("org_id", currentOrg.id). - Note: The frontend uses the generic CRUD API (
/api/db/org_settings) for this update, while the directPOST /api/org-managementaction also works.
CLI verification: When allow_exit_nodes is true, a machine may advertise itself as an exit node using ztna set --advertise-exit-node on 🐧 Linux-C .
Your Test Setup
| Machine | Role |
|---|---|
| ⊞ Win-A | Admin browser session — toggles the setting |
| 🐧 Linux-C | Connected to tailnet — tests exit node advertisement |
Prerequisites: Both machines are registered and online. 🐧 Linux-C has ztna installed and is connected (ztna up).
ST1 — Toggle Exit Nodes ON via Dashboard
What it verifies: The Exit Nodes switch in the Settings UI writes allow_exit_nodes = true to the org_settings table.
Steps:
- Log in to
https://login.quickztna.comas an org admin on ⊞ Win-A . - Navigate to Settings > General tab.
- Scroll to the Network Features card.
- Locate the Exit Nodes row. Confirm the toggle is currently OFF (grey).
- Click the toggle to enable Exit Nodes.
Expected behavior:
- The switch animates to the ON (blue/accent) state immediately.
- No error toast appears.
- Opening browser DevTools > Network, you should see a successful PATCH request to
/api/db/org_settingswith body containingallow_exit_nodes: true.
Pass: Switch is ON, no error toast, network request returns HTTP 200.
Fail / Common issues:
- Toast “Failed to update settings” — open DevTools Network tab. Check the PATCH response. A 403 means your role is not
adminorowner. A 404 means theorg_settingsrow does not exist and the CRUD update found no rows to update (in that case, use the API path in ST2 which handles upsert).
ST2 — Enable Exit Nodes via API (Upsert Path)
What it verifies: The update_org_settings action in handleOrgManagement upserts the org_settings row correctly.
Steps:
- Using an admin JWT:
curl -s -X POST https://login.quickztna.com/api/org-management \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{"action":"update_org_settings","org_id":"<org_id>","allow_exit_nodes":true}'
Expected behavior:
- HTTP 200
- Response body:
{
"success": true,
"data": {
"updated": true
}
}
- Reload the Settings page: Exit Nodes toggle is ON.
Pass: API returns updated: true, UI toggle reflects the new state.
Fail / Common issues:
- HTTP 403
FORBIDDEN— caller is not an admin. - HTTP 400
MISSING_FIELDS—org_idis missing from the body.
ST3 — Advertise Exit Node from Linux-C When Enabled
What it verifies: With allow_exit_nodes = true, a machine can successfully advertise as an exit node without being blocked.
Steps:
- Ensure
allow_exit_nodesistrue(from ST1 or ST2). - On 🐧 Linux-C , run:
sudo ztna set --advertise-exit-node
- Check the status:
ztna status
Expected behavior:
ztna set --advertise-exit-nodereturns without error.ztna statusoutput includes a line such as:
ExitNode: advertising
- In the dashboard, navigating to Machines and clicking 🐧 Linux-C shows an “Exit Node” badge on the machine detail page.
Pass: Exit node advertisement accepted. Machine detail shows exit node capability active.
Fail / Common issues:
- Error “exit nodes not allowed for this org” — the
allow_exit_nodesflag is stillfalse. Verify the API call in ST2 succeeded and the Settings page toggle is ON. ztna statusshows no exit node info — the--advertise-exit-nodeflag may require a restart: runztna down && ztna upto re-register the advertisement.
ST4 — Toggle Exit Nodes OFF and Verify Restriction
What it verifies: Disabling exit nodes at the org level prevents the advertisement.
Steps:
- On ⊞ Win-A , toggle Exit Nodes OFF on the Settings page (or via API with
allow_exit_nodes: false). - Via API:
curl -s -X POST https://login.quickztna.com/api/org-management \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{"action":"update_org_settings","org_id":"<org_id>","allow_exit_nodes":false}'
- On 🐧 Linux-C , run
ztna downand thenztna upto re-register. - Then attempt:
sudo ztna set --advertise-exit-node
Expected behavior:
- The
allow_exit_nodestoggle on the Settings page is now OFF. - The
ztna set --advertise-exit-nodecommand returns an error or the advertisement is ignored by the control plane. ztna statusdoes not show “ExitNode: advertising”.
Pass: Exit node advertisement is blocked or removed when the org-level flag is false.
Fail / Common issues:
- Exit node still shows as advertising after toggling OFF — the machine heartbeat has not yet re-evaluated the org setting. Wait for the next heartbeat cycle (30 seconds) or run
ztna down && ztna upto force a re-registration.
ST5 — Non-Admin Cannot Change Exit Node Setting
What it verifies: The isOrgAdmin guard blocks member and auditor roles from modifying allow_exit_nodes.
Steps:
- Log in as a
member(not admin/owner) and copy their access token. - Attempt to enable exit nodes:
curl -s -X POST https://login.quickztna.com/api/org-management \
-H "Authorization: Bearer <member_token>" \
-H "Content-Type: application/json" \
-d '{"action":"update_org_settings","org_id":"<org_id>","allow_exit_nodes":true}'
Expected behavior:
- HTTP 403
- Response body:
{
"success": false,
"error": {
"code": "FORBIDDEN",
"message": "Admin required"
}
}
Pass: Non-admin is blocked with 403 FORBIDDEN.
Fail / Common issues:
- HTTP 200 returned — the
isOrgAdmincheck is not being executed. Ensure the handler is routing theupdate_org_settingscase correctly in the switch statement.
Summary
| Sub-test | Exercises | Key assertion |
|---|---|---|
| ST1 | Dashboard Exit Nodes toggle ON | Switch animates ON, PATCH to /api/db/org_settings succeeds |
| ST2 | API update_org_settings upsert | 200 updated: true, allow_exit_nodes = true in DB |
| ST3 | Linux-C advertises exit node | ztna set --advertise-exit-node succeeds, machine detail shows badge |
| ST4 | Toggle OFF blocks advertisement | allow_exit_nodes = false prevents exit node registration |
| ST5 | Non-admin blocked | 403 FORBIDDEN for member role |