From 1ba12e16201e5fad0bebec8782811cb72837018a Mon Sep 17 00:00:00 2001 From: Alessandro De Blasis Date: Tue, 16 Dec 2025 22:26:51 +0100 Subject: [PATCH] fix: Windows build + gosec lint errors (#585) Fixes Windows build by adding platform-specific inode handling via build tags. Also fixes gosec lint warnings in migrate_tombstones.go. Thanks @deblasis! --- cmd/bd/doctor/fix/migrate_tombstones.go | 6 +++--- internal/storage/sqlite/freshness.go | 16 +++------------- internal/storage/sqlite/freshness_unix.go | 19 +++++++++++++++++++ internal/storage/sqlite/freshness_windows.go | 16 ++++++++++++++++ 4 files changed, 41 insertions(+), 16 deletions(-) create mode 100644 internal/storage/sqlite/freshness_unix.go create mode 100644 internal/storage/sqlite/freshness_windows.go diff --git a/cmd/bd/doctor/fix/migrate_tombstones.go b/cmd/bd/doctor/fix/migrate_tombstones.go index 08918a27..ae1e7b3c 100644 --- a/cmd/bd/doctor/fix/migrate_tombstones.go +++ b/cmd/bd/doctor/fix/migrate_tombstones.go @@ -42,7 +42,7 @@ func MigrateTombstones(path string) error { // Load existing JSONL to check for already-existing tombstones existingTombstones := make(map[string]bool) - if file, err := os.Open(jsonlPath); err == nil { + if file, err := os.Open(filepath.Clean(jsonlPath)); err == nil { scanner := bufio.NewScanner(file) scanner.Buffer(make([]byte, 0, 64*1024), 10*1024*1024) for scanner.Scan() { @@ -56,7 +56,7 @@ func MigrateTombstones(path string) error { } } } - file.Close() + _ = file.Close() } // Convert deletions to tombstones @@ -74,7 +74,7 @@ func MigrateTombstones(path string) error { fmt.Printf(" All %d deletion(s) already have tombstones - archiving deletions.jsonl\n", skipped) } else { // Append tombstones to issues.jsonl - file, err := os.OpenFile(jsonlPath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644) + file, err := os.OpenFile(filepath.Clean(jsonlPath), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) if err != nil { return fmt.Errorf("failed to open issues.jsonl: %w", err) } diff --git a/internal/storage/sqlite/freshness.go b/internal/storage/sqlite/freshness.go index 4e1b9d70..6f541ea5 100644 --- a/internal/storage/sqlite/freshness.go +++ b/internal/storage/sqlite/freshness.go @@ -4,7 +4,6 @@ package sqlite import ( "os" "sync" - "syscall" "time" ) @@ -49,12 +48,8 @@ func (fc *FreshnessChecker) captureFileState() { fc.lastMtime = info.ModTime() fc.lastSize = info.Size() - // Get inode on Unix systems - if sys := info.Sys(); sys != nil { - if stat, ok := sys.(*syscall.Stat_t); ok { - fc.lastInode = stat.Ino - } - } + // Get inode (Unix only, returns 0 on Windows) + fc.lastInode = getFileInode(info) } // Check examines the database file for changes and triggers reconnection if needed. @@ -75,12 +70,7 @@ func (fc *FreshnessChecker) Check() bool { } // Check if file was replaced by comparing inode - var currentInode uint64 - if sys := info.Sys(); sys != nil { - if stat, ok := sys.(*syscall.Stat_t); ok { - currentInode = stat.Ino - } - } + currentInode := getFileInode(info) // Detect file replacement: // 1. Inode changed (file was replaced, most reliable on Unix) diff --git a/internal/storage/sqlite/freshness_unix.go b/internal/storage/sqlite/freshness_unix.go new file mode 100644 index 00000000..0fb49d4a --- /dev/null +++ b/internal/storage/sqlite/freshness_unix.go @@ -0,0 +1,19 @@ +//go:build !windows + +// Package sqlite implements the storage interface using SQLite. +package sqlite + +import ( + "os" + "syscall" +) + +// getFileInode extracts the inode from file info on Unix systems. +func getFileInode(info os.FileInfo) uint64 { + if sys := info.Sys(); sys != nil { + if stat, ok := sys.(*syscall.Stat_t); ok { + return stat.Ino + } + } + return 0 +} diff --git a/internal/storage/sqlite/freshness_windows.go b/internal/storage/sqlite/freshness_windows.go new file mode 100644 index 00000000..62eec70c --- /dev/null +++ b/internal/storage/sqlite/freshness_windows.go @@ -0,0 +1,16 @@ +//go:build windows + +// Package sqlite implements the storage interface using SQLite. +package sqlite + +import ( + "os" +) + +// getFileInode returns 0 on Windows since inodes are not available. +// File replacement detection will rely on mtime/size instead. +func getFileInode(info os.FileInfo) uint64 { + // Windows doesn't have inodes, return 0 to skip inode-based detection. + // The FreshnessChecker will fall back to mtime-based detection. + return 0 +}