Files
certctl/internal/domain/certificate_test.go
shankar0123 7cb453a336 chore(fmt): repo-wide gofmt -w sweep — close drift surfaced by ci-pipeline-cleanup Phase 4
Mechanical reformat. The new 'gofmt drift' CI step (added in
ci-pipeline-cleanup Phase 4, commit 0f205a8) surfaced 111 files
with accumulated gofmt drift across cmd/, internal/, and deploy/test/.

Each file's diff is gofmt-standard: whitespace adjustments, intra-
group import sorting (alphabetical by import path within blank-line-
separated groups), and struct-tag column alignment. No semantic
changes — verified via 'git diff --ignore-all-space' which shows only
the line-position deltas from import reordering.

The gate stays in place after this commit. Going forward it catches
gofmt drift at PR time.
2026-04-30 22:33:57 +00:00

207 lines
7.0 KiB
Go

package domain
import "testing"
func TestCertificateStatus_Constants(t *testing.T) {
tests := map[string]CertificateStatus{
"Pending": CertificateStatusPending,
"Active": CertificateStatusActive,
"Expiring": CertificateStatusExpiring,
"Expired": CertificateStatusExpired,
"RenewalInProgress": CertificateStatusRenewalInProgress,
"Failed": CertificateStatusFailed,
"Revoked": CertificateStatusRevoked,
"Archived": CertificateStatusArchived,
}
for expected, got := range tests {
if string(got) != expected {
t.Errorf("expected %q, got %q", expected, string(got))
}
}
}
func TestDefaultAlertThresholds(t *testing.T) {
defaults := DefaultAlertThresholds()
expected := []int{30, 14, 7, 0}
if len(defaults) != len(expected) {
t.Errorf("expected %d thresholds, got %d", len(expected), len(defaults))
}
for i, v := range expected {
if i >= len(defaults) {
break
}
if defaults[i] != v {
t.Errorf("threshold[%d]: expected %d, got %d", i, v, defaults[i])
}
}
}
func TestRenewalPolicy_EffectiveAlertThresholds_Custom(t *testing.T) {
policy := &RenewalPolicy{
AlertThresholdsDays: []int{60, 30, 14, 7},
}
result := policy.EffectiveAlertThresholds()
if len(result) != 4 {
t.Errorf("expected 4 thresholds, got %d", len(result))
}
if result[0] != 60 {
t.Errorf("expected first threshold 60, got %d", result[0])
}
}
func TestRenewalPolicy_EffectiveAlertThresholds_Default(t *testing.T) {
policy := &RenewalPolicy{
AlertThresholdsDays: []int{},
}
result := policy.EffectiveAlertThresholds()
expected := DefaultAlertThresholds()
if len(result) != len(expected) {
t.Errorf("expected %d thresholds, got %d", len(expected), len(result))
}
for i, v := range expected {
if i >= len(result) {
break
}
if result[i] != v {
t.Errorf("threshold[%d]: expected %d, got %d", i, v, result[i])
}
}
}
func TestRenewalPolicy_EffectiveAlertThresholds_Nil(t *testing.T) {
policy := &RenewalPolicy{
AlertThresholdsDays: nil,
}
result := policy.EffectiveAlertThresholds()
expected := DefaultAlertThresholds()
if len(result) != len(expected) {
t.Errorf("expected %d thresholds, got %d", len(expected), len(result))
}
}
// --- 45-Day / Short-Lived Certificate Renewal Threshold Tests ---
// These tests validate that certctl's renewal logic works correctly with shorter-lived
// certificates as the industry transitions from 90-day to 45-day validity (SC-081v3)
// and Let's Encrypt introduces 6-day "shortlived" profiles.
func TestRenewalThresholds_45DayCert(t *testing.T) {
// A 45-day cert with default thresholds [30, 14, 7, 0]:
// - 30-day alert fires when cert is 15 days old (45 - 30 = 15 days remaining)
// - 14-day alert fires when cert is 31 days old
// - 7-day alert fires when cert is 38 days old
// - 0-day alert fires at expiry
// The 30-day threshold fires at the 1/3 lifetime mark — this is correct
// (Let's Encrypt recommends renewal at 2/3 through lifetime, i.e. day 30).
thresholds := DefaultAlertThresholds()
certLifetimeDays := 45
for _, threshold := range thresholds {
daysCertAge := certLifetimeDays - threshold
if daysCertAge < 0 {
t.Errorf("threshold %d days exceeds cert lifetime %d days", threshold, certLifetimeDays)
}
}
// Verify the first alert (30 days) fires when 15 days remain
// This means the cert is 15 days old — at 1/3 of its lifetime
firstAlertDaysRemaining := certLifetimeDays - (certLifetimeDays - thresholds[0])
if firstAlertDaysRemaining != 30 {
t.Errorf("expected first alert at 30 days remaining, got %d", firstAlertDaysRemaining)
}
// The renewal window query (31 days ahead) will find 45-day certs
// when they have 31 or fewer days remaining — at day 14 of a 45-day cert.
renewalWindowDays := 31
certAgeAtRenewalCheck := certLifetimeDays - renewalWindowDays
if certAgeAtRenewalCheck != 14 {
t.Errorf("expected renewal check to find cert at age %d, got %d", 14, certAgeAtRenewalCheck)
}
}
func TestRenewalThresholds_6DayCert(t *testing.T) {
// A 6-day "shortlived" cert with default thresholds [30, 14, 7, 0]:
// - The 30-day, 14-day, and 7-day thresholds can NEVER fire (cert expires before reaching them)
// - Only the 0-day threshold fires at expiry
// For 6-day certs, ARI (RFC 9773) is the expected renewal path — the CA directs timing.
// Short-lived certs also skip CRL/OCSP (revocation via expiry, per M15b).
thresholds := DefaultAlertThresholds()
certLifetimeDays := 6
firingThresholds := 0
for _, threshold := range thresholds {
if threshold < certLifetimeDays {
firingThresholds++
}
}
// Only the 0-day threshold can fire (0 < 6).
// The 7-day threshold means "alert when 7 days remain" — a 6-day cert
// never has 7 days remaining, so it never fires.
// For 6-day certs, ARI (RFC 9773) is the expected renewal path.
if firingThresholds != 1 {
t.Errorf("expected 1 threshold to fire for 6-day cert, got %d", firingThresholds)
}
// The renewal window query (31 days ahead) will find 6-day certs immediately
// (they're always within the 31-day window from the moment they're issued).
renewalWindowDays := 31
if certLifetimeDays < renewalWindowDays {
// This is expected — 6-day certs are always in the renewal window.
// ARI should override the threshold-based logic for these certs.
}
}
func TestRenewalThresholds_47DayCert(t *testing.T) {
// SC-081v3 mandates 47-day max validity by March 2029.
// Default thresholds [30, 14, 7, 0] should work correctly.
thresholds := DefaultAlertThresholds()
certLifetimeDays := 47
for _, threshold := range thresholds {
if threshold > certLifetimeDays {
t.Errorf("threshold %d exceeds cert lifetime %d", threshold, certLifetimeDays)
}
}
// With RenewalWindowDays=30, renewal triggers at day 17 (47-30=17).
// That's at the 36% mark of the cert's lifetime — reasonable.
renewalWindowDays := 30
renewalDay := certLifetimeDays - renewalWindowDays
if renewalDay != 17 {
t.Errorf("expected renewal at day 17, got %d", renewalDay)
}
}
func TestRenewalThresholds_200DayCert(t *testing.T) {
// SC-081v3 Phase 1: 200-day max validity (March 2026).
// All default thresholds should fire normally.
thresholds := DefaultAlertThresholds()
certLifetimeDays := 200
for _, threshold := range thresholds {
if threshold > certLifetimeDays {
t.Errorf("threshold %d exceeds cert lifetime %d", threshold, certLifetimeDays)
}
}
}
func TestRenewalThresholds_100DayCert(t *testing.T) {
// SC-081v3 Phase 2: 100-day max validity (March 2027).
thresholds := DefaultAlertThresholds()
certLifetimeDays := 100
for _, threshold := range thresholds {
if threshold > certLifetimeDays {
t.Errorf("threshold %d exceeds cert lifetime %d", threshold, certLifetimeDays)
}
}
// With default 31-day renewal window, renewal triggers at day 69 — at 69% of lifetime.
// This is close to Let's Encrypt's recommended 2/3 mark.
renewalWindowDays := 31
renewalDay := certLifetimeDays - renewalWindowDays
if renewalDay != 69 {
t.Errorf("expected renewal at day 69, got %d", renewalDay)
}
}