Skip to content

Commit 46ca680

Browse files
fix(pg): add tls host support for pgdump
1 parent a8c753e commit 46ca680

2 files changed

Lines changed: 106 additions & 8 deletions

File tree

flow/connectors/postgres/pgdump_schema.go

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,13 @@ func runPipeline(
233233
return nil
234234
}
235235

236+
func tlsHostOrHost(config *protos.PostgresConfig) string {
237+
if config.TlsHost != "" {
238+
return config.TlsHost
239+
}
240+
return config.Host
241+
}
242+
236243
func buildPgDumpArgs(config *protos.PostgresConfig) []string {
237244
port := config.Port
238245
if port == 0 {
@@ -243,7 +250,7 @@ func buildPgDumpArgs(config *protos.PostgresConfig) []string {
243250
"--schema-only",
244251
"--no-owner",
245252
"--no-privileges",
246-
"-h", config.Host,
253+
"-h", tlsHostOrHost(config),
247254
"-p", strconv.FormatUint(uint64(port), 10),
248255
"-d", config.Database,
249256
}
@@ -260,7 +267,7 @@ func buildPsqlArgs(config *protos.PostgresConfig) []string {
260267
}
261268

262269
args := []string{
263-
"-h", config.Host,
270+
"-h", tlsHostOrHost(config),
264271
"-p", strconv.FormatUint(uint64(port), 10),
265272
"-d", config.Database,
266273
// Wrap the entire dump in a single transaction so partial failures
@@ -282,8 +289,6 @@ func buildPsqlArgs(config *protos.PostgresConfig) []string {
282289

283290
func appendTLSEnv(ctx context.Context, cmd *exec.Cmd, config *protos.PostgresConfig) {
284291
hasRootCA := config.RootCa != nil && *config.RootCa != ""
285-
// Match the regular connector: enable TLS when explicitly required OR when
286-
// a root CA is provided (which implies the user wants a verified connection).
287292
if !internal.PGMustUseTlsConnection(config) && !hasRootCA {
288293
return
289294
}
@@ -294,13 +299,10 @@ func appendTLSEnv(ctx context.Context, cmd *exec.Cmd, config *protos.PostgresCon
294299
case hasRootCA:
295300
cmd.Env = append(cmd.Env, "PGSSLMODE=verify-ca")
296301
default:
297-
// TLS required but no CA provided — encrypt the connection without
298-
// attempting certificate verification (matches pgx "require" behaviour).
299302
cmd.Env = append(cmd.Env, "PGSSLMODE=require")
300303
}
301304

302305
if hasRootCA {
303-
// write root CA to a temp file
304306
tmpFile, err := os.CreateTemp("", "peerdb-root-ca-*.pem")
305307
if err != nil {
306308
slog.WarnContext(ctx, "failed to create temp file for root CA, skipping sslrootcert", slog.Any("error", err))
@@ -314,6 +316,9 @@ func appendTLSEnv(ctx context.Context, cmd *exec.Cmd, config *protos.PostgresCon
314316
}
315317
tmpFile.Close()
316318
cmd.Env = append(cmd.Env, "PGSSLROOTCERT="+tmpFile.Name())
317-
// note: temp file is cleaned up when the process exits
319+
}
320+
321+
if config.TlsHost != "" {
322+
cmd.Env = append(cmd.Env, "PGHOSTADDR="+config.Host)
318323
}
319324
}

flow/connectors/postgres/pgdump_schema_test.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,20 @@ func TestBuildPgDumpArgs(t *testing.T) {
319319
"-h", "remote", "-p", "6543", "-d", "prod",
320320
},
321321
},
322+
{
323+
name: "TlsHost overrides -h",
324+
config: &protos.PostgresConfig{
325+
Host: "10.0.0.1",
326+
Port: 5432,
327+
Database: "mydb",
328+
User: "admin",
329+
TlsHost: "db.example.com",
330+
},
331+
wantArgs: []string{
332+
"--schema-only", "--no-owner", "--no-privileges",
333+
"-h", "db.example.com", "-p", "5432", "-d", "mydb", "-U", "admin",
334+
},
335+
},
322336
}
323337

324338
for _, tt := range tests {
@@ -367,6 +381,23 @@ func TestBuildPsqlArgs(t *testing.T) {
367381
"--quiet",
368382
},
369383
},
384+
{
385+
name: "TlsHost overrides -h",
386+
config: &protos.PostgresConfig{
387+
Host: "10.0.0.1",
388+
Port: 5432,
389+
Database: "db",
390+
User: "u",
391+
TlsHost: "db.example.com",
392+
},
393+
wantArgs: []string{
394+
"-h", "db.example.com", "-p", "5432", "-d", "db",
395+
"--single-transaction",
396+
"-v", "ON_ERROR_STOP=1",
397+
"--quiet",
398+
"-U", "u",
399+
},
400+
},
370401
}
371402

372403
for _, tt := range tests {
@@ -515,6 +546,68 @@ func TestAppendTLSEnv(t *testing.T) {
515546
}
516547
}
517548

549+
func TestAppendTLSEnv_TlsHost(t *testing.T) {
550+
ctx := t.Context()
551+
552+
t.Run("PGHOSTADDR set when TlsHost configured", func(t *testing.T) {
553+
cmd := exec.CommandContext(ctx, "echo") //nolint:gosec
554+
cmd.Env = os.Environ()
555+
556+
config := &protos.PostgresConfig{
557+
Host: "10.0.0.1", Port: 5432, Database: "d",
558+
RequireTls: true,
559+
TlsHost: "db.example.com",
560+
}
561+
appendTLSEnv(ctx, cmd, config)
562+
563+
if got := envValue(cmd, "PGHOSTADDR"); got != "10.0.0.1" {
564+
t.Errorf("PGHOSTADDR = %q, want %q", got, "10.0.0.1")
565+
}
566+
if got := envValue(cmd, "PGSSLMODE"); got != "require" {
567+
t.Errorf("PGSSLMODE = %q, want %q", got, "require")
568+
}
569+
})
570+
571+
t.Run("PGHOSTADDR not set when TlsHost empty", func(t *testing.T) {
572+
cmd := exec.CommandContext(ctx, "echo") //nolint:gosec
573+
cmd.Env = os.Environ()
574+
575+
config := &protos.PostgresConfig{
576+
Host: "10.0.0.1", Port: 5432, Database: "d",
577+
RequireTls: true,
578+
}
579+
appendTLSEnv(ctx, cmd, config)
580+
581+
if got := envValue(cmd, "PGHOSTADDR"); got != "" {
582+
t.Errorf("PGHOSTADDR should be empty, got %q", got)
583+
}
584+
})
585+
586+
t.Run("PGHOSTADDR with root CA and TlsHost", func(t *testing.T) {
587+
cmd := exec.CommandContext(ctx, "echo") //nolint:gosec
588+
cmd.Env = os.Environ()
589+
590+
config := &protos.PostgresConfig{
591+
Host: "10.0.0.1", Port: 5432, Database: "d",
592+
RequireTls: true,
593+
TlsHost: "db.example.com",
594+
RootCa: strPtr("-----BEGIN CERTIFICATE-----\ntest\n-----END CERTIFICATE-----"),
595+
}
596+
appendTLSEnv(ctx, cmd, config)
597+
598+
if got := envValue(cmd, "PGHOSTADDR"); got != "10.0.0.1" {
599+
t.Errorf("PGHOSTADDR = %q, want %q", got, "10.0.0.1")
600+
}
601+
if got := envValue(cmd, "PGSSLMODE"); got != "verify-ca" {
602+
t.Errorf("PGSSLMODE = %q, want %q", got, "verify-ca")
603+
}
604+
// clean up temp file
605+
if f := envValue(cmd, "PGSSLROOTCERT"); f != "" {
606+
os.Remove(f)
607+
}
608+
})
609+
}
610+
518611
func TestIncompatibleLineRegex(t *testing.T) {
519612
tests := []struct {
520613
line string

0 commit comments

Comments
 (0)