feat: preserve governed configuration context
This commit is contained in:
@@ -165,6 +165,10 @@ from govoplan_core.core.configuration_control import (
|
||||
record_configuration_change_applied,
|
||||
)
|
||||
from govoplan_core.core.configuration_safety import configuration_safety_catalog, plan_configuration_change
|
||||
from govoplan_core.core.provider_governance import (
|
||||
ExternalProviderStateContext,
|
||||
collect_external_provider_states,
|
||||
)
|
||||
from govoplan_core.core.access import CAPABILITY_ACCESS_EXPLANATION, AccessExplanationService, AccessDecisionProvenance, PrincipalRef
|
||||
from govoplan_core.core.identity import CAPABILITY_IDENTITY_DIRECTORY, IdentityDirectory
|
||||
from govoplan_core.core.idm import CAPABILITY_IDM_DIRECTORY, IdmDirectory, OrganizationFunctionAssignmentRef
|
||||
@@ -916,9 +920,10 @@ def configuration_package_catalog_validation(
|
||||
@router.post("/configuration-packages/dry-run", response_model=ConfigurationPackageDryRunResponse)
|
||||
def configuration_package_dry_run_endpoint(
|
||||
payload: ConfigurationPackageRunRequest,
|
||||
session: Session = Depends(get_session),
|
||||
principal: ApiPrincipal = Depends(require_any_scope("admin:settings:read", "admin:policies:read", "system:settings:read", "system:governance:read")),
|
||||
):
|
||||
result = dry_run_configuration_package(payload.package, _configuration_providers(), _configuration_context(principal, tenant_id=payload.tenant_id, supplied_data=payload.supplied_data))
|
||||
result = dry_run_configuration_package(payload.package, _configuration_providers(), _configuration_context(principal, tenant_id=payload.tenant_id, supplied_data=payload.supplied_data, session=session))
|
||||
return ConfigurationPackageDryRunResponse(
|
||||
diagnostics=[item.to_dict() for item in result.diagnostics],
|
||||
required_data=[item.to_dict() for item in result.required_data],
|
||||
@@ -944,7 +949,7 @@ def configuration_package_apply_endpoint(
|
||||
)
|
||||
except ConfigurationControlError as exc:
|
||||
raise _configuration_control_http_error(exc) from exc
|
||||
result = apply_configuration_package(payload.package, _configuration_providers(), _configuration_context(principal, tenant_id=payload.tenant_id, supplied_data=payload.supplied_data))
|
||||
result = apply_configuration_package(payload.package, _configuration_providers(), _configuration_context(principal, tenant_id=payload.tenant_id, supplied_data=payload.supplied_data, session=session))
|
||||
record_configuration_change_applied(
|
||||
session,
|
||||
key="configuration_packages.apply",
|
||||
@@ -975,6 +980,7 @@ def configuration_package_apply_endpoint(
|
||||
@router.post("/configuration-packages/export", response_model=ConfigurationPackageExportResponse)
|
||||
def configuration_package_export_endpoint(
|
||||
payload: ConfigurationPackageExportRequest,
|
||||
session: Session = Depends(get_session),
|
||||
principal: ApiPrincipal = Depends(require_any_scope("admin:settings:read", "admin:policies:read", "system:settings:read", "system:governance:read")),
|
||||
):
|
||||
selection = ConfigurationExportSelection(
|
||||
@@ -983,7 +989,7 @@ def configuration_package_export_endpoint(
|
||||
module_ids=tuple(payload.module_ids),
|
||||
object_refs=tuple(payload.object_refs),
|
||||
)
|
||||
result = export_configuration_package(_configuration_providers(), selection, _configuration_context(principal, tenant_id=payload.tenant_id))
|
||||
result = export_configuration_package(_configuration_providers(), selection, _configuration_context(principal, tenant_id=payload.tenant_id, session=session))
|
||||
return ConfigurationPackageExportResponse(
|
||||
fragments=[item.to_dict() for item in result.fragments],
|
||||
data_requirements=[item.to_dict() for item in result.data_requirements],
|
||||
@@ -1010,21 +1016,43 @@ def _configuration_context(
|
||||
*,
|
||||
tenant_id: str | None = None,
|
||||
supplied_data: dict[str, Any] | None = None,
|
||||
session: Session | None = None,
|
||||
) -> ConfigurationPreflightContext:
|
||||
registry = get_registry()
|
||||
installed_modules: dict[str, str] = {"access": "0.1.6"}
|
||||
capabilities = {CONFIGURATION_PROVIDER_CAPABILITY, ACCESS_CONFIGURATION_CAPABILITY}
|
||||
external_provider_declarations: dict[str, dict[str, object]] = {}
|
||||
external_provider_states: dict[str, dict[str, object]] = {}
|
||||
if registry is not None and hasattr(registry, "manifests"):
|
||||
manifests = registry.manifests()
|
||||
installed_modules = {manifest.id: manifest.version for manifest in manifests}
|
||||
if hasattr(registry, "capability_names"):
|
||||
capabilities.update(registry.capability_names())
|
||||
if hasattr(registry, "external_provider_declarations"):
|
||||
external_provider_declarations = {
|
||||
declaration.id: declaration.to_dict()
|
||||
for declaration in registry.external_provider_declarations()
|
||||
}
|
||||
if session is not None and hasattr(
|
||||
registry,
|
||||
"external_provider_state_providers",
|
||||
):
|
||||
external_provider_states = collect_external_provider_states(
|
||||
registry.external_provider_state_providers(),
|
||||
ExternalProviderStateContext(
|
||||
session=session,
|
||||
tenant_id=tenant_id or principal.tenant_id,
|
||||
principal=principal,
|
||||
),
|
||||
)
|
||||
return ConfigurationPreflightContext(
|
||||
tenant_id=tenant_id or principal.tenant_id,
|
||||
operator_user_id=principal.user.id,
|
||||
supplied_data=supplied_data or {},
|
||||
installed_modules=installed_modules,
|
||||
capabilities=frozenset(capabilities),
|
||||
external_provider_declarations=external_provider_declarations,
|
||||
external_provider_states=external_provider_states,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ from govoplan_core.core.identity import CAPABILITY_IDENTITY_DIRECTORY, IdentityD
|
||||
from govoplan_core.core.idm import CAPABILITY_IDM_DIRECTORY, IdmDirectory
|
||||
from govoplan_core.core.organizations import CAPABILITY_ORGANIZATION_DIRECTORY, OrganizationDirectory
|
||||
from govoplan_core.core.module_guards import persistent_table_uninstall_guard
|
||||
from govoplan_core.core.provider_governance import declared_module_architecture
|
||||
from govoplan_core.core.modules import (
|
||||
DocumentationCondition,
|
||||
DocumentationLink,
|
||||
@@ -741,6 +742,18 @@ manifest = ModuleManifest(
|
||||
ACCESS_CONFIGURATION_CAPABILITY: _configuration_provider,
|
||||
},
|
||||
documentation=ACCESS_DOCUMENTATION,
|
||||
architecture=declared_module_architecture(
|
||||
layer="institutional_foundation",
|
||||
kind="foundation",
|
||||
maturity="vertical_slice",
|
||||
documentation_ref="docs/ACCESS_MODULE_BOUNDARY.md",
|
||||
test_ref="tests/test_login_security.py",
|
||||
known_limits=("Recovery and upgrade evidence is not yet complete enough for supported maturity.",),
|
||||
owned_concepts=("account authentication", "application role", "permission evaluation", "service account"),
|
||||
non_owned_concepts=("person identity", "organization structure", "function incumbency", "policy definition"),
|
||||
security_docs=("docs/ACCESS_MODULE_BOUNDARY.md",),
|
||||
operations_docs=("README.md",),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user