From 9cb2080938213109c8e4212f4f8269fc23560b99 Mon Sep 17 00:00:00 2001 From: Albrecht Degering Date: Mon, 24 Aug 2026 15:00:08 +0200 Subject: [PATCH] feat: collect infrastructure dependency inventories --- docs/CONFIGURATION_PACKAGES.md | 13 + pyproject.toml | 2 +- .../core/infrastructure_capabilities.py | 253 +++++++++++++++++- tests/test_infrastructure_capabilities.py | 76 ++++++ webui/package-lock.json | 4 +- webui/package-lock.release.json | 52 ++-- webui/package.json | 2 +- webui/package.release.json | 14 +- 8 files changed, 378 insertions(+), 38 deletions(-) diff --git a/docs/CONFIGURATION_PACKAGES.md b/docs/CONFIGURATION_PACKAGES.md index 464392b..63aefa1 100644 --- a/docs/CONFIGURATION_PACKAGES.md +++ b/docs/CONFIGURATION_PACKAGES.md @@ -200,6 +200,19 @@ Feature providers remain responsible for their own semantics: Ops projects the same Core-validated receipt. It must not maintain a second parser with different validation or secret-handling rules. +Core also defines the inverse, read-only dependency-inventory contract used +before the installer changes one of those infrastructure capabilities. An +enabled module registers +`infrastructure.dependency_inventory.` and returns bounded, stable +references to its persisted configuration or data, a lifecycle state, scope, +numeric metrics, and a required operator action. Providers must not return +secrets or use this read to migrate state. The Core collector validates provider +identity and capability coverage, orders records deterministically, and marks +the complete inventory failed when any provider raises or violates the +contract. Ops is the authorized projection boundary; the installer remains the +consumer and must match installation id, freshness, completion and impacted +capability coverage before apply. + The admin wizard backend starts with these routes: - `GET /api/v1/admin/configuration-packages/catalog` diff --git a/pyproject.toml b/pyproject.toml index a40dcb6..cfde941 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "govoplan-core" -version = "0.1.41" +version = "0.1.42" description = "Reusable GovOPlaN platform core, access, tenancy, and RBAC components." readme = "README.md" requires-python = ">=3.12" diff --git a/src/govoplan_core/core/infrastructure_capabilities.py b/src/govoplan_core/core/infrastructure_capabilities.py index 79ea508..e166ab4 100644 --- a/src/govoplan_core/core/infrastructure_capabilities.py +++ b/src/govoplan_core/core/infrastructure_capabilities.py @@ -2,14 +2,18 @@ from __future__ import annotations from collections.abc import Mapping from dataclasses import dataclass +from datetime import UTC, datetime import json import os from pathlib import Path import re -from typing import Any +from typing import Any, Protocol, runtime_checkable DEPLOYMENT_CAPABILITIES_ENV = "GOVOPLAN_DEPLOYMENT_CAPABILITIES_PATH" +INFRASTRUCTURE_DEPENDENCY_PROVIDER_CAPABILITY_PREFIX = ( + "infrastructure.dependency_inventory." +) MAX_CAPABILITY_DOCUMENT_BYTES = 256 * 1024 CAPABILITY_STATES = frozenset( { @@ -20,12 +24,125 @@ CAPABILITY_STATES = frozenset( } ) _ENV_REFERENCE_RE = re.compile(r"^env:[A-Za-z_][A-Za-z0-9_]*$") +_DEPENDENCY_STATES = frozenset( + {"active", "inactive", "data_present", "pending_work", "runtime_binding"} +) class InfrastructureCapabilityReceiptError(ValueError): pass +@dataclass(frozen=True, slots=True) +class InfrastructureDependency: + """A non-secret module-owned dependency on deployment infrastructure.""" + + capability_id: str + module_id: str + dependency_type: str + dependency_ref: str + state: str + scope: str + summary: str + metrics: Mapping[str, int] + required_action: str + + def __post_init__(self) -> None: + for field_name, value, maximum in ( + ("capability_id", self.capability_id, 120), + ("module_id", self.module_id, 120), + ("dependency_type", self.dependency_type, 120), + ("dependency_ref", self.dependency_ref, 240), + ("scope", self.scope, 120), + ("summary", self.summary, 1000), + ("required_action", self.required_action, 1000), + ): + if ( + not value.strip() + or len(value) > maximum + or any(ord(char) < 32 for char in value) + ): + raise ValueError( + f"Infrastructure dependency {field_name} is invalid." + ) + if self.state not in _DEPENDENCY_STATES: + raise ValueError( + f"Infrastructure dependency state is unsupported: {self.state!r}." + ) + if len(self.metrics) > 20 or any( + not isinstance(key, str) + or not key.strip() + or len(key) > 80 + or any(ord(char) < 32 for char in key) + or type(value) is not int + or value < 0 + for key, value in self.metrics.items() + ): + raise ValueError("Infrastructure dependency metrics are invalid.") + + def to_dict(self) -> dict[str, object]: + return { + "capability_id": self.capability_id, + "module_id": self.module_id, + "dependency_type": self.dependency_type, + "dependency_ref": self.dependency_ref, + "state": self.state, + "scope": self.scope, + "summary": self.summary, + "metrics": dict(sorted(self.metrics.items())), + "required_action": self.required_action, + } + + +@runtime_checkable +class InfrastructureDependencyProvider(Protocol): + module_id: str + capability_ids: tuple[str, ...] + + def infrastructure_dependencies(self) -> tuple[InfrastructureDependency, ...]: + ... + + +@dataclass(frozen=True, slots=True) +class InfrastructureDependencyProviderReport: + module_id: str + capability_ids: tuple[str, ...] + state: str + dependency_count: int + error: str | None = None + + def to_dict(self) -> dict[str, object]: + return { + "module_id": self.module_id, + "capability_ids": list(self.capability_ids), + "state": self.state, + "dependency_count": self.dependency_count, + "error": self.error, + } + + +@dataclass(frozen=True, slots=True) +class InfrastructureDependencyInventory: + installation_id: str + generated_at: str + complete: bool + inspected_capability_ids: tuple[str, ...] + providers: tuple[InfrastructureDependencyProviderReport, ...] + dependencies: tuple[InfrastructureDependency, ...] + schema_version: int = 1 + + def to_dict(self) -> dict[str, object]: + return { + "schema_version": self.schema_version, + "installation_id": self.installation_id, + "generated_at": self.generated_at, + "complete": self.complete, + "inspected_capability_ids": list(self.inspected_capability_ids), + "providers": [item.to_dict() for item in self.providers], + "dependencies": [item.to_dict() for item in self.dependencies], + } + + @dataclass(frozen=True, slots=True) class InfrastructureCapability: id: str @@ -214,6 +331,134 @@ def deployment_capability_status( } +def collect_infrastructure_dependency_inventory( + registry: object, + *, + installation_id: str, + observed_at: datetime | None = None, +) -> InfrastructureDependencyInventory: + """Collect actual module-owned dependencies without importing module internals.""" + + normalized_installation_id = installation_id.strip() + if not normalized_installation_id or len(normalized_installation_id) > 100: + raise ValueError("Infrastructure dependency installation id is invalid.") + capability_names = getattr(registry, "capability_names", None) + capability = getattr(registry, "capability", None) + if not callable(capability_names) or not callable(capability): + raise ValueError("Infrastructure dependency inventory requires a module registry.") + + provider_names = tuple( + name + for name in capability_names() + if isinstance(name, str) + and name.startswith(INFRASTRUCTURE_DEPENDENCY_PROVIDER_CAPABILITY_PREFIX) + ) + reports: list[InfrastructureDependencyProviderReport] = [] + dependencies: list[InfrastructureDependency] = [] + inspected_capability_ids: set[str] = set() + complete = True + + for provider_name in sorted(provider_names): + expected_module_id = provider_name.removeprefix( + INFRASTRUCTURE_DEPENDENCY_PROVIDER_CAPABILITY_PREFIX + ) + module_id = expected_module_id or "unknown" + declared_ids: tuple[str, ...] = () + try: + provider = capability(provider_name) + if not isinstance(provider, InfrastructureDependencyProvider): + raise TypeError("provider does not implement the inventory contract") + module_id = provider.module_id.strip() + declared_ids = tuple( + sorted( + { + item.strip() + for item in provider.capability_ids + if isinstance(item, str) and item.strip() + } + ) + ) + if ( + module_id != expected_module_id + or len(module_id) > 120 + or any(ord(char) < 32 for char in module_id) + or not declared_ids + or len(declared_ids) > 30 + or any( + len(item) > 120 or any(ord(char) < 32 for char in item) + for item in declared_ids + ) + ): + raise ValueError("provider identity or capability declaration is invalid") + provider_dependencies = tuple(provider.infrastructure_dependencies()) + if len(provider_dependencies) > 10_000: + raise ValueError("provider dependency inventory is too large") + seen_refs: set[tuple[str, str, str]] = set() + for item in provider_dependencies: + if not isinstance(item, InfrastructureDependency): + raise TypeError("provider returned an invalid dependency") + if item.module_id != module_id or item.capability_id not in declared_ids: + raise ValueError("provider returned a dependency outside its declaration") + identity = ( + item.capability_id, + item.dependency_type, + item.dependency_ref, + ) + if identity in seen_refs: + raise ValueError("provider returned a duplicate dependency") + seen_refs.add(identity) + if len(dependencies) + len(provider_dependencies) > 10_000: + raise ValueError("combined dependency inventory is too large") + dependencies.extend(provider_dependencies) + inspected_capability_ids.update(declared_ids) + reports.append( + InfrastructureDependencyProviderReport( + module_id=module_id, + capability_ids=declared_ids, + state="complete", + dependency_count=len(provider_dependencies), + ) + ) + except Exception as exc: + complete = False + inspected_capability_ids.update(declared_ids) + reports.append( + InfrastructureDependencyProviderReport( + module_id=module_id, + capability_ids=declared_ids, + state="error", + dependency_count=0, + error=( + f"{type(exc).__name__}: provider inventory could not be completed" + ), + ) + ) + + timestamp = observed_at or datetime.now(UTC) + if timestamp.tzinfo is None: + timestamp = timestamp.replace(tzinfo=UTC) + return InfrastructureDependencyInventory( + installation_id=normalized_installation_id, + generated_at=timestamp.astimezone(UTC).isoformat(), + complete=complete, + inspected_capability_ids=tuple(sorted(inspected_capability_ids)), + providers=tuple( + sorted(reports, key=lambda item: (item.module_id, item.capability_ids)) + ), + dependencies=tuple( + sorted( + dependencies, + key=lambda item: ( + item.capability_id, + item.module_id, + item.dependency_type, + item.dependency_ref, + ), + ) + ), + ) + + def _capability(value: object) -> InfrastructureCapability: if not isinstance(value, Mapping): raise InfrastructureCapabilityReceiptError( @@ -352,10 +597,16 @@ def _unavailable_status(*, configured: bool, error: str | None) -> dict[str, obj __all__ = [ "CAPABILITY_STATES", "DEPLOYMENT_CAPABILITIES_ENV", + "INFRASTRUCTURE_DEPENDENCY_PROVIDER_CAPABILITY_PREFIX", "InfrastructureCapability", "InfrastructureCapabilityReceipt", "InfrastructureCapabilityReceiptError", + "InfrastructureDependency", + "InfrastructureDependencyInventory", + "InfrastructureDependencyProvider", + "InfrastructureDependencyProviderReport", "InfrastructurePostInstallTask", + "collect_infrastructure_dependency_inventory", "deployment_capability_status", "infrastructure_capability_receipt_from_mapping", "load_infrastructure_capability_receipt", diff --git a/tests/test_infrastructure_capabilities.py b/tests/test_infrastructure_capabilities.py index e67ee73..83bb107 100644 --- a/tests/test_infrastructure_capabilities.py +++ b/tests/test_infrastructure_capabilities.py @@ -2,6 +2,7 @@ from __future__ import annotations import json import os +from datetime import UTC, datetime from pathlib import Path import tempfile import unittest @@ -9,12 +10,53 @@ from unittest.mock import patch from govoplan_core.core.infrastructure_capabilities import ( InfrastructureCapabilityReceiptError, + InfrastructureDependency, + collect_infrastructure_dependency_inventory, deployment_capability_status, infrastructure_capability_receipt_from_mapping, load_infrastructure_capability_receipt, ) +class _InventoryProvider: + module_id = "mail" + capability_ids = ("mail.smtp",) + + def infrastructure_dependencies(self) -> tuple[InfrastructureDependency, ...]: + return ( + InfrastructureDependency( + capability_id="mail.smtp", + module_id="mail", + dependency_type="smtp_endpoint", + dependency_ref="mail-server:server-1", + state="active", + scope="system", + summary="One active SMTP endpoint uses the deployment relay.", + metrics={"credential_binding_count": 1}, + required_action="Rebind or retire the endpoint before removal.", + ), + ) + + +class _FailingInventoryProvider: + module_id = "files" + capability_ids = ("files.storage",) + + def infrastructure_dependencies(self) -> tuple[InfrastructureDependency, ...]: + raise RuntimeError("database URL must not escape") + + +class _Registry: + def __init__(self, providers: dict[str, object]) -> None: + self.providers = providers + + def capability_names(self) -> tuple[str, ...]: + return tuple(self.providers) + + def capability(self, name: str) -> object | None: + return self.providers.get(name) + + def _receipt_payload() -> dict[str, object]: return { "schema_version": 1, @@ -48,6 +90,40 @@ def _receipt_payload() -> dict[str, object]: class InfrastructureCapabilityReceiptTests(unittest.TestCase): + def test_collects_non_secret_provider_dependency_inventory(self) -> None: + inventory = collect_infrastructure_dependency_inventory( + _Registry( + { + "infrastructure.dependency_inventory.mail": _InventoryProvider(), + "unrelated.capability": object(), + } + ), + installation_id="govoplan-test", + observed_at=datetime(2026, 8, 24, 12, 0, tzinfo=UTC), + ) + + self.assertTrue(inventory.complete) + self.assertEqual(("mail.smtp",), inventory.inspected_capability_ids) + self.assertEqual("mail-server:server-1", inventory.dependencies[0].dependency_ref) + self.assertEqual("2026-08-24T12:00:00+00:00", inventory.generated_at) + self.assertNotIn("database URL", json.dumps(inventory.to_dict())) + + def test_provider_failure_makes_inventory_incomplete_without_leaking_error(self) -> None: + inventory = collect_infrastructure_dependency_inventory( + _Registry( + { + "infrastructure.dependency_inventory.files": ( + _FailingInventoryProvider() + ) + } + ), + installation_id="govoplan-test", + ) + + self.assertFalse(inventory.complete) + self.assertEqual("error", inventory.providers[0].state) + self.assertNotIn("database URL", str(inventory.providers[0].error)) + def test_parses_typed_capability_and_task_lookup(self) -> None: receipt = infrastructure_capability_receipt_from_mapping(_receipt_payload()) diff --git a/webui/package-lock.json b/webui/package-lock.json index 07150c3..7a8f4dd 100644 --- a/webui/package-lock.json +++ b/webui/package-lock.json @@ -1,12 +1,12 @@ { "name": "@govoplan/core-webui", - "version": "0.1.41", + "version": "0.1.42", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@govoplan/core-webui", - "version": "0.1.41", + "version": "0.1.42", "dependencies": { "@govoplan/access-webui": "file:../../govoplan-access/webui", "@govoplan/addresses-webui": "file:../../govoplan-addresses/webui", diff --git a/webui/package-lock.release.json b/webui/package-lock.release.json index b252175..a336ae3 100644 --- a/webui/package-lock.release.json +++ b/webui/package-lock.release.json @@ -1,28 +1,28 @@ { "name": "@govoplan/core-webui", - "version": "0.1.41", + "version": "0.1.42", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@govoplan/core-webui", - "version": "0.1.41", + "version": "0.1.42", "dependencies": { "@govoplan/access-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-access.git#v0.1.23", "@govoplan/admin-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-admin.git#v0.1.22", - "@govoplan/audit-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-audit.git#v0.1.18", + "@govoplan/audit-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-audit.git#v0.1.20", "@govoplan/calendar-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-calendar.git#v0.1.22", "@govoplan/campaign-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-campaign.git#v0.1.27", "@govoplan/cases-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-cases.git#v0.1.20", - "@govoplan/dashboard-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-dashboard.git#v0.1.18", + "@govoplan/dashboard-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-dashboard.git#v0.1.20", "@govoplan/docs-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-docs.git#v0.1.22", - "@govoplan/files-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-files.git#v0.1.23", + "@govoplan/files-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-files.git#v0.1.24", "@govoplan/helpdesk-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-helpdesk.git#v0.1.20", "@govoplan/idm-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-idm.git#v0.1.24", - "@govoplan/mail-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-mail.git#v0.1.25", - "@govoplan/ops-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-ops.git#v0.1.18", + "@govoplan/mail-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-mail.git#v0.1.26", + "@govoplan/ops-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-ops.git#v0.1.21", "@govoplan/organizations-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-organizations.git#v0.1.20", - "@govoplan/policy-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-policy.git#v0.1.18", + "@govoplan/policy-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-policy.git#v0.1.22", "@govoplan/tickets-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-tickets.git#v0.1.22", "@govoplan/wiki-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-wiki.git#v0.1.22", "@tiptap/core": "^3.29.2", @@ -789,8 +789,8 @@ } }, "node_modules/@govoplan/audit-webui": { - "version": "0.1.18", - "resolved": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-audit.git#6e63f6920ad5fb71f5d40e785eaed263905d658c", + "version": "0.1.20", + "resolved": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-audit.git#f2d7b9b29a497607d20f57886448247a8561df8d", "peerDependencies": { "@govoplan/core-webui": "^0.1.18", "lucide-react": "^1.23.0", @@ -859,8 +859,8 @@ } }, "node_modules/@govoplan/dashboard-webui": { - "version": "0.1.18", - "resolved": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-dashboard.git#ede16c5439f71ed36b50994d5ad7f656212a43c4", + "version": "0.1.20", + "resolved": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-dashboard.git#ec240ed2199637a68751e348887908a82d4cfe65", "peerDependencies": { "@govoplan/core-webui": "^0.1.18", "lucide-react": "^1.23.0", @@ -894,8 +894,8 @@ } }, "node_modules/@govoplan/files-webui": { - "version": "0.1.23", - "resolved": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-files.git#11b9b7c4c6d919b9f6649034445edfea0c77d042", + "version": "0.1.24", + "resolved": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-files.git#6176e9f40e070387f03c15d10b3b3d2f132508b5", "peerDependencies": { "@govoplan/core-webui": "^0.1.18", "@vitejs/plugin-react": "^5.2.0", @@ -948,8 +948,8 @@ } }, "node_modules/@govoplan/mail-webui": { - "version": "0.1.25", - "resolved": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-mail.git#ecc1283de76f154919c786cb84354afb8f2299c1", + "version": "0.1.26", + "resolved": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-mail.git#c62c7783d6f522b7ec13063024885bb88e257012", "peerDependencies": { "@govoplan/core-webui": "^0.1.18", "lucide-react": "^1.23.0", @@ -964,8 +964,8 @@ } }, "node_modules/@govoplan/ops-webui": { - "version": "0.1.18", - "resolved": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-ops.git#71666db45c8e602ea439495017e5849cad44ec4b", + "version": "0.1.21", + "resolved": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-ops.git#ac6b211827571c69b058fc857bbddd15125519c6", "peerDependencies": { "@govoplan/core-webui": "^0.1.18", "@vitejs/plugin-react": "^5.2.0", @@ -1002,8 +1002,8 @@ } }, "node_modules/@govoplan/policy-webui": { - "version": "0.1.18", - "resolved": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-policy.git#65159dec5fb6594fddfc2c5f8ab199c1e23994a2", + "version": "0.1.22", + "resolved": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-policy.git#29a9aea3b186b45fcf1b7bed9ebbd1712390f5c6", "peerDependencies": { "@govoplan/core-webui": "^0.1.18", "lucide-react": "^1.23.0", @@ -2127,9 +2127,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.412", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.412.tgz", - "integrity": "sha512-z4rMe3esBzlzovKHj4gxJnsCGZRK5l4baUvm+gCGJBPE+gsyUMKsuU9tnEUtI1dOebXz1ytAPGjvXhmQ7rIPwA==", + "version": "1.5.413", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.413.tgz", + "integrity": "sha512-F1XPKvt7HVfly5WND90ec16nFsdr4g5x/cVUP3EqjeyXynupabGDqpMa84wwvuYGDnldXLBz6DLXyZXWO9TPvw==", "license": "ISC" }, "node_modules/esbuild": { @@ -2289,9 +2289,9 @@ } }, "node_modules/lucide-react": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.33.0.tgz", - "integrity": "sha512-MTRwMy0ZlL8Ur/vOAiJ9XGHE+kFPC7brq6MxAm0GiGXEBj0qy0jA/pG4N675oSzciO/UCdX8T+5yUQdmDeTLxg==", + "version": "1.34.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.34.0.tgz", + "integrity": "sha512-vnjGJNI7Htk5+oWW8gXGuaLgwgAb0T6/iZbBrp9JCfRFwdNWZ0YTm3eyxjOLgwN6r8iyAf3UA70zNmBRBNv7yg==", "license": "ISC", "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" diff --git a/webui/package.json b/webui/package.json index c67349c..dc84e04 100644 --- a/webui/package.json +++ b/webui/package.json @@ -1,6 +1,6 @@ { "name": "@govoplan/core-webui", - "version": "0.1.41", + "version": "0.1.42", "private": true, "type": "module", "main": "src/index.ts", diff --git a/webui/package.release.json b/webui/package.release.json index cef0074..a9564dd 100644 --- a/webui/package.release.json +++ b/webui/package.release.json @@ -1,6 +1,6 @@ { "name": "@govoplan/core-webui", - "version": "0.1.41", + "version": "0.1.42", "private": true, "type": "module", "main": "src/index.ts", @@ -28,19 +28,19 @@ "dependencies": { "@govoplan/access-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-access.git#v0.1.23", "@govoplan/admin-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-admin.git#v0.1.22", - "@govoplan/audit-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-audit.git#v0.1.18", + "@govoplan/audit-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-audit.git#v0.1.20", "@govoplan/calendar-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-calendar.git#v0.1.22", "@govoplan/cases-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-cases.git#v0.1.20", - "@govoplan/dashboard-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-dashboard.git#v0.1.18", + "@govoplan/dashboard-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-dashboard.git#v0.1.20", "@govoplan/docs-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-docs.git#v0.1.22", - "@govoplan/files-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-files.git#v0.1.23", + "@govoplan/files-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-files.git#v0.1.24", "@govoplan/helpdesk-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-helpdesk.git#v0.1.20", "@govoplan/idm-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-idm.git#v0.1.24", - "@govoplan/mail-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-mail.git#v0.1.25", + "@govoplan/mail-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-mail.git#v0.1.26", "@govoplan/campaign-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-campaign.git#v0.1.27", "@govoplan/organizations-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-organizations.git#v0.1.20", - "@govoplan/ops-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-ops.git#v0.1.18", - "@govoplan/policy-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-policy.git#v0.1.18", + "@govoplan/ops-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-ops.git#v0.1.21", + "@govoplan/policy-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-policy.git#v0.1.22", "@govoplan/tickets-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-tickets.git#v0.1.22", "@govoplan/wiki-webui": "git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-wiki.git#v0.1.22", "@tiptap/core": "^3.29.2",