fix: stabilize development config and account settings

This commit is contained in:
2026-07-11 17:15:38 +08:00
parent d2cb6bbbc6
commit 7f2d5579ff
19 changed files with 607 additions and 392 deletions
+49 -1
View File
@@ -3,6 +3,7 @@ package database
import (
"errors"
"fmt"
"os"
"github.com/golang-migrate/migrate/v4"
_ "github.com/golang-migrate/migrate/v4/database/postgres"
@@ -10,6 +11,17 @@ import (
_ "github.com/golang-migrate/migrate/v4/source/file"
)
var unsupportedPQEnvironmentKeys = []string{"PGSERVICE", "PGSERVICEFILE", "PGREALM"}
// SanitizePostgresEnvironment removes libpq service-file settings that are
// incompatible with GoChat's explicit database configuration and can make
// both pgx and lib/pq ignore or reject the configured host/user/database.
func SanitizePostgresEnvironment() {
for _, key := range unsupportedPQEnvironmentKeys {
_ = os.Unsetenv(key)
}
}
// RunMigrations applies all pending database migrations from the given path.
// dbURL should be a database connection string (PostgreSQL or SQLite).
// migrationsPath should be a file path to the migrations directory (e.g. "migrations").
@@ -20,6 +32,12 @@ import (
// - A migration fails to apply
// - The database is in a dirty state (a previous migration partially failed)
func RunMigrations(dbURL string, migrationsPath string) error {
return withSanitizedPQEnvironment(func() error {
return runMigrations(dbURL, migrationsPath)
})
}
func runMigrations(dbURL string, migrationsPath string) error {
m, err := migrate.New(
fmt.Sprintf("file://%s", migrationsPath),
dbURL,
@@ -45,6 +63,36 @@ func RunMigrations(dbURL string, migrationsPath string) error {
return nil
}
// withSanitizedPQEnvironment prevents lib/pq from panicking when PostgreSQL
// service-file variables are inherited from the user's shell. GoChat passes a
// complete connection URL to golang-migrate, and lib/pq does not support these
// libpq service variables. Restore them after the migration operation so this
// workaround remains scoped to the legacy migration driver.
func withSanitizedPQEnvironment(fn func() error) error {
type savedValue struct {
value string
set bool
}
saved := make(map[string]savedValue, len(unsupportedPQEnvironmentKeys))
for _, key := range unsupportedPQEnvironmentKeys {
value, set := os.LookupEnv(key)
saved[key] = savedValue{value: value, set: set}
_ = os.Unsetenv(key)
}
defer func() {
for _, key := range unsupportedPQEnvironmentKeys {
previous := saved[key]
if previous.set {
_ = os.Setenv(key, previous.value)
} else {
_ = os.Unsetenv(key)
}
}
}()
return fn()
}
// MigrateSteps applies N migration steps (positive = up, negative = down).
func MigrateSteps(dbURL string, migrationsPath string, steps int) error {
m, err := migrate.New(
@@ -128,4 +176,4 @@ func CurrentVersion(dbURL string, migrationsPath string) (uint, bool, error) {
}
return version, dirty, nil
}
}
+39
View File
@@ -0,0 +1,39 @@
package database
import (
"os"
"testing"
"github.com/stretchr/testify/require"
)
func TestWithSanitizedPQEnvironment(t *testing.T) {
t.Setenv("PGSERVICE", "local-service")
t.Setenv("PGSERVICEFILE", "/tmp/pg_service.conf")
t.Setenv("PGREALM", "local-realm")
err := withSanitizedPQEnvironment(func() error {
for _, key := range []string{"PGSERVICE", "PGSERVICEFILE", "PGREALM"} {
_, exists := os.LookupEnv(key)
require.False(t, exists, "%s should be unset during migration", key)
}
return nil
})
require.NoError(t, err)
require.Equal(t, "local-service", os.Getenv("PGSERVICE"))
require.Equal(t, "/tmp/pg_service.conf", os.Getenv("PGSERVICEFILE"))
require.Equal(t, "local-realm", os.Getenv("PGREALM"))
}
func TestSanitizePostgresEnvironment(t *testing.T) {
t.Setenv("PGSERVICE", "local-service")
t.Setenv("PGSERVICEFILE", "/tmp/pg_service.conf")
t.Setenv("PGREALM", "local-realm")
SanitizePostgresEnvironment()
for _, key := range unsupportedPQEnvironmentKeys {
_, exists := os.LookupEnv(key)
require.False(t, exists, "%s should be removed at application startup", key)
}
}