"""ops-warden routing contract. ops-warden routes non-SSH credential needs here. It must NOT vend secret values. A route result is a pointer: catalog id, readiness, decision status, and the safe next command. This module computes that pointer for a lane. No value is read. """ from __future__ import annotations from dataclasses import dataclass, asdict from pathlib import Path from typing import Any from secrets_engine.catalog import CatalogEntry from secrets_engine.decisions import Decision, resolve_decision from secrets_engine.errors import DecisionError from secrets_engine.openbao import OpenBaoClient @dataclass class RouteResult: catalog_id: str owner: str stage: str decision_status: str decision_ref: str review_url: str metadata_applied: bool value_present: bool ready: bool next_command: str missing: str def to_json(self) -> dict[str, Any]: return asdict(self) def route_lane( entry: CatalogEntry, *, hub_url: str, repo_root: Path, client: OpenBaoClient | None = None, ) -> RouteResult: """Build the front-door routing pointer for a lane. Never reads the value.""" decision_status = "n/a (bootstrap-only)" decision_ref = entry.approval.get("decision_ref", "") review_url = "" decision: Decision | None = None if entry.approval_required(): try: decision = resolve_decision( hub_url=hub_url, repo_root=repo_root, decision_ref=decision_ref ) decision_status = decision.status review_url = decision.review_url except DecisionError: decision_status = "missing" metadata_applied = False value_present = False if client is not None and client.is_reachable(): metadata_applied = client.read_policy(entry.policy_name) is not None # Presence check uses the engine's own token; reports boolean only. field = entry.fields[0] if entry.fields else "" if field: value_present = client.kv_field_present(entry.mount, entry.path, field) approved = decision is None or decision.is_approved() ready = approved and metadata_applied and value_present if not approved: missing = f"approved decision for '{decision_ref}'" next_command = f"secrets-engine decision inspect {decision_ref or entry.id}" elif not metadata_applied: missing = "OpenBao policy/role apply" next_command = f"secrets-engine apply {decision_ref or entry.id} --stage {entry.stage}" elif not value_present: missing = "provisioned secret value" next_command = ( f"secrets-engine provision {entry.id} --stage {entry.stage} " f"--field {entry.fields[0]} --from-file " ) else: missing = "" next_command = f"secrets-engine exec --catalog {entry.id} -- " return RouteResult( catalog_id=entry.id, owner=entry.owner, stage=entry.stage, decision_status=decision_status, decision_ref=decision_ref, review_url=review_url, metadata_applied=metadata_applied, value_present=value_present, ready=ready, next_command=next_command, missing=missing, )