diff --git a/api/observability/v1/filter_types.go b/api/observability/v1/filter_types.go index eb93e646fd..035abbdfff 100644 --- a/api/observability/v1/filter_types.go +++ b/api/observability/v1/filter_types.go @@ -119,6 +119,7 @@ type DropCondition struct { // Must define only one of matches OR notMatches // // +kubebuilder:validation:Optional + // +kubebuilder:validation:Pattern:=`^[^'\n\r]*$` // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Drop Match Expression" Matches string `json:"matches,omitempty"` @@ -127,6 +128,7 @@ type DropCondition struct { // Must define only one of matches or notMatches // // +kubebuilder:validation:Optional + // +kubebuilder:validation:Pattern:=`^[^'\n\r]*$` // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Keep Match Expression" NotMatches string `json:"notMatches,omitempty"` } diff --git a/bundle/manifests/observability.openshift.io_clusterlogforwarders.yaml b/bundle/manifests/observability.openshift.io_clusterlogforwarders.yaml index 3cd225f12d..3f4f5c35f1 100644 --- a/bundle/manifests/observability.openshift.io_clusterlogforwarders.yaml +++ b/bundle/manifests/observability.openshift.io_clusterlogforwarders.yaml @@ -1115,12 +1115,14 @@ spec: A regular expression that the field will match. If the value of the field defined in the DropTest matches the regular expression, the log record will be dropped. Must define only one of matches OR notMatches + pattern: ^[^'\n\r]*$ type: string notMatches: description: |- A regular expression that the field does not match. If the value of the field defined in the DropTest does not match the regular expression, the log record will be dropped. Must define only one of matches or notMatches + pattern: ^[^'\n\r]*$ type: string type: object x-kubernetes-validations: diff --git a/config/crd/bases/observability.openshift.io_clusterlogforwarders.yaml b/config/crd/bases/observability.openshift.io_clusterlogforwarders.yaml index fcdf4f6c95..3fe192785d 100644 --- a/config/crd/bases/observability.openshift.io_clusterlogforwarders.yaml +++ b/config/crd/bases/observability.openshift.io_clusterlogforwarders.yaml @@ -1115,12 +1115,14 @@ spec: A regular expression that the field will match. If the value of the field defined in the DropTest matches the regular expression, the log record will be dropped. Must define only one of matches OR notMatches + pattern: ^[^'\n\r]*$ type: string notMatches: description: |- A regular expression that the field does not match. If the value of the field defined in the DropTest does not match the regular expression, the log record will be dropped. Must define only one of matches or notMatches + pattern: ^[^'\n\r]*$ type: string type: object x-kubernetes-validations: diff --git a/docs/reference/datamodels/viaq/v1.adoc b/docs/reference/datamodels/viaq/v1.adoc index 638e99f982..e131c52b2f 100644 --- a/docs/reference/datamodels/viaq/v1.adoc +++ b/docs/reference/datamodels/viaq/v1.adoc @@ -518,7 +518,7 @@ Type:: object |labels |object a| *(optional)* Labels is a set of common, static labels that were spec'd for log forwarding to be sent with the log Records |sequence -|string a| Sequence is increasing id used in conjunction with the timestamp to establish a linear timeline of log records. This was added as a workaround for logstores that do not have nano-second precision. +|string a| Sequence is an increasing ID used in conjunction with the timestamp to establish a linear timeline of log records. This was added as a workaround for logstores that do not have nano-second precision. |====================== ==== .openshift.cluster_id @@ -536,7 +536,7 @@ Type:: object ==== .openshift.sequence -Sequence is increasing id used in conjunction with the timestamp to establish a linear timeline +Sequence is an increasing ID used in conjunction with the timestamp to establish a linear timeline of log records. This was added as a workaround for logstores that do not have nano-second precision. Type:: string @@ -916,7 +916,7 @@ Type:: object |labels |object a| *(optional)* Labels is a set of common, static labels that were spec'd for log forwarding to be sent with the log Records |sequence -|string a| Sequence is increasing id used in conjunction with the timestamp to establish a linear timeline of log records. This was added as a workaround for logstores that do not have nano-second precision. +|string a| Sequence is an increasing ID used in conjunction with the timestamp to establish a linear timeline of log records. This was added as a workaround for logstores that do not have nano-second precision. |====================== ==== .openshift.cluster_id @@ -934,7 +934,7 @@ Type:: object ==== .openshift.sequence -Sequence is increasing id used in conjunction with the timestamp to establish a linear timeline +Sequence is an increasing ID used in conjunction with the timestamp to establish a linear timeline of log records. This was added as a workaround for logstores that do not have nano-second precision. Type:: string @@ -1476,7 +1476,7 @@ Type:: object |labels |object a| *(optional)* Labels is a set of common, static labels that were spec'd for log forwarding to be sent with the log Records |sequence -|string a| Sequence is increasing id used in conjunction with the timestamp to establish a linear timeline of log records. This was added as a workaround for logstores that do not have nano-second precision. +|string a| Sequence is an increasing ID used in conjunction with the timestamp to establish a linear timeline of log records. This was added as a workaround for logstores that do not have nano-second precision. |====================== ==== .openshift.cluster_id @@ -1494,7 +1494,7 @@ Type:: object ==== .openshift.sequence -Sequence is increasing id used in conjunction with the timestamp to establish a linear timeline +Sequence is an increasing ID used in conjunction with the timestamp to establish a linear timeline of log records. This was added as a workaround for logstores that do not have nano-second precision. Type:: string @@ -2325,7 +2325,7 @@ Type:: object |labels |object a| *(optional)* Labels is a set of common, static labels that were spec'd for log forwarding to be sent with the log Records |sequence -|string a| Sequence is increasing id used in conjunction with the timestamp to establish a linear timeline of log records. This was added as a workaround for logstores that do not have nano-second precision. +|string a| Sequence is an increasing ID used in conjunction with the timestamp to establish a linear timeline of log records. This was added as a workaround for logstores that do not have nano-second precision. |====================== ==== .openshift.cluster_id @@ -2343,7 +2343,7 @@ Type:: object ==== .openshift.sequence -Sequence is increasing id used in conjunction with the timestamp to establish a linear timeline +Sequence is an increasing ID used in conjunction with the timestamp to establish a linear timeline of log records. This was added as a workaround for logstores that do not have nano-second precision. Type:: string diff --git a/internal/generator/forwarder/generator.go b/internal/generator/forwarder/generator.go index 816af12fca..72411b1a72 100644 --- a/internal/generator/forwarder/generator.go +++ b/internal/generator/forwarder/generator.go @@ -13,7 +13,7 @@ import ( ) type ConfigGenerator struct { - conf func(secrets map[string]*corev1.Secret, clfspec obs.ClusterLogForwarderSpec, namespace, forwarderName string, resNames factory.ForwarderResourceNames, op utils.Options) *api.Config + conf func(secrets map[string]*corev1.Secret, clfspec obs.ClusterLogForwarderSpec, namespace, forwarderName string, resNames factory.ForwarderResourceNames, op utils.Options) (*api.Config, error) } func New() *ConfigGenerator { @@ -24,6 +24,9 @@ func New() *ConfigGenerator { } func (cg *ConfigGenerator) GenerateConf(secrets map[string]*corev1.Secret, clfspec obs.ClusterLogForwarderSpec, namespace, forwarderName string, resNames factory.ForwarderResourceNames, op framework.Options) (string, error) { - config := cg.conf(secrets, clfspec, namespace, forwarderName, resNames, op) + config, err := cg.conf(secrets, clfspec, namespace, forwarderName, resNames, op) + if err != nil { + return "", err + } return toml.Marshal(config) } diff --git a/internal/generator/vector/adapters/pipeline.go b/internal/generator/vector/adapters/pipeline.go index 77ba9f0e52..55250e6d57 100644 --- a/internal/generator/vector/adapters/pipeline.go +++ b/internal/generator/vector/adapters/pipeline.go @@ -1,6 +1,7 @@ package adapters import ( + "fmt" "os" "strconv" @@ -23,12 +24,16 @@ type Pipeline struct { } // Transforms creates instances of transforms based upon the pipeline spec -func (p *Pipeline) Transforms() (tfs api.Transforms) { - tfs = api.Transforms{} +func (p *Pipeline) Transforms() (api.Transforms, error) { + tfs := api.Transforms{} for _, pf := range p.Filters { - tfs.Add(pf.ID(), pf.Transform()) + tf := pf.Transform() + if tf == nil { + return nil, fmt.Errorf("filter %q produced nil transform for pipeline %q", pf.ID(), p.Name()) + } + tfs.Add(pf.ID(), tf) } - return tfs + return tfs, nil } func NewPipeline(index int, p obs.PipelineSpec, inputs map[string]helpers.InputComponent, outputs map[string]*Output, filters map[string]*InternalFilterSpec, inputSpecs []obs.InputSpec, addPostFilters func(p *Pipeline)) *Pipeline { diff --git a/internal/generator/vector/adapters/pipeline_test.go b/internal/generator/vector/adapters/pipeline_test.go index c3d199f3ed..24de215122 100644 --- a/internal/generator/vector/adapters/pipeline_test.go +++ b/internal/generator/vector/adapters/pipeline_test.go @@ -80,15 +80,49 @@ var _ = Describe("Pipeline adapters", func() { }, ) Expect(adapter.Filters).To(HaveLen(2), "expected the filter and post-filter to be added to the pipeline") + tfs, err := adapter.Transforms() + Expect(err).ToNot(HaveOccurred()) Expect(api.Transforms{ "pipeline_mypipeline_dropfilter_0": transforms.NewRemap("fakeElementVRL", "input_app_in_container_meta"), "pipeline_mypipeline_fakefilter_1": transforms.NewRemap("updatedFromAddPostfilter: mypipeline", "pipeline_mypipeline_dropfilter_0"), - }).To(Equal(adapter.Transforms())) + }).To(Equal(tfs)) Expect(outputMap["referenced"].Inputs()).To(Equal([]string{"pipeline_mypipeline_fakefilter_1"})) Expect(outputMap["notReferenced"].Inputs()).To(BeNil(), "Exp. the unreferenced output to not have the filter as an input") }) }) + Describe("#Transforms with nil-returning factory", func() { + It("should return an error when a filter factory produces a nil transform", func() { + nilFilterMap := map[string]*adapters.InternalFilterSpec{ + "nilFilter": { + FilterSpec: &obs.FilterSpec{ + Name: "nilFilter", + Type: obs.FilterTypeDrop, + }, + Factory: func(inputs ...string) types.Transform { + return nil + }, + }, + } + adapter := adapters.NewPipeline(0, obs.PipelineSpec{ + Name: "mypipeline", + InputRefs: []string{"app-in"}, + FilterRefs: []string{"nilFilter"}, + OutputRefs: []string{"referenced"}, + }, inputMap, + outputMap, + nilFilterMap, + inputSpecs, + func(p *adapters.Pipeline) {}, + ) + Expect(adapter.Filters).To(HaveLen(1)) + _, err := adapter.Transforms() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("nil transform")) + Expect(err.Error()).To(ContainSubstring("mypipeline")) + }) + }) + Describe("#NewPipelineFilter", func() { It("should add drop filter when spec'd for the pipeline", func() { @@ -104,9 +138,11 @@ var _ = Describe("Pipeline adapters", func() { func(p *adapters.Pipeline) {}, ) Expect(adapter.Filters).To(HaveLen(1), "") + tfs, err := adapter.Transforms() + Expect(err).ToNot(HaveOccurred()) Expect(api.Transforms{ "pipeline_mypipeline_dropfilter_0": transforms.NewRemap("fakeElementVRL", "input_app_in_container_meta"), - }).To(Equal(adapter.Transforms())) + }).To(Equal(tfs)) Expect(outputMap["referenced"].Inputs()).To(Equal([]string{"pipeline_mypipeline_dropfilter_0"})) Expect(outputMap["notReferenced"].Inputs()).To(BeNil(), "Exp. the unreferenced output to not have the filter as an input") diff --git a/internal/generator/vector/conf/conf.go b/internal/generator/vector/conf/conf.go index bbf8c31f79..9e146efb60 100644 --- a/internal/generator/vector/conf/conf.go +++ b/internal/generator/vector/conf/conf.go @@ -1,6 +1,7 @@ package conf import ( + "fmt" "sort" obs "github.com/openshift/cluster-logging-operator/api/observability/v1" @@ -64,7 +65,7 @@ const ( output_mykafka_dedot */ //nolint:govet // using declarative style -func Conf(secrets map[string]*corev1.Secret, clfspec obs.ClusterLogForwarderSpec, namespace, forwarderName string, resNames factory.ForwarderResourceNames, op utils.Options) (config *api.Config) { +func Conf(secrets map[string]*corev1.Secret, clfspec obs.ClusterLogForwarderSpec, namespace, forwarderName string, resNames factory.ForwarderResourceNames, op utils.Options) (*api.Config, error) { op[helpers.CLFSpec] = internalobs.ClusterLogForwarderSpec(clfspec) // Init inputs, outputs, pipelines @@ -90,7 +91,7 @@ func Conf(secrets map[string]*corev1.Secret, clfspec obs.ClusterLogForwarderSpec pipelineMap[p.Name] = a } - config = api.NewConfig(func(c *api.Config) { + config := api.NewConfig(func(c *api.Config) { Global(c, namespace, forwarderName) c.Sources[InternalMetricsSourceName] = sources.NewInternalMetrics() }) @@ -100,7 +101,11 @@ func Conf(secrets map[string]*corev1.Secret, clfspec obs.ClusterLogForwarderSpec config.AddTransforms(transforms) } for _, p := range sortAdapters(pipelineMap) { - config.AddTransforms(p.Transforms()) + transforms, err := p.Transforms() + if err != nil { + return nil, fmt.Errorf("generating pipeline transforms: %w", err) + } + config.AddTransforms(transforms) } for _, o := range sortAdapters(outputMap) { sinks, transforms := output.New(o, o.InputIDs, secrets, op) @@ -109,7 +114,7 @@ func Conf(secrets map[string]*corev1.Secret, clfspec obs.ClusterLogForwarderSpec } config.Transforms[metrics.AddNodenameToMetricTransformName] = metrics.AddNodeNameToMetric([]string{InternalMetricsSourceName}) config.Sinks[metrics.PrometheusOutputSinkName] = metrics.PrometheusOutput([]string{metrics.AddNodenameToMetricTransformName}, op) - return config + return config, nil } // sortAdapters sorts ClusterLogForwarder adapters to ensure consistent generation of component configs diff --git a/internal/generator/vector/conf/conf_test.go b/internal/generator/vector/conf/conf_test.go index c1862a914b..56bb6f2ac5 100644 --- a/internal/generator/vector/conf/conf_test.go +++ b/internal/generator/vector/conf/conf_test.go @@ -61,7 +61,8 @@ var _ = Describe("Testing Complete Config Generation", func() { if op == nil { op = clusterOptions } - conf := Conf(secrets, spec, constants.OpenshiftNS, "my-forwarder", factory.ForwarderResourceNames{CommonName: constants.CollectorName}, op) + conf, err := Conf(secrets, spec, constants.OpenshiftNS, "my-forwarder", factory.ForwarderResourceNames{CommonName: constants.CollectorName}, op) + Expect(err).ToNot(HaveOccurred()) Expect(exp).To(EqualConfigFrom(conf)) }, Entry("with complex spec", diff --git a/internal/generator/vector/filter/drop/filter.go b/internal/generator/vector/filter/drop/filter.go index e1673367fa..649dd1178c 100644 --- a/internal/generator/vector/filter/drop/filter.go +++ b/internal/generator/vector/filter/drop/filter.go @@ -5,6 +5,7 @@ import ( "strings" log "github.com/ViaQ/logerr/v2/log/static" + obs "github.com/openshift/cluster-logging-operator/api/observability/v1" "github.com/openshift/cluster-logging-operator/internal/generator/vector/api/transforms" "github.com/openshift/cluster-logging-operator/internal/generator/vector/api/types" @@ -29,17 +30,34 @@ func New(spec []obs.DropTest, inputs ...string) types.Transform { return transforms.NewFilter(vrl, inputs...) } +func buildMatchCondition(field, pattern string, negate bool) (string, error) { + if strings.ContainsAny(pattern, "'\n\r") { + return "", fmt.Errorf("match pattern must not contain single quotes, newlines, or carriage returns: %q", pattern) + } + prefix := "" + if negate { + prefix = "!" + } + return fmt.Sprintf(`%smatch(to_string(%s) ?? "", r'%s')`, prefix, field, pattern), nil +} + func (f *Filter) VRL() (string, error) { vrlTests := []string{} for _, test := range f.tests { condList := []string{} for _, cond := range test.DropConditions { field := fmt.Sprintf("._internal%s", cond.Field) + var matchExpr string + var err error if cond.Matches != "" { - condList = append(condList, fmt.Sprintf(`match(to_string(%s) ?? "", r'%s')`, field, cond.Matches)) + matchExpr, err = buildMatchCondition(field, cond.Matches, false) } else { - condList = append(condList, fmt.Sprintf(`!match(to_string(%s) ?? "", r'%s')`, field, cond.NotMatches)) + matchExpr, err = buildMatchCondition(field, cond.NotMatches, true) + } + if err != nil { + return "", err } + condList = append(condList, matchExpr) } // Concatenate the conditions with ANDs and add Vector's error coalescing. // If any errors arise from the match such as, `cond.Field` not being a string or a field diff --git a/internal/generator/vector/filter/drop/filter_test.go b/internal/generator/vector/filter/drop/filter_test.go index ca8405b9a8..350de68fdc 100644 --- a/internal/generator/vector/filter/drop/filter_test.go +++ b/internal/generator/vector/filter/drop/filter_test.go @@ -10,6 +10,38 @@ import ( var _ = Describe("drop filter", func() { Context("#VRL", func() { + It("should reject matches containing single quotes", func() { + spec := []obs.DropTest{ + { + DropConditions: []obs.DropCondition{ + { + Field: ".kubernetes.namespace_name", + Matches: "foo'bar", + }, + }, + }, + } + _, err := NewFilter(spec).VRL() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("single quotes")) + }) + + It("should reject notMatches containing single quotes", func() { + spec := []obs.DropTest{ + { + DropConditions: []obs.DropCondition{ + { + Field: ".kubernetes.namespace_name", + NotMatches: "x'''[sources.evil]", + }, + }, + }, + } + _, err := NewFilter(spec).VRL() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("single quotes")) + }) + It("should generate valid VRL for dropping", func() { spec := []obs.DropTest{ { diff --git a/internal/pkg/generator/forwarder/generator.go b/internal/pkg/generator/forwarder/generator.go index e5b8ca8208..6b4770cc67 100644 --- a/internal/pkg/generator/forwarder/generator.go +++ b/internal/pkg/generator/forwarder/generator.go @@ -6,11 +6,14 @@ import ( obs "github.com/openshift/cluster-logging-operator/api/observability/v1" "github.com/openshift/cluster-logging-operator/internal/api/initialize" + internalobs "github.com/openshift/cluster-logging-operator/internal/api/observability" "github.com/openshift/cluster-logging-operator/internal/factory" forwardergenerator "github.com/openshift/cluster-logging-operator/internal/generator/forwarder" "github.com/openshift/cluster-logging-operator/internal/generator/framework" "github.com/openshift/cluster-logging-operator/internal/utils" + filtervalidation "github.com/openshift/cluster-logging-operator/internal/validations/observability/filters" corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/yaml" log "github.com/ViaQ/logerr/v2/log/static" @@ -43,6 +46,19 @@ func Generate(clfYaml string, debugOutput bool, client client.Client) (string, e //} forwarder = initialize.ClusterLogForwarder(forwarder, utils.NoOptions) log.V(3).Info("Initialized ClusterLogForwarder", "cr", forwarder) + + filterMap := internalobs.FilterMap(forwarder.Spec) + var filterErrors []error + for _, filter := range filterMap { + cond := filtervalidation.ValidateFilter(*filter) + if cond.Status == metav1.ConditionFalse { + filterErrors = append(filterErrors, errors.New(cond.Message)) + } + } + if len(filterErrors) > 0 { + return "", fmt.Errorf("invalid filter spec: %w", errors.Join(filterErrors...)) + } + // TODO: enable secrets //secrets := internalobs.FetchSecrets(forwarder.Spec.Outputs, client) secrets := map[string]*corev1.Secret{} diff --git a/internal/validations/observability/filters/validate_filters.go b/internal/validations/observability/filters/validate_filters.go index d372b5bb79..e9b80116eb 100644 --- a/internal/validations/observability/filters/validate_filters.go +++ b/internal/validations/observability/filters/validate_filters.go @@ -2,12 +2,13 @@ package filters import ( "fmt" + "regexp" + "strings" + obs "github.com/openshift/cluster-logging-operator/api/observability/v1" internalobs "github.com/openshift/cluster-logging-operator/internal/api/observability" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/set" - "regexp" - "strings" ) var ( @@ -54,11 +55,14 @@ func validateDropFilter(filterSpec obs.FilterSpec) (results []string) { if testCondition.Matches != "" && testCondition.NotMatches != "" { testErrors = append(testErrors, "only one of matches or notMatches can be defined at once") } + if strings.ContainsAny(testCondition.Matches, "'\n\r") || strings.ContainsAny(testCondition.NotMatches, "'\n\r") { + testErrors = append(testErrors, "matches/notMatches must not contain single quotes, newlines, or carriage returns") + } // Validate provided regex if testCondition.Matches != "" { _, err = regexp.Compile(testCondition.Matches) } else if testCondition.NotMatches != "" { - _, err = regexp.Compile(testCondition.Matches) + _, err = regexp.Compile(testCondition.NotMatches) } if err != nil { testErrors = append(testErrors, "matches/notMatches must be a valid regular expression.") diff --git a/internal/validations/observability/filters/validate_filters_test.go b/internal/validations/observability/filters/validate_filters_test.go index 8011f11636..b9949dcbc2 100644 --- a/internal/validations/observability/filters/validate_filters_test.go +++ b/internal/validations/observability/filters/validate_filters_test.go @@ -95,6 +95,45 @@ var _ = Describe("[internal][validations][observability][filters]", func() { }, "[matches/notMatches must be a valid regular expression.]", ), + Entry("should fail validation if notMatches contains an invalid regular expression", + []obs.DropTest{ + { + DropConditions: []obs.DropCondition{ + { + Field: ".kubernetes.namespace_name", + NotMatches: "[invalid", + }, + }, + }, + }, + "[matches/notMatches must be a valid regular expression.]", + ), + Entry("should fail validation if matches contains a single quote", + []obs.DropTest{ + { + DropConditions: []obs.DropCondition{ + { + Field: ".kubernetes.namespace_name", + Matches: "foo'bar", + }, + }, + }, + }, + "[matches/notMatches must not contain single quotes, newlines, or carriage returns]", + ), + Entry("should fail validation if notMatches contains a single quote", + []obs.DropTest{ + { + DropConditions: []obs.DropCondition{ + { + Field: ".kubernetes.namespace_name", + NotMatches: "x'''[sources.evil]", + }, + }, + }, + }, + "[matches/notMatches must not contain single quotes, newlines, or carriage returns]", + ), ) DescribeTable("valid drop filter spec", func(dropTests []obs.DropTest) { diff --git a/test/e2e/collection/apivalidations/api_validations_test.go b/test/e2e/collection/apivalidations/api_validations_test.go index 8d6e3f8c7a..b6dbf8cc02 100644 --- a/test/e2e/collection/apivalidations/api_validations_test.go +++ b/test/e2e/collection/apivalidations/api_validations_test.go @@ -156,5 +156,16 @@ var _ = Describe("", func() { Expect(err).To(HaveOccurred()) Expect(err.Error()).To(MatchRegexp("sourceType can only be set when payloadKey is defined")) }), + Entry("should pass for drop filter with valid matches", "drop-filter-valid.yaml", func(out string, err error) { + Expect(err).ToNot(HaveOccurred()) + }), + Entry("should fail for drop filter with single quote in matches", "drop-filter-single-quote-matches.yaml", func(out string, err error) { + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("Invalid value")) + }), + Entry("should fail for drop filter with single quote in notMatches", "drop-filter-single-quote-notmatches.yaml", func(out string, err error) { + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("Invalid value")) + }), ) }) diff --git a/test/e2e/collection/apivalidations/drop-filter-single-quote-matches.yaml b/test/e2e/collection/apivalidations/drop-filter-single-quote-matches.yaml new file mode 100644 index 0000000000..83ce3beb24 --- /dev/null +++ b/test/e2e/collection/apivalidations/drop-filter-single-quote-matches.yaml @@ -0,0 +1,35 @@ +apiVersion: observability.openshift.io/v1 +kind: ClusterLogForwarder +metadata: + name: clf-validation-test +spec: + filters: + - name: my-drop-filter + type: drop + drop: + - test: + - field: .kubernetes.namespace_name + matches: "foo'bar" + managementState: Managed + outputs: + - name: splunk-aosqe + splunk: + authentication: + token: + key: hecToken + secretName: to-splunk-secret-54980 + index: main + tuning: + compression: none + url: http://to-nowhere.svc:8088 + type: splunk + pipelines: + - filterRefs: + - my-drop-filter + inputRefs: + - application + name: forward-log-splunk + outputRefs: + - splunk-aosqe + serviceAccount: + name: clf-validation-test diff --git a/test/e2e/collection/apivalidations/drop-filter-single-quote-notmatches.yaml b/test/e2e/collection/apivalidations/drop-filter-single-quote-notmatches.yaml new file mode 100644 index 0000000000..8dde61bcb3 --- /dev/null +++ b/test/e2e/collection/apivalidations/drop-filter-single-quote-notmatches.yaml @@ -0,0 +1,35 @@ +apiVersion: observability.openshift.io/v1 +kind: ClusterLogForwarder +metadata: + name: clf-validation-test +spec: + filters: + - name: my-drop-filter + type: drop + drop: + - test: + - field: .kubernetes.namespace_name + notMatches: "x'''[sources.evil]" + managementState: Managed + outputs: + - name: splunk-aosqe + splunk: + authentication: + token: + key: hecToken + secretName: to-splunk-secret-54980 + index: main + tuning: + compression: none + url: http://to-nowhere.svc:8088 + type: splunk + pipelines: + - filterRefs: + - my-drop-filter + inputRefs: + - application + name: forward-log-splunk + outputRefs: + - splunk-aosqe + serviceAccount: + name: clf-validation-test diff --git a/test/e2e/collection/apivalidations/drop-filter-valid.yaml b/test/e2e/collection/apivalidations/drop-filter-valid.yaml new file mode 100644 index 0000000000..6b1b2980ad --- /dev/null +++ b/test/e2e/collection/apivalidations/drop-filter-valid.yaml @@ -0,0 +1,35 @@ +apiVersion: observability.openshift.io/v1 +kind: ClusterLogForwarder +metadata: + name: clf-validation-test +spec: + filters: + - name: my-drop-filter + type: drop + drop: + - test: + - field: .kubernetes.namespace_name + matches: busybox + managementState: Managed + outputs: + - name: splunk-aosqe + splunk: + authentication: + token: + key: hecToken + secretName: to-splunk-secret-54980 + index: main + tuning: + compression: none + url: http://to-nowhere.svc:8088 + type: splunk + pipelines: + - filterRefs: + - my-drop-filter + inputRefs: + - application + name: forward-log-splunk + outputRefs: + - splunk-aosqe + serviceAccount: + name: clf-validation-test diff --git a/test/functional/filters/prune/prune_filter_test.go b/test/functional/filters/prune/prune_filter_test.go index 5788066573..fac122becf 100644 --- a/test/functional/filters/prune/prune_filter_test.go +++ b/test/functional/filters/prune/prune_filter_test.go @@ -186,6 +186,7 @@ var _ = Describe("[Functional][Filters][Prune] Prune filter", func() { ".log_type", ".log_source", ".k8s_audit_level", + ".message", }, } }).ToHttpOutput() diff --git a/test/helpers/types/types.go b/test/helpers/types/types.go index f55e70f76d..8c91da6a28 100644 --- a/test/helpers/types/types.go +++ b/test/helpers/types/types.go @@ -165,7 +165,7 @@ type OpenshiftMeta struct { //+optional Labels map[string]string `json:"labels,omitempty"` - //Sequence is increasing id used in conjunction with the timestamp to establish a linear timeline + //Sequence is an increasing ID used in conjunction with the timestamp to establish a linear timeline //of log records. This was added as a workaround for logstores that do not have nano-second precision. Sequence OptionalInt `json:"sequence,omitempty"` }