feat(cli): §3 M3 — per-env approval gating ([project.environments])
A `[project.environments]` block maps an env name to `{ confirm = bool }`
(`ManifestProject.environments`, client-side only — `skip_serializing`).
`pic apply --env <e>` is refused before any request when `<e>` is
confirm-required unless it is explicitly `--approve <e>`d; a blanket `--yes`
does NOT cover a gated env (§4.2 "CI must opt in per environment"); an unlisted
or `confirm = false` env applies freely. `require_env_approval` gates both the
single (`run`) and tree (`run_tree`) apply paths; `--approve <env>` is a
repeatable flag. Per-env value overlays (`picloud.<env>.toml`) already merge
client-side, so this is the confirm-policy gate only.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -283,6 +283,22 @@ pub struct ManifestProject {
|
||||
/// that subtree. Absent = instance root = no ceiling (the default).
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub parent_group: Option<String>,
|
||||
/// §3 M3 per-env approval policy: `[project.environments]` maps an env name
|
||||
/// to its policy. A `confirm = true` env requires an explicit `--approve
|
||||
/// <env>` on `pic apply --env <env>` (a blanket `--yes` does NOT cover it —
|
||||
/// §4.2 "CI must opt in per environment"). Client-side gating only; never
|
||||
/// sent to the server.
|
||||
#[serde(default, skip_serializing)]
|
||||
pub environments: std::collections::BTreeMap<String, EnvPolicy>,
|
||||
}
|
||||
|
||||
/// §3 M3: the apply-gating policy for one environment.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct EnvPolicy {
|
||||
/// Require an explicit `--approve <env>` to apply to this env.
|
||||
#[serde(default)]
|
||||
pub confirm: bool,
|
||||
}
|
||||
|
||||
/// The store kind of a shared collection (§11.6).
|
||||
|
||||
Reference in New Issue
Block a user