feat: add workflow engine contribution contracts

This commit is contained in:
2026-07-31 16:58:57 +02:00
parent 5211e07d0b
commit 1884274f8d
11 changed files with 301 additions and 13 deletions
+51 -1
View File
@@ -101,7 +101,7 @@ from govoplan_core.core.module_package_catalog import (
)
from govoplan_core.core.modules import FrontendModule, FrontendRoute, MigrationRetirementPlan, ModuleCompatibility, ModuleMigrationTask, ModuleMigrationTaskContext, ModuleMigrationTaskResult, ModuleUninstallGuardResult, PublicFrontendRoute
from govoplan_core.core.module_guards import drop_table_retirement_provider
from govoplan_core.core.modules import MigrationSpec, ModuleInterfaceProvider, ModuleInterfaceRequirement, ModuleManifest, RoleTemplate
from govoplan_core.core.modules import MigrationSpec, ModuleInterfaceProvider, ModuleInterfaceRequirement, ModuleManifest, PermissionDefinition, RoleTemplate
from govoplan_core.core.registry import PlatformRegistry, RegistryError
from govoplan_core.admin.models import SystemSettings
from govoplan_core.db.base import Base
@@ -363,6 +363,56 @@ class ModuleSystemTests(unittest.TestCase):
with self.assertRaisesRegex(RegistryError, "unsupported manifest contract version"):
registry.validate()
def test_manifest_can_preserve_a_legacy_permission_namespace(self) -> None:
registry = PlatformRegistry()
registry.register(
ModuleManifest(
id="workflow_engine",
name="Workflow Engine",
version="test",
permission_namespace="workflow",
permissions=(
PermissionDefinition(
scope="workflow:definition:read",
label="Read workflows",
description="Read workflow definitions.",
category="Workflow",
level="tenant",
module_id="workflow",
resource="definition",
action="read",
),
),
)
)
registry.validate()
def test_manifest_rejects_an_undeclared_permission_namespace(self) -> None:
registry = PlatformRegistry()
registry.register(
ModuleManifest(
id="workflow_engine",
name="Workflow Engine",
version="test",
permissions=(
PermissionDefinition(
scope="workflow:definition:read",
label="Read workflows",
description="Read workflow definitions.",
category="Workflow",
level="tenant",
module_id="workflow",
resource="definition",
action="read",
),
),
)
)
with self.assertRaisesRegex(RegistryError, "expected 'workflow_engine'"):
registry.validate()
def test_default_authenticated_role_templates_are_managed_tenant_roles(self) -> None:
for template, message in (
(
+45
View File
@@ -10,8 +10,13 @@ from govoplan_core.celery_app import (
from govoplan_core.core.modules import ModuleContext, ModuleManifest
from govoplan_core.core.registry import PlatformRegistry
from govoplan_core.core.workflows import (
CAPABILITY_WORKFLOW_DEFINITION_CONTRIBUTIONS,
CAPABILITY_WORKFLOW_RUNTIME_WORKER,
WorkflowDefinitionContribution,
WorkflowDefinitionContributionProvider,
WorkflowRuntimeWorker,
workflow_definition_contribution_hash,
workflow_definition_contribution_provider,
workflow_runtime_worker,
)
@@ -21,7 +26,47 @@ class _Worker:
return {"inspected": 0, "advanced": 0}
class _ContributionProvider:
def reconcile(self, session, *, tenant_ids=()):
return {"created": 0, "tenant_ids": tuple(tenant_ids)}
class WorkflowRuntimeWorkerTests(unittest.TestCase):
def test_contribution_contract_hash_and_provider_are_stable(self) -> None:
contribution = WorkflowDefinitionContribution(
origin_module_id="example",
origin_module_version="1.0.0",
definition_key="approval",
name="Approval",
graph={"schema_version": 1, "nodes": [], "edges": []},
)
self.assertEqual(
workflow_definition_contribution_hash(contribution),
workflow_definition_contribution_hash(contribution),
)
provider = _ContributionProvider()
self.assertIsInstance(provider, WorkflowDefinitionContributionProvider)
registry = PlatformRegistry()
registry.register(
ModuleManifest(
id="workflow_engine_test",
name="Workflow Engine test",
version="test",
capability_factories={
CAPABILITY_WORKFLOW_DEFINITION_CONTRIBUTIONS: (
lambda _context: provider
),
},
)
)
registry.configure_capability_context(
ModuleContext(registry=registry, settings=object())
)
self.assertIs(
provider,
workflow_definition_contribution_provider(registry),
)
def test_contract_is_runtime_checkable_and_resolved(self) -> None:
worker = _Worker()
self.assertIsInstance(worker, WorkflowRuntimeWorker)