Sync GovOPlaN module state
This commit is contained in:
@@ -13,9 +13,12 @@ from govoplan_core.core.access import (
|
||||
CAPABILITY_ACCESS_PRINCIPAL_RESOLVER,
|
||||
CAPABILITY_ACCESS_TENANT_PROVISIONER,
|
||||
CAPABILITY_ACCESS_SEMANTIC_DIRECTORY,
|
||||
CAPABILITY_AUTH_API_PRINCIPAL_PROVIDER,
|
||||
CAPABILITY_AUTH_PERMISSION_EVALUATOR,
|
||||
CAPABILITY_AUTH_PRINCIPAL_RESOLVER,
|
||||
CAPABILITY_AUTH_TENANT_CONTEXT_SWITCHER,
|
||||
)
|
||||
from govoplan_core.core.idm import CAPABILITY_IDM_DIRECTORY, IdmDirectory
|
||||
from govoplan_core.core.module_guards import persistent_table_uninstall_guard
|
||||
from govoplan_core.core.modules import (
|
||||
DocumentationCondition,
|
||||
@@ -318,14 +321,51 @@ ACCESS_DOCUMENTATION: tuple[DocumentationTopic, ...] = (
|
||||
],
|
||||
},
|
||||
),
|
||||
DocumentationTopic(
|
||||
id="access.reference.external-function-role-mappings",
|
||||
title="Function facts and access roles",
|
||||
summary="Access maps accepted organization function facts to roles and permissions. IDM assignment ownership remains separate from authorization.",
|
||||
body=(
|
||||
"When IDM is installed, Access can consume identity-to-organization-function assignments through the IDM directory capability. "
|
||||
"Organizations must be installed because Access validates mappings against the Organizations function directory instead of accepting arbitrary function identifiers. "
|
||||
"An assignment does not grant rights by itself. Access grants rights only when an explicit external function role mapping connects the organization function ID to an assignable tenant role. "
|
||||
"Tenant administrators manage these mappings under Admin > Function role mappings, and the same records are exposed through the admin API. "
|
||||
"This keeps the audit trail clear: IDM records who holds a function, while Access records which function facts produce role-derived permissions."
|
||||
),
|
||||
layer="configured",
|
||||
documentation_types=("admin", "user"),
|
||||
audience=("tenant_admin", "access_admin", "operator"),
|
||||
order=32,
|
||||
conditions=(
|
||||
DocumentationCondition(
|
||||
required_modules=("access", "organizations"),
|
||||
any_scopes=("access:function:read", "access:role:read", "admin:roles:read"),
|
||||
),
|
||||
),
|
||||
links=(
|
||||
DocumentationLink(label="Function role mappings", href="/admin?section=tenant-function-role-mappings", kind="runtime"),
|
||||
DocumentationLink(label="External function role mappings API", href="/api/v1/admin/external-function-role-mappings", kind="api"),
|
||||
DocumentationLink(label="IDM assignments", href="/idm", kind="runtime"),
|
||||
),
|
||||
metadata={
|
||||
"kind": "reference",
|
||||
"route": "/admin",
|
||||
"api_path": "/api/v1/admin/external-function-role-mappings",
|
||||
"permission_scopes": ["access:function:write", "access:role:assign"],
|
||||
"related_topic_ids": [
|
||||
"idm.workflow.assign-function-to-identity",
|
||||
"docs.reference.organization-identity-idm-access-boundary",
|
||||
],
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _legacy_principal_resolver(context: ModuleContext) -> object:
|
||||
del context
|
||||
from govoplan_access.backend.auth.dependencies import LegacyPrincipalResolver
|
||||
|
||||
return LegacyPrincipalResolver()
|
||||
idm_directory = _optional_idm_directory(context)
|
||||
return LegacyPrincipalResolver(idm_directory=idm_directory)
|
||||
|
||||
|
||||
def _legacy_permission_evaluator(context: ModuleContext) -> object:
|
||||
@@ -335,18 +375,39 @@ def _legacy_permission_evaluator(context: ModuleContext) -> object:
|
||||
return LegacyPermissionEvaluator()
|
||||
|
||||
|
||||
def _access_directory(context: ModuleContext) -> object:
|
||||
def _api_principal_provider(context: ModuleContext) -> object:
|
||||
del context
|
||||
from govoplan_access.backend.auth.dependencies import AccessApiPrincipalProvider
|
||||
|
||||
return AccessApiPrincipalProvider()
|
||||
|
||||
|
||||
def _tenant_context_switcher(context: ModuleContext) -> object:
|
||||
del context
|
||||
from govoplan_access.backend.auth.tenant_context import AccessTenantContextSwitcher
|
||||
|
||||
return AccessTenantContextSwitcher()
|
||||
|
||||
|
||||
def _access_directory(context: ModuleContext) -> object:
|
||||
from govoplan_access.backend.directory import SqlAccessDirectory
|
||||
|
||||
return SqlAccessDirectory()
|
||||
return SqlAccessDirectory(idm_directory=_optional_idm_directory(context))
|
||||
|
||||
|
||||
def _access_semantic_directory(context: ModuleContext) -> object:
|
||||
del context
|
||||
from govoplan_access.backend.directory import SqlAccessDirectory
|
||||
|
||||
return SqlAccessDirectory()
|
||||
return SqlAccessDirectory(idm_directory=_optional_idm_directory(context))
|
||||
|
||||
|
||||
def _optional_idm_directory(context: ModuleContext) -> IdmDirectory | None:
|
||||
if not context.registry.has_capability(CAPABILITY_IDM_DIRECTORY):
|
||||
return None
|
||||
capability = context.registry.require_capability(CAPABILITY_IDM_DIRECTORY)
|
||||
if not isinstance(capability, IdmDirectory):
|
||||
raise RuntimeError(f"Invalid capability: {CAPABILITY_IDM_DIRECTORY}")
|
||||
return capability
|
||||
|
||||
|
||||
def _access_explanation_service(context: ModuleContext) -> object:
|
||||
@@ -404,7 +465,7 @@ manifest = ModuleManifest(
|
||||
id="access",
|
||||
name="Access",
|
||||
version="0.1.6",
|
||||
optional_dependencies=("identity", "organizations", "tenancy"),
|
||||
optional_dependencies=("identity", "organizations", "tenancy", "idm"),
|
||||
permissions=ACCESS_PERMISSIONS,
|
||||
role_templates=ACCESS_ROLE_TEMPLATES,
|
||||
route_factory=_route_factory,
|
||||
@@ -424,6 +485,7 @@ manifest = ModuleManifest(
|
||||
access_models.OrganizationUnit,
|
||||
access_models.Function,
|
||||
access_models.FunctionRoleAssignment,
|
||||
access_models.ExternalFunctionRoleAssignment,
|
||||
access_models.FunctionAssignment,
|
||||
access_models.FunctionDelegation,
|
||||
access_models.SystemRoleAssignment,
|
||||
@@ -443,8 +505,10 @@ manifest = ModuleManifest(
|
||||
nav_items=(NavItem(path="/admin", label="Admin", icon="admin", required_any=ADMIN_READ_SCOPES, order=900),),
|
||||
),
|
||||
capability_factories={
|
||||
CAPABILITY_AUTH_API_PRINCIPAL_PROVIDER: _api_principal_provider,
|
||||
CAPABILITY_AUTH_PRINCIPAL_RESOLVER: _legacy_principal_resolver,
|
||||
CAPABILITY_AUTH_PERMISSION_EVALUATOR: _legacy_permission_evaluator,
|
||||
CAPABILITY_AUTH_TENANT_CONTEXT_SWITCHER: _tenant_context_switcher,
|
||||
CAPABILITY_ACCESS_PRINCIPAL_RESOLVER: _legacy_principal_resolver,
|
||||
CAPABILITY_ACCESS_PERMISSION_EVALUATOR: _legacy_permission_evaluator,
|
||||
CAPABILITY_ACCESS_DIRECTORY: _access_directory,
|
||||
|
||||
Reference in New Issue
Block a user