Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions integrations/access/accessrequest/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,10 @@ func (a *App) handleAccessMonitoringRule(ctx context.Context, event types.Event)
if !ok {
return trace.BadParameter("expected AccessMonitoringRule resource type, got %T", event.Resource)
}

// In the event an existing rule no longer applies we must remove it.
if !a.amrAppliesToThisPlugin(req) {
delete(a.accessMonitoringRules.rules, event.Resource.GetName())
return nil
}
a.accessMonitoringRules.rules[req.Metadata.Name] = req
Expand Down
126 changes: 126 additions & 0 deletions integrations/access/slack/testlib/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,132 @@ func (s *SlackSuiteOSS) TestRecipientsFromAccessMonitoringRule() {
assert.Equal(t, s.requesterOSSSlackUser.ID, messages[0].Channel)
assert.Equal(t, s.reviewer1SlackUser.ID, messages[1].Channel)
assert.Equal(t, s.reviewer2SlackUser.ID, messages[2].Channel)

assert.NoError(t, s.ClientByName(integration.RulerUserName).
AccessMonitoringRulesClient().DeleteAccessMonitoringRule(ctx, "test-slack-amr"))
}

func (s *SlackSuiteOSS) TestRecipientsFromAccessMonitoringRuleAfterUpdate() {
t := s.T()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
t.Cleanup(cancel)

// Setup base config to ensure access monitoring rule recipient take precidence
s.appConfig.Recipients = common.RawRecipientsMap{
types.Wildcard: []string{
s.reviewer2SlackUser.Profile.Email,
},
}

s.startApp()
const numMessagesInitial = 3
const numMessagesFinal = 2

_, err := s.ClientByName(integration.RulerUserName).
AccessMonitoringRulesClient().
CreateAccessMonitoringRule(ctx, &accessmonitoringrulesv1.AccessMonitoringRule{
Kind: types.KindAccessMonitoringRule,
Version: types.V1,
Metadata: &v1.Metadata{
Name: "test-slack-amr-2",
},
Spec: &accessmonitoringrulesv1.AccessMonitoringRuleSpec{
Subjects: []string{types.KindAccessRequest},
Condition: "!is_empty(access_request.spec.roles)",
Notification: &accessmonitoringrulesv1.Notification{
Name: "slack",
Recipients: []string{
s.reviewer1SlackUser.ID,
s.reviewer2SlackUser.Profile.Email,
},
},
},
})
assert.NoError(t, err)

// Test execution: we create an access request
userName := integration.RequesterOSSUserName
request := s.CreateAccessRequest(ctx, userName, nil)
pluginData := s.checkPluginData(ctx, request.GetName(), func(data accessrequest.PluginData) bool {
return len(data.SentMessages) > 0
})
assert.Len(t, pluginData.SentMessages, numMessagesInitial)

var messages []slack.Message

messageSet := make(SlackDataMessageSet)

// Validate we got 3 messages: one for each recipient and one for the requester.
for i := 0; i < numMessagesInitial; i++ {
msg, err := s.fakeSlack.CheckNewMessage(ctx)
require.NoError(t, err)
messageSet.Add(accessrequest.MessageData{ChannelID: msg.Channel, MessageID: msg.Timestamp})
messages = append(messages, msg)
}

assert.Len(t, messageSet, numMessagesInitial)
for i := 0; i < numMessagesInitial; i++ {
assert.Contains(t, messageSet, pluginData.SentMessages[i])
}

// Validate the message recipients
sort.Sort(SlackMessageSlice(messages))
assert.Equal(t, s.requesterOSSSlackUser.ID, messages[0].Channel)
assert.Equal(t, s.reviewer1SlackUser.ID, messages[1].Channel)
assert.Equal(t, s.reviewer2SlackUser.ID, messages[2].Channel)

_, err = s.ClientByName(integration.RulerUserName).
AccessMonitoringRulesClient().
UpdateAccessMonitoringRule(ctx, &accessmonitoringrulesv1.AccessMonitoringRule{
Kind: types.KindAccessMonitoringRule,
Version: types.V1,
Metadata: &v1.Metadata{
Name: "test-slack-amr-2",
},
Spec: &accessmonitoringrulesv1.AccessMonitoringRuleSpec{
Subjects: []string{"someOtherKind"},
Condition: "!is_empty(access_request.spec.roles)",
Notification: &accessmonitoringrulesv1.Notification{
Name: "slack",
Recipients: []string{
s.reviewer1SlackUser.ID,
s.reviewer2SlackUser.Profile.Email,
},
},
},
})
assert.NoError(t, err)

messages = []slack.Message{}
messageSet = make(SlackDataMessageSet)

// Test execution: we create an access request
request = s.CreateAccessRequest(ctx, userName, nil)
pluginData = s.checkPluginData(ctx, request.GetName(), func(data accessrequest.PluginData) bool {
return len(data.SentMessages) > 0
})
assert.Len(t, pluginData.SentMessages, numMessagesFinal)

// Validate we got 2 messages since the base config should kick back in
for i := 0; i < numMessagesFinal; i++ {
msg, err := s.fakeSlack.CheckNewMessage(ctx)
require.NoError(t, err)
messageSet.Add(accessrequest.MessageData{ChannelID: msg.Channel, MessageID: msg.Timestamp})
messages = append(messages, msg)
}

assert.Len(t, messageSet, numMessagesFinal)
for i := numMessagesInitial - 1; i < numMessagesFinal; i++ {
assert.Contains(t, messageSet, pluginData.SentMessages[i])
}

// Validate the message recipients
sort.Sort(SlackMessageSlice(messages))
assert.Equal(t, s.requesterOSSSlackUser.ID, messages[0].Channel)
assert.Equal(t, s.reviewer2SlackUser.ID, messages[1].Channel)

assert.NoError(t, s.ClientByName(integration.RulerUserName).
AccessMonitoringRulesClient().DeleteAccessMonitoringRule(ctx, "test-slack-amr-2"))
}

// TestApproval tests that when a request is approved, its corresponding message
Expand Down