Skip to content

Commit

Permalink
Enabled Plugins Report (#1374)
Browse files Browse the repository at this point in the history
* ADD PluginsConfigReport

* FIX CR

* ADD golden file to test

* ADD more tests

* FIX CR
  • Loading branch information
madebyrogal authored Feb 9, 2024
1 parent 865191b commit 45a6cd4
Show file tree
Hide file tree
Showing 8 changed files with 272 additions and 1 deletion.
4 changes: 4 additions & 0 deletions cmd/botkube-agent/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ func run(ctx context.Context) (err error) {
if err != nil {
return reportFatalError("while registering current identity", err)
}
err = analyticsReporter.ReportPluginsEnabled(conf.Executors, conf.Sources)
if err != nil {
logger.Errorf("while reporting plugins configuration: %v", err.Error())
}

statusReporter.SetLogger(logger)
statusReporter.SetResourceVersion(cfgVersion)
Expand Down
5 changes: 5 additions & 0 deletions internal/analytics/noop_reporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ func (n NoopReporter) ReportFatalError(_ error) error {
return nil
}

// ReportPluginsEnabled reports plugins enabled.
func (n NoopReporter) ReportPluginsEnabled(_ map[string]config.Executors, _ map[string]config.Sources) error {
return nil
}

// Run runs the reporter.
func (n NoopReporter) Run(_ context.Context) error {
return nil
Expand Down
3 changes: 3 additions & 0 deletions internal/analytics/reporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ type Reporter interface {
// ReportFatalError reports a fatal app error.
ReportFatalError(err error) error

// ReportPluginsEnabled reports plugins enabled.
ReportPluginsEnabled(executors map[string]config.Executors, sources map[string]config.Sources) error

Run(ctx context.Context) error

// Close cleans up the reporter resources.
Expand Down
50 changes: 50 additions & 0 deletions internal/analytics/segment_reporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"k8s.io/client-go/kubernetes"

"github.com/kubeshop/botkube/internal/analytics/batched"
"github.com/kubeshop/botkube/internal/plugin"
"github.com/kubeshop/botkube/pkg/config"
"github.com/kubeshop/botkube/pkg/ptr"
"github.com/kubeshop/botkube/pkg/version"
Expand Down Expand Up @@ -44,6 +45,12 @@ type BatchedDataStore interface {
Reset()
}

type pluginReport struct {
Name string
Type plugin.Type
RBAC *config.PolicyRule
}

// SegmentReporter is a default Reporter implementation that uses Twilio Segment.
type SegmentReporter struct {
log logrus.FieldLogger
Expand Down Expand Up @@ -106,6 +113,18 @@ func (r *SegmentReporter) ReportBotEnabled(platform config.CommPlatformIntegrati
})
}

// ReportPluginsEnabled reports plugins enabled.
func (r *SegmentReporter) ReportPluginsEnabled(executors map[string]config.Executors, sources map[string]config.Sources) error {
pluginsConfig := make(map[string]interface{})
for _, values := range executors {
r.generatePluginsReport(pluginsConfig, values.Plugins, plugin.TypeExecutor)
}
for _, values := range sources {
r.generatePluginsReport(pluginsConfig, values.Plugins, plugin.TypeSource)
}
return r.reportEvent("Plugin enabled", pluginsConfig)
}

// ReportSinkEnabled reports an enabled sink.
// The RegisterCurrentIdentity needs to be called first.
func (r *SegmentReporter) ReportSinkEnabled(platform config.CommPlatformIntegration, commGroupIdx int) error {
Expand Down Expand Up @@ -333,3 +352,34 @@ func (r *SegmentReporter) getNodeCount(ctx context.Context, k8sCli kubernetes.In

return workerNodesCount, controlPlaneNodesCount, nil
}

func (r *SegmentReporter) generatePluginsReport(pluginsConfig map[string]interface{}, plugins config.Plugins, pluginType plugin.Type) {
for name, pluginValue := range plugins {
if !pluginValue.Enabled {
continue
}
pluginsConfig[name] = pluginReport{
Name: name,
Type: pluginType,
RBAC: r.getAnonymizedRBAC(pluginValue.Context.RBAC),
}
}
}

func (r *SegmentReporter) getAnonymizedRBAC(rbac *config.PolicyRule) *config.PolicyRule {
rbac.Group.Prefix = r.anonymizedValue(rbac.Group.Prefix)
for key, name := range rbac.Group.Static.Values {
rbac.Group.Static.Values[key] = r.anonymizedValue(name)
}

rbac.User.Prefix = r.anonymizedValue(rbac.User.Prefix)
rbac.User.Static.Value = r.anonymizedValue(rbac.User.Static.Value)
return rbac
}

func (r *SegmentReporter) anonymizedValue(value string) string {
if value == "" || value == config.RBACDefaultGroup || value == config.RBACDefaultUser {
return value
}
return "***"
}
126 changes: 126 additions & 0 deletions internal/analytics/segment_reporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,132 @@ func TestSegmentReporter_ReportBotEnabled(t *testing.T) {
compareMessagesAgainstGoldenFile(t, segmentCli.messages)
}

func TestSegmentReporter_ReportPluginsEnabled(t *testing.T) {
// given
identity := fixIdentity()
segmentReporter, segmentCli := fakeSegmentReporterWithIdentity(identity)

// when
err := segmentReporter.ReportPluginsEnabled(map[string]config.Executors{
"botkube/helm_11yy1": {
DisplayName: "helm",
Plugins: map[string]config.Plugin{
"botkube/helm": {
Enabled: true,
Config: "{}",
Context: config.PluginContext{
RBAC: &config.PolicyRule{
User: config.UserPolicySubject{
Type: config.StaticPolicySubjectType,
Static: config.UserStaticSubject{
Value: "user-name",
},
Prefix: "custom-user-prefix",
},
Group: config.GroupPolicySubject{
Type: config.StaticPolicySubjectType,
Static: config.GroupStaticSubject{
Values: []string{
config.RBACDefaultGroup,
"custom-group-name",
},
},
Prefix: "custom-group-prefix",
},
},
},
},
},
},
"botkube/kubectl_44yy4": {
DisplayName: "kubectl",
Plugins: map[string]config.Plugin{
"botkube/kubectl": {
Enabled: true,
Config: "{}",
Context: config.PluginContext{
RBAC: &config.PolicyRule{
User: config.UserPolicySubject{
Type: config.StaticPolicySubjectType,
Static: config.UserStaticSubject{
Value: "user-name",
},
Prefix: "custom-user-prefix",
},
Group: config.GroupPolicySubject{
Type: config.ChannelNamePolicySubjectType,
Static: config.GroupStaticSubject{
Values: []string{},
},
Prefix: "custom-channel-prefix",
},
},
},
},
},
},
}, map[string]config.Sources{
"botkube/kubernetes_22yy2": {
DisplayName: "k8s",
Plugins: map[string]config.Plugin{
"botkube/kubernetes": {
Enabled: true,
Config: "{}",
Context: config.PluginContext{
RBAC: &config.PolicyRule{
User: config.UserPolicySubject{
Type: config.StaticPolicySubjectType,
Static: config.UserStaticSubject{
Value: config.RBACDefaultUser,
},
},
Group: config.GroupPolicySubject{
Type: config.StaticPolicySubjectType,
Static: config.GroupStaticSubject{
Values: []string{
config.RBACDefaultGroup,
},
},
},
},
},
},
},
},
"botkube/keptn_33yy3": {
DisplayName: "keptn",
Plugins: map[string]config.Plugin{
"botkube/kubernetes": {
Enabled: false,
Config: "{}",
Context: config.PluginContext{
RBAC: &config.PolicyRule{
User: config.UserPolicySubject{
Type: config.EmptyPolicySubjectType,
Static: config.UserStaticSubject{
Value: "",
},
},
Group: config.GroupPolicySubject{
Type: config.StaticPolicySubjectType,
Static: config.GroupStaticSubject{
Values: []string{
config.RBACDefaultGroup,
},
},
},
},
},
},
},
},
})
require.NoError(t, err)

// then
compareMessagesAgainstGoldenFile(t, segmentCli.messages)
}

func TestSegmentReporter_ReportSinkEnabled(t *testing.T) {
// given
identity := fixIdentity()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
[
{
"type": "track",
"messageId": "0",
"anonymousId": "cluster-id",
"event": "Plugin enabled",
"timestamp": "2009-11-17T20:34:58.651387237Z",
"properties": {
"botkube/helm": {
"Name": "botkube/helm",
"Type": "executor",
"RBAC": {
"User": {
"Type": "Static",
"Static": {
"Value": "***"
},
"Prefix": "***"
},
"Group": {
"Type": "Static",
"Static": {
"Values": [
"botkube-plugins-default",
"***"
]
},
"Prefix": "***"
}
}
},
"botkube/kubectl": {
"Name": "botkube/kubectl",
"Type": "executor",
"RBAC": {
"User": {
"Type": "Static",
"Static": {
"Value": "***"
},
"Prefix": "***"
},
"Group": {
"Type": "ChannelName",
"Static": {
"Values": []
},
"Prefix": "***"
}
}
},
"botkube/kubernetes": {
"Name": "botkube/kubernetes",
"Type": "source",
"RBAC": {
"User": {
"Type": "Static",
"Static": {
"Value": "botkube-internal-static-user"
},
"Prefix": ""
},
"Group": {
"Type": "Static",
"Static": {
"Values": [
"botkube-plugins-default"
]
},
"Prefix": ""
}
}
}
}
}
]
2 changes: 1 addition & 1 deletion internal/plugin/kubeconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func generateUserSubject(rbac config.UserPolicySubject, group config.GroupPolicy
user = rbac.Prefix + input.Channel
default:
if group.Type != config.EmptyPolicySubjectType {
user = "botkube-internal-static-user"
user = config.RBACDefaultUser
}
}
return
Expand Down
7 changes: 7 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ const (
allValuesPattern = ".*"
)

const (
// RBACDefaultGroup describes default rbac group name.
RBACDefaultGroup = "botkube-plugins-default"
// RBACDefaultUser describes default rbac user name.
RBACDefaultUser = "botkube-internal-static-user"
)

// EventType to watch
type EventType string

Expand Down

0 comments on commit 45a6cd4

Please sign in to comment.