fix(backend): secure production startup and migrations
This commit is contained in:
68
backend/internal/testutil/postgres_integration.go
Normal file
68
backend/internal/testutil/postgres_integration.go
Normal file
@@ -0,0 +1,68 @@
|
||||
//go:build integration
|
||||
|
||||
// Package testutil contains opt-in helpers for isolated integration databases.
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// OpenIsolatedPostgres creates a random schema and binds every pooled test
|
||||
// connection to it through search_path. It never reads the production DSN.
|
||||
func OpenIsolatedPostgres(t testing.TB, config *gorm.Config) *gorm.DB {
|
||||
t.Helper()
|
||||
dsn := strings.TrimSpace(os.Getenv("TEST_DATABASE_URL"))
|
||||
require.NotEmpty(t, dsn, "TEST_DATABASE_URL is required for integration tests and must point to an isolated database")
|
||||
|
||||
schema := randomSchemaName(t)
|
||||
admin, err := gorm.Open(postgres.Open(dsn), config)
|
||||
require.NoError(t, err)
|
||||
adminSQL, err := admin.DB()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, admin.Exec(fmt.Sprintf(`CREATE SCHEMA "%s"`, schema)).Error)
|
||||
|
||||
schemaDSN, err := postgresSchemaDSN(dsn, schema)
|
||||
require.NoError(t, err)
|
||||
database, err := gorm.Open(postgres.Open(schemaDSN), config)
|
||||
require.NoError(t, err)
|
||||
isolationSQL, err := database.DB()
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
_ = isolationSQL.Close()
|
||||
_ = admin.Exec(fmt.Sprintf(`DROP SCHEMA IF EXISTS "%s" CASCADE`, schema)).Error
|
||||
_ = adminSQL.Close()
|
||||
})
|
||||
return database
|
||||
}
|
||||
|
||||
func randomSchemaName(t testing.TB) string {
|
||||
t.Helper()
|
||||
value := make([]byte, 12)
|
||||
_, err := rand.Read(value)
|
||||
require.NoError(t, err)
|
||||
return "senlin_test_" + hex.EncodeToString(value)
|
||||
}
|
||||
|
||||
func postgresSchemaDSN(dsn, schema string) (string, error) {
|
||||
if strings.Contains(dsn, "://") {
|
||||
parsed, err := url.Parse(dsn)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
query := parsed.Query()
|
||||
query.Set("search_path", schema)
|
||||
parsed.RawQuery = query.Encode()
|
||||
return parsed.String(), nil
|
||||
}
|
||||
return strings.TrimSpace(dsn) + " search_path=" + schema, nil
|
||||
}
|
||||
Reference in New Issue
Block a user