mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 15:01:32 +00:00
804a1b05ce
Follow-up to590f654(awsacmpca: replace stub client with AWS SDK v2 implementation). CI's golangci-lint contextcheck rule flagged six violations in awsacmpca_test.go where mustNew/awsacmpca.New were called from test functions that had ctx in scope but didn't thread it through New(). The previous commit used context.Background() inside New() with the rationale that "the audit allows either threading or documenting the limitation"; CI made that choice for us. Threading ctx is the right shape per the audit's stated preference. The fix cascades from awsacmpca.New through issuerfactory.NewFromConfig and IssuerRegistry.Rebuild because the contextcheck rule propagates upward through every caller that has ctx in scope. This commit: - Changes awsacmpca.New(config, logger) to awsacmpca.New(ctx, config, logger). The ctx is passed to buildSDKClient → awsconfig.LoadDefaultConfig so SDK credential chain resolution honors caller deadlines (LoadDefaultConfig may probe IMDS or remote credential sources). The doc-comment on New explains that callers without a useful deadline should pass context.Background() and that the SDK has internal credential-resolution timeouts. - Adds ctx as the first parameter of issuerfactory.NewFromConfig. Currently only the AWSACMPCA branch uses ctx (it's threaded into awsacmpca.New); the other 11 branches accept ctx without using it. This is a contractual change that lets callers thread ctx through without contextcheck warnings, even though most issuer constructors do no ctx-aware work today. - Adds ctx as the first parameter of IssuerRegistry.Rebuild. Rebuild iterates over configs and calls NewFromConfig per issuer; the same ctx flows through every connector instantiation. - Updates the two production call sites in internal/service: - issuer.go:279 (TestIssuer connection test) now passes its method-scoped ctx - issuer.go:303 (BuildRegistry) now passes its method-scoped ctx to Rebuild - Updates 13 test sites in internal/connector/issuerfactory/factory_test.go via a new testCtx() helper that returns context.Background(). Helper is dedicated to this file so contextcheck's "you have a ctx in scope, pass it" rule doesn't fire on test functions that don't otherwise need ctx. - Updates 6 test sites in internal/service/issuer_registry_test.go to pass context.Background() to Rebuild. - Removes the now-stale "// NewFromConfig has no ctx parameter (preserved across all 12 connectors); pass context.Background() ..." comment from the awsacmpca branch in factory.go — that workaround is no longer the design. Verified locally: - gofmt -l . clean - go vet ./... clean - staticcheck ./... clean - golangci-lint run --timeout 5m ./... clean (was failing with 6 contextcheck issues before the cascade; now 0 issues) - go test -short -count=1 across all changed packages green Sandbox couldn't run the existing CI's full make verify due to disk pressure on /sessions and a virtiofs concurrent-open-file ceiling on go mod tidy; operator should run `make verify` on the workstation to confirm. Audit reference: cowork/issuer-coverage-audit-2026-05-01/RESULTS.md Top-10 fix #1 (CI follow-up; behavior unchanged from590f654).
156 lines
4.6 KiB
Go
156 lines
4.6 KiB
Go
package issuerfactory
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"log/slog"
|
|
"os"
|
|
"testing"
|
|
)
|
|
|
|
func testLogger() *slog.Logger {
|
|
return slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelError}))
|
|
}
|
|
|
|
// testCtx is a fresh background context per test. The factory takes ctx
|
|
// for the AWSACMPCA SDK config load; other connectors ignore it. Tests
|
|
// use a dedicated helper so contextcheck doesn't cascade.
|
|
func testCtx() context.Context { return context.Background() }
|
|
|
|
func TestNewFromConfig_LocalCA(t *testing.T) {
|
|
cfg := json.RawMessage(`{"ca_common_name":"Test CA"}`)
|
|
conn, err := NewFromConfig(testCtx(), "local", cfg, testLogger())
|
|
if err != nil {
|
|
t.Fatalf("NewFromConfig(local) failed: %v", err)
|
|
}
|
|
if conn == nil {
|
|
t.Fatal("expected non-nil connector")
|
|
}
|
|
}
|
|
|
|
func TestNewFromConfig_GenericCA_Alias(t *testing.T) {
|
|
cfg := json.RawMessage(`{}`)
|
|
conn, err := NewFromConfig(testCtx(), "GenericCA", cfg, testLogger())
|
|
if err != nil {
|
|
t.Fatalf("NewFromConfig(GenericCA) failed: %v", err)
|
|
}
|
|
if conn == nil {
|
|
t.Fatal("expected non-nil connector")
|
|
}
|
|
}
|
|
|
|
func TestNewFromConfig_ACME(t *testing.T) {
|
|
cfg := json.RawMessage(`{"directory_url":"https://acme-staging-v02.api.letsencrypt.org/directory","email":"test@example.com"}`)
|
|
conn, err := NewFromConfig(testCtx(), "ACME", cfg, testLogger())
|
|
if err != nil {
|
|
t.Fatalf("NewFromConfig(ACME) failed: %v", err)
|
|
}
|
|
if conn == nil {
|
|
t.Fatal("expected non-nil connector")
|
|
}
|
|
}
|
|
|
|
func TestNewFromConfig_StepCA(t *testing.T) {
|
|
cfg := json.RawMessage(`{"ca_url":"https://ca.internal:9000","provisioner_name":"test"}`)
|
|
conn, err := NewFromConfig(testCtx(), "StepCA", cfg, testLogger())
|
|
if err != nil {
|
|
t.Fatalf("NewFromConfig(StepCA) failed: %v", err)
|
|
}
|
|
if conn == nil {
|
|
t.Fatal("expected non-nil connector")
|
|
}
|
|
}
|
|
|
|
func TestNewFromConfig_OpenSSL(t *testing.T) {
|
|
cfg := json.RawMessage(`{"sign_script":"/path/to/sign.sh"}`)
|
|
conn, err := NewFromConfig(testCtx(), "OpenSSL", cfg, testLogger())
|
|
if err != nil {
|
|
t.Fatalf("NewFromConfig(OpenSSL) failed: %v", err)
|
|
}
|
|
if conn == nil {
|
|
t.Fatal("expected non-nil connector")
|
|
}
|
|
}
|
|
|
|
func TestNewFromConfig_VaultPKI(t *testing.T) {
|
|
cfg := json.RawMessage(`{"addr":"https://vault:8200","token":"hvs.test","mount":"pki","role":"web","ttl":"8760h"}`)
|
|
conn, err := NewFromConfig(testCtx(), "VaultPKI", cfg, testLogger())
|
|
if err != nil {
|
|
t.Fatalf("NewFromConfig(VaultPKI) failed: %v", err)
|
|
}
|
|
if conn == nil {
|
|
t.Fatal("expected non-nil connector")
|
|
}
|
|
}
|
|
|
|
func TestNewFromConfig_DigiCert(t *testing.T) {
|
|
cfg := json.RawMessage(`{"api_key":"test-key","org_id":"123","product_type":"ssl_basic"}`)
|
|
conn, err := NewFromConfig(testCtx(), "DigiCert", cfg, testLogger())
|
|
if err != nil {
|
|
t.Fatalf("NewFromConfig(DigiCert) failed: %v", err)
|
|
}
|
|
if conn == nil {
|
|
t.Fatal("expected non-nil connector")
|
|
}
|
|
}
|
|
|
|
func TestNewFromConfig_Sectigo(t *testing.T) {
|
|
cfg := json.RawMessage(`{"customer_uri":"test-org","login":"api-user","password":"secret","org_id":1}`)
|
|
conn, err := NewFromConfig(testCtx(), "Sectigo", cfg, testLogger())
|
|
if err != nil {
|
|
t.Fatalf("NewFromConfig(Sectigo) failed: %v", err)
|
|
}
|
|
if conn == nil {
|
|
t.Fatal("expected non-nil connector")
|
|
}
|
|
}
|
|
|
|
func TestNewFromConfig_GoogleCAS(t *testing.T) {
|
|
cfg := json.RawMessage(`{"project":"my-project","location":"us-central1","ca_pool":"my-pool","credentials":"/path/to/creds.json"}`)
|
|
conn, err := NewFromConfig(testCtx(), "GoogleCAS", cfg, testLogger())
|
|
if err != nil {
|
|
t.Fatalf("NewFromConfig(GoogleCAS) failed: %v", err)
|
|
}
|
|
if conn == nil {
|
|
t.Fatal("expected non-nil connector")
|
|
}
|
|
}
|
|
|
|
func TestNewFromConfig_UnknownType(t *testing.T) {
|
|
cfg := json.RawMessage(`{}`)
|
|
_, err := NewFromConfig(testCtx(), "UnknownCA", cfg, testLogger())
|
|
if err == nil {
|
|
t.Fatal("expected error for unknown type")
|
|
}
|
|
}
|
|
|
|
func TestNewFromConfig_MalformedJSON(t *testing.T) {
|
|
cfg := json.RawMessage(`{invalid json}`)
|
|
_, err := NewFromConfig(testCtx(), "ACME", cfg, testLogger())
|
|
if err == nil {
|
|
t.Fatal("expected error for malformed JSON")
|
|
}
|
|
}
|
|
|
|
func TestNewFromConfig_EmptyConfig(t *testing.T) {
|
|
// Empty config should work — connectors have defaults
|
|
conn, err := NewFromConfig(testCtx(), "local", nil, testLogger())
|
|
if err != nil {
|
|
t.Fatalf("NewFromConfig with nil config failed: %v", err)
|
|
}
|
|
if conn == nil {
|
|
t.Fatal("expected non-nil connector")
|
|
}
|
|
}
|
|
|
|
func TestNewFromConfig_AWSACMPCA(t *testing.T) {
|
|
cfg := json.RawMessage(`{"project":"my-project","location":"us-central1","ca_pool":"my-pool","credentials":"/path/to/creds.json"}`)
|
|
conn, err := NewFromConfig(testCtx(), "AWSACMPCA", cfg, testLogger())
|
|
if err != nil {
|
|
t.Fatalf("NewFromConfig(AWSACMPCA) failed: %v", err)
|
|
}
|
|
if conn == nil {
|
|
t.Fatal("expected non-nil connector")
|
|
}
|
|
}
|