Release Core v0.1.35 configuration package safeguards
Module Package Release / publish-packages (push) Successful in 13s

This commit is contained in:
2026-08-22 18:05:33 +02:00
parent aa91063211
commit 1c3ee9e8c7
8 changed files with 409 additions and 25 deletions
@@ -3,13 +3,22 @@ from __future__ import annotations
import unittest
from govoplan_core.core.configuration_packages import (
ConfigurationApplyResult,
ConfigurationExportResult,
ConfigurationExportSelection,
ConfigurationModuleRequirement,
ConfigurationPackageFragment,
ConfigurationPackageEvidence,
ConfigurationPackageManifest,
ConfigurationPackageParent,
ConfigurationPlanItem,
ConfigurationPreflightContext,
ConfigurationPreflightResult,
ConfigurationProviderExpectation,
ConfigurationRequiredData,
apply_configuration_package,
dry_run_configuration_package,
export_configuration_package,
validate_configuration_package_derivation,
)
@@ -27,6 +36,121 @@ def _evidence(*kinds: str) -> tuple[ConfigurationPackageEvidence, ...]:
class ConfigurationPackageArchitectureTests(unittest.TestCase):
def test_deployment_data_references_are_declared_resolved_and_never_exported(self) -> None:
class Provider:
module_id = "forms"
def __init__(self) -> None:
self.preflight_payloads: list[dict[str, object]] = []
def describe(self):
from govoplan_core.core.configuration_packages import ConfigurationProviderDescription
return ConfigurationProviderDescription(
module_id=self.module_id,
fragment_types=("definition",),
)
def preflight(self, fragment, context):
del context
self.preflight_payloads.append(dict(fragment.payload))
return ConfigurationPreflightResult(plan=(ConfigurationPlanItem(
action="create",
module_id=self.module_id,
fragment_type=fragment.fragment_type,
fragment_id=fragment.fragment_id,
),))
def apply(self, fragment, supplied_data, context):
del supplied_data, context
return ConfigurationApplyResult(
created_refs={fragment.fragment_id or "definition": "form:resident-parking"}
)
def export(self, selection, context):
del selection, context
return ConfigurationExportResult(
fragments=(ConfigurationPackageFragment(
module_id=self.module_id,
fragment_type="definition",
payload={"name": "Resident parking permit"},
),),
data_requirements=(ConfigurationRequiredData(
key="payment_credential_ref",
label="Payment credential reference",
secret=True,
),),
)
def health(self, import_result, context):
del import_result, context
return ()
provider = Provider()
package = ConfigurationPackageManifest(
package_id="product.resident-parking",
name="Resident parking permit",
version="1.0.0",
required_modules=(ConfigurationModuleRequirement("forms"),),
data_requirements=({
"key": "service_name",
"label": "Public service name",
},),
fragments=(ConfigurationPackageFragment(
module_id="forms",
fragment_type="definition",
fragment_id="resident-parking",
payload={
"definition": {
"title": {"$data": "service_name"},
}
},
),),
)
missing_context = ConfigurationPreflightContext(
installed_modules={"forms": "0.1.0"},
)
missing = dry_run_configuration_package(package, (provider,), missing_context)
self.assertEqual([], provider.preflight_payloads)
self.assertIn(
"fragment_data_reference_missing",
{item.code for item in missing.diagnostics},
)
ready_context = ConfigurationPreflightContext(
installed_modules={"forms": "0.1.0"},
supplied_data={"service_name": "Anwohnerparkausweis"},
operator_user_id="operator-1",
)
ready = dry_run_configuration_package(package, (provider,), ready_context)
applied = apply_configuration_package(package, (provider,), ready_context)
exported = export_configuration_package(
(provider,),
ConfigurationExportSelection(
tenant_id="tenant-1",
module_ids=("forms",),
),
ready_context,
)
self.assertFalse(any(item.severity == "blocker" for item in ready.diagnostics))
self.assertEqual(
"Anwohnerparkausweis",
provider.preflight_payloads[-1]["definition"]["title"], # type: ignore[index]
)
self.assertIsNotNone(applied.rollback)
assert applied.rollback is not None
self.assertEqual("database_restore_required", applied.rollback.status)
self.assertIsNotNone(exported.provenance)
assert exported.provenance is not None
self.assertEqual("operator-1", exported.provenance.exporter_id)
self.assertEqual(
("payment_credential_ref",),
exported.provenance.redacted_secret_keys,
)
def test_legacy_package_defaults_to_product_and_round_trips(self) -> None:
package = ConfigurationPackageManifest.from_mapping(
{"package_id": "example", "name": "Example", "version": "1.0.0"}