the environment has no read-side coordinate — so a legacy box gets to name OUR environments #17

Closed
opened 2026-07-13 18:03:59 +00:00 by dan-claude-bot · 0 comments
dan-claude-bot commented 2026-07-13 18:03:59 +00:00 (Migrated from github.com)

The gap

--project exists because a hand-built Coolify project is "called whatever
someone typed", and cast must be pointed at the real name rather than guess.
The environment has exactly the same problem and no flag.

cast names the Coolify environment after --env. But --env is our name for
the environment — it selects the manifest block, the environments.yaml entry,
the secret store path (secrets/<repo>.<env>.env.age), and the age recipient.
On a hand-built source box, the Coolify environment is called whatever Coolify
defaulted to — which is production, not prod.

So reading a legacy box forces a choice between two bad options:

  1. Rename the environment in the source box's UI — a mutation on a live box
    you may not own, to satisfy a tool that is only reading it.
  2. Rename our own environment to match the legacy box.

Option 2 is what actually happened here, and it is worth spelling out because it
looks harmless and isn't: prod was renamed to production across the manifest
and environments.yaml — so a hand-built box that is being deleted next week
got to name the environment of the brand-new box forever (cast names the
environment after --env, so apply would have created it as production), and
it silently moved the secret store to secrets/incubator.production.env.age and
invalidated every --env prod in the runbooks. It was reverted.

The general shape of the bug: cast's own principle is that a live box never
gets to define desired state — but with no read-side coordinate for the
environment, the only way to read a legacy box is to let it define one.

Proposal

Add a read-side environment coordinate, exactly parallel to --project:

--environment <name>   the Coolify environment to act on, when it is not named
                       after --env (the default). A box built by hand in the UI
                       has whatever Coolify defaulted to — usually `production`.
  • --env keeps meaning our environment: manifest block, environments.yaml
    entry, store path, recipient, team assert.
  • --environment means their name for it on the wire.
  • Absent, it defaults to --env, so nothing changes for boxes cast built.
  • The absent-environment refusal from #12/D-237 stays exactly as it is — it
    should now also name this flag in its message, the way the absent-project
    refusal names --project.

Most valuable on diff and capture (the read verbs — the ones you point at a
box you did not build). Harmless and consistent on apply.

Acceptance

  • cast capture <slug> --env prod --environment production --instance box-b
    reads the source's production environment and writes
    secrets/<repo>.prod.env.ageour name on our side of the line, theirs
    on theirs.
  • With no --environment, behavior is unchanged.
  • The absent-environment refusal names --environment as the fix.
## The gap `--project` exists because a hand-built Coolify project is "called whatever someone typed", and cast must be pointed at the real name rather than guess. **The environment has exactly the same problem and no flag.** cast names the Coolify environment after `--env`. But `--env` is *our* name for the environment — it selects the manifest block, the `environments.yaml` entry, the secret store path (`secrets/<repo>.<env>.env.age`), and the age recipient. On a hand-built source box, the Coolify environment is called whatever Coolify defaulted to — which is **`production`**, not `prod`. So reading a legacy box forces a choice between two bad options: 1. **Rename the environment in the source box's UI** — a mutation on a live box you may not own, to satisfy a tool that is only *reading* it. 2. **Rename our own environment to match the legacy box.** Option 2 is what actually happened here, and it is worth spelling out because it looks harmless and isn't: `prod` was renamed to `production` across the manifest and `environments.yaml` — so a **hand-built box that is being deleted next week** got to name the environment of the brand-new box **forever** (cast names the environment after `--env`, so `apply` would have created it as `production`), and it silently moved the secret store to `secrets/incubator.production.env.age` and invalidated every `--env prod` in the runbooks. It was reverted. The general shape of the bug: **cast's own principle is that a live box never gets to define desired state — but with no read-side coordinate for the environment, the only way to read a legacy box is to let it define one.** ## Proposal Add a read-side environment coordinate, exactly parallel to `--project`: ``` --environment <name> the Coolify environment to act on, when it is not named after --env (the default). A box built by hand in the UI has whatever Coolify defaulted to — usually `production`. ``` - `--env` keeps meaning *our* environment: manifest block, `environments.yaml` entry, store path, recipient, team assert. - `--environment` means *their* name for it on the wire. - Absent, it defaults to `--env`, so nothing changes for boxes cast built. - The absent-environment refusal from #12/D-237 stays exactly as it is — it should now also **name this flag** in its message, the way the absent-project refusal names `--project`. Most valuable on `diff` and `capture` (the read verbs — the ones you point at a box you did not build). Harmless and consistent on `apply`. ## Acceptance - `cast capture <slug> --env prod --environment production --instance box-b` reads the source's `production` environment and writes `secrets/<repo>.prod.env.age` — **our** name on our side of the line, theirs on theirs. - With no `--environment`, behavior is unchanged. - The absent-environment refusal names `--environment` as the fix.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: heavy-duty/cast#17
No description provided.