mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 15:01:32 +00:00
6.7 KiB
6.7 KiB
PostgreSQL Repository Implementation
Overview
Complete PostgreSQL implementation for the certctl certificate control plane using database/sql and lib/pq driver. All 71 interface methods across 11 repositories have been implemented.
File Structure
internal/repository/postgres/
├── db.go # Database connection and migration setup
├── certificate.go # CertificateRepository (8 methods)
├── issuer.go # IssuerRepository (5 methods)
├── target.go # TargetRepository (6 methods)
├── agent.go # AgentRepository (7 methods)
├── job.go # JobRepository (9 methods)
├── policy.go # PolicyRepository (7 methods)
├── audit.go # AuditRepository (2 methods)
├── notification.go # NotificationRepository (3 methods)
├── team.go # TeamRepository (5 methods)
└── owner.go # OwnerRepository (5 methods)
Key Implementation Details
Database Connection (db.go)
-
NewDB(connStr string)- Opens PostgreSQL connection with connection pooling- Max open connections: 25
- Max idle connections: 5
- Verifies connection with Ping()
-
RunMigrations(db, migrationsPath)- Executes SQL migration files- Reads all
.sqlfiles from migrations directory - Executes files in alphabetical order
- Simple approach without external migration library
- Reads all
Data Patterns Used
- UUID Generation: Using
github.com/google/uuidfor ID generation - Parameterized Queries: All queries use
$1, $2, etc.parameter placeholders - Context Propagation: All database operations use
*Contextvariants - Nullable Types:
sql.NullTimefor optional timestampssql.NullStringfor optional strings
- JSON Handling:
json.Marshal/Unmarshalfor JSONB columns- Config fields stored as
json.RawMessage
- Array Handling:
pq.Array()for storing Go slices in PostgreSQL arrayspq.StringArrayfor scanning string arrays
- RETURNING Clauses: Used in CREATE operations to retrieve generated IDs
Error Handling
- All errors wrapped with
fmt.Errorffor context - Specific error messages for not found cases
- Row count verification for UPDATE/DELETE operations
Repository Implementations
CertificateRepository (8 methods)
- Manages certificate lifecycle with filtering by status, environment, owner, team, issuer
- Pagination support (default 50, max 500 per page)
- Certificate versioning with history tracking
- Expiration tracking and notifications
- Tags stored as JSON
IssuerRepository (5 methods)
- Manages certificate authorities (ACME, GenericCA)
- Configuration stored as JSON for flexibility
- Enable/disable issuers
TargetRepository (6 methods)
- Manages deployment targets (NGINX, F5, IIS)
- Lists targets associated with certificates via join table
- Configuration stored as JSON
AgentRepository (7 methods)
- Manages control plane agents with status tracking
- Heartbeat update functionality
- API key hash lookup for authentication
- Last heartbeat timestamp tracking
JobRepository (9 methods)
- Manages renewal, deployment, issuance, and validation jobs
- Status tracking with error messages
- Attempt counters for retry logic
- Pending job retrieval by type
- Filtering by status and certificate
PolicyRepository (7 methods)
- Policy rules with multiple enforcement types
- Policy violation recording and querying
- Configurable rules stored as JSON
- Severity levels for violations (Warning, Error, Critical)
AuditRepository (2 methods)
- Records all control plane actions
- Filtering by actor, resource type, time range
- Pagination support
- Details stored as JSON
NotificationRepository (3 methods)
- Notification event tracking
- Multiple channels (Email, Webhook, Slack)
- Delivery status tracking
- Certificate-specific notification filtering
TeamRepository (5 methods)
- Organizational unit management
- Basic CRUD operations
- Team descriptions for organization
OwnerRepository (5 methods)
- Certificate owner management
- Email field for notifications
- Team affiliation tracking
- Basic CRUD operations
Database Assumptions
The implementation expects the following table structures:
certificates
- id, name, common_name, sans (array), environment, owner_id, team_id, issuer_id
- status, expires_at, tags (json), last_renewal_at, last_deployment_at
- created_at, updated_at
certificate_versions
- id, certificate_id, serial_number, not_before, not_after
- fingerprint_sha256, pem_chain, csr_pem, created_at
certificate_target_mappings (join table)
- certificate_id, target_id
issuers
- id, name, type, config (json), enabled, created_at, updated_at
deployment_targets
- id, name, type, agent_id, config (json), enabled, created_at, updated_at
agents
- id, name, hostname, status, last_heartbeat_at, registered_at, api_key_hash
jobs
- id, type, certificate_id, target_id, status, attempts, max_attempts
- last_error, scheduled_at, started_at, completed_at, created_at
policy_rules
- id, name, type, config (json), enabled, created_at, updated_at
policy_violations
- id, certificate_id, rule_id, message, severity, created_at
audit_events
- id, actor, actor_type, action, resource_type, resource_id, details (json), timestamp
notifications
- id, type, certificate_id, channel, recipient, message, sent_at, status, error, created_at
teams
- id, name, description, created_at, updated_at
owners
- id, name, email, team_id, created_at, updated_at
Integration Points
Constructor functions for each repository:
NewCertificateRepository(db *sql.DB) *CertificateRepository
NewIssuerRepository(db *sql.DB) *IssuerRepository
NewTargetRepository(db *sql.DB) *TargetRepository
NewAgentRepository(db *sql.DB) *AgentRepository
NewJobRepository(db *sql.DB) *JobRepository
NewPolicyRepository(db *sql.DB) *PolicyRepository
NewAuditRepository(db *sql.DB) *AuditRepository
NewNotificationRepository(db *sql.DB) *NotificationRepository
NewTeamRepository(db *sql.DB) *TeamRepository
NewOwnerRepository(db *sql.DB) *OwnerRepository
Dependencies
database/sql(stdlib)github.com/lib/pqv1.10.9github.com/google/uuidv1.6.0
Notes
- All list operations support pagination with configurable page size (default 50, max 500)
- Filtering is dynamic - only conditions with non-empty values are added to WHERE clause
- Timestamps use
time.Timefor CreatedAt/UpdatedAt with automatic Now() on updates - Array fields use
pq.Array()for proper PostgreSQL array handling - Nullable fields use
sql.Null*types for proper NULL handling - All operations are context-aware and respect cancellation signals
- Error messages are descriptive and wrapped for debugging