v0.2.0
Dashboard and observability release. Adds a local HTTP control plane with a web dashboard, live log and event streaming, a restart workflow, a bundled OpenTelemetry collector, orchestrator self-tracing and Prometheus metrics. Ships two new published crates and a round of network-surface hardening.
Added
- New crate
lightshuttle-control(#43): the local HTTP control plane and dashboard, served on127.0.0.1.LifecycleHandletrait andManagerHandleadapter exposing the running stack without leaking runtime types (#44).- HTTP control server wired into
upwith aGET /healthzprobe (#45). - REST API
GET /api/resourcesandGET /api/resources/{name}(#46). - WebSocket log streaming on
GET /ws/logs/{name}(#47). POST /api/resources/{name}/restartplus aGET /ws/eventslifecycle event stream (#49).- Server-side rendered dashboard built with Askama and HTMX, with an embedded stylesheet and HTMX bundle (#50).
- New crate
lightshuttle-otel(#51): bundles theotel/opentelemetry-collectorcontainer, injects the standardOTEL_*environment variables into resources and exposes anobservability.otelmanifest section.- Orchestrator self-tracing over OTLP and a Prometheus
/metricsendpoint on the dashboard server (#52).
- Orchestrator self-tracing over OTLP and a Prometheus
restart_onelifecycle primitive onLifecycleManager, with three ordered lifecycle events (#48).lightshuttle restart <resource>CLI command that follows lifecycle events to completion, with a--detachflag (#49).lightshuttle aliascommand (install/check/uninstall) that manages the optionallshshell alias: detects bash, zsh, fish and PowerShell, refuses to shadow a conflictinglshon the PATH, and edits the startup file idempotently (#40).- Optional
dashboard.portmanifest field (#45).
Changed
- Dependency upgrades:
bollard0.18 to 0.21,schemars0.8 to 1,jsonschema0.17 to 0.46;axumgains thewsfeature (#64). The generated JSON Schema now targets draft 2020-12. - The lifecycle event channel moved from
mpsctobroadcastso multiple consumers (dashboard, CLI, metrics) can subscribe;LifecycleEventgainedserde::Serialize. LifecycleError::UnknownResourcewas renamed toLifecycleError::ResourceNotFound.
Security
- Published ports now bind to
127.0.0.1by default instead of0.0.0.0, so managed services are not exposed to the wider network; a broader bind requires an explicitaddress:host:containermapping (#65). - Generated resource passwords now use a cryptographically secure random source (#66).
- The control plane sets baseline security headers (
X-Content-Type-Options,X-Frame-Options) and a same-origin Content Security Policy (#73). - The
restartclient validates that.lightshuttle/control.urlpoints at a loopback address (parsed, not prefix matched) and disables HTTP redirects (#72).
Fixed
- Starting a resource now removes any container left over from a previous run before recreating it, so a second
upor arestartno longer fails with a name conflict (#82). - Container log chunks now carry the Docker emission timestamp instead of the read time, and the timestamp prefix is stripped from the forwarded bytes (#68).
augment_manifestno longer overwrites a user resource namedlightshuttle_otel(#67).- The tracing subscriber is installed with
try_init, returning an error instead of panicking on a double install (#69). - The metrics pump no longer leaks a pending entry when a resource fails before becoming healthy (#71).
- The bundled collector healthcheck no longer always reports healthy; a crash now surfaces through the container exit status (#70).
- Database identifier length is bounded to the PostgreSQL 63 byte limit (#75).
- Interpolation references inside
commandandhealthcheck.testare now validated statically (#76).
Documentation
docs/spec/control-api.md(REST and WebSocket surface),docs/spec/observability.md(spans and metrics) anddocs/tutorial/dashboard.md(dashboard walkthrough).
Notes for upgraders
- Two new crates are published:
lightshuttle-controlandlightshuttle-otel. - Managed services now bind to loopback by default. Use the explicit
address:host:containerport form to expose a service on another interface. LifecycleError::UnknownResourceis nowLifecycleError::ResourceNotFound. This is a breaking change for direct consumers oflightshuttle-runtime.