From fd77a4c323be75f05455d1a15811b3a643d9929c Mon Sep 17 00:00:00 2001 From: CarterPerez-dev Date: Wed, 29 Apr 2026 00:28:54 -0400 Subject: [PATCH] feat(domain): Credential struct with kind enum and tag accessor CredentialKind enum covers AwsSecretsmgr, AwsIamKey, VaultDynamic, GithubPat, EnvFile, Database. Auto-generated kind predicates (c.kind.aws_secretsmgr?) drive policy matching at compile time. tag() accepts both string and symbol keys. --- .../spec/unit/domain/credential_spec.cr | 54 +++++++++++++++++++ .../src/cre/domain/credential.cr | 48 +++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 PROJECTS/intermediate/credential-rotation-enforcer/spec/unit/domain/credential_spec.cr create mode 100644 PROJECTS/intermediate/credential-rotation-enforcer/src/cre/domain/credential.cr diff --git a/PROJECTS/intermediate/credential-rotation-enforcer/spec/unit/domain/credential_spec.cr b/PROJECTS/intermediate/credential-rotation-enforcer/spec/unit/domain/credential_spec.cr new file mode 100644 index 00000000..593f5e57 --- /dev/null +++ b/PROJECTS/intermediate/credential-rotation-enforcer/spec/unit/domain/credential_spec.cr @@ -0,0 +1,54 @@ +# =================== +# ©AngelaMos | 2026 +# credential_spec.cr +# =================== + +require "../../spec_helper" +require "../../../src/cre/domain/credential" + +describe CRE::Domain::Credential do + it "constructs with required fields" do + c = CRE::Domain::Credential.new( + id: UUID.random, + external_id: "arn:aws:secretsmanager:us-east-1:1:secret:db-prod", + kind: CRE::Domain::CredentialKind::AwsSecretsmgr, + name: "db-prod", + tags: {"env" => "prod"} of String => String, + ) + c.kind.aws_secretsmgr?.should be_true + c.tag(:env).should eq "prod" + end + + it "returns nil for missing tag" do + c = CRE::Domain::Credential.new( + id: UUID.random, + external_id: "x", + kind: CRE::Domain::CredentialKind::EnvFile, + name: "n", + tags: {} of String => String, + ) + c.tag(:env).should be_nil + end + + it "supports kind predicates" do + c = CRE::Domain::Credential.new( + id: UUID.random, + external_id: "x", + kind: CRE::Domain::CredentialKind::GithubPat, + name: "n", + tags: {} of String => String, + ) + c.kind.github_pat?.should be_true + c.kind.aws_iam_key?.should be_false + end + + it "tag() accepts both string and symbol keys" do + c = CRE::Domain::Credential.new( + id: UUID.random, external_id: "x", + kind: CRE::Domain::CredentialKind::EnvFile, + name: "n", tags: {"foo" => "bar"} of String => String, + ) + c.tag("foo").should eq "bar" + c.tag(:foo).should eq "bar" + end +end diff --git a/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/domain/credential.cr b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/domain/credential.cr new file mode 100644 index 00000000..a800bc59 --- /dev/null +++ b/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/domain/credential.cr @@ -0,0 +1,48 @@ +# =================== +# ©AngelaMos | 2026 +# credential.cr +# =================== + +require "uuid" + +module CRE::Domain + enum CredentialKind + AwsSecretsmgr + AwsIamKey + VaultDynamic + GithubPat + EnvFile + Database + end + + struct Credential + getter id : UUID + getter external_id : String + getter kind : CredentialKind + getter name : String + getter tags : Hash(String, String) + getter current_version_id : UUID? + getter pending_version_id : UUID? + getter previous_version_id : UUID? + getter created_at : Time + getter updated_at : Time + + def initialize( + @id : UUID, + @external_id : String, + @kind : CredentialKind, + @name : String, + @tags : Hash(String, String), + @current_version_id : UUID? = nil, + @pending_version_id : UUID? = nil, + @previous_version_id : UUID? = nil, + @created_at : Time = Time.utc, + @updated_at : Time = Time.utc, + ) + end + + def tag(key : String | Symbol) : String? + @tags[key.to_s]? + end + end +end