headscale is core, so stop offering to install it
Reported as: the routes are unreachable and there is no dock tile, on a server where officer-headscale is up and healthy. Both symptoms, one cause. Availability is derived ONLY from the sidecar_installs table — `usable` is the rows with status='installed' AND enabled, and every capability mapped to a sidecar outside that set is added to `unavailable`. A CORE sidecar never gets a row there, because core processes are started by pm2 from the generated ecosystem file and never go through the app store. So `headscale` and `vpn` were permanently unavailable, which withheld the dock manifest AND put /headscale into deniedRoutes for the route guard. The design already knew. catalogue.test.ts has a test called "does not offer to install the baseline", and it has been FAILING since headscale was promoted: Expected to not contain: "officer-headscale" docs/secret-store.md predicted it in as many words — "moving headscale into the light profile also removes it from the app store automatically: catalogue.test.ts asserts the catalogue equals full − light, so the test fails until the entry is deleted". The entry was never deleted, and the failing test was never read. So: entry removed, and the tile moved to CORE_DOCK_ITEMS, where the other things that are always present live. DashboardLayout filters every tile through canVisit(), so a member still never sees it — the capability is kind: 'admin'. The entry's existingFields (URL + API key) are not lost. Servers are added from the Servers view inside the app — ServersView.tsx, ServerForm.tsx, useHeadscaleServers.ts — which is where they were really configured; the app-store form was a second place to type the same two values. Verified: catalogue.test.ts 19 pass/1 fail → 20 pass/0 fail, tsgo clean. PRE-EXISTING, not touched: 10 other tests fail on master, 8 of them in src/servers/capabilities. Confirmed identical before and after this change by stashing it and re-running. Worth a look but not this change's business. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -174,6 +174,10 @@ export const CORE_DOCK_ITEMS: DockItem[] = [
|
|||||||
{ label: 'Monitor', to: '/system-monitor', icon: Activity, color: '#0ea5e9' },
|
{ label: 'Monitor', to: '/system-monitor', icon: Activity, color: '#0ea5e9' },
|
||||||
{ label: 'Activity', to: '/activity', icon: Radio, color: '#f59e0b' },
|
{ label: 'Activity', to: '/activity', icon: Radio, color: '#f59e0b' },
|
||||||
{ label: 'Dashboards', to: '/dashboards', icon: LayoutGrid, color: '#8b5cf6' },
|
{ label: 'Dashboards', to: '/dashboards', icon: LayoutGrid, color: '#8b5cf6' },
|
||||||
|
// Core because the tailnet is the perimeter — origin checking was removed on the grounds that the
|
||||||
|
// tailnet stands in its place, so administering it cannot be an optional extra. It is `kind: 'admin'`,
|
||||||
|
// and DashboardLayout filters every tile through canVisit(), so a member never sees this one.
|
||||||
|
{ label: 'Headscale', to: '/headscale', icon: Network, color: '#818cf8' },
|
||||||
// Core by necessity: the store is how every other feature arrives, so it can never be one of the
|
// Core by necessity: the store is how every other feature arrives, so it can never be one of the
|
||||||
// things that disappears when uninstalled.
|
// things that disappears when uninstalled.
|
||||||
{ label: 'App store', to: '/app-store', icon: Store, color: '#64748b' },
|
{ label: 'App store', to: '/app-store', icon: Store, color: '#64748b' },
|
||||||
|
|||||||
@@ -359,22 +359,18 @@ export const CATALOGUE: CatalogueEntry[] = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
// Headscale was here until 2026-08-14 and is CORE now — `officer-headscale` runs in the baseline
|
||||||
id: 'headscale',
|
// profile, so it is not something you install, and `catalogue.test.ts` had been failing on exactly
|
||||||
ui: { name: 'Headscale', icon: 'Network', color: '#818cf8', rootRoute: '/headscale', routes: ['/headscale'] },
|
// that ("does not offer to install the baseline") since it was promoted.
|
||||||
process: 'officer-headscale',
|
//
|
||||||
label: 'Headscale',
|
// Leaving it here did more than fail a test. Availability is derived ONLY from `sidecar_installs`,
|
||||||
summary: 'Your own tailnet control plane',
|
// and a core sidecar never gets a row there — so `headscale` and `vpn` were permanently `unavailable`,
|
||||||
members: 'none',
|
// which withheld the dock manifest AND put /headscale into `deniedRoutes`. The screen was unreachable
|
||||||
modes: ['existing'],
|
// and invisible on a server where the sidecar was up and healthy.
|
||||||
capability: 'headscale',
|
//
|
||||||
// A member enrolling their own device is the same sidecar. See `alsoServes`.
|
// Its tile is in CORE_DOCK_ITEMS instead, and servers are configured where they always really were —
|
||||||
alsoServes: ['vpn'],
|
// the Servers view inside the app, which is why the `existingFields` here were a redundant second
|
||||||
existingFields: [
|
// place to type the same URL and API key.
|
||||||
{ key: 'url', label: 'Headscale URL', type: 'url', required: true },
|
|
||||||
{ key: 'secret', label: 'API key', type: 'secret', required: true },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
|
|
||||||
// ── Nothing to reach: configuration only ───────────────────────────────────────────────────────────
|
// ── Nothing to reach: configuration only ───────────────────────────────────────────────────────────
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user