package layout import ( "io/fs" "os" "os/exec" "path/filepath" "regexp" "strings" "testing" ) // rawDirLiteral matches the raw directory as a path literal: a quote or a // slash, then ".instances" as a whole word. The bare substring would also // match ordinary field names such as s.cli.instances. var rawDirLiteral = regexp.MustCompile(`["/]\.instances\b`) // The raw directories are named in exactly one package, plus bootstrap's // tmpfiles and fixture lines that create them: a second caller would be a // second way to bypass the bind mount's nosymfollow (design §3.2). func TestRawInstancesDirectoryIsNamedOnlyHere(t *testing.T) { root := filepath.Join("..", "..") var files []string err := filepath.WalkDir(filepath.Join(root, "internal"), func(path string, d fs.DirEntry, err error) error { if err != nil { return err } if !d.IsDir() && strings.HasSuffix(path, ".go") { files = append(files, path) } return nil }) if err != nil { t.Fatal(err) } top, err := filepath.Glob(filepath.Join(root, "*.go")) if err != nil { t.Fatal(err) } files = append(files, top...) if len(top) == 0 { t.Fatal("no .go files at the repository root; the walk is looking in the wrong place") } for _, path := range files { if strings.HasSuffix(path, "_test.go") { continue } slash := filepath.ToSlash(path) if strings.Contains(slash, "internal/layout/") || strings.HasSuffix(slash, "internal/host/bootstrap.go") { continue } b, err := os.ReadFile(path) if err != nil { t.Fatal(err) } if loc := rawDirLiteral.FindIndex(b); loc != nil { line := 1 + strings.Count(string(b[:loc[0]]), "\n") t.Errorf("%s:%d names the raw .instances directory; only internal/layout (and bootstrap's tmpfiles lines) may", slash, line) } } } // The pattern must catch the literal forms and nothing else. func TestRawDirLiteralPattern(t *testing.T) { for _, s := range []string{`filepath.Join(d, ".instances")`, `"/data/.instances/x"`, `"/run/carlos/.instances"`} { if !rawDirLiteral.MatchString(s) { t.Errorf("missed %s", s) } } for _, s := range []string{`s.cli.instances.allow`, `"/data/instances"`, `".instancesX"`} { if rawDirLiteral.MatchString(s) { t.Errorf("matched %s", s) } } } // With a real bind mount, a rename THROUGH the mount answers EXDEV and the // pass's rename through the raw directory succeeds. Needs CAP_SYS_ADMIN; // skipped where it cannot mount. func TestRenameThroughTheRawDirectoryAvoidsEXDEV(t *testing.T) { if os.Geteuid() != 0 { t.Skip("needs root to bind mount") } base := t.TempDir() raw, view := filepath.Join(base, ".instances"), filepath.Join(base, "instances") if err := os.MkdirAll(raw, 0o700); err != nil { t.Fatal(err) } if err := os.MkdirAll(view, 0o700); err != nil { t.Fatal(err) } if out, err := exec.Command("mount", "--bind", "-o", "nosymfollow", raw, view).CombinedOutput(); err != nil { t.Skipf("cannot bind mount here: %v %s", err, out) } defer exec.Command("umount", view).Run() src := filepath.Join(base, "h.db") if err := os.WriteFile(src, []byte("x"), 0o600); err != nil { t.Fatal(err) } if err := os.Rename(src, filepath.Join(view, "h.db")); err == nil { t.Fatal("rename through the bind mount succeeded; the EXDEV premise of §3.2 does not hold here") } if err := os.Rename(src, filepath.Join(raw, "h.db")); err != nil { t.Fatalf("rename through the raw directory: %v", err) } if _, err := os.Stat(filepath.Join(view, "h.db")); err != nil { t.Fatalf("the view does not show the renamed file: %v", err) } }