fix(init): prevent parent hub contamination during bd init (GH#896)
When running bd init in a subdirectory of a hub (e.g., ~/Repos/project where ~/Repos/.beads exists), the new database was incorrectly inheriting issues from the parent hub. Root cause: checkGitForIssues() computed the relative path from gitRoot to beadsDir but did not validate that beadsDir was actually inside the git repository. When beadsDir was outside (e.g., ../.beads), it would still attempt to import, causing contamination. Fix: Add a guard to reject beadsDir paths that start with .. (outside the git repository boundary). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
committed by
Steve Yegge
parent
9d69099803
commit
b3ebedb063
@@ -4,10 +4,12 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/steveyegge/beads/internal/beads"
|
||||
"github.com/steveyegge/beads/internal/git"
|
||||
"github.com/steveyegge/beads/internal/storage/sqlite"
|
||||
"github.com/steveyegge/beads/internal/types"
|
||||
)
|
||||
@@ -282,6 +284,59 @@ func TestCheckGitForIssues_NoBeadsDir(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestCheckGitForIssues_ParentHubNotInherited tests the GH#896 fix: when running
|
||||
// bd init in a subdirectory of a hub, the parent hub's .beads should NOT be used
|
||||
// for importing issues. This prevents contamination from parent hub issues.
|
||||
func TestCheckGitForIssues_ParentHubNotInherited(t *testing.T) {
|
||||
// Create a structure simulating the bug scenario:
|
||||
// tmpDir/
|
||||
// .beads/ <- parent hub (NOT a git repo)
|
||||
// issues.jsonl
|
||||
// config.yaml
|
||||
// newproject/ <- new project (IS a git repo)
|
||||
// .git/
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
// Create parent hub's .beads with issues
|
||||
parentBeadsDir := filepath.Join(tmpDir, ".beads")
|
||||
if err := os.MkdirAll(parentBeadsDir, 0755); err != nil {
|
||||
t.Fatalf("Failed to create parent .beads: %v", err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(parentBeadsDir, "config.yaml"), []byte("prefix: hub\n"), 0644); err != nil {
|
||||
t.Fatalf("Failed to create parent config.yaml: %v", err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(parentBeadsDir, "issues.jsonl"), []byte(`{"id":"hub-001","title":"Parent Issue"}`+"\n"), 0644); err != nil {
|
||||
t.Fatalf("Failed to create parent issues.jsonl: %v", err)
|
||||
}
|
||||
|
||||
// Create newproject as a git repo
|
||||
newProject := filepath.Join(tmpDir, "newproject")
|
||||
if err := os.MkdirAll(newProject, 0755); err != nil {
|
||||
t.Fatalf("Failed to create newproject: %v", err)
|
||||
}
|
||||
|
||||
// Initialize git repo in newproject
|
||||
t.Chdir(newProject)
|
||||
cmd := exec.Command("git", "init")
|
||||
if err := cmd.Run(); err != nil {
|
||||
t.Fatalf("Failed to git init: %v", err)
|
||||
}
|
||||
|
||||
// Reset git context cache (important for test isolation)
|
||||
git.ResetCaches()
|
||||
|
||||
// Now checkGitForIssues should NOT find the parent hub's issues
|
||||
// because the parent .beads is outside the git root (newproject)
|
||||
count, path, _ := checkGitForIssues()
|
||||
|
||||
if count != 0 {
|
||||
t.Errorf("GH#896: checkGitForIssues found %d issues from parent hub (should be 0)", count)
|
||||
}
|
||||
if path != "" {
|
||||
t.Errorf("GH#896: checkGitForIssues returned path %q (should be empty)", path)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBoolToFlag(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := []struct {
|
||||
|
||||
Reference in New Issue
Block a user