Expand description
gtc op env apply — declarative, upsert-only environment apply
(PR-1 + PR-2 of plans/env-manifest-apply.md).
Consumes a greentic.env-manifest.v1 document (via the standard
--answers <PATH> payload convention) and reconciles the environment
toward it: validate → diff → plan → execute → verify.
- Upsert-only: resources in the store but absent from the manifest are left untouched. No pruning, no deletes (v1 decision).
- Wiring only: the manifest starts at “artifacts exist” — no pack or bundle building.
- Safe re-run: a second apply of an unchanged manifest is a visible no-op; a re-run after a partial failure completes the remainder (fail-fast, no rollback — every composed verb leaves the store valid, so the store itself is the checkpoint).
- Cross-step references resolve in-process:
add-endpointreturns the store-assignedendpoint_id, which the subsequentlink-endpoint/set-welcome-flowsteps consume — no output-capture plumbing. - Deterministic idempotency keys: derived from
(schema, env, step kind, natural key, desired-state hash)so a re-run replays instead of double-mutating (HTTP-store dedupe compatible). Exceptions:deploy’s traffic cut-over key intentionally stays per-revision-derived (a re-stage is by definition a new cut-over);put-secretcarries no deterministic key (an always-put is by definition a new write — a value-insensitive key would conflate rotations in audit and break A8 same-key-different-body semantics;secrets::putmints a fresh per-invocation key). - Store-level verify only: runtime readiness (secrets resolvable by
the reader, routes served) is
gtc doctor’s job — apply must work without a running runtime. --check(CI convergence gate): validate + diff + plan, never mutate; exit non-zero when diffable changes are pending. Always-put secret rows are excluded from the verdict (values cannot be diffed until A9) and reported underundiffableinstead.- Missing-inputs contract: an unset
from_envvariable or an absentbundle_pathartifact is collected (not fail-fast) and reported undermissingin the JSON report, so one run surfaces every gap. Mutating apply refuses to execute while any remain; on a TTY, missing secret values are prompted for (masked, in-memory only).--non-interactivenever prompts and implies--yes;--dry-runand--checkreport missing inputs without failing on them (--checkexcludes them from the convergence verdict — CI gates must be runnable without holding credentials).
The --emit-answers-template <path> shortcut writes a skeleton manifest
to start from — it is dispatched as a peer verb mode
(emit_answers_template) before the apply engine is entered, because
it needs no store, no manifest, and no flags.
- Secrets are always-put:
op secrets getis not-yet-implemented, so values cannot be diffed — the plan saysput (cannot diff)instead of ever claiming a false no-op. Values resolve fromfrom_envprocess variables at validation time and never appear in the manifest, plan, report, or audit records.
Every mutation is executed through the existing single-purpose verb
functions (deploy::deploy, bundles::update, messaging::add/…,
secrets::put, trust_root::bootstrap, env::init/set_public_url),
so audit, authorization, signing, and revenue-policy logic stay
single-sourced — each step lands its own audit event under the composed
verb’s noun.
Human-readable plan/progress lines go to stderr; stdout carries only
the standard {op, noun, result} JSON envelope (so the output is
already machine-readable — no separate --json flag).
Structs§
- Apply
Options - Knobs for
applybeyond the globalOpFlags. Built fromEnvApplyArgson the CLI path; library callers (greentic-setup’s env mode) construct it directly —Defaultis a plain mutating apply.
Enums§
- Apply
Mode - How
applyterminates once the plan is computed.
Functions§
- apply
gtc op env apply --answers <manifest.json> [--dry-run | --check | --non-interactive] [--updated-by <who>] [--yes].- emit_
answers_ template - Write the skeleton
greentic.env-manifest.v1template topath.