v0.4.1 · disposable previews · mesh isolation · bucket websites Agents ship · humans inspect
← Engineering log

Routes compose: app paths and public bucket assets

A route now owns one host and composes app and bucket-backed paths as named attachments, while bucket public reads stay an explicit, read-only addon policy.

A real site is rarely one backend. The app serves the pages, a bucket serves the static assets, and both want to live under one hostname. Mechanics 0.3.36 makes that composition first-class: a route owns the host and TLS identity, and named attachments map path prefixes to app instances or bucket addon prefixes.

one host, two backends

ssh -T mechanics.run -- route create web --app myapp
ssh -T mechanics.run -- route attach assets --route web \
  --path /assets --bucket media --prefix site/
ssh -T mechanics.run -- addon -a media public-read add site/
ssh -T mechanics.run -- route wait web
ssh -T mechanics.run -- route check web

Attachments, not route sprawl

route create manages the reserved root attachment. route attach and route detach manage the rest. Each attachment renders its own HTTPRoute file in the gitops repo, paths must be absolute and non-overlapping, and route wait and route info aggregate readiness across every declared attachment. A route is not ready while any of its paths is missing or pointing at an unhealthy backend.

Bucket paths are read-only plumbing

A bucket attachment forwards only GET and HEAD, rewrites to path-style S3 under the workspace-prefixed bucket, and terminates at a separate read-only S3 gateway. Wiring a path to a bucket does not make objects public: anonymous reads are a separate, explicit bucket policy managed with addon -a <bucket> public-read list|add|remove, which grants only s3:GetObject on the listed prefixes, never listing, writes, or IAM actions.

Buckets stopped sharing identities

The groundwork landed in 0.3.35: every bucket addon now uses a workspace-scoped IAM identity derived from the workspace-prefixed bucket name. Two workspaces can create the same addon name without colliding on a principal, cross-workspace S3 access returns AccessDenied, and the public endpoint at s3.mechanics.run is backed by a read-only gateway that denies unauthenticated writes instead of falling back to permissive behavior.

The host belongs to the route, the paths belong to attachments, and public reads stay a policy you can point at.