From a1634909e85448354d656ad2b3b3f2337b9696bf Mon Sep 17 00:00:00 2001 From: Aldino Kemal Date: Mon, 19 Jan 2026 19:50:36 +0700 Subject: [PATCH 1/2] feat(management): add PATCH endpoint to enable/disable auth files Add new PATCH /v0/management/auth-files/status endpoint that allows toggling the disabled state of auth files without deleting them. This enables users to temporarily disable credentials from the management UI. --- .../api/handlers/management/auth_files.go | 62 +++++++++++++++++++ internal/api/server.go | 1 + 2 files changed, 63 insertions(+) diff --git a/internal/api/handlers/management/auth_files.go b/internal/api/handlers/management/auth_files.go index e6830d1d..005bc7b9 100644 --- a/internal/api/handlers/management/auth_files.go +++ b/internal/api/handlers/management/auth_files.go @@ -747,6 +747,68 @@ func (h *Handler) registerAuthFromFile(ctx context.Context, path string, data [] return err } +// PatchAuthFileStatus toggles the disabled state of an auth file +func (h *Handler) PatchAuthFileStatus(c *gin.Context) { + if h.authManager == nil { + c.JSON(http.StatusServiceUnavailable, gin.H{"error": "core auth manager unavailable"}) + return + } + + var req struct { + Name string `json:"name"` + Disabled *bool `json:"disabled"` + } + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"}) + return + } + + name := strings.TrimSpace(req.Name) + if name == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "name is required"}) + return + } + if req.Disabled == nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "disabled is required"}) + return + } + + ctx := c.Request.Context() + + // Find auth by name or ID + var targetAuth *coreauth.Auth + auths := h.authManager.List() + for _, auth := range auths { + if auth.FileName == name || auth.ID == name { + targetAuth = auth + break + } + } + + if targetAuth == nil { + c.JSON(http.StatusNotFound, gin.H{"error": "auth file not found"}) + return + } + + // Update disabled state + targetAuth.Disabled = *req.Disabled + if *req.Disabled { + targetAuth.Status = coreauth.StatusDisabled + targetAuth.StatusMessage = "disabled via management API" + } else { + targetAuth.Status = coreauth.StatusActive + targetAuth.StatusMessage = "" + } + targetAuth.UpdatedAt = time.Now() + + if _, err := h.authManager.Update(ctx, targetAuth); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("failed to update auth: %v", err)}) + return + } + + c.JSON(http.StatusOK, gin.H{"status": "ok", "disabled": *req.Disabled}) +} + func (h *Handler) disableAuth(ctx context.Context, id string) { if h == nil || h.authManager == nil { return diff --git a/internal/api/server.go b/internal/api/server.go index aa78ac2a..8b26044e 100644 --- a/internal/api/server.go +++ b/internal/api/server.go @@ -610,6 +610,7 @@ func (s *Server) registerManagementRoutes() { mgmt.GET("/auth-files/download", s.mgmt.DownloadAuthFile) mgmt.POST("/auth-files", s.mgmt.UploadAuthFile) mgmt.DELETE("/auth-files", s.mgmt.DeleteAuthFile) + mgmt.PATCH("/auth-files/status", s.mgmt.PatchAuthFileStatus) mgmt.POST("/vertex/import", s.mgmt.ImportVertexCredential) mgmt.GET("/anthropic-auth-url", s.mgmt.RequestAnthropicToken) From 2f6004d74a8cf5706526e836f4da3c13b69e3174 Mon Sep 17 00:00:00 2001 From: Aldino Kemal Date: Mon, 19 Jan 2026 20:05:37 +0700 Subject: [PATCH 2/2] perf(management): optimize auth lookup in PatchAuthFileStatus Use GetByID() for O(1) map lookup first, falling back to iteration only for FileName matching. Consistent with pattern in disableAuth(). --- internal/api/handlers/management/auth_files.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/internal/api/handlers/management/auth_files.go b/internal/api/handlers/management/auth_files.go index 005bc7b9..77988fea 100644 --- a/internal/api/handlers/management/auth_files.go +++ b/internal/api/handlers/management/auth_files.go @@ -777,11 +777,15 @@ func (h *Handler) PatchAuthFileStatus(c *gin.Context) { // Find auth by name or ID var targetAuth *coreauth.Auth - auths := h.authManager.List() - for _, auth := range auths { - if auth.FileName == name || auth.ID == name { - targetAuth = auth - break + if auth, ok := h.authManager.GetByID(name); ok { + targetAuth = auth + } else { + auths := h.authManager.List() + for _, auth := range auths { + if auth.FileName == name { + targetAuth = auth + break + } } }