mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-06-23 21:58:06 +02:00
feat: fine-grained capabilities and enterprise IAM schema extensions (#996)
Split coarse gateway capabilities into fine-grained variants to support per-operation access control in the enterprise IAM regime. Add additive schema fields for enterprise group and grant management. Capability split (gateway registry): - graph:read -> triples:read, sparql:read, graph-rag:read, graph-embeddings:read - graph:write -> triples:write, graph-embeddings:write, entity-contexts:write - documents:read -> documents:read, document-rag:read, document-embeddings:read, entity-contexts:read - documents:write -> documents:write, document-embeddings:write - rows:read -> rows:read, nlp-query:read, structured-query:read, row-embeddings:read OSS role definitions expanded to include all new fine-grained capability names — no behavioral change for OSS deployments. Schema additions (IamRequest): - group_id, member_type, member_id for group membership operations - group (GroupInput), grant (GrantInput) for create/update payloads - Decoder now handles capability, resource_json, parameters_json, authorise_checks (previously missing from translator) Schema additions (IamResponse): - group_json, groups_json, members_json, grants_json, effective_permissions_json for enterprise operation responses - Encoder now emits authorise decision fields Gateway registry: - 16 enterprise IAM operations registered (create-group, add-group-member, add-user-grant, etc.) under iam:admin capability
This commit is contained in:
parent
8797d9d9ff
commit
09b8a1d347
4 changed files with 147 additions and 18 deletions
|
|
@ -5,6 +5,7 @@ from ...schema import (
|
|||
UserInput, UserRecord,
|
||||
WorkspaceInput, WorkspaceRecord,
|
||||
ApiKeyInput, ApiKeyRecord,
|
||||
GroupInput, GrantInput,
|
||||
)
|
||||
from .base import MessageTranslator
|
||||
|
||||
|
|
@ -43,6 +44,25 @@ def _api_key_input_from_dict(d):
|
|||
)
|
||||
|
||||
|
||||
def _group_input_from_dict(d):
|
||||
if d is None:
|
||||
return None
|
||||
return GroupInput(
|
||||
name=d.get("name", ""),
|
||||
description=d.get("description", ""),
|
||||
enabled=d.get("enabled", True),
|
||||
)
|
||||
|
||||
|
||||
def _grant_input_from_dict(d):
|
||||
if d is None:
|
||||
return None
|
||||
return GrantInput(
|
||||
capability=d.get("capability", ""),
|
||||
workspace=d.get("workspace", ""),
|
||||
)
|
||||
|
||||
|
||||
def _user_record_to_dict(r):
|
||||
if r is None:
|
||||
return None
|
||||
|
|
@ -102,6 +122,15 @@ class IamRequestTranslator(MessageTranslator):
|
|||
data.get("workspace_record")
|
||||
),
|
||||
key=_api_key_input_from_dict(data.get("key")),
|
||||
group_id=data.get("group_id", ""),
|
||||
member_type=data.get("member_type", ""),
|
||||
member_id=data.get("member_id", ""),
|
||||
group=_group_input_from_dict(data.get("group")),
|
||||
grant=_grant_input_from_dict(data.get("grant")),
|
||||
capability=data.get("capability", ""),
|
||||
resource_json=data.get("resource_json", ""),
|
||||
parameters_json=data.get("parameters_json", ""),
|
||||
authorise_checks=data.get("authorise_checks", ""),
|
||||
)
|
||||
|
||||
def encode(self, obj: IamRequest) -> Dict[str, Any]:
|
||||
|
|
@ -109,6 +138,9 @@ class IamRequestTranslator(MessageTranslator):
|
|||
for fname in (
|
||||
"workspace", "actor", "user_id", "username", "key_id",
|
||||
"api_key", "password", "new_password",
|
||||
"group_id", "member_type", "member_id",
|
||||
"capability", "resource_json", "parameters_json",
|
||||
"authorise_checks",
|
||||
):
|
||||
v = getattr(obj, fname, "")
|
||||
if v:
|
||||
|
|
@ -135,6 +167,17 @@ class IamRequestTranslator(MessageTranslator):
|
|||
"name": obj.key.name,
|
||||
"expires": obj.key.expires,
|
||||
}
|
||||
if obj.group is not None:
|
||||
result["group"] = {
|
||||
"name": obj.group.name,
|
||||
"description": obj.group.description,
|
||||
"enabled": obj.group.enabled,
|
||||
}
|
||||
if obj.grant is not None:
|
||||
result["grant"] = {
|
||||
"capability": obj.grant.capability,
|
||||
"workspace": obj.grant.workspace,
|
||||
}
|
||||
return result
|
||||
|
||||
|
||||
|
|
@ -190,6 +233,23 @@ class IamResponseTranslator(MessageTranslator):
|
|||
# setup, so it can't be dropped by a truthy-only filter.
|
||||
result["bootstrap_available"] = bool(obj.bootstrap_available)
|
||||
|
||||
# authorise / authorise-many outputs.
|
||||
if obj.decision_allow:
|
||||
result["decision_allow"] = obj.decision_allow
|
||||
if obj.decision_ttl_seconds:
|
||||
result["decision_ttl_seconds"] = obj.decision_ttl_seconds
|
||||
if obj.decisions_json:
|
||||
result["decisions_json"] = obj.decisions_json
|
||||
|
||||
# Enterprise IAM outputs.
|
||||
for fname in (
|
||||
"group_json", "groups_json", "members_json",
|
||||
"grants_json", "effective_permissions_json",
|
||||
):
|
||||
v = getattr(obj, fname, "")
|
||||
if v:
|
||||
result[fname] = v
|
||||
|
||||
return result
|
||||
|
||||
def encode_with_completion(
|
||||
|
|
|
|||
|
|
@ -74,6 +74,21 @@ class ApiKeyRecord:
|
|||
last_used: str = ""
|
||||
|
||||
|
||||
# ---- Enterprise IAM types (additive) ----
|
||||
|
||||
@dataclass
|
||||
class GroupInput:
|
||||
name: str = ""
|
||||
description: str = ""
|
||||
enabled: bool = True
|
||||
|
||||
|
||||
@dataclass
|
||||
class GrantInput:
|
||||
capability: str = ""
|
||||
workspace: str = ""
|
||||
|
||||
|
||||
@dataclass
|
||||
class IamRequest:
|
||||
operation: str = ""
|
||||
|
|
@ -99,6 +114,13 @@ class IamRequest:
|
|||
workspace_record: WorkspaceInput | None = None
|
||||
key: ApiKeyInput | None = None
|
||||
|
||||
# ---- Enterprise IAM inputs (additive) ----
|
||||
group_id: str = ""
|
||||
member_type: str = ""
|
||||
member_id: str = ""
|
||||
group: GroupInput | None = None
|
||||
grant: GrantInput | None = None
|
||||
|
||||
# ---- authorise / authorise-many inputs ----
|
||||
# Capability string from the vocabulary in capabilities.md.
|
||||
capability: str = ""
|
||||
|
|
@ -164,6 +186,14 @@ class IamResponse:
|
|||
# authorise_checks.
|
||||
decisions_json: str = ""
|
||||
|
||||
# ---- Enterprise IAM outputs (additive) ----
|
||||
# JSON-serialised payloads for enterprise group/grant operations.
|
||||
group_json: str = ""
|
||||
groups_json: str = ""
|
||||
members_json: str = ""
|
||||
grants_json: str = ""
|
||||
effective_permissions_json: str = ""
|
||||
|
||||
error: Error | None = None
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue