feat(license): distributed license enforcement across multi-node setups (#359)

* feat(license): distributed license enforcement across multi-node setups

The primary instance's license tier is now asserted to remote nodes on
every proxied HTTP and WebSocket request via trusted headers. Remote
nodes honor the assertion only when the request carries a valid
node_proxy JWT, preventing unauthorized elevation from browsers or API
tokens. Falls back to local license tier for direct access.

* fix(test): remove unused vi import in distributed-license tests
This commit is contained in:
Anso
2026-04-03 11:31:14 -04:00
committed by GitHub
parent 9e87e14d62
commit 6c26ae3f50
7 changed files with 324 additions and 9 deletions
+13
View File
@@ -134,6 +134,19 @@ Click the **wifi icon** on the node row to re-test connectivity after making cha
---
## Pro features return 403 on remote nodes
**Symptom:** A Pro or Admiral feature works on the local node but returns "This feature requires Sencho Pro" (403) when you switch to a remote node.
**Checks in order:**
1. **Is your primary instance licensed?** Go to **Settings > License** on the primary instance and verify it shows an active Skipper or Admiral license. Remote nodes inherit the primary's tier — if the primary is on Community, all remote nodes will be Community too.
2. **Is the remote node's token valid?** An expired or revoked token prevents the license tier from being transmitted. Regenerate the token on the remote instance and update the node config on the primary.
3. **Is the remote node running an up-to-date version of Sencho?** Distributed license enforcement requires both the primary and remote instances to be on v0.34.0 or later. Update the remote node if it's on an older version.
4. **Are you accessing the remote node directly?** If you navigate directly to the remote Sencho instance's URL (bypassing the primary), it uses its own local license. License inheritance only works through the primary's proxy.
---
## Forgotten admin password
Sencho has no password recovery flow. To reset the password: