From acaf250fa8cd30b9d8b0a8d128e813d7e6738edc Mon Sep 17 00:00:00 2001 From: Luis Pater Date: Wed, 17 Jun 2026 21:48:34 +0800 Subject: [PATCH] feat(management): add test to validate priority preservation in auth file uploads - Implemented `TestUploadAuthFile_PreservesPriorityAttributes` to ensure priority attributes and metadata are preserved during auth file uploads. - Updated `UploadAuthFile` logic to utilize `SynthesizeAuthFile` for better handling of generated auth attributes and metadata. Closes: #2924 --- .../api/handlers/management/auth_files.go | 41 +++++++---- .../management/auth_files_upload_test.go | 69 +++++++++++++++++++ 2 files changed, 97 insertions(+), 13 deletions(-) create mode 100644 internal/api/handlers/management/auth_files_upload_test.go diff --git a/internal/api/handlers/management/auth_files.go b/internal/api/handlers/management/auth_files.go index 8c1a7da2f..e24836909 100644 --- a/internal/api/handlers/management/auth_files.go +++ b/internal/api/handlers/management/auth_files.go @@ -32,6 +32,7 @@ import ( "github.com/router-for-me/CLIProxyAPI/v7/internal/misc" "github.com/router-for-me/CLIProxyAPI/v7/internal/registry" "github.com/router-for-me/CLIProxyAPI/v7/internal/util" + "github.com/router-for-me/CLIProxyAPI/v7/internal/watcher/synthesizer" sdkAuth "github.com/router-for-me/CLIProxyAPI/v7/sdk/auth" coreauth "github.com/router-for-me/CLIProxyAPI/v7/sdk/cliproxy/auth" "github.com/router-for-me/CLIProxyAPI/v7/sdk/pluginapi" @@ -1161,21 +1162,35 @@ func (h *Handler) buildAuthFromFileData(path string, data []byte) (*coreauth.Aut if authID == "" { authID = path } - attr := map[string]string{ - "path": path, - "source": path, + auth := (*coreauth.Auth)(nil) + if h != nil && h.cfg != nil { + sctx := &synthesizer.SynthesisContext{ + Config: h.cfg, + AuthDir: h.cfg.AuthDir, + Now: time.Now(), + IDGenerator: synthesizer.NewStableIDGenerator(), + } + if generated := synthesizer.SynthesizeAuthFile(sctx, path, data); len(generated) > 0 && generated[0] != nil { + auth = generated[0].Clone() + } } - auth := &coreauth.Auth{ - ID: authID, - Provider: provider, - FileName: filepath.Base(path), - Label: label, - Status: coreauth.StatusActive, - Attributes: attr, - Metadata: metadata, - CreatedAt: time.Now(), - UpdatedAt: time.Now(), + if auth == nil { + auth = &coreauth.Auth{ + ID: authID, + Provider: provider, + Label: label, + Status: coreauth.StatusActive, + Attributes: map[string]string{ + "path": path, + "source": path, + }, + Metadata: metadata, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } } + auth.ID = authID + auth.FileName = filepath.Base(path) if hasLastRefresh { auth.LastRefreshedAt = lastRefresh } diff --git a/internal/api/handlers/management/auth_files_upload_test.go b/internal/api/handlers/management/auth_files_upload_test.go new file mode 100644 index 000000000..108c8bac7 --- /dev/null +++ b/internal/api/handlers/management/auth_files_upload_test.go @@ -0,0 +1,69 @@ +package management + +import ( + "bytes" + "encoding/json" + "mime/multipart" + "net/http" + "net/http/httptest" + "testing" + + "github.com/gin-gonic/gin" + "github.com/router-for-me/CLIProxyAPI/v7/internal/config" + coreauth "github.com/router-for-me/CLIProxyAPI/v7/sdk/cliproxy/auth" +) + +func TestUploadAuthFile_PreservesPriorityAttributes(t *testing.T) { + t.Setenv("MANAGEMENT_PASSWORD", "") + gin.SetMode(gin.TestMode) + + authDir := t.TempDir() + manager := coreauth.NewManager(nil, nil, nil) + h := NewHandlerWithoutConfigFilePath(&config.Config{AuthDir: authDir}, manager) + + content := `{"type":"codex","email":"midai0530@gmail.com","priority":98}` + + var body bytes.Buffer + writer := multipart.NewWriter(&body) + part, err := writer.CreateFormFile("file", "codex-midai0530@gmail.com-plus.json") + if err != nil { + t.Fatalf("failed to create multipart file: %v", err) + } + if _, err = part.Write([]byte(content)); err != nil { + t.Fatalf("failed to write multipart content: %v", err) + } + if err = writer.Close(); err != nil { + t.Fatalf("failed to close multipart writer: %v", err) + } + + rec := httptest.NewRecorder() + ctx, _ := gin.CreateTestContext(rec) + req := httptest.NewRequest(http.MethodPost, "/v0/management/auth-files", &body) + req.Header.Set("Content-Type", writer.FormDataContentType()) + ctx.Request = req + + h.UploadAuthFile(ctx) + + if rec.Code != http.StatusOK { + t.Fatalf("expected upload status %d, got %d with body %s", http.StatusOK, rec.Code, rec.Body.String()) + } + + var payload map[string]any + if err = json.Unmarshal(rec.Body.Bytes(), &payload); err != nil { + t.Fatalf("failed to decode response: %v", err) + } + if status, _ := payload["status"].(string); status != "ok" { + t.Fatalf("expected status ok, got %#v", payload["status"]) + } + + auth, ok := manager.GetByID("codex-midai0530@gmail.com-plus.json") + if !ok || auth == nil { + t.Fatalf("expected uploaded auth record to exist") + } + if got := auth.Attributes["priority"]; got != "98" { + t.Fatalf("priority attribute = %q, want %q", got, "98") + } + if got := auth.Metadata["priority"]; got != float64(98) { + t.Fatalf("priority metadata = %#v, want 98", got) + } +}