In-dashboard terminal
MajNet gives operators a real terminal in the browser: exec into a running app
container, or open a root shell on a node. It’s the one deliberate exception to
“everything goes through git” — a restart-class imperative action — so it’s
gated, attributed, and fully recorded.
Opening a session
Section titled “Opening a session”- Container exec — from an app’s page, Exec opens a shell in that app’s running container (app containers only; the control-plane and database containers are off-limits).
- Host shell — from Nodes, Open shell drops you into a root shell on
the node itself (via a privileged,
--pid=hosthelper that MajNet pulls on demand and reaps when the session ends).
Both are platform-admin only.
Guardrails
Section titled “Guardrails”- Named admin, always attributed. The terminal never accepts the header-less “infra” fallback the rest of the API allows — it requires a resolved human admin, so every session has a name attached.
- Full transcript. Input and output are recorded per session and surfaced in the Activity feed, alongside an open/close event. Transcripts can contain secrets, so they’re platform-admin-read-only.
- Production is guarded. Targeting a production-zone node or container requires a typed confirmation and shows a persistent warning banner.
Reaching the dashboard
Section titled “Reaching the dashboard”The dashboard is tailnet-only — there are two front doors, and identity is established differently on each:
http://majksa— served bytailscale serve, which injects your Tailscale identity natively (including on the terminal’s WebSocket). Works out of the box.dash.majksa.net— the HTTPS edge (Caddy). It resolves your identity by asking the bot’s/tsauth, which needs the Tailnet identity credential below. Until that’s set, the terminal works onhttp://majksabut not here.
Tailnet identity
Section titled “Tailnet identity”To resolve who you are on the dash.majksa.net edge, the bot needs read access
to your tailnet’s device list. Configure it in Settings → Tailnet identity
(platform-admin):
- In the Tailscale admin console, create an OAuth client (not an access
token) with the
devices:readscope. - Paste the client ID and secret into Settings, Save, then Verify identity — it resolves your login live to confirm the credential works.
The OAuth client secret is long-lived; the bot mints short-lived API tokens from it on demand, so nothing needs manual rotation. The credential lives with the bot (the only component that talks to Tailscale) and is never exposed by the API.
Tailnet ACL management
Section titled “Tailnet ACL management”MajNet can also manage your tailnet’s access policy — rendering it from
people.yaml and project membership — but this is opt-in and off by default
(Settings → Tailnet identity → “Let MajNet manage the tailnet ACL”).
Leave it off unless you run a tagged tailnet and want MajNet to own the
policy: when on, it overwrites your entire ACL with a generated tag-based one
(tag:main, tag:proj-*), which would lock out an untagged or
manually-managed tailnet. Enabling it also requires policy_file:write on the
OAuth client — the devices:read client used for identity alone can never touch
your ACL.