mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-04-29 18:36:22 +02:00
iam: self-service ops, optional workspace filters, Mux service routing (#855)
Three threads, all reinforcing the contract's system-level vs.
workspace-association distinction.
WS Mux service routing
- tg-show-flows (and any workspace-level service over the WS) was
failing with "unknown service" because the post-refactor Mux
unconditionally looked up flow-service:<kind>. Now branches on
the envelope's flow field: with flow → flow-service:<kind>;
without flow → <kind>:<op> from the inner body; with bare op
lookup for service=iam. Resource and parameters come from the
matched op's own extractors — same path the HTTP endpoints take.
Optional workspace on system-level user/key ops
- list-users returns the deployment-wide list when no workspace is
supplied, filters when one is. get-user, update-user,
disable-user, enable-user, delete-user, reset-password,
create-api-key, list-api-keys, revoke-api-key all treat workspace
as an optional integrity check rather than a required argument.
- create-user keeps workspace required — there it's the new user's
home-workspace binding, a parameter rather than an address.
- API keys reclassified as SYSTEM-level resources. By the same
reasoning that makes users system-level, an API key is a
credential record on a deployment-wide registry; the workspace it
authenticates to is a property, not a containment.
Self-service surface
- whoami: returns the caller's own user record. AUTHENTICATED-only;
no users:read capability required. Foundation for UI affordances
that depend on the caller's permissions.
- bootstrap-status: POST /api/v1/auth/bootstrap-status, PUBLIC,
side-effect-free. Returns {bootstrap_available: bool} so a
first-run UI can decide whether to render setup without consuming
the bootstrap op.
- Gateway now injects actor=identity.handle on every authenticated
forward to iam-svc (IamEndpoint and WS Mux iam path), overwriting
any caller-supplied value. Underpins whoami, audit logging, and
future regime-side decisions that need actor identity.
- tg-whoami and tg-update-user CLIs.
Spec polish
- iam-contract.md: actor-injection rule documented; whoami /
bootstrap-status added to operations list; permission-scope
framing tightened (workspace scope is a property of the grant,
not the user or role).
- iam.md: self-service section; gateway flow gains the actor-
injection step; role section reframed so iam-svc constraints
don't leak into contract-level prose.
- iam-protocol.md: ops table updated for whoami, bootstrap-status,
optional-workspace pattern; bootstrap_available added to the
IamResponse listing.
This commit is contained in:
parent
6302eb8c97
commit
9fc1d4527b
15 changed files with 555 additions and 147 deletions
|
|
@ -41,6 +41,27 @@ class IamClient(RequestResponse):
|
|||
)
|
||||
return resp.bootstrap_admin_user_id, resp.bootstrap_admin_api_key
|
||||
|
||||
async def bootstrap_status(self, timeout=IAM_TIMEOUT):
|
||||
"""Returns whether an unconsumed ``bootstrap`` call would
|
||||
currently succeed (i.e. iam-svc is in ``bootstrap`` mode and
|
||||
its tables are empty). Side-effect-free; intended for first-
|
||||
run UX so a UI can decide whether to render setup."""
|
||||
resp = await self._request(
|
||||
operation="bootstrap-status", timeout=timeout,
|
||||
)
|
||||
return resp.bootstrap_available
|
||||
|
||||
async def whoami(self, actor, timeout=IAM_TIMEOUT):
|
||||
"""Return the user record for ``actor`` (the authenticated
|
||||
caller's handle). AUTHENTICATED-only; no capability check —
|
||||
every authenticated user can read themselves."""
|
||||
resp = await self._request(
|
||||
operation="whoami",
|
||||
actor=actor,
|
||||
timeout=timeout,
|
||||
)
|
||||
return resp.user
|
||||
|
||||
async def resolve_api_key(self, api_key, timeout=IAM_TIMEOUT):
|
||||
"""Resolve a plaintext API key to its identity triple.
|
||||
|
||||
|
|
|
|||
|
|
@ -185,6 +185,10 @@ class IamResponseTranslator(MessageTranslator):
|
|||
result["bootstrap_admin_user_id"] = obj.bootstrap_admin_user_id
|
||||
if obj.bootstrap_admin_api_key:
|
||||
result["bootstrap_admin_api_key"] = obj.bootstrap_admin_api_key
|
||||
# bootstrap-status: emit unconditionally — the false case is
|
||||
# meaningful for UIs deciding whether to render first-run
|
||||
# setup, so it can't be dropped by a truthy-only filter.
|
||||
result["bootstrap_available"] = bool(obj.bootstrap_available)
|
||||
|
||||
return result
|
||||
|
||||
|
|
|
|||
|
|
@ -148,6 +148,10 @@ class IamResponse:
|
|||
bootstrap_admin_user_id: str = ""
|
||||
bootstrap_admin_api_key: str = ""
|
||||
|
||||
# bootstrap-status — true iff iam-svc is in 'bootstrap' mode with
|
||||
# empty tables, i.e. an unconsumed bootstrap call would succeed.
|
||||
bootstrap_available: bool = False
|
||||
|
||||
# ---- authorise / authorise-many outputs ----
|
||||
# authorise: the regime's allow / deny verdict.
|
||||
decision_allow: bool = False
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue