修复PostgreSQL首次安装连接选项与配置迁移不一致
Some checks are pending
Security Checks / security (push) Waiting to run
Some checks are pending
Security Checks / security (push) Waiting to run
This commit is contained in:
parent
6fe278f612
commit
fa0cea93b8
@ -683,9 +683,21 @@ func parseLegacyMySQLDSN(value string) (DatabaseConfig, string, bool) {
|
||||
|
||||
func parseLegacyPostgreSQLDSN(value string) (DatabaseConfig, string, bool) {
|
||||
parsed, err := url.ParseRequestURI(value)
|
||||
if err != nil || (parsed.Scheme != "postgres" && parsed.Scheme != "postgresql") || parsed.RawQuery != "" || parsed.Fragment != "" || parsed.User == nil || parsed.Host == "" {
|
||||
if err != nil || (parsed.Scheme != "postgres" && parsed.Scheme != "postgresql") || parsed.Fragment != "" || parsed.User == nil || parsed.Host == "" {
|
||||
return DatabaseConfig{}, "", false
|
||||
}
|
||||
// 仅接受正式运行能够原样表达的选项;未知、重复和降级 TLS 的选项仍需人工迁移。
|
||||
query, err := url.ParseQuery(parsed.RawQuery)
|
||||
if err != nil {
|
||||
return DatabaseConfig{}, "", false
|
||||
}
|
||||
supported := map[string]string{"sslmode": "require", "timezone": "UTC", "search_path": "public"}
|
||||
for key, values := range query {
|
||||
expected, known := supported[key]
|
||||
if !known || len(values) != 1 || values[0] != expected {
|
||||
return DatabaseConfig{}, "", false
|
||||
}
|
||||
}
|
||||
username := parsed.User.Username()
|
||||
password, ok := parsed.User.Password()
|
||||
if !ok || !validLegacyDatabaseUser(username) || !validLegacyDatabasePassword(password) {
|
||||
|
||||
51
backend/config/migrate_postgres_test.go
Normal file
51
backend/config/migrate_postgres_test.go
Normal file
@ -0,0 +1,51 @@
|
||||
package config
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestLegacyPostgresRuntimeOptions(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
query string
|
||||
valid bool
|
||||
}{
|
||||
{"", true},
|
||||
{"sslmode=require", true},
|
||||
{"sslmode=require&timezone=UTC&search_path=public", true},
|
||||
{"sslmode=disable", false},
|
||||
{"sslmode=prefer", false},
|
||||
{"sslmode=verify-full", false},
|
||||
{"sslmode=require&sslmode=disable", false},
|
||||
{"sslmode=require&sslmode=require", false},
|
||||
{"sslmode=require&options=-c%20search_path%3Dprivate", false},
|
||||
{"sslmode=require&search_path=private", false},
|
||||
{"sslmode=require&timezone=Asia%2FShanghai", false},
|
||||
{"sslmode=require&unknown=", false},
|
||||
{"sslmode=require;search_path=private", false},
|
||||
{"sslmode=%zz", false},
|
||||
} {
|
||||
t.Run(test.query, func(t *testing.T) {
|
||||
value := "postgres://smail:sample@127.0.0.1:5432/smail"
|
||||
if test.query != "" {
|
||||
value += "?" + test.query
|
||||
}
|
||||
database, password, valid := parseLegacyPostgreSQLDSN(value)
|
||||
if valid != test.valid {
|
||||
t.Fatalf("连接选项验证错误:%t", valid)
|
||||
}
|
||||
if valid && (database.Type != DatabaseTypePostgreSQL || database.Port != 5432 || password != "sample") {
|
||||
t.Fatal("安全选项影响了数据库连接字段")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLegacyPostgresSetupDSNMigration(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
writeLegacyMigrationFixture(t, root, map[string]any{
|
||||
"dbType": DBTypePostgres,
|
||||
"dbDSN": "postgres://smail:sample@127.0.0.1:5432/smail?sslmode=require",
|
||||
})
|
||||
plan, err := PlanLegacyMigration(root, RuntimeValidationOptions{})
|
||||
if err != nil || len(plan.ManualFields) != 0 {
|
||||
t.Fatalf("首次安装产生的安全连接串不能迁移:%v", err)
|
||||
}
|
||||
}
|
||||
@ -363,7 +363,8 @@ func buildPostgresDSN(settings DatabaseSettings, previousDSN string) (string, er
|
||||
query = previous.Query()
|
||||
}
|
||||
if query.Get("sslmode") == "" {
|
||||
query.Set("sslmode", "disable")
|
||||
// 首次安装与正式运行保持相同的 TLS 要求,避免完成安装时切换连接语义。
|
||||
query.Set("sslmode", "require")
|
||||
}
|
||||
parsed := &url.URL{
|
||||
Scheme: "postgres",
|
||||
|
||||
@ -135,7 +135,7 @@ func TestBuildPostgresDSNUsesStructuredFields(t *testing.T) {
|
||||
if host != "2001:db8::2" || port != "5432" || strings.TrimPrefix(parsed.Path, "/") != "smail_1" {
|
||||
t.Fatalf("unexpected connection settings: host=%q port=%q name=%q", host, port, parsed.Path)
|
||||
}
|
||||
if parsed.Query().Get("sslmode") != "disable" {
|
||||
if parsed.Query().Get("sslmode") != "require" {
|
||||
t.Fatalf("unexpected sslmode: %q", parsed.Query().Get("sslmode"))
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user