feat(M42): Postfix/Dovecot mail server target connector

Dual-mode TLS connector for mail servers — single package with mode
field selecting Postfix or Dovecot defaults. File-based cert/key
deployment with correct permissions (cert 0644, key 0600), optional
chain append, shell injection prevention, and configurable
reload/validate commands. 18 tests covering config validation,
deployment, and security. GUI wizard fields and OpenAPI enum updated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Shankar
2026-04-03 01:46:15 -04:00
parent c47d83ccf5
commit 8dc78b7455
8 changed files with 931 additions and 4 deletions
+21
View File
@@ -30,6 +30,7 @@ import (
"github.com/shankar0123/certctl/internal/connector/target/apache"
"github.com/shankar0123/certctl/internal/connector/target/caddy"
"github.com/shankar0123/certctl/internal/connector/target/envoy"
pf "github.com/shankar0123/certctl/internal/connector/target/postfix"
"github.com/shankar0123/certctl/internal/connector/target/f5"
"github.com/shankar0123/certctl/internal/connector/target/haproxy"
"github.com/shankar0123/certctl/internal/connector/target/iis"
@@ -622,6 +623,26 @@ func (a *Agent) createTargetConnector(targetType string, configJSON json.RawMess
}
return envoy.New(&cfg, a.logger), nil
case "Postfix":
var cfg pf.Config
cfg.Mode = "postfix"
if len(configJSON) > 0 {
if err := json.Unmarshal(configJSON, &cfg); err != nil {
return nil, fmt.Errorf("invalid Postfix config: %w", err)
}
}
return pf.New(&cfg, a.logger), nil
case "Dovecot":
var cfg pf.Config
cfg.Mode = "dovecot"
if len(configJSON) > 0 {
if err := json.Unmarshal(configJSON, &cfg); err != nil {
return nil, fmt.Errorf("invalid Dovecot config: %w", err)
}
}
return pf.New(&cfg, a.logger), nil
default:
return nil, fmt.Errorf("unsupported target type: %s", targetType)
}