From b71fc2e19abfeadcbe0b431094ff7f6ed1c8d046 Mon Sep 17 00:00:00 2001 From: Mathias Date: Mon, 5 Oct 2026 09:27:38 +0200 Subject: [PATCH] test(pipeline): pin BackfillRefs' page read with a swap race (#157) Review round 1 on PR #176: reverting the BackfillRefs concept-page read to os.ReadFile left every test green. The static symlinked page never reaches that read, because LoadInventory does not list it; the read is reachable only when a page listed as regular is swapped for a symlink before it is read. New test does that against an in-brain target and reads the page back with O_NOFOLLOW; red under the flip (2/2), green 3/3 on head. Co-Authored-By: Claude Opus 5.5 --- ingestion/internal/pipeline/root_test.go | 31 ++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/ingestion/internal/pipeline/root_test.go b/ingestion/internal/pipeline/root_test.go index 185cb48..f5ca876 100644 --- a/ingestion/internal/pipeline/root_test.go +++ b/ingestion/internal/pipeline/root_test.go @@ -3,8 +3,10 @@ package pipeline import ( "context" "fmt" + "io" "os" "path/filepath" + "syscall" "testing" "time" @@ -134,3 +136,32 @@ func TestBackfillRefsDoesNotWriteARefFromASourceSwappedInBehindASymlink(t *testi require.Contains(t, read(), "zqinside", "positive control") brainfstest.AssertNoLeakFrom(t, src, inside, target, 1500*time.Millisecond, read) } + +// A concept page that is regular when the inventory lists it, then swapped +// for a symlink to an in-brain file before BackfillRefs reads it: only the +// page read's own check refuses it (a static symlink never gets this far, +// because LoadInventory does not list it). +func TestBackfillRefsDoesNotCopyAPageSwappedInBehindASymlink(t *testing.T) { + brain := t.TempDir() + mkdirs(t, brain, "wiki/sources", "wiki/concepts", "raw") + require.NoError(t, os.WriteFile(filepath.Join(brain, "wiki", "sources", "s.md"), []byte("---\ntitle: S\n---\n[[c|C]]\n"), 0o644)) + page := filepath.Join(brain, "wiki", "concepts", "c.md") + target := filepath.Join(brain, "raw", "secret.md") + inside := "---\ntitle: C\n---\nzqinside\n" + read := func() string { + // The write path still follows a swapped-in link (#158) and can + // overwrite the target, so restore it each round. + _ = os.WriteFile(target, []byte("---\ntitle: X\n---\n"+brainfstest.Sentinel+"\n"), 0o644) + _, _ = BackfillRefs(context.Background(), brain) + f, err := os.OpenFile(page, os.O_RDONLY|syscall.O_NOFOLLOW|syscall.O_NONBLOCK, 0) + if err != nil { + return "" + } + defer func() { _ = f.Close() }() + b, _ := io.ReadAll(f) + return string(b) + } + require.NoError(t, os.WriteFile(page, []byte(inside), 0o644)) + require.Contains(t, read(), "zqinside", "positive control: the regular page gets the ref") + brainfstest.AssertNoLeakFrom(t, page, inside, target, 3*time.Second, read) +}