fix(qfs): project ui, config naming, sync timestamps - v1.5.4
This commit is contained in:
@@ -39,6 +39,10 @@ logging:
|
||||
t.Fatalf("load legacy config: %v", err)
|
||||
}
|
||||
setConfigDefaults(cfg)
|
||||
cfg.Server.Host, _, err = normalizeLoopbackServerHost(cfg.Server.Host)
|
||||
if err != nil {
|
||||
t.Fatalf("normalize server host: %v", err)
|
||||
}
|
||||
if err := migrateConfigFileToRuntimeShape(path, cfg); err != nil {
|
||||
t.Fatalf("migrate config: %v", err)
|
||||
}
|
||||
@@ -60,32 +64,43 @@ logging:
|
||||
if !strings.Contains(text, "port: 9191") {
|
||||
t.Fatalf("migrated config did not preserve server port:\n%s", text)
|
||||
}
|
||||
if !strings.Contains(text, "host: 127.0.0.1") {
|
||||
t.Fatalf("migrated config did not normalize server host:\n%s", text)
|
||||
}
|
||||
if !strings.Contains(text, "level: debug") {
|
||||
t.Fatalf("migrated config did not preserve logging level:\n%s", text)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnsureLoopbackServerHost(t *testing.T) {
|
||||
func TestNormalizeLoopbackServerHost(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
cases := []struct {
|
||||
host string
|
||||
wantErr bool
|
||||
host string
|
||||
want string
|
||||
wantChanged bool
|
||||
wantErr bool
|
||||
}{
|
||||
{host: "127.0.0.1", wantErr: false},
|
||||
{host: "localhost", wantErr: false},
|
||||
{host: "::1", wantErr: false},
|
||||
{host: "0.0.0.0", wantErr: true},
|
||||
{host: "192.168.1.10", wantErr: true},
|
||||
{host: "127.0.0.1", want: "127.0.0.1", wantChanged: false, wantErr: false},
|
||||
{host: "localhost", want: "127.0.0.1", wantChanged: true, wantErr: false},
|
||||
{host: "::1", want: "127.0.0.1", wantChanged: true, wantErr: false},
|
||||
{host: "0.0.0.0", want: "127.0.0.1", wantChanged: true, wantErr: false},
|
||||
{host: "192.168.1.10", want: "127.0.0.1", wantChanged: true, wantErr: false},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
err := ensureLoopbackServerHost(tc.host)
|
||||
got, changed, err := normalizeLoopbackServerHost(tc.host)
|
||||
if tc.wantErr && err == nil {
|
||||
t.Fatalf("expected error for host %q", tc.host)
|
||||
}
|
||||
if !tc.wantErr && err != nil {
|
||||
t.Fatalf("unexpected error for host %q: %v", tc.host, err)
|
||||
}
|
||||
if got != tc.want {
|
||||
t.Fatalf("unexpected normalized host for %q: got %q want %q", tc.host, got, tc.want)
|
||||
}
|
||||
if changed != tc.wantChanged {
|
||||
t.Fatalf("unexpected changed flag for %q: got %t want %t", tc.host, changed, tc.wantChanged)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,10 +148,15 @@ func main() {
|
||||
}
|
||||
}
|
||||
setConfigDefaults(cfg)
|
||||
if err := ensureLoopbackServerHost(cfg.Server.Host); err != nil {
|
||||
normalizedHost, changed, err := normalizeLoopbackServerHost(cfg.Server.Host)
|
||||
if err != nil {
|
||||
slog.Error("invalid server host", "host", cfg.Server.Host, "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if changed {
|
||||
slog.Warn("corrected server host to loopback", "from", cfg.Server.Host, "to", normalizedHost)
|
||||
}
|
||||
cfg.Server.Host = normalizedHost
|
||||
if err := migrateConfigFileToRuntimeShape(resolvedConfigPath, cfg); err != nil {
|
||||
slog.Error("failed to migrate config file format", "path", resolvedConfigPath, "error", err)
|
||||
os.Exit(1)
|
||||
@@ -334,21 +339,28 @@ func setConfigDefaults(cfg *config.Config) {
|
||||
}
|
||||
}
|
||||
|
||||
func ensureLoopbackServerHost(host string) error {
|
||||
func normalizeLoopbackServerHost(host string) (string, bool, error) {
|
||||
trimmed := strings.TrimSpace(host)
|
||||
if trimmed == "" {
|
||||
return fmt.Errorf("server.host must not be empty")
|
||||
return "", false, fmt.Errorf("server.host must not be empty")
|
||||
}
|
||||
const loopbackHost = "127.0.0.1"
|
||||
if trimmed == loopbackHost {
|
||||
return loopbackHost, false, nil
|
||||
}
|
||||
if strings.EqualFold(trimmed, "localhost") {
|
||||
return nil
|
||||
return loopbackHost, true, nil
|
||||
}
|
||||
|
||||
ip := net.ParseIP(strings.Trim(trimmed, "[]"))
|
||||
if ip != nil && ip.IsLoopback() {
|
||||
return nil
|
||||
if ip != nil {
|
||||
if ip.IsLoopback() || ip.IsUnspecified() {
|
||||
return loopbackHost, trimmed != loopbackHost, nil
|
||||
}
|
||||
return loopbackHost, true, nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("QuoteForge local client must bind to localhost only")
|
||||
return loopbackHost, true, nil
|
||||
}
|
||||
|
||||
func vendorImportBodyLimit() int64 {
|
||||
@@ -1490,6 +1502,8 @@ func setupRouter(cfg *config.Config, local *localdb.LocalDB, connMgr *db.Connect
|
||||
project, err := projectService.Create(dbUsername, &req)
|
||||
if err != nil {
|
||||
switch {
|
||||
case errors.Is(err, services.ErrReservedMainVariant):
|
||||
respondError(c, http.StatusBadRequest, "invalid request", err)
|
||||
case errors.Is(err, services.ErrProjectCodeExists):
|
||||
respondError(c, http.StatusConflict, "conflict detected", err)
|
||||
default:
|
||||
@@ -1525,6 +1539,8 @@ func setupRouter(cfg *config.Config, local *localdb.LocalDB, connMgr *db.Connect
|
||||
project, err := projectService.Update(c.Param("uuid"), dbUsername, &req)
|
||||
if err != nil {
|
||||
switch {
|
||||
case errors.Is(err, services.ErrReservedMainVariant):
|
||||
respondError(c, http.StatusBadRequest, "invalid request", err)
|
||||
case errors.Is(err, services.ErrProjectCodeExists):
|
||||
respondError(c, http.StatusConflict, "conflict detected", err)
|
||||
case errors.Is(err, services.ErrProjectNotFound):
|
||||
|
||||
Reference in New Issue
Block a user