T-1: buildTLSConfig Shared + Conditional CA Validation
Description
Create shared function for building tls.Config from in-memory CA PEM and make CA validation conditional in the connection model. This function will be the reusable base for all factories (MySQL, SQL Server, Oracle).
Delivered Value
Reusable base for all factories + users are no longer required to provide CA when unnecessary.
Files to Create/Modify
| File |
Action |
Description |
pkg/datasource/tlsutil/tlsconfig.go |
Create |
Shared BuildTLSConfig function |
pkg/datasource/tlsutil/tlsconfig_test.go |
Create |
Unit tests |
pkg/model/connection.go |
Modify |
Conditional CA validation |
pkg/model/connection_test.go |
Modify |
Tests for conditional validation |
Implementation
tlsconfig.go:
package tlsutil
import (
"crypto/tls"
"crypto/x509"
"fmt"
)
// BuildTLSConfig cria tls.Config a partir de PEM strings in-memory.
// caCertPEM: CA certificate (obrigatorio).
// serverName: hostname para validacao (pode ser vazio).
// clientCertPEM, clientKeyPEM: client certificate para mTLS (opcionais, devem ser fornecidos juntos).
func BuildTLSConfig(caCertPEM string, serverName string, clientCertPEM string, clientKeyPEM string) (*tls.Config, error) {
if caCertPEM == "" {
return nil, fmt.Errorf("CA certificate PEM content is empty")
}
certPool := x509.NewCertPool()
if ok := certPool.AppendCertsFromPEM([]byte(caCertPEM)); !ok {
return nil, fmt.Errorf("failed to parse CA certificate PEM (length=%d)", len(caCertPEM))
}
tlsConfig := &tls.Config{
RootCAs: certPool,
MinVersion: tls.VersionTLS12,
}
if serverName != "" {
tlsConfig.ServerName = serverName
}
// mTLS: client certificate (Cert e Key devem ser fornecidos juntos)
if clientCertPEM != "" || clientKeyPEM != "" {
if clientCertPEM == "" || clientKeyPEM == "" {
return nil, fmt.Errorf("client certificate and key must be provided together for mTLS")
}
clientCert, err := tls.X509KeyPair([]byte(clientCertPEM), []byte(clientKeyPEM))
if err != nil {
return nil, fmt.Errorf("failed to parse client certificate/key PEM: %w", err)
}
tlsConfig.Certificates = []tls.Certificate{clientCert}
}
return tlsConfig, nil
}
Conditional validation in connection.go:
func (conn *Connection) validateSSLRequiredFields(requiredFields map[string]string) {
if conn.SSL == nil {
return
}
if conn.SSL.Mode == "" {
requiredFields["ssl.mode"] = "SSL mode is required"
}
// CA e opcional - quando fornecido, e utilizado pela factory.
// Quando nao fornecido, factory usa comportamento default do driver
// (system CA store ou skip verify dependendo do modo).
// mTLS: Cert e Key devem ser fornecidos juntos
hasCert := conn.SSL.Cert != nil && *conn.SSL.Cert != ""
hasKey := conn.SSL.Key != nil && *conn.SSL.Key != ""
if hasCert && !hasKey {
requiredFields["ssl.key"] = "SSL key is required when cert is provided (mTLS)"
}
if hasKey && !hasCert {
requiredFields["ssl.cert"] = "SSL cert is required when key is provided (mTLS)"
}
}
Dependencies
Estimate
- Size: S (small)
- Complexity: Low
Acceptance Criteria
Test Strategy
- Unit tests for
BuildTLSConfig
- Updated unit tests for conditional validation
- Verify existing
connection_test.go tests don't break
Phase 2 - Implementation (parallel)
Task gerada pelo Floki
Jira: FET-144
Link: https://lerian.atlassian.net/browse/FET-144
T-1: buildTLSConfig Shared + Conditional CA Validation
Description
Create shared function for building
tls.Configfrom in-memory CA PEM and make CA validation conditional in the connection model. This function will be the reusable base for all factories (MySQL, SQL Server, Oracle).Delivered Value
Reusable base for all factories + users are no longer required to provide CA when unnecessary.
Files to Create/Modify
pkg/datasource/tlsutil/tlsconfig.gopkg/datasource/tlsutil/tlsconfig_test.gopkg/model/connection.gopkg/model/connection_test.goImplementation
tlsconfig.go:
Conditional validation in connection.go:
Dependencies
Estimate
Acceptance Criteria
BuildTLSConfigcreates validtls.Configfrom CA PEM stringBuildTLSConfigreturns descriptive error for invalid PEMBuildTLSConfigsetsMinVersion: tls.VersionTLS12BuildTLSConfigwith Cert+Key: includes client certificate intls.Config.Certificates(mTLS)BuildTLSConfigwith Cert without Key (or vice-versa): returns "must be provided together" errorBuildTLSConfigwith invalid Cert+Key: returns descriptive errorvalidateSSLRequiredFieldsCertprovided,Keymandatory (and vice-versa)Test Strategy
BuildTLSConfigconnection_test.gotests don't breakPhase 2 - Implementation (parallel)
Task gerada pelo Floki
Jira: FET-144
Link: https://lerian.atlassian.net/browse/FET-144