feat: add governed local content encryption provider

This commit is contained in:
2026-08-02 03:40:50 +02:00
parent 858c41d5ad
commit 42f35f8d00
11 changed files with 2318 additions and 26 deletions
+49 -7
View File
@@ -3,8 +3,11 @@ from __future__ import annotations
from pathlib import Path
from govoplan_core.core.encryption import (
CAPABILITY_ENCRYPTION_CONTENT_CIPHER,
CAPABILITY_ENCRYPTION_CONTENT_CIPHER_PROVIDER_PREFIX,
CAPABILITY_ENCRYPTION_CONTENT_PROTECTION,
CAPABILITY_ENCRYPTION_DISABLE_PREFLIGHT,
CAPABILITY_ENCRYPTION_KEY_MATERIAL_PROVIDER_PREFIX,
CAPABILITY_ENCRYPTION_KEY_VAULT,
CAPABILITY_ENCRYPTION_RECOVERY,
)
@@ -27,6 +30,10 @@ from govoplan_core.core.modules import (
from govoplan_core.core.provider_governance import declared_module_architecture
from govoplan_core.db.base import Base
from govoplan_encryption.backend.db import models
from govoplan_encryption.backend.local_provider import (
LOCAL_PROVIDER_ID,
LocalAesGcmProvider,
)
from govoplan_encryption.backend.service import SqlEncryptionService
@@ -75,6 +82,10 @@ def _service(context: ModuleContext) -> SqlEncryptionService:
return SqlEncryptionService(context.registry)
def _local_provider(context: ModuleContext) -> LocalAesGcmProvider:
return LocalAesGcmProvider(getattr(context.settings, "master_key_b64", None))
def _disable_guard(
session: object | None,
_module_id: str,
@@ -148,19 +159,31 @@ manifest = ModuleManifest(
optional_dependencies=OPTIONAL_DEPENDENCIES,
provides_interfaces=(
ModuleInterfaceProvider(
name="encryption.key_vault",
name=CAPABILITY_ENCRYPTION_KEY_VAULT,
version="1.0.0",
),
ModuleInterfaceProvider(
name="encryption.content_protection",
name=CAPABILITY_ENCRYPTION_CONTENT_PROTECTION,
version="1.0.0",
),
ModuleInterfaceProvider(
name="encryption.recovery_ceremony",
name=CAPABILITY_ENCRYPTION_CONTENT_CIPHER,
version="1.0.0",
),
ModuleInterfaceProvider(
name="encryption.disable_preflight",
name=f"{CAPABILITY_ENCRYPTION_KEY_MATERIAL_PROVIDER_PREFIX}{LOCAL_PROVIDER_ID}",
version="1.0.0",
),
ModuleInterfaceProvider(
name=f"{CAPABILITY_ENCRYPTION_CONTENT_CIPHER_PROVIDER_PREFIX}{LOCAL_PROVIDER_ID}",
version="1.0.0",
),
ModuleInterfaceProvider(
name=CAPABILITY_ENCRYPTION_RECOVERY,
version="1.0.0",
),
ModuleInterfaceProvider(
name=CAPABILITY_ENCRYPTION_DISABLE_PREFLIGHT,
version="1.0.0",
),
),
@@ -170,8 +193,11 @@ manifest = ModuleManifest(
capability_factories={
CAPABILITY_ENCRYPTION_KEY_VAULT: _service,
CAPABILITY_ENCRYPTION_CONTENT_PROTECTION: _service,
CAPABILITY_ENCRYPTION_CONTENT_CIPHER: _service,
CAPABILITY_ENCRYPTION_RECOVERY: _service,
CAPABILITY_ENCRYPTION_DISABLE_PREFLIGHT: _service,
f"{CAPABILITY_ENCRYPTION_KEY_MATERIAL_PROVIDER_PREFIX}{LOCAL_PROVIDER_ID}": _local_provider,
f"{CAPABILITY_ENCRYPTION_CONTENT_CIPHER_PROVIDER_PREFIX}{LOCAL_PROVIDER_ID}": _local_provider,
},
capability_documentation={
CAPABILITY_ENCRYPTION_KEY_VAULT: CapabilityDocumentation(
@@ -191,6 +217,15 @@ manifest = ModuleManifest(
),
contract_version="1.0.0",
),
CAPABILITY_ENCRYPTION_CONTENT_CIPHER: CapabilityDocumentation(
label="Server-side content cipher",
summary=(
"Protects and opens owner-module content through opaque, "
"versioned envelopes without exporting key material."
),
contract_version="1.0.0",
audience=("module_developer", "security_officer", "auditor"),
),
CAPABILITY_ENCRYPTION_RECOVERY: CapabilityDocumentation(
label="Encryption recovery ceremony",
summary=(
@@ -218,6 +253,9 @@ manifest = ModuleManifest(
models.RecoveryCeremony,
models.ProtectionMigration,
models.ContentProtectionRecord,
models.EncryptionLocalProviderOperation,
models.EncryptionLocalWrappedContentKey,
models.EncryptionLocalKeyMaterial,
models.EncryptionKeyOperation,
models.EncryptionKeyVersion,
models.EncryptionVault,
@@ -238,6 +276,9 @@ manifest = ModuleManifest(
models.ProtectionMigration,
models.RecoveryCeremony,
models.RecoveryApproval,
models.EncryptionLocalKeyMaterial,
models.EncryptionLocalWrappedContentKey,
models.EncryptionLocalProviderOperation,
label=MODULE_NAME,
),
),
@@ -255,8 +296,9 @@ manifest = ModuleManifest(
"implicitly grants cryptographic keys. High-risk lifecycle "
"actions require recent Identity Trust assurance. Disabling is "
"blocked until each envelope is migrated, decrypted, explicitly "
"exported, or cryptographically destroyed. No bundled provider "
"or E2EE claim is implied by enabling this module."
"exported, or cryptographically destroyed. The bundled local "
"AES-GCM provider is server-readable and requires the deployment "
"master key; it does not imply end-to-end encryption."
),
layer="available",
documentation_types=("admin", "user"),
@@ -285,7 +327,7 @@ manifest = ModuleManifest(
documentation_ref="docs/ENCRYPTION_BOUNDARY.md",
test_ref="tests/test_encryption.py",
known_limits=(
"The module orchestrates references and evidence but ships no concrete cryptographic provider, raw key store, cipher implementation, client E2EE protocol, KMS/HSM conformance suite, or production recovery executor.",
"The bundled local AES-256-GCM provider is a server-side reference provider backed by shared SQL state and MASTER_KEY_B64; it is not an HSM/KMS, client E2EE protocol, or independent certification.",
"A true E2EE claim remains prohibited until a selected client/provider profile passes its threat model, interoperability fixtures, backup/restore tests, and independent review.",
),
owned_concepts=(