package repo import ( "errors" "strings" "testing" "time" "git.polynom.me/rio/internal/context" "git.polynom.me/rio/internal/gitea" log "github.com/sirupsen/logrus" ) func TestHeaderFilter(t *testing.T) { map1 := filterHeaders( map[string]interface{}{ "Content-Type": "hallo", "content-Type": "welt", "content-type": "uwu", "CONTENT-TYPE": "lol", "Content-Security-Policy": "none", }, ) if len(map1) != 1 { t.Fatalf("filterHeaders allowed %d != 1 headers", len(map1)) } for key := range map1 { if strings.ToLower(key) == "content-type" { t.Fatalf("filterHeaders allowed Content-Type") } } } func TestPickingCorrectRepositoryDefault(t *testing.T) { // Test that we default to the . repository, if we have only // one path component. log.SetLevel(log.DebugLevel) client := gitea.GiteaClient{ GetRepository: func(username, repositoryName string) (gitea.Repository, error) { if username != "example-user" { t.Fatalf("Called with unknown user %s", username) } if repositoryName != "example-user.pages.example.org" { t.Fatalf("Called with unknown repository %s", repositoryName) } return gitea.Repository{}, nil }, HasBranch: func(username, repositoryName, branchName string) bool { if username == "example-user" && repositoryName == "example-user.pages.example.org" && branchName == "pages" { return true } return false }, GetFile: func(username, repositoryName, branch, path string, since *time.Time) ([]byte, bool, error) { t.Fatal("getFile called") return []byte{}, true, nil }, LookupCNAME: func(domain string) (string, error) { t.Fatal("LookupCNAME called") return "", nil }, LookupRepoTXT: func(domain string) (string, error) { t.Fatal("LookupRepoTXT called") return "", nil }, } ctx := &context.GlobalContext{ Gitea: &client, Cache: &context.CacheContext{ RepositoryInformationCache: context.MakeRepoInfoCache(), RepositoryPathCache: context.MakeRepoPathCache(), }, } res, path, err := RepoFromPath("example-user", "example-user.pages.example.org", "", "index.html", ctx) if err != nil { t.Fatalf("An error occured: %v", err) } if res == nil { t.Fatal("Result is nil") } if path != "index.html" { t.Fatalf("Returned path is invalid: %s", path) } } func TestPickingCorrectRepositoryDefaultSubdirectory(t *testing.T) { // Test that we return the default repository when the first path component does // not correspong to an existing repository. log.SetLevel(log.DebugLevel) client := gitea.GiteaClient{ GetRepository: func(username, repositoryName string) (gitea.Repository, error) { if username != "example-user" { t.Fatalf("Called with unknown user %s", username) } if repositoryName == "assets" { return gitea.Repository{}, errors.New("gitea.Repository does not exist") } else if repositoryName == "example-user.pages.example.org" { return gitea.Repository{}, nil } else { t.Fatalf("Called with unknown repository %s", repositoryName) return gitea.Repository{}, nil } }, HasBranch: func(username, repositoryName, branchName string) bool { if username == "example-user" && repositoryName == "example-user.pages.example.org" && branchName == "pages" { return true } return false }, GetFile: func(username, repositoryName, branch, path string, since *time.Time) ([]byte, bool, error) { t.Fatal("getFile called") return []byte{}, true, nil }, LookupCNAME: func(domain string) (string, error) { t.Fatal("LookupCNAME called") return "", nil }, LookupRepoTXT: func(domain string) (string, error) { t.Fatal("LookupRepoTXT called") return "", nil }, } ctx := &context.GlobalContext{ Gitea: &client, Cache: &context.CacheContext{ RepositoryInformationCache: context.MakeRepoInfoCache(), RepositoryPathCache: context.MakeRepoPathCache(), }, } res, path, err := RepoFromPath("example-user", "example-user.pages.example.org", "", "assets/index.css", ctx) if err != nil { t.Fatalf("An error occured: %v", err) } if res == nil { t.Fatal("Result is nil") } if path != "assets/index.css" { t.Fatalf("Returned path is invalid: %s", path) } } func TestPickingCorrectRepositorySubdirectoryNoPagesBranch(t *testing.T) { // Test that we're picking the correct repository when the first path component // returns a repository without a pages branch. log.SetLevel(log.DebugLevel) client := gitea.GiteaClient{ GetRepository: func(username, repositoryName string) (gitea.Repository, error) { if username != "example-user" { t.Fatalf("Called with unknown user %s", username) } if repositoryName == "blog" { return gitea.Repository{ Name: "blog", }, nil } else if repositoryName == "example-user.pages.example.org" { return gitea.Repository{ Name: "example-user.pages.example.org", }, nil } else { t.Fatalf("Called with unknown repository %s", repositoryName) return gitea.Repository{}, nil } }, HasBranch: func(username, repositoryName, branchName string) bool { if username == "example-user" && repositoryName == "example-user.pages.example.org" && branchName == "pages" { return true } return false }, GetFile: func(username, repositoryName, branch, path string, since *time.Time) ([]byte, bool, error) { t.Fatal("getFile called") return []byte{}, true, nil }, LookupCNAME: func(domain string) (string, error) { t.Fatal("LookupCNAME called") return "", nil }, LookupRepoTXT: func(domain string) (string, error) { t.Fatal("LookupRepoTXT called") return "", nil }, } ctx := &context.GlobalContext{ Gitea: &client, Cache: &context.CacheContext{ RepositoryInformationCache: context.MakeRepoInfoCache(), RepositoryPathCache: context.MakeRepoPathCache(), }, } res, path, err := RepoFromPath("example-user", "example-user.pages.example.org", "", "blog/post1.html", ctx) if err != nil { t.Fatalf("An error occured: %v", err) } if res == nil { t.Fatal("Result is nil") } if res.Name != "example-user.pages.example.org" { t.Fatalf("Invalid repository selected: %s", res.Name) } if path != "blog/post1.html" { t.Fatalf("Returned path is invalid: %s", path) } } func TestPickingNoRepositoryInvalidCNAME(t *testing.T) { // Test that we're not picking a repository if the CNAME validation fails. log.SetLevel(log.DebugLevel) client := gitea.GiteaClient{ GetRepository: func(username, repositoryName string) (gitea.Repository, error) { if username == "example-user" && repositoryName == "example-user.pages.example.org" { return gitea.Repository{ Name: "example-user.pages.example.org", }, nil } else { t.Fatalf("Called with unknown repository %s", repositoryName) return gitea.Repository{}, nil } }, HasBranch: func(username, repositoryName, branchName string) bool { if username == "example-user" && repositoryName == "example-user.pages.example.org" && branchName == "pages" { return true } return false }, GetFile: func(username, repositoryName, branch, path string, since *time.Time) ([]byte, bool, error) { if username == "example-user" && repositoryName == "example-user.pages.example.org" && branch == "pages" && path == "rio.json" { return []byte("{\"CNAME\": \"some-other-domain.local\"}"), true, nil } t.Fatalf("Invalid file requested: %s/%s@%s:%s", username, repositoryName, branch, path) return []byte{}, true, nil }, LookupCNAME: func(domain string) (string, error) { return "", errors.New("No CNAME") }, LookupRepoTXT: func(domain string) (string, error) { return "", nil }, } ctx := &context.GlobalContext{ Gitea: &client, Cache: &context.CacheContext{ RepositoryInformationCache: context.MakeRepoInfoCache(), RepositoryPathCache: context.MakeRepoPathCache(), }, } _, _, err := RepoFromPath("example-user", "example-user.pages.example.org", "example-user.local", "index.html", ctx) if err == nil { t.Fatal("gitea.Repository returned even though CNAME validation should fail") } } func TestPickingRepositoryValidCNAME(t *testing.T) { // Test that we're picking a repository, given a CNAME, if the CNAME validation succeeds. log.SetLevel(log.DebugLevel) client := gitea.GiteaClient{ GetRepository: func(username, repositoryName string) (gitea.Repository, error) { if username == "example-user" && repositoryName == "example-user.local" { return gitea.Repository{ Name: "example-user.local", }, nil } else { t.Fatalf("Called with unknown repository %s", repositoryName) return gitea.Repository{}, nil } }, HasBranch: func(username, repositoryName, branchName string) bool { if username == "example-user" && repositoryName == "example-user.local" && branchName == "pages" { return true } return false }, GetFile: func(username, repositoryName, branch, path string, since *time.Time) ([]byte, bool, error) { if username == "example-user" && repositoryName == "example-user.local" && branch == "pages" && path == "rio.json" { return []byte("{\"CNAME\": \"example-user.local\"}"), true, nil } t.Fatalf("Invalid file requested: %s/%s@%s:%s", username, repositoryName, branch, path) return []byte{}, true, nil }, LookupCNAME: func(domain string) (string, error) { return "", errors.New("No CNAME") }, LookupRepoTXT: func(domain string) (string, error) { return "", nil }, } ctx := &context.GlobalContext{ Gitea: &client, Cache: &context.CacheContext{ RepositoryInformationCache: context.MakeRepoInfoCache(), RepositoryPathCache: context.MakeRepoPathCache(), }, } repo, _, err := RepoFromPath("example-user", "example-user.local", "example-user.pages.example.org", "index.html", ctx) if err != nil { t.Fatalf("Error returned: %v", err) } if repo.Name != "example-user.local" { t.Fatalf("Invalid repository name returned: %s", repo.Name) } } func TestPickingRepositoryValidCNAMEWithTXTLookup(t *testing.T) { // Test that we're picking a repository, given a CNAME, if the CNAME validation succeeds // and the TXT lookup returns something different. log.SetLevel(log.DebugLevel) client := gitea.GiteaClient{ GetRepository: func(username, repositoryName string) (gitea.Repository, error) { if username == "example-user" && repositoryName == "some-different-repository" { return gitea.Repository{ Name: "some-different-repository", }, nil } else { t.Fatalf("Called with unknown repository %s", repositoryName) return gitea.Repository{}, nil } }, HasBranch: func(username, repositoryName, branchName string) bool { if username == "example-user" && repositoryName == "some-different-repository" && branchName == "pages" { return true } return false }, GetFile: func(username, repositoryName, branch, path string, since *time.Time) ([]byte, bool, error) { if username == "example-user" && repositoryName == "some-different-repository" && branch == "pages" && path == "rio.json" { return []byte("{\"CNAME\": \"example-user.local\"}"), true, nil } t.Fatalf("Invalid file requested: %s/%s@%s:%s", username, repositoryName, branch, path) return []byte{}, true, nil }, LookupCNAME: func(domain string) (string, error) { return "", errors.New("No CNAME") }, LookupRepoTXT: func(domain string) (string, error) { if domain == "example-user.local" { return "some-different-repository", nil } return "", nil }, } ctx := &context.GlobalContext{ Gitea: &client, Cache: &context.CacheContext{ RepositoryInformationCache: context.MakeRepoInfoCache(), RepositoryPathCache: context.MakeRepoPathCache(), }, } repo, _, err := RepoFromPath("example-user", "example-user.local", "example-user.pages.example.org", "index.html", ctx) if err != nil { t.Fatalf("Error returned: %v", err) } if repo.Name != "some-different-repository" { t.Fatalf("Invalid repository name returned: %s", repo.Name) } } func TestPickingRepositoryValidCNAMEWithTXTLookupAndSubdirectory(t *testing.T) { // Test that we're picking a repository, given a CNAME, if the CNAME validation succeeds // and the TXT lookup returns something different. Additionally, we now have a subdirectory log.SetLevel(log.DebugLevel) client := gitea.GiteaClient{ GetRepository: func(username, repositoryName string) (gitea.Repository, error) { if username == "example-user" && repositoryName == "some-different-repository" { return gitea.Repository{ Name: "some-different-repository", }, nil } return gitea.Repository{}, errors.New("Unknown repository") }, HasBranch: func(username, repositoryName, branchName string) bool { if username == "example-user" && repositoryName == "some-different-repository" && branchName == "pages" { return true } return false }, GetFile: func(username, repositoryName, branch, path string, since *time.Time) ([]byte, bool, error) { if username == "example-user" && repositoryName == "some-different-repository" && branch == "pages" && path == "rio.json" { return []byte("{\"CNAME\": \"example-user.local\"}"), true, nil } t.Fatalf("Invalid file requested: %s/%s@%s:%s", username, repositoryName, branch, path) return []byte{}, true, nil }, LookupCNAME: func(domain string) (string, error) { return "", errors.New("No CNAME") }, LookupRepoTXT: func(domain string) (string, error) { if domain == "example-user.local" { return "some-different-repository", nil } return "", nil }, } ctx := &context.GlobalContext{ Gitea: &client, Cache: &context.CacheContext{ RepositoryInformationCache: context.MakeRepoInfoCache(), RepositoryPathCache: context.MakeRepoPathCache(), }, } repo, _, err := RepoFromPath("example-user", "example-user.local", "example-user.pages.example.org", "blog/index.html", ctx) if err != nil { t.Fatalf("Error returned: %v", err) } if repo.Name != "some-different-repository" { t.Fatalf("Invalid repository name returned: %s", repo.Name) } } func TestHeaderParsingEmpty(t *testing.T) { // Test that we are correctly handling a repository with no headers. log.SetLevel(log.DebugLevel) client := gitea.GiteaClient{ GetRepository: func(username, repositoryName string) (gitea.Repository, error) { if username == "example-user" && repositoryName == "some-different-repository" { return gitea.Repository{ Name: "some-different-repository", }, nil } return gitea.Repository{}, errors.New("Unknown repository") }, HasBranch: func(username, repositoryName, branchName string) bool { if username == "example-user" && repositoryName == "some-different-repository" && branchName == "pages" { return true } return false }, GetFile: func(username, repositoryName, branch, path string, since *time.Time) ([]byte, bool, error) { if username == "example-user" && repositoryName == "some-different-repository" && branch == "pages" && path == "rio.json" { return []byte("{\"CNAME\": \"example-user.local\"}"), true, nil } t.Fatalf("Invalid file requested: %s/%s@%s:%s", username, repositoryName, branch, path) return []byte{}, true, nil }, LookupCNAME: func(domain string) (string, error) { return "", errors.New("No CNAME") }, LookupRepoTXT: func(domain string) (string, error) { if domain == "example-user.local" { return "some-different-repository", nil } return "", nil }, } ctx := &context.GlobalContext{ Gitea: &client, Cache: &context.CacheContext{ RepositoryInformationCache: context.MakeRepoInfoCache(), RepositoryPathCache: context.MakeRepoPathCache(), }, } info := GetRepositoryInformation("example-user", "some-different-repository", ctx) if info == nil { t.Fatalf("No repository information returned") } if len(info.Headers) > 0 { t.Fatalf("Headers returned: %v", info.Headers) } } func TestHeaderParsing(t *testing.T) { // Test that we are correctly handling a repository with no headers. log.SetLevel(log.DebugLevel) client := gitea.GiteaClient{ GetRepository: func(username, repositoryName string) (gitea.Repository, error) { if username == "example-user" && repositoryName == "some-different-repository" { return gitea.Repository{ Name: "some-different-repository", }, nil } return gitea.Repository{}, errors.New("Unknown repository") }, HasBranch: func(username, repositoryName, branchName string) bool { if username == "example-user" && repositoryName == "some-different-repository" && branchName == "pages" { return true } return false }, GetFile: func(username, repositoryName, branch, path string, since *time.Time) ([]byte, bool, error) { if username == "example-user" && repositoryName == "some-different-repository" && branch == "pages" && path == "rio.json" { return []byte("{\"CNAME\": \"example-user.local\", \"headers\": {\"X-Cool-Header\": \"Very nice!\"}}"), true, nil } t.Fatalf("Invalid file requested: %s/%s@%s:%s", username, repositoryName, branch, path) return []byte{}, true, nil }, LookupCNAME: func(domain string) (string, error) { return "", errors.New("No CNAME") }, LookupRepoTXT: func(domain string) (string, error) { if domain == "example-user.local" { return "some-different-repository", nil } return "", nil }, } ctx := &context.GlobalContext{ Gitea: &client, Cache: &context.CacheContext{ RepositoryInformationCache: context.MakeRepoInfoCache(), RepositoryPathCache: context.MakeRepoPathCache(), }, } info := GetRepositoryInformation("example-user", "some-different-repository", ctx) if info == nil { t.Fatalf("No repository information returned") } if len(info.Headers) != 1 { t.Fatalf("len(info.Headers) != 1: %v", info.Headers) } header, found := info.Headers["X-Cool-Header"] if !found { t.Fatal("Header X-Cool-Header not found") } if header != "Very nice!" { t.Fatalf("Invalid header value for X-Cool-Header: \"%s\"", header) } }