Release Access v0.1.20 configuration package context
Module Package Release / publish-packages (push) Successful in 11s

This commit is contained in:
2026-08-22 18:04:33 +02:00
parent 2d1b1e356e
commit 206873b62a
8 changed files with 103 additions and 5 deletions
+1 -1
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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,
) )
+58 -1
View File
@@ -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
View File
@@ -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": {