Skip to content

Commit 90ce7a4

Browse files
chmouelsavitaashture
authored andcommitted
Fix policy settings
Policy setting was broken, this would always get the other ACLs check to run even when the user was not there. The tests was also not testing the policy setting properly. The E2E tests is hard to test on GitHub since we need to create another two others users and another organisation with a bunch of teams to test it properly. Hopefully if we can get our own GitHub enterprise instance we would be able to do those in the future. I have done those tests manually: An organisation with three users: chmouel sam rubben A team with the users sam and chmouel in there but not rubben. I have created a repo CR with the policy settings like this: ```yaml settings: policy: pull_request: - pull_request ``` the user sam gets allowed to run CI but the user rubben get disallowed. If I issue a comment with /ok-to-test from the user sam on the rubben PR it will be disallowed (since it only to run the pr and not issue ok-to-test). I changed the policy on the repo settings with the ok-to-test section allowing the group pull_request: ```yaml settings: policy: ok_to_test: - pull_request pull_request: - pull_request ``` and then I can issue /ok-to-test from the user sam on the user rubben and it will be tested. Signed-off-by: Chmouel Boudjnah <[email protected]>
1 parent 27db417 commit 90ce7a4

File tree

11 files changed

+246
-134
lines changed

11 files changed

+246
-134
lines changed

pkg/policy/policy.go

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ type Policy struct {
2727
EventEmitter *events.EventEmitter
2828
}
2929

30-
func (p *Policy) checkAllowed(ctx context.Context, tType info.TriggerType) (Result, error) {
30+
func (p *Policy) checkAllowed(ctx context.Context, tType info.TriggerType) (Result, string) {
3131
if p.Repository == nil {
32-
return ResultNotSet, nil
32+
return ResultNotSet, ""
3333
}
3434
settings := p.Repository.Spec.Settings
3535
if settings == nil || settings.Policy == nil {
36-
return ResultNotSet, nil
36+
return ResultNotSet, ""
3737
}
3838

3939
var sType []string
@@ -45,42 +45,61 @@ func (p *Policy) checkAllowed(ctx context.Context, tType info.TriggerType) (Resu
4545
sType = settings.Policy.PullRequest
4646
// NOTE: not supported yet, will imp if it gets requested and reasonable to implement
4747
case info.TriggerTypePush, info.TriggerTypeCancel, info.TriggerTypeCheckSuiteRerequested, info.TriggerTypeCheckRunRerequested:
48-
return ResultNotSet, nil
48+
return ResultNotSet, ""
4949
default:
50-
return ResultNotSet, nil
50+
return ResultNotSet, ""
5151
}
5252

53+
// if policy is set but empty then it mean disallow everything
5354
if len(sType) == 0 {
54-
return ResultNotSet, nil
55+
return ResultDisallowed, "no policy set"
5556
}
5657

57-
allowed, reason := p.VCX.CheckPolicyAllowing(ctx, p.Event, sType)
58-
reasonMsg := fmt.Sprintf("policy check: %s, %s", string(tType), reason)
59-
if reason != "" {
60-
p.EventEmitter.EmitMessage(p.Repository, zap.InfoLevel, "PolicyCheck", reasonMsg)
58+
// remove empty values from sType
59+
temp := []string{}
60+
for _, val := range sType {
61+
if val != "" {
62+
temp = append(temp, val)
63+
}
64+
}
65+
sType = temp
66+
67+
// if policy is set but with empty values then bail out.
68+
if len(sType) == 0 {
69+
return ResultDisallowed, "policy set and empty with no groups"
6170
}
71+
72+
allowed, reason := p.VCX.CheckPolicyAllowing(ctx, p.Event, sType)
6273
if allowed {
63-
return ResultAllowed, nil
74+
return ResultAllowed, ""
6475
}
65-
return ResultDisallowed, fmt.Errorf(reasonMsg)
76+
return ResultDisallowed, fmt.Sprintf("policy check: %s, %s", string(tType), reason)
6677
}
6778

68-
func (p *Policy) IsAllowed(ctx context.Context, tType info.TriggerType) (bool, string) {
79+
func (p *Policy) IsAllowed(ctx context.Context, tType info.TriggerType) (Result, string) {
6980
var reason string
70-
policyRes, err := p.checkAllowed(ctx, tType)
71-
if err != nil {
72-
return false, err.Error()
73-
}
81+
policyRes, reason := p.checkAllowed(ctx, tType)
7482
switch policyRes {
7583
case ResultAllowed:
7684
reason = fmt.Sprintf("policy check: policy is set for sender %s has been allowed to run CI via policy", p.Event.Sender)
7785
p.EventEmitter.EmitMessage(p.Repository, zap.InfoLevel, "PolicySetAllowed", reason)
78-
return true, ""
86+
return ResultAllowed, ""
7987
case ResultDisallowed:
80-
reason = fmt.Sprintf("policy check: policy is set but sender %s is not in the allowed groups trying the next ACL conditions", p.Event.Sender)
88+
allowed, err := p.VCX.IsAllowedOwnersFile(ctx, p.Event)
89+
if err != nil {
90+
return ResultDisallowed, err.Error()
91+
}
92+
if allowed {
93+
reason = fmt.Sprintf("policy check: policy is set, sender %s not in the allowed policy but allowed via OWNERS file", p.Event.Sender)
94+
p.EventEmitter.EmitMessage(p.Repository, zap.InfoLevel, "PolicySetAllowed", reason)
95+
return ResultAllowed, ""
96+
}
97+
if reason == "" {
98+
reason = fmt.Sprintf("policy check: policy is set but sender %s is not in the allowed groups", p.Event.Sender)
99+
}
81100
p.EventEmitter.EmitMessage(p.Repository, zap.InfoLevel, "PolicySetDisallowed", reason)
82-
case ResultNotSet:
83-
// should we put a warning here? it does fill up quite a bit the log every time! so I am not so sure..
101+
return ResultDisallowed, ""
102+
case ResultNotSet: // this is to make golangci-lint happy
84103
}
85-
return false, reason
104+
return ResultNotSet, reason
86105
}

pkg/policy/policy_test.go

Lines changed: 111 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package policy
22

33
import (
4+
"fmt"
5+
"strings"
46
"testing"
57

68
"go.uber.org/zap"
@@ -26,6 +28,10 @@ func newRepoWithPolicy(policy *v1alpha1.Policy) *v1alpha1.Repository {
2628
}
2729

2830
func TestPolicy_IsAllowed(t *testing.T) {
31+
senderName := "sender"
32+
eventWithSender := info.NewEvent()
33+
eventWithSender.Sender = senderName
34+
2935
type fields struct {
3036
repository *v1alpha1.Repository
3137
event *info.Event
@@ -34,130 +40,180 @@ func TestPolicy_IsAllowed(t *testing.T) {
3440
tType info.TriggerType
3541
}
3642
tests := []struct {
37-
name string
38-
fields fields
39-
args args
40-
replyAllowed bool
41-
want bool
42-
wantErr bool
43-
wantReason string
43+
name string
44+
fields fields
45+
args args
46+
vcsReplyAllowed bool
47+
want Result
48+
wantErr bool
49+
wantReason string
50+
allowedInOwnersFile bool
51+
expectedLogsSnippets []string
4452
}{
4553
{
46-
name: "Test Policy.IsAllowed with no settings",
54+
name: "notset/not set",
4755
fields: fields{
4856
repository: nil,
4957
event: nil,
5058
},
5159
args: args{
5260
tType: info.TriggerTypePush,
5361
},
54-
want: false,
62+
want: ResultNotSet,
5563
},
5664
{
57-
name: "Test Policy.IsAllowed with unknown event type",
65+
name: "notset/unknown event type",
5866
fields: fields{
5967
repository: newRepoWithPolicy(&v1alpha1.Policy{PullRequest: []string{"pull_request"}}),
6068
event: nil,
6169
},
6270
args: args{
6371
tType: "unknown",
6472
},
65-
want: false,
73+
want: ResultNotSet,
6674
},
6775
{
68-
name: "allowing member not in team for pull request",
76+
name: "notset/push",
6977
fields: fields{
7078
repository: newRepoWithPolicy(&v1alpha1.Policy{PullRequest: []string{"pull_request"}}),
71-
event: info.NewEvent(),
79+
event: nil,
7280
},
7381
args: args{
74-
tType: info.TriggerTypePullRequest,
82+
tType: info.TriggerTypePush,
7583
},
76-
replyAllowed: true,
77-
want: true,
84+
want: ResultNotSet,
7885
},
7986
{
80-
name: "empty settings policy ignore",
81-
wantReason: "policy check: pull_request, policy disallowing",
87+
name: "allowed/allowing member for pull request",
8288
fields: fields{
83-
repository: newRepoWithPolicy(&v1alpha1.Policy{PullRequest: []string{""}}),
89+
repository: newRepoWithPolicy(&v1alpha1.Policy{PullRequest: []string{"pull_request"}}),
8490
event: info.NewEvent(),
8591
},
8692
args: args{
8793
tType: info.TriggerTypePullRequest,
8894
},
89-
want: false,
95+
vcsReplyAllowed: true,
96+
want: ResultAllowed,
9097
},
9198
{
92-
name: "disallowing member not in team for pull request",
93-
wantReason: "policy check: pull_request, policy disallowing",
99+
name: "allowed/from owners file",
94100
fields: fields{
95101
repository: newRepoWithPolicy(&v1alpha1.Policy{PullRequest: []string{"pull_request"}}),
96-
event: info.NewEvent(),
102+
event: eventWithSender,
97103
},
98104
args: args{
99105
tType: info.TriggerTypePullRequest,
100106
},
101-
want: false,
102-
wantErr: true,
107+
vcsReplyAllowed: false,
108+
allowedInOwnersFile: true,
109+
want: ResultAllowed,
110+
expectedLogsSnippets: []string{
111+
fmt.Sprintf("policy check: policy is set, sender %s not in the allowed policy but allowed via OWNERS file", senderName),
112+
},
103113
},
104114
{
105-
name: "allowing member in team for ok-to-test",
115+
name: "allowed/member in team for ok-to-test",
106116
fields: fields{
107-
repository: newRepoWithPolicy(&v1alpha1.Policy{PullRequest: []string{"ok-to-test"}}),
117+
repository: newRepoWithPolicy(&v1alpha1.Policy{OkToTest: []string{"ok-to-test"}}),
108118
event: info.NewEvent(),
109119
},
110120
args: args{
111121
tType: info.TriggerTypeOkToTest,
112122
},
113-
replyAllowed: true,
114-
want: false,
123+
vcsReplyAllowed: true,
124+
want: ResultAllowed,
125+
},
126+
{
127+
name: "allowed/retest same as ok-to-test",
128+
fields: fields{
129+
repository: newRepoWithPolicy(&v1alpha1.Policy{OkToTest: []string{"ok-to-test"}}),
130+
event: info.NewEvent(),
131+
},
132+
args: args{
133+
tType: info.TriggerTypeRetest,
134+
},
135+
vcsReplyAllowed: true,
136+
want: ResultAllowed,
137+
},
138+
{
139+
name: "disallowed/policy set with empty list",
140+
expectedLogsSnippets: []string{"policy set and empty with no groups"},
141+
fields: fields{
142+
repository: newRepoWithPolicy(&v1alpha1.Policy{PullRequest: []string{""}}),
143+
event: eventWithSender,
144+
},
145+
args: args{
146+
tType: info.TriggerTypePullRequest,
147+
},
148+
want: ResultDisallowed,
149+
},
150+
{
151+
name: "disallowed/member not in team for pull request",
152+
fields: fields{
153+
repository: newRepoWithPolicy(&v1alpha1.Policy{PullRequest: []string{"pull_request"}}),
154+
event: info.NewEvent(),
155+
},
156+
args: args{
157+
tType: info.TriggerTypePullRequest,
158+
},
159+
want: ResultDisallowed,
160+
wantErr: true,
161+
expectedLogsSnippets: []string{"policy check: pull_request, policy disallowing"},
115162
},
116163
{
117-
name: "disallowing member not in team for ok-to-test",
164+
name: "disallowed/member not in team for ok-to-test",
118165
fields: fields{
119-
repository: newRepoWithPolicy(&v1alpha1.Policy{PullRequest: []string{"ok-to-test"}}),
166+
repository: newRepoWithPolicy(&v1alpha1.Policy{OkToTest: []string{"nono"}}),
120167
event: info.NewEvent(),
121168
},
122169
args: args{
123170
tType: info.TriggerTypeOkToTest,
124171
},
125-
want: false,
126-
wantErr: true,
172+
want: ResultDisallowed,
173+
wantErr: true,
174+
expectedLogsSnippets: []string{"policy check: ok-to-test, policy disallowing"},
127175
},
128176
{
129-
name: "allowing member not in team for retest",
177+
name: "disallowed/member not in team",
130178
fields: fields{
131-
repository: newRepoWithPolicy(&v1alpha1.Policy{PullRequest: []string{"ok-to-test"}}),
179+
repository: newRepoWithPolicy(&v1alpha1.Policy{OkToTest: []string{"ok-to-test"}}),
132180
event: info.NewEvent(),
133181
},
134182
args: args{
135183
tType: info.TriggerTypeRetest,
136184
},
137-
want: false,
185+
want: ResultDisallowed,
186+
wantErr: true,
187+
vcsReplyAllowed: false,
188+
expectedLogsSnippets: []string{"policy check: retest, policy disallowing"},
138189
},
139190
{
140-
name: "disallowing member not in team for retest",
191+
name: "disallowed/from owners file",
141192
fields: fields{
142-
repository: newRepoWithPolicy(&v1alpha1.Policy{PullRequest: []string{"ok-to-test"}}),
193+
repository: newRepoWithPolicy(&v1alpha1.Policy{PullRequest: []string{"pull_request"}}),
143194
event: info.NewEvent(),
144195
},
145196
args: args{
146-
tType: info.TriggerTypeRetest,
197+
tType: info.TriggerTypePullRequest,
147198
},
148-
want: false,
149-
wantErr: true,
199+
vcsReplyAllowed: false,
200+
allowedInOwnersFile: false,
201+
want: ResultDisallowed,
202+
expectedLogsSnippets: []string{"policy check: pull_request, policy disallowing"},
150203
},
151204
}
152205
for _, tt := range tests {
153206
t.Run(tt.name, func(t *testing.T) {
154-
observer, _ := zapobserver.New(zap.InfoLevel)
207+
observer, log := zapobserver.New(zap.InfoLevel)
155208
logger := zap.New(observer).Sugar()
156209

157210
ctx, _ := rtesting.SetupFakeContext(t)
158211
stdata, _ := testclient.SeedTestData(t, ctx, testclient.Data{})
159212

160-
vcx := &testprovider.TestProviderImp{PolicyDisallowing: !tt.replyAllowed}
213+
vcx := &testprovider.TestProviderImp{
214+
PolicyDisallowing: !tt.vcsReplyAllowed,
215+
AllowedInOwnersFile: tt.allowedInOwnersFile,
216+
}
161217
if tt.fields.event == nil {
162218
tt.fields.event = info.NewEvent()
163219
}
@@ -169,10 +225,20 @@ func TestPolicy_IsAllowed(t *testing.T) {
169225
EventEmitter: events.NewEventEmitter(stdata.Kube, logger),
170226
}
171227
got, reason := p.IsAllowed(ctx, tt.args.tType)
172-
if got != tt.want {
173-
t.Errorf("Policy.IsAllowed() = %v, want %v", got, tt.want)
228+
switch got {
229+
case ResultAllowed:
230+
assert.Equal(t, tt.want, ResultAllowed)
231+
case ResultDisallowed:
232+
assert.Equal(t, tt.want, ResultDisallowed)
233+
case ResultNotSet:
234+
assert.Equal(t, tt.want, ResultNotSet)
174235
}
175236
assert.Equal(t, tt.wantReason, reason)
237+
238+
for k, snippet := range tt.expectedLogsSnippets {
239+
logmsg := log.AllUntimed()[k].Message
240+
assert.Assert(t, strings.Contains(logmsg, snippet), "\n on index: %d\n we want: %s\n we got: %s", k, snippet, logmsg)
241+
}
176242
})
177243
}
178244
}

0 commit comments

Comments
 (0)