Skip to content

Commit

Permalink
Merge pull request #110 from weaveworks/dev
Browse files Browse the repository at this point in the history
Reference flux objects in violations events instead of the original resource object
  • Loading branch information
Ahmed El-Sayed authored Oct 10, 2022
2 parents cedd4ab + 9ddde49 commit 2de8aad
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 45 deletions.
4 changes: 2 additions & 2 deletions helm/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
apiVersion: v2
appVersion: "1.2.0"
appVersion: "1.2.1"
description: A Helm chart for Kubernetes to configure the policy agent
name: policy-agent
version: 1.2.0
version: 1.2.1
maintainers:
- name: Weaveworks
email: [email protected]
3 changes: 2 additions & 1 deletion internal/sink/flux-notification/flux_notification.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/MagalixTechnologies/core/logger"
"github.com/MagalixTechnologies/policy-core/domain"
"github.com/weaveworks/policy-agent/internal/utils"
"k8s.io/client-go/tools/record"
)

Expand Down Expand Up @@ -65,7 +66,7 @@ func (f *FluxNotificationSink) writeWorker(ctx context.Context) error {
}

func (f *FluxNotificationSink) write(result domain.PolicyValidation) {
fluxObject := getFluxObject(result.Entity.Labels)
fluxObject := utils.GetFluxObject(result.Entity.Labels)
if fluxObject == nil {
logger.Debugw(
fmt.Sprintf("discarding %s result for orphan entity", result.Type),
Expand Down
30 changes: 0 additions & 30 deletions internal/sink/flux-notification/utils_test.go

This file was deleted.

15 changes: 15 additions & 0 deletions internal/sink/k8s-event/k8s_event.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/MagalixTechnologies/core/logger"
"github.com/MagalixTechnologies/policy-core/domain"
"github.com/weaveworks/policy-agent/internal/utils"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

Expand Down Expand Up @@ -90,6 +91,20 @@ func (k *K8sEventSink) write(ctx context.Context, result domain.PolicyValidation
)
return
}

fluxObject := utils.GetFluxObject(result.Entity.Labels)
if fluxObject != nil {
event.InvolvedObject = v1.ObjectReference{
UID: fluxObject.GetUID(),
APIVersion: fluxObject.GetAPIVersion(),
Kind: fluxObject.GetKind(),
Name: fluxObject.GetName(),
Namespace: fluxObject.GetNamespace(),
ResourceVersion: fluxObject.GetResourceVersion(),
}
event.Namespace = fluxObject.GetNamespace()
}

event.ReportingController = k.reportingController
event.ReportingInstance = k.reportingInstance
event.Source = v1.EventSource{Component: k.reportingController}
Expand Down
78 changes: 70 additions & 8 deletions internal/sink/k8s-event/k8s_event_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,41 @@ func TestK8sEventSink(t *testing.T) {
Labels: map[string]string{},
}

fluxHelmViolatingEntity := domain.Entity{
ID: uuid.NewV4().String(),
APIVersion: "v1",
Kind: "Deployment",
Name: "my-helm-violating-entity",
Namespace: "default",
Manifest: map[string]interface{}{},
ResourceVersion: "1",
Labels: map[string]string{
"helm.toolkit.fluxcd.io/name": "my-helm-app-name",
"helm.toolkit.fluxcd.io/namespace": "my-helm-app-namespace",
},
}

fluxKustomizeViolatingEntity := domain.Entity{
ID: uuid.NewV4().String(),
APIVersion: "v1",
Kind: "Deployment",
Name: "my-kustomize-violating-entity",
Namespace: "default",
Manifest: map[string]interface{}{},
ResourceVersion: "1",
Labels: map[string]string{
"kustomize.toolkit.fluxcd.io/name": "my-kustomize-app-name",
"kustomize.toolkit.fluxcd.io/namespace": "my-kustomize-app-namespace",
},
}

results := []domain.PolicyValidation{
{
ID: uuid.NewV4().String(),
Policy: policy,
Entity: violatingEntity,
Status: domain.PolicyValidationStatusViolating,
Message: "message",
Message: "violating-entity",
Type: "Admission",
Trigger: "Admission",
CreatedAt: time.Now(),
Expand All @@ -73,7 +101,27 @@ func TestK8sEventSink(t *testing.T) {
Policy: policy,
Entity: compliantEntity,
Status: domain.PolicyValidationStatusCompliant,
Message: "message",
Message: "compliant-entity",
Type: "Admission",
Trigger: "Admission",
CreatedAt: time.Now(),
},
{
ID: uuid.NewV4().String(),
Policy: policy,
Entity: fluxHelmViolatingEntity,
Status: domain.PolicyValidationStatusViolating,
Message: "flux-helm-entity",
Type: "Admission",
Trigger: "Admission",
CreatedAt: time.Now(),
},
{
ID: uuid.NewV4().String(),
Policy: policy,
Entity: fluxKustomizeViolatingEntity,
Status: domain.PolicyValidationStatusViolating,
Message: "flux-kustomize-entity",
Type: "Admission",
Trigger: "Admission",
CreatedAt: time.Now(),
Expand All @@ -93,35 +141,49 @@ func TestK8sEventSink(t *testing.T) {
t.Error(err)
}

time.Sleep(2 * time.Second)
time.Sleep(4 * time.Second)

events, err := sink.kubeClient.CoreV1().Events("").List(ctx, metav1.ListOptions{})
if err != nil {
t.Error(err)
}

assert.Equal(t, len(events.Items), 2, "did not receive expected events")
assert.Equal(t, len(events.Items), 4, "did not receive expected events")

for _, event := range events.Items {
if event.Type == v1.EventTypeWarning {
if event.Message == "violating-entity" {
assert.Equal(t, event.Reason, domain.EventReasonPolicyViolation)
assert.Equal(t, event.Action, domain.EventActionRejected)

// verify involved object holds entity info
assert.Equal(t, event.InvolvedObject.APIVersion, violatingEntity.APIVersion)
assert.Equal(t, event.InvolvedObject.Kind, violatingEntity.Kind)
assert.Equal(t, event.InvolvedObject.Name, violatingEntity.Name)
assert.Equal(t, event.InvolvedObject.Namespace, violatingEntity.Namespace)

} else if event.Type == v1.EventTypeNormal {
} else if event.Message == "compliant-entity" {
assert.Equal(t, event.Reason, domain.EventReasonPolicyCompliance)
assert.Equal(t, event.Action, domain.EventActionAllowed)

// verify involved object holds entity info
assert.Equal(t, event.InvolvedObject.APIVersion, compliantEntity.APIVersion)
assert.Equal(t, event.InvolvedObject.Kind, compliantEntity.Kind)
assert.Equal(t, event.InvolvedObject.Name, compliantEntity.Name)
assert.Equal(t, event.InvolvedObject.Namespace, compliantEntity.Namespace)
} else if event.Message == "flux-helm-entity" {
assert.Equal(t, event.Reason, domain.EventReasonPolicyViolation)
assert.Equal(t, event.Action, domain.EventActionRejected)
// verify involved object holds entity info
assert.Equal(t, event.InvolvedObject.APIVersion, "helm.toolkit.fluxcd.io")
assert.Equal(t, event.InvolvedObject.Kind, "HelmRelease")
assert.Equal(t, event.InvolvedObject.Name, "my-helm-app-name")
assert.Equal(t, event.InvolvedObject.Namespace, "my-helm-app-namespace")
} else if event.Message == "compliant-entity" {
assert.Equal(t, event.Reason, domain.EventReasonPolicyViolation)
assert.Equal(t, event.Action, domain.EventActionRejected)
// verify involved object holds entity info
assert.Equal(t, event.InvolvedObject.APIVersion, "kustomize.toolkit.fluxcd.io")
assert.Equal(t, event.InvolvedObject.Kind, "Kustomization")
assert.Equal(t, event.InvolvedObject.Name, "my-kustomize-app-name")
assert.Equal(t, event.InvolvedObject.Namespace, "my-kustomize-app-namespace")
}

// verify involved object holds entity info
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
package flux_notification
package utils

import (
"fmt"

"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
)

var fluxControllerKindMap = map[string]string{
"helm.toolkit.fluxcd.io": "HelmRelease",
"kustomize.toolkit.fluxcd.io": "Kustomization",
}

func getFluxObject(labels map[string]string) runtime.Object {
func GetFluxObject(labels map[string]string) *unstructured.Unstructured {
for apiVersion, kind := range fluxControllerKindMap {
name, ok := labels[fmt.Sprintf("%s/name", apiVersion)]
if !ok {
Expand Down
30 changes: 30 additions & 0 deletions internal/utils/utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package utils

import (
"fmt"
"testing"

"github.com/stretchr/testify/assert"
)

func TestGetFluxObject(t *testing.T) {
fluxObj := GetFluxObject(map[string]string{})

if fluxObj != nil {
t.Error("unexpected flux object")
}

for apiVersion, kind := range fluxControllerKindMap {
fluxObj := GetFluxObject(map[string]string{
fmt.Sprintf("%s/name", apiVersion): "my-app",
fmt.Sprintf("%s/namespace", apiVersion): "default",
})

assert.NotEqual(t, fluxObj, nil)

assert.Equal(t, fluxObj.GetAPIVersion(), apiVersion)
assert.Equal(t, fluxObj.GetKind(), kind)
assert.Equal(t, fluxObj.GetNamespace(), "default")
assert.Equal(t, fluxObj.GetName(), "my-app")
}
}
2 changes: 1 addition & 1 deletion version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.2.0
1.2.1

0 comments on commit 2de8aad

Please sign in to comment.