Fix bd-36870264: Prevent nested .beads directories with path canonicalization

- Add filepath.Abs() + EvalSymlinks() to FindDatabasePath() to normalize all database paths
- Add nested .beads directory detection in setupDaemonLock() with helpful error messages
- Prevents infinite .beads/.beads/.beads/ recursion when using relative BEADS_DB paths
- All acceptance criteria passed: singleton enforcement, lock release, no recursion

Amp-Thread-ID: https://ampcode.com/threads/T-c7fc78b8-a935-48dc-8453-a1bd47a14f72
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Steve Yegge
2025-11-01 19:50:34 -07:00
parent ce9a5164f7
commit 537844cb11
3 changed files with 78 additions and 59 deletions

View File

@@ -423,6 +423,16 @@ func startDaemon(interval time.Duration, autoCommit, autoPush bool, logFile, pid
// setupDaemonLock acquires the daemon lock and writes PID file
func setupDaemonLock(pidFile string, dbPath string, log daemonLogger) (*DaemonLock, error) {
beadsDir := filepath.Dir(pidFile)
// Detect nested .beads directories (e.g., .beads/.beads/.beads/)
cleanPath := filepath.Clean(beadsDir)
if strings.Contains(cleanPath, string(filepath.Separator)+".beads"+string(filepath.Separator)+".beads") {
log.log("Error: Nested .beads directory detected: %s", cleanPath)
log.log("Hint: Do not run 'bd daemon' from inside .beads/ directory")
log.log("Hint: Use absolute paths for BEADS_DB or run from workspace root")
return nil, fmt.Errorf("nested .beads directory detected")
}
lock, err := acquireDaemonLock(beadsDir, dbPath)
if err != nil {
if err == ErrDaemonLocked {