This commit is contained in:
parent
9404d7f9c8
commit
33b4258fbb
@ -47,9 +47,23 @@ func TestSQLiteLocalRefIsBackendReferenceOnly(t *testing.T) {
|
|||||||
if err := ValidateDatabaseConfig(valid); err != nil {
|
if err := ValidateDatabaseConfig(valid); err != nil {
|
||||||
t.Fatalf("valid SQLite database rejected: %v", err)
|
t.Fatalf("valid SQLite database rejected: %v", err)
|
||||||
}
|
}
|
||||||
|
for _, localRef := range []string{
|
||||||
|
"archive/review.db",
|
||||||
|
"data/2026/smail.db",
|
||||||
|
} {
|
||||||
|
t.Run("nested/"+localRef, func(t *testing.T) {
|
||||||
|
candidate := valid
|
||||||
|
candidate.LocalRef = localRef
|
||||||
|
if err := ValidateDatabaseConfig(candidate); err != nil {
|
||||||
|
t.Fatalf("nested SQLite localRef %q was rejected: %v", localRef, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
for _, localRef := range []string{
|
for _, localRef := range []string{
|
||||||
"../smail.db",
|
"../smail.db",
|
||||||
"config/smail.db",
|
"config/smail.db",
|
||||||
|
"archive/../smail.db",
|
||||||
|
"archive//smail.db",
|
||||||
"C:\\data\\smail.db",
|
"C:\\data\\smail.db",
|
||||||
"/var/lib/smail/smail.db",
|
"/var/lib/smail/smail.db",
|
||||||
"\\\\server\\share\\smail.db",
|
"\\\\server\\share\\smail.db",
|
||||||
|
|||||||
@ -78,7 +78,7 @@ func validateDatabase(database DatabaseConfig) error {
|
|||||||
if !validSQLiteLocalRef(database.LocalRef) ||
|
if !validSQLiteLocalRef(database.LocalRef) ||
|
||||||
filepath.IsAbs(database.LocalRef) ||
|
filepath.IsAbs(database.LocalRef) ||
|
||||||
isWindowsAbsolute(database.LocalRef) ||
|
isWindowsAbsolute(database.LocalRef) ||
|
||||||
strings.ContainsAny(database.LocalRef, `/\\:`) ||
|
strings.ContainsAny(database.LocalRef, `\\:`) ||
|
||||||
database.Host != "" || database.Port != 0 || database.Username != "" ||
|
database.Host != "" || database.Port != 0 || database.Username != "" ||
|
||||||
database.Password.Configured() || database.Password.Ciphertext != "" || database.Password.Version != 0 || !database.Password.UpdatedAt.IsZero() || database.Name != "" {
|
database.Password.Configured() || database.Password.Ciphertext != "" || database.Password.Version != 0 || !database.Password.UpdatedAt.IsZero() || database.Name != "" {
|
||||||
return ErrInvalidDatabase
|
return ErrInvalidDatabase
|
||||||
|
|||||||
@ -172,7 +172,7 @@ func (e *SQLiteExecutor) resolveReference(reference string) (string, error) {
|
|||||||
|
|
||||||
func validSQLiteReference(value string) bool {
|
func validSQLiteReference(value string) bool {
|
||||||
value = filepath.ToSlash(strings.TrimSpace(value))
|
value = filepath.ToSlash(strings.TrimSpace(value))
|
||||||
if value == "" || filepath.IsAbs(value) || isWindowsAbsoluteReference(value) || strings.ContainsAny(value, `\\:`) {
|
if value == "" || filepath.IsAbs(value) || isWindowsAbsoluteReference(value) || strings.HasPrefix(value, "config/") || strings.ContainsAny(value, `\\:`) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for _, part := range strings.Split(value, "/") {
|
for _, part := range strings.Split(value, "/") {
|
||||||
|
|||||||
@ -78,6 +78,34 @@ func TestSQLiteExecutorCopiesDatabaseAndSwitchesConfiguration(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSQLiteExecutorSupportsNestedReferences(t *testing.T) {
|
||||||
|
var switched config.DatabaseConfig
|
||||||
|
service, root := newSQLiteMigrationFixture(t, func(_ context.Context, candidate config.DatabaseConfig) error {
|
||||||
|
switched = candidate
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err := os.MkdirAll(filepath.Join(root, "config", "archive"), 0700); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := os.Rename(filepath.Join(root, "config", "smail.db"), filepath.Join(root, "config", "archive", "review.db")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
record, token, err := service.Preview(context.Background(), config.DatabaseConfig{Type: config.DatabaseTypeSQLite, LocalRef: "archive/review.db"}, 1, "archive/next.db")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
completed, err := service.Execute(context.Background(), record.ID, token)
|
||||||
|
if err != nil || completed.Status != StatusSucceeded {
|
||||||
|
t.Fatalf("nested migration result = %+v, error = %v", completed, err)
|
||||||
|
}
|
||||||
|
if switched.LocalRef != "archive/next.db" {
|
||||||
|
t.Fatalf("switched localRef = %q, want archive/next.db", switched.LocalRef)
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(filepath.Join(root, "config", "archive", "next.db")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestSQLiteExecutorRejectsExistingTarget(t *testing.T) {
|
func TestSQLiteExecutorRejectsExistingTarget(t *testing.T) {
|
||||||
service, root := newSQLiteMigrationFixture(t, func(context.Context, config.DatabaseConfig) error { return nil })
|
service, root := newSQLiteMigrationFixture(t, func(context.Context, config.DatabaseConfig) error { return nil })
|
||||||
if err := os.WriteFile(filepath.Join(root, "config", "smail-next.db"), []byte("existing"), 0600); err != nil {
|
if err := os.WriteFile(filepath.Join(root, "config", "smail-next.db"), []byte("existing"), 0600); err != nil {
|
||||||
|
|||||||
@ -64,7 +64,7 @@ func buildTargetPlan(source, target config.DatabaseConfig) (Plan, error) {
|
|||||||
return Plan{}, ErrInvalidRequest
|
return Plan{}, ErrInvalidRequest
|
||||||
}
|
}
|
||||||
if target.Type == config.DatabaseTypeSQLite {
|
if target.Type == config.DatabaseTypeSQLite {
|
||||||
if !sqliteTargetNamePattern.MatchString(target.LocalRef) {
|
if !validSQLiteReference(target.LocalRef) {
|
||||||
return Plan{}, ErrInvalidTargetName
|
return Plan{}, ErrInvalidTargetName
|
||||||
}
|
}
|
||||||
} else if !targetNamePattern.MatchString(target.Name) {
|
} else if !targetNamePattern.MatchString(target.Name) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user