mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-13 22:18:57 +00:00
feat: M25 post-deployment TLS verification + M26 Traefik/Caddy targets
M25: After deploying a certificate, the agent probes the live TLS
endpoint and compares SHA-256 fingerprints to verify the correct cert
is being served. Best-effort — failures don't block deployments.
New endpoints: POST /jobs/{id}/verify, GET /jobs/{id}/verification.
Migration 000008 adds verification columns to jobs table.
M26: Traefik target connector (file provider, auto-reload) and Caddy
target connector (dual-mode: admin API hot-reload or file-based).
Both wired into agent dispatch.
Also: restructured README to highlight supported integrations (issuers,
targets, notifiers) earlier, moved API/CLI/MCP sections lower. Updated
all docs (features, connectors, architecture, testing guide, why-certctl)
and fixed integration tests for 18-param RegisterHandlers signature.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestVerificationStatus_Constants(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
status VerificationStatus
|
||||
expected string
|
||||
}{
|
||||
{"Pending", VerificationPending, "pending"},
|
||||
{"Success", VerificationSuccess, "success"},
|
||||
{"Failed", VerificationFailed, "failed"},
|
||||
{"Skipped", VerificationSkipped, "skipped"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if string(tt.status) != tt.expected {
|
||||
t.Errorf("expected %s, got %s", tt.expected, string(tt.status))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerificationResult_Marshaling(t *testing.T) {
|
||||
now := time.Now().UTC()
|
||||
result := &VerificationResult{
|
||||
JobID: "j-test123",
|
||||
TargetID: "t-nginx1",
|
||||
ExpectedFingerprint: "abc123def456",
|
||||
ActualFingerprint: "abc123def456",
|
||||
Verified: true,
|
||||
VerifiedAt: now,
|
||||
Error: "",
|
||||
}
|
||||
|
||||
if result.JobID != "j-test123" {
|
||||
t.Errorf("JobID mismatch: got %s", result.JobID)
|
||||
}
|
||||
if !result.Verified {
|
||||
t.Error("expected Verified to be true")
|
||||
}
|
||||
if result.Error != "" {
|
||||
t.Errorf("expected no error, got %s", result.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerificationResult_WithError(t *testing.T) {
|
||||
now := time.Now().UTC()
|
||||
result := &VerificationResult{
|
||||
JobID: "j-test456",
|
||||
TargetID: "t-apache1",
|
||||
ExpectedFingerprint: "aaa111bbb222",
|
||||
ActualFingerprint: "ccc333ddd444",
|
||||
Verified: false,
|
||||
VerifiedAt: now,
|
||||
Error: "connection timeout",
|
||||
}
|
||||
|
||||
if result.Verified {
|
||||
t.Error("expected Verified to be false")
|
||||
}
|
||||
if result.Error != "connection timeout" {
|
||||
t.Errorf("expected error message, got %s", result.Error)
|
||||
}
|
||||
if result.ExpectedFingerprint == result.ActualFingerprint {
|
||||
t.Error("expected fingerprints to differ")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user