Skip to content

Commit 8ae9b82

Browse files
cpcloudclaude
andauthored
chore: update flake inputs and fix new gosec findings (#728)
## Summary - Update nixpkgs (2026-03-09) and git-hooks (2026-03-07) flake inputs - Add ignore entries for GO-2026-4601 (url.Parse IPv6 flaw; only caller parses user config) and GO-2026-4602 (os.ReadDir traversal via Root; micasa never uses os.OpenRoot) - Fix gosec G118 in all test files with `t.Cleanup(cancel)` instead of nolint; keep nolint in extraction.go where cancel is stored in struct field - Suppress false-positive gosec G602 (slice bounds proven equal by construction) and G703 (WriteFile paths use tmpDir + constant filenames) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 3bc8003 commit 8ae9b82

12 files changed

Lines changed: 99 additions & 29 deletions

flake.lock

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/app/chat.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -345,8 +345,10 @@ func (m *Model) startSQLStream(query string) tea.Cmd {
345345
messages = append(messages, history...)
346346
messages = append(messages, llm.Message{Role: roleUser, Content: query})
347347

348-
ctx, cancel := context.WithCancel(context.Background())
349-
348+
//nolint:gosec // cancel stored in CancelFn, called on ctrl+c
349+
ctx, cancel := context.WithCancel(
350+
context.Background(),
351+
)
350352
streamCh, err := client.ChatStream(ctx, messages)
351353
if err != nil {
352354
return sqlStreamStartedMsg{

internal/app/chat_test.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,9 @@ func TestCancellationDuringSQLGeneration(t *testing.T) {
120120
m := newTestModel(t)
121121
m.openChat()
122122

123-
_, cancel := context.WithCancel(context.Background())
123+
ctx, cancel := context.WithCancel(context.Background())
124+
t.Cleanup(cancel)
125+
_ = ctx // only the cancel func is needed; ctx is cleaned up via t.Cleanup
124126
m.chat.CurrentQuery = testQuestion
125127
m.chat.Streaming = true
126128
m.chat.StreamingSQL = true
@@ -150,7 +152,9 @@ func TestCancellationDuringAnswerStreaming(t *testing.T) {
150152
m := newTestModel(t)
151153
m.openChat()
152154

153-
_, cancel := context.WithCancel(context.Background())
155+
ctx, cancel := context.WithCancel(context.Background())
156+
t.Cleanup(cancel)
157+
_ = ctx
154158
m.chat.CurrentQuery = testQuestion
155159
m.chat.Streaming = true
156160
m.chat.StreamingSQL = false // stage 2
@@ -240,6 +244,7 @@ func TestNoSpinnerAfterCancellation(t *testing.T) {
240244
m.openChat()
241245

242246
_, cancel := context.WithCancel(context.Background())
247+
t.Cleanup(cancel)
243248
m.chat.Streaming = true
244249
m.chat.StreamingSQL = true
245250
m.chat.CancelFn = cancel
@@ -274,6 +279,7 @@ func TestLateSQLChunkAfterCancellationIsDropped(t *testing.T) {
274279
m.openChat()
275280

276281
_, cancel := context.WithCancel(context.Background())
282+
t.Cleanup(cancel)
277283
m.chat.Streaming = true
278284
m.chat.StreamingSQL = true
279285
m.chat.CancelFn = cancel
@@ -310,6 +316,7 @@ func TestLateChatChunkAfterCancellationIsDropped(t *testing.T) {
310316
m.openChat()
311317

312318
_, cancel := context.WithCancel(context.Background())
319+
t.Cleanup(cancel)
313320
m.chat.Streaming = true
314321
m.chat.CancelFn = cancel
315322
m.chat.Messages = []chatMessage{

internal/app/extraction.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,10 @@ func (m *Model) startExtractionOverlay(
269269
sp := spinner.New(spinner.WithSpinner(spinner.Dot))
270270
sp.Style = appStyles.AccentText()
271271

272-
ctx, cancel := context.WithCancel(context.Background())
272+
//nolint:gosec // cancel stored in ex.CancelFn, called on extraction close
273+
ctx, cancel := context.WithCancel(
274+
context.Background(),
275+
)
273276

274277
// Text extraction only applies to PDFs and text files; skip for images.
275278
hasText := !extract.IsImageMIME(mime)
@@ -935,7 +938,9 @@ func (m *Model) rerunLLMExtraction() tea.Cmd {
935938

936939
// Replace a cancelled context so the rerun has a live one.
937940
if ex.ctx.Err() != nil {
938-
ctx, cancel := context.WithCancel(context.Background())
941+
ctx, cancel := context.WithCancel( //nolint:gosec // cancel stored in ex.CancelFn, called on extraction close
942+
context.Background(),
943+
)
939944
ex.ctx = ctx
940945
ex.CancelFn = cancel
941946
}

internal/app/extraction_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ func newExtractionModel(t *testing.T, steps map[extractionStep]stepStatus) *Mode
2626

2727
m := newTestModel(t)
2828
ctx, cancel := context.WithCancel(context.Background())
29+
t.Cleanup(cancel)
2930
ex := &extractionLogState{
3031
ID: nextExtractionID.Add(1),
3132
ctx: ctx,
@@ -913,6 +914,7 @@ func TestForeground_SwapsCurrentToBackground(t *testing.T) {
913914

914915
// Create a new foreground extraction.
915916
ctx, cancel := context.WithCancel(context.Background())
917+
t.Cleanup(cancel)
916918
m.ex.extraction = &extractionLogState{
917919
ID: nextExtractionID.Add(1),
918920
Filename: "second.pdf",
@@ -1051,6 +1053,7 @@ func TestMultipleBgExtractions(t *testing.T) {
10511053

10521054
// Create and background second.
10531055
ctx, cancel := context.WithCancel(context.Background())
1056+
t.Cleanup(cancel)
10541057
m.ex.extraction = &extractionLogState{
10551058
ID: nextExtractionID.Add(1),
10561059
Filename: "b.pdf",
@@ -1088,6 +1091,7 @@ func TestStartExtraction_AutoBackgroundsExisting(t *testing.T) {
10881091
// This tests the backgrounding logic directly.
10891092
m.backgroundExtraction()
10901093
ctx, cancel := context.WithCancel(context.Background())
1094+
t.Cleanup(cancel)
10911095
m.ex.extraction = &extractionLogState{
10921096
ID: nextExtractionID.Add(1),
10931097
Filename: "new.pdf",
@@ -1134,6 +1138,7 @@ func TestCtrlQ_CancelsAllBgExtractions(t *testing.T) {
11341138

11351139
// Create another foreground extraction.
11361140
ctx, cancel := context.WithCancel(context.Background())
1141+
t.Cleanup(cancel)
11371142
m.ex.extraction = &extractionLogState{
11381143
ID: nextExtractionID.Add(1),
11391144
Filename: "fg2.pdf",
@@ -1817,6 +1822,7 @@ func TestDispatch_VendorCrossReference(t *testing.T) {
18171822
require.NoError(t, sdb.Stage(ops))
18181823

18191824
ctx, cancel := context.WithCancel(context.Background())
1825+
t.Cleanup(cancel)
18201826
defer cancel()
18211827
ex := &extractionLogState{
18221828
ID: nextExtractionID.Add(1),
@@ -1885,6 +1891,7 @@ func TestDispatch_InvalidProjectIDShowsError(t *testing.T) {
18851891
require.NoError(t, sdb.Stage(ops))
18861892

18871893
ctx, cancel := context.WithCancel(context.Background())
1894+
t.Cleanup(cancel)
18881895
defer cancel()
18891896
ex := &extractionLogState{
18901897
ID: nextExtractionID.Add(1),
@@ -1950,6 +1957,7 @@ func TestDispatch_OffsetCrossReference(t *testing.T) {
19501957
require.NoError(t, sdb.Stage(ops))
19511958

19521959
ctx, cancel := context.WithCancel(context.Background())
1960+
t.Cleanup(cancel)
19531961
defer cancel()
19541962
ex := &extractionLogState{
19551963
ID: nextExtractionID.Add(1),
@@ -2032,6 +2040,7 @@ func TestDispatch_DuplicateVendorDedup(t *testing.T) {
20322040
require.NoError(t, sdb.Stage(ops))
20332041

20342042
ctx, cancel := context.WithCancel(context.Background())
2043+
t.Cleanup(cancel)
20352044
defer cancel()
20362045
ex := &extractionLogState{
20372046
ID: nextExtractionID.Add(1),
@@ -2102,6 +2111,7 @@ func TestDispatch_DuplicateApplianceDedup(t *testing.T) {
21022111
require.NoError(t, sdb.Stage(ops))
21032112

21042113
ctx, cancel := context.WithCancel(context.Background())
2114+
t.Cleanup(cancel)
21052115
defer cancel()
21062116
ex := &extractionLogState{
21072117
ID: nextExtractionID.Add(1),
@@ -2163,6 +2173,7 @@ func TestDispatch_TransactionRollbackOnFailure(t *testing.T) {
21632173
require.NoError(t, sdb.Stage(ops))
21642174

21652175
ctx, cancel := context.WithCancel(context.Background())
2176+
t.Cleanup(cancel)
21662177
defer cancel()
21672178
ex := &extractionLogState{
21682179
ID: nextExtractionID.Add(1),

internal/app/table.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -879,8 +879,9 @@ func columnWidths(
879879
// Content exceeds terminal width — apply Max constraints.
880880
widths := make([]int, columnCount)
881881
for i, w := range natural {
882-
if specs[i].Max > 0 && w > specs[i].Max {
883-
w = specs[i].Max
882+
if specs[i].Max > 0 && //nolint:gosec // specs and natural have equal length (columnCount)
883+
w > specs[i].Max { //nolint:gosec // same bounds
884+
w = specs[i].Max //nolint:gosec // same bounds
884885
}
885886
widths[i] = w
886887
}

internal/extract/ocr.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func ocrPDF(ctx context.Context, data []byte, maxPages int) (string, []byte, err
3838
defer os.RemoveAll(tmpDir) //nolint:errcheck // best-effort cleanup
3939

4040
pdfPath := filepath.Join(tmpDir, "input.pdf")
41-
if err := os.WriteFile(pdfPath, data, 0o600); err != nil {
41+
if err := os.WriteFile(pdfPath, data, 0o600); err != nil { //nolint:gosec // path is tmpDir + constant filename
4242
return "", nil, fmt.Errorf("write temp pdf: %w", err)
4343
}
4444

@@ -271,7 +271,7 @@ func ocrImage(ctx context.Context, data []byte) (string, []byte, error) {
271271
defer os.RemoveAll(tmpDir) //nolint:errcheck // best-effort cleanup
272272

273273
imgPath := filepath.Join(tmpDir, "input")
274-
if err := os.WriteFile(imgPath, data, 0o600); err != nil {
274+
if err := os.WriteFile(imgPath, data, 0o600); err != nil { //nolint:gosec // path is tmpDir + constant filename
275275
return "", nil, fmt.Errorf("write temp image: %w", err)
276276
}
277277

internal/extract/ocr_bench_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func BenchmarkOcrPage(b *testing.B) {
4444

4545
tmpDir := b.TempDir()
4646
pdfPath := filepath.Join(tmpDir, "input.pdf")
47-
if err := os.WriteFile(pdfPath, data, 0o600); err != nil {
47+
if err := os.WriteFile(pdfPath, data, 0o600); err != nil { //nolint:gosec // path is tmpDir + constant filename
4848
b.Fatal(err)
4949
}
5050

internal/extract/ocr_coverage_test.go

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,11 @@ func TestPdfPageCount_ValidPDF(t *testing.T) {
275275

276276
tmpDir := t.TempDir()
277277
pdfPath := filepath.Join(tmpDir, "input.pdf")
278-
require.NoError(t, os.WriteFile(pdfPath, data, 0o600))
278+
//nolint:gosec // path is tmpDir + constant filename
279+
require.NoError(
280+
t,
281+
os.WriteFile(pdfPath, data, 0o600),
282+
)
279283

280284
count, err := pdfPageCount(context.Background(), pdfPath)
281285
require.NoError(t, err)
@@ -290,7 +294,11 @@ func TestPdfPageCount_InvalidPDF(t *testing.T) {
290294

291295
tmpDir := t.TempDir()
292296
pdfPath := filepath.Join(tmpDir, "corrupt.pdf")
293-
require.NoError(t, os.WriteFile(pdfPath, []byte("corrupt data"), 0o600))
297+
//nolint:gosec // path is tmpDir + constant filename
298+
require.NoError(
299+
t,
300+
os.WriteFile(pdfPath, []byte("corrupt data"), 0o600),
301+
)
294302

295303
_, err := pdfPageCount(context.Background(), pdfPath)
296304
assert.Error(t, err)
@@ -309,7 +317,11 @@ func TestPdfPageCount_ContextCancelled(t *testing.T) {
309317

310318
tmpDir := t.TempDir()
311319
pdfPath := filepath.Join(tmpDir, "input.pdf")
312-
require.NoError(t, os.WriteFile(pdfPath, data, 0o600))
320+
//nolint:gosec // path is tmpDir + constant filename
321+
require.NoError(
322+
t,
323+
os.WriteFile(pdfPath, data, 0o600),
324+
)
313325

314326
ctx, cancel := context.WithCancel(context.Background())
315327
cancel()
@@ -335,7 +347,11 @@ func TestOcrPage_ValidPDF(t *testing.T) {
335347

336348
tmpDir := t.TempDir()
337349
pdfPath := filepath.Join(tmpDir, "input.pdf")
338-
require.NoError(t, os.WriteFile(pdfPath, data, 0o600))
350+
//nolint:gosec // path is tmpDir + constant filename
351+
require.NoError(
352+
t,
353+
os.WriteFile(pdfPath, data, 0o600),
354+
)
339355

340356
result := ocrPage(context.Background(), pdfPath, 1, nil)
341357
require.NoError(t, result.err)
@@ -351,7 +367,11 @@ func TestOcrPage_InvalidPDF(t *testing.T) {
351367

352368
tmpDir := t.TempDir()
353369
pdfPath := filepath.Join(tmpDir, "corrupt.pdf")
354-
require.NoError(t, os.WriteFile(pdfPath, []byte("corrupt data"), 0o600))
370+
//nolint:gosec // path is tmpDir + constant filename
371+
require.NoError(
372+
t,
373+
os.WriteFile(pdfPath, []byte("corrupt data"), 0o600),
374+
)
355375

356376
result := ocrPage(context.Background(), pdfPath, 1, nil)
357377
assert.Error(t, result.err)
@@ -370,7 +390,11 @@ func TestOcrPage_ContextCancelled(t *testing.T) {
370390

371391
tmpDir := t.TempDir()
372392
pdfPath := filepath.Join(tmpDir, "input.pdf")
373-
require.NoError(t, os.WriteFile(pdfPath, data, 0o600))
393+
//nolint:gosec // path is tmpDir + constant filename
394+
require.NoError(
395+
t,
396+
os.WriteFile(pdfPath, data, 0o600),
397+
)
374398

375399
ctx, cancel := context.WithCancel(context.Background())
376400
cancel()
@@ -812,7 +836,11 @@ func TestOcrPDFPages_ValidPDF(t *testing.T) {
812836

813837
tmpDir := t.TempDir()
814838
pdfPath := filepath.Join(tmpDir, "input.pdf")
815-
require.NoError(t, os.WriteFile(pdfPath, data, 0o600))
839+
//nolint:gosec // path is tmpDir + constant filename
840+
require.NoError(
841+
t,
842+
os.WriteFile(pdfPath, data, 0o600),
843+
)
816844

817845
pageCount, err := pdfPageCount(context.Background(), pdfPath)
818846
require.NoError(t, err)
@@ -844,7 +872,11 @@ func TestOcrPDFPages_ContextCancelled(t *testing.T) {
844872

845873
tmpDir := t.TempDir()
846874
pdfPath := filepath.Join(tmpDir, "input.pdf")
847-
require.NoError(t, os.WriteFile(pdfPath, data, 0o600))
875+
//nolint:gosec // path is tmpDir + constant filename
876+
require.NoError(
877+
t,
878+
os.WriteFile(pdfPath, data, 0o600),
879+
)
848880

849881
ctx, cancel := context.WithCancel(context.Background())
850882
cancel()
@@ -867,7 +899,11 @@ func TestOcrPDFPages_ProgressReporting(t *testing.T) {
867899

868900
tmpDir := t.TempDir()
869901
pdfPath := filepath.Join(tmpDir, "input.pdf")
870-
require.NoError(t, os.WriteFile(pdfPath, data, 0o600))
902+
//nolint:gosec // path is tmpDir + constant filename
903+
require.NoError(
904+
t,
905+
os.WriteFile(pdfPath, data, 0o600),
906+
)
871907

872908
pageDone := make(chan struct{}, 2)
873909
results := ocrPDFPages(context.Background(), pdfPath, 1, nil, pageDone)

internal/extract/ocr_progress.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func ocrImageWithProgress(ctx context.Context, data []byte, ch chan<- ExtractPro
7373
defer os.RemoveAll(tmpDir) //nolint:errcheck // best-effort cleanup
7474

7575
imgPath := filepath.Join(tmpDir, "input.png")
76-
if err := os.WriteFile(imgPath, data, 0o600); err != nil {
76+
if err := os.WriteFile(imgPath, data, 0o600); err != nil { //nolint:gosec // path is tmpDir + constant filename
7777
ch <- ExtractProgress{Err: fmt.Errorf("write temp image: %w", err), Done: true}
7878
return
7979
}
@@ -118,7 +118,7 @@ func ocrPDFWithProgress(
118118
defer os.RemoveAll(tmpDir) //nolint:errcheck // best-effort cleanup
119119

120120
pdfPath := filepath.Join(tmpDir, "input.pdf")
121-
if err := os.WriteFile(pdfPath, data, 0o600); err != nil {
121+
if err := os.WriteFile(pdfPath, data, 0o600); err != nil { //nolint:gosec // path is tmpDir + constant filename
122122
ch <- ExtractProgress{Err: fmt.Errorf("write temp pdf: %w", err), Done: true}
123123
return
124124
}

0 commit comments

Comments
 (0)