Harden production authorization and service auth
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a0217e-8c4c-7383-be6b-f50a6e485306
This commit is contained in:
tegwick 2026-08-23 14:15:42 +02:00
parent f579f3761c
commit 70371649af
20 changed files with 1268 additions and 54 deletions

View file

@ -21,8 +21,10 @@ Every privileged action is decision-gated and writes non-secret evidence.
from __future__ import annotations
import argparse
import os
import sys
from pathlib import Path
from urllib.parse import urlparse
from secrets_engine import __version__
from secrets_engine.apply import apply_plan
@ -83,8 +85,28 @@ def _privileged_evidence(
)
def _require_lane_approval(cfg: Config, entry):
"""Resolve and enforce the lane approval for a privileged live action."""
def _unsafe_local_demo_enabled(cfg: Config) -> bool:
"""Return true only for an explicit, offline, loopback-only demo."""
host = (urlparse(cfg.bao_addr).hostname or "").lower()
return (
os.environ.get("SECRETS_ENGINE_UNSAFE_DEMO") == "1"
and not cfg.hub_url
and host in {"127.0.0.1", "localhost", "::1"}
)
def _require_lane_approval(cfg: Config, entry, action: str = ""):
"""Resolve approval for a live action, failing production closed.
The durable State Hub action-authorization endpoint is not available yet.
Production therefore cannot rely on a coarse lane decision. The one narrow
exception is an explicit offline demo against a loopback OpenBao instance.
"""
if entry.stage == "prod" and not _unsafe_local_demo_enabled(cfg):
raise DecisionError(
f"production action '{action or 'unknown'}' requires a durable "
"State Hub action authorization; live production remains disabled"
)
if not entry.approval_required():
return None
decision = resolve_decision(
@ -207,7 +229,7 @@ def cmd_apply(cfg: Config, args) -> int:
return 0
with _privileged_evidence(cfg, entry, "apply") as evidence:
decision = _require_lane_approval(cfg, entry)
decision = _require_lane_approval(cfg, entry, "apply")
evidence.mark_approved(decision)
plan = build_plan(
entry, args.stage, decision_id=decision.id if decision else ""
@ -236,7 +258,7 @@ def cmd_provision(cfg: Config, args) -> int:
raise ProvisioningError(
f"lane '{entry.id}' is stage '{entry.stage}', not '{args.stage}'"
)
decision = _require_lane_approval(cfg, entry)
decision = _require_lane_approval(cfg, entry, "provision")
evidence.mark_approved(decision)
client = OpenBaoClient.resolve(
cfg.bao_addr, bootstrap_token_file=args.bootstrap_token_file
@ -269,7 +291,7 @@ def cmd_verify(cfg: Config, args) -> int:
"negative_requested": negative,
},
) as evidence:
decision = _require_lane_approval(cfg, entry)
decision = _require_lane_approval(cfg, entry, "verify")
evidence.mark_approved(decision)
client = OpenBaoClient.resolve(
cfg.bao_addr, bootstrap_token_file=args.bootstrap_token_file
@ -345,7 +367,7 @@ def cmd_handoff(cfg: Config, args) -> int:
raise ProvisioningError(
f"lane '{entry.id}' is {entry.kind}; handoff needs auth-capability"
)
decision = _require_lane_approval(cfg, entry)
decision = _require_lane_approval(cfg, entry, "handoff")
evidence.mark_approved(decision)
client = OpenBaoClient.resolve(
cfg.bao_addr, bootstrap_token_file=args.bootstrap_token_file
@ -397,7 +419,7 @@ def cmd_exec(cfg: Config, args) -> int:
},
) as evidence:
# require approval + readiness before running.
decision = _require_lane_approval(cfg, entry)
decision = _require_lane_approval(cfg, entry, "exec")
evidence.mark_approved(decision)
if not args.command:
from secrets_engine.errors import DeliveryError
@ -476,7 +498,7 @@ def cmd_revoke(cfg: Config, args) -> int:
with _privileged_evidence(
cfg, entry, "revoke", detail={"operation": plan.operation}
) as evidence:
decision = _require_lane_approval(cfg, entry)
decision = _require_lane_approval(cfg, entry, "deactivate")
evidence.mark_approved(decision)
client = OpenBaoClient.resolve(
cfg.bao_addr, bootstrap_token_file=args.bootstrap_token_file
@ -524,7 +546,7 @@ def cmd_lifecycle(cfg: Config, args) -> int:
"live destroy is disabled until an exact-action destruction "
"approval contract is available; use --dry-run to inspect targets"
)
decision = _require_lane_approval(cfg, entry)
decision = _require_lane_approval(cfg, entry, args.operation)
evidence.mark_approved(decision)
client = OpenBaoClient.resolve(
cfg.bao_addr, bootstrap_token_file=args.bootstrap_token_file