From 980ec50058d24dd531be49b905b2b96a581b22ba Mon Sep 17 00:00:00 2001 From: David Gageot Date: Mon, 23 Mar 2026 08:14:09 +0100 Subject: [PATCH] Enable bodyclose, makezero, and sqlclosecheck linters Add three new linters to golangci-lint configuration and fix all reported issues: - bodyclose: ensure HTTP response bodies are closed in tests; add nolint for false positives (websocket upgrade, goroutine-deferred close) - makezero: use make+append instead of make+copy in hasCycle - sqlclosecheck: use defer rows.Close() instead of manual close calls Assisted-By: docker-agent --- .golangci.yml | 3 +++ pkg/audio/transcribe/transcribe_darwin.go | 2 +- pkg/model/provider/oaistream/middleware_test.go | 5 +++++ pkg/runtime/client.go | 2 +- pkg/session/store.go | 4 +--- pkg/tools/builtin/tasks.go | 4 ++-- 6 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 34fc8995b..6faf59942 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -63,6 +63,9 @@ linters: - usetesting - whitespace - wastedassign + - bodyclose + - makezero + - sqlclosecheck settings: forbidigo: forbid: diff --git a/pkg/audio/transcribe/transcribe_darwin.go b/pkg/audio/transcribe/transcribe_darwin.go index fb01e58dc..ec686e75b 100644 --- a/pkg/audio/transcribe/transcribe_darwin.go +++ b/pkg/audio/transcribe/transcribe_darwin.go @@ -67,7 +67,7 @@ func (t *Transcriber) Start(ctx context.Context, handler TranscriptHandler) erro t.cancel = cancel // Connect to OpenAI Realtime API - conn, _, err := websocket.DefaultDialer.DialContext(ctx, openAIRealtimeURL, http.Header{ + conn, _, err := websocket.DefaultDialer.DialContext(ctx, openAIRealtimeURL, http.Header{ //nolint:bodyclose // websocket upgrade response "Authorization": []string{"Bearer " + t.apiKey}, "OpenAI-Beta": []string{"realtime=v1"}, }) diff --git a/pkg/model/provider/oaistream/middleware_test.go b/pkg/model/provider/oaistream/middleware_test.go index bbc3fc243..8537a8bf8 100644 --- a/pkg/model/provider/oaistream/middleware_test.go +++ b/pkg/model/provider/oaistream/middleware_test.go @@ -102,6 +102,7 @@ func TestErrorBodyMiddleware(t *testing.T) { resp, err := middleware(req, next) require.NoError(t, err) + defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) }) @@ -121,6 +122,7 @@ func TestErrorBodyMiddleware(t *testing.T) { resp, err := middleware(req, next) require.NoError(t, err) + defer resp.Body.Close() assert.Equal(t, http.StatusTooManyRequests, resp.StatusCode) body, err := io.ReadAll(resp.Body) @@ -144,6 +146,7 @@ func TestErrorBodyMiddleware(t *testing.T) { resp, err := middleware(req, next) require.NoError(t, err) + defer resp.Body.Close() assert.Equal(t, http.StatusTooManyRequests, resp.StatusCode) body, err := io.ReadAll(resp.Body) @@ -167,6 +170,7 @@ func TestErrorBodyMiddleware(t *testing.T) { resp, err := middleware(req, next) require.NoError(t, err) + defer resp.Body.Close() assert.Equal(t, http.StatusTooManyRequests, resp.StatusCode) body, err := io.ReadAll(resp.Body) @@ -191,6 +195,7 @@ func TestErrorBodyMiddleware(t *testing.T) { resp, err := middleware(req, next) require.NoError(t, err) + defer resp.Body.Close() body, err := io.ReadAll(resp.Body) require.NoError(t, err) diff --git a/pkg/runtime/client.go b/pkg/runtime/client.go index 94286eca9..8218e4eec 100644 --- a/pkg/runtime/client.go +++ b/pkg/runtime/client.go @@ -311,7 +311,7 @@ func (c *Client) runAgentWithAgentName(ctx context.Context, sessionID, agent, ag req.Header.Set("Accept", "text/event-stream") req.Header.Set("Cache-Control", "no-cache") - resp, err := c.httpClient.Do(req) + resp, err := c.httpClient.Do(req) //nolint:bodyclose // body is closed in the goroutine below if err != nil { return nil, fmt.Errorf("performing request: %w", err) } diff --git a/pkg/session/store.go b/pkg/session/store.go index 965138897..0982588be 100644 --- a/pkg/session/store.go +++ b/pkg/session/store.go @@ -680,6 +680,7 @@ func (s *SQLiteSessionStore) loadSessionItemsWith(ctx context.Context, q querier if err != nil { return nil, err } + defer rows.Close() // First, collect all raw row data so we can close the result set // before making any recursive calls (SQLite doesn't allow concurrent queries) @@ -687,16 +688,13 @@ func (s *SQLiteSessionStore) loadSessionItemsWith(ctx context.Context, q querier for rows.Next() { var row sessionItemRow if err := rows.Scan(&row.position, &row.itemType, &row.agentName, &row.messageJSON, &row.implicit, &row.subsessionID, &row.summaryText); err != nil { - rows.Close() return nil, err } rawRows = append(rawRows, row) } if err := rows.Err(); err != nil { - rows.Close() return nil, err } - rows.Close() if len(rawRows) == 0 { return nil, nil diff --git a/pkg/tools/builtin/tasks.go b/pkg/tools/builtin/tasks.go index 9f7cb1047..9f8c943da 100644 --- a/pkg/tools/builtin/tasks.go +++ b/pkg/tools/builtin/tasks.go @@ -155,8 +155,8 @@ func effectiveStatus(task Task, tasks map[string]Task) TaskStatus { func hasCycle(tasks map[string]Task, startID string, deps []string) bool { visited := make(map[string]bool) - stack := make([]string, len(deps)) - copy(stack, deps) + stack := make([]string, 0, len(deps)) + stack = append(stack, deps...) for len(stack) > 0 { current := stack[len(stack)-1] stack = stack[:len(stack)-1]