feat(core): add datasource lifecycle governance contracts
Module Package Release / publish-packages (push) Successful in 13s

This commit is contained in:
2026-08-22 19:37:44 +02:00
parent 1c3ee9e8c7
commit c6f6faf64f
7 changed files with 66 additions and 7 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "govoplan-core"
version = "0.1.35"
version = "0.1.36"
description = "Reusable GovOPlaN platform core, access, tenancy, and RBAC components."
readme = "README.md"
requires-python = ">=3.12"
+9
View File
@@ -101,6 +101,8 @@ class DatasourceGovernance:
transfer_agreement_ref: str | None = None
freshness_policy: Mapping[str, object] = field(default_factory=dict)
quality_policy: Mapping[str, object] = field(default_factory=dict)
approval_policy: Mapping[str, object] = field(default_factory=dict)
retention_policy: Mapping[str, object] = field(default_factory=dict)
known_limits: tuple[str, ...] = ()
correction_procedure_ref: str | None = None
affected_refs: tuple[str, ...] = ()
@@ -179,6 +181,8 @@ class DatasourceGovernance:
),
freshness_policy=_governance_mapping(source.get("freshness_policy")),
quality_policy=_governance_mapping(source.get("quality_policy")),
approval_policy=_governance_mapping(source.get("approval_policy")),
retention_policy=_governance_mapping(source.get("retention_policy")),
known_limits=_governance_texts(source.get("known_limits")),
correction_procedure_ref=_optional_governance_text(
source.get("correction_procedure_ref")
@@ -210,6 +214,8 @@ class DatasourceGovernance:
"transfer_agreement_ref": self.transfer_agreement_ref,
"freshness_policy": dict(self.freshness_policy),
"quality_policy": dict(self.quality_policy),
"approval_policy": dict(self.approval_policy),
"retention_policy": dict(self.retention_policy),
"known_limits": list(self.known_limits),
"correction_procedure_ref": self.correction_procedure_ref,
"affected_refs": list(self.affected_refs),
@@ -289,6 +295,8 @@ class DatasourceMaterialization:
frozen_label: str | None = None
source_timestamp: datetime | None = None
created_at: datetime | None = None
disposed_at: datetime | None = None
disposition: Mapping[str, object] = field(default_factory=dict)
provenance: Mapping[str, object] = field(default_factory=dict)
metadata: Mapping[str, object] = field(default_factory=dict)
governance: DatasourceGovernance = field(default_factory=DatasourceGovernance)
@@ -309,6 +317,7 @@ class DatasourceStage:
row_count: int | None = None
byte_count: int | None = None
validation: Mapping[str, object] = field(default_factory=dict)
approval: Mapping[str, object] = field(default_factory=dict)
created_at: datetime | None = None
promoted_at: datetime | None = None
promoted_materialization_ref: str | None = None
+50
View File
@@ -13,6 +13,7 @@ from govoplan_core.core.datasources import (
DatasourceArtifactBackendProvider,
DatasourceDescriptor,
DatasourceField,
DatasourceGovernance,
DatasourceLifecycleProvider,
DatasourceMaterialization,
DatasourceOrigin,
@@ -212,6 +213,55 @@ class DatasourceContractTests(unittest.TestCase):
self.assertEqual("upload", descriptor.kind)
self.assertEqual("tabular", descriptor.shape)
def test_lifecycle_governance_round_trips_without_provider_specific_types(self) -> None:
governance = DatasourceGovernance.from_mapping(
{
"approval_policy": {
"version": "approval-v2",
"required": True,
"required_approvals": 2,
},
"retention_policy": {
"version": "retention-v3",
"enabled": True,
"stage_days": 30,
},
}
)
self.assertEqual("approval-v2", governance.approval_policy["version"])
self.assertEqual(30, governance.retention_policy["stage_days"])
self.assertEqual(
governance.approval_policy,
governance.to_dict()["approval_policy"],
)
self.assertEqual(
governance.retention_policy,
governance.to_dict()["retention_policy"],
)
stage = DatasourceStage(
ref="stage:governed",
name="Governed stage",
source_name="governed",
kind="upload",
mode="static",
shape="tabular",
state="awaiting_approval",
approval={"status": "pending", "policy_version": "approval-v2"},
)
materialization = DatasourceMaterialization(
ref="materialization:disposed",
datasource_ref="datasource:governed",
revision=1,
state="disposed",
fingerprint="abc123",
disposition={"reason": "retention_policy", "policy_version": "retention-v3"},
)
self.assertEqual("pending", stage.approval["status"])
self.assertEqual("retention_policy", materialization.disposition["reason"])
if __name__ == "__main__":
unittest.main()
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "@govoplan/core-webui",
"version": "0.1.35",
"version": "0.1.36",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@govoplan/core-webui",
"version": "0.1.35",
"version": "0.1.36",
"dependencies": {
"@govoplan/access-webui": "file:../../govoplan-access/webui",
"@govoplan/addresses-webui": "file:../../govoplan-addresses/webui",
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "@govoplan/core-webui",
"version": "0.1.35",
"version": "0.1.36",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@govoplan/core-webui",
"version": "0.1.35",
"version": "0.1.36",
"dependencies": {
"@govoplan/access-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-access.git#v0.1.20",
"@govoplan/admin-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-admin.git#v0.1.19",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@govoplan/core-webui",
"version": "0.1.35",
"version": "0.1.36",
"private": true,
"type": "module",
"main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@govoplan/core-webui",
"version": "0.1.35",
"version": "0.1.36",
"private": true,
"type": "module",
"main": "src/index.ts",