Implement governed encryption lifecycle

This commit is contained in:
2026-08-01 20:57:27 +02:00
parent c78deab5b5
commit 858c41d5ad
14 changed files with 3667 additions and 111 deletions
@@ -0,0 +1,313 @@
from __future__ import annotations
from datetime import datetime
from typing import Any
import uuid
from sqlalchemy import (
DateTime,
Index,
Integer,
JSON,
String,
Text,
UniqueConstraint,
)
from sqlalchemy.orm import Mapped, mapped_column
from govoplan_core.db.base import Base, TimestampMixin
def new_uuid() -> str:
return str(uuid.uuid4())
class EncryptionVault(Base, TimestampMixin):
__tablename__ = "encryption_vaults"
__table_args__ = (
UniqueConstraint("tenant_id", "vault_id", name="uq_encryption_vault"),
UniqueConstraint(
"tenant_id",
"create_idempotency_key",
name="uq_encryption_vault_create_idempotency",
),
Index(
"ix_encryption_vault_scope",
"tenant_id",
"scope_type",
"scope_id",
"state",
),
)
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
tenant_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
vault_id: Mapped[str] = mapped_column(String(255), nullable=False, index=True)
name: Mapped[str] = mapped_column(String(255), nullable=False)
provider_id: Mapped[str] = mapped_column(String(120), nullable=False, index=True)
purpose: Mapped[str] = mapped_column(String(255), nullable=False)
profile_kind: Mapped[str] = mapped_column(String(40), nullable=False)
scope_type: Mapped[str] = mapped_column(String(80), nullable=False, index=True)
scope_id: Mapped[str | None] = mapped_column(String(255), nullable=True, index=True)
policy_ref: Mapped[str] = mapped_column(String(1000), nullable=False)
recovery_quorum: Mapped[int] = mapped_column(Integer, nullable=False)
state: Mapped[str] = mapped_column(String(40), nullable=False, index=True)
revision: Mapped[int] = mapped_column(Integer, default=1, nullable=False)
current_key_version: Mapped[int | None] = mapped_column(Integer, nullable=True)
create_idempotency_key: Mapped[str] = mapped_column(String(255), nullable=False)
create_request_digest: Mapped[str] = mapped_column(String(64), nullable=False)
provenance: Mapped[dict[str, Any]] = mapped_column(
JSON, default=dict, nullable=False
)
created_by: Mapped[str] = mapped_column(String(255), nullable=False)
updated_by: Mapped[str] = mapped_column(String(255), nullable=False)
class EncryptionKeyVersion(Base, TimestampMixin):
__tablename__ = "encryption_key_versions"
__table_args__ = (
UniqueConstraint(
"tenant_id",
"vault_id",
"version",
name="uq_encryption_key_version",
),
UniqueConstraint(
"tenant_id",
"provider_id",
"provider_key_ref",
name="uq_encryption_provider_key_ref",
),
Index(
"ix_encryption_key_vault_state",
"tenant_id",
"vault_id",
"state",
),
)
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
tenant_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
vault_id: Mapped[str] = mapped_column(String(255), nullable=False, index=True)
version: Mapped[int] = mapped_column(Integer, nullable=False)
provider_id: Mapped[str] = mapped_column(String(120), nullable=False, index=True)
provider_key_ref: Mapped[str | None] = mapped_column(String(1000), nullable=True)
algorithm_suite: Mapped[str] = mapped_column(String(120), nullable=False)
state: Mapped[str] = mapped_column(String(40), nullable=False, index=True)
public_key_ref: Mapped[str | None] = mapped_column(String(1000), nullable=True)
imported: Mapped[bool] = mapped_column(default=False, nullable=False)
exportable: Mapped[bool] = mapped_column(default=False, nullable=False)
provider_version: Mapped[str | None] = mapped_column(String(120), nullable=True)
provider_provenance: Mapped[dict[str, Any]] = mapped_column(
JSON, default=dict, nullable=False
)
activated_at: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True), nullable=True
)
revoked_at: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True), nullable=True
)
destruction_scheduled_at: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True), nullable=True
)
destroyed_at: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True), nullable=True
)
class EncryptionKeyOperation(Base, TimestampMixin):
__tablename__ = "encryption_key_operations"
__table_args__ = (
UniqueConstraint(
"tenant_id", "idempotency_key", name="uq_encryption_key_operation_idem"
),
Index(
"ix_encryption_key_operation_state",
"tenant_id",
"state",
"updated_at",
),
)
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
tenant_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
vault_id: Mapped[str] = mapped_column(String(255), nullable=False, index=True)
key_version: Mapped[int] = mapped_column(Integer, nullable=False)
operation: Mapped[str] = mapped_column(String(40), nullable=False, index=True)
provider_id: Mapped[str] = mapped_column(String(120), nullable=False)
state: Mapped[str] = mapped_column(String(40), nullable=False, index=True)
idempotency_key: Mapped[str] = mapped_column(String(255), nullable=False)
request_digest: Mapped[str] = mapped_column(String(64), nullable=False)
request_payload: Mapped[dict[str, Any]] = mapped_column(JSON, nullable=False)
error_code: Mapped[str | None] = mapped_column(String(255), nullable=True)
policy_decision_ref: Mapped[str | None] = mapped_column(String(1000), nullable=True)
assurance_evidence_ref: Mapped[str | None] = mapped_column(
String(1000), nullable=True
)
requested_by: Mapped[str] = mapped_column(String(255), nullable=False)
completed_at: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True), nullable=True
)
class ContentProtectionRecord(Base, TimestampMixin):
__tablename__ = "encryption_content_protections"
__table_args__ = (
UniqueConstraint(
"tenant_id", "envelope_id", name="uq_encryption_content_envelope"
),
UniqueConstraint(
"tenant_id",
"idempotency_key",
name="uq_encryption_content_idempotency",
),
Index(
"ix_encryption_content_owner",
"tenant_id",
"owner_module",
"resource_type",
"resource_id",
),
Index("ix_encryption_content_state", "tenant_id", "state", "updated_at"),
)
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
envelope_id: Mapped[str] = mapped_column(String(255), nullable=False, index=True)
tenant_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
owner_module: Mapped[str] = mapped_column(String(120), nullable=False, index=True)
resource_type: Mapped[str] = mapped_column(String(120), nullable=False)
resource_id: Mapped[str] = mapped_column(String(255), nullable=False)
profile_kind: Mapped[str] = mapped_column(String(40), nullable=False)
profile_id: Mapped[str] = mapped_column(String(255), nullable=False)
provider_id: Mapped[str] = mapped_column(String(120), nullable=False)
vault_id: Mapped[str] = mapped_column(String(255), nullable=False, index=True)
key_version: Mapped[int] = mapped_column(Integer, nullable=False)
algorithm_suite: Mapped[str] = mapped_column(String(120), nullable=False)
ciphertext_ref: Mapped[str] = mapped_column(String(2000), nullable=False)
ciphertext_digest: Mapped[str] = mapped_column(String(255), nullable=False)
authenticated_context_digest: Mapped[str] = mapped_column(
String(255), nullable=False
)
wrapped_key_refs: Mapped[list[str]] = mapped_column(
JSON, default=list, nullable=False
)
state: Mapped[str] = mapped_column(String(40), nullable=False, index=True)
source_envelope_id: Mapped[str | None] = mapped_column(String(255), nullable=True)
migration_id: Mapped[str | None] = mapped_column(String(36), nullable=True)
envelope_metadata: Mapped[dict[str, Any]] = mapped_column(
JSON, default=dict, nullable=False
)
idempotency_key: Mapped[str] = mapped_column(String(255), nullable=False)
request_digest: Mapped[str] = mapped_column(String(64), nullable=False)
policy_decision_ref: Mapped[str] = mapped_column(String(1000), nullable=False)
registered_by: Mapped[str] = mapped_column(String(255), nullable=False)
class ProtectionMigration(Base, TimestampMixin):
__tablename__ = "encryption_protection_migrations"
__table_args__ = (
UniqueConstraint(
"tenant_id",
"idempotency_key",
name="uq_encryption_migration_idempotency",
),
Index("ix_encryption_migration_state", "tenant_id", "state", "updated_at"),
)
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
tenant_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
source_envelope_id: Mapped[str] = mapped_column(
String(255), nullable=False, index=True
)
target_envelope_id: Mapped[str | None] = mapped_column(String(255), nullable=True)
target_provider_id: Mapped[str] = mapped_column(String(120), nullable=False)
target_vault_id: Mapped[str] = mapped_column(String(255), nullable=False)
target_key_version: Mapped[int] = mapped_column(Integer, nullable=False)
target_algorithm_suite: Mapped[str] = mapped_column(String(120), nullable=False)
mode: Mapped[str] = mapped_column(String(40), nullable=False)
state: Mapped[str] = mapped_column(String(40), nullable=False, index=True)
policy_decision_ref: Mapped[str] = mapped_column(String(1000), nullable=False)
assurance_evidence_ref: Mapped[str] = mapped_column(String(1000), nullable=False)
idempotency_key: Mapped[str] = mapped_column(String(255), nullable=False)
request_digest: Mapped[str] = mapped_column(String(64), nullable=False)
evidence_refs: Mapped[list[str]] = mapped_column(JSON, default=list, nullable=False)
error_code: Mapped[str | None] = mapped_column(String(255), nullable=True)
provenance: Mapped[dict[str, Any]] = mapped_column(
JSON, default=dict, nullable=False
)
requested_by: Mapped[str] = mapped_column(String(255), nullable=False)
completed_at: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True), nullable=True
)
class RecoveryCeremony(Base, TimestampMixin):
__tablename__ = "encryption_recovery_ceremonies"
__table_args__ = (
UniqueConstraint(
"tenant_id",
"idempotency_key",
name="uq_encryption_recovery_idempotency",
),
Index("ix_encryption_recovery_state", "tenant_id", "state", "expires_at"),
)
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
tenant_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
vault_id: Mapped[str] = mapped_column(String(255), nullable=False, index=True)
state: Mapped[str] = mapped_column(String(40), nullable=False, index=True)
requested_scope: Mapped[str] = mapped_column(String(255), nullable=False)
reason: Mapped[str] = mapped_column(Text, nullable=False)
quorum: Mapped[int] = mapped_column(Integer, nullable=False)
revision: Mapped[int] = mapped_column(Integer, default=1, nullable=False)
policy_decision_ref: Mapped[str] = mapped_column(String(1000), nullable=False)
requester_assurance_ref: Mapped[str] = mapped_column(String(1000), nullable=False)
requester_account_id: Mapped[str] = mapped_column(String(255), nullable=False)
idempotency_key: Mapped[str] = mapped_column(String(255), nullable=False)
request_digest: Mapped[str] = mapped_column(String(64), nullable=False)
expires_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), nullable=False, index=True
)
execution_ref: Mapped[str | None] = mapped_column(String(1000), nullable=True)
provenance: Mapped[dict[str, Any]] = mapped_column(
JSON, default=dict, nullable=False
)
class RecoveryApproval(Base, TimestampMixin):
__tablename__ = "encryption_recovery_approvals"
__table_args__ = (
UniqueConstraint(
"tenant_id",
"recovery_id",
"approver_account_id",
name="uq_encryption_recovery_approver",
),
UniqueConstraint(
"tenant_id",
"idempotency_key",
name="uq_encryption_recovery_approval_idem",
),
)
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid)
tenant_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
recovery_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True)
approver_account_id: Mapped[str] = mapped_column(String(255), nullable=False)
decision: Mapped[str] = mapped_column(String(20), nullable=False)
reason: Mapped[str] = mapped_column(Text, nullable=False)
assurance_evidence_ref: Mapped[str] = mapped_column(String(1000), nullable=False)
idempotency_key: Mapped[str] = mapped_column(String(255), nullable=False)
request_digest: Mapped[str] = mapped_column(String(64), nullable=False)
__all__ = [
"ContentProtectionRecord",
"EncryptionKeyOperation",
"EncryptionKeyVersion",
"EncryptionVault",
"ProtectionMigration",
"RecoveryApproval",
"RecoveryCeremony",
"new_uuid",
]