Make the token-store file lock compile on Windows · Entire
Make the token-store file lock compile on Windows
293cf4c→main
Soph·1mo ago·3 files·+66 added/-26 removed
tokenstore.go used syscall.Flock and syscall.LOCK_* directly, which don't exist on Windows — so the public library (which transitively imports internal/auth) failed to cross-compile for GOOS=windows.
Split the lock behind build tags: tokenstore_lock_unix.go keeps the real flock(2), and tokenstore_lock_windows.go provides a compiling fallback. Windows has no flock; the file store's atomic temp-file+rename keeps individual writes safe, and the lock only guarded the rare concurrent read-modify-write lost update, so the fallback opens the lock file as a no-op advisory lock rather than pulling in a Windows locking dependency.
Verified with GOOS=windows go build/vet ./... (previously failed to compile).
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Changes
3
internal/auth
Mtokenstore.go+3/-26
Atokenstore_lock_unix.go+35
Atokenstore_lock_windows.go+28
// flockShared acquires a shared (read) lock on path+
.lock.
func flockShared(path string) (func(), error) {
return flockOpen(path + ".lock", syscall.LOCK_SH)
}
// flockExclusive acquires an exclusive (write) lock on path+
.lock.
func flockExclusive(path string) (func(), error) {
return flockOpen(path + ".lock", syscall.LOCK_EX)
}
func flockOpen(lockPath string, how int) (func(), error) {
f, err := os.OpenFile(lockPath, os.O_CREATE|os.O_RDWR, 0o600)
if err != nil {
return nil, fmt.Errorf("open lock file: %w", err)
}
if err := syscall.Flock(int(f.Fd()), how); err != nil {
f.Close()
return nil, fmt.Errorf("acquire file lock: %w", err)
}
return func() {
//nolint:errcheck // unlock errors on close are not actionable
syscall.Flock(int(f.Fd()), syscall.LOCK_UN)
f.Close()
}, nil
}
internal/auth/tokenstore.go
//go:build !windows
package auth
import (
"fmt"
"os"
"syscall"
)
// flockShared acquires a shared (read) lock on path+
.lock.
func flockShared(path string) (func(), error) {
return flockOpen(path + ".lock", syscall.LOCK_SH)
}
### internal/auth/tokenstore_lock_unix.go
```go
//go:build windows
package auth
import (
"fmt"
"os"
)
// Windows has no flock(2). The file token store's writes are atomic
// (temp file + rename), which keeps a single write safe on its own; the lock
// only guards against a lost update between concurrent read-modify-write
// processes, which is rare for a credential store. Rather than pull in a
// Windows-specific locking dependency, open (and create) the lock file so the
// call still succeeds and behaves like a no-op advisory lock.
//
// flockShared / flockExclusive mirror the Unix signatures so callers compile
// unchanged across platforms.
func flockShared(path string) (func(), error) { return flockOpen(path + ".lock") }
func flockExclusive(path string) (func(), error) { return flockOpen(path + ".lock") }
func flockOpen(lockPath string) (func(), error) {
f, err := os.OpenFile(lockPath, os.O_CREATE|os.O_RDWR, 0o600)
if err != nil {
return nil, fmt.Errorf("open lock file: %w", err)
}
return func() { _ = f.Close() }, nil
}
internal/auth/tokenstore_lock_windows.go
package auth
import (
"fmt"
"os"
)
func flockShared(path string) (func(), error) { return flockOpen(path + ".lock") }
func flockExclusive(path string) (func(), error) { return flockOpen(path + ".lock") }