// Copyright (c) 2026 Storm Dragon // SPDX-License-Identifier: GPL-3.0-or-later package tentacle import ( "context" "os" "os/exec" "path/filepath" "strings" "testing" ) func repository_files() map[string]string { return map[string]string{ "repository.toml": "format-version = 1\nid = 'example.tentacles'\nname = 'Example tentacles'\ndescription = 'Test catalog'\nmaintainer = 'Maintainer'\n", "catalog.toml": "format-version = 1\n[[tentacles]]\nid = 'echo'\nmanifest = 'echo/tentacle.toml'\n", "echo/tentacle.toml": "format-version = 1\nid = 'echo'\nname = 'Echo'\nversion = '0.1'\ndescription = 'An example'\ncapabilities = ['presentation']\n", } } func read_repository_fixture(files map[string]string) (Repository, error) { return read_repository("https://example.org/team/tentacles", strings.Repeat("a", 40), func(filename string) ([]byte, error) { data, found := files[filename] if !found { return nil, os.ErrNotExist } return []byte(data), nil }) } func TestRepositoryMetadataDiscoveryValidation(t *testing.T) { repository, err := read_repository_fixture(repository_files()) if err != nil || repository.ID != "example.tentacles" || len(repository.Tentacles) != 1 || repository.Tentacles[0].Name != "Echo" { t.Fatalf("discovery: %+v %v", repository, err) } for _, problem := range []string{"missing root", "version", "missing manifest", "traversal", "nested", "mismatch", "duplicate", "oversized", "invalid id"} { t.Run(problem, func(t *testing.T) { files := repository_files() switch problem { case "missing root": delete(files, "repository.toml") case "version": files["repository.toml"] = strings.Replace(files["repository.toml"], "format-version = 1", "format-version = 2", 1) case "missing manifest": delete(files, "echo/tentacle.toml") case "traversal": files["catalog.toml"] = strings.Replace(files["catalog.toml"], "echo/tentacle.toml", "../tentacle.toml", 1) case "nested": files["catalog.toml"] = strings.Replace(files["catalog.toml"], "echo/tentacle.toml", "a/b/tentacle.toml", 1) case "mismatch": files["echo/tentacle.toml"] = strings.Replace(files["echo/tentacle.toml"], "id = 'echo'", "id = 'different'", 1) case "duplicate": files["catalog.toml"] += "[[tentacles]]\nid='echo'\nmanifest='echo/tentacle.toml'\n" case "oversized": files["repository.toml"] += "#" + strings.Repeat("x", MaxFrameBytes) case "invalid id": files["echo/tentacle.toml"] = strings.Replace(files["echo/tentacle.toml"], "id = 'echo'", "id = 'Echo!'", 1) } if _, err := read_repository_fixture(files); err == nil { t.Fatal("accepted invalid metadata") } }) } } func TestRepositoryURLAndLabel(t *testing.T) { origin, err := RepositoryURL(" https://EXAMPLE.org/team/tentacles.git/ ") if err != nil || origin != "https://example.org/team/tentacles.git" || RepositoryLabel(origin) != "team/tentacles" { t.Fatalf("URL %q %v", origin, err) } for _, origin := range []string{"file:///tmp/source", "http://example.org/team/repo", "ssh://example.org/team/repo", "https://Username@example.org/team/repo", "https://example.org/", "https://example.org/team/../repo", "https://example.org/team/repo?ref=main", "https://example.org/team/repo#ref", "https://example.org/team/%00repo"} { if _, err := RepositoryURL(origin); err == nil { t.Fatalf("accepted %q", origin) } } } func TestRepositorySnapshotPersistenceAndIsolation(t *testing.T) { repository, err := read_repository_fixture(repository_files()) if err != nil { t.Fatal(err) } registry := &Registry{Path: filepath.Join(t.TempDir(), "tentacles.toml")} entries, err := registry.Load() if err != nil { t.Fatal(err) } if err := registry.SaveState(entries, []Repository{repository}); err != nil { t.Fatal(err) } reopened := &Registry{Path: registry.Path} if _, err := reopened.Load(); err != nil { t.Fatal(err) } cached := reopened.Repositories() if len(cached) != 1 || cached[0].Tentacles[0].Name != "Echo" { t.Fatal(cached) } cached[0].Tentacles[0].Name = "mutated" if reopened.Repositories()[0].Tentacles[0].Name != "Echo" { t.Fatal("shared snapshot storage") } if err := reopened.Save(nil); err != nil { t.Fatal(err) } if _, err := registry.Load(); err != nil || len(registry.Repositories()) != 1 { t.Fatalf("entry save dropped catalog: %v", err) } } func TestRepositoryGitIgnoresInheritedConfigAndReadsBlobs(t *testing.T) { directory := t.TempDir() // A poisoned inherited config must not affect even Git initialization. t.Setenv("GIT_CONFIG_COUNT", "1") t.Setenv("GIT_CONFIG_KEY_0", "core.bare") t.Setenv("GIT_CONFIG_VALUE_0", "invalid") ctx := context.Background() if _, err := repository_git(ctx, directory, "init", "--bare", "--template="); err != nil { t.Fatal(err) } source := t.TempDir() for name, data := range repository_files() { filename := filepath.Join(source, name) if err := os.MkdirAll(filepath.Dir(filename), 0700); err != nil { t.Fatal(err) } if err := os.WriteFile(filename, []byte(data), 0600); err != nil { t.Fatal(err) } } // Populate a local test snapshot without enabling file transport in the // production fetch path or contacting a real repository. run := func(args ...string) string { command := exec.Command("git", args...) command.Dir = source command.Env = []string{"PATH=" + os.Getenv("PATH"), "HOME=" + source, "GIT_CONFIG_NOSYSTEM=1", "GIT_CONFIG_GLOBAL=/dev/null", "GIT_AUTHOR_NAME=Maintainer", "GIT_AUTHOR_EMAIL=maintainer@example.invalid", "GIT_COMMITTER_NAME=Maintainer", "GIT_COMMITTER_EMAIL=maintainer@example.invalid"} output, err := command.CombinedOutput() if err != nil { t.Fatalf("git: %s %v", output, err) } return strings.TrimSpace(string(output)) } run("init", "--template=") run("add", ".") run("commit", "-m", "Fixture") setHead := func() { t.Helper() if err := os.WriteFile(filepath.Join(source, ".git", "FETCH_HEAD"), []byte(run("rev-parse", "HEAD")+"\n"), 0600); err != nil { t.Fatal(err) } } setHead() repository, err := read_git_repository(ctx, source, "https://example.org/team/tentacles") if err != nil || len(repository.Tentacles) != 1 { t.Fatalf("Git discovery: %+v %v", repository, err) } revision := run("rev-parse", "HEAD") data, err := repository_git(ctx, source, "show", revision+":repository.toml") if err != nil || !strings.Contains(string(data), "example.tentacles") { t.Fatalf("read blob: %s %v", data, err) } // A regular-looking root symlink must be rejected rather than interpreted // as metadata, including when it references an otherwise valid file. if err := os.Remove(filepath.Join(source, "repository.toml")); err != nil { t.Fatal(err) } if err := os.Symlink("echo/tentacle.toml", filepath.Join(source, "repository.toml")); err != nil { t.Fatal(err) } run("add", ".") run("commit", "-m", "Symlink fixture") setHead() if _, err := read_git_repository(ctx, source, "https://example.org/team/tentacles"); err == nil { t.Fatal("accepted symlink metadata") } cancelled, cancel := context.WithCancel(ctx) cancel() if _, err := repository_git(cancelled, source, "status"); err == nil { t.Fatal("ignored cancellation") } }