diff --git a/cmd/review-bot/validatedocmap_test.go b/cmd/review-bot/validatedocmap_test.go index 51f517e..26890fd 100644 --- a/cmd/review-bot/validatedocmap_test.go +++ b/cmd/review-bot/validatedocmap_test.go @@ -599,3 +599,45 @@ func TestValidateDocmapPath_DirSymlinkBypass(t *testing.T) { t.Error("expected rejection of dir-symlink bypass, got nil error") } } + +// TestValidateDocmapPath_InRepoSymlinkAllowed verifies that an in-repo +// file-level symlink whose resolved target is still within the repo root is +// accepted. This is the positive case for the issue #150 behavioral change: +// only symlinks that escape the root are rejected; intra-repo symlinks are +// allowed because EvalSymlinks resolves the target and the confinement check +// is applied to the resolved path, not the symlink entry itself. +func TestValidateDocmapPath_InRepoSymlinkAllowed(t *testing.T) { + dir := t.TempDir() + + // Create the real docmap file inside the repo root. + if err := os.MkdirAll(filepath.Join(dir, ".review-bot"), 0o755); err != nil { + t.Fatalf("MkdirAll: %v", err) + } + realDocmap := filepath.Join(dir, ".review-bot", "doc-map-real.yml") + if err := os.WriteFile(realDocmap, []byte("mappings: []\n"), 0o644); err != nil { + t.Fatalf("WriteFile: %v", err) + } + + // Create a symlink inside the repo root that points to the real file + // (also inside the root). + symlinkPath := filepath.Join(dir, ".review-bot", "doc-map-link.yml") + if err := os.Symlink(realDocmap, symlinkPath); err != nil { + t.Skipf("cannot create symlink (platform may not support it): %v", err) + } + + // Resolve dir to a symlink-free root, as runValidateDocmap does. + resolvedRoot, err := filepath.EvalSymlinks(dir) + if err != nil { + t.Fatalf("EvalSymlinks(dir): %v", err) + } + + // In-repo symlink whose target is within root: must be accepted. + resolved, err := validateDocmapPath(symlinkPath, resolvedRoot) + if err != nil { + t.Fatalf("expected in-repo symlink to be accepted, got error: %v", err) + } + // The returned resolved path must be the real file (not the symlink entry). + if resolved == symlinkPath { + t.Errorf("expected resolved path to differ from symlink path") + } +}