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
12 changes: 6 additions & 6 deletions internal/generator/vector/api/sinks/prometheus_export.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ type PrometheusExporterAuth struct {
}

type PrometheusExporter struct {
Type types.SinkType `json:"type,omitempty" yaml:"type,omitempty" toml:"type,omitempty"`
Inputs []string `json:"inputs,omitempty" yaml:"inputs,omitempty" toml:"inputs,omitempty"`
Address string `json:"address,omitempty" yaml:"address,omitempty" toml:"address,omitempty"`
DefaultNamespace string `json:"default_namespace,omitempty" yaml:"default_namespace,omitempty" toml:"default_namespace,omitempty"`
TLS *transport.TlsEnabled `json:"tls,omitempty" yaml:"tls,omitempty" toml:"tls,omitempty"`
Auth *PrometheusExporterAuth `json:"auth,omitempty" yaml:"auth,omitempty" toml:"auth,omitempty"`
Type types.SinkType `json:"type,omitempty" yaml:"type,omitempty" toml:"type,omitempty"`
Inputs []string `json:"inputs,omitempty" yaml:"inputs,omitempty" toml:"inputs,omitempty"`
Address string `json:"address,omitempty" yaml:"address,omitempty" toml:"address,omitempty"`
DefaultNamespace string `json:"default_namespace,omitempty" yaml:"default_namespace,omitempty" toml:"default_namespace,omitempty"`
TLS *transport.TlsEnabled `json:"tls,omitempty" yaml:"tls,omitempty" toml:"tls,omitempty"`
Auth *PrometheusExporterAuth `json:"auth,omitempty" yaml:"auth,omitempty" toml:"auth,omitempty"`
}

func (p PrometheusExporter) SinkType() types.SinkType {
Expand Down
78 changes: 78 additions & 0 deletions internal/generator/vector/filter/apiaudit/filter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package apiaudit

import (
"strings"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
obs "github.com/openshift/cluster-logging-operator/api/observability/v1"
auditv1 "k8s.io/apiserver/pkg/apis/audit/v1"
)

var _ = Describe("KubeAPIAudit filter VRL generation", func() {
Context("when OmitManagedFields is set", func() {
It("should generate VRL code to delete managedFields when set to true", func() {
omitTrue := true
spec := &obs.KubeAPIAudit{
Rules: []auditv1.PolicyRule{
{
Level: auditv1.LevelRequestResponse,
OmitManagedFields: &omitTrue,
},
},
}
vrl, err := NewFilter(spec).VRL()
Expect(err).NotTo(HaveOccurred())
Expect(vrl).To(ContainSubstring("omit_managed = true"))
Expect(vrl).To(ContainSubstring("del(.requestObject.metadata.managedFields)"))
Expect(vrl).To(ContainSubstring("del(.responseObject.metadata.managedFields)"))
})

It("should generate VRL code to not delete managedFields when set to false", func() {
omitFalse := false
spec := &obs.KubeAPIAudit{
Rules: []auditv1.PolicyRule{
{
Level: auditv1.LevelRequestResponse,
OmitManagedFields: &omitFalse,
},
},
}
vrl, err := NewFilter(spec).VRL()
Expect(err).NotTo(HaveOccurred())
Expect(vrl).To(ContainSubstring("omit_managed = false"))
Expect(vrl).To(ContainSubstring("del(.requestObject.metadata.managedFields)"))
Expect(vrl).To(ContainSubstring("del(.responseObject.metadata.managedFields)"))
})

It("should initialize omit_managed to false when not configured", func() {
spec := &obs.KubeAPIAudit{
Rules: []auditv1.PolicyRule{
{
Level: auditv1.LevelRequestResponse,
// OmitManagedFields not set (nil)
},
},
}
vrl, err := NewFilter(spec).VRL()
Expect(err).NotTo(HaveOccurred())
// Should initialize to false
Expect(vrl).To(ContainSubstring("omit_managed = false"))
// Should not set it to true in any rule
lines := strings.Split(vrl, "\n")
falseCount := 0
for _, line := range lines {
if strings.Contains(line, "omit_managed = false") {
falseCount++
}
if strings.Contains(line, "omit_managed = true") {
Fail("Should not set omit_managed = true when not configured")
}
}
// Should only have one initialization
Expect(falseCount).To(Equal(1))
// Should still have the conditional deletion code
Expect(vrl).To(ContainSubstring("if omit_managed"))
})
})
})
10 changes: 10 additions & 0 deletions internal/generator/vector/filter/apiaudit/policy.vrl.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ if is_string(.auditID) && is_string(.verb) {
namespace = if is_null(.objectRef.namespace) { "" } else { string!(.objectRef.namespace) }
username = if is_null(.user.username) { "" } else { string!(.user.username) }
if sub != "" { res = res + "/" + sub }
omit_managed = false
{{with .OmitStages -}}
if includes({{. | json}}, .stage) { # Policy OmitStages
.level = "None"
Expand All @@ -30,6 +31,9 @@ if is_string(.auditID) && is_string(.verb) {
{{- with .OmitStages}}
if includes({{. | json}}, .stage) { .level = "None" }
{{- end}}
{{- with .OmitManagedFields}}
omit_managed = {{.}}
{{- end}}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
} else {{end -}}
{
# No rule matched, apply default rules for system events.
Expand All @@ -55,6 +59,12 @@ if is_string(.auditID) && is_string(.verb) {
} else if .level == "Request" {
del(.responseObject)
}
# Omit managed fields if requested
if omit_managed {
del(.metadata.managedFields)
del(.requestObject.metadata.managedFields)
del(.responseObject.metadata.managedFields)
}
}
}

Expand Down
248 changes: 248 additions & 0 deletions test/functional/filters/apiaudit/vrl/filter_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package apiaudit

import (
"encoding/json"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
obs "github.com/openshift/cluster-logging-operator/api/observability/v1"
"github.com/openshift/cluster-logging-operator/test"
authv1 "k8s.io/api/authentication/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
apiruntime "k8s.io/apimachinery/pkg/runtime"
. "k8s.io/apiserver/pkg/apis/audit/v1"
)

Expand Down Expand Up @@ -235,4 +238,249 @@ var _ = Describe("Policy to VRL Filter", func() {
Expect(Filtered(p, Event{Verb: "update", User: authv1.UserInfo{Username: "system:blah"}})).To(HaveLevel(LevelRequest))
})
})

Context("omit managed fields", func() {
createEventWithManagedFields := func() Event {
reqObj := &v1.PartialObjectMetadata{
ObjectMeta: v1.ObjectMeta{
Name: "test-object",
Namespace: "test-namespace",
ManagedFields: []v1.ManagedFieldsEntry{
{
Manager: "test-manager",
Operation: v1.ManagedFieldsOperationUpdate,
},
},
},
}
respObj := &v1.PartialObjectMetadata{
ObjectMeta: v1.ObjectMeta{
Name: "test-object",
Namespace: "test-namespace",
ManagedFields: []v1.ManagedFieldsEntry{
{
Manager: "test-manager",
Operation: v1.ManagedFieldsOperationUpdate,
},
},
},
}
reqJSON, _ := json.Marshal(reqObj)
respJSON, _ := json.Marshal(respObj)
Comment on lines +268 to +269
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Handle JSON errors explicitly in test helpers.

Ignoring marshal/unmarshal errors here can hide setup failures and produce less actionable test failures.

Suggested patch
-			reqJSON, _ := json.Marshal(reqObj)
-			respJSON, _ := json.Marshal(respObj)
+			reqJSON, err := json.Marshal(reqObj)
+			Expect(err).NotTo(HaveOccurred())
+			respJSON, err := json.Marshal(respObj)
+			Expect(err).NotTo(HaveOccurred())
@@
-				eventJSON, _ := json.Marshal(event)
+				eventJSON, err := json.Marshal(event)
+				Expect(err).NotTo(HaveOccurred())
@@
-				_ = json.Unmarshal(eventJSON, &eventMap)
+				err = json.Unmarshal(eventJSON, &eventMap)
+				Expect(err).NotTo(HaveOccurred())
@@
-				modifiedJSON, _ := json.Marshal(eventMap)
+				modifiedJSON, err := json.Marshal(eventMap)
+				Expect(err).NotTo(HaveOccurred())
 				return modifiedJSON

Also applies to: 370-370, 374-374, 383-383

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/functional/filters/apiaudit/vrl/filter_test.go` around lines 268 - 269,
The test currently ignores errors from json.Marshal (e.g., the reqJSON, respJSON
assignments), which can mask setup failures; update each json.Marshal call in
filter_test.go to check the returned error and fail the test immediately (use
t.Fatalf or require.NoError) when marshal fails—specifically handle the errors
for reqJSON and respJSON and the other marshal/unmarshal occurrences noted
(around the other json.Marshal/json.Unmarshal calls) so failures surface clearly
during test setup.


return Event{
Level: LevelRequestResponse,
AuditID: "test-audit-id",
Verb: "update",
User: authv1.UserInfo{Username: "test-user"},
RequestObject: &apiruntime.Unknown{Raw: reqJSON},
ResponseObject: &apiruntime.Unknown{Raw: respJSON},
}
}

It("should remove managedFields when OmitManagedFields is true", func() {
omitTrue := true
p := &obs.KubeAPIAudit{
Rules: []PolicyRule{
{
Level: LevelRequestResponse,
OmitManagedFields: &omitTrue,
},
},
}
event := createEventWithManagedFields()
filtered := Filtered(p, event)

Expect(filtered).NotTo(BeNil())
Expect(filtered.Level).To(Equal(LevelRequestResponse))

// Verify managedFields were removed from requestObject
reqMeta := &v1.PartialObjectMetadata{}
err := json.Unmarshal(filtered.RequestObject.Raw, reqMeta)
Expect(err).To(BeNil(), "Failed to unmarshal RequestObject")
Expect(reqMeta.ObjectMeta.ManagedFields).To(BeNil())

// Verify managedFields were removed from responseObject
respMeta := &v1.PartialObjectMetadata{}
err = json.Unmarshal(filtered.ResponseObject.Raw, respMeta)
Expect(err).To(BeNil(), "Failed to unmarshal ResponseObject")
Expect(respMeta.ObjectMeta.ManagedFields).To(BeNil())
})

It("should keep managedFields when OmitManagedFields is false", func() {
omitFalse := false
p := &obs.KubeAPIAudit{
Rules: []PolicyRule{
{
Level: LevelRequestResponse,
OmitManagedFields: &omitFalse,
},
},
}
event := createEventWithManagedFields()
filtered := Filtered(p, event)

Expect(filtered).NotTo(BeNil())
Expect(filtered.Level).To(Equal(LevelRequestResponse))

// Verify managedFields were kept in requestObject
reqMeta := &v1.PartialObjectMetadata{}
err := json.Unmarshal(filtered.RequestObject.Raw, reqMeta)
Expect(err).To(BeNil(), "Failed to unmarshal RequestObject")
Expect(reqMeta.ObjectMeta.ManagedFields).To(HaveLen(1))

// Verify managedFields were kept in responseObject
respMeta := &v1.PartialObjectMetadata{}
err = json.Unmarshal(filtered.ResponseObject.Raw, respMeta)
Expect(err).To(BeNil(), "Failed to unmarshal ResponseObject")
Expect(respMeta.ObjectMeta.ManagedFields).To(HaveLen(1))
})

It("should keep managedFields when OmitManagedFields is not set", func() {
p := &obs.KubeAPIAudit{
Rules: []PolicyRule{
{
Level: LevelRequestResponse,
// OmitManagedFields not set (nil)
},
},
}
event := createEventWithManagedFields()
filtered := Filtered(p, event)

Expect(filtered).NotTo(BeNil())
Expect(filtered.Level).To(Equal(LevelRequestResponse))

// Verify managedFields were kept in requestObject
reqMeta := &v1.PartialObjectMetadata{}
err := json.Unmarshal(filtered.RequestObject.Raw, reqMeta)
Expect(err).To(BeNil(), "Failed to unmarshal RequestObject")
Expect(reqMeta.ObjectMeta.ManagedFields).To(HaveLen(1))

// Verify managedFields were kept in responseObject
respMeta := &v1.PartialObjectMetadata{}
err = json.Unmarshal(filtered.ResponseObject.Raw, respMeta)
Expect(err).To(BeNil(), "Failed to unmarshal ResponseObject")
Expect(respMeta.ObjectMeta.ManagedFields).To(HaveLen(1))
Comment thread
coderabbitai[bot] marked this conversation as resolved.
})

Context("with event containing .metadata.managedFields", func() {
createEventWithRootManagedFields := func() []byte {
event := createEventWithManagedFields()
eventJSON, _ := json.Marshal(event)

// Parse as map to add root-level metadata.managedFields
var eventMap map[string]interface{}
_ = json.Unmarshal(eventJSON, &eventMap)
eventMap["metadata"] = map[string]interface{}{
"managedFields": []map[string]interface{}{
{
"manager": "root-manager",
"operation": "Update",
},
},
}
modifiedJSON, _ := json.Marshal(eventMap)
return modifiedJSON
}

It("should remove .metadata.managedFields when OmitManagedFields is true", func() {
omitTrue := true
p := &obs.KubeAPIAudit{
Rules: []PolicyRule{
{
Level: LevelRequestResponse,
OmitManagedFields: &omitTrue,
},
},
}
eventJSON := createEventWithRootManagedFields()
filteredJSON := FilteredBytes(p, eventJSON)

// Parse filtered output to verify .metadata.managedFields was removed
var filteredMap map[string]interface{}
err := json.Unmarshal(filteredJSON, &filteredMap)
Expect(err).To(BeNil(), "Failed to unmarshal filtered output")

// Verify root-level metadata.managedFields was removed
if metadata, exists := filteredMap["metadata"]; exists {
metadataMap := metadata.(map[string]interface{})
_, hasManaged := metadataMap["managedFields"]
Expect(hasManaged).To(BeFalse(), ".metadata.managedFields should be removed")
}
})

It("should keep .metadata.managedFields when OmitManagedFields is false", func() {
omitFalse := false
p := &obs.KubeAPIAudit{
Rules: []PolicyRule{
{
Level: LevelRequestResponse,
OmitManagedFields: &omitFalse,
},
},
}
eventJSON := createEventWithRootManagedFields()
filteredJSON := FilteredBytes(p, eventJSON)

// Parse filtered output to verify .metadata.managedFields was kept
var filteredMap map[string]interface{}
err := json.Unmarshal(filteredJSON, &filteredMap)
Expect(err).To(BeNil(), "Failed to unmarshal filtered output")

// Verify root-level metadata.managedFields was kept
metadata, exists := filteredMap["metadata"]
Expect(exists).To(BeTrue(), ".metadata should exist")
metadataMap := metadata.(map[string]interface{})
managedFields, hasManaged := metadataMap["managedFields"]
Expect(hasManaged).To(BeTrue(), ".metadata.managedFields should be kept")
Expect(managedFields).To(HaveLen(1))
})

It("should remove all managedFields from all locations when OmitManagedFields is true", func() {
omitTrue := true
p := &obs.KubeAPIAudit{
Rules: []PolicyRule{
{
Level: LevelRequestResponse,
OmitManagedFields: &omitTrue,
},
},
}
eventJSON := createEventWithRootManagedFields()
filteredJSON := FilteredBytes(p, eventJSON)

var filteredMap map[string]interface{}
err := json.Unmarshal(filteredJSON, &filteredMap)
Expect(err).To(BeNil(), "Failed to unmarshal filtered output")

// Verify root-level metadata.managedFields was removed
if metadata, exists := filteredMap["metadata"]; exists {
metadataMap := metadata.(map[string]interface{})
_, hasManaged := metadataMap["managedFields"]
Expect(hasManaged).To(BeFalse(), ".metadata.managedFields should be removed")
}

// Verify requestObject.metadata.managedFields was removed
if reqObj, exists := filteredMap["requestObject"]; exists {
reqMap := reqObj.(map[string]interface{})
if reqMeta, exists := reqMap["metadata"]; exists {
reqMetaMap := reqMeta.(map[string]interface{})
_, hasManaged := reqMetaMap["managedFields"]
Expect(hasManaged).To(BeFalse(), ".requestObject.metadata.managedFields should be removed")
}
}

// Verify responseObject.metadata.managedFields was removed
if respObj, exists := filteredMap["responseObject"]; exists {
respMap := respObj.(map[string]interface{})
if respMeta, exists := respMap["metadata"]; exists {
respMetaMap := respMeta.(map[string]interface{})
_, hasManaged := respMetaMap["managedFields"]
Expect(hasManaged).To(BeFalse(), ".responseObject.metadata.managedFields should be removed")
}
}
})
})
})
})