carlos / platform Public

Sidecars can't bind their own config environment (bot secrets leak into the app's instance) open

🤖 From: Eleven's move onto Carloku. Its bot sidecar runs as a native sidecar member on the proving app (account bdr). Moved here from GitHub #425, which was opened there by mistake.

The gap. SidecarRecord has an Environment field, and sidecarRouteFor carries it onto the route. But no door can set it:

  • carlos sidecars create takes only -region and -channel.
  • The console's create body (internal/console/apisidecars.go) decodes only name, region and channel.
  • instances set-environment works on instances only.

So a sidecar reads the app's default bundle, which is the same bundle the app's instance (the chat server) reads.

Why it matters for Eleven. The bot holds the ANTHROPIC_API_KEY and the bots' one-time invites. The chat server process must never hold either. This is load-bearing in Eleven's E2EE model: "bot code never runs inside the server process", and compromising the server must not yield bot keys. Named bundles don't help from the instance side, because LoadMerged overlays a named bundle on top of the default.

It also limits an app to one bot sidecar in practice: each space's bot needs its own LCHAT_BASE.

Asked: -environment <e> on carlos sidecars create, plus the console body field, plus a set-environment for an existing sidecar. Related, but a different case: #305, per-instance values from the provisioning credential.

Today: Eleven's ops carloku bots refuses ANTHROPIC_API_KEY and refuses apps with more than one space, so the bots run on the deterministic command floor only. Verified live on 2026-10-21: the sidecar adopted its release and both identities connected.

🤖 Branch sidecar-environment (61b926da) implements this. The branch description could not be set from here: this CLI build refuses branch describe without a session block. Here is the description:

🤖 What: carlos sidecars create -environment <e> (plus the console's create body) binds a sidecar to a named config environment instead of the app's default bundle. Closes the gap in discussion #340.

Why: a sidecar used to read the app's default bundle, which is the same bundle the app's instances read. So a secret that the sidecar needs, and that the app's server must never hold, had nowhere to live. The motivating case is Eleven's bot sidecar, which holds an ANTHROPIC_API_KEY and one-time invites; the chat server must never see them. sidecarRouteFor already carried Record.Environment onto the route, and config delivery already keys on it. Only the doors (console + CLI) were missing.

Changes:

  • internal/console/apisidecars.go: the create body takes environment and stamps it on the record.
  • internal/provision/sidecar.go: ValidateSidecarShape checks the environment name, using the instance record's [a-z0-9-]{1,32} rule.
  • sidecars_cli.go / apimode.go: a -environment flag and usage text, and the "created" line names the binding.
  • Tests: TestAPISidecarCreateBindsAnEnvironment (named, blank, omitted, traversal refused) and an extended shape test.

Authority: the same binding power an instance create already has (instanceGateFor). The sidecar still runs only the app's own release with the manifest's argv.

Census (needs a ruling):

  • Record-write census: handleAPISidecarCreate's digest is re-pinned. It is still the single create-only CreateSidecarRecord write; the record now also carries Environment.
  • Plan 14: a PROPOSED envelope-only overlay, plan14-root-reads-sidecar-environment.tsv, loaded last. It re-pins the root, internal/console and internal/provision envelopes. No root-read unit changed and the seal stands. This awaits the Plan 14 owner's ruling: re-word it to a ruling marker, or reject it.

Tested:

  • Locally on macOS, the sidecar, provision and root tests pass.
  • Some console tests and the Plan 14 census also fail on unchanged main locally, so they are unrelated: - the hostops-contract tests; - the case-insensitive filesystem test; - 6682 local-only census discrepancies. This branch adds none beyond base.
  • Linux CI is the gate.

Follow-up, not in this branch: set-environment for an existing sidecar.

Do not merge until the census overlay is ruled.