Implement stricter daemon lock file validation (bd-161)

- Add JSON format to daemon.lock with database path, version, PID, and timestamp
- Validate database path on client connection (fail if mismatch)
- Backward compatible with old plain-PID lock files
- Add comprehensive tests for JSON format and validation
- Update all lock acquisition callsites to pass database path

Amp-Thread-ID: https://ampcode.com/threads/T-137e6a9c-b690-4ade-9bec-13fcd7d0e4ed
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Steve Yegge
2025-10-26 18:37:17 -07:00
parent 50623f8be1
commit 7549bd86bc
5 changed files with 212 additions and 43 deletions

View File

@@ -829,9 +829,9 @@ func setupDaemonLogger(logPath string) (*lumberjack.Logger, daemonLogger) {
return logF, logger
}
func setupDaemonLock(pidFile string, global bool, log daemonLogger) (io.Closer, error) {
func setupDaemonLock(pidFile string, dbPath string, log daemonLogger) (io.Closer, error) {
beadsDir := filepath.Dir(pidFile)
lock, err := acquireDaemonLock(beadsDir, global)
lock, err := acquireDaemonLock(beadsDir, dbPath)
if err != nil {
if err == ErrDaemonLocked {
log.log("Daemon already running (lock held), exiting")
@@ -1044,7 +1044,22 @@ func runDaemonLoop(interval time.Duration, autoCommit, autoPush bool, logPath, p
logF, log := setupDaemonLogger(logPath)
defer func() { _ = logF.Close() }()
lock, err := setupDaemonLock(pidFile, global, log)
// Determine database path first (needed for lock file metadata)
daemonDBPath := ""
if !global {
daemonDBPath = dbPath
if daemonDBPath == "" {
if foundDB := beads.FindDatabasePath(); foundDB != "" {
daemonDBPath = foundDB
} else {
log.log("Error: no beads database found")
log.log("Hint: run 'bd init' to create a database or set BEADS_DB environment variable")
os.Exit(1)
}
}
}
lock, err := setupDaemonLock(pidFile, daemonDBPath, log)
if err != nil {
os.Exit(1)
}
@@ -1058,17 +1073,6 @@ func runDaemonLoop(interval time.Duration, autoCommit, autoPush bool, logPath, p
return
}
daemonDBPath := dbPath
if daemonDBPath == "" {
if foundDB := beads.FindDatabasePath(); foundDB != "" {
daemonDBPath = foundDB
} else {
log.log("Error: no beads database found")
log.log("Hint: run 'bd init' to create a database or set BEADS_DB environment variable")
os.Exit(1)
}
}
// Check for multiple .db files (ambiguity error)
beadsDir := filepath.Dir(daemonDBPath)
matches, err := filepath.Glob(filepath.Join(beadsDir, "*.db"))