Repository navigation
feat(mesh): Lens as the CA of a Nebula mesh between its machines, with join tokens and a node registry - #546
Merged
Merged
Conversation
…h join tokens and a node registry Lens runs on one machine until an admin adds another. This is the core of the private network those machines talk over: Lens makes the mesh's certificate authority the first time a node is added (its key sealed in the database), signs a certificate per machine naming its role (worker or compute) and the namespaces it serves as Nebula groups, and renders each machine's Nebula config, whose firewall lets worker nodes reach the database port and every node the API port on the primary, and the primary a node's agent port, and nothing else. A machine joins with a token shown once to the admin, without ever sending it: POST /api/v1/mesh/join carries the token's id, a nonce, the machine's name and public key and an HMAC keyed with the token's secret; the answer (certificate, config, node token) comes back sealed with a key derived from that secret. Wrong proofs are throttled per address. After joining, a node renews its certificate, reports every minute and fetches its config (whose version changes with the blocklist) with its own node token. Removing a node blocklists every certificate it was given on every machine and stops its token; undo while its certificate is good. Settings section `mesh` (network, port, hosts, cipher, cert_days, relay, mtu, log level), off until a node is added; the network can't change once machines have addresses in it. Nebula's release is pinned to one version with its checksums kept here, fetched on first use. Workers register the node they run on. Tests fake nebula-cert; the same flows were run against Nebula 1.11.2, two machines in separate network namespaces reaching each other. Nebula running on the primary, the install line that joins a machine and the Settings pages follow in their own pull requests (docs/mesh.md). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GTrHPwWHtEvFJFq3M1YpH4
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GTrHPwWHtEvFJFq3M1YpH4
… in the server job too Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GTrHPwWHtEvFJFq3M1YpH4
20 of 23 tasks
adeelahmad
pushed a commit
that referenced
this pull request
Oct 18, 2026
…ay and clipper sign-in as built Since the last README refresh, #474, #484, #510, #511, #497, #495, #406, #516, #517, #491, #400 and #506 merged. The README's built list now says the assistant answers questions about Lens itself; a conversation exports as Markdown, PDF or JSON and its answers, questions and code copy; a Tools chip picks an answer's tools, limit and namespaces; sandbox runs open under the answer with downloads, and Settings starts the gateway; deep research plans, runs and returns a cited report; ready-made MCP servers, the MCP servers page and the optional containers start from the web app; and the web clipper signs in or takes an API token. Each has its checks in docs/requirements.md. In progress lists only open PRs; the Nebula mesh (#546, merged, partly built) moves to Planned with what's next; the Planned proof item keeps only the Raspberry Pi timing; the docs index links requirements and checks, and published feeds. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HDx7PPUauyjMn1LZs8JAsS
This was referenced Oct 18, 2026
adeelahmad
added a commit
that referenced
this pull request
Oct 18, 2026
…ay and clipper sign-in as built (#536) Since the last README refresh, #474, #484, #510, #511, #497, #495, #406, #516, #517, #491, #400 and #506 merged. The README's built list now says the assistant answers questions about Lens itself; a conversation exports as Markdown, PDF or JSON and its answers, questions and code copy; a Tools chip picks an answer's tools, limit and namespaces; sandbox runs open under the answer with downloads, and Settings starts the gateway; deep research plans, runs and returns a cited report; ready-made MCP servers, the MCP servers page and the optional containers start from the web app; and the web clipper signs in or takes an API token. Each has its checks in docs/requirements.md. In progress lists only open PRs; the Nebula mesh (#546, merged, partly built) moves to Planned with what's next; the Planned proof item keeps only the Raspberry Pi timing; the docs index links requirements and checks, and published feeds. Claude-Session: https://claude.ai/code/session_01HDx7PPUauyjMn1LZs8JAsS Co-authored-by: Adeel Ahmad <noreply@anthropic.com>
20 of 23 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Before: Lens ran on one machine, and a worker on another machine had no private, managed way to reach it.
After: Lens can be the certificate authority of a Nebula mesh (MIT) between the machines it runs on. An admin adds a node with a join token (
POST /api/v1/mesh/tokens, shown once). The machine joins withPOST /api/v1/mesh/joinwithout ever sending the token: an HMAC keyed with its secret proves it, and the answer comes back sealed with a key derived from it. The machine gets an address, a certificate naming its role (worker or compute) and its namespaces as Nebula groups, and its whole Nebula config. The rendered firewall lets worker nodes reach the database port and every node the API port on the primary, and the primary a node's agent port, and nothing else. A node renews its certificate, reports every minute and refreshes its config with its own node token. Removing a node blocklists every certificate it was given on every machine, with undo while its certificate is good./api/v1/mesh/nodeslists every machine with the job workers running on it.How:
domain/mesh.pydrivesnebula-cert(Nebula 1.11.2, pinned with checksums, fetched into<data_dir>/binon first use). The CA key and token secrets are sealed like other setting secrets; node tokens are stored as hashes. Settings sectionmeshholds the network, port, hosts, cipher, certificate lifetime, relay, MTU and log level, off until a node is added. Workers record the node they run on (LENS_MESH_NODE).This is the first of four pull requests (docs/mesh.md). Nebula running on the primary behind an optional Compose profile, the install line that joins a machine, Settings › Network and Nodes in the web app, and running sandboxes on compute nodes follow in their own.
Motivation and Context
Adeel asked for workers and every non-primary node to talk to Lens over its own private network, auto set up and managed, with Settings pages to configure, monitor and debug it, and for the assistant's Bash tools to run sandboxes on remote nodes over that network.
Steps to reproduce (if appropriate):
The tests use a fake
nebula-cert(tests/fake_nebula_cert.py) because CI runners don't have the binary. The same flows were run by hand against Nebula 1.11.2: two machines in separate network namespaces, with configs rendered bymesh.render, pinged each other and opened a TCP connection through the mesh with the firewall as rendered.Types of changes
!in the title)Checklist:
make hookschecks it on commit).docs/accordingly.## UnreleasedinCHANGELOG.md.Done questions (AGENTS.md)
/api/v1/mesh, in the regenerated OpenAPI client..envedit. Nebula is fetched on first use.meshwith defaults, editable through the settings API; the Settings › Network page comes in PR 3. Nothing in the setup wizard.mesh.enabled, §1.7 the join, node and admin calls, §1.11 P-MESH.mesh.enabledoff).make openapi).Generated by Claude Code