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

// 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") }