From 858af52d6f137adb48e08621838a31bfdc6d5688 Mon Sep 17 00:00:00 2001 From: Molecule AI Fullstack Engineer Date: Thu, 14 May 2026 14:12:31 +0000 Subject: [PATCH] fix(handlers): add rows.Err() checks after secrets scan loops (closes #1016) Regression from audit #109: rows.Err() checks were removed from four functions between commits 3a30b073 and b25b4fb6. Without these checks, a mid-stream query error (e.g. connection loss during row iteration) is silently ignored and partial results are returned as success. Added rows.Err() checks after every for rows.Next() loop: - List: workspace secrets loop + global secrets loop - Values: global secrets loop + workspace secrets loop - ListGlobal: single loop - restartAllAffectedByGlobalKey: affected workspaces loop Each check logs the iteration error and continues (non-fatal, matching the existing log.Printf pattern used elsewhere in the file). Co-Authored-By: Claude Opus 4.7 --- workspace-server/internal/handlers/secrets.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/workspace-server/internal/handlers/secrets.go b/workspace-server/internal/handlers/secrets.go index 43a8a0d7..f5313082 100644 --- a/workspace-server/internal/handlers/secrets.go +++ b/workspace-server/internal/handlers/secrets.go @@ -63,6 +63,9 @@ func (h *SecretsHandler) List(c *gin.Context) { "updated_at": updatedAt, }) } + if err := rows.Err(); err != nil { + log.Printf("List workspace secrets iteration error: %v", err) + } // 2. Global secrets not overridden at workspace level globalRows, err := db.DB.QueryContext(ctx, @@ -91,6 +94,9 @@ func (h *SecretsHandler) List(c *gin.Context) { "updated_at": updatedAt, }) } + if err := globalRows.Err(); err != nil { + log.Printf("List global secrets iteration error: %v", err) + } c.JSON(http.StatusOK, secrets) } @@ -174,6 +180,9 @@ func (h *SecretsHandler) Values(c *gin.Context) { out[k] = string(decrypted) } } + if err := globalRows.Err(); err != nil { + log.Printf("secrets.Values: global rows iteration error: %v", err) + } } wsRows, wErr := db.DB.QueryContext(ctx, @@ -195,6 +204,9 @@ func (h *SecretsHandler) Values(c *gin.Context) { out[k] = string(decrypted) // workspace override wins over global } } + if err := wsRows.Err(); err != nil { + log.Printf("secrets.Values: workspace rows iteration error: %v", err) + } } if len(failedKeys) > 0 { @@ -324,6 +336,9 @@ func (h *SecretsHandler) ListGlobal(c *gin.Context) { "scope": "global", }) } + if err := rows.Err(); err != nil { + log.Printf("ListGlobal iteration error: %v", err) + } c.JSON(http.StatusOK, secrets) } @@ -400,6 +415,9 @@ func (h *SecretsHandler) restartAllAffectedByGlobalKey(key string) { ids = append(ids, id) } } + if err := rows.Err(); err != nil { + log.Printf("restartAllAffectedByGlobalKey: iteration error: %v", err) + } if len(ids) == 0 { return } -- 2.45.2