Repository: sse-secure-systems/connaisseur (go)

Issue:
Image references mutated even when mode is set to insecureValidateOnly
**Describe the bug**
<A clear and concise description of what the bug is.>
Image references in the pod definition is mutated and the digests are included even when `with.mode` is set to **insecureValidateOnly** in the policies.

Below is the extract from `connaisseur-app-config` configmap.
```
data:
  config.yaml: |
    validators:
    -
      name: default
      trustRoots:
      - key: |
          <KEY>
        name: default
      type: cosign
    policy:
    -
      pattern: '*:*'
      validator: default
      with:
        mode: insecureValidateOnly
        verifyInTransparencyLog: false
```

Logs in the Connaisseur pod
```
{
  "level": "info",
  "msg": "successfully validated image sfbrdevhelmweacr.azurecr.io/stakater/reloader:v1.0.95 using rule *:* and validator default. Result is sfbrdevhelmweacr.azurecr.io/stakater/reloader:v1.0.95@sha256:5e15985882a8312abe5281aaae61301089244d5a33470eba16a7aeca715340c9.",
  "time": "2024-11-10T15:28:24Z"
}
```

**Expected behavior**
<A clear and concise description of what you expected to happen.>
Only the validation should happen and the image references should not be mutated.

**Optional: To reproduce**
<Stepwise guide or instructions or minimal example to reproduce.>
Deployment with the above config should reproduce the issue

**Optional: Versions (please complete the following information as relevant):**
 - OS: Redhat8.6
 - Kubernetes Cluster: RKE2 (1.30.5)
 - Container registry: Azure Container Registry
 - Connaisseur: v3.7.0


**Optional: Additional context**
<Add any other context or screenshots about the bug here.>
This causes applications as OutOfSync in Argocd. Is any additional configuration needed to do only validation?


Pull request:
fix: validation mode lower case
The check on the validation mode is done by lower casing the input and comparing it to a constant. Unfortunately the constant wasn\'t entirely lower case. This has been fixed.

fixes #1816

## Description

<!--- Provide a short description of the PR: why? how? -->

## Checklist
<!--- Mark as done if a point is not necessary. Feel free to reach out if help on any items in the checklist is needed. -->

- [x] PR is rebased to/aimed at branch `develop`
- [x] PR follows [Contributing Guide](https://github.com/sse-secure-systems/connaisseur/blob/master/docs/CONTRIBUTING.md)
- [x] Added tests (if necessary)
- [x] Extended README/Documentation (if necessary)
- [x] Adjusted versions of image and Helm chart in `Chart.yaml` (if necessary)


Patch:
diff --git a/internal/handler/validation/validation.go b/internal/handler/validation/validation.go
index ea2996e1..7ef95020 100644
--- a/internal/handler/validation/validation.go
+++ b/internal/handler/validation/validation.go
@@ -9,7 +9,6 @@ import (
 	"connaisseur/internal/utils"
 	"context"
 	"fmt"
-	"strings"
 
 	"github.com/sirupsen/logrus"
 )
@@ -161,7 +160,7 @@ func ValidateImage(ctx context.Context, in ValidationInput, out chan<- Validatio
 	logrus.Debugf("validator: %s", validatorName)
 
 	// get validation mode
-	switch strings.ToLower(rule.With.ValidationMode) {
+	switch rule.With.ValidationMode {
 	case constants.MutateMode:
 		validationMode = constants.MutateMode
 	case constants.ValidateMode:


Test patch:
diff --git a/internal/handler/validation/validation_test.go b/internal/handler/validation/validation_test.go
index 8be2f423..ea42c4a1 100644
--- a/internal/handler/validation/validation_test.go
+++ b/internal/handler/validation/validation_test.go
@@ -32,8 +32,9 @@ func TestValidateWorkloadObject(t *testing.T) {
 	var testCases = []struct {
 		newWLO kubernetes.WorkloadObject
 		out    map[string]struct {
-			img string
-			err error
+			img            string
+			validationMode string
+			err            error
 		}
 	}{
 		// test case with one image
@@ -43,10 +44,11 @@ func TestValidateWorkloadObject(t *testing.T) {
 				InitContainers: []core.Container{{Image: "nginx"}},
 			},
 			map[string]struct {
-				img string
-				err error
+				img            string
+				validationMode string
+				err            error
 			}{
-				"nginx": {"index.docker.io/library/nginx:latest", nil},
+				"nginx": {"index.docker.io/library/nginx:latest", constants.MutateMode, nil},
 			},
 		},
 		// test case with validationMode set to mutate
@@ -56,11 +58,13 @@ func TestValidateWorkloadObject(t *testing.T) {
 				InitContainers: []core.Container{{Image: "docker.io/securesystemsengineering/sample"}},
 			},
 			map[string]struct {
-				img string
-				err error
+				img            string
+				validationMode string
+				err            error
 			}{
 				"docker.io/securesystemsengineering/sample": {
 					"index.docker.io/securesystemsengineering/sample:latest",
+					constants.MutateMode,
 					nil,
 				},
 			},
@@ -72,11 +76,13 @@ func TestValidateWorkloadObject(t *testing.T) {
 				InitContainers: []core.Container{{Image: "docker.io/securesystemsengineering/sample:v1"}},
 			},
 			map[string]struct {
-				img string
-				err error
+				img            string
+				validationMode string
+				err            error
 			}{
 				"docker.io/securesystemsengineering/sample:v1": {
 					"index.docker.io/securesystemsengineering/sample:v1",
+					constants.ValidateMode,
 					nil,
 				},
 			},
@@ -89,11 +95,12 @@ func TestValidateWorkloadObject(t *testing.T) {
 				EphemeralContainers: []core.EphemeralContainer{{EphemeralContainerCommon: core.EphemeralContainerCommon{Image: "debian"}}},
 			},
 			map[string]struct {
-				img string
-				err error
+				img            string
+				validationMode string
+				err            error
 			}{
-				"nginx":  {"index.docker.io/library/nginx:latest", nil},
-				"debian": {"index.docker.io/library/debian:latest", nil},
+				"nginx":  {"index.docker.io/library/nginx:latest", constants.MutateMode, nil},
+				"debian": {"index.docker.io/library/debian:latest", constants.MutateMode, nil},
 			},
 		},
 	}
@@ -108,16 +115,18 @@ func TestValidateWorkloadObject(t *testing.T) {
 	for idx, tc := range testCases {
 		voChannel := ValidateWorkloadObject(ctx, &tc.newWLO, &kubernetes.WorkloadObject{})
 		validatedImages := map[string]struct {
-			img string
-			err error
+			img  string
+			mode string
+			err  error
 		}{}
 		containers := tc.newWLO.ConsolidatedContainers()
 		for range containers {
 			vo := <-voChannel
 			validatedImages[vo.RawImage] = struct {
-				img string
-				err error
-			}{vo.NewImage, vo.Error}
+				img  string
+				mode string
+				err  error
+			}{vo.NewImage, vo.ValidationMode, vo.Error}
 		}
 		assert.Equalf(t, len(tc.out), len(validatedImages), "test case %i", idx+1)
 		for expectedValidatedImg := range tc.out {
@@ -130,6 +139,13 @@ func TestValidateWorkloadObject(t *testing.T) {
 				"test case %i",
 				idx+1,
 			)
+			assert.Equalf(
+				t,
+				tc.out[expectedValidatedImg].validationMode,
+				actualValidatedImg.mode,
+				"test case %i",
+				idx+1,
+			)
 			assert.Equalf(
 				t,
 				tc.out[expectedValidatedImg].err,