package auth
import ( "os" "path/filepath" "testing"
"gitweb/internal/store"
)
// writeTree writes files (path -> content) under a fresh temp root and returns a // LocalStore over it. func writeTree(t *testing.T, files map[string]string) *store.LocalStore { t.Helper() root := t.TempDir() for p, content := range files { full := filepath.Join(root, filepath.FromSlash(p)) if err := os.MkdirAll(filepath.Dir(full), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(full, []byte(content), 0o644); err != nil { t.Fatal(err) } } return store.NewLocalStore(root) }
// checker reduces the boilerplate of asserting CanRead/CanWrite outcomes. type checker struct { t *testing.T a *Authorizer }
func (c checker) read(name, user, p string, want bool) { c.t.Helper() got, err := c.a.CanRead(user, p) if err != nil { c.t.Fatalf("%s: CanRead error: %v", name, err) } if got != want { c.t.Errorf("%s: CanRead(%q) = %v, want %v", name, user, got, want) } }
func (c checker) write(name, user, p string, want bool) { c.t.Helper() got, err := c.a.CanWrite(user, p) if err != nil { c.t.Fatalf("%s: CanWrite error: %v", name, err) } if got != want { c.t.Errorf("%s: CanWrite(%q) = %v, want %v", name, user, got, want) } }
func TestAuthorizerPublicRepo(t testing.T) { const owner = "u@d.com" repo := owner + "/public.git" st := writeTree(t, map[string]string{ repo + "/HEAD": "ref: refs/heads/main\n", repo + "/Access": "read,list: all\n: " + owner + "\n", }) c := checker{t, NewAuthorizer(st)}
c.read("anon", "", repo, true)
c.read("stranger", "x@other.com", repo, true)
c.read("owner", owner, repo, true)
c.write("anon", "", repo, false)
c.write("owner", owner, repo, true)
c.write("stranger", "x@other.com", repo, false)
}
func TestAuthorizerPrivateRepo(t testing.T) { const owner = "u@d.com" repo := owner + "/private.git" st := writeTree(t, map[string]string{ repo + "/HEAD": "ref: refs/heads/main\n", repo + "/Access": ": " + owner + "\nread,write: w@d.com\n", }) c := checker{t, NewAuthorizer(st)}
c.read("anon", "", repo, false)
c.read("collaborator", "w@d.com", repo, true)
c.read("stranger", "x@other.com", repo, false)
c.write("collaborator", "w@d.com", repo, true)
c.write("stranger", "x@other.com", repo, false)
c.write("owner", owner, repo, true)
}
// A private Access file inside the repo overrides a public one on the parent // directory (nearest ancestor wins). func TestAuthorizerNearestAccessWins(t testing.T) { const owner = "u@d.com" repo := owner + "/proj/secret.git" st := writeTree(t, map[string]string{ owner + "/proj/Access": "read,list: all\n: " + owner + "\n", repo + "/HEAD": "ref: refs/heads/main\n", repo + "/Access": "*: " + owner + "\n", }) c := checker{t, NewAuthorizer(st)}
c.read("anon", "", repo, false)
c.read("owner", owner, repo, true)
}
// With no Access file anywhere, only the owner has any rights. func TestAuthorizerNoAccessOwnerOnly(t *testing.T) { const owner = "u@d.com" repo := owner + "/bare.git" st := writeTree(t, map[string]string{ repo + "/HEAD": "ref: refs/heads/main\n", }) c := checker{t, NewAuthorizer(st)}
c.read("owner", owner, repo, true)
c.read("anon", "", repo, false)
c.read("stranger", "x@other.com", repo, false)
c.write("owner", owner, repo, true)
}