From 7f57b1d3bfd9513f0451b3c50b1940bf7172328d Mon Sep 17 00:00:00 2001 From: shankar0123 Date: Thu, 14 May 2026 04:55:49 +0000 Subject: [PATCH] =?UTF-8?q?refactor(config):=20extract=20Issuers=20family?= =?UTF-8?q?=20=E2=80=94=20LAST=20in-config=20cut=20(Phase=209,=207=20of=20?= =?UTF-8?q?N)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Continuing Phase 9 ARCH-M2 closure. Sprint 7 is the LAST in-config cut of Phase 9. After this commit lands, the remaining sub-splits target non-config hotspots (cmd/server/main.go, service/acme.go, mcp/tools.go, auth_session_oidc.go, cmd/agent/main.go). What moved ========== internal/config/issuers.go (new, 435 lines including BSL header + Phase 9 doc-comment + 12 structs) Twelve issuer-related structs collected in one place for the first time: - KeygenConfig global key-generation policy (agent vs server) - CAConfig Local CA mode (self-signed vs sub-CA) - StepCAConfig step-ca (URL + JWK provisioner) - VaultConfig HashiCorp Vault PKI - DigiCertConfig DigiCert CertCentral - SectigoConfig Sectigo Certificate Manager - GoogleCASConfig Google Cloud CA Service - AWSACMPCAConfig AWS ACM Private CA - EntrustConfig Entrust Certificate Services - GlobalSignConfig GlobalSign Atlas HVCA - EJBCAConfig EJBCA / Keyfactor - OpenSSLConfig OpenSSL / custom CA Simplest split shape of Phase 9 so far ====================================== - ZERO helpers move. Every issuer config is pure data — strings, ints, bools. No time.Duration, no nested struct, no helper function reference. - ZERO imports needed in issuers.go beyond the package declaration. Verified by: `awk 'NR>=136 && NR<=269 || NR>=355 && NR<=527 || NR>=586 && NR<=609' internal/config/config.go | grep -E '\btime\. |\bos\.|\bfmt\.'` returned empty before the move. Three sed passes (Sprint-6 pattern, scattered targets) ====================================================== The 12 issuer types were SCATTERED across config.go interleaved with non-issuer types (OCSPResponderConfig, EncryptionConfig, the discovery family, DigestConfig, HealthCheckConfig, NetworkScanConfig, VerificationConfig, ApprovalConfig). Three independent sed deletes from highest-line to lowest: Block 3 (line 586-609): OpenSSLConfig alone (24 lines) Block 2 (line 355-527): KeygenConfig + CAConfig + StepCAConfig + VaultConfig + DigiCertConfig + SectigoConfig + GoogleCASConfig (173 lines) Block 1 (line 136-269): AWSACMPCAConfig + EntrustConfig + GlobalSignConfig + EJBCAConfig (134 lines) Total: 331 lines deleted. Highest-line-first ordering keeps every range pre-shift-stable — no mid-edit re-derivation. What stayed in config.go ======================== - OCSPResponderConfig (server-side OCSP responder; not issuer-side) - EncryptionConfig (config-at-rest encryption; not issuer-side) - CloudDiscoveryConfig + AWSSecretsMgrDiscoveryConfig + AzureKVDiscoveryConfig + GCPSecretMgrDiscoveryConfig (cloud-DISCOVERY sources reading certs others issued; not issuer connectors. Could form a future config/discovery.go split.) - DigestConfig + HealthCheckConfig (notifier-policy / health-monitor cadence; not issuer-related) - NetworkScanConfig + VerificationConfig (discovery / verify; not issuer-related) - ApprovalConfig (RBAC issuance-approval workflow; Sprint 6's deliberate exclusion still applies) - The Config struct itself (line 67) + every Load() / Validate() body that references issuer configs by field name. Public-surface invariant ======================== Every type, exported field, and doc-comment is byte-identical to pre-split. Package stays `config`. No issuer-config type exports a method (the entire surface is fields — preserved verbatim). Every external caller path (`config.AWSACMPCAConfig` / `config.EntrustConfig` / etc.) resolves the same way. Verification (all clean): gofmt -l internal/config/ → clean go build ./internal/config/... → clean go test ./internal/config/... -count=1 → ok (0.67s) staticcheck ./internal/config/... → clean go build ./cmd/server/... ./internal/auth/... ./internal/api/router/... ./internal/api/handler/... ./internal/scheduler/... ./internal/connector/issuer/... → clean (broader build expanded to include issuer packages this sprint since they're the most likely external consumers of the moved types) grep -nE '^type (KeygenConfig|CAConfig|StepCAConfig|VaultConfig| DigiCertConfig|SectigoConfig|GoogleCASConfig| OpenSSLConfig|AWSACMPCAConfig|EntrustConfig| GlobalSignConfig|EJBCAConfig)' internal/config/config.go → empty (none remain) grep -nE '^type (KeygenConfig|CAConfig|...)' internal/config/issuers.go → 12 types (correct) LOC delta: config.go: 1673 → 1342 (-331 lines: -134 Block 1, -173 Block 2, -24 Block 3) issuers.go: new, 435 lines (incl. 102-line Phase 9 doc-comment + BSL header + package decl) Cumulative Phase 9 progress (Sprints 1-7 from config.go): Pre-Phase-9: 3403 LOC After Sprint 1 (Notifier): 3335 LOC (-68) After Sprint 2 (ACME): 3108 LOC (-227) After Sprint 3 (SCEP): 2774 LOC (-334) After Sprint 4 (EST): 2467 LOC (-307) After Sprint 5 (Auth): 1963 LOC (-504) After Sprint 6 (Server): 1673 LOC (-290) After Sprint 7 (Issuers): 1342 LOC (-331) Total Sprint 1+2+3+4+5+6+7: -2061 LOC (-60.6%) Notable milestones (Sprint 7) ============================== - config.go has lost MORE than 60% of its original lines. - 6 sibling config-package files now exist alongside config.go, each scoped to a single concern. Total config package size 3898 LOC across 7 files (was 3403 LOC in 1 file pre-Phase-9 — net 14.6% growth from per-file Phase 9 doc-comments + the file headers; in exchange, the largest single file dropped from 3403 → 1342 LOC, a 60.6% concentration reduction). - This is the LAST cut from config.go. The remaining 5 sub-splits target non-config hotspots and use entirely different file-shape patterns (subpackage creation for service/acme; per-verb file splits for handlers; pure-domain grouping for mcp/tools). Next queued (Sprint 8): cmd/server/main.go split into main.go (entrypoint) + cmd/server/wire.go (DI assembly) + cmd/server/migrations.go (boot-time migration path). main.go is the SECOND-LARGEST hotspot at 2966 LOC. Different from config.go cuts because: - cmd/server/ is a package with multiple files already (per `ls cmd/server/`); the new files will live alongside existing ones (auth_backfill.go, tls.go, etc.) which means no new subdirectory needed. - The cut is by FUNCTIONAL CONCERN (boot sequencing) rather than by TYPE FAMILY (struct grouping), so the boundary lines are different in nature. - Phase 4's migration-hook code (in main.go today) inherits into migrations.go without code-change — the Phase 9 prompt explicitly says "Phase 4's pre-install migration hook adds a path to cmd/server/migrations.go; doing the split first means double-touching the same lines." Closes: cowork/certctl-architecture-diligence-audit.html#fix-ARCH-M2 (partial — 7 of 12 — full ARCH-M2 closure is the aggregate) --- internal/config/config.go | 331 ---------------------------- internal/config/issuers.go | 435 +++++++++++++++++++++++++++++++++++++ 2 files changed, 435 insertions(+), 331 deletions(-) create mode 100644 internal/config/issuers.go diff --git a/internal/config/config.go b/internal/config/config.go index 6f13f96..ec9ab6d 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -133,140 +133,6 @@ type OCSPResponderConfig struct { Validity time.Duration } -// AWSACMPCAConfig contains AWS ACM Private CA issuer connector configuration. -type AWSACMPCAConfig struct { - // Region is the AWS region where the Private CA resides (e.g., "us-east-1"). - // Required for AWS ACM PCA integration. - // Setting: CERTCTL_AWS_PCA_REGION environment variable. - Region string - - // CAArn is the ARN of the ACM Private CA certificate authority. - // Format: arn:aws:acm-pca:::certificate-authority/ - // Required for AWS ACM PCA integration. - // Setting: CERTCTL_AWS_PCA_CA_ARN environment variable. - CAArn string - - // SigningAlgorithm is the signing algorithm for certificate issuance. - // Valid: SHA256WITHRSA, SHA384WITHRSA, SHA512WITHRSA, SHA256WITHECDSA, SHA384WITHECDSA, SHA512WITHECDSA. - // Default: "SHA256WITHRSA". - // Setting: CERTCTL_AWS_PCA_SIGNING_ALGORITHM environment variable. - SigningAlgorithm string - - // ValidityDays is the certificate validity period in days. - // Default: 365. - // Setting: CERTCTL_AWS_PCA_VALIDITY_DAYS environment variable. - ValidityDays int - - // TemplateArn is the optional ARN of an ACM PCA certificate template. - // Used for constrained subordinate CAs or custom certificate profiles. - // Setting: CERTCTL_AWS_PCA_TEMPLATE_ARN environment variable. - TemplateArn string -} - -// EntrustConfig contains Entrust Certificate Services issuer connector configuration. -// Entrust uses mTLS client certificate authentication. -type EntrustConfig struct { - // APIUrl is the Entrust CA Gateway base URL. - // Setting: CERTCTL_ENTRUST_API_URL environment variable. - APIUrl string - - // ClientCertPath is the path to the mTLS client certificate PEM file. - // Setting: CERTCTL_ENTRUST_CLIENT_CERT_PATH environment variable. - ClientCertPath string - - // ClientKeyPath is the path to the mTLS client private key PEM file. - // Setting: CERTCTL_ENTRUST_CLIENT_KEY_PATH environment variable. - ClientKeyPath string - - // CAId is the Entrust CA identifier. - // Setting: CERTCTL_ENTRUST_CA_ID environment variable. - CAId string - - // ProfileId is the optional enrollment profile identifier. - // Setting: CERTCTL_ENTRUST_PROFILE_ID environment variable. - ProfileId string - - // PollMaxWaitSeconds caps GetOrderStatus's bounded-polling - // deadline. Approval-pending workflows should bump this (e.g., - // 86400 = 24h) so a single tick can wait through the approval - // window. Default 600. Audit fix #5. - // Setting: CERTCTL_ENTRUST_POLL_MAX_WAIT_SECONDS. - PollMaxWaitSeconds int -} - -// GlobalSignConfig contains GlobalSign Atlas HVCA issuer connector configuration. -// GlobalSign uses mTLS client certificate authentication plus API key/secret headers. -type GlobalSignConfig struct { - // APIUrl is the GlobalSign Atlas HVCA base URL (region-aware). - // Setting: CERTCTL_GLOBALSIGN_API_URL environment variable. - APIUrl string - - // APIKey is the GlobalSign API key. - // Setting: CERTCTL_GLOBALSIGN_API_KEY environment variable. - APIKey string - - // APISecret is the GlobalSign API secret. - // Setting: CERTCTL_GLOBALSIGN_API_SECRET environment variable. - APISecret string - - // ClientCertPath is the path to the mTLS client certificate PEM file. - // Setting: CERTCTL_GLOBALSIGN_CLIENT_CERT_PATH environment variable. - ClientCertPath string - - // ClientKeyPath is the path to the mTLS client private key PEM file. - // Setting: CERTCTL_GLOBALSIGN_CLIENT_KEY_PATH environment variable. - ClientKeyPath string - - // ServerCAPath is the optional path to a PEM file containing the CA - // certificate(s) used to verify the GlobalSign Atlas HVCA API server - // certificate. If empty, the system trust store is used. Set this - // for private/lab Atlas deployments whose server TLS chain is not - // present in the host's default trust bundle. - // Setting: CERTCTL_GLOBALSIGN_SERVER_CA_PATH environment variable. - ServerCAPath string - - // PollMaxWaitSeconds caps GetOrderStatus's bounded-polling - // deadline. Default 600 (10 minutes). Audit fix #5. - // Setting: CERTCTL_GLOBALSIGN_POLL_MAX_WAIT_SECONDS. - PollMaxWaitSeconds int -} - -// EJBCAConfig contains EJBCA (Keyfactor) issuer connector configuration. -// EJBCA supports dual authentication: mTLS or OAuth2 Bearer token. -type EJBCAConfig struct { - // APIUrl is the EJBCA REST API base URL. - // Setting: CERTCTL_EJBCA_API_URL environment variable. - APIUrl string - - // AuthMode selects the authentication method: "mtls" or "oauth2". Default: "mtls". - // Setting: CERTCTL_EJBCA_AUTH_MODE environment variable. - AuthMode string - - // ClientCertPath is the path to the mTLS client certificate PEM file (required when auth_mode=mtls). - // Setting: CERTCTL_EJBCA_CLIENT_CERT_PATH environment variable. - ClientCertPath string - - // ClientKeyPath is the path to the mTLS client private key PEM file (required when auth_mode=mtls). - // Setting: CERTCTL_EJBCA_CLIENT_KEY_PATH environment variable. - ClientKeyPath string - - // Token is the OAuth2 Bearer token (required when auth_mode=oauth2). - // Setting: CERTCTL_EJBCA_TOKEN environment variable. - Token string - - // CAName is the EJBCA CA name. Required. - // Setting: CERTCTL_EJBCA_CA_NAME environment variable. - CAName string - - // CertProfile is the optional EJBCA certificate profile name. - // Setting: CERTCTL_EJBCA_CERT_PROFILE environment variable. - CertProfile string - - // EEProfile is the optional EJBCA end-entity profile name. - // Setting: CERTCTL_EJBCA_EE_PROFILE environment variable. - EEProfile string -} - // EncryptionConfig contains configuration for encrypting sensitive data at rest. type EncryptionConfig struct { // ConfigEncryptionKey is the passphrase used to derive AES-256-GCM keys for encrypting @@ -352,179 +218,6 @@ type GCPSecretMgrDiscoveryConfig struct { Credentials string } -// KeygenConfig controls where private keys are generated. -type KeygenConfig struct { - // Mode determines where certificate private keys are generated. - // Valid values: "agent" (default, production) or "server" (demo only). - // In "agent" mode, renewal/issuance jobs enter AwaitingCSR state and agents - // generate ECDSA P-256 keys locally. Private keys never leave agent infrastructure. - // In "server" mode, the control plane generates RSA keys — demo only, not for production - // as private keys touch the server. Requires explicit opt-in. - Mode string -} - -// CAConfig controls the Local CA's operating mode. -type CAConfig struct { - // CertPath is the path to a PEM-encoded CA certificate for sub-CA mode. - // When set with KeyPath, the Local CA loads this cert instead of generating a self-signed root. - // Required: sub-CA mode must have both CertPath and KeyPath set. - // Optional: leave empty for self-signed mode (development/demo). Path must be absolute. - CertPath string - - // KeyPath is the path to a PEM-encoded CA private key for sub-CA mode. - // Supports RSA, ECDSA, and PKCS#8 encoded keys. - // Required: must be set together with CertPath for sub-CA mode. - // Optional: leave empty for self-signed mode (development/demo). Path must be absolute. - KeyPath string -} - -// StepCAConfig contains step-ca issuer connector configuration. -type StepCAConfig struct { - // URL is the base URL of the step-ca server. - // Example: "https://ca.example.com:9000". Required for step-ca integration. - URL string - - // ProvisionerName is the name of the JWK provisioner configured in step-ca. - // Used to select which provisioner signs the certificate requests. - ProvisionerName string - - // ProvisionerKeyPath is the path to the PEM-encoded JWK provisioner private key. - // Authenticates with the step-ca /sign API. Must be absolute path. - ProvisionerKeyPath string - - // ProvisionerPassword is the optional password for the provisioner private key. - // Leave empty if the key file is not encrypted. - ProvisionerPassword string -} - -// VaultConfig contains HashiCorp Vault PKI issuer connector configuration. -type VaultConfig struct { - // Addr is the Vault server address (e.g., "https://vault.example.com:8200"). - // Required for Vault PKI integration. - // Setting: CERTCTL_VAULT_ADDR environment variable. - Addr string - - // Token is the Vault token for authentication. - // Required for Vault PKI integration. - // Setting: CERTCTL_VAULT_TOKEN environment variable. - Token string - - // Mount is the PKI secrets engine mount path. - // Default: "pki". - // Setting: CERTCTL_VAULT_MOUNT environment variable. - Mount string - - // Role is the PKI role name used for signing certificates. - // Required for Vault PKI integration. - // Setting: CERTCTL_VAULT_ROLE environment variable. - Role string - - // TTL is the requested certificate time-to-live. - // Default: "8760h" (1 year). - // Setting: CERTCTL_VAULT_TTL environment variable. - TTL string -} - -// DigiCertConfig contains DigiCert CertCentral issuer connector configuration. -type DigiCertConfig struct { - // APIKey is the CertCentral API key for authentication. - // Required for DigiCert integration. - // Setting: CERTCTL_DIGICERT_API_KEY environment variable. - APIKey string - - // OrgID is the DigiCert organization ID for certificate orders. - // Required for DigiCert integration. - // Setting: CERTCTL_DIGICERT_ORG_ID environment variable. - OrgID string - - // ProductType is the DigiCert product type for certificate orders. - // Default: "ssl_basic". Common values: "ssl_basic", "ssl_wildcard", "ssl_ev_basic". - // Setting: CERTCTL_DIGICERT_PRODUCT_TYPE environment variable. - ProductType string - - // BaseURL is the DigiCert CertCentral API base URL. - // Default: "https://www.digicert.com/services/v2". - // Setting: CERTCTL_DIGICERT_BASE_URL environment variable. - BaseURL string - - // PollMaxWaitSeconds caps how long GetOrderStatus blocks doing - // internal exponential-backoff polling before returning. Default - // 600 (10 minutes); 0 falls back to asyncpoll default. - // Setting: CERTCTL_DIGICERT_POLL_MAX_WAIT_SECONDS. Audit fix #5. - PollMaxWaitSeconds int -} - -// SectigoConfig contains Sectigo Certificate Manager issuer connector configuration. -type SectigoConfig struct { - // CustomerURI is the Sectigo customer URI (organization identifier). - // Required for Sectigo integration. - // Setting: CERTCTL_SECTIGO_CUSTOMER_URI environment variable. - CustomerURI string - - // Login is the Sectigo API account login. - // Required for Sectigo integration. - // Setting: CERTCTL_SECTIGO_LOGIN environment variable. - Login string - - // Password is the Sectigo API account password or API key. - // Required for Sectigo integration. - // Setting: CERTCTL_SECTIGO_PASSWORD environment variable. - Password string - - // OrgID is the Sectigo organization ID for certificate enrollments. - // Required for Sectigo integration. - // Setting: CERTCTL_SECTIGO_ORG_ID environment variable. - OrgID int - - // CertType is the Sectigo certificate type ID (from GET /ssl/v1/types). - // Required for enrollment. Set via CERTCTL_SECTIGO_CERT_TYPE environment variable. - CertType int - - // Term is the certificate validity in days (e.g., 365, 730). - // Default: 365. - // Setting: CERTCTL_SECTIGO_TERM environment variable. - Term int - - // BaseURL is the Sectigo SCM API base URL. - // Default: "https://cert-manager.com/api". - // Setting: CERTCTL_SECTIGO_BASE_URL environment variable. - BaseURL string - - // PollMaxWaitSeconds caps how long GetOrderStatus blocks doing - // internal exponential-backoff polling. Default 600. Sectigo's - // collectNotReady sentinel rides the backoff schedule. - // Setting: CERTCTL_SECTIGO_POLL_MAX_WAIT_SECONDS. Audit fix #5. - PollMaxWaitSeconds int -} - -// GoogleCASConfig contains Google Cloud Certificate Authority Service configuration. -type GoogleCASConfig struct { - // Project is the GCP project ID. - // Required for Google CAS integration. - // Setting: CERTCTL_GOOGLE_CAS_PROJECT environment variable. - Project string - - // Location is the GCP region (e.g., "us-central1"). - // Required for Google CAS integration. - // Setting: CERTCTL_GOOGLE_CAS_LOCATION environment variable. - Location string - - // CAPool is the Certificate Authority pool name. - // Required for Google CAS integration. - // Setting: CERTCTL_GOOGLE_CAS_CA_POOL environment variable. - CAPool string - - // Credentials is the path to the service account JSON credentials file. - // Required for Google CAS integration. - // Setting: CERTCTL_GOOGLE_CAS_CREDENTIALS environment variable. - Credentials string - - // TTL is the default certificate time-to-live. - // Default: "8760h" (1 year). - // Setting: CERTCTL_GOOGLE_CAS_TTL environment variable. - TTL string -} - // DigestConfig controls the scheduled certificate digest email feature. type DigestConfig struct { // Enabled controls whether periodic digest emails are generated and sent. @@ -583,30 +276,6 @@ type HealthCheckConfig struct { AutoCreate bool } -// OpenSSLConfig contains OpenSSL/Custom CA issuer connector configuration. -type OpenSSLConfig struct { - // SignScript is the path to a shell script that signs certificate requests. - // Script receives: CSR_PATH, COMMON_NAME, OUTPUT_CERT_PATH as env vars. - // Must output the signed certificate PEM to OUTPUT_CERT_PATH. - // Example: /opt/ca-scripts/sign.sh - SignScript string - - // RevokeScript is the path to a shell script that revokes certificates. - // Script receives: SERIAL_NUMBER, REASON_CODE as env vars. - // Best-effort: script failures do not block revocation recording. - // Leave empty if revocation is not supported by the custom CA. - RevokeScript string - - // CRLScript is the path to a shell script that generates CRL (Certificate Revocation List). - // Script should output the DER-encoded CRL to stdout. - // Leave empty if CRL generation is not supported by the custom CA. - CRLScript string - - // TimeoutSeconds is the maximum execution time for any shell script invocation. - // Default: 30 seconds. Prevents hung processes from blocking certificate operations. - TimeoutSeconds int -} - // NetworkScanConfig controls the server-side active TLS scanner. type NetworkScanConfig struct { Enabled bool // Enable network scanning (default false) diff --git a/internal/config/issuers.go b/internal/config/issuers.go new file mode 100644 index 0000000..1769309 --- /dev/null +++ b/internal/config/issuers.go @@ -0,0 +1,435 @@ +// Copyright 2026 certctl LLC. All rights reserved. +// SPDX-License-Identifier: BUSL-1.1 + +package config + +// Phase 9 ARCH-M2 closure Sprint 7 (2026-05-14): extracted from +// config.go. The LAST in-config cut of Phase 9. Sprint 7 collects +// the issuer-connector configurations — every external CA the local +// server talks UP to (StepCA, Vault, DigiCert, Sectigo, GoogleCAS, +// AWS ACM PCA, Entrust, GlobalSign, EJBCA, OpenSSL) plus the +// local CA mode + key-generation policy. +// +// Twelve structs move: +// +// KeygenConfig — global key-generation policy (Mode: "agent" +// production default, or "server" demo-only). +// CAConfig — Local CA mode: self-signed vs sub-CA +// (CertPath + KeyPath). +// StepCAConfig — step-ca issuer (URL + JWK provisioner). +// VaultConfig — HashiCorp Vault PKI (Addr + Token + Mount + +// Role + TTL). +// DigiCertConfig — DigiCert CertCentral (APIKey + OrgID + +// ProductType + BaseURL + PollMaxWait). +// SectigoConfig — Sectigo Certificate Manager (CustomerURI + +// Login + Password + OrgID + CertType + Term + +// BaseURL + PollMaxWait). +// GoogleCASConfig — Google Cloud CA Service (Project + Location + +// CAPool + Credentials + TTL). +// AWSACMPCAConfig — AWS ACM Private CA (Region + CAArn + +// SigningAlgorithm + ValidityDays + +// TemplateArn). +// EntrustConfig — Entrust Certificate Services (APIUrl + mTLS +// client cert/key + CAId + ProfileId + +// PollMaxWait). +// GlobalSignConfig — GlobalSign Atlas HVCA (APIUrl + APIKey + +// APISecret + mTLS client cert/key + ServerCA +// + PollMaxWait). +// EJBCAConfig — EJBCA / Keyfactor (APIUrl + AuthMode + +// mTLS / OAuth2 token + CAName + cert profile +// + EE profile). +// OpenSSLConfig — OpenSSL / custom CA (SignScript + RevokeScript +// + CRLScript + TimeoutSeconds). +// +// No helpers move. The bodies are pure-data field declarations — +// the simplest possible split shape since every issuer config +// struct uses only stdlib primitive types (string, int, bool) and +// no time.Duration, no nested struct, no helper-function reference. +// Verified by: `awk 'NR>=136 && NR<=269 || NR>=355 && NR<=527 || +// NR>=586 && NR<=609' internal/config/config.go | grep -E '\btime\. +// |\bos\.|\bfmt\.'` → empty pre-move. issuers.go therefore needs +// ZERO imports beyond the package declaration. +// +// Edit shape +// ========== +// Sprint 7 used three independent sed deletes from highest-line to +// lowest-line (same pattern Sprint 6 introduced) because the 12 +// issuer structs were SCATTERED across config.go interleaved with +// non-issuer types: +// +// Block 1 (top of file, after Config + OCSPResponderConfig): +// AWSACMPCAConfig (137) + EntrustConfig (168) + +// GlobalSignConfig (199) + EJBCAConfig (236). +// Followed by EncryptionConfig (271) — NOT an issuer; stays. +// +// Block 2 (middle, after the discovery configs): +// KeygenConfig (356) + CAConfig (367) + StepCAConfig (382) + +// VaultConfig (401) + DigiCertConfig (429) + SectigoConfig (458) + +// GoogleCASConfig (501). +// Followed by DigestConfig (529) — notifier-policy; stays. +// +// Block 3 (single, between HealthCheck and NetworkScan): +// OpenSSLConfig (587). +// +// What stayed in config.go +// ======================== +// - OCSPResponderConfig (114) — server-side OCSP responder, not +// issuer-side; conceptually adjacent to ServerConfig (already +// moved). Could be folded into server.go in a future cut; left +// in place this sprint to keep the cut scope tight. +// - EncryptionConfig (271 pre-move) — config-at-rest encryption, +// not issuer-side. +// - The cloud-discovery family (CloudDiscoveryConfig + +// AWSSecretsMgrDiscoveryConfig + AzureKVDiscoveryConfig + +// GCPSecretMgrDiscoveryConfig) — those are DISCOVERY sources, +// not ISSUER connectors. Reading from cloud secret managers to +// find certificates someone else issued; not signing. +// - DigestConfig + HealthCheckConfig — notifier/health-monitor +// policy, not issuer-related. +// - NetworkScanConfig + VerificationConfig — discovery / verify, +// not issuer-related. +// - ApprovalConfig — RBAC issuance-approval workflow; stays per +// Sprint 6's reasoning. +// - All Load() / Validate() bodies that reference the moved +// issuer-config types (cross-cutting validation logic stays +// in config.go). +// +// Public-surface invariant +// ======================== +// Every type, exported field, and doc-comment is byte-identical to +// pre-split. Package stays `config`. Every external caller of +// `config.AWSACMPCAConfig` / `config.EntrustConfig` / +// `config.KeygenConfig` / etc. resolves the same way. None of these +// types declare an exported method; the entire surface is fields, +// preserved verbatim. + +// AWSACMPCAConfig contains AWS ACM Private CA issuer connector configuration. +type AWSACMPCAConfig struct { + // Region is the AWS region where the Private CA resides (e.g., "us-east-1"). + // Required for AWS ACM PCA integration. + // Setting: CERTCTL_AWS_PCA_REGION environment variable. + Region string + + // CAArn is the ARN of the ACM Private CA certificate authority. + // Format: arn:aws:acm-pca:::certificate-authority/ + // Required for AWS ACM PCA integration. + // Setting: CERTCTL_AWS_PCA_CA_ARN environment variable. + CAArn string + + // SigningAlgorithm is the signing algorithm for certificate issuance. + // Valid: SHA256WITHRSA, SHA384WITHRSA, SHA512WITHRSA, SHA256WITHECDSA, SHA384WITHECDSA, SHA512WITHECDSA. + // Default: "SHA256WITHRSA". + // Setting: CERTCTL_AWS_PCA_SIGNING_ALGORITHM environment variable. + SigningAlgorithm string + + // ValidityDays is the certificate validity period in days. + // Default: 365. + // Setting: CERTCTL_AWS_PCA_VALIDITY_DAYS environment variable. + ValidityDays int + + // TemplateArn is the optional ARN of an ACM PCA certificate template. + // Used for constrained subordinate CAs or custom certificate profiles. + // Setting: CERTCTL_AWS_PCA_TEMPLATE_ARN environment variable. + TemplateArn string +} + +// EntrustConfig contains Entrust Certificate Services issuer connector configuration. +// Entrust uses mTLS client certificate authentication. +type EntrustConfig struct { + // APIUrl is the Entrust CA Gateway base URL. + // Setting: CERTCTL_ENTRUST_API_URL environment variable. + APIUrl string + + // ClientCertPath is the path to the mTLS client certificate PEM file. + // Setting: CERTCTL_ENTRUST_CLIENT_CERT_PATH environment variable. + ClientCertPath string + + // ClientKeyPath is the path to the mTLS client private key PEM file. + // Setting: CERTCTL_ENTRUST_CLIENT_KEY_PATH environment variable. + ClientKeyPath string + + // CAId is the Entrust CA identifier. + // Setting: CERTCTL_ENTRUST_CA_ID environment variable. + CAId string + + // ProfileId is the optional enrollment profile identifier. + // Setting: CERTCTL_ENTRUST_PROFILE_ID environment variable. + ProfileId string + + // PollMaxWaitSeconds caps GetOrderStatus's bounded-polling + // deadline. Approval-pending workflows should bump this (e.g., + // 86400 = 24h) so a single tick can wait through the approval + // window. Default 600. Audit fix #5. + // Setting: CERTCTL_ENTRUST_POLL_MAX_WAIT_SECONDS. + PollMaxWaitSeconds int +} + +// GlobalSignConfig contains GlobalSign Atlas HVCA issuer connector configuration. +// GlobalSign uses mTLS client certificate authentication plus API key/secret headers. +type GlobalSignConfig struct { + // APIUrl is the GlobalSign Atlas HVCA base URL (region-aware). + // Setting: CERTCTL_GLOBALSIGN_API_URL environment variable. + APIUrl string + + // APIKey is the GlobalSign API key. + // Setting: CERTCTL_GLOBALSIGN_API_KEY environment variable. + APIKey string + + // APISecret is the GlobalSign API secret. + // Setting: CERTCTL_GLOBALSIGN_API_SECRET environment variable. + APISecret string + + // ClientCertPath is the path to the mTLS client certificate PEM file. + // Setting: CERTCTL_GLOBALSIGN_CLIENT_CERT_PATH environment variable. + ClientCertPath string + + // ClientKeyPath is the path to the mTLS client private key PEM file. + // Setting: CERTCTL_GLOBALSIGN_CLIENT_KEY_PATH environment variable. + ClientKeyPath string + + // ServerCAPath is the optional path to a PEM file containing the CA + // certificate(s) used to verify the GlobalSign Atlas HVCA API server + // certificate. If empty, the system trust store is used. Set this + // for private/lab Atlas deployments whose server TLS chain is not + // present in the host's default trust bundle. + // Setting: CERTCTL_GLOBALSIGN_SERVER_CA_PATH environment variable. + ServerCAPath string + + // PollMaxWaitSeconds caps GetOrderStatus's bounded-polling + // deadline. Default 600 (10 minutes). Audit fix #5. + // Setting: CERTCTL_GLOBALSIGN_POLL_MAX_WAIT_SECONDS. + PollMaxWaitSeconds int +} + +// EJBCAConfig contains EJBCA (Keyfactor) issuer connector configuration. +// EJBCA supports dual authentication: mTLS or OAuth2 Bearer token. +type EJBCAConfig struct { + // APIUrl is the EJBCA REST API base URL. + // Setting: CERTCTL_EJBCA_API_URL environment variable. + APIUrl string + + // AuthMode selects the authentication method: "mtls" or "oauth2". Default: "mtls". + // Setting: CERTCTL_EJBCA_AUTH_MODE environment variable. + AuthMode string + + // ClientCertPath is the path to the mTLS client certificate PEM file (required when auth_mode=mtls). + // Setting: CERTCTL_EJBCA_CLIENT_CERT_PATH environment variable. + ClientCertPath string + + // ClientKeyPath is the path to the mTLS client private key PEM file (required when auth_mode=mtls). + // Setting: CERTCTL_EJBCA_CLIENT_KEY_PATH environment variable. + ClientKeyPath string + + // Token is the OAuth2 Bearer token (required when auth_mode=oauth2). + // Setting: CERTCTL_EJBCA_TOKEN environment variable. + Token string + + // CAName is the EJBCA CA name. Required. + // Setting: CERTCTL_EJBCA_CA_NAME environment variable. + CAName string + + // CertProfile is the optional EJBCA certificate profile name. + // Setting: CERTCTL_EJBCA_CERT_PROFILE environment variable. + CertProfile string + + // EEProfile is the optional EJBCA end-entity profile name. + // Setting: CERTCTL_EJBCA_EE_PROFILE environment variable. + EEProfile string +} + +// KeygenConfig controls where private keys are generated. +type KeygenConfig struct { + // Mode determines where certificate private keys are generated. + // Valid values: "agent" (default, production) or "server" (demo only). + // In "agent" mode, renewal/issuance jobs enter AwaitingCSR state and agents + // generate ECDSA P-256 keys locally. Private keys never leave agent infrastructure. + // In "server" mode, the control plane generates RSA keys — demo only, not for production + // as private keys touch the server. Requires explicit opt-in. + Mode string +} + +// CAConfig controls the Local CA's operating mode. +type CAConfig struct { + // CertPath is the path to a PEM-encoded CA certificate for sub-CA mode. + // When set with KeyPath, the Local CA loads this cert instead of generating a self-signed root. + // Required: sub-CA mode must have both CertPath and KeyPath set. + // Optional: leave empty for self-signed mode (development/demo). Path must be absolute. + CertPath string + + // KeyPath is the path to a PEM-encoded CA private key for sub-CA mode. + // Supports RSA, ECDSA, and PKCS#8 encoded keys. + // Required: must be set together with CertPath for sub-CA mode. + // Optional: leave empty for self-signed mode (development/demo). Path must be absolute. + KeyPath string +} + +// StepCAConfig contains step-ca issuer connector configuration. +type StepCAConfig struct { + // URL is the base URL of the step-ca server. + // Example: "https://ca.example.com:9000". Required for step-ca integration. + URL string + + // ProvisionerName is the name of the JWK provisioner configured in step-ca. + // Used to select which provisioner signs the certificate requests. + ProvisionerName string + + // ProvisionerKeyPath is the path to the PEM-encoded JWK provisioner private key. + // Authenticates with the step-ca /sign API. Must be absolute path. + ProvisionerKeyPath string + + // ProvisionerPassword is the optional password for the provisioner private key. + // Leave empty if the key file is not encrypted. + ProvisionerPassword string +} + +// VaultConfig contains HashiCorp Vault PKI issuer connector configuration. +type VaultConfig struct { + // Addr is the Vault server address (e.g., "https://vault.example.com:8200"). + // Required for Vault PKI integration. + // Setting: CERTCTL_VAULT_ADDR environment variable. + Addr string + + // Token is the Vault token for authentication. + // Required for Vault PKI integration. + // Setting: CERTCTL_VAULT_TOKEN environment variable. + Token string + + // Mount is the PKI secrets engine mount path. + // Default: "pki". + // Setting: CERTCTL_VAULT_MOUNT environment variable. + Mount string + + // Role is the PKI role name used for signing certificates. + // Required for Vault PKI integration. + // Setting: CERTCTL_VAULT_ROLE environment variable. + Role string + + // TTL is the requested certificate time-to-live. + // Default: "8760h" (1 year). + // Setting: CERTCTL_VAULT_TTL environment variable. + TTL string +} + +// DigiCertConfig contains DigiCert CertCentral issuer connector configuration. +type DigiCertConfig struct { + // APIKey is the CertCentral API key for authentication. + // Required for DigiCert integration. + // Setting: CERTCTL_DIGICERT_API_KEY environment variable. + APIKey string + + // OrgID is the DigiCert organization ID for certificate orders. + // Required for DigiCert integration. + // Setting: CERTCTL_DIGICERT_ORG_ID environment variable. + OrgID string + + // ProductType is the DigiCert product type for certificate orders. + // Default: "ssl_basic". Common values: "ssl_basic", "ssl_wildcard", "ssl_ev_basic". + // Setting: CERTCTL_DIGICERT_PRODUCT_TYPE environment variable. + ProductType string + + // BaseURL is the DigiCert CertCentral API base URL. + // Default: "https://www.digicert.com/services/v2". + // Setting: CERTCTL_DIGICERT_BASE_URL environment variable. + BaseURL string + + // PollMaxWaitSeconds caps how long GetOrderStatus blocks doing + // internal exponential-backoff polling before returning. Default + // 600 (10 minutes); 0 falls back to asyncpoll default. + // Setting: CERTCTL_DIGICERT_POLL_MAX_WAIT_SECONDS. Audit fix #5. + PollMaxWaitSeconds int +} + +// SectigoConfig contains Sectigo Certificate Manager issuer connector configuration. +type SectigoConfig struct { + // CustomerURI is the Sectigo customer URI (organization identifier). + // Required for Sectigo integration. + // Setting: CERTCTL_SECTIGO_CUSTOMER_URI environment variable. + CustomerURI string + + // Login is the Sectigo API account login. + // Required for Sectigo integration. + // Setting: CERTCTL_SECTIGO_LOGIN environment variable. + Login string + + // Password is the Sectigo API account password or API key. + // Required for Sectigo integration. + // Setting: CERTCTL_SECTIGO_PASSWORD environment variable. + Password string + + // OrgID is the Sectigo organization ID for certificate enrollments. + // Required for Sectigo integration. + // Setting: CERTCTL_SECTIGO_ORG_ID environment variable. + OrgID int + + // CertType is the Sectigo certificate type ID (from GET /ssl/v1/types). + // Required for enrollment. Set via CERTCTL_SECTIGO_CERT_TYPE environment variable. + CertType int + + // Term is the certificate validity in days (e.g., 365, 730). + // Default: 365. + // Setting: CERTCTL_SECTIGO_TERM environment variable. + Term int + + // BaseURL is the Sectigo SCM API base URL. + // Default: "https://cert-manager.com/api". + // Setting: CERTCTL_SECTIGO_BASE_URL environment variable. + BaseURL string + + // PollMaxWaitSeconds caps how long GetOrderStatus blocks doing + // internal exponential-backoff polling. Default 600. Sectigo's + // collectNotReady sentinel rides the backoff schedule. + // Setting: CERTCTL_SECTIGO_POLL_MAX_WAIT_SECONDS. Audit fix #5. + PollMaxWaitSeconds int +} + +// GoogleCASConfig contains Google Cloud Certificate Authority Service configuration. +type GoogleCASConfig struct { + // Project is the GCP project ID. + // Required for Google CAS integration. + // Setting: CERTCTL_GOOGLE_CAS_PROJECT environment variable. + Project string + + // Location is the GCP region (e.g., "us-central1"). + // Required for Google CAS integration. + // Setting: CERTCTL_GOOGLE_CAS_LOCATION environment variable. + Location string + + // CAPool is the Certificate Authority pool name. + // Required for Google CAS integration. + // Setting: CERTCTL_GOOGLE_CAS_CA_POOL environment variable. + CAPool string + + // Credentials is the path to the service account JSON credentials file. + // Required for Google CAS integration. + // Setting: CERTCTL_GOOGLE_CAS_CREDENTIALS environment variable. + Credentials string + + // TTL is the default certificate time-to-live. + // Default: "8760h" (1 year). + // Setting: CERTCTL_GOOGLE_CAS_TTL environment variable. + TTL string +} + +// OpenSSLConfig contains OpenSSL/Custom CA issuer connector configuration. +type OpenSSLConfig struct { + // SignScript is the path to a shell script that signs certificate requests. + // Script receives: CSR_PATH, COMMON_NAME, OUTPUT_CERT_PATH as env vars. + // Must output the signed certificate PEM to OUTPUT_CERT_PATH. + // Example: /opt/ca-scripts/sign.sh + SignScript string + + // RevokeScript is the path to a shell script that revokes certificates. + // Script receives: SERIAL_NUMBER, REASON_CODE as env vars. + // Best-effort: script failures do not block revocation recording. + // Leave empty if revocation is not supported by the custom CA. + RevokeScript string + + // CRLScript is the path to a shell script that generates CRL (Certificate Revocation List). + // Script should output the DER-encoded CRL to stdout. + // Leave empty if CRL generation is not supported by the custom CA. + CRLScript string + + // TimeoutSeconds is the maximum execution time for any shell script invocation. + // Default: 30 seconds. Prevents hung processes from blocking certificate operations. + TimeoutSeconds int +}