Release Access v0.1.20 configuration package context
Module Package Release / publish-packages (push) Successful in 11s
Module Package Release / publish-packages (push) Successful in 11s
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@govoplan/access-webui",
|
"name": "@govoplan/access-webui",
|
||||||
"version": "0.1.19",
|
"version": "0.1.20",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "webui/src/index.ts",
|
"main": "webui/src/index.ts",
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "govoplan-access"
|
name = "govoplan-access"
|
||||||
version = "0.1.19"
|
version = "0.1.20"
|
||||||
description = "GovOPlaN access platform module with identity, auth, RBAC, and scope primitives."
|
description = "GovOPlaN access platform module with identity, auth, RBAC, and scope primitives."
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
"""GovOPlaN access platform module."""
|
"""GovOPlaN access platform module."""
|
||||||
|
|
||||||
__version__ = "0.1.19"
|
__version__ = "0.1.20"
|
||||||
|
|||||||
@@ -850,6 +850,7 @@ class ConfigurationPackageApplyResponse(BaseModel):
|
|||||||
diagnostics: list[dict[str, Any]] = Field(default_factory=list)
|
diagnostics: list[dict[str, Any]] = Field(default_factory=list)
|
||||||
created_refs: dict[str, str] = Field(default_factory=dict)
|
created_refs: dict[str, str] = Field(default_factory=dict)
|
||||||
updated_refs: dict[str, str] = Field(default_factory=dict)
|
updated_refs: dict[str, str] = Field(default_factory=dict)
|
||||||
|
rollback: dict[str, Any] | None = None
|
||||||
|
|
||||||
|
|
||||||
class ConfigurationPackageExportRequest(BaseModel):
|
class ConfigurationPackageExportRequest(BaseModel):
|
||||||
@@ -865,6 +866,7 @@ class ConfigurationPackageExportResponse(BaseModel):
|
|||||||
fragments: list[dict[str, Any]] = Field(default_factory=list)
|
fragments: list[dict[str, Any]] = Field(default_factory=list)
|
||||||
data_requirements: list[dict[str, Any]] = Field(default_factory=list)
|
data_requirements: list[dict[str, Any]] = Field(default_factory=list)
|
||||||
diagnostics: list[dict[str, Any]] = Field(default_factory=list)
|
diagnostics: list[dict[str, Any]] = Field(default_factory=list)
|
||||||
|
provenance: dict[str, Any] | None = None
|
||||||
|
|
||||||
|
|
||||||
class SystemSettingsItem(BaseModel):
|
class SystemSettingsItem(BaseModel):
|
||||||
|
|||||||
@@ -1036,6 +1036,7 @@ def configuration_package_apply_endpoint(
|
|||||||
diagnostics=[item.to_dict() for item in result.diagnostics],
|
diagnostics=[item.to_dict() for item in result.diagnostics],
|
||||||
created_refs=dict(result.created_refs),
|
created_refs=dict(result.created_refs),
|
||||||
updated_refs=dict(result.updated_refs),
|
updated_refs=dict(result.updated_refs),
|
||||||
|
rollback=result.rollback.to_dict() if result.rollback is not None else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -1056,6 +1057,7 @@ def configuration_package_export_endpoint(
|
|||||||
fragments=[item.to_dict() for item in result.fragments],
|
fragments=[item.to_dict() for item in result.fragments],
|
||||||
data_requirements=[item.to_dict() for item in result.data_requirements],
|
data_requirements=[item.to_dict() for item in result.data_requirements],
|
||||||
diagnostics=[item.to_dict() for item in result.diagnostics],
|
diagnostics=[item.to_dict() for item in result.diagnostics],
|
||||||
|
provenance=result.provenance.to_dict() if result.provenance is not None else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -378,6 +378,63 @@ ACCESS_DOCUMENTATION: tuple[DocumentationTopic, ...] = (
|
|||||||
"help_contexts": ["access.resource-explanation.subject"],
|
"help_contexts": ["access.resource-explanation.subject"],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
DocumentationTopic(
|
||||||
|
id="access.workflow.configuration-packages",
|
||||||
|
title="Preflight and apply configuration packages",
|
||||||
|
summary="Access exposes the governed admin API that resolves module providers, verifies operator authority, and records package apply evidence.",
|
||||||
|
body=(
|
||||||
|
"A configuration-package dry-run resolves installed module providers and reports missing modules, capabilities, deployment data, conflicts, and policy blockers before any provider is invoked for apply. Portable $data references are accepted only when the package declares the corresponding requirement; their supplied values are resolved in memory and are not added to export provenance. Apply remains subject to the configuration-change approval policy. Providers may commit independently, so processing stops at the first apply or health blocker and the response distinguishes blocked-before-apply, no-op, snapshot rollback, and partial-apply recovery states. Export invokes only selected module providers, preserves their secret redaction rules, and adds bounded provenance without serializing supplied credentials."
|
||||||
|
),
|
||||||
|
layer="configured",
|
||||||
|
documentation_types=("admin",),
|
||||||
|
audience=("system_admin", "operator", "security_reviewer"),
|
||||||
|
order=28,
|
||||||
|
conditions=(
|
||||||
|
DocumentationCondition(
|
||||||
|
required_modules=("access", "admin"),
|
||||||
|
any_scopes=(
|
||||||
|
"admin:settings:read",
|
||||||
|
"admin:settings:write",
|
||||||
|
"system:settings:read",
|
||||||
|
"system:settings:write",
|
||||||
|
"system:governance:read",
|
||||||
|
"system:governance:write",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
links=(
|
||||||
|
DocumentationLink(label="Configuration package preflight", href="/api/v1/admin/configuration-packages/dry-run", kind="api"),
|
||||||
|
DocumentationLink(label="Configuration package apply", href="/api/v1/admin/configuration-packages/apply", kind="api"),
|
||||||
|
DocumentationLink(label="Configuration package export", href="/api/v1/admin/configuration-packages/export", kind="api"),
|
||||||
|
),
|
||||||
|
related_modules=("admin", "audit", "ops"),
|
||||||
|
translations={
|
||||||
|
"de": {
|
||||||
|
"title": "Konfigurationspakete vorprüfen und anwenden",
|
||||||
|
"summary": "Access stellt die gesteuerte Admin-API bereit, die Modul-Provider auflöst, die Ausführungsberechtigung prüft und Anwendungsnachweise festhält.",
|
||||||
|
"body": (
|
||||||
|
"Die Vorprüfung eines Konfigurationspakets löst die Provider installierter Module auf und meldet fehlende Module, Fähigkeiten, Einsatzdaten, Konflikte und Richtlinienblocker, bevor eine Anwendung beginnt. "
|
||||||
|
"Portable $data-Verweise sind nur zulässig, wenn das Paket die zugehörige Anforderung deklariert; bereitgestellte Werte werden ausschließlich im Arbeitsspeicher aufgelöst und nicht in den Herkunftsnachweis des Exports aufgenommen. "
|
||||||
|
"Das Anwenden unterliegt weiterhin der Freigaberichtlinie für Konfigurationsänderungen. Provider können unabhängig festschreiben. Deshalb endet die Verarbeitung beim ersten Anwendungs- oder Gesundheitsblocker; die Antwort unterscheidet Blockierung vor Anwendung, Leerlauf, Snapshot-Rücksetzung und Wiederherstellung nach Teilanwendung. "
|
||||||
|
"Der Export ruft nur die ausgewählten Modul-Provider auf, wahrt deren Regeln zur Geheimnisschwärzung und ergänzt einen begrenzten Herkunftsnachweis, ohne bereitgestellte Zugangsdaten zu serialisieren."
|
||||||
|
),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
metadata={
|
||||||
|
"kind": "workflow",
|
||||||
|
"help_contexts": ["admin.configuration-packages"],
|
||||||
|
"limitations": [
|
||||||
|
"Package apply does not install missing modules.",
|
||||||
|
"Cross-provider apply is not an atomic distributed transaction.",
|
||||||
|
"Generic rollback depends on a retained pre-apply database snapshot.",
|
||||||
|
],
|
||||||
|
"operational_consequences": [
|
||||||
|
"A stale or blocked preflight must be rerun before apply.",
|
||||||
|
"A partial apply requires recovery before the package is retried.",
|
||||||
|
"Secret values remain outside portable fragments and provenance.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
),
|
||||||
DocumentationTopic(
|
DocumentationTopic(
|
||||||
id="access.operator.enroll-first-administrator",
|
id="access.operator.enroll-first-administrator",
|
||||||
title="Enroll the first production administrator",
|
title="Enroll the first production administrator",
|
||||||
@@ -1254,7 +1311,7 @@ def _people_search(context: ModuleContext) -> object:
|
|||||||
manifest = ModuleManifest(
|
manifest = ModuleManifest(
|
||||||
id="access",
|
id="access",
|
||||||
name="Access",
|
name="Access",
|
||||||
version="0.1.19",
|
version="0.1.20",
|
||||||
optional_dependencies=("identity", "organizations", "tenancy", "idm"),
|
optional_dependencies=("identity", "organizations", "tenancy", "idm"),
|
||||||
provides_interfaces=(
|
provides_interfaces=(
|
||||||
ModuleInterfaceProvider(name=CAPABILITY_ACCESS_PEOPLE_SEARCH, version="0.1.0"),
|
ModuleInterfaceProvider(name=CAPABILITY_ACCESS_PEOPLE_SEARCH, version="0.1.0"),
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ from types import SimpleNamespace
|
|||||||
import unittest
|
import unittest
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from govoplan_access.backend.api.v1.admin_schemas import (
|
||||||
|
ConfigurationPackageApplyResponse,
|
||||||
|
ConfigurationPackageExportResponse,
|
||||||
|
)
|
||||||
from govoplan_access.backend.api.v1.routes import _configuration_context
|
from govoplan_access.backend.api.v1.routes import _configuration_context
|
||||||
from govoplan_core.core.infrastructure_capabilities import (
|
from govoplan_core.core.infrastructure_capabilities import (
|
||||||
InfrastructureCapabilityReceiptError,
|
InfrastructureCapabilityReceiptError,
|
||||||
@@ -16,6 +20,39 @@ from govoplan_core.core.provider_governance import (
|
|||||||
|
|
||||||
|
|
||||||
class ConfigurationPackageContextTests(unittest.TestCase):
|
class ConfigurationPackageContextTests(unittest.TestCase):
|
||||||
|
def test_api_responses_preserve_rollback_and_redacted_export_provenance(self) -> None:
|
||||||
|
applied = ConfigurationPackageApplyResponse(
|
||||||
|
rollback={
|
||||||
|
"status": "database_restore_required",
|
||||||
|
"summary": "Snapshot is the generic rollback boundary.",
|
||||||
|
"recovery_action": "Retain the snapshot.",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
exported = ConfigurationPackageExportResponse(
|
||||||
|
provenance={
|
||||||
|
"exported_at": "2026-08-22T12:00:00+00:00",
|
||||||
|
"source_core_version": "0.1.35",
|
||||||
|
"module_versions": {"forms": "0.1.20"},
|
||||||
|
"tenant_id": "tenant-1",
|
||||||
|
"exporter_id": "user-1",
|
||||||
|
"selection": {
|
||||||
|
"scopes": ["tenant"],
|
||||||
|
"module_ids": ["forms"],
|
||||||
|
"object_refs": [],
|
||||||
|
},
|
||||||
|
"redacted_secret_keys": ["credential_ref"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
"database_restore_required",
|
||||||
|
applied.model_dump()["rollback"]["status"],
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
["credential_ref"],
|
||||||
|
exported.model_dump()["provenance"]["redacted_secret_keys"],
|
||||||
|
)
|
||||||
|
|
||||||
def test_context_carries_operator_scopes_and_validated_infrastructure_receipt(self) -> None:
|
def test_context_carries_operator_scopes_and_validated_infrastructure_receipt(self) -> None:
|
||||||
receipt = SimpleNamespace(installation_id="deployment-1")
|
receipt = SimpleNamespace(installation_id="deployment-1")
|
||||||
principal = SimpleNamespace(
|
principal = SimpleNamespace(
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@govoplan/access-webui",
|
"name": "@govoplan/access-webui",
|
||||||
"version": "0.1.19",
|
"version": "0.1.20",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
Reference in New Issue
Block a user