Manifest the lifecycle engine as a library, a one-stage CLI, and an in-process service.
Planning stays off the store client. The process binds one stage credential at start, serve runs the same lifecycle library, and a local allow flag does not authorize a protected call. Assistant: grok Assistant-Session: 01a1609f-72b8-7222-9dff-fae300115e42
This commit is contained in:
parent
3e3f8fc629
commit
06dfe12c18
8 changed files with 530 additions and 26 deletions
71
src/secrets_engine/service.py
Normal file
71
src/secrets_engine/service.py
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
"""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
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue