From fb4e26c798e8ade8213dcb72ed3cd52d168e6486 Mon Sep 17 00:00:00 2001 From: CarterPerez-dev Date: Wed, 29 Apr 2026 00:33:26 -0400 Subject: [PATCH] feat(persistence): abstract Persistence + repo contracts (CredentialsRepo, VersionsRepo, RotationsRepo, AuditRepo) and record types --- .../src/cre/persistence/persistence.cr | 20 ++++++ .../src/cre/persistence/repos.cr | 72 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 PROJECTS/intermediate/credential-rotation-enforcer/src/cre/persistence/persistence.cr create mode 100644 PROJECTS/intermediate/credential-rotation-enforcer/src/cre/persistence/repos.cr diff --git a/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/persistence/persistence.cr b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/persistence/persistence.cr new file mode 100644 index 00000000..862bf62e --- /dev/null +++ b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/persistence/persistence.cr @@ -0,0 +1,20 @@ +# =================== +# ©AngelaMos | 2026 +# persistence.cr +# =================== + +require "./repos" + +module CRE::Persistence + abstract class Persistence + abstract def credentials : CredentialsRepo + abstract def versions : VersionsRepo + abstract def rotations : RotationsRepo + abstract def audit : AuditRepo + + abstract def transaction(&block : ->) + abstract def with_advisory_lock(key : Int64, &block : ->) + abstract def migrate! : Nil + abstract def close : Nil + end +end diff --git a/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/persistence/repos.cr b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/persistence/repos.cr new file mode 100644 index 00000000..c924c67f --- /dev/null +++ b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/persistence/repos.cr @@ -0,0 +1,72 @@ +# =================== +# ©AngelaMos | 2026 +# repos.cr +# =================== + +require "uuid" +require "../domain/credential" +require "../domain/credential_version" + +module CRE::Persistence + record RotationRecord, + id : UUID, + credential_id : UUID, + rotator_kind : Symbol, + state : Symbol, + started_at : Time, + completed_at : Time?, + failure_reason : String? + + record AuditEntry, + seq : Int64, + event_id : UUID, + occurred_at : Time, + event_type : String, + actor : String, + target_id : UUID?, + payload : String, + prev_hash : Bytes, + content_hash : Bytes, + hmac : Bytes, + hmac_key_version : Int32 + + record AuditBatch, + id : UUID, + start_seq : Int64, + end_seq : Int64, + merkle_root : Bytes, + signature : Bytes, + signing_key_version : Int32, + sealed_at : Time + + abstract class CredentialsRepo + abstract def insert(c : Domain::Credential) : Nil + abstract def update(c : Domain::Credential) : Nil + abstract def find(id : UUID) : Domain::Credential? + abstract def find_by_external(kind : Domain::CredentialKind, external_id : String) : Domain::Credential? + abstract def all : Array(Domain::Credential) + abstract def overdue(now : Time, max_age : Time::Span) : Array(Domain::Credential) + end + + abstract class VersionsRepo + abstract def insert(v : Domain::CredentialVersion) : Nil + abstract def find(id : UUID) : Domain::CredentialVersion? + abstract def for_credential(credential_id : UUID) : Array(Domain::CredentialVersion) + abstract def revoke(id : UUID, at : Time = Time.utc) : Nil + end + + abstract class RotationsRepo + abstract def insert(rotation : RotationRecord) : Nil + abstract def update_state(id : UUID, state : Symbol, error : String? = nil) : Nil + abstract def in_flight : Array(RotationRecord) + end + + abstract class AuditRepo + abstract def append(entry : AuditEntry) : Nil + abstract def latest_hash : Bytes + abstract def latest_seq : Int64 + abstract def range(start_seq : Int64, end_seq : Int64) : Array(AuditEntry) + abstract def insert_batch(batch : AuditBatch) : Nil + abstract def last_sealed_seq : Int64 + end +end