fix: validate BEADS_DIR env var for project files (bd-420)
Extends the fix from PR #424 to also validate the BEADS_DIR environment variable. Previously, only the directory tree search was validated, but BEADS_DIR could still point to a daemon-only directory. Changes: - Add validation to BEADS_DIR path using hasBeadsProjectFiles() - Add comprehensive test for BEADS_DIR validation - Test verifies both rejection of daemon-only dirs and acceptance of valid dirs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -275,9 +275,12 @@ func FindBeadsDir() string {
|
|||||||
if beadsDir := os.Getenv("BEADS_DIR"); beadsDir != "" {
|
if beadsDir := os.Getenv("BEADS_DIR"); beadsDir != "" {
|
||||||
absBeadsDir := utils.CanonicalizePath(beadsDir)
|
absBeadsDir := utils.CanonicalizePath(beadsDir)
|
||||||
if info, err := os.Stat(absBeadsDir); err == nil && info.IsDir() {
|
if info, err := os.Stat(absBeadsDir); err == nil && info.IsDir() {
|
||||||
|
// Validate directory contains actual project files (bd-420)
|
||||||
|
if hasBeadsProjectFiles(absBeadsDir) {
|
||||||
return absBeadsDir
|
return absBeadsDir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 2. Search for .beads/ in current directory and ancestors
|
// 2. Search for .beads/ in current directory and ancestors
|
||||||
cwd, err := os.Getwd()
|
cwd, err := os.Getwd()
|
||||||
|
|||||||
@@ -410,6 +410,55 @@ func TestFindBeadsDirSkipsDaemonRegistry(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestFindBeadsDirValidatesBeadsDirEnv verifies that BEADS_DIR env var
|
||||||
|
// is validated for project files (bd-420)
|
||||||
|
func TestFindBeadsDirValidatesBeadsDirEnv(t *testing.T) {
|
||||||
|
// Save original state
|
||||||
|
originalEnv := os.Getenv("BEADS_DIR")
|
||||||
|
defer func() {
|
||||||
|
if originalEnv != "" {
|
||||||
|
os.Setenv("BEADS_DIR", originalEnv)
|
||||||
|
} else {
|
||||||
|
os.Unsetenv("BEADS_DIR")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Create temp directory with only daemon registry files
|
||||||
|
tmpDir, err := os.MkdirTemp("", "beads-env-test-*")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
|
if err := os.WriteFile(filepath.Join(tmpDir, "registry.json"), []byte("[]"), 0644); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set BEADS_DIR to daemon-only directory
|
||||||
|
os.Setenv("BEADS_DIR", tmpDir)
|
||||||
|
|
||||||
|
// Should NOT return the daemon-only directory
|
||||||
|
result := FindBeadsDir()
|
||||||
|
if result != "" {
|
||||||
|
resultResolved, _ := filepath.EvalSymlinks(result)
|
||||||
|
tmpDirResolved, _ := filepath.EvalSymlinks(tmpDir)
|
||||||
|
if resultResolved == tmpDirResolved {
|
||||||
|
t.Errorf("FindBeadsDir() should skip BEADS_DIR with only daemon files, got %q", result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now add a project file
|
||||||
|
if err := os.WriteFile(filepath.Join(tmpDir, "beads.db"), []byte{}, 0644); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should now return the directory
|
||||||
|
result = FindBeadsDir()
|
||||||
|
if result == "" {
|
||||||
|
t.Error("FindBeadsDir() should return BEADS_DIR with project files")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestFindDatabasePathHomeDefault(t *testing.T) {
|
func TestFindDatabasePathHomeDefault(t *testing.T) {
|
||||||
// This test verifies that if no database is found, it falls back to home directory
|
// This test verifies that if no database is found, it falls back to home directory
|
||||||
// We can't reliably test this without modifying the home directory, so we'll skip
|
// We can't reliably test this without modifying the home directory, so we'll skip
|
||||||
|
|||||||
Reference in New Issue
Block a user