mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-07-01 09:29:38 +02:00
fix: use envelope workspace for mux authorisation, not inner request body
The mux was extracting the authorisation resource workspace from the inner request body via registry extractors. But workspace-scoped services (config, flow, librarian, etc.) receive workspace from the queue identity, not the message body — the inner workspace field is a dead field that no service handler reads. This caused access-denied errors when the inner body's workspace (e.g. CLI default "default") disagreed with the caller's assigned workspace, even though the envelope workspace was correct. Fix: resolve workspace from the envelope only. Split the non-flow authorisation path by resource level — WORKSPACE ops use the envelope workspace directly; SYSTEM ops (IAM) still use registry extractors since they legitimately read operation-specific body fields.
This commit is contained in:
parent
a3df4f62bb
commit
30bc073ee8
1 changed files with 18 additions and 8 deletions
|
|
@ -5,6 +5,7 @@ import uuid
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from ..capabilities import PUBLIC, AUTHENTICATED
|
from ..capabilities import PUBLIC, AUTHENTICATED
|
||||||
|
from ..registry import ResourceLevel
|
||||||
|
|
||||||
# Module logger
|
# Module logger
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
@ -159,12 +160,14 @@ class Mux:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Resolve workspace (default-fill from the caller's
|
# Resolve workspace (default-fill from the caller's
|
||||||
# bound workspace). Workspace resolution applies to all
|
# bound workspace). The envelope workspace is the
|
||||||
# operations regardless of capability level.
|
# single canonical workspace for routing AND
|
||||||
|
# authorisation. The inner request body's workspace
|
||||||
|
# field is not consulted — workspace-scoped services
|
||||||
|
# receive workspace from the queue identity, not the
|
||||||
|
# message body.
|
||||||
try:
|
try:
|
||||||
await enforce_workspace(data, self.identity, self.auth)
|
await enforce_workspace(data, self.identity, self.auth)
|
||||||
if isinstance(inner, dict):
|
|
||||||
await enforce_workspace(inner, self.identity, self.auth)
|
|
||||||
|
|
||||||
# Authorisation: capability sentinels short-circuit
|
# Authorisation: capability sentinels short-circuit
|
||||||
# the regime call; capability strings go through
|
# the regime call; capability strings go through
|
||||||
|
|
@ -176,11 +179,18 @@ class Mux:
|
||||||
"flow": data.get("flow", ""),
|
"flow": data.get("flow", ""),
|
||||||
}
|
}
|
||||||
parameters = {}
|
parameters = {}
|
||||||
|
elif op.resource_level == ResourceLevel.WORKSPACE:
|
||||||
|
# Workspace-scoped services (config, flow,
|
||||||
|
# librarian, etc.) — workspace comes from the
|
||||||
|
# envelope, same as flow-level services.
|
||||||
|
resource = {
|
||||||
|
"workspace": data.get("workspace", ""),
|
||||||
|
}
|
||||||
|
parameters = {}
|
||||||
else:
|
else:
|
||||||
# Build a minimal RequestContext so the matched
|
# System-level services (IAM) — resource is
|
||||||
# operation's own extractors decide resource
|
# {} and parameters come from the inner body
|
||||||
# and parameters — same path the HTTP
|
# (e.g. user.workspace, workspace_record.id).
|
||||||
# endpoints take.
|
|
||||||
from ..registry import RequestContext
|
from ..registry import RequestContext
|
||||||
ctx = RequestContext(
|
ctx = RequestContext(
|
||||||
body=inner if isinstance(inner, dict) else {},
|
body=inner if isinstance(inner, dict) else {},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue