secrets-engine/src/secrets_engine/service.py

72 lines
2.4 KiB
Python
Raw Normal View History

"""Kept-running manifestation of the lifecycle library.
This is the same library the CLI uses, in a process that stays up for one
injected stage. It is not a second implementation and not a Deployment.
"""
from __future__ import annotations
import os
from collections.abc import Iterable, Mapping
from typing import Any
from secrets_engine import lifecycle as lifecycle_lib
from secrets_engine.catalog import CatalogEntry
from secrets_engine.lifecycle import LifecyclePlan
from secrets_engine.stage_binding import StageBinding, StartupError
LOCAL_ALLOW_ENV = "SECRETS_ENGINE_LOCAL_ALLOW"
def local_allow_requested(flag: bool = False) -> bool:
"""True when a caller asked to be allowed. The answer is not authority."""
env = os.environ.get(LOCAL_ALLOW_ENV, "").strip() in {"1", "true", "yes"}
return bool(flag) or env
def run_service(
binding: StageBinding | None,
jobs: Iterable[Mapping[str, Any]],
) -> list[LifecyclePlan]:
"""Run lifecycle jobs for one stage until the job iterable ends.
A job may carry ``foreign_stage_credential`` only as a refusal test. A
present value refuses the job. The binding credential is never rendered.
"""
if binding is None or not binding.credential or not binding.stage:
raise StartupError("startup refused: no stage credential is present")
plans: list[LifecyclePlan] = []
for job in jobs:
foreign = str(job.get("foreign_stage_credential") or "")
if foreign:
raise StartupError(
"startup refused: another stage credential is present"
)
entry = job.get("entry")
if not isinstance(entry, CatalogEntry):
raise StartupError("service job is missing a catalog entry")
operation = str(job.get("operation") or "")
plans.append(lifecycle_lib.build_lifecycle_plan(entry, operation))
return plans
def invoke_protected(
cfg: Any,
entry: CatalogEntry,
action: str,
*,
allow: bool = False,
auth_args: Any = None,
) -> Any:
"""Gate a protected call the way the CLI does.
``allow`` and ``SECRETS_ENGINE_LOCAL_ALLOW`` are recorded as not authority
and then discarded. The call still requires a decision record or the
published unreachable-engine stance.
"""
local_allow_requested(allow)
from secrets_engine.cli import _require_lane_approval
return _require_lane_approval(
cfg, entry, action, None, auth_args=auth_args
)