From 95b84ea748d20b94b7223ef66390bf2841888e4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Sat, 15 Aug 2026 18:41:52 +0000 Subject: [PATCH] rebrand to OffScale, and fix what the first extraction missed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Offscale was the first plugin extracted and it was done before we knew what "extracted" meant. Music, done last, is the standard. This brings offscale to it. ── The rebrand ── The plugin was `offscale` to the platform and `headscale` to itself: sidecar name and handles, the port announcement, the API proxy name, the React components, every hook, the react-query keys, the panel ids and appTypes, and the Postgres table. Now all of those say offscale. The line drawn, and it is deliberate: OffScale is Officer's tooling layer, and Headscale is the server it manages. So every IDENTIFIER is offscale, while a message like `headscale unreachable`, the `headscale apikeys create` hint and the ACL assistant's prompt still say Headscale — because they are talking about the remote server, and renaming them would make the code lie about what it reached. 495 occurrences became 180, and the 180 are all of that second kind. ── The live bug this uncovered ── `headscaleSectionPath` built links to `/headscale/
`. The shell has no such route — plugin routes come from `plugin.route`, which is `/offscale` — and it redirects unknown paths to the home page. So every section link in the nav, the console and the server picker silently went home. The extraction moved the route and left the link builder behind. Also live: ServersView told the user to run `pm2 start ecosystem.config.cjs --only officer-headscale`, a process that has not existed since the sidecar was renamed. ── The correctness fix music already had ── api/router.ts hardcoded `prefix: '/api/offscale'`. The proxy strips `prefix.length` characters, so a literal is correct only for a first-party publisher; published by anyone else this mounts at `/api/p//offscale` and forwards the wrong subpath. Derived from `mountPrefix()` now, as music does. ── The rest ── - assets/icon.png — the OffScale artwork, 256px to match music's. The tile stops being a glyph badge. - First tests: 21 of them, over the version floor and the protobuf normalisers. Those are the two places a Headscale release actually breaks this, and they had no coverage at all. `meetsFloor` has a real trap pinned now — comparing minor first would refuse 1.0 as older than 0.29. - OFFSCALE_API.md — the contract was a 45-line comment inside sidecar/index.ts, which is not linkable and not published. Now a document, as MUSIC_API.md is. - web/panels.ts re-exported three components. A plugin cannot export components; that was residue of the platform importing them before extraction. - Comments pointed at src/servers/api/headscale/ and src/servers/sidecar/headscale/, neither of which has existed since the extraction. The crypto purpose moved headscale → offscale too, and the secret-store row was renamed rather than left to create a fresh key — the material is preserved, so this is reversible. Free to do only because offscale_servers had 0 rows; with one stored API key it would have been a migration. --- OFFSCALE_API.md | 133 ++++++++++++++++++ api/router.ts | 31 +++- assets/icon.png | Bin 0 -> 140401 bytes db/queries.ts | 116 +++++++-------- db/schema.ts | 18 +-- manifest.ts | 2 +- sidecar/active.ts | 8 +- sidecar/client.ts | 20 +-- sidecar/companion.ts | 18 +-- sidecar/enroll.ts | 12 +- sidecar/index.ts | 31 ++-- sidecar/invites.ts | 8 +- sidecar/nodes.ts | 4 +- sidecar/normalize.test.ts | 102 ++++++++++++++ sidecar/policy.ts | 8 +- sidecar/routes.ts | 4 +- sidecar/servers.ts | 40 +++--- sidecar/version.test.ts | 57 ++++++++ web/ConsoleView.tsx | 8 +- web/DiagnosticsView.tsx | 6 +- web/InvitesView.tsx | 28 ++-- web/KeysView.tsx | 22 +-- web/NodesView.tsx | 22 +-- web/{HeadscaleNav.tsx => OffscaleNav.tsx} | 16 +-- ...verPicker.tsx => OffscaleServerPicker.tsx} | 12 +- web/{HeadscaleView.tsx => OffscaleView.tsx} | 6 +- ...eViewHeader.tsx => OffscaleViewHeader.tsx} | 14 +- web/PolicyAssistant.tsx | 4 +- web/PolicyView.tsx | 4 +- web/ServerForm.tsx | 20 +-- web/ServersView.tsx | 30 ++-- web/UsersView.tsx | 18 +-- web/ViewShell.tsx | 4 +- web/layout.ts | 8 +- web/panels.ts | 24 ++-- web/shared.ts | 48 +++---- ...leCompanion.ts => useOffscaleCompanion.ts} | 4 +- ...useHeadscaleData.ts => useOffscaleData.ts} | 34 ++--- ...dscaleInvites.ts => useOffscaleInvites.ts} | 10 +- ...eadscalePolicy.ts => useOffscalePolicy.ts} | 14 +- ...dscaleSection.ts => useOffscaleSection.ts} | 8 +- ...dscaleServers.ts => useOffscaleServers.ts} | 28 ++-- 42 files changed, 658 insertions(+), 346 deletions(-) create mode 100644 OFFSCALE_API.md create mode 100644 assets/icon.png create mode 100644 sidecar/normalize.test.ts create mode 100644 sidecar/version.test.ts rename web/{HeadscaleNav.tsx => OffscaleNav.tsx} (83%) rename web/{HeadscaleServerPicker.tsx => OffscaleServerPicker.tsx} (86%) rename web/{HeadscaleView.tsx => OffscaleView.tsx} (88%) rename web/{HeadscaleViewHeader.tsx => OffscaleViewHeader.tsx} (57%) rename web/{useHeadscaleCompanion.ts => useOffscaleCompanion.ts} (98%) rename web/{useHeadscaleData.ts => useOffscaleData.ts} (79%) rename web/{useHeadscaleInvites.ts => useOffscaleInvites.ts} (83%) rename web/{useHeadscalePolicy.ts => useOffscalePolicy.ts} (88%) rename web/{useHeadscaleSection.ts => useOffscaleSection.ts} (51%) rename web/{useHeadscaleServers.ts => useOffscaleServers.ts} (76%) diff --git a/OFFSCALE_API.md b/OFFSCALE_API.md new file mode 100644 index 0000000..ab8bd1f --- /dev/null +++ b/OFFSCALE_API.md @@ -0,0 +1,133 @@ +# The OffScale HTTP contract + +What `officer-offscale` serves, and what the platform forwards to it. + +OffScale is Officer's tooling layer over Headscale. It adds nothing destructive and deviates from +nothing Headscale does — it composes, normalises and gates. The naming follows that split exactly: +**everything Officer owns is `offscale`; the server being managed is a Headscale server and is still +called one.** So the sidecar registers as `offscale`, mounts at `/api/offscale`, and stores its rows in +`offscale_servers` — while an error saying `headscale unreachable` means precisely what it says. + +## How a request gets here + +``` +browser ──▶ /api/offscale/_officer/nodes the platform: auth + permission gate only + ──▶ createSidecarProxy strips the prefix ../api/router.ts, derived from mountPrefix() + ──▶ 127.0.0.1:/_officer/nodes this sidecar + ──▶ https:///api/v1/node the Headscale admin API, with the stored key +``` + +The platform holds **no Headscale credential** and does not know any Headscale URL. It knows a +permission key and a port. That is the whole of its involvement. + +The prefix is derived from `mountPrefix()`, never written as a literal — the proxy strips +`prefix.length` characters, so a hardcoded `/api/offscale` would forward the wrong subpath the moment +this plugin were published by anyone but `officerdev` (it would mount at `/api/p//offscale`). + +## Many servers, one active + +Officer manages **many** Headscale servers, not one. Each is registered with a URL and an API key +generated on that server; one is active at a time. + +Configuration therefore lives in Postgres (`offscale_servers`, keys encrypted at rest) and **not** in +environment variables. This sidecar deliberately reads neither `OFFSCALE_URL` nor `OFFSCALE_API_KEY`, so +a registered server can never be silently shadowed by host env. + +Every route below `/_officer/servers` acts on the **active** server and answers `409` when none is +selected. + +## Routes + +### Liveness + +| Method | Path | Notes | +| ------ | ---------- | ----------------------------------------------------------------------------------------------- | +| `GET` | `/_health` | This sidecar only. Per-server reachability is a different question — see `/servers/:id/health`. | + +### Server registry + +| Method | Path | Notes | +| -------- | -------------------------------- | ------------------------------------------------------------------------- | +| `GET` | `/_officer/servers` | Registered servers. **Never** includes API keys. | +| `POST` | `/_officer/servers` | `{name?, url, apiKey}` — validated against the server before it is saved. | +| `PATCH` | `/_officer/servers/:id` | Re-validated when `url` or `apiKey` changes. | +| `DELETE` | `/_officer/servers/:id` | Promotes the newest survivor if the deleted one was active. | +| `POST` | `/_officer/servers/:id/activate` | Switch the active server. | +| `GET` | `/_officer/servers/:id/health` | Reachable? Version? Is the key still accepted? | + +### Nodes + +| Method | Path | Notes | +| -------- | ---------------------------- | ---------------------------------------------------------------------------------------------------------- | +| `GET` | `/_officer/nodes` | Normalised. `?user=` filters. | +| `GET` | `/_officer/nodes/:id` | | +| `DELETE` | `/_officer/nodes/:id` | Removes it from the tailnet. | +| `POST` | `/_officer/nodes/:id/rename` | `{name}` | +| `POST` | `/_officer/nodes/:id/tags` | `{tags}` — a `tag:` prefix is added when missing. | +| `POST` | `/_officer/nodes/:id/routes` | `{routes}` for the whole set, or `{route, approved}` for a single toggle (read-modify-write happens here). | +| `POST` | `/_officer/nodes/:id/expire` | Expires its key, forcing re-auth. **Not** a delete. | + +### Users + +| Method | Path | Notes | +| -------- | ---------------------------- | ------------------------------------------------------ | +| `GET` | `/_officer/users` | Each with a node count the admin API does not provide. | +| `POST` | `/_officer/users` | `{name, displayName?, email?}` | +| `POST` | `/_officer/users/:id/rename` | `{name}` | +| `DELETE` | `/_officer/users/:id` | Refused upstream while the user still owns nodes. | + +### Pre-auth keys + +| Method | Path | Notes | +| -------- | --------------------------- | -------------------------------------------------------------------------------------------------------------- | +| `GET` | `/_officer/keys` | Secrets masked, with a derived status. | +| `POST` | `/_officer/keys` | `{userId, reusable?, ephemeral?, expirationDays?, aclTags?}` — **the only response carrying the real secret.** | +| `POST` | `/_officer/keys/:id/expire` | Expire without deleting. | +| `DELETE` | `/_officer/keys/:id` | Delete outright. | + +### Enrollment + +| Method | Path | Notes | +| ------ | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `POST` | `/_officer/enroll` | `{userId?}` → `{controlUrl, authKey}`, a single-use 10-minute key for a joining device. `userId` is required only when the server has more than one user. | + +`/_officer/enroll` has had **no direct caller since 2026-08-14**, when `/api/vpn/enroll` was deleted. It +is kept because it is the handler a route under `/api/offscale` would reuse, and because +`/enroll/invites` — which is live — dispatches through the same function. + +Anything else: `404`. + +## There is deliberately no `/api/v1/*` passthrough + +Headscale's REST shape changed repeatedly below 0.29 and its ids are uint64-as-JSON-string. Proxying raw +would push all of that into the browser — the mistake the Soulseek panels made with 37 raw upstream +calls. Every quirk is absorbed here instead. + +## The three protobuf leaks, and where they are contained + +Headscale's REST layer is a gRPC gateway marshalling protobuf. It leaks in exactly three ways, all +handled in `sidecar/normalize.ts` (and pinned by `sidecar/normalize.test.ts`): + +1. **Every uint64 is a JSON string.** Ids stay strings end to end. Never `Number()` them — it breaks + silently above 2^53, and Headscale's ids are database-assigned, not small by contract. +2. **Unset timestamps are the protobuf zero value**, serialised as `0001-01-01T00:00:00Z` rather than + omitted. Rendered naively that reads as the year 1; it means "never", so it becomes `null`. +3. **`EmitUnpopulated`** means absent repeated fields arrive as `[]` and absent messages as `null`. There + is no way to distinguish "unset" from "empty", so every accessor tolerates both. + +## The version floor + +Officer targets **Headscale >= 0.29** and nothing older, checked once at registration by an +unauthenticated `GET /version` on the server itself. Below that floor the admin API changed shape +repeatedly — identifiers went name→numeric at 0.26, `/api/v1/routes` was removed at 0.26 in favour of +node-owned route sets, `forcedTags`/`validTags` collapsed into `tags` at 0.28, pre-auth key expiry became +id-based at 0.28, and `MoveNode` was removed at 0.28. Supporting 0.23–0.28 would mean carrying several +incompatible data models; refusing them at registration costs one probe. + +A version that will not parse — a self-built image reporting the literal `dev` — is reported as +`supported: 'unknown'` rather than refused. Locking out legitimately self-built deployments would be the +worse failure. `sidecar/version.test.ts` pins that case specifically. + +Do not confuse `GET /version` with the two similarly-named endpoints: `GET /health` (root, +unauthenticated, `{status:'pass'}`) and `GET /api/v1/health` (authenticated, +`{databaseConnectivity:true}`) carry no version at all. diff --git a/api/router.ts b/api/router.ts index 3d3a09a..ffb0369 100644 --- a/api/router.ts +++ b/api/router.ts @@ -1,18 +1,35 @@ import { createSidecarProxy } from '@@/sidecar/create-proxy'; +import { mountPrefix } from '@@/plugins/manifest'; +import { manifest } from '../manifest'; -// /api/headscale/* — auth, then forward to officer-headscale. No routes of its own and no headscale knowledge: -// this file must never grow app logic. +// /api/offscale/* — auth, then forward to officer-offscale. No routes of its own and no Headscale +// knowledge: this file must never grow app logic. // // The sidecar exposes only Officer-owned routes under `/_officer/` — Headscale's REST shape differs // across releases, and version handling belongs in the sidecar. It holds the admin API key; the platform -// does not know Headscale's URL. - +// does not know any Headscale URL. +// +// ── The prefix is DERIVED, not written ── +// +// It was the literal '/api/offscale'. That is wrong in a way that only shows up for someone else's +// plugin: the proxy strips `prefix.length` characters to build the sidecar path, so a hardcoded +// '/api/offscale' (13 chars) is correct only because `mountPrefix` happens to return `/offscale` for a +// first-party publisher. The same plugin published by anyone else mounts at +// `/api/p//offscale` and would forward `/alice/offscale/nodes` to a sidecar expecting +// `/nodes`. +// +// `mountPrefix` is the ONE function allowed to know about provenance, so the prefix comes from it. A +// literal here is that rule being broken quietly, which is how first-party and third-party become two +// systems with only one of them tested. Carried over from music, which hit this first. +// +// `appName` is a literal because this file cannot see its own directory name — the platform imports +// `router.ts` and reads `router`, so there is nowhere to inject it. Same known gap music records. const proxy = createSidecarProxy({ - name: 'headscale', - prefix: '/api/offscale', + name: 'offscale', + prefix: `/api${mountPrefix({ appName: 'offscale', manifest })}`, }); export const router = proxy.router; /** Base URL of the sidecar's HTTP server, or null if it hasn't reported in yet. */ -export const getHeadscaleServerUrl = proxy.getHttpUrl; +export const getOffscaleServerUrl = proxy.getHttpUrl; diff --git a/assets/icon.png b/assets/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..81a706be4c35787b93404216f1443b611852fa18 GIT binary patch literal 140401 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�NkvXXu0mjfSE?_3 literal 0 HcmV?d00001 diff --git a/db/queries.ts b/db/queries.ts index ba3b155..5213a2f 100644 --- a/db/queries.ts +++ b/db/queries.ts @@ -1,20 +1,20 @@ import { eq, and, desc } from 'drizzle-orm'; import { db } from 'officerdb/db'; -import { headscaleServers } from './schema'; +import { offscaleServers } from './schema'; import { encryptSecret, decryptSecret } from 'officerdb/crypto'; -// Headscale server registry access for the officer-headscale sidecar. Callers deal in PLAINTEXT — +// Headscale server registry access for the officer-offscale sidecar. Callers deal in PLAINTEXT — // encryption to/from at-rest ciphertext happens here, so the sidecar's route handlers never touch crypto. -// See ../crypto.ts and ../schema/headscale.ts. +// See ./schema.ts — the encryption lives in the platform, via officerdb. // // Two return types on purpose: -// HeadscaleServer — safe to serialize to the browser. Has NO api key field at all. -// HeadscaleServerCredentials — url + decrypted key, for the sidecar's own upstream calls. Never returned +// OffscaleServer — safe to serialize to the browser. Has NO api key field at all. +// OffscaleServerCredentials — url + decrypted key, for the sidecar's own upstream calls. Never returned // by a route handler. // The `serverCols` projection is what enforces that: `select()` without it would leak the ciphertext column // into every list response the moment someone forgot to strip it. -export type HeadscaleServer = { +export type OffscaleServer = { id: number; name: string; url: string; @@ -25,49 +25,49 @@ export type HeadscaleServer = { createdAt: Date; }; -export type HeadscaleServerCredentials = { id: number; name: string; url: string; apiKey: string }; +export type OffscaleServerCredentials = { id: number; name: string; url: string; apiKey: string }; const serverCols = { - id: headscaleServers.id, - name: headscaleServers.name, - url: headscaleServers.url, - version: headscaleServers.version, - sshHost: headscaleServers.sshHost, - isActive: headscaleServers.isActive, - lastSeenAt: headscaleServers.lastSeenAt, - createdAt: headscaleServers.createdAt, + id: offscaleServers.id, + name: offscaleServers.name, + url: offscaleServers.url, + version: offscaleServers.version, + sshHost: offscaleServers.sshHost, + isActive: offscaleServers.isActive, + lastSeenAt: offscaleServers.lastSeenAt, + createdAt: offscaleServers.createdAt, }; /** Every server the owner has registered, active first then newest. Never includes the API key. */ -export async function listHeadscaleServers(userId: number): Promise { +export async function listOffscaleServers(userId: number): Promise { return db .select(serverCols) - .from(headscaleServers) - .where(eq(headscaleServers.userId, userId)) - .orderBy(desc(headscaleServers.isActive), desc(headscaleServers.createdAt)); + .from(offscaleServers) + .where(eq(offscaleServers.userId, userId)) + .orderBy(desc(offscaleServers.isActive), desc(offscaleServers.createdAt)); } /** The currently selected server with its key decrypted, or null when none is registered/active. */ -export async function getActiveHeadscaleCredentials(userId: number): Promise { +export async function getActiveOffscaleCredentials(userId: number): Promise { const [row] = await db .select() - .from(headscaleServers) - .where(and(eq(headscaleServers.userId, userId), eq(headscaleServers.isActive, true))); + .from(offscaleServers) + .where(and(eq(offscaleServers.userId, userId), eq(offscaleServers.isActive, true))); if (!row) return null; - return { id: row.id, name: row.name, url: row.url, apiKey: decryptSecret('headscale', row.apiKey) }; + return { id: row.id, name: row.name, url: row.url, apiKey: decryptSecret('offscale', row.apiKey) }; } /** One server's credentials by id — for probing a specific server rather than the active one. */ -export async function getHeadscaleCredentials(userId: number, id: number): Promise { +export async function getOffscaleCredentials(userId: number, id: number): Promise { const [row] = await db .select() - .from(headscaleServers) - .where(and(eq(headscaleServers.userId, userId), eq(headscaleServers.id, id))); + .from(offscaleServers) + .where(and(eq(offscaleServers.userId, userId), eq(offscaleServers.id, id))); if (!row) return null; - return { id: row.id, name: row.name, url: row.url, apiKey: decryptSecret('headscale', row.apiKey) }; + return { id: row.id, name: row.name, url: row.url, apiKey: decryptSecret('offscale', row.apiKey) }; } -type CreateHeadscaleServerParams = { +type CreateOffscaleServerParams = { userId: number; name: string; url: string; @@ -80,22 +80,22 @@ type CreateHeadscaleServerParams = { }; /** Register a server. The key is encrypted before write; the returned row carries no key. */ -export async function createHeadscaleServer(params: CreateHeadscaleServerParams): Promise { +export async function createOffscaleServer(params: CreateOffscaleServerParams): Promise { const { userId, name, url, apiKey, version, sshHost, activate } = params; return db.transaction(async (tx) => { if (activate) { await tx - .update(headscaleServers) + .update(offscaleServers) .set({ isActive: false, updatedAt: new Date() }) - .where(and(eq(headscaleServers.userId, userId), eq(headscaleServers.isActive, true))); + .where(and(eq(offscaleServers.userId, userId), eq(offscaleServers.isActive, true))); } const [row] = await tx - .insert(headscaleServers) + .insert(offscaleServers) .values({ userId, name, url, - apiKey: encryptSecret('headscale', apiKey), + apiKey: encryptSecret('offscale', apiKey), version, sshHost, isActive: activate, @@ -108,39 +108,39 @@ export async function createHeadscaleServer(params: CreateHeadscaleServerParams) // `sshHost: null` clears the console target; omitting the field leaves it alone. The two must stay // distinguishable, which is why this is `string | null` and not `string`. -type UpdateHeadscaleServerParams = { name?: string; url?: string; apiKey?: string; sshHost?: string | null }; +type UpdateOffscaleServerParams = { name?: string; url?: string; apiKey?: string; sshHost?: string | null }; /** Edit a registration. Omitted fields are left alone; a supplied key is re-encrypted. */ -export async function updateHeadscaleServer( +export async function updateOffscaleServer( userId: number, id: number, - params: UpdateHeadscaleServerParams, -): Promise { + params: UpdateOffscaleServerParams, +): Promise { const set: Record = { updatedAt: new Date() }; if (params.name !== undefined) set.name = params.name; if (params.url !== undefined) set.url = params.url; - if (params.apiKey !== undefined) set.apiKey = encryptSecret('headscale', params.apiKey); + if (params.apiKey !== undefined) set.apiKey = encryptSecret('offscale', params.apiKey); if (params.sshHost !== undefined) set.sshHost = params.sshHost; const [row] = await db - .update(headscaleServers) + .update(offscaleServers) .set(set) - .where(and(eq(headscaleServers.userId, userId), eq(headscaleServers.id, id))) + .where(and(eq(offscaleServers.userId, userId), eq(offscaleServers.id, id))) .returning(serverCols); return row ?? null; } /** Select a server. Clearing the others first keeps the one-active partial index satisfied. */ -export async function setActiveHeadscaleServer(userId: number, id: number): Promise { +export async function setActiveOffscaleServer(userId: number, id: number): Promise { return db.transaction(async (tx) => { await tx - .update(headscaleServers) + .update(offscaleServers) .set({ isActive: false, updatedAt: new Date() }) - .where(and(eq(headscaleServers.userId, userId), eq(headscaleServers.isActive, true))); + .where(and(eq(offscaleServers.userId, userId), eq(offscaleServers.isActive, true))); const [row] = await tx - .update(headscaleServers) + .update(offscaleServers) .set({ isActive: true, updatedAt: new Date() }) - .where(and(eq(headscaleServers.userId, userId), eq(headscaleServers.id, id))) + .where(and(eq(offscaleServers.userId, userId), eq(offscaleServers.id, id))) .returning(serverCols); return row ?? null; }); @@ -151,26 +151,26 @@ export async function setActiveHeadscaleServer(userId: number, id: number): Prom * active server would leave the UI with servers registered but none selected, which reads as "not * configured" and is a confusing place to land. */ -export async function deleteHeadscaleServer(userId: number, id: number): Promise { +export async function deleteOffscaleServer(userId: number, id: number): Promise { return db.transaction(async (tx) => { const [deleted] = await tx - .delete(headscaleServers) - .where(and(eq(headscaleServers.userId, userId), eq(headscaleServers.id, id))) - .returning({ id: headscaleServers.id, wasActive: headscaleServers.isActive }); + .delete(offscaleServers) + .where(and(eq(offscaleServers.userId, userId), eq(offscaleServers.id, id))) + .returning({ id: offscaleServers.id, wasActive: offscaleServers.isActive }); if (!deleted) return false; if (deleted.wasActive) { const [next] = await tx - .select({ id: headscaleServers.id }) - .from(headscaleServers) - .where(eq(headscaleServers.userId, userId)) - .orderBy(desc(headscaleServers.createdAt)) + .select({ id: offscaleServers.id }) + .from(offscaleServers) + .where(eq(offscaleServers.userId, userId)) + .orderBy(desc(offscaleServers.createdAt)) .limit(1); if (next) { await tx - .update(headscaleServers) + .update(offscaleServers) .set({ isActive: true, updatedAt: new Date() }) - .where(eq(headscaleServers.id, next.id)); + .where(eq(offscaleServers.id, next.id)); } } return true; @@ -178,9 +178,9 @@ export async function deleteHeadscaleServer(userId: number, id: number): Promise } /** Record a successful reachability probe: the version observed and when we last reached the server. */ -export async function recordHeadscaleProbe(userId: number, id: number, version: string | null): Promise { +export async function recordOffscaleProbe(userId: number, id: number, version: string | null): Promise { await db - .update(headscaleServers) + .update(offscaleServers) .set({ version, lastSeenAt: new Date(), updatedAt: new Date() }) - .where(and(eq(headscaleServers.userId, userId), eq(headscaleServers.id, id))); + .where(and(eq(offscaleServers.userId, userId), eq(offscaleServers.id, id))); } diff --git a/db/schema.ts b/db/schema.ts index 08376bb..fd60a35 100644 --- a/db/schema.ts +++ b/db/schema.ts @@ -2,7 +2,7 @@ import { pgTable, serial, integer, text, boolean, timestamp, uniqueIndex } from import { sql } from 'drizzle-orm'; import { users } from 'officerdb/auth/schema'; -// The Headscale servers the owner manages, for the officer-headscale sidecar. Officer targets no single +// The Headscale servers the owner manages, for the officer-offscale sidecar. Officer targets no single // Headscale: the owner registers one or more servers (URL + an admin API key generated on that server) and // toggles between them, so this is configuration the user creates at runtime rather than env vars. // @@ -12,12 +12,12 @@ import { users } from 'officerdb/auth/schema'; // at all. SECURITY_AUDIT.md L2 records plaintext credential storage as an open finding, so the plaintext // email/integrations tables are debt to avoid copying, not a precedent to follow. // -// Every table here is `headscale_`-prefixed and this file holds nothing else: when sidecars own their own -// schema it moves wholesale into src/servers/sidecar/headscale/ with no untangling. Only the -// officer-headscale sidecar reads or writes these tables. +// Every table here is `offscale_`-prefixed and this file holds nothing else: when sidecars own their own +// schema it moves wholesale into ../sidecar/ with no untangling. Only the +// officer-offscale sidecar reads or writes these tables. -export const headscaleServers = pgTable( - 'headscale_servers', +export const offscaleServers = pgTable( + 'offscale_servers', { id: serial('id').primaryKey(), userId: integer('user_id') @@ -44,11 +44,11 @@ export const headscaleServers = pgTable( }, (t) => [ // One registration per URL — re-registering the same server should be an edit, not a duplicate. - uniqueIndex('uq_headscale_servers_user_url').on(t.userId, t.url), + uniqueIndex('uq_offscale_servers_user_url').on(t.userId, t.url), // At most one active server per owner, enforced by the DB rather than by convention: a partial unique - // index over the active rows only. setActiveHeadscaleServer still clears the others in a transaction, + // index over the active rows only. setActiveOffscaleServer still clears the others in a transaction, // but a bug there fails loudly here instead of silently leaving two servers active. - uniqueIndex('uq_headscale_servers_one_active') + uniqueIndex('uq_offscale_servers_one_active') .on(t.userId) .where(sql`${t.isActive}`), ], diff --git a/manifest.ts b/manifest.ts index 2a01d9a..b80a94f 100644 --- a/manifest.ts +++ b/manifest.ts @@ -25,7 +25,7 @@ export const manifest: PluginManifest = { // One permission gating the whole surface, grantable per role at read or write like every other. // // `[open]` What a member's grant MEANS here is this plugin's own job and is not finished. The queries - // still scope by the caller (`listHeadscaleServers(userId)`), so a granted member would see their own + // still scope by the caller (`listOffscaleServers(userId)`), so a granted member would see their own // empty server list rather than the owner's, and could register a Headscale of their own. The model in // ./PLUGIN.md is one shared resource: read sees what the owner sees, write can change it. // That is a change inside these queries, not a flag on the manifest. diff --git a/sidecar/active.ts b/sidecar/active.ts index d41e781..a1e1706 100644 --- a/sidecar/active.ts +++ b/sidecar/active.ts @@ -1,5 +1,5 @@ -import { getActiveHeadscaleCredentials } from '../db/queries'; -import { createClient, type HeadscaleClient } from './client'; +import { getActiveOffscaleCredentials } from '../db/queries'; +import { createClient, type OffscaleClient } from './client'; // Every domain route acts on the ACTIVE server — the one the owner selected in the servers section. That // choice lives in Postgres (one row, enforced by a partial unique index), not in a request parameter, so @@ -11,8 +11,8 @@ import { createClient, type HeadscaleClient } from './client'; * 409 rather than 404: the route exists and the request was well-formed, the account just has no server * selected yet. The UI maps it to "pick a server", which is a different message from "that node is gone". */ -export async function activeClient(userId: number): Promise { - const creds = await getActiveHeadscaleCredentials(userId); +export async function activeClient(userId: number): Promise { + const creds = await getActiveOffscaleCredentials(userId); if (!creds) { return Response.json({ error: 'no active Headscale server', code: 'no_active_server' }, { status: 409 }); } diff --git a/sidecar/client.ts b/sidecar/client.ts index 5e51fb3..1cb5edc 100644 --- a/sidecar/client.ts +++ b/sidecar/client.ts @@ -1,4 +1,4 @@ -import type { HeadscaleServerCredentials } from '../db/queries'; +import type { OffscaleServerCredentials } from '../db/queries'; // The Headscale admin API call layer. Every upstream request in this sidecar goes through here, so the // wire-level quirks are handled once: @@ -18,7 +18,7 @@ import type { HeadscaleServerCredentials } from '../db/queries'; const DEFAULT_TIMEOUT_MS = 15_000; /** An upstream failure carrying the HTTP status to surface, mapped to a response at the route boundary. */ -export class HeadscaleError extends Error { +export class OffscaleError extends Error { constructor( readonly status: number, message: string, @@ -33,7 +33,7 @@ export class HeadscaleError extends Error { readonly detail?: string, ) { super(message); - this.name = 'HeadscaleError'; + this.name = 'OffscaleError'; } } @@ -55,14 +55,14 @@ async function errorMessage(res: Response): Promise { return text.slice(0, 300); } -export type HeadscaleClient = { +export type OffscaleClient = { readonly serverId: number; - /** Call an admin API path (e.g. `/api/v1/node`). Throws HeadscaleError on any non-2xx. */ + /** Call an admin API path (e.g. `/api/v1/node`). Throws OffscaleError on any non-2xx. */ call: (path: string, opts?: CallOptions) => Promise; }; /** Build a client bound to one registered server's credentials. */ -export function createClient(creds: HeadscaleServerCredentials): HeadscaleClient { +export function createClient(creds: OffscaleServerCredentials): OffscaleClient { async function call(path: string, opts: CallOptions = {}): Promise { const { method = 'GET', body, timeoutMs = DEFAULT_TIMEOUT_MS } = opts; @@ -82,13 +82,13 @@ export function createClient(creds: HeadscaleServerCredentials): HeadscaleClient }); } catch (err) { const timedOut = err instanceof Error && err.name === 'TimeoutError'; - throw new HeadscaleError(504, timedOut ? 'headscale timed out' : 'headscale unreachable'); + throw new OffscaleError(504, timedOut ? 'headscale timed out' : 'headscale unreachable'); } if (res.status === 401 || res.status === 403) { // The stored key is wrong, expired, or was revoked on the server. Actionable, and distinct from an // Officer-side auth problem — the UI should point the owner at re-entering the key. - throw new HeadscaleError(502, 'headscale rejected the stored API key'); + throw new OffscaleError(502, 'headscale rejected the stored API key'); } if (!res.ok) { @@ -96,7 +96,7 @@ export function createClient(creds: HeadscaleServerCredentials): HeadscaleClient console.error(`[headscale] ${method} ${path} -> ${res.status}: ${message}`); // 4xx from the admin API is usually a bad argument and safe to relay; 5xx is not, so it's generalized. const serverSide = res.status >= 500; - throw new HeadscaleError(serverSide ? 502 : res.status, serverSide ? 'headscale error' : message, message); + throw new OffscaleError(serverSide ? 502 : res.status, serverSide ? 'headscale error' : message, message); } // 204 and empty 200s are legitimate: several mutations return `{}` or nothing at all. @@ -105,7 +105,7 @@ export function createClient(creds: HeadscaleServerCredentials): HeadscaleClient try { return JSON.parse(text) as T; } catch { - throw new HeadscaleError(502, 'headscale returned a non-JSON body'); + throw new OffscaleError(502, 'headscale returned a non-JSON body'); } } diff --git a/sidecar/companion.ts b/sidecar/companion.ts index c44a21c..30ee41f 100644 --- a/sidecar/companion.ts +++ b/sidecar/companion.ts @@ -1,9 +1,9 @@ -import { getActiveHeadscaleCredentials, type HeadscaleServerCredentials } from '../db/queries'; +import { getActiveOffscaleCredentials, type OffscaleServerCredentials } from '../db/queries'; import { badRequest, methodNotAllowed, notFound, type OfficerContext } from './routes'; // The Officer Companion API — a small service deployed NEXT TO each Headscale server that answers what the // admin API structurally cannot: is the container up, what do its logs say, and start/stop/restart it. -// Contract: COMMS/HEADSCALE_COMPANION_API.md. +// Contract: COMMS/OFFSCALE_COMPANION_API.md. // // Three facts shape everything here. // @@ -38,7 +38,7 @@ type CompanionCall = { path: string; method?: string; body?: unknown; timeoutMs? * "unreachable" is information rather than a failure. */ export async function callCompanion( - creds: HeadscaleServerCredentials, + creds: OffscaleServerCredentials, { path, method = 'GET', body, timeoutMs = DEFAULT_TIMEOUT_MS, signal }: CompanionCall, ): Promise { let res: Response; @@ -85,8 +85,8 @@ export async function readBody(res: Response): Promise | } /** The active server's credentials, or a 409 the UI already knows how to render. */ -export async function activeCreds(userId: number): Promise { - const creds = await getActiveHeadscaleCredentials(userId); +export async function activeCreds(userId: number): Promise { + const creds = await getActiveOffscaleCredentials(userId); if (!creds) { return Response.json({ error: 'no active Headscale server', code: 'no_active_server' }, { status: 409 }); } @@ -94,7 +94,7 @@ export async function activeCreds(userId: number): Promise { +async function health(creds: OffscaleServerCredentials): Promise { const res = await callCompanion(creds, { path: '/health' }); if (typeof res === 'string') return Response.json(unavailable(res)); @@ -106,7 +106,7 @@ async function health(creds: HeadscaleServerCredentials): Promise { } /** `GET /_officer/companion/logs?tail=N` — a snapshot of the last N lines. */ -async function logs(creds: HeadscaleServerCredentials, url: URL): Promise { +async function logs(creds: OffscaleServerCredentials, url: URL): Promise { const tail = Number(url.searchParams.get('tail') ?? 200); if (!Number.isInteger(tail) || tail < 1 || tail > 2000) return badRequest('tail must be 1–2000'); @@ -127,7 +127,7 @@ async function logs(creds: HeadscaleServerCredentials, url: URL): Promise { +async function logStream(creds: OffscaleServerCredentials, ctx: OfficerContext): Promise { const tail = Number(ctx.url.searchParams.get('tail') ?? 200); if (!Number.isInteger(tail) || tail < 1 || tail > 2000) return badRequest('tail must be 1–2000'); @@ -165,7 +165,7 @@ const ACTIONS = new Set(['restart', 'stop', 'start']); * Every one of these drops every node's control-plane connection for the duration. That is the intended * "kill it" behaviour and the reason the UI asks twice; it is not something to retry automatically. */ -async function action(creds: HeadscaleServerCredentials, name: string): Promise { +async function action(creds: OffscaleServerCredentials, name: string): Promise { // 60s: docker restart on a busy container is not fast, and a timeout here reads as "did it work?" — the // one question this feature exists to answer. const res = await callCompanion(creds, { path: `/${name}`, method: 'POST', timeoutMs: 60_000 }); diff --git a/sidecar/enroll.ts b/sidecar/enroll.ts index eed8195..ea09027 100644 --- a/sidecar/enroll.ts +++ b/sidecar/enroll.ts @@ -1,8 +1,8 @@ import type { OfficerContext } from './routes'; import type { OfficerUser } from './normalize'; -import { getActiveHeadscaleCredentials } from '../db/queries'; +import { getActiveOffscaleCredentials } from '../db/queries'; import { badRequest, methodNotAllowed, readJson } from './routes'; -import { createClient, type HeadscaleClient } from './client'; +import { createClient, type OffscaleClient } from './client'; import { arrayField, toUser } from './normalize'; import { handleInvitesRoute } from './invites'; @@ -10,8 +10,8 @@ import { handleInvitesRoute } from './invites'; // Officer session into a short-lived, single-use pre-auth key, so nobody pastes a key by hand. // // THIS USED TO LIVE IN THE PLATFORM. `src/servers/api/vpn/router.ts` (deleted 2026-08-14) read -// HEADSCALE_URL, HEADSCALE_API_KEY -// and HEADSCALE_USER straight from the host env — three globals that could only ever describe ONE server, +// OFFSCALE_URL, OFFSCALE_API_KEY +// and OFFSCALE_USER straight from the host env — three globals that could only ever describe ONE server, // while this sidecar already kept a registry of many. Worse, the two credential vars were removed at some // point and nobody noticed: the route had been answering 503 to every enrolment attempt, because it checks // those two before it gets anywhere near the user name. Enrolment acts on the ACTIVE registered server now, @@ -32,7 +32,7 @@ const KEY_TTL_MS = 10 * 60_000; * files someone's phone under the wrong owner and the mistake stays invisible until somebody audits the * tailnet. The old env var picked one name for every server at once, which is precisely that bug. */ -async function resolveOwner(client: HeadscaleClient, ctx: OfficerContext): Promise { +async function resolveOwner(client: OffscaleClient, ctx: OfficerContext): Promise { const body = await readJson(ctx.req); const requested = typeof body?.userId === 'string' ? body.userId.trim() : ''; @@ -75,7 +75,7 @@ export async function handleEnrollRoute(ctx: OfficerContext, segments: string[]) if (ctx.req.method !== 'POST') return methodNotAllowed(); // Not activeClient(): the control URL goes back to the device, and only the credentials carry it. - const creds = await getActiveHeadscaleCredentials(ctx.userId); + const creds = await getActiveOffscaleCredentials(ctx.userId); if (!creds) { return Response.json({ error: 'no active Headscale server', code: 'no_active_server' }, { status: 409 }); } diff --git a/sidecar/index.ts b/sidecar/index.ts index ebb5ff5..2373e4f 100644 --- a/sidecar/index.ts +++ b/sidecar/index.ts @@ -4,19 +4,20 @@ import { handleOfficerRoute } from './routes'; import { MIN_VERSION_LABEL } from './version'; import { API_URL } from '@@/officer-url.mjs'; -// The officer-headscale sidecar. Owns the whole Headscale contract for Officer: the registered servers and +// The officer-offscale sidecar. Owns the whole Headscale contract for Officer: the registered servers and // their admin API keys, the >=0.29 version floor, and every multi-call composition the UI needs. The platform -// API is a thin auth-gated forwarder (src/servers/api/headscale/router.ts) holding no Headscale credentials. +// API is a thin auth-gated forwarder (../api/router.ts) holding no Headscale credentials. // // Officer manages MANY Headscale servers, not one. The owner registers each with a URL and an API key // generated on that server, and switches between them; one is active at a time. So configuration lives in -// Postgres (headscale_servers, keys encrypted at rest), NOT in env vars — this sidecar deliberately reads -// neither HEADSCALE_URL nor HEADSCALE_API_KEY, so a registered server can never be shadowed by host env. +// Postgres (offscale_servers, keys encrypted at rest), NOT in env vars — this sidecar deliberately reads +// neither OFFSCALE_URL nor OFFSCALE_API_KEY, so a registered server can never be shadowed by host env. // Device enrollment used to be the exception, minting keys in the platform from those two vars plus -// HEADSCALE_USER; it moved here (enroll.ts) and now acts on the active server like everything else. +// OFFSCALE_USER; it moved here (enroll.ts) and now acts on the active server like everything else. // // ───────────────────────────────────────────────────────────────────────────────────────────────── -// HTTP CONTRACT — the platform strips its /api/headscale mount prefix before forwarding. +// HTTP CONTRACT — the platform strips its /api/offscale mount prefix before forwarding. +// Published in full as ../OFFSCALE_API.md; keep the two in step. // // GET /_health ours. Sidecar liveness only. Per-server reachability is a // different question and needs an owner, so it lives below. @@ -79,7 +80,7 @@ const server = Bun.serve({ // Liveness, not upstream health: with many registered servers there is no single upstream to probe, and // choosing one would need an authenticated owner. See /_officer/servers/:id/health for that. if (url.pathname === '/_health') { - return Response.json({ ok: true, minHeadscaleVersion: MIN_VERSION_LABEL }); + return Response.json({ ok: true, minOffscaleVersion: MIN_VERSION_LABEL }); } if (url.pathname.startsWith('/_officer/')) { @@ -87,7 +88,7 @@ const server = Bun.serve({ const res = await handleOfficerRoute(req, url); return res ?? new Response('not found', { status: 404 }); } catch (err) { - console.error(`[headscale] ${req.method} ${url.pathname} failed`, err); + console.error(`[offscale] ${req.method} ${url.pathname} failed`, err); return Response.json({ error: 'internal error' }, { status: 500 }); } } @@ -96,7 +97,7 @@ const server = Bun.serve({ }, }); -console.log(`[headscale] listening on 127.0.0.1:${port} (Headscale >=${MIN_VERSION_LABEL})`); +console.log(`[offscale] listening on 127.0.0.1:${port} (Headscale >=${MIN_VERSION_LABEL})`); // ── Command handlers ── @@ -120,22 +121,22 @@ function handleCommand(cmd: SidecarCommand, reply: ReplyFn) { const connection = createSidecarConnector({ apiUrl: `${API_URL}/api/sidecar/register`, - name: 'headscale', - handles: ['headscale'], + name: 'offscale', + handles: ['offscale'], onCommand(cmd, reply) { handleCommand(cmd as SidecarCommand, reply as ReplyFn); }, onConnected() { - // Tell the API where we're listening, so it can forward /api/headscale/* here. - connection.send({ type: 'headscale:server', port }); - console.log(`[headscale] reported port ${port} to API`); + // Tell the API where we're listening, so it can forward /api/offscale/* here. + connection.send({ type: 'offscale:server', port }); + console.log(`[offscale] reported port ${port} to API`); }, }); // ── Graceful shutdown ── function shutdown(signal: string) { - console.log(`[headscale] ${signal} received, shutting down...`); + console.log(`[offscale] ${signal} received, shutting down...`); try { server.stop(true); } catch { diff --git a/sidecar/invites.ts b/sidecar/invites.ts index 37fed1d..11fd00c 100644 --- a/sidecar/invites.ts +++ b/sidecar/invites.ts @@ -1,4 +1,4 @@ -import type { HeadscaleServerCredentials } from '../db/queries'; +import type { OffscaleServerCredentials } from '../db/queries'; import { badRequest, methodNotAllowed, notFound, readJson, type OfficerContext } from './routes'; import { activeCreds, callCompanion, readBody, unavailable } from './companion'; @@ -122,7 +122,7 @@ function withNameHint(url: unknown, name: string | undefined): unknown { * dropped here rather than passed on: it carries the same claim token in its fragment, and a second copy of * a single-use credential in the browser is a second chance to leak it. Nothing on our side opens it. */ -async function create(creds: HeadscaleServerCredentials, ctx: OfficerContext): Promise { +async function create(creds: OffscaleServerCredentials, ctx: OfficerContext): Promise { const input = parseCreate(await readJson(ctx.req)); if (input instanceof Response) return input; @@ -153,13 +153,13 @@ function pickInvites(body: Record): unknown[] { } /** `GET /_officer/enroll/invites` — the admin's audit list. Never carries a token or a key. */ -async function list(creds: HeadscaleServerCredentials): Promise { +async function list(creds: OffscaleServerCredentials): Promise { const res = await callCompanion(creds, { path: INVITES_PATH }); return relay(res, (body) => ({ available: true, invites: pickInvites(body) })); } /** `DELETE /_officer/enroll/invites/:id` — revoke an unclaimed invite. A no-op on a claimed one. */ -async function revoke(creds: HeadscaleServerCredentials, id: string): Promise { +async function revoke(creds: OffscaleServerCredentials, id: string): Promise { const res = await callCompanion(creds, { path: `${INVITES_PATH}/${encodeURIComponent(id)}`, method: 'DELETE' }); return relay(res, (body) => ({ available: true, ...body })); } diff --git a/sidecar/nodes.ts b/sidecar/nodes.ts index dc34a2c..838724f 100644 --- a/sidecar/nodes.ts +++ b/sidecar/nodes.ts @@ -1,6 +1,6 @@ import type { OfficerContext } from './routes'; import { badRequest, notFound, methodNotAllowed, readJson } from './routes'; -import type { HeadscaleClient } from './client'; +import type { OffscaleClient } from './client'; import { activeClient } from './active'; import { toNode, arrayField, type OfficerNode } from './normalize'; @@ -32,7 +32,7 @@ async function listNodes(ctx: OfficerContext): Promise { } /** Re-read one node after a mutation. Headscale's mutation responses are inconsistent; a GET never is. */ -async function getNode(client: HeadscaleClient, id: string): Promise { +async function getNode(client: OffscaleClient, id: string): Promise { const body = await client.call<{ node?: Record }>(`/api/v1/node/${encodeURIComponent(id)}`); return body.node ? toNode(body.node) : null; } diff --git a/sidecar/normalize.test.ts b/sidecar/normalize.test.ts new file mode 100644 index 0000000..d459b94 --- /dev/null +++ b/sidecar/normalize.test.ts @@ -0,0 +1,102 @@ +import { describe, expect, test } from 'bun:test'; +import { arrayField, isoOrNull, toNode, toUser } from './normalize'; + +// Headscale's REST layer is a gRPC gateway marshalling protobuf, and it leaks in three specific ways. +// These transforms are where that leak is contained, so they are the file most likely to be quietly wrong +// after an upstream release — and they had no tests at all. + +describe('isoOrNull', () => { + test("the protobuf zero timestamp means 'never', not the year 1", () => { + // The leak that matters most: unset timestamps arrive as this literal rather than being omitted. + // Rendered naively a node's expiry reads as year 1, which looks like an expired node rather than one + // that never expires. + expect(isoOrNull('0001-01-01T00:00:00Z')).toBeNull(); + }); + + test('pre-1971 is treated as the sentinel too, for builds that emit a different zero', () => { + expect(isoOrNull('1970-01-01T00:00:00Z')).toBeNull(); + expect(isoOrNull('1960-06-01T00:00:00Z')).toBeNull(); + }); + + test('a real timestamp survives, normalised to ISO', () => { + expect(isoOrNull('2026-08-15T10:30:00Z')).toBe('2026-08-15T10:30:00.000Z'); + }); + + test('anything that is not a usable string is null rather than a crash', () => { + // EmitUnpopulated means absent messages arrive as null, so these are normal input, not corruption. + for (const bad of [null, undefined, '', 'not a date', 42, {}, []]) { + expect(isoOrNull(bad)).toBeNull(); + } + }); +}); + +describe('toNode', () => { + test('ids stay STRINGS — never numbers', () => { + // Headscale ids are uint64 serialized as JSON strings. Number() breaks silently above 2^53, and the + // ids are database-assigned rather than small by contract, so this is a real ceiling and not theory. + const node = toNode({ id: '9007199254740993', name: 'a' }); + expect(node.id).toBe('9007199254740993'); + expect(typeof node.id).toBe('string'); + }); + + test('givenName wins over name, falling back when it is unset', () => { + expect(toNode({ id: '1', givenName: 'laptop', name: 'laptop.tail1234.ts.net' }).name).toBe('laptop'); + expect(toNode({ id: '1', name: 'laptop.tail1234.ts.net' }).name).toBe('laptop.tail1234.ts.net'); + }); + + test('an exit node is recognised from either default route', () => { + expect(toNode({ id: '1', availableRoutes: ['0.0.0.0/0'] }).isExitNode).toBe(true); + expect(toNode({ id: '1', availableRoutes: ['::/0'] }).isExitNode).toBe(true); + expect(toNode({ id: '1', availableRoutes: ['10.0.0.0/24'] }).isExitNode).toBe(false); + expect(toNode({ id: '1' }).isExitNode).toBe(false); + }); + + test('an unknown register method degrades rather than leaking the enum', () => { + expect(toNode({ id: '1', registerMethod: 'REGISTER_METHOD_AUTH_KEY' }).registerMethod).toBe('authkey'); + // A method added in a future release must not put REGISTER_METHOD_SOMETHING_NEW in the UI. + expect(toNode({ id: '1', registerMethod: 'REGISTER_METHOD_FUTURE' }).registerMethod).toBe('unknown'); + expect(toNode({ id: '1' }).registerMethod).toBe('unknown'); + }); + + test('online is strictly true, so a missing field is offline rather than truthy', () => { + expect(toNode({ id: '1', online: true }).online).toBe(true); + expect(toNode({ id: '1', online: 'true' }).online).toBe(false); + expect(toNode({ id: '1' }).online).toBe(false); + }); + + test('a node with nothing but an id normalises instead of throwing', () => { + // EmitUnpopulated guarantees absent repeated fields arrive as [] and absent messages as null, and + // there is no way to tell "unset" from "empty" — so every accessor has to tolerate both. + const node = toNode({ id: '7' }); + expect(node.ipAddresses).toEqual([]); + expect(node.tags).toEqual([]); + expect(node.user).toBeNull(); + expect(node.lastSeen).toBeNull(); + }); + + test('non-string entries are dropped from string arrays rather than rendered', () => { + expect(toNode({ id: '1', ipAddresses: ['100.64.0.1', null, 42, '::1'] }).ipAddresses).toEqual([ + '100.64.0.1', + '::1', + ]); + }); +}); + +describe('toUser', () => { + test('null and undefined pass through as null', () => { + expect(toUser(null)).toBeNull(); + expect(toUser(undefined)).toBeNull(); + }); +}); + +describe('arrayField', () => { + test('pulls the named array, keeping only objects', () => { + expect(arrayField({ nodes: [{ id: '1' }, null, 'x', { id: '2' }] }, 'nodes')).toEqual([{ id: '1' }, { id: '2' }]); + }); + + test('a missing field or a non-array body is an empty list, not a throw', () => { + expect(arrayField({}, 'nodes')).toEqual([]); + expect(arrayField(null, 'nodes')).toEqual([]); + expect(arrayField({ nodes: 'not-an-array' }, 'nodes')).toEqual([]); + }); +}); diff --git a/sidecar/policy.ts b/sidecar/policy.ts index 8a5a3bd..db79588 100644 --- a/sidecar/policy.ts +++ b/sidecar/policy.ts @@ -1,6 +1,6 @@ import type { OfficerContext } from './routes'; import { badRequest, methodNotAllowed, readJson } from './routes'; -import { HeadscaleError } from './client'; +import { OffscaleError } from './client'; import { activeClient } from './active'; import { handlePolicyAssistRoute } from './assist'; @@ -23,7 +23,7 @@ import { handlePolicyAssistRoute } from './assist'; // be the one shown. So the text goes up untouched and Headscale's verdict comes back verbatim. // // 3. **Both of those arrive as HTTP 500** from grpc-gateway, which the client layer normally generalizes -// to "headscale error". `HeadscaleError.detail` is how the real message survives that; see client.ts. +// to "headscale error". `OffscaleError.detail` is how the real message survives that; see client.ts. /** * Does this failure mean "writing is turned off here", as opposed to "your document is wrong"? @@ -59,7 +59,7 @@ async function getPolicy(ctx: OfficerContext): Promise { const body = await client.call('/api/v1/policy'); return Response.json({ policy: asText(body.policy), updatedAt: asDate(body.updatedAt) }); } catch (err) { - if (!(err instanceof HeadscaleError)) throw err; + if (!(err instanceof OffscaleError)) throw err; const detail = err.detail ?? err.message; if (err.status === 404 || detail.toLowerCase().includes('not found')) { return Response.json({ policy: '', updatedAt: null }); @@ -91,7 +91,7 @@ async function putPolicy(ctx: OfficerContext): Promise { // never blanks the editor. return Response.json({ policy: asText(saved.policy) || body.policy, updatedAt: asDate(saved.updatedAt) }); } catch (err) { - if (!(err instanceof HeadscaleError)) throw err; + if (!(err instanceof OffscaleError)) throw err; const detail = err.detail ?? err.message; if (isWriteDisabled(detail)) { diff --git a/sidecar/routes.ts b/sidecar/routes.ts index c939de7..ad99ae4 100644 --- a/sidecar/routes.ts +++ b/sidecar/routes.ts @@ -1,4 +1,4 @@ -import { HeadscaleError } from './client'; +import { OffscaleError } from './client'; import { handleServersRoute } from './servers'; import { handleNodesRoute } from './nodes'; import { handleUsersRoute } from './users'; @@ -74,7 +74,7 @@ export async function handleOfficerRoute(req: Request, url: URL): Promise { const { req, userId } = ctx; if (req.method === 'GET') { - return Response.json({ servers: await listHeadscaleServers(userId) }); + return Response.json({ servers: await listOffscaleServers(userId) }); } if (req.method === 'POST') { @@ -94,8 +94,8 @@ async function handleCollection(ctx: OfficerContext): Promise { if (validated instanceof Response) return validated; // First registration becomes active, so the owner is never left with servers but none selected. - const existing = await listHeadscaleServers(userId); - const server = await createHeadscaleServer({ + const existing = await listOffscaleServers(userId); + const server = await createOffscaleServer({ userId, name, url, @@ -115,13 +115,13 @@ async function handleOne(ctx: OfficerContext, id: number, action: string | undef if (action === 'activate') { if (req.method !== 'POST') return methodNotAllowed(); - const server = await setActiveHeadscaleServer(userId, id); + const server = await setActiveOffscaleServer(userId, id); return server ? Response.json({ server }) : notFound('no such server'); } if (action === 'health') { if (req.method !== 'GET') return methodNotAllowed(); - const creds = await getHeadscaleCredentials(userId, id); + const creds = await getOffscaleCredentials(userId, id); if (!creds) return notFound('no such server'); const started = Date.now(); @@ -132,11 +132,11 @@ async function handleOne(ctx: OfficerContext, id: number, action: string | undef try { await createClient(creds).call('/api/v1/apikey'); } catch (err) { - const message = err instanceof HeadscaleError ? err.message : 'upstream error'; + const message = err instanceof OffscaleError ? err.message : 'upstream error'; return Response.json({ ok: false, version: probe.version, error: message, ms: Date.now() - started }); } - await recordHeadscaleProbe(userId, id, probe.version); + await recordOffscaleProbe(userId, id, probe.version); return Response.json({ ok: true, version: probe.version, supported: probe.supported, ms: Date.now() - started }); } @@ -146,7 +146,7 @@ async function handleOne(ctx: OfficerContext, id: number, action: string | undef const body = (await req.json().catch(() => null)) as Record | null; if (!body) return badRequest('expected a JSON body'); - const current = await getHeadscaleCredentials(userId, id); + const current = await getOffscaleCredentials(userId, id); if (!current) return notFound('no such server'); let url: string | undefined; @@ -177,12 +177,12 @@ async function handleOne(ctx: OfficerContext, id: number, action: string | undef if (validated instanceof Response) return validated; } - const server = await updateHeadscaleServer(userId, id, { name, url, apiKey, sshHost }); + const server = await updateOffscaleServer(userId, id, { name, url, apiKey, sshHost }); return server ? Response.json({ server }) : notFound('no such server'); } if (req.method === 'DELETE') { - const deleted = await deleteHeadscaleServer(userId, id); + const deleted = await deleteOffscaleServer(userId, id); return deleted ? new Response(null, { status: 204 }) : notFound('no such server'); } diff --git a/sidecar/version.test.ts b/sidecar/version.test.ts new file mode 100644 index 0000000..d7c47da --- /dev/null +++ b/sidecar/version.test.ts @@ -0,0 +1,57 @@ +import { describe, expect, test } from 'bun:test'; +import { MIN_MAJOR, MIN_MINOR, MIN_VERSION_LABEL, meetsFloor, parseVersion } from './version'; + +// The version floor is the plugin's whole compatibility story: Headscale changed its admin API shape +// repeatedly below 0.29, so `meetsFloor` is what stops a server with an incompatible data model being +// registered at all. It has no I/O, so the interesting cases are cheap to pin down — and they were not +// pinned down at all until now. + +describe('parseVersion', () => { + test('reads major.minor from the shapes a server actually reports', () => { + expect(parseVersion('0.29.0')).toEqual({ major: 0, minor: 29 }); + expect(parseVersion('v0.29.0')).toEqual({ major: 0, minor: 29 }); + expect(parseVersion(' 0.30.1 ')).toEqual({ major: 0, minor: 30 }); + expect(parseVersion('1.0')).toEqual({ major: 1, minor: 0 }); + }); + + test("returns null for 'dev', which is what a self-built image reports", () => { + // Not an error case. probeVersion turns this into supported:'unknown' rather than a refusal, so that + // someone building Headscale from source is not locked out. If this ever returned a version, those + // servers would start being REJECTED — the failure would look like a compatibility bug. + expect(parseVersion('dev')).toBeNull(); + }); + + test('returns null rather than guessing at non-semver', () => { + expect(parseVersion('')).toBeNull(); + expect(parseVersion('unstable')).toBeNull(); + expect(parseVersion('.29')).toBeNull(); + }); +}); + +describe('meetsFloor', () => { + test('accepts the floor itself and anything above it', () => { + expect(meetsFloor({ major: MIN_MAJOR, minor: MIN_MINOR })).toBe(true); + expect(meetsFloor({ major: 0, minor: 30 })).toBe(true); + expect(meetsFloor({ major: 1, minor: 0 })).toBe(true); + }); + + test('refuses the releases whose API shape Officer cannot speak', () => { + // 0.26 moved identifiers name→numeric, 0.28 collapsed forcedTags/validTags. Supporting these would + // mean carrying several incompatible models, which is the cost the floor exists to avoid. + expect(meetsFloor({ major: 0, minor: 28 })).toBe(false); + expect(meetsFloor({ major: 0, minor: 26 })).toBe(false); + expect(meetsFloor({ major: 0, minor: 0 })).toBe(false); + }); + + test('a higher major wins regardless of minor — 1.0 is not below 0.29', () => { + // The bug this guards: comparing minor first makes 1.0 (minor 0) fail against a floor of 0.29, so the + // first stable Headscale release would be refused by the plugin as too old. + expect(meetsFloor({ major: 1, minor: 0 })).toBe(true); + }); + + test('the advertised label agrees with the numeric floor', () => { + // Two constants describing one fact. They drift silently otherwise: the label is what users are told + // to install, and the numbers are what actually gates them. + expect(MIN_VERSION_LABEL).toBe(`${MIN_MAJOR}.${MIN_MINOR}`); + }); +}); diff --git a/web/ConsoleView.tsx b/web/ConsoleView.tsx index fe932b9..333612a 100644 --- a/web/ConsoleView.tsx +++ b/web/ConsoleView.tsx @@ -1,8 +1,8 @@ import { useCallback } from 'react'; import { Link } from 'react-router'; import { Loader2, TerminalSquare } from 'lucide-react'; -import { headscaleSectionPath } from './shared'; -import { useHeadscaleServers } from './useHeadscaleServers'; +import { offscaleSectionPath } from './shared'; +import { useOffscaleServers } from './useOffscaleServers'; import { TerminalView } from 'officerdev'; import { Button } from './Cards'; @@ -31,7 +31,7 @@ const Centred = ({ children }: { children: React.ReactNode }) => ( ); export const ConsoleView = () => { - const { active, isLoading } = useHeadscaleServers(); + const { active, isLoading } = useOffscaleServers(); // The terminal reports its connection state; nothing in this section acts on it yet, but TerminalView wants // a stable callback and an inline arrow would remount its effect on every render. @@ -67,7 +67,7 @@ export const ConsoleView = () => { the Headscale hostname — the console is most useful exactly when that name has stopped answering.

- + diff --git a/web/DiagnosticsView.tsx b/web/DiagnosticsView.tsx index 9595d8c..2f534fb 100644 --- a/web/DiagnosticsView.tsx +++ b/web/DiagnosticsView.tsx @@ -13,13 +13,13 @@ import { } from 'lucide-react'; import type { CompanionAction, CompanionContainer, CompanionHealthBody, CompanionVerdict } from './shared'; import { timeAgo } from './format'; -import { useHeadscaleServers } from './useHeadscaleServers'; +import { useOffscaleServers } from './useOffscaleServers'; import { useCompanionAction, useCompanionHealth, useCompanionLogStream, useCompanionLogs, -} from './useHeadscaleCompanion'; +} from './useOffscaleCompanion'; import { Card, SectionHeader, Button, Dot, ErrorNote } from './Cards'; import { ViewShell } from './ViewShell'; @@ -261,7 +261,7 @@ const Lifecycle = ({ running }: { running: boolean | null }) => { }; export const DiagnosticsView = () => { - const { active } = useHeadscaleServers(); + const { active } = useOffscaleServers(); const query = useCompanionHealth(); const result = query.data; diff --git a/web/InvitesView.tsx b/web/InvitesView.tsx index 81ca3f5..7d218e5 100644 --- a/web/InvitesView.tsx +++ b/web/InvitesView.tsx @@ -1,11 +1,11 @@ import { useEffect, useRef, useState } from 'react'; import QRCode from 'qrcode'; import { Check, Copy, Loader2, Plus, QrCode, Share2, Smartphone, Trash2 } from 'lucide-react'; -import type { HeadscaleInvite, HeadscaleInviteCreated, InviteStatus } from './shared'; +import type { OffscaleInvite, OffscaleInviteCreated, InviteStatus } from './shared'; import { INVITE_TTL_DEFAULT_SECONDS } from './shared'; -import { useHeadscaleInvites } from './useHeadscaleInvites'; -import { useHeadscaleUsers } from './useHeadscaleData'; -import { headscaleErrorMessage } from './useHeadscaleServers'; +import { useOffscaleInvites } from './useOffscaleInvites'; +import { useOffscaleUsers } from './useOffscaleData'; +import { offscaleErrorMessage } from './useOffscaleServers'; import { fullDate, timeAgo, timeUntil } from './format'; import { Badge, Button, Card, Dot, ErrorNote, Field } from './Cards'; import { EmptyBody, ViewShell } from './ViewShell'; @@ -76,7 +76,7 @@ const InviteQr = ({ url }: { url: string }) => { return ; }; -type InviteLinkPanelProps = { invite: HeadscaleInviteCreated; onDismiss: () => void }; +type InviteLinkPanelProps = { invite: OffscaleInviteCreated; onDismiss: () => void }; const InviteLinkPanel = ({ invite, onDismiss }: InviteLinkPanelProps) => { const [showQr, setShowQr] = useState(true); @@ -138,11 +138,11 @@ const InviteLinkPanel = ({ invite, onDismiss }: InviteLinkPanelProps) => { ); }; -type CreateInviteFormProps = { onCreated: (invite: HeadscaleInviteCreated) => void; onClose: () => void }; +type CreateInviteFormProps = { onCreated: (invite: OffscaleInviteCreated) => void; onClose: () => void }; const CreateInviteForm = ({ onCreated, onClose }: CreateInviteFormProps) => { - const { users } = useHeadscaleUsers(); - const { create } = useHeadscaleInvites(); + const { users } = useOffscaleUsers(); + const { create } = useOffscaleInvites(); const [user, setUser] = useState(''); const [note, setNote] = useState(''); const [ttl, setTtl] = useState(INVITE_TTL_DEFAULT_SECONDS); @@ -171,7 +171,7 @@ const CreateInviteForm = ({ onCreated, onClose }: CreateInviteFormProps) => { onCreated(invite); onClose(); } catch (err) { - setError(headscaleErrorMessage(err)); + setError(offscaleErrorMessage(err)); } }; @@ -266,17 +266,17 @@ const CreateInviteForm = ({ onCreated, onClose }: CreateInviteFormProps) => { ); }; -type InviteRowProps = { invite: HeadscaleInvite; onError: (message: string) => void }; +type InviteRowProps = { invite: OffscaleInvite; onError: (message: string) => void }; const InviteRow = ({ invite, onError }: InviteRowProps) => { - const { revoke } = useHeadscaleInvites(); + const { revoke } = useOffscaleInvites(); const [confirming, setConfirming] = useState(false); const run = async () => { try { await revoke.mutateAsync(invite.id); } catch (err) { - onError(headscaleErrorMessage(err)); + onError(offscaleErrorMessage(err)); } }; @@ -338,9 +338,9 @@ const InviteRow = ({ invite, onError }: InviteRowProps) => { }; export const InvitesView = () => { - const { invites, unavailable, isLoading, error } = useHeadscaleInvites(); + const { invites, unavailable, isLoading, error } = useOffscaleInvites(); const [creating, setCreating] = useState(false); - const [created, setCreated] = useState(null); + const [created, setCreated] = useState(null); const [actionError, setActionError] = useState(null); const pending = invites.filter((i) => i.status === 'pending').length; diff --git a/web/KeysView.tsx b/web/KeysView.tsx index e3b25d2..098efd2 100644 --- a/web/KeysView.tsx +++ b/web/KeysView.tsx @@ -1,8 +1,8 @@ import { useState } from 'react'; import { KeyRound, Plus, Trash2, TimerOff, Copy, Check, Loader2, ShieldAlert } from 'lucide-react'; -import type { HeadscalePreAuthKey } from './shared'; -import { useHeadscaleKeys, useHeadscaleUsers } from './useHeadscaleData'; -import { useHeadscaleServers, headscaleErrorMessage } from './useHeadscaleServers'; +import type { OffscalePreAuthKey } from './shared'; +import { useOffscaleKeys, useOffscaleUsers } from './useOffscaleData'; +import { useOffscaleServers, offscaleErrorMessage } from './useOffscaleServers'; import { timeAgo, timeUntil, fullDate } from './format'; import { Card, Button, Field, Badge, Dot, ErrorNote } from './Cards'; import { ViewShell, EmptyBody } from './ViewShell'; @@ -102,8 +102,8 @@ const Toggle = ({ checked, onChange, label, hint }: ToggleProps) => ( type CreateKeyFormProps = { onCreated: (secret: string) => void; onClose: () => void }; const CreateKeyForm = ({ onCreated, onClose }: CreateKeyFormProps) => { - const { users } = useHeadscaleUsers(); - const { create } = useHeadscaleKeys(); + const { users } = useOffscaleUsers(); + const { create } = useOffscaleKeys(); const [userId, setUserId] = useState(''); const [reusable, setReusable] = useState(false); const [ephemeral, setEphemeral] = useState(false); @@ -133,7 +133,7 @@ const CreateKeyForm = ({ onCreated, onClose }: CreateKeyFormProps) => { if (result.key.key) onCreated(result.key.key); onClose(); } catch (err) { - setError(headscaleErrorMessage(err)); + setError(offscaleErrorMessage(err)); } }; @@ -203,10 +203,10 @@ const CreateKeyForm = ({ onCreated, onClose }: CreateKeyFormProps) => { ); }; -type KeyRowProps = { entry: HeadscalePreAuthKey; onError: (message: string) => void }; +type KeyRowProps = { entry: OffscalePreAuthKey; onError: (message: string) => void }; const KeyRow = ({ entry, onError }: KeyRowProps) => { - const { expire, remove } = useHeadscaleKeys(); + const { expire, remove } = useOffscaleKeys(); const [confirming, setConfirming] = useState(false); const busy = expire.isPending || remove.isPending; @@ -214,7 +214,7 @@ const KeyRow = ({ entry, onError }: KeyRowProps) => { try { await fn(); } catch (err) { - onError(headscaleErrorMessage(err)); + onError(offscaleErrorMessage(err)); } }; @@ -271,8 +271,8 @@ const KeyRow = ({ entry, onError }: KeyRowProps) => { }; export const KeysView = () => { - const { keys, isLoading, error } = useHeadscaleKeys(); - const { active } = useHeadscaleServers(); + const { keys, isLoading, error } = useOffscaleKeys(); + const { active } = useOffscaleServers(); const [creating, setCreating] = useState(false); const [secret, setSecret] = useState(null); const [filter, setFilter] = useState('active'); diff --git a/web/NodesView.tsx b/web/NodesView.tsx index bdbc479..8ccc1c2 100644 --- a/web/NodesView.tsx +++ b/web/NodesView.tsx @@ -14,9 +14,9 @@ import { ArrowRightLeft, Tag as TagIcon, } from 'lucide-react'; -import type { HeadscaleNode } from './shared'; -import { useHeadscaleNodes, useHeadscaleUsers } from './useHeadscaleData'; -import { headscaleErrorMessage } from './useHeadscaleServers'; +import type { OffscaleNode } from './shared'; +import { useOffscaleNodes, useOffscaleUsers } from './useOffscaleData'; +import { offscaleErrorMessage } from './useOffscaleServers'; import { timeAgo, timeUntil, fullDate } from './format'; import { Card, Button, Dot, Badge, ErrorNote } from './Cards'; import { ViewShell, EmptyBody } from './ViewShell'; @@ -72,7 +72,7 @@ const parseTags = (text: string): string[] => { /** Set comparison, not sequence: Headscale is free to store the tags in an order the owner didn't type. */ const sameTags = (a: string[], b: string[]) => a.length === b.length && a.every((t) => b.includes(t)); -type OwnershipProps = { node: HeadscaleNode; busy: boolean; onError: (message: string) => void }; +type OwnershipProps = { node: OffscaleNode; busy: boolean; onError: (message: string) => void }; /** * Owner and tags — the two things that decide which ACL rules apply to a node, which is why they sit @@ -83,8 +83,8 @@ type OwnershipProps = { node: HeadscaleNode; busy: boolean; onError: (message: s * shared with the Users section, so an expanded card is usually a cache hit anyway. */ const Ownership = ({ node, busy, onError }: OwnershipProps) => { - const { setTags, moveToUser } = useHeadscaleNodes(); - const { users } = useHeadscaleUsers(); + const { setTags, moveToUser } = useOffscaleNodes(); + const { users } = useOffscaleUsers(); const [owner, setOwner] = useState(node.user?.id ?? ''); const [draftTags, setDraftTags] = useState(node.tags.join(' ')); @@ -99,7 +99,7 @@ const Ownership = ({ node, busy, onError }: OwnershipProps) => { try { await fn(); } catch (err) { - onError(headscaleErrorMessage(err)); + onError(offscaleErrorMessage(err)); } }; @@ -185,10 +185,10 @@ const Ownership = ({ node, busy, onError }: OwnershipProps) => { ); }; -type NodeCardProps = { node: HeadscaleNode; onError: (message: string) => void }; +type NodeCardProps = { node: OffscaleNode; onError: (message: string) => void }; const NodeCard = ({ node, onError }: NodeCardProps) => { - const { rename, toggleRoute, expire, remove } = useHeadscaleNodes(); + const { rename, toggleRoute, expire, remove } = useOffscaleNodes(); const [open, setOpen] = useState(false); const [renaming, setRenaming] = useState(false); const [draftName, setDraftName] = useState(node.name); @@ -200,7 +200,7 @@ const NodeCard = ({ node, onError }: NodeCardProps) => { try { await fn(); } catch (err) { - onError(headscaleErrorMessage(err)); + onError(offscaleErrorMessage(err)); } }; @@ -373,7 +373,7 @@ const NodeCard = ({ node, onError }: NodeCardProps) => { }; export const NodesView = () => { - const { nodes, isLoading, error } = useHeadscaleNodes(); + const { nodes, isLoading, error } = useOffscaleNodes(); const [filter, setFilter] = useState(''); const [actionError, setActionError] = useState(null); diff --git a/web/HeadscaleNav.tsx b/web/OffscaleNav.tsx similarity index 83% rename from web/HeadscaleNav.tsx rename to web/OffscaleNav.tsx index 2e14b31..9a29d22 100644 --- a/web/HeadscaleNav.tsx +++ b/web/OffscaleNav.tsx @@ -1,17 +1,17 @@ import type { LucideIcon } from 'lucide-react'; import { NavLink } from 'react-router'; import { Server, Laptop, Users, KeyRound, Smartphone, ShieldCheck, Activity, TerminalSquare } from 'lucide-react'; -import { HEADSCALE_SECTIONS, headscaleSectionPath, type HeadscaleSectionId } from './shared'; -import { useHeadscaleServers } from './useHeadscaleServers'; +import { OFFSCALE_SECTIONS, offscaleSectionPath, type OffscaleSectionId } from './shared'; +import { useOffscaleServers } from './useOffscaleServers'; // Lower-left panel of the /headscale workspace: the section list. Which server it all acts on is the panel -// above (HeadscaleServerPicker) — that one mutates, this one navigates, which is why they are separate. +// above (OffscaleServerPicker) — that one mutates, this one navigates, which is why they are separate. // // Sections are real links to /headscale/
, not channel writes — so they cmd-click into a new tab, // survive a reload, and answer the back button. Active state comes from react-router's NavLink rather than // being derived in JS, per the navigation audit's Phase 4. -const ICONS: Record = { +const ICONS: Record = { servers: Server, nodes: Laptop, users: Users, @@ -36,13 +36,13 @@ const SectionBody = ({ icon: Icon, label, selected }: SectionBodyProps) => ( ); -export const HeadscaleNav = () => { - const { active } = useHeadscaleServers(); +export const OffscaleNav = () => { + const { active } = useOffscaleServers(); return (