e2e/teams_test.go

ba0a7d33f3a65ce53aafb074fda1682cf1cecfdf
gitbay/e2e/teams_test.go history · blame · raw

120 lines · 5222 bytes

  1package e2e
  2
  3import (
  4	"strings"
  5	"testing"
  6)
  7
  8func TestOrgTeams(t *testing.T) {
  9	t.Parallel()
 10	inst := startInstance(t)
 11	adminKey := inst.newKey(t, "alice")
 12	bobKey := inst.newKey(t, "bob")
 13	carolKey := inst.newKey(t, "carol")
 14	eveKey := inst.newKey(t, "eve")
 15	inst.admin(t, "admin", "user", "create", "alice", "--key", adminKey+".pub")
 16	inst.admin(t, "admin", "user", "create", "bob", "--key", bobKey+".pub")
 17	inst.admin(t, "admin", "user", "create", "carol", "--key", carolKey+".pub")
 18	inst.admin(t, "admin", "user", "create", "eve", "--key", eveKey+".pub")
 19
 20	// Org with two private repos; bob and carol are plain members.
 21	for _, args := range [][]string{
 22		{"org", "create", "acme"},
 23		{"org", "members", "add", "acme", "bob"},
 24		{"org", "members", "add", "acme", "carol"},
 25		{"repo", "create", "acme/core", "--private"},
 26		{"repo", "create", "acme/site", "--private"},
 27	} {
 28		if _, errOut, code := inst.ssh(t, adminKey, "", args...); code != 0 {
 29			t.Fatalf("%v: %s", args, errOut)
 30		}
 31	}
 32
 33	// Degenerate case: plain membership implies write everywhere.
 34	if _, _, code := inst.ssh(t, bobKey, "", "issue", "create", "acme/core", "--title", "'pre'"); code != 0 {
 35		t.Fatal("member write lost (degenerate case broken)")
 36	}
 37
 38	// Scope the org: members get nothing by default, teams grant.
 39	if _, _, code := inst.ssh(t, bobKey, "", "org", "settings", "members-role", "acme", "none"); code != 4 {
 40		t.Fatal("non-admin changed members-role")
 41	}
 42	if _, _, code := inst.ssh(t, adminKey, "", "org", "settings", "members-role", "acme", "none"); code != 0 {
 43		t.Fatal("members-role failed")
 44	}
 45	// bob now cannot even see the private repo.
 46	if _, _, code := inst.ssh(t, bobKey, "", "repo", "show", "acme/core"); code != 3 {
 47		t.Fatal("scoped member still sees private repo")
 48	}
 49
 50	// Team "core-devs": bob gets write on core, read on site.
 51	if _, _, code := inst.ssh(t, adminKey, "", "org", "team", "create", "acme", "core-devs"); code != 0 {
 52		t.Fatal("team create failed")
 53	}
 54	if _, errOut, code := inst.ssh(t, adminKey, "", "org", "team", "add", "acme", "core-devs", "eve"); code != 2 || !strings.Contains(errOut, "not a member") {
 55		t.Fatalf("non-member added to team: %d %s", code, errOut)
 56	}
 57	if _, _, code := inst.ssh(t, adminKey, "", "org", "team", "add", "acme", "core-devs", "bob"); code != 0 {
 58		t.Fatal("team add failed")
 59	}
 60	if _, _, code := inst.ssh(t, adminKey, "", "org", "team", "grant", "acme", "core-devs", "acme/core", "write"); code != 0 {
 61		t.Fatal("team grant failed")
 62	}
 63	if _, _, code := inst.ssh(t, adminKey, "", "org", "team", "grant", "acme", "core-devs", "acme/site", "read"); code != 0 {
 64		t.Fatal("second grant failed")
 65	}
 66	// Grants are limited to the org's own repos.
 67	if _, _, code := inst.ssh(t, adminKey, "", "repo", "create", "alice/own"); code != 0 {
 68		t.Fatal("repo create failed")
 69	}
 70	if _, errOut, code := inst.ssh(t, adminKey, "", "org", "team", "grant", "acme", "core-devs", "alice/own", "read"); code != 2 || !strings.Contains(errOut, "own org") {
 71		t.Fatalf("cross-org grant allowed: %d %s", code, errOut)
 72	}
 73
 74	// bob: write on core (can open issues), read-only on site (visible,
 75	// not writable). carol (no team): nothing.
 76	if _, _, code := inst.ssh(t, bobKey, "", "issue", "create", "acme/core", "--title", "'works'"); code != 0 {
 77		t.Fatal("team write not effective")
 78	}
 79	if _, _, code := inst.ssh(t, bobKey, "", "repo", "show", "acme/site"); code != 0 {
 80		t.Fatal("team read not effective")
 81	}
 82	if _, _, code := inst.ssh(t, bobKey, "", "repo", "settings", "protect", "acme/site", "main"); code != 4 {
 83		t.Fatal("read grant allowed admin action")
 84	}
 85	if _, _, code := inst.ssh(t, carolKey, "", "repo", "show", "acme/core"); code != 3 {
 86		t.Fatal("teamless member sees scoped repo")
 87	}
 88	out, _, _ := inst.ssh(t, bobKey, "", "repo", "list")
 89	if !strings.Contains(out, "acme/core") || !strings.Contains(out, "acme/site") {
 90		t.Fatalf("team repos missing from listing: %s", out)
 91	}
 92
 93	// show reflects members and grants; member removal drops access.
 94	out, _, _ = inst.ssh(t, adminKey, "", "org", "team", "show", "acme", "core-devs", "--json")
 95	if !strings.Contains(out, `"members":["bob"]`) || !strings.Contains(out, `"repo":"acme/core","role":"write"`) {
 96		t.Fatalf("team show: %s", out)
 97	}
 98	if _, _, code := inst.ssh(t, adminKey, "", "org", "team", "remove", "acme", "core-devs", "bob"); code != 0 {
 99		t.Fatal("team remove failed")
100	}
101	if _, _, code := inst.ssh(t, bobKey, "", "repo", "show", "acme/core"); code != 3 {
102		t.Fatal("removed member kept access")
103	}
104
105	// Deleting the team cascades its grants.
106	inst.ssh(t, adminKey, "", "org", "team", "add", "acme", "core-devs", "carol")
107	if _, _, code := inst.ssh(t, carolKey, "", "repo", "show", "acme/core"); code != 0 {
108		t.Fatal("carol team access missing")
109	}
110	if _, _, code := inst.ssh(t, adminKey, "", "org", "team", "delete", "acme", "core-devs"); code != 0 {
111		t.Fatal("team delete failed")
112	}
113	if _, _, code := inst.ssh(t, carolKey, "", "repo", "show", "acme/core"); code != 3 {
114		t.Fatal("deleted team's grant survived")
115	}
116	// Org admins keep admin regardless of scoping.
117	if _, _, code := inst.ssh(t, adminKey, "", "repo", "settings", "protect", "acme/core", "main"); code != 0 {
118		t.Fatal("org admin lost access")
119	}
120}