mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 12:41:30 +00:00
2497be496d
- Add ctx first param to 21 service-layer handler-interface methods
across policy.go (6), profile.go (5), owner.go (5), team.go (5)
- Replace 24 context.Background() call sites with received ctx; use
context.WithoutCancel(ctx) for subsidiary audit-recording ops to
preserve fire-and-forget audit semantics without inheriting caller
cancellation
- Add ctx first param to 21 handler-interface method signatures across
policies.go (6), profiles.go (5), owners.go (5), teams.go (5)
- Thread r.Context() through 21 HTTP handler sites (ListPolicies,
GetPolicy, CreatePolicy, UpdatePolicy, DeletePolicy, ListViolations,
ListProfiles, GetProfile, CreateProfile, UpdateProfile, DeleteProfile,
ListOwners, GetOwner, CreateOwner, UpdateOwner, DeleteOwner,
ListTeams, GetTeam, CreateTeam, UpdateTeam, DeleteTeam)
- Update MockPolicyService/MockProfileService/MockOwnerService/
MockTeamService mock method impls with _ context.Context first param
(Fn fields unchanged — closures do not need ctx); update mock impls
in integration/lifecycle_test.go for all four services
- Update 12 service-layer test callsites (policy_test.go ×2,
owner_test.go ×5, team_test.go ×5, profile_test.go ×13) to pass
context.Background() at the call site
Audit complete. Commit: 1f6cf0eafa. Sections: 12. Findings: 2/7/10/4/6.
423 lines
10 KiB
Go
423 lines
10 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/shankar0123/certctl/internal/domain"
|
|
)
|
|
|
|
func TestCreateRule(t *testing.T) {
|
|
ctx := context.Background()
|
|
policyRepo := &mockPolicyRepo{
|
|
Rules: make(map[string]*domain.PolicyRule),
|
|
Violations: []*domain.PolicyViolation{},
|
|
}
|
|
auditRepo := &mockAuditRepo{Events: []*domain.AuditEvent{}}
|
|
auditService := NewAuditService(auditRepo)
|
|
|
|
policyService := NewPolicyService(policyRepo, auditService)
|
|
|
|
config := map[string]interface{}{"issuers": []string{"iss-acme"}}
|
|
configJSON, _ := json.Marshal(config)
|
|
|
|
rule := &domain.PolicyRule{
|
|
ID: "rule-001",
|
|
Name: "Allowed Issuers",
|
|
Type: domain.PolicyTypeAllowedIssuers,
|
|
Config: configJSON,
|
|
Enabled: true,
|
|
}
|
|
|
|
err := policyService.CreateRule(ctx, rule, "user-1")
|
|
if err != nil {
|
|
t.Fatalf("CreateRule failed: %v", err)
|
|
}
|
|
|
|
if len(policyRepo.Rules) != 1 {
|
|
t.Errorf("expected 1 rule, got %d", len(policyRepo.Rules))
|
|
}
|
|
|
|
if len(auditRepo.Events) != 1 {
|
|
t.Errorf("expected 1 audit event, got %d", len(auditRepo.Events))
|
|
}
|
|
}
|
|
|
|
func TestGetRule(t *testing.T) {
|
|
ctx := context.Background()
|
|
now := time.Now()
|
|
rule := &domain.PolicyRule{
|
|
ID: "rule-001",
|
|
Name: "Allowed Issuers",
|
|
Type: domain.PolicyTypeAllowedIssuers,
|
|
Enabled: true,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}
|
|
|
|
policyRepo := &mockPolicyRepo{
|
|
Rules: map[string]*domain.PolicyRule{"rule-001": rule},
|
|
Violations: []*domain.PolicyViolation{},
|
|
}
|
|
auditRepo := &mockAuditRepo{}
|
|
auditService := NewAuditService(auditRepo)
|
|
|
|
policyService := NewPolicyService(policyRepo, auditService)
|
|
|
|
retrieved, err := policyService.GetRule(ctx, "rule-001")
|
|
if err != nil {
|
|
t.Fatalf("GetRule failed: %v", err)
|
|
}
|
|
|
|
if retrieved.Name != "Allowed Issuers" {
|
|
t.Errorf("expected name Allowed Issuers, got %s", retrieved.Name)
|
|
}
|
|
}
|
|
|
|
func TestGetRule_NotFound(t *testing.T) {
|
|
ctx := context.Background()
|
|
policyRepo := &mockPolicyRepo{
|
|
Rules: make(map[string]*domain.PolicyRule),
|
|
Violations: []*domain.PolicyViolation{},
|
|
}
|
|
auditRepo := &mockAuditRepo{}
|
|
auditService := NewAuditService(auditRepo)
|
|
|
|
policyService := NewPolicyService(policyRepo, auditService)
|
|
|
|
_, err := policyService.GetRule(ctx, "nonexistent")
|
|
if err == nil {
|
|
t.Fatal("expected error for nonexistent rule")
|
|
}
|
|
}
|
|
|
|
func TestListRules(t *testing.T) {
|
|
ctx := context.Background()
|
|
now := time.Now()
|
|
|
|
rule1 := &domain.PolicyRule{
|
|
ID: "rule-001",
|
|
Name: "Allowed Issuers",
|
|
Type: domain.PolicyTypeAllowedIssuers,
|
|
Enabled: true,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}
|
|
rule2 := &domain.PolicyRule{
|
|
ID: "rule-002",
|
|
Name: "Required Metadata",
|
|
Type: domain.PolicyTypeRequiredMetadata,
|
|
Enabled: true,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}
|
|
|
|
policyRepo := &mockPolicyRepo{
|
|
Rules: map[string]*domain.PolicyRule{"rule-001": rule1, "rule-002": rule2},
|
|
Violations: []*domain.PolicyViolation{},
|
|
}
|
|
auditRepo := &mockAuditRepo{}
|
|
auditService := NewAuditService(auditRepo)
|
|
|
|
policyService := NewPolicyService(policyRepo, auditService)
|
|
|
|
rules, err := policyService.ListRules(ctx)
|
|
if err != nil {
|
|
t.Fatalf("ListRules failed: %v", err)
|
|
}
|
|
|
|
if len(rules) != 2 {
|
|
t.Errorf("expected 2 rules, got %d", len(rules))
|
|
}
|
|
}
|
|
|
|
func TestUpdateRule(t *testing.T) {
|
|
ctx := context.Background()
|
|
now := time.Now()
|
|
|
|
originalRule := &domain.PolicyRule{
|
|
ID: "rule-001",
|
|
Name: "Allowed Issuers",
|
|
Type: domain.PolicyTypeAllowedIssuers,
|
|
Enabled: true,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}
|
|
|
|
policyRepo := &mockPolicyRepo{
|
|
Rules: map[string]*domain.PolicyRule{"rule-001": originalRule},
|
|
Violations: []*domain.PolicyViolation{},
|
|
}
|
|
auditRepo := &mockAuditRepo{Events: []*domain.AuditEvent{}}
|
|
auditService := NewAuditService(auditRepo)
|
|
|
|
policyService := NewPolicyService(policyRepo, auditService)
|
|
|
|
updatedRule := *originalRule
|
|
updatedRule.Enabled = false
|
|
|
|
err := policyService.UpdateRule(ctx, &updatedRule, "user-1")
|
|
if err != nil {
|
|
t.Fatalf("UpdateRule failed: %v", err)
|
|
}
|
|
|
|
stored := policyRepo.Rules["rule-001"]
|
|
if stored.Enabled {
|
|
t.Error("expected rule to be disabled")
|
|
}
|
|
|
|
if len(auditRepo.Events) != 1 {
|
|
t.Errorf("expected 1 audit event, got %d", len(auditRepo.Events))
|
|
}
|
|
}
|
|
|
|
func TestDeleteRule(t *testing.T) {
|
|
ctx := context.Background()
|
|
now := time.Now()
|
|
|
|
rule := &domain.PolicyRule{
|
|
ID: "rule-001",
|
|
Name: "Allowed Issuers",
|
|
Type: domain.PolicyTypeAllowedIssuers,
|
|
Enabled: true,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}
|
|
|
|
policyRepo := &mockPolicyRepo{
|
|
Rules: map[string]*domain.PolicyRule{"rule-001": rule},
|
|
Violations: []*domain.PolicyViolation{},
|
|
}
|
|
auditRepo := &mockAuditRepo{Events: []*domain.AuditEvent{}}
|
|
auditService := NewAuditService(auditRepo)
|
|
|
|
policyService := NewPolicyService(policyRepo, auditService)
|
|
|
|
err := policyService.DeleteRule(ctx, "rule-001", "user-1")
|
|
if err != nil {
|
|
t.Fatalf("DeleteRule failed: %v", err)
|
|
}
|
|
|
|
if len(policyRepo.Rules) != 0 {
|
|
t.Errorf("expected 0 rules, got %d", len(policyRepo.Rules))
|
|
}
|
|
|
|
if len(auditRepo.Events) != 1 {
|
|
t.Errorf("expected 1 audit event, got %d", len(auditRepo.Events))
|
|
}
|
|
}
|
|
|
|
func TestValidateCertificate(t *testing.T) {
|
|
ctx := context.Background()
|
|
now := time.Now()
|
|
|
|
rule := &domain.PolicyRule{
|
|
ID: "rule-001",
|
|
Name: "Allowed Issuers",
|
|
Type: domain.PolicyTypeAllowedIssuers,
|
|
Enabled: true,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}
|
|
|
|
policyRepo := &mockPolicyRepo{
|
|
Rules: map[string]*domain.PolicyRule{"rule-001": rule},
|
|
Violations: []*domain.PolicyViolation{},
|
|
}
|
|
auditRepo := &mockAuditRepo{}
|
|
auditService := NewAuditService(auditRepo)
|
|
|
|
policyService := NewPolicyService(policyRepo, auditService)
|
|
|
|
cert := &domain.ManagedCertificate{
|
|
ID: "cert-001",
|
|
CommonName: "example.com",
|
|
IssuerID: "iss-acme",
|
|
Status: domain.CertificateStatusActive,
|
|
ExpiresAt: now.AddDate(1, 0, 0),
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}
|
|
|
|
violations, err := policyService.ValidateCertificate(ctx, cert)
|
|
if err != nil {
|
|
t.Fatalf("ValidateCertificate failed: %v", err)
|
|
}
|
|
|
|
if len(violations) > 0 {
|
|
t.Errorf("expected no violations, got %d", len(violations))
|
|
}
|
|
}
|
|
|
|
func TestValidateCertificate_WithViolation(t *testing.T) {
|
|
ctx := context.Background()
|
|
now := time.Now()
|
|
|
|
rule := &domain.PolicyRule{
|
|
ID: "rule-001",
|
|
Name: "Allowed Issuers",
|
|
Type: domain.PolicyTypeAllowedIssuers,
|
|
Enabled: true,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}
|
|
|
|
policyRepo := &mockPolicyRepo{
|
|
Rules: map[string]*domain.PolicyRule{"rule-001": rule},
|
|
Violations: []*domain.PolicyViolation{},
|
|
}
|
|
auditRepo := &mockAuditRepo{}
|
|
auditService := NewAuditService(auditRepo)
|
|
|
|
policyService := NewPolicyService(policyRepo, auditService)
|
|
|
|
cert := &domain.ManagedCertificate{
|
|
ID: "cert-001",
|
|
CommonName: "example.com",
|
|
IssuerID: "", // Missing issuer
|
|
Status: domain.CertificateStatusActive,
|
|
ExpiresAt: now.AddDate(1, 0, 0),
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}
|
|
|
|
violations, err := policyService.ValidateCertificate(ctx, cert)
|
|
if err != nil {
|
|
t.Fatalf("ValidateCertificate failed: %v", err)
|
|
}
|
|
|
|
if len(violations) != 1 {
|
|
t.Errorf("expected 1 violation, got %d", len(violations))
|
|
}
|
|
|
|
if violations[0].CertificateID != "cert-001" {
|
|
t.Errorf("expected violation for cert-001, got %s", violations[0].CertificateID)
|
|
}
|
|
}
|
|
|
|
func TestValidateCertificate_MultipleViolations(t *testing.T) {
|
|
ctx := context.Background()
|
|
now := time.Now()
|
|
|
|
rule1 := &domain.PolicyRule{
|
|
ID: "rule-001",
|
|
Name: "Allowed Issuers",
|
|
Type: domain.PolicyTypeAllowedIssuers,
|
|
Enabled: true,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}
|
|
rule2 := &domain.PolicyRule{
|
|
ID: "rule-002",
|
|
Name: "Required Metadata",
|
|
Type: domain.PolicyTypeRequiredMetadata,
|
|
Enabled: true,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}
|
|
|
|
policyRepo := &mockPolicyRepo{
|
|
Rules: map[string]*domain.PolicyRule{"rule-001": rule1, "rule-002": rule2},
|
|
Violations: []*domain.PolicyViolation{},
|
|
}
|
|
auditRepo := &mockAuditRepo{}
|
|
auditService := NewAuditService(auditRepo)
|
|
|
|
policyService := NewPolicyService(policyRepo, auditService)
|
|
|
|
cert := &domain.ManagedCertificate{
|
|
ID: "cert-001",
|
|
CommonName: "example.com",
|
|
IssuerID: "", // Missing issuer
|
|
Tags: nil, // Missing metadata
|
|
Status: domain.CertificateStatusActive,
|
|
ExpiresAt: now.AddDate(1, 0, 0),
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}
|
|
|
|
violations, err := policyService.ValidateCertificate(ctx, cert)
|
|
if err != nil {
|
|
t.Fatalf("ValidateCertificate failed: %v", err)
|
|
}
|
|
|
|
if len(violations) != 2 {
|
|
t.Errorf("expected 2 violations, got %d", len(violations))
|
|
}
|
|
}
|
|
|
|
func TestListPolicies(t *testing.T) {
|
|
now := time.Now()
|
|
rule1 := &domain.PolicyRule{
|
|
ID: "rule-001",
|
|
Name: "Rule 1",
|
|
Type: domain.PolicyTypeAllowedIssuers,
|
|
Enabled: true,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}
|
|
rule2 := &domain.PolicyRule{
|
|
ID: "rule-002",
|
|
Name: "Rule 2",
|
|
Type: domain.PolicyTypeRequiredMetadata,
|
|
Enabled: true,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}
|
|
|
|
policyRepo := &mockPolicyRepo{
|
|
Rules: map[string]*domain.PolicyRule{"rule-001": rule1, "rule-002": rule2},
|
|
Violations: []*domain.PolicyViolation{},
|
|
}
|
|
auditRepo := &mockAuditRepo{}
|
|
auditService := NewAuditService(auditRepo)
|
|
|
|
policyService := NewPolicyService(policyRepo, auditService)
|
|
|
|
policies, total, err := policyService.ListPolicies(context.Background(), 1, 50)
|
|
if err != nil {
|
|
t.Fatalf("ListPolicies failed: %v", err)
|
|
}
|
|
|
|
if len(policies) != 2 {
|
|
t.Errorf("expected 2 policies, got %d", len(policies))
|
|
}
|
|
if total != 2 {
|
|
t.Errorf("expected total 2, got %d", total)
|
|
}
|
|
}
|
|
|
|
func TestCreatePolicy(t *testing.T) {
|
|
now := time.Now()
|
|
policyRepo := &mockPolicyRepo{
|
|
Rules: make(map[string]*domain.PolicyRule),
|
|
Violations: []*domain.PolicyViolation{},
|
|
}
|
|
auditRepo := &mockAuditRepo{}
|
|
auditService := NewAuditService(auditRepo)
|
|
|
|
policyService := NewPolicyService(policyRepo, auditService)
|
|
|
|
policy := domain.PolicyRule{
|
|
Name: "Test Policy",
|
|
Type: domain.PolicyTypeAllowedIssuers,
|
|
Enabled: true,
|
|
CreatedAt: now,
|
|
}
|
|
|
|
created, err := policyService.CreatePolicy(context.Background(), policy)
|
|
if err != nil {
|
|
t.Fatalf("CreatePolicy failed: %v", err)
|
|
}
|
|
|
|
if created.ID == "" {
|
|
t.Fatal("expected non-empty policy ID")
|
|
}
|
|
|
|
if len(policyRepo.Rules) != 1 {
|
|
t.Errorf("expected 1 rule in repo, got %d", len(policyRepo.Rules))
|
|
}
|
|
}
|