secrets-engine/src/secrets_engine/rotate.py

44 lines
1.6 KiB
Python
Raw Normal View History

"""Native KV rotation: replace a declared field without touching siblings.
This updates OpenBao custody only. Catalog ``rotation.owner`` remains the
provider/workload owner; this engine does not roll consumers or revoke a
provider credential. Auth-capability lanes rotate via wrap/handoff, not here.
"""
from __future__ import annotations
from pathlib import Path
from secrets_engine.catalog import CatalogEntry
from secrets_engine.errors import ProvisioningError
from secrets_engine.openbao import OpenBaoClient
from secrets_engine.provision import provision_from_file
def render_rotate_plan(entry: CatalogEntry, field: str) -> str:
owner = str((entry.rotation or {}).get("owner") or "")
lines = [
f"Rotate plan for lane '{entry.id}'",
f" field: {field}",
f" target: {entry.mount}/{entry.path}",
f" owner: {owner or '-'}",
" siblings: preserved (CAS patch)",
" workload delivery: not mutated",
]
return "\n".join(lines)
def rotate_from_file(
client: OpenBaoClient, entry: CatalogEntry, field: str, file_path: Path
) -> str:
"""Replace one declared KV field. Returns the field name only."""
if not entry.stores_kv_value():
raise ProvisioningError(
f"lane '{entry.id}' is {entry.kind}; rotate native KV via this "
"command, or wrap/handoff for auth-capability material"
)
if field not in entry.fields:
raise ProvisioningError(
f"field '{field}' not declared in lane '{entry.id}' fields {entry.fields}"
)
return provision_from_file(client, entry, field, file_path)