mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-10 15:38:56 +00:00
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 71b2245) 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.
This commit is contained in:
@@ -12,16 +12,16 @@ import (
|
||||
|
||||
// mockAgentGroupRepo is a test implementation of AgentGroupRepository
|
||||
type mockAgentGroupRepo struct {
|
||||
groups map[string]*domain.AgentGroup
|
||||
members map[string][]*domain.Agent
|
||||
CreateErr error
|
||||
UpdateErr error
|
||||
DeleteErr error
|
||||
GetErr error
|
||||
ListErr error
|
||||
ListMembersErr error
|
||||
AddMemberErr error
|
||||
RemoveMemberErr error
|
||||
groups map[string]*domain.AgentGroup
|
||||
members map[string][]*domain.Agent
|
||||
CreateErr error
|
||||
UpdateErr error
|
||||
DeleteErr error
|
||||
GetErr error
|
||||
ListErr error
|
||||
ListMembersErr error
|
||||
AddMemberErr error
|
||||
RemoveMemberErr error
|
||||
}
|
||||
|
||||
func newMockAgentGroupRepository() *mockAgentGroupRepo {
|
||||
|
||||
@@ -109,9 +109,9 @@ func TestAgentService_UpdateJobStatus_DelegatesToReportJobStatus(t *testing.T) {
|
||||
svc, repo, _, jobRepo, _ := newTestAgentSvc(t)
|
||||
repo.Agents["a-1"] = &domain.Agent{ID: "a-1", Status: domain.AgentStatusOnline}
|
||||
jobRepo.Jobs["j-1"] = &domain.Job{
|
||||
ID: "j-1",
|
||||
AgentID: strPtr("a-1"),
|
||||
Status: domain.JobStatusRunning,
|
||||
ID: "j-1",
|
||||
AgentID: strPtr("a-1"),
|
||||
Status: domain.JobStatusRunning,
|
||||
}
|
||||
err := svc.UpdateJobStatus(context.Background(), "a-1", "j-1", "Completed", "")
|
||||
if err != nil {
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/shankar0123/certctl/internal/domain"
|
||||
)
|
||||
|
||||
|
||||
func TestRegisterAgent(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
agentRepo := &mockAgentRepo{
|
||||
|
||||
@@ -73,29 +73,29 @@ var credentialKeys = map[string]bool{
|
||||
// Note `ip_address` is debatable — useful for forensics but flagged by
|
||||
// GDPR Art. 32 — defaulting to redact, operators can audit + adjust.
|
||||
var piiKeys = map[string]bool{
|
||||
"email": true,
|
||||
"email_address": true,
|
||||
"phone": true,
|
||||
"phone_number": true,
|
||||
"telephone": true,
|
||||
"ssn": true,
|
||||
"email": true,
|
||||
"email_address": true,
|
||||
"phone": true,
|
||||
"phone_number": true,
|
||||
"telephone": true,
|
||||
"ssn": true,
|
||||
"social_security": true,
|
||||
"dob": true,
|
||||
"date_of_birth": true,
|
||||
"name": true,
|
||||
"full_name": true,
|
||||
"first_name": true,
|
||||
"last_name": true,
|
||||
"surname": true,
|
||||
"address": true,
|
||||
"street": true,
|
||||
"street_address": true,
|
||||
"city": true,
|
||||
"postal_code": true,
|
||||
"zip": true,
|
||||
"zipcode": true,
|
||||
"ip": true,
|
||||
"ip_address": true,
|
||||
"dob": true,
|
||||
"date_of_birth": true,
|
||||
"name": true,
|
||||
"full_name": true,
|
||||
"first_name": true,
|
||||
"last_name": true,
|
||||
"surname": true,
|
||||
"address": true,
|
||||
"street": true,
|
||||
"street_address": true,
|
||||
"city": true,
|
||||
"postal_code": true,
|
||||
"zip": true,
|
||||
"zipcode": true,
|
||||
"ip": true,
|
||||
"ip_address": true,
|
||||
}
|
||||
|
||||
// RedactDetailsForAudit walks a details map and returns a NEW map with
|
||||
|
||||
@@ -30,8 +30,8 @@ func TestRedactDetailsForAudit_CredentialKeys(t *testing.T) {
|
||||
for _, key := range cases {
|
||||
t.Run(key, func(t *testing.T) {
|
||||
in := map[string]interface{}{
|
||||
key: "sensitive-value-do-not-leak",
|
||||
"non_sensitive_id": "ok-public-id",
|
||||
key: "sensitive-value-do-not-leak",
|
||||
"non_sensitive_id": "ok-public-id",
|
||||
}
|
||||
out := RedactDetailsForAudit(in)
|
||||
if out[key] != "[REDACTED:CREDENTIAL]" {
|
||||
@@ -70,7 +70,7 @@ func TestRedactDetailsForAudit_NestedMap(t *testing.T) {
|
||||
in := map[string]interface{}{
|
||||
"resource_id": "iss-prod",
|
||||
"config": map[string]interface{}{
|
||||
"endpoint": "https://acme.example.com",
|
||||
"endpoint": "https://acme.example.com",
|
||||
"eab_secret": "do-not-leak-this-secret",
|
||||
"contact": map[string]interface{}{
|
||||
"email": "ops@example.com",
|
||||
@@ -159,8 +159,8 @@ func TestRedactDetailsForAudit_NoRedactionPath(t *testing.T) {
|
||||
// Maps with no sensitive keys should NOT have a redacted_keys array
|
||||
// — clutter-free for the common case.
|
||||
in := map[string]interface{}{
|
||||
"action": "create_certificate",
|
||||
"cert_id": "mc-prod-001",
|
||||
"action": "create_certificate",
|
||||
"cert_id": "mc-prod-001",
|
||||
"latency_ms": float64(42),
|
||||
}
|
||||
out := RedactDetailsForAudit(in)
|
||||
@@ -171,7 +171,7 @@ func TestRedactDetailsForAudit_NoRedactionPath(t *testing.T) {
|
||||
|
||||
func TestRedactDetailsForAudit_DoesNotMutateInput(t *testing.T) {
|
||||
in := map[string]interface{}{
|
||||
"api_key": "secret-do-not-leak",
|
||||
"api_key": "secret-do-not-leak",
|
||||
"resource": "iss-prod",
|
||||
}
|
||||
_ = RedactDetailsForAudit(in)
|
||||
@@ -197,8 +197,8 @@ func TestRedactDetailsForAudit_JSONRoundTrip(t *testing.T) {
|
||||
// The redacted map MUST round-trip through json.Marshal (the
|
||||
// AuditService persistence path). Catches type-assertion regressions.
|
||||
in := map[string]interface{}{
|
||||
"reason": "compromised-key",
|
||||
"api_key": "leak-me",
|
||||
"reason": "compromised-key",
|
||||
"api_key": "leak-me",
|
||||
"contacts": []interface{}{
|
||||
map[string]interface{}{"email": "ops@example.com"},
|
||||
},
|
||||
|
||||
@@ -67,8 +67,8 @@ func TestBulkReassign_HappyPath(t *testing.T) {
|
||||
func TestBulkReassign_SkipsAlreadyOwned(t *testing.T) {
|
||||
svc, certRepo, ownerRepo, _ := newBulkReassignmentTestService()
|
||||
addOwner(ownerRepo, "o-bob")
|
||||
addOwnedCert(certRepo, "mc-1", "o-bob", "") // already owned by target
|
||||
addOwnedCert(certRepo, "mc-2", "o-alice", "") // needs reassign
|
||||
addOwnedCert(certRepo, "mc-1", "o-bob", "") // already owned by target
|
||||
addOwnedCert(certRepo, "mc-2", "o-alice", "") // needs reassign
|
||||
|
||||
res, err := svc.BulkReassign(context.Background(),
|
||||
domain.BulkReassignmentRequest{
|
||||
|
||||
@@ -32,11 +32,11 @@ func newBulkRevocationTestService() (*BulkRevocationService, *mockCertRepo, *moc
|
||||
|
||||
func addTestCert(repo *mockCertRepo, id, status, issuerID string) {
|
||||
cert := &domain.ManagedCertificate{
|
||||
ID: id,
|
||||
ID: id,
|
||||
CommonName: id + ".example.com",
|
||||
Status: domain.CertificateStatus(status),
|
||||
IssuerID: issuerID,
|
||||
ExpiresAt: time.Now().AddDate(0, 6, 0),
|
||||
Status: domain.CertificateStatus(status),
|
||||
IssuerID: issuerID,
|
||||
ExpiresAt: time.Now().AddDate(0, 6, 0),
|
||||
}
|
||||
repo.AddCert(cert)
|
||||
// Add a version with serial number (needed by RevokeCertificateWithActor)
|
||||
@@ -54,13 +54,13 @@ func addTestCert(repo *mockCertRepo, id, status, issuerID string) {
|
||||
|
||||
func addTestCertWithProfile(repo *mockCertRepo, id, status, issuerID, profileID, ownerID string) {
|
||||
cert := &domain.ManagedCertificate{
|
||||
ID: id,
|
||||
CommonName: id + ".example.com",
|
||||
Status: domain.CertificateStatus(status),
|
||||
IssuerID: issuerID,
|
||||
ID: id,
|
||||
CommonName: id + ".example.com",
|
||||
Status: domain.CertificateStatus(status),
|
||||
IssuerID: issuerID,
|
||||
CertificateProfileID: profileID,
|
||||
OwnerID: ownerID,
|
||||
ExpiresAt: time.Now().AddDate(0, 6, 0),
|
||||
OwnerID: ownerID,
|
||||
ExpiresAt: time.Now().AddDate(0, 6, 0),
|
||||
}
|
||||
repo.AddCert(cert)
|
||||
repo.Versions[id] = []*domain.CertificateVersion{
|
||||
@@ -272,11 +272,11 @@ func TestBulkRevoke_PartialFailure(t *testing.T) {
|
||||
addTestCert(certRepo, "mc-1", "Active", "iss-local")
|
||||
// mc-2 is active but has NO version — RevokeCertificateWithActor will fail on GetLatestVersion
|
||||
cert2 := &domain.ManagedCertificate{
|
||||
ID: "mc-2",
|
||||
ID: "mc-2",
|
||||
CommonName: "mc-2.example.com",
|
||||
Status: domain.CertificateStatusActive,
|
||||
IssuerID: "iss-local",
|
||||
ExpiresAt: time.Now().AddDate(0, 6, 0),
|
||||
Status: domain.CertificateStatusActive,
|
||||
IssuerID: "iss-local",
|
||||
ExpiresAt: time.Now().AddDate(0, 6, 0),
|
||||
}
|
||||
certRepo.AddCert(cert2)
|
||||
// Don't add versions for mc-2 so GetLatestVersion returns errNotFound
|
||||
|
||||
@@ -266,17 +266,17 @@ func TestDeploymentService_ProcessDeploymentJob_Success(t *testing.T) {
|
||||
// Add agent with recent heartbeat
|
||||
now := time.Now()
|
||||
agent := &domain.Agent{
|
||||
ID: "agent-1",
|
||||
Name: "Test Agent",
|
||||
Hostname: "agent.example.com",
|
||||
Status: domain.AgentStatusOnline,
|
||||
LastHeartbeatAt: &now,
|
||||
RegisteredAt: time.Now(),
|
||||
APIKeyHash: "hash-1",
|
||||
OS: "linux",
|
||||
Architecture: "amd64",
|
||||
IPAddress: "192.168.1.1",
|
||||
Version: "1.0.0",
|
||||
ID: "agent-1",
|
||||
Name: "Test Agent",
|
||||
Hostname: "agent.example.com",
|
||||
Status: domain.AgentStatusOnline,
|
||||
LastHeartbeatAt: &now,
|
||||
RegisteredAt: time.Now(),
|
||||
APIKeyHash: "hash-1",
|
||||
OS: "linux",
|
||||
Architecture: "amd64",
|
||||
IPAddress: "192.168.1.1",
|
||||
Version: "1.0.0",
|
||||
}
|
||||
agentRepo.AddAgent(agent)
|
||||
|
||||
|
||||
+14
-14
@@ -31,20 +31,20 @@ type HTMLEmailSender interface {
|
||||
|
||||
// DigestData holds the aggregated data for a digest email.
|
||||
type DigestData struct {
|
||||
GeneratedAt time.Time `json:"generated_at"`
|
||||
TotalCertificates int64 `json:"total_certificates"`
|
||||
ExpiringCertificates int64 `json:"expiring_certificates"`
|
||||
ExpiredCertificates int64 `json:"expired_certificates"`
|
||||
RevokedCertificates int64 `json:"revoked_certificates"`
|
||||
ActiveAgents int64 `json:"active_agents"`
|
||||
OfflineAgents int64 `json:"offline_agents"`
|
||||
TotalAgents int64 `json:"total_agents"`
|
||||
PendingJobs int64 `json:"pending_jobs"`
|
||||
FailedJobs int64 `json:"failed_jobs"`
|
||||
CompletedJobs int64 `json:"completed_jobs"`
|
||||
ExpiringCerts []DigestCertEntry `json:"expiring_certs"`
|
||||
RecentFailures []DigestJobEntry `json:"recent_failures"`
|
||||
StatusCounts []DigestStatusCount `json:"status_counts"`
|
||||
GeneratedAt time.Time `json:"generated_at"`
|
||||
TotalCertificates int64 `json:"total_certificates"`
|
||||
ExpiringCertificates int64 `json:"expiring_certificates"`
|
||||
ExpiredCertificates int64 `json:"expired_certificates"`
|
||||
RevokedCertificates int64 `json:"revoked_certificates"`
|
||||
ActiveAgents int64 `json:"active_agents"`
|
||||
OfflineAgents int64 `json:"offline_agents"`
|
||||
TotalAgents int64 `json:"total_agents"`
|
||||
PendingJobs int64 `json:"pending_jobs"`
|
||||
FailedJobs int64 `json:"failed_jobs"`
|
||||
CompletedJobs int64 `json:"completed_jobs"`
|
||||
ExpiringCerts []DigestCertEntry `json:"expiring_certs"`
|
||||
RecentFailures []DigestJobEntry `json:"recent_failures"`
|
||||
StatusCounts []DigestStatusCount `json:"status_counts"`
|
||||
}
|
||||
|
||||
// DigestCertEntry represents a certificate entry in the digest.
|
||||
|
||||
@@ -12,17 +12,17 @@ import (
|
||||
|
||||
// mockDiscoveryRepo is a test implementation of DiscoveryRepository
|
||||
type mockDiscoveryRepo struct {
|
||||
Scans map[string]*domain.DiscoveryScan
|
||||
Discovered map[string]*domain.DiscoveredCertificate
|
||||
CreateScanErr error
|
||||
GetScanErr error
|
||||
ListScansErr error
|
||||
Scans map[string]*domain.DiscoveryScan
|
||||
Discovered map[string]*domain.DiscoveredCertificate
|
||||
CreateScanErr error
|
||||
GetScanErr error
|
||||
ListScansErr error
|
||||
CreateDiscoveredErr error
|
||||
GetDiscoveredErr error
|
||||
ListDiscoveredErr error
|
||||
UpdateStatusErr error
|
||||
GetDiscoveredErr error
|
||||
ListDiscoveredErr error
|
||||
UpdateStatusErr error
|
||||
GetByFingerprintErr error
|
||||
CountByStatusErr error
|
||||
CountByStatusErr error
|
||||
}
|
||||
|
||||
func newMockDiscoveryRepository() *mockDiscoveryRepo {
|
||||
@@ -268,20 +268,20 @@ func TestListDiscovered_Success(t *testing.T) {
|
||||
|
||||
now := time.Now()
|
||||
cert1 := &domain.DiscoveredCertificate{
|
||||
ID: "dcert-1",
|
||||
AgentID: "agent-1",
|
||||
CommonName: "example.com",
|
||||
Status: domain.DiscoveryStatusUnmanaged,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
ID: "dcert-1",
|
||||
AgentID: "agent-1",
|
||||
CommonName: "example.com",
|
||||
Status: domain.DiscoveryStatusUnmanaged,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
cert2 := &domain.DiscoveredCertificate{
|
||||
ID: "dcert-2",
|
||||
AgentID: "agent-1",
|
||||
CommonName: "api.example.com",
|
||||
Status: domain.DiscoveryStatusManaged,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
ID: "dcert-2",
|
||||
AgentID: "agent-1",
|
||||
CommonName: "api.example.com",
|
||||
Status: domain.DiscoveryStatusManaged,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
discoveryRepo.Discovered[cert1.ID] = cert1
|
||||
discoveryRepo.Discovered[cert2.ID] = cert2
|
||||
@@ -304,20 +304,20 @@ func TestListDiscovered_WithStatusFilter(t *testing.T) {
|
||||
|
||||
now := time.Now()
|
||||
cert1 := &domain.DiscoveredCertificate{
|
||||
ID: "dcert-1",
|
||||
AgentID: "agent-1",
|
||||
ID: "dcert-1",
|
||||
AgentID: "agent-1",
|
||||
CommonName: "example.com",
|
||||
Status: domain.DiscoveryStatusUnmanaged,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
Status: domain.DiscoveryStatusUnmanaged,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
cert2 := &domain.DiscoveredCertificate{
|
||||
ID: "dcert-2",
|
||||
AgentID: "agent-1",
|
||||
ID: "dcert-2",
|
||||
AgentID: "agent-1",
|
||||
CommonName: "api.example.com",
|
||||
Status: domain.DiscoveryStatusManaged,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
Status: domain.DiscoveryStatusManaged,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
discoveryRepo.Discovered[cert1.ID] = cert1
|
||||
discoveryRepo.Discovered[cert2.ID] = cert2
|
||||
@@ -340,11 +340,11 @@ func TestGetDiscovered_Success(t *testing.T) {
|
||||
|
||||
now := time.Now()
|
||||
cert := &domain.DiscoveredCertificate{
|
||||
ID: "dcert-1",
|
||||
CommonName: "example.com",
|
||||
Status: domain.DiscoveryStatusUnmanaged,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
ID: "dcert-1",
|
||||
CommonName: "example.com",
|
||||
Status: domain.DiscoveryStatusUnmanaged,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
discoveryRepo.Discovered[cert.ID] = cert
|
||||
|
||||
@@ -363,12 +363,12 @@ func TestClaimDiscovered_Success(t *testing.T) {
|
||||
|
||||
now := time.Now()
|
||||
discoveredCert := &domain.DiscoveredCertificate{
|
||||
ID: "dcert-1",
|
||||
CommonName: "example.com",
|
||||
FingerprintSHA256: "abc123",
|
||||
Status: domain.DiscoveryStatusUnmanaged,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
ID: "dcert-1",
|
||||
CommonName: "example.com",
|
||||
FingerprintSHA256: "abc123",
|
||||
Status: domain.DiscoveryStatusUnmanaged,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
discoveryRepo.Discovered[discoveredCert.ID] = discoveredCert
|
||||
|
||||
@@ -415,11 +415,11 @@ func TestClaimDiscovered_MissingManagedCertID(t *testing.T) {
|
||||
|
||||
now := time.Now()
|
||||
cert := &domain.DiscoveredCertificate{
|
||||
ID: "dcert-1",
|
||||
ID: "dcert-1",
|
||||
CommonName: "example.com",
|
||||
Status: domain.DiscoveryStatusUnmanaged,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
Status: domain.DiscoveryStatusUnmanaged,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
discoveryRepo.Discovered[cert.ID] = cert
|
||||
|
||||
@@ -434,11 +434,11 @@ func TestClaimDiscovered_ManagedCertNotFound(t *testing.T) {
|
||||
|
||||
now := time.Now()
|
||||
cert := &domain.DiscoveredCertificate{
|
||||
ID: "dcert-1",
|
||||
ID: "dcert-1",
|
||||
CommonName: "example.com",
|
||||
Status: domain.DiscoveryStatusUnmanaged,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
Status: domain.DiscoveryStatusUnmanaged,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
discoveryRepo.Discovered[cert.ID] = cert
|
||||
|
||||
@@ -456,11 +456,11 @@ func TestDismissDiscovered_Success(t *testing.T) {
|
||||
|
||||
now := time.Now()
|
||||
cert := &domain.DiscoveredCertificate{
|
||||
ID: "dcert-1",
|
||||
ID: "dcert-1",
|
||||
CommonName: "example.com",
|
||||
Status: domain.DiscoveryStatusUnmanaged,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
Status: domain.DiscoveryStatusUnmanaged,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
discoveryRepo.Discovered[cert.ID] = cert
|
||||
|
||||
|
||||
@@ -71,10 +71,10 @@ func TestExportPEM_Success(t *testing.T) {
|
||||
Status: domain.CertificateStatusActive,
|
||||
},
|
||||
&domain.CertificateVersion{
|
||||
ID: "cv-1",
|
||||
ID: "cv-1",
|
||||
CertificateID: "mc-test-1",
|
||||
SerialNumber: "abc123",
|
||||
PEMChain: fullPEM,
|
||||
SerialNumber: "abc123",
|
||||
PEMChain: fullPEM,
|
||||
},
|
||||
)
|
||||
auditSvc := &AuditService{auditRepo: &mockAuditRepo{}}
|
||||
|
||||
@@ -14,19 +14,19 @@ import (
|
||||
|
||||
// mockHealthCheckRepo implements the HealthCheckRepository interface for testing.
|
||||
type mockHealthCheckRepo struct {
|
||||
checks map[string]*domain.EndpointHealthCheck
|
||||
history []*domain.HealthHistoryEntry
|
||||
createErr error
|
||||
getErr error
|
||||
updateErr error
|
||||
deleteErr error
|
||||
listErr error
|
||||
listDueErr error
|
||||
getHistoryErr error
|
||||
recordHistoryErr error
|
||||
purgeHistoryErr error
|
||||
getSummaryErr error
|
||||
getSummaryResult *domain.HealthCheckSummary
|
||||
checks map[string]*domain.EndpointHealthCheck
|
||||
history []*domain.HealthHistoryEntry
|
||||
createErr error
|
||||
getErr error
|
||||
updateErr error
|
||||
deleteErr error
|
||||
listErr error
|
||||
listDueErr error
|
||||
getHistoryErr error
|
||||
recordHistoryErr error
|
||||
purgeHistoryErr error
|
||||
getSummaryErr error
|
||||
getSummaryResult *domain.HealthCheckSummary
|
||||
}
|
||||
|
||||
func newMockHealthCheckRepo() *mockHealthCheckRepo {
|
||||
@@ -151,9 +151,9 @@ func TestHealthCheckService_Create_Success(t *testing.T) {
|
||||
svc := NewHealthCheckService(repo, nil, logger, 10, 5*time.Second, 30*24*time.Hour, false)
|
||||
|
||||
check := &domain.EndpointHealthCheck{
|
||||
Endpoint: "example.com:443",
|
||||
Status: domain.HealthStatusUnknown,
|
||||
Enabled: true,
|
||||
Endpoint: "example.com:443",
|
||||
Status: domain.HealthStatusUnknown,
|
||||
Enabled: true,
|
||||
CheckIntervalSecs: 300,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"time"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/shankar0123/certctl/internal/domain"
|
||||
"github.com/shankar0123/certctl/internal/repository"
|
||||
|
||||
@@ -36,9 +36,9 @@ func mkRunningJob(id, agentID string) *domain.Job {
|
||||
a := agentID
|
||||
now := time.Now()
|
||||
return &domain.Job{
|
||||
ID: id,
|
||||
AgentID: &a,
|
||||
Status: domain.JobStatusRunning,
|
||||
ID: id,
|
||||
AgentID: &a,
|
||||
Status: domain.JobStatusRunning,
|
||||
CreatedAt: now.Add(-2 * time.Hour),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -871,8 +871,8 @@ func TestJobService_ReapTimedOutJobs_ContinuesOnIndividualUpdateFailure(t *testi
|
||||
jobA.ID: jobA,
|
||||
jobB.ID: jobB,
|
||||
},
|
||||
StatusUpdates: make(map[string]domain.JobStatus),
|
||||
UpdateErrorByID: make(map[string]error),
|
||||
StatusUpdates: make(map[string]domain.JobStatus),
|
||||
UpdateErrorByID: make(map[string]error),
|
||||
UpdateErrorByIDMu: sync.Mutex{},
|
||||
}
|
||||
// Make Update fail only for jobA
|
||||
@@ -892,7 +892,7 @@ func TestJobService_ReapTimedOutJobs_ContinuesOnIndividualUpdateFailure(t *testi
|
||||
jobAAfter := jobRepo.Jobs[jobA.ID]
|
||||
jobBAfter := jobRepo.Jobs[jobB.ID]
|
||||
if jobAAfter.Status != domain.JobStatusFailed || jobBAfter.Status != domain.JobStatusFailed {
|
||||
t.Fatalf("expected both jobs status Failed (modified before Update), got A=%s B=%s",
|
||||
t.Fatalf("expected both jobs status Failed (modified before Update), got A=%s B=%s",
|
||||
jobAAfter.Status, jobBAfter.Status)
|
||||
}
|
||||
|
||||
|
||||
@@ -377,8 +377,8 @@ func TestExpandCIDR_AllowsPrivateRanges(t *testing.T) {
|
||||
cidr string
|
||||
min int
|
||||
}{
|
||||
{"10/8 sample", "10.0.0.0/30", 2}, // 2 usable (after removing network/broadcast)
|
||||
{"172.16/12 sample", "172.16.0.0/30", 2}, // 2 usable
|
||||
{"10/8 sample", "10.0.0.0/30", 2}, // 2 usable (after removing network/broadcast)
|
||||
{"172.16/12 sample", "172.16.0.0/30", 2}, // 2 usable
|
||||
{"192.168/16 sample", "192.168.1.1/32", 1}, // Single IP
|
||||
}
|
||||
|
||||
|
||||
@@ -43,16 +43,16 @@ import "sync/atomic"
|
||||
// New labels MUST also be added to OCSPCounters.Snapshot AND to the
|
||||
// Prometheus exposer in Phase 8.
|
||||
type OCSPCounters struct {
|
||||
requestGET atomic.Uint64
|
||||
requestPOST atomic.Uint64
|
||||
requestSuccess atomic.Uint64
|
||||
requestInvalid atomic.Uint64
|
||||
issuerNotFound atomic.Uint64
|
||||
certNotFound atomic.Uint64
|
||||
signingFailed atomic.Uint64
|
||||
nonceEchoed atomic.Uint64
|
||||
nonceMalformed atomic.Uint64
|
||||
rateLimited atomic.Uint64
|
||||
requestGET atomic.Uint64
|
||||
requestPOST atomic.Uint64
|
||||
requestSuccess atomic.Uint64
|
||||
requestInvalid atomic.Uint64
|
||||
issuerNotFound atomic.Uint64
|
||||
certNotFound atomic.Uint64
|
||||
signingFailed atomic.Uint64
|
||||
nonceEchoed atomic.Uint64
|
||||
nonceMalformed atomic.Uint64
|
||||
rateLimited atomic.Uint64
|
||||
}
|
||||
|
||||
// NewOCSPCounters constructs a zero-value counter table. The caller
|
||||
|
||||
@@ -977,7 +977,7 @@ func TestCheckExpiringCertificates_ARI_ShouldRenewNow(t *testing.T) {
|
||||
ID: "rp-standard", Name: "Standard", RenewalWindowDays: 30,
|
||||
AutoRenew: true, MaxRetries: 3, RetryInterval: 300,
|
||||
AlertThresholdsDays: []int{30, 14, 7, 0},
|
||||
CreatedAt: time.Now(), UpdatedAt: time.Now(),
|
||||
CreatedAt: time.Now(), UpdatedAt: time.Now(),
|
||||
}
|
||||
policyRepo.AddPolicy(policy)
|
||||
|
||||
@@ -1050,7 +1050,7 @@ func TestCheckExpiringCertificates_ARI_NotYet(t *testing.T) {
|
||||
ID: "rp-standard", Name: "Standard", RenewalWindowDays: 30,
|
||||
AutoRenew: true, MaxRetries: 3, RetryInterval: 300,
|
||||
AlertThresholdsDays: []int{30, 14, 7, 0},
|
||||
CreatedAt: time.Now(), UpdatedAt: time.Now(),
|
||||
CreatedAt: time.Now(), UpdatedAt: time.Now(),
|
||||
}
|
||||
policyRepo.AddPolicy(policy)
|
||||
|
||||
@@ -1110,7 +1110,7 @@ func TestCheckExpiringCertificates_ARI_NilResult_FallsThrough(t *testing.T) {
|
||||
ID: "rp-standard", Name: "Standard", RenewalWindowDays: 30,
|
||||
AutoRenew: true, MaxRetries: 3, RetryInterval: 300,
|
||||
AlertThresholdsDays: []int{30, 14, 7, 0},
|
||||
CreatedAt: time.Now(), UpdatedAt: time.Now(),
|
||||
CreatedAt: time.Now(), UpdatedAt: time.Now(),
|
||||
}
|
||||
policyRepo.AddPolicy(policy)
|
||||
|
||||
@@ -1178,7 +1178,7 @@ func TestCheckExpiringCertificates_ARI_Error_FallsThrough(t *testing.T) {
|
||||
ID: "rp-standard", Name: "Standard", RenewalWindowDays: 30,
|
||||
AutoRenew: true, MaxRetries: 3, RetryInterval: 300,
|
||||
AlertThresholdsDays: []int{30, 14, 7, 0},
|
||||
CreatedAt: time.Now(), UpdatedAt: time.Now(),
|
||||
CreatedAt: time.Now(), UpdatedAt: time.Now(),
|
||||
}
|
||||
policyRepo.AddPolicy(policy)
|
||||
|
||||
@@ -1313,7 +1313,6 @@ func TestFailJob_SetsFailedStatus(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- CreateDeploymentJobs Tests ---
|
||||
|
||||
func TestCreateDeploymentJobs_PartialFailure(t *testing.T) {
|
||||
@@ -1331,10 +1330,10 @@ func TestCreateDeploymentJobs_PartialFailure(t *testing.T) {
|
||||
|
||||
// Create certificate
|
||||
cert := &domain.ManagedCertificate{
|
||||
ID: "mc-partial",
|
||||
ID: "mc-partial",
|
||||
CommonName: "test.example.com",
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
certRepo.AddCert(cert)
|
||||
|
||||
@@ -1383,5 +1382,4 @@ func TestCreateDeploymentJobs_PartialFailure(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// stringPtr is defined in notification_test.go
|
||||
|
||||
@@ -13,11 +13,11 @@ import (
|
||||
// RevocationSvc provides revocation-related business logic.
|
||||
// It handles certificate revocation, revocation notifications, and issuer coordination.
|
||||
type RevocationSvc struct {
|
||||
certRepo repository.CertificateRepository
|
||||
revocationRepo repository.RevocationRepository
|
||||
auditService *AuditService
|
||||
notificationSvc *NotificationService
|
||||
issuerRegistry *IssuerRegistry
|
||||
certRepo repository.CertificateRepository
|
||||
revocationRepo repository.RevocationRepository
|
||||
auditService *AuditService
|
||||
notificationSvc *NotificationService
|
||||
issuerRegistry *IssuerRegistry
|
||||
// ocspCacheInvalidator — production hardening II Phase 2 load-
|
||||
// bearing security wire. After a successful revocation, the
|
||||
// service MUST invalidate the OCSP response cache for this
|
||||
|
||||
@@ -48,31 +48,31 @@ func TestExpireShortLivedCertificates_Success(t *testing.T) {
|
||||
|
||||
// Create a short-lived profile (TTL < 1 hour = 3600 seconds)
|
||||
shortLivedProfile := &domain.CertificateProfile{
|
||||
ID: "prof-short",
|
||||
Name: "Short-Lived",
|
||||
MaxTTLSeconds: 300, // 5 minutes
|
||||
AllowShortLived: true,
|
||||
Enabled: true,
|
||||
ID: "prof-short",
|
||||
Name: "Short-Lived",
|
||||
MaxTTLSeconds: 300, // 5 minutes
|
||||
AllowShortLived: true,
|
||||
Enabled: true,
|
||||
AllowedKeyAlgorithms: domain.DefaultKeyAlgorithms(),
|
||||
AllowedEKUs: domain.DefaultEKUs(),
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
AllowedEKUs: domain.DefaultEKUs(),
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
profileRepo.AddProfile(shortLivedProfile)
|
||||
|
||||
// Create an active certificate that has already expired
|
||||
expiredCert := &domain.ManagedCertificate{
|
||||
ID: "mc-expired-short",
|
||||
Name: "Expired Short-Lived Cert",
|
||||
CommonName: "short.example.com",
|
||||
SANs: []string{},
|
||||
IssuerID: "iss-test",
|
||||
CertificateProfileID: "prof-short",
|
||||
Status: domain.CertificateStatusActive,
|
||||
ExpiresAt: now.Add(-5 * time.Minute), // Already expired
|
||||
CreatedAt: now.Add(-15 * time.Minute),
|
||||
UpdatedAt: now.Add(-5 * time.Minute),
|
||||
Tags: make(map[string]string),
|
||||
ID: "mc-expired-short",
|
||||
Name: "Expired Short-Lived Cert",
|
||||
CommonName: "short.example.com",
|
||||
SANs: []string{},
|
||||
IssuerID: "iss-test",
|
||||
CertificateProfileID: "prof-short",
|
||||
Status: domain.CertificateStatusActive,
|
||||
ExpiresAt: now.Add(-5 * time.Minute), // Already expired
|
||||
CreatedAt: now.Add(-15 * time.Minute),
|
||||
UpdatedAt: now.Add(-5 * time.Minute),
|
||||
Tags: make(map[string]string),
|
||||
}
|
||||
certRepo.AddCert(expiredCert)
|
||||
|
||||
@@ -218,31 +218,31 @@ func TestExpireShortLivedCertificates_PartialUpdateError(t *testing.T) {
|
||||
|
||||
// Create a short-lived profile
|
||||
shortLivedProfile := &domain.CertificateProfile{
|
||||
ID: "prof-short",
|
||||
Name: "Short-Lived",
|
||||
MaxTTLSeconds: 300,
|
||||
AllowShortLived: true,
|
||||
Enabled: true,
|
||||
ID: "prof-short",
|
||||
Name: "Short-Lived",
|
||||
MaxTTLSeconds: 300,
|
||||
AllowShortLived: true,
|
||||
Enabled: true,
|
||||
AllowedKeyAlgorithms: domain.DefaultKeyAlgorithms(),
|
||||
AllowedEKUs: domain.DefaultEKUs(),
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
AllowedEKUs: domain.DefaultEKUs(),
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
profileRepo.AddProfile(shortLivedProfile)
|
||||
|
||||
// Create a certificate with a failing update
|
||||
expiredCert := &domain.ManagedCertificate{
|
||||
ID: "mc-expired-fail",
|
||||
Name: "Expired Cert That Will Fail",
|
||||
CommonName: "fail.example.com",
|
||||
SANs: []string{},
|
||||
IssuerID: "iss-test",
|
||||
CertificateProfileID: "prof-short",
|
||||
Status: domain.CertificateStatusActive,
|
||||
ExpiresAt: now.Add(-5 * time.Minute),
|
||||
CreatedAt: now.Add(-15 * time.Minute),
|
||||
UpdatedAt: now.Add(-5 * time.Minute),
|
||||
Tags: make(map[string]string),
|
||||
ID: "mc-expired-fail",
|
||||
Name: "Expired Cert That Will Fail",
|
||||
CommonName: "fail.example.com",
|
||||
SANs: []string{},
|
||||
IssuerID: "iss-test",
|
||||
CertificateProfileID: "prof-short",
|
||||
Status: domain.CertificateStatusActive,
|
||||
ExpiresAt: now.Add(-5 * time.Minute),
|
||||
CreatedAt: now.Add(-15 * time.Minute),
|
||||
UpdatedAt: now.Add(-5 * time.Minute),
|
||||
Tags: make(map[string]string),
|
||||
}
|
||||
certRepo.AddCert(expiredCert)
|
||||
|
||||
@@ -275,31 +275,31 @@ func TestExpireShortLivedCertificates_AlreadyExpired(t *testing.T) {
|
||||
|
||||
// Create a short-lived profile
|
||||
shortLivedProfile := &domain.CertificateProfile{
|
||||
ID: "prof-short",
|
||||
Name: "Short-Lived",
|
||||
MaxTTLSeconds: 300,
|
||||
AllowShortLived: true,
|
||||
Enabled: true,
|
||||
ID: "prof-short",
|
||||
Name: "Short-Lived",
|
||||
MaxTTLSeconds: 300,
|
||||
AllowShortLived: true,
|
||||
Enabled: true,
|
||||
AllowedKeyAlgorithms: domain.DefaultKeyAlgorithms(),
|
||||
AllowedEKUs: domain.DefaultEKUs(),
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
AllowedEKUs: domain.DefaultEKUs(),
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
profileRepo.AddProfile(shortLivedProfile)
|
||||
|
||||
// Create a certificate that's already in Expired status
|
||||
alreadyExpiredCert := &domain.ManagedCertificate{
|
||||
ID: "mc-already-expired",
|
||||
Name: "Already Expired Cert",
|
||||
CommonName: "already-expired.example.com",
|
||||
SANs: []string{},
|
||||
IssuerID: "iss-test",
|
||||
CertificateProfileID: "prof-short",
|
||||
Status: domain.CertificateStatusExpired, // Already expired
|
||||
ExpiresAt: now.Add(-30 * time.Minute),
|
||||
CreatedAt: now.Add(-45 * time.Minute),
|
||||
UpdatedAt: now.Add(-10 * time.Minute),
|
||||
Tags: make(map[string]string),
|
||||
ID: "mc-already-expired",
|
||||
Name: "Already Expired Cert",
|
||||
CommonName: "already-expired.example.com",
|
||||
SANs: []string{},
|
||||
IssuerID: "iss-test",
|
||||
CertificateProfileID: "prof-short",
|
||||
Status: domain.CertificateStatusExpired, // Already expired
|
||||
ExpiresAt: now.Add(-30 * time.Minute),
|
||||
CreatedAt: now.Add(-45 * time.Minute),
|
||||
UpdatedAt: now.Add(-10 * time.Minute),
|
||||
Tags: make(map[string]string),
|
||||
}
|
||||
certRepo.AddCert(alreadyExpiredCert)
|
||||
|
||||
@@ -329,31 +329,31 @@ func TestExpireShortLivedCertificates_ProfileNotShortLived(t *testing.T) {
|
||||
|
||||
// Create a regular (not short-lived) profile with TTL > 1 hour
|
||||
regularProfile := &domain.CertificateProfile{
|
||||
ID: "prof-regular",
|
||||
Name: "Regular",
|
||||
MaxTTLSeconds: 86400, // 24 hours
|
||||
AllowShortLived: false,
|
||||
Enabled: true,
|
||||
ID: "prof-regular",
|
||||
Name: "Regular",
|
||||
MaxTTLSeconds: 86400, // 24 hours
|
||||
AllowShortLived: false,
|
||||
Enabled: true,
|
||||
AllowedKeyAlgorithms: domain.DefaultKeyAlgorithms(),
|
||||
AllowedEKUs: domain.DefaultEKUs(),
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
AllowedEKUs: domain.DefaultEKUs(),
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
profileRepo.AddProfile(regularProfile)
|
||||
|
||||
// Create an expired certificate with the regular profile
|
||||
expiredCert := &domain.ManagedCertificate{
|
||||
ID: "mc-expired-regular",
|
||||
Name: "Expired Regular Cert",
|
||||
CommonName: "regular.example.com",
|
||||
SANs: []string{},
|
||||
IssuerID: "iss-test",
|
||||
CertificateProfileID: "prof-regular",
|
||||
Status: domain.CertificateStatusActive,
|
||||
ExpiresAt: now.Add(-1 * time.Hour),
|
||||
CreatedAt: now.Add(-25 * time.Hour),
|
||||
UpdatedAt: now.Add(-1 * time.Hour),
|
||||
Tags: make(map[string]string),
|
||||
ID: "mc-expired-regular",
|
||||
Name: "Expired Regular Cert",
|
||||
CommonName: "regular.example.com",
|
||||
SANs: []string{},
|
||||
IssuerID: "iss-test",
|
||||
CertificateProfileID: "prof-regular",
|
||||
Status: domain.CertificateStatusActive,
|
||||
ExpiresAt: now.Add(-1 * time.Hour),
|
||||
CreatedAt: now.Add(-25 * time.Hour),
|
||||
UpdatedAt: now.Add(-1 * time.Hour),
|
||||
Tags: make(map[string]string),
|
||||
}
|
||||
certRepo.AddCert(expiredCert)
|
||||
|
||||
|
||||
+10
-10
@@ -22,16 +22,16 @@ var ErrAgentNotFound = errors.New("referenced agent does not exist")
|
||||
|
||||
// validTargetTypes is the set of allowed target types for validation.
|
||||
var validTargetTypes = map[domain.TargetType]bool{
|
||||
domain.TargetTypeNGINX: true,
|
||||
domain.TargetTypeApache: true,
|
||||
domain.TargetTypeHAProxy: true,
|
||||
domain.TargetTypeF5: true,
|
||||
domain.TargetTypeIIS: true,
|
||||
domain.TargetTypeTraefik: true,
|
||||
domain.TargetTypeCaddy: true,
|
||||
domain.TargetTypeEnvoy: true,
|
||||
domain.TargetTypePostfix: true,
|
||||
domain.TargetTypeDovecot: true,
|
||||
domain.TargetTypeNGINX: true,
|
||||
domain.TargetTypeApache: true,
|
||||
domain.TargetTypeHAProxy: true,
|
||||
domain.TargetTypeF5: true,
|
||||
domain.TargetTypeIIS: true,
|
||||
domain.TargetTypeTraefik: true,
|
||||
domain.TargetTypeCaddy: true,
|
||||
domain.TargetTypeEnvoy: true,
|
||||
domain.TargetTypePostfix: true,
|
||||
domain.TargetTypeDovecot: true,
|
||||
domain.TargetTypeSSH: true,
|
||||
domain.TargetTypeWinCertStore: true,
|
||||
domain.TargetTypeJavaKeystore: true,
|
||||
|
||||
@@ -11,9 +11,9 @@ import (
|
||||
|
||||
// VerificationService handles recording and querying certificate deployment verification results.
|
||||
type VerificationService struct {
|
||||
jobRepo repository.JobRepository
|
||||
auditService *AuditService
|
||||
logger *slog.Logger
|
||||
jobRepo repository.JobRepository
|
||||
auditService *AuditService
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
// NewVerificationService creates a new verification service.
|
||||
@@ -23,9 +23,9 @@ func NewVerificationService(
|
||||
logger *slog.Logger,
|
||||
) *VerificationService {
|
||||
return &VerificationService{
|
||||
jobRepo: jobRepo,
|
||||
auditService: auditService,
|
||||
logger: logger,
|
||||
jobRepo: jobRepo,
|
||||
auditService: auditService,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,11 +76,11 @@ func (s *VerificationService) RecordVerificationResult(ctx context.Context, resu
|
||||
// Record audit event
|
||||
auditEvent := "job_verification_success"
|
||||
auditDetails := map[string]interface{}{
|
||||
"job_id": result.JobID,
|
||||
"target_id": result.TargetID,
|
||||
"expected_fingerprint": result.ExpectedFingerprint,
|
||||
"actual_fingerprint": result.ActualFingerprint,
|
||||
"verified": result.Verified,
|
||||
"job_id": result.JobID,
|
||||
"target_id": result.TargetID,
|
||||
"expected_fingerprint": result.ExpectedFingerprint,
|
||||
"actual_fingerprint": result.ActualFingerprint,
|
||||
"verified": result.Verified,
|
||||
}
|
||||
|
||||
if result.Error != "" {
|
||||
@@ -114,7 +114,7 @@ func (s *VerificationService) GetVerificationResult(ctx context.Context, jobID s
|
||||
}
|
||||
|
||||
result := &domain.VerificationResult{
|
||||
JobID: job.ID,
|
||||
JobID: job.ID,
|
||||
Verified: job.VerificationStatus == domain.VerificationSuccess,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user