Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

A free and open-source forge that lives in your Git repo.

Add instance-wide roles and refine access UI

5b814e9958090cfd1fa826efb2d375bf613547c1 · Keenan Nemetz · 14d ago · parent 9579c1f9

Add instance-wide roles and refine access UI

Instance roles now live on accounts, apply to public repositories, and the Admin role is the unified instance-admin permission with access to every repository. Repository ACLs can raise an instance role but not lower it.

Adds role assignment to the users UI and CLI, open-registration role config, a reusable role picker, and separates adding a repository account from saving access rules.

forge/access/store_test.go +52

@@ -65,6 +65,58 @@ func TestRulesRoundTripAndReplace(t *testing.T) {
65 65 }
66 66 }
67 67
68 // The store is where the roster's instance-wide role meets a repository's rules.
69 // A public repository gets the global grant; a private one does not, unless the
70 // account is an instance admin.
71 func TestStoreAttachesInstanceRoles(t *testing.T) {
72 t.Parallel()
73 s, _ := open(t)
74 s.InstanceRole = func(name string) Role {
75 switch name {
76 case "invited":
77 return Contribute
78 case "boss":
79 return Admin
80 }
81 return None
82 }
83 pub := Empty("owner")
84 pub.Default = "read"
85 if err := s.Set("public-repo", pub, "test", time.Now().UTC()); err != nil {
86 t.Fatal(err)
87 }
88 private := Empty("owner")
89 if err := s.Set("private-repo", private, "test", time.Now().UTC()); err != nil {
90 t.Fatal(err)
91 }
92
93 got, err := s.Get("public-repo")
94 if err != nil {
95 t.Fatal(err)
96 }
97 if got.RoleFor("invited") != Contribute {
98 t.Fatalf("public instance role = %v", got.RoleFor("invited"))
99 }
100 if got.RepositoryRoleFor("invited") != Read {
101 t.Fatalf("repository-only role = %v, want the default read", got.RepositoryRoleFor("invited"))
102 }
103 got, err = s.Get("private-repo")
104 if err != nil {
105 t.Fatal(err)
106 }
107 if got.RoleFor("invited") != None {
108 t.Fatalf("private repo admitted instance contributor: %v", got.RoleFor("invited"))
109 }
110 if got.RoleFor("boss") != Admin {
111 t.Fatalf("instance admin on private repo = %v", got.RoleFor("boss"))
112 }
113 // A repository without a row still has to see the instance rules.
114 empty := s.Attach(Empty(""))
115 if empty.RoleFor("boss") != Admin {
116 t.Fatalf("attached empty ACL = %v", empty.RoleFor("boss"))
117 }
118 }
119
68 120 // An access change is the one administrative act that has to leave a trace: the copy
69 121 // that lived in git kept it in the commit message.
70 122 func TestChangesAreAudited(t *testing.T) {