Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a889071b71 | ||
|
|
8a43b9b676 | ||
|
|
206873b62a |
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@govoplan/access-webui",
|
"name": "@govoplan/access-webui",
|
||||||
"version": "0.1.19",
|
"version": "0.1.22",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "webui/src/index.ts",
|
"main": "webui/src/index.ts",
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "govoplan-access"
|
name = "govoplan-access"
|
||||||
version = "0.1.19"
|
version = "0.1.22"
|
||||||
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,3 +1,3 @@
|
|||||||
"""GovOPlaN access platform module."""
|
"""GovOPlaN access platform module."""
|
||||||
|
|
||||||
__version__ = "0.1.19"
|
__version__ = "0.1.22"
|
||||||
|
|||||||
@@ -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,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,326 @@
|
|||||||
|
"""German translations for public structured documentation metadata."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
GERMAN_STRUCTURED_TRANSLATIONS: dict[str, dict[str, Any]] = {'access.reference.admin-access-fields': {'fields': [{'admin_description': 'Auf dem Konto und den '
|
||||||
|
'Mitglieder-Payloads '
|
||||||
|
'gespeichert. Es muss '
|
||||||
|
'normalisiert und '
|
||||||
|
'eindeutig für das '
|
||||||
|
'entsprechende '
|
||||||
|
'Login-Konto sein.',
|
||||||
|
'api_field': 'email',
|
||||||
|
'api_path': '/api/v1/admin/users',
|
||||||
|
'field_id': 'access.user.email',
|
||||||
|
'label': 'E-Mail',
|
||||||
|
'permission_scope': 'access:membership:create',
|
||||||
|
'provenance': 'Mandantenmitgliedschaft oder '
|
||||||
|
'Kontosuche.',
|
||||||
|
'user_description': 'Die Adresse, die '
|
||||||
|
'verwendet wird, um die '
|
||||||
|
'Person zu '
|
||||||
|
'identifizieren, wenn '
|
||||||
|
'sie sich anmelden.',
|
||||||
|
'validation': 'Muss eine gültige '
|
||||||
|
'E-Mail-Adresse sein.'},
|
||||||
|
{'admin_description': 'Wird, sofern verfügbar, '
|
||||||
|
'in Benutzer- und '
|
||||||
|
'Kontoantworten als '
|
||||||
|
'display_name ausgegeben.',
|
||||||
|
'api_field': 'display_name',
|
||||||
|
'api_path': '/api/v1/admin/users',
|
||||||
|
'field_id': 'access.user.display_name',
|
||||||
|
'label': 'Anzeigename',
|
||||||
|
'permission_scope': 'access:membership:update',
|
||||||
|
'provenance': 'Profil der '
|
||||||
|
'Mandantenmitgliedschaft.',
|
||||||
|
'user_description': 'Der lesbare Name, der '
|
||||||
|
'in Benutzerlisten und '
|
||||||
|
'Bewertungsbildschirmen '
|
||||||
|
'angezeigt wird.',
|
||||||
|
'validation': 'Menschenlesbarer Text; Halten '
|
||||||
|
'Sie ihn für Administratoren '
|
||||||
|
'erkennbar.'},
|
||||||
|
{'admin_description': 'Wird beim Aktualisieren '
|
||||||
|
'einer Benutzer- oder '
|
||||||
|
'Gruppenmitgliedschaft '
|
||||||
|
'als group_ids übertragen.',
|
||||||
|
'api_field': 'group_ids',
|
||||||
|
'api_path': '/api/v1/admin/users/{user_id}',
|
||||||
|
'field_id': 'access.user.groups',
|
||||||
|
'label': 'Gruppen',
|
||||||
|
'permission_scope': 'access:group:manage_members',
|
||||||
|
'provenance': 'Benutzergruppenmitgliedschaftszeilen.',
|
||||||
|
'user_description': 'Gemeinsame Zugriffsbündel, '
|
||||||
|
'die Rollen für viele '
|
||||||
|
'Personen gleichzeitig '
|
||||||
|
'hinzufügen können.',
|
||||||
|
'validation': 'Gruppen müssen zum gleichen '
|
||||||
|
'Mandant gehören.'},
|
||||||
|
{'admin_description': 'Wird bei '
|
||||||
|
'Aktualisierungsanforderungen '
|
||||||
|
'für Benutzer- und '
|
||||||
|
'Gruppenrollen als role_ids '
|
||||||
|
'übertragen.',
|
||||||
|
'api_field': 'role_ids',
|
||||||
|
'api_path': '/api/v1/admin/users/{user_id}',
|
||||||
|
'field_id': 'access.user.roles',
|
||||||
|
'label': 'Rollen',
|
||||||
|
'permission_scope': 'access:role:assign',
|
||||||
|
'provenance': 'Direkte Benutzerrollen plus '
|
||||||
|
'Gruppenrollenvererbung.',
|
||||||
|
'user_description': 'Direktzugangszuschüsse, '
|
||||||
|
'die einer Person '
|
||||||
|
'zugewiesen oder von '
|
||||||
|
'Gruppen geerbt wurden.',
|
||||||
|
'validation': 'Rollen müssen zuordenbar sein '
|
||||||
|
'und dürfen das '
|
||||||
|
'Delegationslimit der '
|
||||||
|
'handelnden Person nicht '
|
||||||
|
'überschreiten.'},
|
||||||
|
{'admin_description': 'Bildet Scopes beim '
|
||||||
|
'Erstellen eines '
|
||||||
|
'API-Schlüssel zu und '
|
||||||
|
'wird mit den aktuellen '
|
||||||
|
'Berechtigungen des '
|
||||||
|
'Besitzers geschnitten.',
|
||||||
|
'api_field': 'scopes',
|
||||||
|
'api_path': '/api/v1/admin/api-keys',
|
||||||
|
'field_id': 'access.api_key.scopes',
|
||||||
|
'label': 'Anwendungsbereiche',
|
||||||
|
'permission_scope': 'access:api_key:create',
|
||||||
|
'provenance': 'API-Schlüssel Grant plus '
|
||||||
|
'Eigentümerdelegation.',
|
||||||
|
'user_description': 'Die Aktionen, die ein '
|
||||||
|
'API-Schlüssel ausführen '
|
||||||
|
'kann.',
|
||||||
|
'validation': 'Verwenden Sie möglichst enge '
|
||||||
|
'Berechtigungsbereiche.'}]},
|
||||||
|
'access.reference.personal-navigation': {'outcome': 'Die Seitenschiene des Benutzers spiegelt die '
|
||||||
|
'persönlichen Präferenzen wider, während '
|
||||||
|
'verschlossene und unzugängliche Einträge '
|
||||||
|
'durch übergeordnete Richtlinien geregelt '
|
||||||
|
'bleiben.'},
|
||||||
|
'access.workflow.configuration-packages': {'limitations': ['Die Paketübernahme installiert keine '
|
||||||
|
'fehlenden Module.',
|
||||||
|
'Die anbieterübergreifende Übernahme ist keine atomar '
|
||||||
|
'verteilte Transaktion.',
|
||||||
|
'Generisches Rollback hängt von einem '
|
||||||
|
'beibehaltenen '
|
||||||
|
'vor der Übernahme erstellten Datenbank-Snapshot ab.'],
|
||||||
|
'operational_consequences': ['Ein abgestandener oder '
|
||||||
|
'blockierter Preflight '
|
||||||
|
'muss vor der Anwendung '
|
||||||
|
'erneut durchgeführt '
|
||||||
|
'werden.',
|
||||||
|
'Eine teilweise Anwendung '
|
||||||
|
'erfordert eine '
|
||||||
|
'Wiederherstellung, bevor '
|
||||||
|
'das Paket erneut '
|
||||||
|
'getestet wird.',
|
||||||
|
'Geheimwerte bleiben '
|
||||||
|
'außerhalb tragbarer '
|
||||||
|
'Fragmente und '
|
||||||
|
'Herkunft.']},
|
||||||
|
'access.workflow.data-subject-request': {'limitations': ['Module ohne DSAR-Anbieter werden als '
|
||||||
|
'Deckungslücken gemeldet.',
|
||||||
|
'Globale Konten und Identitäten werden '
|
||||||
|
'nicht automatisch gelöscht.']},
|
||||||
|
'access.workflow.grant-user-access': {'outcome': 'Eine Person kann sich beim Mandant anmelden und '
|
||||||
|
'erhält den beabsichtigten Zugang durch Gruppen '
|
||||||
|
'und Rollen.',
|
||||||
|
'prerequisites': ['Sie können Admin öffnen.',
|
||||||
|
'Sie können Benutzer, Gruppen und Rollen '
|
||||||
|
'lesen.',
|
||||||
|
'Schreib- oder Zuweisungsaktionen '
|
||||||
|
'erfordern übereinstimmende '
|
||||||
|
'Verwaltungsberechtigungen.'],
|
||||||
|
'result': 'Die Mitgliedschaft hat die beabsichtigten '
|
||||||
|
'effektiven Berechtigungen und keine breiteren '
|
||||||
|
'Rollen als nötig.',
|
||||||
|
'steps': ['Öffnen Sie Admin und gehen Sie zu Benutzern.',
|
||||||
|
'Finden Sie die bestehende Person oder erstellen '
|
||||||
|
'Sie eine Mitgliedschaft mit ihrer E-Mail-Adresse '
|
||||||
|
'und dem Anzeigenamen.',
|
||||||
|
'Überprüfen Sie aktuelle Gruppen und direkte '
|
||||||
|
'Rollen, bevor Sie etwas ändern.',
|
||||||
|
'Fügen Sie die Person der kleinsten Gruppe hinzu, '
|
||||||
|
'die den erforderlichen gemeinsamen Zugriff '
|
||||||
|
'gewährt.',
|
||||||
|
'Weisen Sie direkte Rollen nur zu, wenn eine '
|
||||||
|
'Gruppe nicht mit dem Fall übereinstimmt.',
|
||||||
|
'Speichern und überprüfen Sie eine '
|
||||||
|
'Blockernachricht, bevor Sie einen System- oder '
|
||||||
|
'Mandantbesitzer um Hilfe bitten.'],
|
||||||
|
'verification': 'Öffnen Sie den Benutzer erneut und '
|
||||||
|
'vergleichen Sie Gruppen, direkte Rollen '
|
||||||
|
'und effektive Berechtigungen mit der '
|
||||||
|
'Anforderung.'},
|
||||||
|
'access.workflow.manage-api-keys': {'consequences': ['Der Widerruf lehnt nachfolgende Anfragen, '
|
||||||
|
'die mit dem Schlüssel gestellt wurden, '
|
||||||
|
'sofort ab.',
|
||||||
|
'Durch das Entfernen von Berechtigungen vom '
|
||||||
|
'Besitzer wird der effektive '
|
||||||
|
'Schlüsselzugriff sofort eingeschränkt.'],
|
||||||
|
'limitations': ['Ein einmaliges Geheimnis kann nach dem '
|
||||||
|
'Schließen des Erstellungsdialogs nicht '
|
||||||
|
'angezeigt oder wiederhergestellt werden.',
|
||||||
|
'Ändern des Besitzers, Ablauf oder Scopes '
|
||||||
|
'erfordert einen Ersatzschlüssel.',
|
||||||
|
'Der Widerruf aktualisiert keine externen '
|
||||||
|
'Clients; die Betreiber müssen bei Bedarf '
|
||||||
|
'einen Ersatz installieren.'],
|
||||||
|
'outcome': 'Der Automatisierungsclient verfügt über einen '
|
||||||
|
'zeitlich begrenzten Berechtigungsnachweis, dessen '
|
||||||
|
'effektiver Zugriff weder seine gespeicherten '
|
||||||
|
'Berechtigungsbereiche noch die aktuellen '
|
||||||
|
'Berechtigungen seines Besitzers überschreiten '
|
||||||
|
'kann.',
|
||||||
|
'prerequisites': ['Der Mandant erlaubt '
|
||||||
|
'API-Anmeldeinformationen.',
|
||||||
|
'Die handelnde Person kann API-Schlüssel '
|
||||||
|
'erstellen oder widerrufen und jeden '
|
||||||
|
'ausgewählten Bereich delegieren.',
|
||||||
|
'Ein zugelassener externer Geheimmanager '
|
||||||
|
'und rechenschaftspflichtiger Eigentümer '
|
||||||
|
'sind bekannt.'],
|
||||||
|
'steps': ['Wählen Sie den verantwortlichen Eigentümer und die '
|
||||||
|
'engsten erforderlichen Berechtigungsbereiche.',
|
||||||
|
'Legen Sie den kürzesten praktischen Ablauf fest, '
|
||||||
|
'bevor Sie den Schlüssel erstellen.',
|
||||||
|
'Übertragen Sie das einmalige Geheimnis direkt in '
|
||||||
|
'den genehmigten Geheimmanager.',
|
||||||
|
'Widerrufen Sie den Schlüssel, wenn sein Client, '
|
||||||
|
'Eigentümer oder Zweck nicht mehr gültig ist.'],
|
||||||
|
'verification': 'Laden Sie das Schlüsselverzeichnis neu, '
|
||||||
|
'überprüfen Sie Eigentümer, Präfix, '
|
||||||
|
'Berechtigungsumfang, Ablauf und Status und '
|
||||||
|
'testen Sie dann den beabsichtigten Client, '
|
||||||
|
'ohne geheimes Material in Nachweise zu '
|
||||||
|
'kopieren.'},
|
||||||
|
'access.workflow.manage-reusable-credentials': {'limitations': ['GovOPlaN kann ein konfiguriertes '
|
||||||
|
'Geheimnis nicht anzeigen oder '
|
||||||
|
'wiederherstellen.',
|
||||||
|
'Eine leere Modul- oder '
|
||||||
|
'Serverbeschränkung bedeutet '
|
||||||
|
'jeden Wert, der nach '
|
||||||
|
'Berechtigungsumfang zulässig '
|
||||||
|
'ist.',
|
||||||
|
'Das Löschen oder Leeren eines '
|
||||||
|
'Geheimnisses schreibt keine '
|
||||||
|
'abhängigen Verbindungsreferenzen '
|
||||||
|
'neu.'],
|
||||||
|
'outcome': 'Die Zugangsdaten bleiben '
|
||||||
|
'schreibgeschützt und sind nur '
|
||||||
|
'innerhalb seines aktiven '
|
||||||
|
'Berechtigungsumfangs, Moduls, Servers '
|
||||||
|
'und Autorisierungsgrenzen verwendbar.',
|
||||||
|
'prerequisites': ['Der beabsichtigte '
|
||||||
|
'Berechtigungsinhaber wird '
|
||||||
|
'ausgewählt.',
|
||||||
|
'Die handelnde Person kann '
|
||||||
|
'Anmeldeinformationen lesen und '
|
||||||
|
'hat Schreibautorität für '
|
||||||
|
'Mutationen.',
|
||||||
|
'Der externe '
|
||||||
|
'Secret-Manager-Eigentümer und '
|
||||||
|
'abhängige Verbindungen sind '
|
||||||
|
'bekannt.'],
|
||||||
|
'steps': ['Wählen Sie den engsten Besitzumfang '
|
||||||
|
'und Anmeldetyp.',
|
||||||
|
'Beschränken Sie Module und Server '
|
||||||
|
'explizit, wenn eine breite Nutzung '
|
||||||
|
'nicht beabsichtigt ist.',
|
||||||
|
'Speichern Sie ein neues oder '
|
||||||
|
'Ersatzgeheimnis, ohne zu erwarten, '
|
||||||
|
'dass es erneut angezeigt wird.',
|
||||||
|
'Überprüfen Sie abhängige Verbindungen '
|
||||||
|
'vor der Deaktivierung, geheimen '
|
||||||
|
'Löschung oder Löschung.'],
|
||||||
|
'verification': 'Laden Sie die Liste der '
|
||||||
|
'Zugangsdaten neu, bestätigen Sie '
|
||||||
|
'deren Berechtigungsumfang und '
|
||||||
|
'Verfügbarkeit und testen Sie '
|
||||||
|
'dann jede beabsichtigte '
|
||||||
|
'abhängige Verbindung, ohne das '
|
||||||
|
'Geheimnis zu enthüllen.'},
|
||||||
|
'access.workflow.manage-service-account-credentials': {'consequences': ['Rotation widerruft den '
|
||||||
|
'vorherigen Nachweis in '
|
||||||
|
'der gleichen '
|
||||||
|
'Transaktion, die seinen '
|
||||||
|
'Ersatz schafft.',
|
||||||
|
'Der Widerruf, die '
|
||||||
|
'Deaktivierung des Kontos '
|
||||||
|
'und der Ruhestand lehnen '
|
||||||
|
'betroffene '
|
||||||
|
'Kundenanfragen sofort '
|
||||||
|
'ab.',
|
||||||
|
'Eine veraltete Revision '
|
||||||
|
'wird abgelehnt, so dass '
|
||||||
|
'ein gleichzeitiger '
|
||||||
|
'Verwaltungswechsel nicht '
|
||||||
|
'überschrieben wird.'],
|
||||||
|
'limitations': ['Einmalige '
|
||||||
|
'Anmeldegeheimnisse können '
|
||||||
|
'nach dem Schließen des '
|
||||||
|
'Erstellungsdialogs nicht '
|
||||||
|
'angezeigt oder '
|
||||||
|
'wiederhergestellt werden.',
|
||||||
|
'Deaktivierung und eine '
|
||||||
|
'reduzierte '
|
||||||
|
'Berechtigungsumfangsobergrenze '
|
||||||
|
'betreffen Clients sofort, '
|
||||||
|
'schreiben ihre externe '
|
||||||
|
'Konfiguration jedoch '
|
||||||
|
'nicht neu.',
|
||||||
|
'Der Ruhestand widerruft '
|
||||||
|
'alle aktiven '
|
||||||
|
'Anmeldeinformationen und '
|
||||||
|
'erfordert ein neues '
|
||||||
|
'Servicekonto für die '
|
||||||
|
'spätere '
|
||||||
|
'Wiederverwendung.'],
|
||||||
|
'outcome': 'Der Automatisierungsprinzipal '
|
||||||
|
'bleibt nicht interaktiv und '
|
||||||
|
'kann sich nur durch einen '
|
||||||
|
'aktiven Berechtigungsnachweis '
|
||||||
|
'authentifizieren, dessen '
|
||||||
|
'Gewährung innerhalb der '
|
||||||
|
'aktuellen '
|
||||||
|
'Berechtigungsumfangsobergrenze '
|
||||||
|
'des Kontos liegt.',
|
||||||
|
'prerequisites': ['Der Mandant erlaubt '
|
||||||
|
'API-Anmeldeinformationen.',
|
||||||
|
'Sie haben eine '
|
||||||
|
'Service-Account-Schreibberechtigung '
|
||||||
|
'und können jeden '
|
||||||
|
'ausgewählten Bereich '
|
||||||
|
'delegieren.'],
|
||||||
|
'steps': ['Erstellen Sie ein Servicekonto '
|
||||||
|
'und definieren Sie die engste '
|
||||||
|
'Nutzumfangsobergrenze.',
|
||||||
|
'Öffnen Sie das Konto und '
|
||||||
|
'erstellen Sie einen '
|
||||||
|
'Berechtigungsnachweis mit einem '
|
||||||
|
'gleichen oder engeren '
|
||||||
|
'Berechtigungsumfang.',
|
||||||
|
'Notieren Sie das einmalige '
|
||||||
|
'Geheimnis in einem externen '
|
||||||
|
'Geheimmanager.',
|
||||||
|
'Anmeldeinformationen vor Ablauf '
|
||||||
|
'drehen und Anmeldeinformationen '
|
||||||
|
'widerrufen, die nicht mehr '
|
||||||
|
'verwendet werden.'],
|
||||||
|
'verification': 'Die Verwaltungstabelle '
|
||||||
|
'zeigt die erwartete '
|
||||||
|
'Anzahl der aktiven '
|
||||||
|
'Anmeldeinformationen, den '
|
||||||
|
'Zeitstempel für die '
|
||||||
|
'letzte Verwendung, die '
|
||||||
|
'Revision und die '
|
||||||
|
'Audit-Ereignisse, ohne '
|
||||||
|
'geheimes Material '
|
||||||
|
'preiszugeben.'}}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -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(
|
||||||
|
|||||||
@@ -6,6 +6,18 @@ from govoplan_access.backend.manifest import manifest
|
|||||||
|
|
||||||
|
|
||||||
class InterfaceDocumentationContractTests(unittest.TestCase):
|
class InterfaceDocumentationContractTests(unittest.TestCase):
|
||||||
|
def test_all_static_topics_have_complete_german_content(self) -> None:
|
||||||
|
for topic in manifest.documentation:
|
||||||
|
german = (topic.translations or {}).get("de", {})
|
||||||
|
self.assertEqual(
|
||||||
|
{"title", "summary", "body"},
|
||||||
|
set(german),
|
||||||
|
topic.id,
|
||||||
|
)
|
||||||
|
self.assertTrue(
|
||||||
|
all(str(value).strip() for value in german.values()), topic.id
|
||||||
|
)
|
||||||
|
|
||||||
def test_access_admin_topics_publish_stable_help_contexts(self) -> None:
|
def test_access_admin_topics_publish_stable_help_contexts(self) -> None:
|
||||||
topics = {topic.id: topic for topic in manifest.documentation}
|
topics = {topic.id: topic for topic in manifest.documentation}
|
||||||
|
|
||||||
@@ -112,9 +124,7 @@ class InterfaceDocumentationContractTests(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_access_admin_surfaces_remain_declared(self) -> None:
|
def test_access_admin_surfaces_remain_declared(self) -> None:
|
||||||
surface_ids = {
|
surface_ids = {surface.id for surface in manifest.frontend.view_surfaces}
|
||||||
surface.id for surface in manifest.frontend.view_surfaces
|
|
||||||
}
|
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
{
|
{
|
||||||
"access.admin.system-roles",
|
"access.admin.system-roles",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@govoplan/access-webui",
|
"name": "@govoplan/access-webui",
|
||||||
"version": "0.1.19",
|
"version": "0.1.22",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
Reference in New Issue
Block a user