cast/test
claude-hdb e457261436 feat: select the Coolify instance by name instead of editing .coolify.env (#14)
loadConfig read exactly one COOLIFY_BASE_URL + COOLIFY_ACCESS_TOKEN from
<state>/.coolify.env, with no flag or env override: the connection target was
implicit in a file's current contents. Retargeting cast meant hand-editing a
live credential file — and putting it back afterwards. The failure mode of
getting that wrong is running `apply` against production.

That is not hypothetical during the prod migration (incubator D-193): the
state repo's .coolify.env holds a write+deploy token for the NEW control
plane, while the verification gate needs a --full diff against the legacy,
hand-built box still serving live users.

- Named instances: <state>/.coolify/<name>.env, each with its own base URL
  and token. --instance <name> on every verb that reaches Coolify.
- environments.yaml may bind one per environment (`instance: prod-cp`), so
  --env selects the right control plane with no flag and no file edit at all.
  An explicit --instance still wins, so a one-off read against a legacy box
  needs no change to that file either.
- Refuse, don't guess, on an unknown --instance — naming the instances that
  do exist, in the same spirit as the absent-target refusal (#12/D-237).
  Falling back to the default here is exactly how a diff meant for a legacy
  box gets run against production.
- An instance may declare COOLIFY_READ_ONLY=true; apply, smoke and server add
  then refuse it before their first call, even though the token itself would
  permit the writes. "I pointed the wrong token at the wrong box" becomes an
  exit code rather than a live incident.
- Every command that reaches a Coolify now SAYS which one, next to the team
  assert. It is the most consequential input and the least visible one.

With no --instance and no binding, behavior is byte-for-byte what it was.

The CLI tests spawn cast against stub Coolifys that record what they were
asked, so "which instance did it actually talk to" is answered from the wire
rather than from cast's own console output.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 16:42:45 +00:00
..
fixtures feat: assert the token's team before touching Coolify (fail-closed) 2026-07-12 20:55:04 +00:00
apply.test.ts feat: cast — the Coolify executor, extracted from the infra state repo 2026-07-11 12:25:44 +00:00
bindings.test.ts fix: diff refuses an absent target instead of reporting it as empty (#11, #6) 2026-07-13 14:52:38 +00:00
cli.test.ts feat: select the Coolify instance by name instead of editing .coolify.env (#14) 2026-07-13 16:42:45 +00:00
config.test.ts feat: select the Coolify instance by name instead of editing .coolify.env (#14) 2026-07-13 16:42:45 +00:00
coolify.test.ts feat: assert the token's team before touching Coolify (fail-closed) 2026-07-12 20:55:04 +00:00
diff.test.ts feat: cast — the Coolify executor, extracted from the infra state repo 2026-07-11 12:25:44 +00:00
envtemplate.test.ts feat: cast — the Coolify executor, extracted from the infra state repo 2026-07-11 12:25:44 +00:00
live-lookup.test.ts fix: diff refuses an absent target instead of reporting it as empty (#11, #6) 2026-07-13 14:52:38 +00:00
manifest.test.ts feat: assert the token's team before touching Coolify (fail-closed) 2026-07-12 20:55:04 +00:00
resolve.test.ts fix: authenticate clones via gh / token, never fall into git's prompt (#13) 2026-07-13 16:30:04 +00:00
secrets.test.ts feat: cast — the Coolify executor, extracted from the infra state repo 2026-07-11 12:25:44 +00:00
smoke.test.ts feat: cast — the Coolify executor, extracted from the infra state repo 2026-07-11 12:25:44 +00:00
team.test.ts feat: assert the token's team before touching Coolify (fail-closed) 2026-07-12 20:55:04 +00:00
wire.test.ts feat: cast — the Coolify executor, extracted from the infra state repo 2026-07-11 12:25:44 +00:00