Such a route names a node, not a subnet: it stays approved and listed
but no viewer gets it. Via inclusions skip the election, so the rule
sits on everything RoutesForPeer returns.
A router that reconnects joins as a standby; one that kept its session
takes its routes back once available again, as on Tailscale. Both the
global and the via election use it, in place of anti-flap stickiness.
Peers keep the routes of an offline or expired router, as on Tailscale.
The previous primary keeps the prefix, else the lowest-ID approver;
never one the prober declared unreachable.
Every write inserted a row and nothing deleted one, while every reader
takes only the newest. Writers store and install under one lock, so an
uncommitted insert cannot outlive the newer row that pruned the rest.
Writers validated by installing the policy live, so a store failure
left a refused or unstored policy enforced. Validate on a throwaway
manager, store, then reload from the stored row.
Labels under taken hostnames, case-only renames, hostname changes, long
hostnames and a Service's name; API, peer and self per step, and State
labels as a restart would load them.
The expirable LRU ran its sweeper forever, one goroutine per State. Purge
first so pending waiters get ErrRegistrationExpired instead of hanging.
The OIDC state cache is closed at server shutdown for the same reason.
"Foo" and "foo" could share one DNS name; collisions now ignore case.
A rename never resent the node its own DNS config, so CertDomains lagged.
Updates #2137
The SetPolicy API handler calls State.SetPolicy, which already rebuilds the peer map when the policy changed, and then ReloadPolicy, which rebuilt it again even when nothing changed. So every policy write built the peer map twice.
ReloadPolicy now rebuilds only when the policy really changed. A test checks one build per changed write and none for an unchanged reload.
Part of #3549
The client picks the check rule by login user; the server took the
first rule for the node pair, so a root login could get a 12h
localpart period instead of "always", or be approved after its rule
was removed while another user's rule remained. Hold URLs now carry
the concrete user: tailssh never expanded the encoded $LOCAL_USER.
Updates #3508
A missing key yields the zero NodeView; its ID() panicked inside a reader
goroutine and took down the test binary instead of failing with a diagnostic.
One peer build per tag/user/IP/route write; callers detect policy moves
via NodesGeneration. Per-node caches only store results for the node
pm holds, so a mapper reading mid-build cannot pin a stale filter.
Every exported types.Node field is pinned to relation/election/payload
in nodeFieldImpact; a new field fails until classified, and each
relation/election field gets a mutation check against updateChanges.
Rapid test drives random writes through a real NodeStore and policy
manager, checking adjacency before and after syncPolicy against a
BuildPeerMap from a fresh policy manager.
API keys, pre-auth keys and OAuth clients/tokens share one table and verify
path. Secrets carry 256 bits of crypto/rand entropy, so a SHA-256 digest
needs no stretching; bcrypt/argon2id rows rehash on use until 0.32.
Online now requires a live session and an unexpired key, derived in one
place by Node.ShouldBeOnline so every writer agrees what online means.
Fixes#3470