Skip to content

v0.15.0 — run it as a service, and answer only to a credential

Choose a tag to compare

@gmpassos gmpassos released this 14 Jul 22:09
d8dd29c

Two things a Hub needs before you can walk away from it: something to keep it running, and the habit of asking who is calling.

omnyserver service install hub  --tls-dir /etc/letsencrypt/live/hub.example.com
omnyserver service install node --hub wss://hub:8443 --id worker-01 --token …
omnyserver service status hub

Fixed — the HTTP API was unauthenticated without --api-token

If you run a Hub without --api-token, upgrade.

HttpApiServer.tokenAuthenticator() returned null when no API token was configured, and a service registered with a null authenticator is not authenticated at all. A Hub started with grants but no API token — a reasonable thing to do, since --grant is what the flag exists for — served the whole API to anyone who could reach the port:

$ omnyserver hub start --cert … --key … --grant alice:tok:admin   # no --api-token
$ curl -k https://hub:8443/api/v1/nodes                           # no credentials at all
[]  200

List the fleet, read the audit log, run formulas on every node, issue credentials. --grant looked like it secured the API and did not: grants are only ever consulted from inside the authenticator that was not there, which is why whoami answered {"principal":"anonymous","authenticated":false} even when handed a valid grant token. doc/security.md described this as a feature — "for a loopback-only Hub" — but nothing enforced loopback and the Hub binds 0.0.0.0 by default.

The Hub is controlled with the --api-token, or with a grant's (principal, token) pair, and with nothing else. It now enforces that whether or not an API token is set. A Hub with neither authenticates nobody rather than everybody, and says so at startup instead of looking healthy while answering no one.

/healthz and /metrics stay open on purpose: a load balancer and a Prometheus scraper carry no bearer token, and gating them would make the Hub look dead to the things that check whether it is alive. Neither exposes fleet data.

Anyone relying on the old behaviour was relying on an open API. Pass --api-token, or authenticate with a grant (--token + --principal).

Added — omnyserver service …

hub start runs in the foreground and dies with your terminal, which is fine right up until it is the thing your fleet talks to. The new service command group installs the Hub or a Node agent as a native OS service — a systemd unit on Linux, a launchd job on macOS, a scheduled task on Windows — so it starts at boot and comes back if it falls over.

There is no separate daemon and no config file, because the CLI installs itself. service install takes the same flags as hub start / node start, reconstructs the command line, and bakes this executable plus those flags into the service definition. What the service runs at boot is what you would have typed. Paths are absolutized on the way in, so the unit does not care which directory you installed from.

Nine verbs: install, reinstall, reconfigure, uninstall, start, stop, restart, status, info. --dry-run prints the generated unit or plist without touching the system; --system installs machine-wide. service reconfigure re-applies changed flags to a running service, and service reinstall refreshes the binary while keeping the config it was installed with — how a fleet picks up a new release.

Also new: --cors-origin '*', which used to be accepted and then silently match nothing, since it was compared as a literal origin string. It is a real widening — any page may call the API — but not an open door: the Hub sends no allow-credentials, so a browser attaches nothing ambient and a caller still needs a token it was given. The Hub says so at startup.

Changed — hub start now persists by default

To <OMNYSERVER_HOME>/hub, i.e. ~/.omnyserver/hub. It used to keep everything in memory unless you passed --data-dir. --ephemeral opts out.

A Hub with optional persistence silently forgets the fleet, the audit trail, and every credential grant add ever issued — on every restart. Survivable when you are watching it in a terminal. Supervised by an init system, with Restart=always, it is a trap: the Hub comes back up empty and healthy.

An explicit --data-dir still means what it always meant; only the default moved. HubConfig(dataDir: null) is untouched, so the Dart API still defaults to in-memory — this is a CLI default, not a library one.

Full notes: CHANGELOG.md