internal/policy/access_test.go
112 lines · 3691 bytes
1package policy
2
3import (
4 "testing"
5
6 "gitbay.org/gitbay/internal/store"
7)
8
9var (
10 owner = store.User{ID: 1, Username: "alice"}
11 stranger = store.User{ID: 2, Username: "bob"}
12 priv = store.Repo{ID: 10, OwnerKind: "user", OwnerID: 1, OwnerName: "alice", Name: "p", Visibility: "private"}
13 pub = store.Repo{ID: 11, OwnerKind: "user", OwnerID: 1, OwnerName: "alice", Name: "q", Visibility: "public"}
14)
15
16func TestAccessMatrix(t *testing.T) {
17 cases := []struct {
18 name string
19 user store.User
20 repo store.Repo
21 grant string
22 read bool
23 write bool
24 admin bool
25 }{
26 {"owner private", owner, priv, "", true, true, true},
27 {"stranger private no grant", stranger, priv, "", false, false, false},
28 {"stranger private read", stranger, priv, "read", true, false, false},
29 {"stranger private write", stranger, priv, "write", true, true, false},
30 {"stranger private admin", stranger, priv, "admin", true, true, true},
31 {"stranger public no grant", stranger, pub, "", true, false, false},
32 {"stranger public write", stranger, pub, "write", true, true, false},
33 }
34 for _, tc := range cases {
35 t.Run(tc.name, func(t *testing.T) {
36 if got := CanRead(tc.user, tc.repo, tc.grant); got != tc.read {
37 t.Errorf("CanRead = %v, want %v", got, tc.read)
38 }
39 if got := CanWrite(tc.user, tc.repo, tc.grant); got != tc.write {
40 t.Errorf("CanWrite = %v, want %v", got, tc.write)
41 }
42 if got := CanAdmin(tc.user, tc.repo, tc.grant); got != tc.admin {
43 t.Errorf("CanAdmin = %v, want %v", got, tc.admin)
44 }
45 })
46 }
47}
48
49func TestScopeAllowsGit(t *testing.T) {
50 cases := []struct {
51 scope string
52 repo string
53 write bool
54 want bool
55 }{
56 {"full", "a/b", true, true},
57 {"git", "a/b", true, true},
58 {"deploy:7:ro", "a/b", false, false}, // deploy keys never pass the account path
59 {"", "a/b", false, false},
60 }
61 for _, tc := range cases {
62 if got := ScopeAllowsGit(tc.scope, tc.repo, tc.write); got != tc.want {
63 t.Errorf("ScopeAllowsGit(%q, %q, write=%v) = %v, want %v", tc.scope, tc.repo, tc.write, got, tc.want)
64 }
65 }
66}
67
68func TestDeployScopeAllows(t *testing.T) {
69 cases := []struct {
70 scope string
71 repoID int64
72 write bool
73 want bool
74 }{
75 {"deploy:7:ro", 7, false, true},
76 {"deploy:7:ro", 7, true, false},
77 {"deploy:7:rw", 7, true, true},
78 {"deploy:7:rw", 8, false, false}, // wrong repo
79 {"deploy:7", 7, false, false}, // malformed
80 {"full", 7, false, false}, // not a deploy scope
81 }
82 for _, tc := range cases {
83 if got := DeployScopeAllows(tc.scope, tc.repoID, tc.write); got != tc.want {
84 t.Errorf("DeployScopeAllows(%q, %d, write=%v) = %v, want %v", tc.scope, tc.repoID, tc.write, got, tc.want)
85 }
86 }
87}
88
89func TestCheckPush(t *testing.T) {
90 repo := store.Repo{Settings: store.RepoSettings{ProtectedBranches: []string{"main"}}}
91 cases := []struct {
92 name string
93 updates []RefUpdate
94 denied bool
95 }{
96 {"normal push to protected", []RefUpdate{{Ref: "refs/heads/main"}}, false},
97 {"force to protected", []RefUpdate{{Ref: "refs/heads/main", IsForce: true}}, true},
98 {"delete protected", []RefUpdate{{Ref: "refs/heads/main", IsDelete: true}}, true},
99 {"force to unprotected", []RefUpdate{{Ref: "refs/heads/dev", IsForce: true}}, false},
100 {"delete unprotected", []RefUpdate{{Ref: "refs/heads/dev", IsDelete: true}}, false},
101 {"mr namespace", []RefUpdate{{Ref: "refs/merge-requests/1/head"}}, true},
102 {"tag alongside protected", []RefUpdate{{Ref: "refs/tags/v1"}, {Ref: "refs/heads/main"}}, false},
103 }
104 for _, tc := range cases {
105 t.Run(tc.name, func(t *testing.T) {
106 msg := CheckPush(repo, tc.updates)
107 if (msg != "") != tc.denied {
108 t.Errorf("CheckPush = %q, denied should be %v", msg, tc.denied)
109 }
110 })
111 }
112}