...
▽

Source file src/github.com/cybertec-postgresql/pgwatch/v6/internal/sources/resolver_tls_test.go

Documentation: github.com/cybertec-postgresql/pgwatch/v6/internal/sources

     1  package sources_test
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	"crypto/elliptic"
     6  	"crypto/rand"
     7  	"crypto/x509"
     8  	"crypto/x509/pkix"
     9  	"encoding/pem"
    10  	"math/big"
    11  	"os"
    12  	"path/filepath"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/stretchr/testify/assert"
    17  	"github.com/stretchr/testify/require"
    18  
    19  	"github.com/cybertec-postgresql/pgwatch/v6/internal/sources"
    20  )
    21  
    22  // writeTestCert writes a self-signed certificate and its key as PEM files
    23  // into dir and returns their paths.
    24  func writeTestCert(t *testing.T, dir string) (certFile, keyFile string) {
    25  	t.Helper()
    26  	key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    27  	require.NoError(t, err)
    28  	tmpl := &x509.Certificate{
    29  		SerialNumber:          big.NewInt(1),
    30  		Subject:               pkix.Name{CommonName: "pgwatch-test"},
    31  		NotBefore:             time.Now().Add(-time.Hour),
    32  		NotAfter:              time.Now().Add(time.Hour),
    33  		IsCA:                  true,
    34  		BasicConstraintsValid: true,
    35  	}
    36  	der, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &key.PublicKey, key)
    37  	require.NoError(t, err)
    38  	keyDer, err := x509.MarshalECPrivateKey(key)
    39  	require.NoError(t, err)
    40  
    41  	certFile = filepath.Join(dir, "cert.pem")
    42  	keyFile = filepath.Join(dir, "key.pem")
    43  	require.NoError(t, os.WriteFile(certFile, pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der}), 0o600))
    44  	require.NoError(t, os.WriteFile(keyFile, pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: keyDer}), 0o600))
    45  	return certFile, keyFile
    46  }
    47  
    48  func TestGetTransport(t *testing.T) {
    49  	dir := t.TempDir()
    50  	certFile, keyFile := writeTestCert(t, dir)
    51  	garbage := filepath.Join(dir, "garbage.pem")
    52  	require.NoError(t, os.WriteFile(garbage, []byte("not a certificate"), 0o600))
    53  
    54  	t.Run("no TLS params", func(t *testing.T) {
    55  		cfg, err := sources.GetTransport(sources.HostConfig{})
    56  		require.NoError(t, err)
    57  		assert.Nil(t, cfg)
    58  	})
    59  
    60  	t.Run("CA only", func(t *testing.T) {
    61  		cfg, err := sources.GetTransport(sources.HostConfig{CAFile: certFile})
    62  		require.NoError(t, err)
    63  		require.NotNil(t, cfg)
    64  		assert.NotNil(t, cfg.RootCAs)
    65  		assert.Empty(t, cfg.Certificates)
    66  	})
    67  
    68  	t.Run("client cert without CA", func(t *testing.T) {
    69  		cfg, err := sources.GetTransport(sources.HostConfig{CertFile: certFile, KeyFile: keyFile})
    70  		require.NoError(t, err)
    71  		require.NotNil(t, cfg)
    72  		assert.Nil(t, cfg.RootCAs, "system CA pool must be used")
    73  		assert.Len(t, cfg.Certificates, 1)
    74  	})
    75  
    76  	t.Run("CA and client cert", func(t *testing.T) {
    77  		cfg, err := sources.GetTransport(sources.HostConfig{CAFile: certFile, CertFile: certFile, KeyFile: keyFile})
    78  		require.NoError(t, err)
    79  		require.NotNil(t, cfg)
    80  		assert.NotNil(t, cfg.RootCAs)
    81  		assert.Len(t, cfg.Certificates, 1)
    82  	})
    83  
    84  	t.Run("missing CA file", func(t *testing.T) {
    85  		_, err := sources.GetTransport(sources.HostConfig{CAFile: filepath.Join(dir, "missing.pem")})
    86  		assert.Error(t, err)
    87  	})
    88  
    89  	t.Run("CA file without certificates", func(t *testing.T) {
    90  		_, err := sources.GetTransport(sources.HostConfig{CAFile: garbage})
    91  		assert.ErrorContains(t, err, "no PEM certificates")
    92  	})
    93  
    94  	t.Run("bad client key", func(t *testing.T) {
    95  		_, err := sources.GetTransport(sources.HostConfig{CertFile: certFile, KeyFile: garbage})
    96  		assert.Error(t, err)
    97  	})
    98  }
    99