diff --git a/openflare_server/service/config_version.go b/openflare_server/service/config_version.go index 35b3c45e..18697215 100644 --- a/openflare_server/service/config_version.go +++ b/openflare_server/service/config_version.go @@ -12,6 +12,7 @@ import ( "openflare/model" "regexp" "sort" + "strconv" "strings" "time" @@ -1270,11 +1271,24 @@ func checksumBundle(mainConfig string, routeConfig string, supportFiles []Suppor func nextVersionNumber(now time.Time) (string, error) { prefix := now.Format("20060102") - var count int64 - if err := model.DB.Model(&model.ConfigVersion{}).Where("version LIKE ?", prefix+"-%").Count(&count).Error; err != nil { + var latest model.ConfigVersion + err := model.DB. + Select("version"). + Where("version LIKE ?", prefix+"-%"). + Order("version desc"). + First(&latest).Error + if errors.Is(err, gorm.ErrRecordNotFound) { + return fmt.Sprintf("%s-%03d", prefix, 1), nil + } + if err != nil { return "", err } - return fmt.Sprintf("%s-%03d", prefix, count+1), nil + suffix := strings.TrimPrefix(latest.Version, prefix+"-") + sequence, err := strconv.Atoi(suffix) + if err != nil { + return "", fmt.Errorf("invalid config version sequence %q: %w", latest.Version, err) + } + return fmt.Sprintf("%s-%03d", prefix, sequence+1), nil } func renderHTTPProxyServer(serverNames string, originURL string, originHost string, customHeaders []ProxyRouteCustomHeaderInput, cacheConfig routeCacheConfig, limitConfig routeLimitConfig, upstreamConfig routeUpstreamConfig, powEnabled bool, basicAuthEnabled bool, basicAuthUsername string, basicAuthPassword string, cfg openRestyConfigSnapshot) string { diff --git a/openflare_server/service/https_phase1_test.go b/openflare_server/service/https_phase1_test.go index 7f02c5e2..94f90a82 100644 --- a/openflare_server/service/https_phase1_test.go +++ b/openflare_server/service/https_phase1_test.go @@ -102,6 +102,42 @@ func TestCreateTLSCertificateAndRenderHTTPSConfig(t *testing.T) { } } +func TestNextVersionNumberUsesMaxDailySequence(t *testing.T) { + setupServiceTestDB(t) + + seed := []model.ConfigVersion{ + { + Version: "20260526-001", + SnapshotJSON: "{}", + RenderedConfig: "server {}", + SupportFilesJSON: "[]", + Checksum: "checksum-1", + CreatedBy: "root", + }, + { + Version: "20260526-003", + SnapshotJSON: "{}", + RenderedConfig: "server {}", + SupportFilesJSON: "[]", + Checksum: "checksum-3", + CreatedBy: "root", + }, + } + for _, version := range seed { + if err := model.DB.Create(&version).Error; err != nil { + t.Fatalf("failed to seed config version %s: %v", version.Version, err) + } + } + + next, err := nextVersionNumber(time.Date(2026, 5, 26, 12, 0, 0, 0, time.Local)) + if err != nil { + t.Fatalf("nextVersionNumber failed: %v", err) + } + if next != "20260526-004" { + t.Fatalf("expected next version to follow max suffix, got %s", next) + } +} + func TestCreateProxyRouteRejectsHTTPSWithoutCertificate(t *testing.T) { setupServiceTestDB(t)