Files

178 lines
7.0 KiB
Go

// 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")
}
}