diff --git a/pyproject.toml b/pyproject.toml index f0ed53a..1698ece 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "govoplan-voting" -version = "0.1.18" +version = "0.1.19" description = "Governed voting, ballot assurance, tally, and certification for GovOPlaN." readme = "README.md" requires-python = ">=3.12" diff --git a/src/govoplan_voting/__init__.py b/src/govoplan_voting/__init__.py index 65340f9..ff6b629 100644 --- a/src/govoplan_voting/__init__.py +++ b/src/govoplan_voting/__init__.py @@ -1,3 +1,3 @@ """GovOPlaN Voting module.""" -__version__ = "0.1.18" +__version__ = "0.1.19" diff --git a/src/govoplan_voting/backend/manifest.py b/src/govoplan_voting/backend/manifest.py index 67b85b1..bfd7c95 100644 --- a/src/govoplan_voting/backend/manifest.py +++ b/src/govoplan_voting/backend/manifest.py @@ -16,6 +16,7 @@ from govoplan_core.core.module_guards import ( ) from govoplan_core.core.modules import ( CapabilityDocumentation, + DocumentationCondition, DocumentationLink, DocumentationTopic, FrontendModule, @@ -51,7 +52,7 @@ from govoplan_voting.backend.local_confidential_provider import ( MODULE_ID = "voting" MODULE_NAME = "Voting" -MODULE_VERSION = "0.1.18" +MODULE_VERSION = "0.1.19" READ_SCOPE = "voting:ballot:read" MANAGE_SCOPE = "voting:ballot:manage" CAST_SCOPE = "voting:ballot:cast" @@ -343,6 +344,25 @@ manifest = ModuleManifest( documentation_types=("admin", "user"), audience=("user", "operator", "module_admin", "auditor"), related_modules=("core", "committee", "identity_trust", "encryption"), + translations={ + "de": { + "title": "Betroffenenanfragen für Abstimmungen", + "summary": ( + "Beim Export von Abstimmungsdaten einer Person rekonstruierbare aufgezeichnete Stimmen von vertraulicher Teilnahme " + "unterscheiden." + ), + "body": ( + "Voting korreliert exakte Mandanten- und Wahlberechtigtenkennungen und kann eine bereits verifizierte Suche auf eine " + "Abstimmung begrenzen. Aufgezeichnete Abstimmungen sind ausdrücklich zurechenbar und rekonstruierbar; eine betroffene " + "Person erhält daher ihre eigenen begrenzten Auswahlwerte, Gewichtung, Generation, Zeitpunkte und Quittung. Vertrauliche " + "Abstimmungen liefern nur Metadaten zu Teilnahme, Zusicherungsprofil, Generation, Zeitpunkt und Quittung. Chiffrat, " + "Verschlüsselungshüllen, Ressourcenschlüsselverweise, Wählerschaftsdaten und Auswahlwerte werden niemals offengelegt. " + "Das Handeln für die Stimmabgabe einer anderen Person erzeugt nur eine minimierte Akteurszuordnung. Eine " + "Abstimmungskennung allein verrät keine persönliche Teilnahme. Alle Abstimmungsdatensätze werden zum Schutz von Integrität, " + "Zertifizierung, Nachzählung und Anfechtungsnachweisen aufbewahrt." + ), + } + }, metadata={ "help_contexts": [ "voting.ballot", @@ -375,6 +395,18 @@ manifest = ModuleManifest( layer="configured", documentation_types=("admin", "user"), audience=("user", "operator", "module_admin", "product_owner", "auditor"), + conditions=( + DocumentationCondition( + required_modules=("voting",), + any_scopes=( + READ_SCOPE, + MANAGE_SCOPE, + CAST_SCOPE, + CERTIFY_SCOPE, + ADMIN_SCOPE, + ), + ), + ), links=( DocumentationLink( label="Voting domain and assurance boundary", @@ -392,7 +424,26 @@ manifest = ModuleManifest( kind="repository", ), ), + translations={ + "de": { + "title": "Abstimmungszusicherung und Zertifizierung durchführen", + "summary": ( + "Aufgezeichnete Abstimmungen und providergestützte vertrauliche oder geheime Abstimmungen betreiben, ohne ihre " + "Zusicherungsprofile zu vermischen." + ), + "body": ( + "Das Öffnen einer Abstimmung friert Definition und Wählerschaftshashes ein. Native aufgezeichnete Abstimmungen bewahren " + "aktive Stimmdatensätze zur Rekonstruktion; sie sind nicht geheim. Vertrauliche, geheime und extern zertifizierte Profile " + "verlangen einen installierten Provider und bewahren nur aggregierte Ergebnisse, Quittungen, Hashes und Nachweise. " + "Provider-Zusicherung, Protokollkennung, Zertifikatsnachweis und Gültigkeit werden beim Öffnen festgelegt und vor " + "Provider-Wirkungen erneut geprüft. Der mitgelieferte lokale vertrauliche Provider verschlüsselt rohe Auswahlwerte über " + "Encryption und unterstützt interaktive Stimmabgabe, bleibt aber serverlesbar und nicht zertifiziert. Schließung, " + "Zertifizierung, Anfechtung und Aufhebung bleiben getrennte auditierbare Übergänge." + ), + } + }, metadata={ + "kind": "workflow", "seed": True, "help_contexts": [ "voting.navigation", @@ -431,7 +482,27 @@ manifest = ModuleManifest( kind="repository", ), ), + translations={ + "de": { + "title": "Abstimmungsfelder, Zusicherung und Folgen des Lebenszyklus", + "summary": ( + "Semantik von eingefrorener Wählerschaft, Schwellenwert, Provider, Quittung, Auszählung, Zertifizierung, Anfechtung und " + "Aufhebung." + ), + "body": ( + "Das Öffnen friert exakte Optionen, Methode, Wählerschaft, Gewichtungen, Quorum, Schwellenwert, Ersetzungsregel, " + "Zusicherungsprofil und Providerbindung ein. Aufgezeichnete Abstimmungen bleiben zurechenbar und rekonstruierbar. " + "Vertrauliche, geheime und extern zertifizierte Profile sind ausschließlich Zusicherungen ihres installierten Providers; " + "der lokale vertrauliche Provider ist serverlesbar und nicht zertifiziert. Eine Stimmabgabe zeichnet eine Stimme nur auf " + "oder ersetzt sie, wenn die eingefrorene Definition dies erlaubt, und liefert eine Quittung. Schließen verhindert weitere " + "Stimmabgaben und zeichnet die Auszählung auf. Zertifizieren ergänzt Nachweise, ohne das Ergebnis umzuschreiben. Anfechtung " + "und Aufhebung sind getrennt begründete, auditierbare Übergänge und löschen niemals eingefrorene Definition, Quittungen " + "oder frühere Historie." + ), + } + }, metadata={ + "kind": "reference", "seed": True, "help_contexts": [ "voting.field.assurance-profile", diff --git a/tests/test_interface_documentation_contract.py b/tests/test_interface_documentation_contract.py index 412532b..38e02f8 100644 --- a/tests/test_interface_documentation_contract.py +++ b/tests/test_interface_documentation_contract.py @@ -6,6 +6,14 @@ from govoplan_voting.backend.manifest import manifest class VotingInterfaceDocumentationContractTests(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_route_and_surfaces_remain_declared(self) -> None: frontend = manifest.frontend self.assertIsNotNone(frontend) @@ -21,9 +29,13 @@ class VotingInterfaceDocumentationContractTests(unittest.TestCase): reference = topics["voting.reference.fields-and-consequences"] self.assertIn("voting.ballot", guide.metadata["help_contexts"]) self.assertGreaterEqual(len(guide.metadata["privacy_notes"]), 3) - self.assertIn("voting.field.assurance-profile", reference.metadata["help_contexts"]) + self.assertEqual("workflow", guide.metadata["kind"]) + self.assertIn( + "voting.field.assurance-profile", reference.metadata["help_contexts"] + ) self.assertIn("cast", reference.metadata["consequence_classes"]) self.assertIn("challenge_or_annul", reference.metadata["consequence_classes"]) + self.assertEqual("reference", reference.metadata["kind"]) if __name__ == "__main__": diff --git a/webui/package.json b/webui/package.json index 71c4c64..781b0d7 100644 --- a/webui/package.json +++ b/webui/package.json @@ -1,6 +1,6 @@ { "name": "@govoplan/voting-webui", - "version": "0.1.18", + "version": "0.1.19", "private": true, "type": "module", "main": "src/index.ts",