From a72b0f1a6302a739fcccd5d534e8503eb9402606 Mon Sep 17 00:00:00 2001 From: Bruno Bressi Date: Sun, 28 Jan 2024 22:35:08 +0100 Subject: [PATCH] refactor: more robust E2E tests Added a new test case for the COSIGN_REPOSITORY variable and made the e2e tests more robust by properly handling timeouts, which weren't working half the time. Signed-off-by: Bruno Bressi --- .golangci.yaml | 105 +++++++++++++++ .pre-commit-config.yaml | 17 +++ Makefile | 2 +- README.md | 1 + main.go | 32 ++--- test/framework/client.go | 28 ++-- test/framework/cosign.go | 5 +- test/main_test.go | 3 +- test/webhook_test.go | 232 ++++++++++++++++++++++++---------- webhook/cosignwebhook.go | 73 ++++++----- webhook/cosignwebhook_test.go | 2 +- 11 files changed, 355 insertions(+), 145 deletions(-) create mode 100644 .golangci.yaml create mode 100644 .pre-commit-config.yaml diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 0000000..d1098e2 --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,105 @@ +linters-settings: + dupl: + threshold: 100 + funlen: + lines: -1 # the number of lines (code + empty lines) is not a right metric and leads to code without empty line or one-liner. + statements: 50 + goconst: + min-len: 2 + min-occurrences: 3 + gocritic: + enabled-tags: + - diagnostic + - experimental + - opinionated + - performance + - style + disabled-checks: + - dupImport # https://github.com/go-critic/go-critic/issues/845 + - ifElseChain + - octalLiteral + - whyNoLint + gocyclo: + min-complexity: 15 + gofmt: + rewrite-rules: + - pattern: 'interface{}' + replacement: 'any' + goimports: + local-prefixes: github.com/golangci/golangci-lint + gomnd: + # don't include the "operation" and "assign" + checks: + - argument + - case + - condition + - return + ignored-numbers: + - '0' + - '1' + - '2' + - '3' + ignored-functions: + - strings.SplitN + + govet: + check-shadowing: true + settings: + printf: + funcs: + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf + lll: + line-length: 140 + misspell: + locale: US + nolintlint: + allow-unused: false # report any unused nolint directives + require-explanation: false # don't require an explanation for nolint directives + require-specific: false # don't require nolint directives to be specific about which linter is being skipped + revive: + rules: + - name: unexported-return + disabled: true + - name: unused-parameter + +linters: + disable-all: true + enable: + - bodyclose + - dogsled + - dupl + - errcheck + - exportloopref + - funlen + - gocheckcompilerdirectives + - gochecknoinits + - goconst + - gocritic + - gocyclo + - gofmt + - goimports + - gomnd + - goprintffuncname + - gosec + - gosimple + - govet + - ineffassign + - misspell + - nakedret + - noctx + - nolintlint + - revive + - staticcheck + - typecheck + - unconvert + - unparam + - unused + - whitespace + +run: + timeout: 5m + skip-files: + - .*_test\.go diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..ea06623 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,17 @@ +repos: + - repo: local + hooks: + - id: go-test + name: go-unit-tests + entry: make test-unit + language: system + types: [go] + - repo: https://github.com/tekwizely/pre-commit-golang + rev: v1.0.0-rc.1 + hooks: + - id: go-mod-tidy-repo + - id: go-vet-repo-mod + - id: go-fumpt-repo + args: [ -l, -w ] + - id: golangci-lint-repo-mod + args: [ --config, .golangci.yaml, --, --fix ] diff --git a/Makefile b/Makefile index 81a2ebd..cc75da0 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ e2e-keys: e2e-images: @echo "Checking for cosign.key..." - @test -f cosign.key || (echo "cosign.key not found. Run 'make generate-key' to generate one." && exit 1) + @test -f cosign.key || (echo "cosign.key not found. Run 'make e2e-keys' to generate the pairs needed for the tests." && exit 1) @echo "Building test image..." @docker build -t k3d-registry.localhost:5000/cosignwebhook:dev . @echo "Pushing test image..." diff --git a/README.md b/README.md index 38a8a56..aa2a7db 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,7 @@ targets. To run the tests the following is required: To run the E2E tests, the following steps are required (in order): +- create a k3d local cluster for the tests and a local iamge registry (`make e2e-cluster`) - signing keys are generated (`make e2e-keys`) - a new `cosignwebhook` image is build and signed with a temp key (`make e2e-images`) - the image is pushed to a local registry & deployed to the test cluster (`make e2e-deploy`) diff --git a/main.go b/main.go index 45273aa..81329f6 100644 --- a/main.go +++ b/main.go @@ -5,13 +5,13 @@ import ( "crypto/tls" "flag" "fmt" + "github.com/gookit/slog" "net/http" "os" "os/signal" "syscall" "github.com/eumel8/cosignwebhook/webhook" - log "github.com/gookit/slog" "github.com/prometheus/client_golang/prometheus/promhttp" ) @@ -34,26 +34,26 @@ func main() { // set log level switch *logLevel { case "fatal": - log.SetLogLevel(log.FatalLevel) + slog.SetLogLevel(slog.FatalLevel) case "trace": - log.SetLogLevel(log.TraceLevel) + slog.SetLogLevel(slog.TraceLevel) case "debug": - log.SetLogLevel(log.DebugLevel) + slog.SetLogLevel(slog.DebugLevel) case "error": - log.SetLogLevel(log.ErrorLevel) + slog.SetLogLevel(slog.ErrorLevel) case "warn": - log.SetLogLevel(log.WarnLevel) + slog.SetLogLevel(slog.WarnLevel) case "info": - log.SetLogLevel(log.InfoLevel) + slog.SetLogLevel(slog.InfoLevel) default: - log.SetLogLevel(log.InfoLevel) + slog.SetLogLevel(slog.InfoLevel) } - log.GetFormatter().(*log.TextFormatter).SetTemplate(logTemplate) + slog.GetFormatter().(*slog.TextFormatter).SetTemplate(logTemplate) certs, err := tls.LoadX509KeyPair(tlscert, tlskey) if err != nil { - log.Errorf("Failed to load key pair: ", err) + slog.Error("failed to load key pair", "error", err) } server := &http.Server{ @@ -79,23 +79,23 @@ func main() { // start webhook server in new rountine go func() { if err := server.ListenAndServeTLS("", ""); err != nil { - log.Errorf("Failed to listen and serve webhook server %v", err) + slog.Error("Failed to listen and serve webhook server", "error", err) } }() go func() { if err := mserver.ListenAndServe(); err != nil { - log.Errorf("Failed to listen and serve monitor server %v", err) + slog.Error("Failed to listen and serve monitor server %v", "error", err) } }() - log.Infof("Server running listening in port: %s,%s", port, mport) + slog.Info("Webhook server running", "port", port, "metricsPort", mport) // listening shutdown signal signalChan := make(chan os.Signal, 1) signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM) <-signalChan - log.Info("Got shutdown signal, shutting down webhook server gracefully...") - server.Shutdown(context.Background()) - mserver.Shutdown(context.Background()) + slog.Info("Got shutdown signal, shutting down webhook server gracefully...") + _ = server.Shutdown(context.Background()) + _ = mserver.Shutdown(context.Background()) } diff --git a/test/framework/client.go b/test/framework/client.go index 3e7cc52..a872bf9 100644 --- a/test/framework/client.go +++ b/test/framework/client.go @@ -3,14 +3,15 @@ package framework import ( "context" "fmt" + "os" + "testing" + "time" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" - "os" - "testing" - "time" ) // Framework is a helper struct for testing @@ -61,13 +62,11 @@ func (f *Framework) Cleanup(t testing.TB) { // cleanupDeployments removes all deployments from the testing namespace // if they exist func (f *Framework) cleanupDeployments(t testing.TB) { - t.Logf("cleaning up deployments") deployments, err := f.k8s.AppsV1().Deployments("test-cases").List(context.Background(), metav1.ListOptions{}) if err != nil { f.Cleanup(t) t.Fatal(err) - } for _, d := range deployments.Items { err = f.k8s.AppsV1().Deployments("test-cases").Delete(context.Background(), d.Name, metav1.DeleteOptions{}) @@ -100,7 +99,6 @@ func (f *Framework) cleanupDeployments(t testing.TB) { // cleanupSecrets removes all secrets from the testing namespace func (f *Framework) cleanupSecrets(t testing.TB) { - t.Logf("cleaning up secrets") secrets, err := f.k8s.CoreV1().Secrets("test-cases").List(context.Background(), metav1.ListOptions{}) if err != nil { @@ -130,25 +128,24 @@ func (f *Framework) CreateDeployment(t testing.TB, d appsv1.Deployment) { // WaitForDeployment waits until the deployment is ready func (f *Framework) WaitForDeployment(t *testing.T, d appsv1.Deployment) { - t.Logf("waiting for deployment %s to be ready", d.Name) // wait until the deployment is ready - w, err := f.k8s.AppsV1().Deployments(d.Namespace).Watch(context.Background(), metav1.ListOptions{ + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + w, err := f.k8s.AppsV1().Deployments(d.Namespace).Watch(ctx, metav1.ListOptions{ FieldSelector: fmt.Sprintf("metadata.name=%s", d.Name), }) - if err != nil { f.Cleanup(t) t.Fatal(err) } - timeout := time.After(30 * time.Second) - for event := range w.ResultChan() { + for { select { - case <-timeout: + case <-ctx.Done(): f.Cleanup(t) t.Fatal("timeout reached while waiting for deployment to be ready") - default: + case event := <-w.ResultChan(): deployment, ok := event.Object.(*appsv1.Deployment) if !ok { time.Sleep(5 * time.Second) @@ -162,9 +159,6 @@ func (f *Framework) WaitForDeployment(t *testing.T, d appsv1.Deployment) { time.Sleep(5 * time.Second) } } - - f.Cleanup(t) - t.Fatal("failed to wait for deployment to be ready") } // CreateSecret creates a secret in the testing namespace @@ -180,7 +174,6 @@ func (f *Framework) CreateSecret(t *testing.T, secret corev1.Secret) { // AssertDeploymentFailed asserts that the deployment cannot start func (f *Framework) AssertDeploymentFailed(t *testing.T, d appsv1.Deployment) { - t.Logf("waiting for deployment %s to fail", d.Name) // watch for replicasets of the deployment @@ -222,7 +215,6 @@ func (f *Framework) AssertDeploymentFailed(t *testing.T, d appsv1.Deployment) { // AssertEventForPod asserts that a PodVerified event is created func (f *Framework) AssertEventForPod(t *testing.T, reason string, p corev1.Pod) { - t.Logf("waiting for %s event to be created for pod %s", reason, p.Name) // watch for events of deployment's namespace and check if the podverified event is created diff --git a/test/framework/cosign.go b/test/framework/cosign.go index 9c23bde..047be76 100644 --- a/test/framework/cosign.go +++ b/test/framework/cosign.go @@ -2,15 +2,15 @@ package framework import ( "fmt" - "github.com/sigstore/cosign/v2/cmd/cosign/cli" "os" "regexp" "testing" + + "github.com/sigstore/cosign/v2/cmd/cosign/cli" ) // cleanupKeys removes all keypair files from the testing directory func cleanupKeys(t testing.TB) { - t.Logf("cleaning up keypair files") files, err := os.ReadDir(".") if err != nil { @@ -87,5 +87,6 @@ func (f *Framework) SignContainer(t *testing.T, priv, img string) { err := cmd.Execute() if err != nil { f.Cleanup(t) + t.Fatal(err) } } diff --git a/test/main_test.go b/test/main_test.go index 1146500..863114d 100644 --- a/test/main_test.go +++ b/test/main_test.go @@ -6,7 +6,6 @@ import ( // TestPassingDeployments tests deployments that should pass signature verification func TestPassingDeployments(t *testing.T) { - testFuncs := map[string]func(t *testing.T){ "OneContainerSinglePubKeyEnvRef": testOneContainerSinglePubKeyEnvRef, "TwoContainersSinglePubKeyEnvRef": testTwoContainersSinglePubKeyEnvRef, @@ -16,6 +15,7 @@ func TestPassingDeployments(t *testing.T) { "TwoContainersSingleWithInitPubKeyMixedRef": testTwoContainersWithInitSinglePubKeyMixedRef, "EventEmittedOnSignatureVerification": testEventEmittedOnSignatureVerification, "EventEmittedOnNoSignatureVerification": testEventEmittedOnNoSignatureVerification, + "OneContainerWithCosingRepoVariable": testOneContainerWithCosingRepoVariable, } for name, tf := range testFuncs { @@ -25,7 +25,6 @@ func TestPassingDeployments(t *testing.T) { // TestFailingDeployments tests deployments that should fail signature verification func TestFailingDeployments(t *testing.T) { - testFuncs := map[string]func(t *testing.T){ "OneContainerSinglePubKeyMalformedEnvRef": testOneContainerSinglePubKeyMalformedEnvRef, "TwoContainersSinglePubKeyMalformedEnvRef": testTwoContainersSinglePubKeyMalformedEnvRef, diff --git a/test/webhook_test.go b/test/webhook_test.go index 5c92fb3..7f9bc16 100644 --- a/test/webhook_test.go +++ b/test/webhook_test.go @@ -1,12 +1,13 @@ package test import ( + "testing" + "github.com/eumel8/cosignwebhook/test/framework" "github.com/eumel8/cosignwebhook/webhook" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "testing" ) // terminationGracePeriodSeconds is the termination grace period for the test deployments @@ -26,22 +27,22 @@ func testOneContainerSinglePubKeyEnvRef(t *testing.T) { // create a deployment with a single signed container and a public key provided via an environment variable depl := appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: "test-case-1", + Name: "one-container-env-ref", Namespace: "test-cases", }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"app": "test-case-1"}, + MatchLabels: map[string]string{"app": "one-container-env-ref"}, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{"app": "test-case-1"}, + Labels: map[string]string{"app": "one-container-env-ref"}, }, Spec: corev1.PodSpec{ TerminationGracePeriodSeconds: &terminationGracePeriodSeconds, Containers: []corev1.Container{ { - Name: "test-case-1", + Name: "one-container-env-ref", Image: "k3d-registry.localhost:5000/busybox:first", Command: []string{ "sh", @@ -69,7 +70,6 @@ func testOneContainerSinglePubKeyEnvRef(t *testing.T) { // testTwoContainersSinglePubKeyEnvRef tests that a deployment with two signed containers, // with a public key provided via an environment variable, succeeds. func testTwoContainersSinglePubKeyEnvRef(t *testing.T) { - fw, err := framework.New() if err != nil { t.Fatal(err) @@ -82,22 +82,22 @@ func testTwoContainersSinglePubKeyEnvRef(t *testing.T) { // create a deployment with two signed containers and a public key provided via an environment variable depl := appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: "test-case-2", + Name: "two-containers-same-pub-key-env-ref", Namespace: "test-cases", }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"app": "test-case-2"}, + MatchLabels: map[string]string{"app": "two-containers-same-pub-key-env-ref"}, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{"app": "test-case-2"}, + Labels: map[string]string{"app": "two-containers-same-pub-key-env-ref"}, }, Spec: corev1.PodSpec{ TerminationGracePeriodSeconds: &terminationGracePeriodSeconds, Containers: []corev1.Container{ { - Name: "test-case-2-first", + Name: "two-containers-same-pub-key-env-ref-first", Image: "k3d-registry.localhost:5000/busybox:first", Command: []string{ "sh", @@ -112,7 +112,7 @@ func testTwoContainersSinglePubKeyEnvRef(t *testing.T) { }, }, { - Name: "test-case-2-second", + Name: "two-containers-same-pub-key-env-ref-second", Image: "k3d-registry.localhost:5000/busybox:second", Command: []string{ "sh", @@ -140,7 +140,6 @@ func testTwoContainersSinglePubKeyEnvRef(t *testing.T) { // testOneContainerPubKeySecret tests that a deployment with a single signed container, // with a public key provided via a secret, succeeds. func testOneContainerSinglePubKeySecretRef(t *testing.T) { - fw, err := framework.New() if err != nil { t.Fatal(err) @@ -152,7 +151,7 @@ func testOneContainerSinglePubKeySecretRef(t *testing.T) { // create a secret with the public key secret := corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: "test-case-3", + Name: "one-container-secret-ref", Namespace: "test-cases", }, StringData: map[string]string{ @@ -163,22 +162,22 @@ func testOneContainerSinglePubKeySecretRef(t *testing.T) { // create a deployment with a single signed container and a public key provided via a secret depl := appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: "test-case-3", + Name: "one-container-secret-ref", Namespace: "test-cases", }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"app": "test-case-3"}, + MatchLabels: map[string]string{"app": "one-container-secret-ref"}, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{"app": "test-case-3"}, + Labels: map[string]string{"app": "one-container-secret-ref"}, }, Spec: corev1.PodSpec{ TerminationGracePeriodSeconds: &terminationGracePeriodSeconds, Containers: []corev1.Container{ { - Name: "test-case-3", + Name: "one-container-secret-ref", Image: "k3d-registry.localhost:5000/busybox:first", Command: []string{ "sh", @@ -192,7 +191,7 @@ func testOneContainerSinglePubKeySecretRef(t *testing.T) { SecretKeyRef: &corev1.SecretKeySelector{ Key: "cosign.pub", LocalObjectReference: corev1.LocalObjectReference{ - Name: "test-case-3", + Name: "one-container-secret-ref", }, }, }, @@ -227,7 +226,7 @@ func testTwoContainersMixedPubKeyMixedRef(t *testing.T) { // create a secret with the public key secret := corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: "test-case-4", + Name: "two-containers-mixed-pub-keyrefs", Namespace: "test-cases", }, StringData: map[string]string{ @@ -238,22 +237,22 @@ func testTwoContainersMixedPubKeyMixedRef(t *testing.T) { // create a deployment with two signed containers and a public key provided via a secret depl := appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: "test-case-4", + Name: "two-containers-mixed-pub-keyrefs", Namespace: "test-cases", }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"app": "test-case-4"}, + MatchLabels: map[string]string{"app": "two-containers-mixed-pub-keyrefs"}, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{"app": "test-case-4"}, + Labels: map[string]string{"app": "two-containers-mixed-pub-keyrefs"}, }, Spec: corev1.PodSpec{ TerminationGracePeriodSeconds: &terminationGracePeriodSeconds, Containers: []corev1.Container{ { - Name: "test-case-4-first", + Name: "two-containers-mixed-pub-keyrefs-first", Image: "k3d-registry.localhost:5000/busybox:first", Command: []string{ "sh", @@ -267,7 +266,7 @@ func testTwoContainersMixedPubKeyMixedRef(t *testing.T) { SecretKeyRef: &corev1.SecretKeySelector{ Key: "cosign.pub", LocalObjectReference: corev1.LocalObjectReference{ - Name: "test-case-4", + Name: "two-containers-mixed-pub-keyrefs", }, }, }, @@ -275,7 +274,7 @@ func testTwoContainersMixedPubKeyMixedRef(t *testing.T) { }, }, { - Name: "test-case-4-second", + Name: "two-containers-mixed-pub-keyrefs-second", Image: "k3d-registry.localhost:5000/busybox:second", Command: []string{ "sh", @@ -299,13 +298,11 @@ func testTwoContainersMixedPubKeyMixedRef(t *testing.T) { fw.CreateDeployment(t, depl) fw.WaitForDeployment(t, depl) fw.Cleanup(t) - } // testTwoContainersSinglePubKeyMixedRef tests that a deployment with two signed containers, // with a public key provided via a secret and an environment variable, succeeds. func testTwoContainersSinglePubKeyMixedRef(t *testing.T) { - fw, err := framework.New() if err != nil { t.Fatal(err) @@ -318,7 +315,7 @@ func testTwoContainersSinglePubKeyMixedRef(t *testing.T) { // create a secret with the public key secret := corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: "test-case-5", + Name: "two-containers-onekey-mixed-ref", Namespace: "test-cases", }, StringData: map[string]string{ @@ -329,22 +326,22 @@ func testTwoContainersSinglePubKeyMixedRef(t *testing.T) { // create a deployment with two signed containers and a public key provided via a secret depl := appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: "test-case-5", + Name: "two-containers-onekey-mixed-ref", Namespace: "test-cases", }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"app": "test-case-5"}, + MatchLabels: map[string]string{"app": "two-containers-onekey-mixed-ref"}, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{"app": "test-case-5"}, + Labels: map[string]string{"app": "two-containers-onekey-mixed-ref"}, }, Spec: corev1.PodSpec{ TerminationGracePeriodSeconds: &terminationGracePeriodSeconds, Containers: []corev1.Container{ { - Name: "test-case-5-first", + Name: "two-containers-onekey-mixed-ref-first", Image: "k3d-registry.localhost:5000/busybox:first", Command: []string{ "sh", @@ -358,7 +355,7 @@ func testTwoContainersSinglePubKeyMixedRef(t *testing.T) { SecretKeyRef: &corev1.SecretKeySelector{ Key: "cosign.pub", LocalObjectReference: corev1.LocalObjectReference{ - Name: "test-case-5", + Name: "two-containers-onekey-mixed-ref", }, }, }, @@ -366,7 +363,7 @@ func testTwoContainersSinglePubKeyMixedRef(t *testing.T) { }, }, { - Name: "test-case-5-second", + Name: "two-containers-onekey-mixed-ref-second", Image: "k3d-registry.localhost:5000/busybox:second", Command: []string{ "sh", @@ -390,13 +387,11 @@ func testTwoContainersSinglePubKeyMixedRef(t *testing.T) { fw.CreateDeployment(t, depl) fw.WaitForDeployment(t, depl) fw.Cleanup(t) - } // testTwoContainersSinglePubKeyMixedRef tests that a deployment with two signed containers, // with a public key provided via a secret and an environment variable, succeeds. func testTwoContainersWithInitSinglePubKeyMixedRef(t *testing.T) { - fw, err := framework.New() if err != nil { t.Fatal(err) @@ -409,7 +404,7 @@ func testTwoContainersWithInitSinglePubKeyMixedRef(t *testing.T) { // create a secret with the public key secret := corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: "test-case-6", + Name: "two-containers-init-singlekey-mixed-ref", Namespace: "test-cases", }, StringData: map[string]string{ @@ -420,22 +415,22 @@ func testTwoContainersWithInitSinglePubKeyMixedRef(t *testing.T) { // create a deployment with two signed containers and a public key provided via a secret depl := appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: "test-case-6", + Name: "two-containers-init-singlekey-mixed-ref", Namespace: "test-cases", }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"app": "test-case-6"}, + MatchLabels: map[string]string{"app": "two-containers-init-singlekey-mixed-ref"}, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{"app": "test-case-6"}, + Labels: map[string]string{"app": "two-containers-init-singlekey-mixed-ref"}, }, Spec: corev1.PodSpec{ TerminationGracePeriodSeconds: &terminationGracePeriodSeconds, InitContainers: []corev1.Container{ { - Name: "test-case-6-first", + Name: "two-containers-init-singlekey-mixed-ref-first", Image: "k3d-registry.localhost:5000/busybox:first", Command: []string{ "sh", @@ -449,7 +444,7 @@ func testTwoContainersWithInitSinglePubKeyMixedRef(t *testing.T) { SecretKeyRef: &corev1.SecretKeySelector{ Key: "cosign.pub", LocalObjectReference: corev1.LocalObjectReference{ - Name: "test-case-6", + Name: "two-containers-init-singlekey-mixed-ref", }, }, }, @@ -459,7 +454,7 @@ func testTwoContainersWithInitSinglePubKeyMixedRef(t *testing.T) { }, Containers: []corev1.Container{ { - Name: "test-case-6-second", + Name: "two-containers-init-singlekey-mixed-ref-second", Image: "k3d-registry.localhost:5000/busybox:second", Command: []string{ "sh", @@ -499,22 +494,22 @@ func testEventEmittedOnSignatureVerification(t *testing.T) { // create a deployment with a single signed container and a public key provided via an environment variable depl := appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: "test-case-7", + Name: "event-emitted-on-verify", Namespace: "test-cases", }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"app": "test-case-7"}, + MatchLabels: map[string]string{"app": "event-emitted-on-verify"}, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{"app": "test-case-7"}, + Labels: map[string]string{"app": "event-emitted-on-verify"}, }, Spec: corev1.PodSpec{ TerminationGracePeriodSeconds: &terminationGracePeriodSeconds, Containers: []corev1.Container{ { - Name: "test-case-7", + Name: "event-emitted-on-verify", Image: "k3d-registry.localhost:5000/busybox:first", Command: []string{ "sh", @@ -550,22 +545,22 @@ func testEventEmittedOnNoSignatureVerification(t *testing.T) { // create a deployment with a single unsigned container depl := appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: "test-case-8", + Name: "event-emitted-on-no-verify-needed", Namespace: "test-cases", }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"app": "test-case-8"}, + MatchLabels: map[string]string{"app": "event-emitted-on-no-verify-needed"}, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{"app": "test-case-8"}, + Labels: map[string]string{"app": "event-emitted-on-no-verify-needed"}, }, Spec: corev1.PodSpec{ TerminationGracePeriodSeconds: &terminationGracePeriodSeconds, Containers: []corev1.Container{ { - Name: "test-case-8", + Name: "event-emitted-on-no-verify-needed", Image: "k3d-registry.localhost:5000/busybox:first", Command: []string{"sh", "-c", "echo 'hello world, i am tired and will sleep now, for a bit...'; sleep 60"}, }, @@ -582,10 +577,64 @@ func testEventEmittedOnNoSignatureVerification(t *testing.T) { fw.Cleanup(t) } +func testOneContainerWithCosingRepoVariable(t *testing.T) { + fw, err := framework.New() + if err != nil { + t.Fatal(err) + } + + _, pub := fw.CreateKeys(t, "test") + t.Setenv("COSIGN_REPOSITORY", "k3d-registry.localhost:5000/sigs") + fw.SignContainer(t, "test", "k3d-registry.localhost:5000/busybox:first") + + depl := appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "one-container-with-cosign-repo", + Namespace: "test-cases", + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "one-container-with-cosign-repo"}, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"app": "one-container-with-cosign-repo"}, + }, + Spec: corev1.PodSpec{ + TerminationGracePeriodSeconds: &terminationGracePeriodSeconds, + Containers: []corev1.Container{ + { + Name: "one-container-with-cosign-repo", + Image: "k3d-registry.localhost:5000/busybox:first", + Command: []string{ + "sh", "-c", + "echo 'hello world, i am tired and will sleep now, for a bit...'; sleep 60", + }, + Env: []corev1.EnvVar{ + { + Name: webhook.CosignEnvVar, + Value: pub, + }, + { + Name: "COSIGN_REPOSITORY", + Value: "k3d-registry.localhost:5000/signatures", + }, + }, + }, + }, + }, + }, + }, + } + + fw.CreateDeployment(t, depl) + fw.WaitForDeployment(t, depl) + fw.Cleanup(t) +} + // testOneContainerSinglePubKeyNoMatchEnvRef tests that a deployment with a single signed container, // with a public key provided via an environment variable, fails if the public key does not match the signature. func testOneContainerSinglePubKeyNoMatchEnvRef(t *testing.T) { - fw, err := framework.New() if err != nil { t.Fatal(err) @@ -598,22 +647,22 @@ func testOneContainerSinglePubKeyNoMatchEnvRef(t *testing.T) { // create a deployment with a single signed container and a public key provided via an environment variable depl := appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: "fail-case-1", + Name: "no-match-env-ref", Namespace: "test-cases", }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"app": "fail-case-1"}, + MatchLabels: map[string]string{"app": "no-match-env-ref"}, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{"app": "fail-case-1"}, + Labels: map[string]string{"app": "no-match-env-ref"}, }, Spec: corev1.PodSpec{ TerminationGracePeriodSeconds: &terminationGracePeriodSeconds, Containers: []corev1.Container{ { - Name: "fail-case-1", + Name: "no-match-env-ref", Image: "k3d-registry.localhost:5000/busybox:first", Command: []string{ "sh", @@ -636,13 +685,11 @@ func testOneContainerSinglePubKeyNoMatchEnvRef(t *testing.T) { fw.CreateDeployment(t, depl) fw.AssertDeploymentFailed(t, depl) fw.Cleanup(t) - } // testTwoContainersSinglePubKeyNoMatchEnvRef tests that a deployment with two signed containers, // with a public key provided via an environment variable, fails if one of the container's pub key is malformed. func testTwoContainersSinglePubKeyMalformedEnvRef(t *testing.T) { - fw, err := framework.New() if err != nil { t.Fatal(err) @@ -654,22 +701,22 @@ func testTwoContainersSinglePubKeyMalformedEnvRef(t *testing.T) { // create a deployment with two signed containers and a public key provided via an environment variable depl := appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: "fail-case-2", + Name: "malformed-env-ref", Namespace: "test-cases", }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"app": "fail-case-2"}, + MatchLabels: map[string]string{"app": "malformed-env-ref"}, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{"app": "fail-case-2"}, + Labels: map[string]string{"app": "malformed-env-ref"}, }, Spec: corev1.PodSpec{ TerminationGracePeriodSeconds: &terminationGracePeriodSeconds, Containers: []corev1.Container{ { - Name: "fail-case-2-first", + Name: "malformed-env-ref-first", Image: "k3d-registry.localhost:5000/busybox:first", Command: []string{ "sh", @@ -684,7 +731,7 @@ func testTwoContainersSinglePubKeyMalformedEnvRef(t *testing.T) { }, }, { - Name: "fail-case-2-second", + Name: "malformed-env-ref-second", Image: "k3d-registry.localhost:5000/busybox:second", Command: []string{ "sh", @@ -707,7 +754,6 @@ func testTwoContainersSinglePubKeyMalformedEnvRef(t *testing.T) { fw.CreateDeployment(t, depl) fw.AssertDeploymentFailed(t, depl) fw.Cleanup(t) - } // testOneContainerSinglePubKeyMalformedEnvRef tests that a deployment with a single signed container, @@ -720,22 +766,22 @@ func testOneContainerSinglePubKeyMalformedEnvRef(t *testing.T) { depl := appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: "fail-case-3", + Name: "single-malformed-env-ref", Namespace: "test-cases", }, Spec: appsv1.DeploymentSpec{ Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"app": "fail-case-3"}, + MatchLabels: map[string]string{"app": "single-malformed-env-ref"}, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{"app": "fail-case-3"}, + Labels: map[string]string{"app": "single-malformed-env-ref"}, }, Spec: corev1.PodSpec{ TerminationGracePeriodSeconds: &terminationGracePeriodSeconds, Containers: []corev1.Container{ { - Name: "fail-case-3", + Name: "single-malformed-env-ref", Image: "k3d-registry.localhost:5000/busybox:first", Command: []string{ "sh", @@ -758,5 +804,55 @@ func testOneContainerSinglePubKeyMalformedEnvRef(t *testing.T) { fw.CreateDeployment(t, depl) fw.AssertDeploymentFailed(t, depl) fw.Cleanup(t) +} + +func testOneContainerWithCosingRepoVariableMissing(t *testing.T) { + fw, err := framework.New() + if err != nil { + t.Fatal(err) + } + + _, pub := fw.CreateKeys(t, "test") + t.Setenv("COSIGN_REPOSITORY", "k3d-registry.localhost:5000/sigs") + fw.SignContainer(t, "test", "k3d-registry.localhost:5000/busybox:first") + + depl := appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "one-container-with-cosign-repo-missing", + Namespace: "test-cases", + }, + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "one-container-with-cosign-repo-missing"}, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"app": "one-container-with-cosign-repo-missing"}, + }, + Spec: corev1.PodSpec{ + TerminationGracePeriodSeconds: &terminationGracePeriodSeconds, + Containers: []corev1.Container{ + { + Name: "one-container-with-cosign-repo-missing", + Image: "k3d-registry.localhost:5000/busybox:first", + Command: []string{ + "sh", "-c", + "echo 'hello world, i can't start because I'm missing an env var...'; sleep 60", + }, + Env: []corev1.EnvVar{ + { + Name: webhook.CosignEnvVar, + Value: pub, + }, + }, + }, + }, + }, + }, + }, + } + fw.CreateDeployment(t, depl) + fw.WaitForDeployment(t, depl) + fw.Cleanup(t) } diff --git a/webhook/cosignwebhook.go b/webhook/cosignwebhook.go index 9277970..2615ecc 100644 --- a/webhook/cosignwebhook.go +++ b/webhook/cosignwebhook.go @@ -7,6 +7,7 @@ import ( "encoding/json" "errors" "fmt" + "github.com/gookit/slog" "io" "net/http" "os" @@ -17,7 +18,6 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "k8s.io/apimachinery/pkg/types" - log "github.com/gookit/slog" v1 "k8s.io/api/admission/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -67,7 +67,7 @@ type CosignServerHandler struct { func NewCosignServerHandler() *CosignServerHandler { cs, err := restClient() if err != nil { - log.Errorf("Can't init rest client: %v", err) + slog.Errorf("Can't init rest client: %v", err) } eb := record.NewBroadcaster() eb.StartRecordingToSink(&typedcorev1.EventSinkImpl{Interface: cs.CoreV1().Events("")}) @@ -81,12 +81,12 @@ func NewCosignServerHandler() *CosignServerHandler { func restClient() (*kubernetes.Clientset, error) { restConfig, err := rest.InClusterConfig() if err != nil { - log.Errorf("error init in-cluster config: %v", err) + slog.Errorf("error init in-cluster config: %v", err) return nil, err } cs, err := kubernetes.NewForConfig(restConfig) if err != nil { - log.Errorf("error creating k8sclientset: %v", err) + slog.Errorf("error creating k8sclientset: %v", err) return nil, err } return cs, err @@ -108,17 +108,17 @@ func (csh *CosignServerHandler) recordNoVerification(p *corev1.Pod) { func getPod(byte []byte) (*corev1.Pod, *v1.AdmissionReview, error) { arRequest := v1.AdmissionReview{} if err := json.Unmarshal(byte, &arRequest); err != nil { - log.Error("Incorrect body") + slog.Error("Incorrect body") return nil, nil, err } if arRequest.Request == nil { - log.Error("AdmissionReview request not found") + slog.Error("AdmissionReview request not found") return nil, nil, fmt.Errorf("admissionreview request not found") } raw := arRequest.Request.Object.Raw pod := corev1.Pod{} if err := json.Unmarshal(raw, &pod); err != nil { - log.Error("Error deserializing container") + slog.Error("Error deserializing container") return nil, nil, err } return &pod, &arRequest, nil @@ -130,12 +130,12 @@ func (csh *CosignServerHandler) getPubKeyFromEnv(c *corev1.Container, ns string) for _, envVar := range c.Env { if envVar.Name == CosignEnvVar { if len(envVar.Value) != 0 { - log.Debugf("Found public key in env var for container %q", c.Name) + slog.Debugf("Found public key in env var for container %q", c.Name) return envVar.Value, nil } if envVar.ValueFrom != nil && envVar.ValueFrom.SecretKeyRef != nil { - log.Debugf("Found reference to public key in secret %q for container %q", envVar.ValueFrom.SecretKeyRef.Name, c.Name) + slog.Debugf("Found reference to public key in secret %q for container %q", envVar.ValueFrom.SecretKeyRef.Name, c.Name) return csh.getSecretValue(ns, envVar.ValueFrom.SecretKeyRef.Name, envVar.ValueFrom.SecretKeyRef.Key, @@ -152,15 +152,15 @@ func (csh *CosignServerHandler) getSecretValue(namespace string, name string, ke defer cancel() secret, err := csh.cs.CoreV1().Secrets(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { - log.Debugf("Can't get secret %s/%s : %v", namespace, name, err) + slog.Debugf("Can't get secret %s/%s : %v", namespace, name, err) return "", err } value := secret.Data[key] if len(value) == 0 { - log.Errorf("Secret value of %q is empty for %s/%s", key, namespace, name) + slog.Errorf("Secret value of %q is empty for %s/%s", key, namespace, name) return "", nil } - log.Debugf("Found public key in secret %s/%s, value: %s", namespace, name, value) + slog.Debugf("Found public key in secret %s/%s, value: %s", namespace, name, value) return string(value), nil } @@ -168,7 +168,7 @@ func (csh *CosignServerHandler) Healthz(w http.ResponseWriter, r *http.Request) w.WriteHeader(http.StatusOK) _, err := w.Write([]byte("ok")) if err != nil { - log.Errorf("Can't write response: %v", err) + slog.Errorf("Can't write response: %v", err) http.Error(w, fmt.Sprintf("could not write response: %v", err), http.StatusInternalServerError) } } @@ -189,13 +189,13 @@ func (csh *CosignServerHandler) Serve(w http.ResponseWriter, r *http.Request) { // Url path of admission if r.URL.Path != "/validate" { - log.Error("No validate URI") + slog.Error("No validate URI") http.Error(w, "no validate", http.StatusBadRequest) return } if len(body) == 0 { - log.Error("Empty body") + slog.Error("Empty body") http.Error(w, "empty body", http.StatusBadRequest) return } @@ -205,7 +205,7 @@ func (csh *CosignServerHandler) Serve(w http.ResponseWriter, r *http.Request) { pod, arRequest, err := getPod(body) if err != nil { - log.Errorf("Error getPod in %s/%s: %v", pod.Namespace, pod.Name, err) + slog.Errorf("Error getPod in %s/%s: %v", pod.Namespace, pod.Name, err) http.Error(w, "incorrect body", http.StatusBadRequest) return } @@ -224,7 +224,7 @@ func (csh *CosignServerHandler) Serve(w http.ResponseWriter, r *http.Request) { ctx := r.Context() kc, err := k8schain.NewInCluster(ctx, opt) if err != nil { - log.Errorf("Error intializing k8schain %s/%s: %v", pod.Namespace, pod.Name, err) + slog.Errorf("Error intializing k8schain %s/%s: %v", pod.Namespace, pod.Name, err) http.Error(w, "Failed initializing k8schain", http.StatusInternalServerError) return } @@ -232,7 +232,6 @@ func (csh *CosignServerHandler) Serve(w http.ResponseWriter, r *http.Request) { signatureChecked := false for _, c := range pod.Spec.InitContainers { - pubKey := csh.getPubKeyFor(c, pod.Namespace) if len(pubKey) == 0 { continue @@ -240,7 +239,7 @@ func (csh *CosignServerHandler) Serve(w http.ResponseWriter, r *http.Request) { err = csh.verifyContainer(&c, pubKey) if err != nil { - log.Errorf("Error verifying init container %s/%s/%s: %v", pod.Namespace, pod.Name, pod.Spec.InitContainers[0].Name, err) + slog.Errorf("Error verifying init container %s/%s/%s: %v", pod.Namespace, pod.Name, pod.Spec.InitContainers[0].Name, err) deny(w, err.Error(), arRequest.Request.UID) return } @@ -254,7 +253,7 @@ func (csh *CosignServerHandler) Serve(w http.ResponseWriter, r *http.Request) { } err = csh.verifyContainer(&c, pubKey) if err != nil { - log.Errorf("Error verifying container %s/%s/%s: %v", pod.Namespace, pod.Name, pod.Spec.Containers[i].Name, err) + slog.Errorf("Error verifying container %s/%s/%s: %v", pod.Namespace, pod.Name, pod.Spec.Containers[i].Name, err) deny(w, err.Error(), arRequest.Request.UID) return } @@ -273,66 +272,66 @@ func (csh *CosignServerHandler) Serve(w http.ResponseWriter, r *http.Request) { // If no public key is found, it returns an empty string. func (csh *CosignServerHandler) getPubKeyFor(c corev1.Container, ns string) string { if len(c.Image) == 0 { - log.Debugf("Container %q has no image, skipping verification", c.Name) + slog.Debugf("Container %q has no image, skipping verification", c.Name) return "" } if len(c.Env) == 0 { - log.Debugf("Container %q has no env vars, skipping verification", c.Name) + slog.Debugf("Container %q has no env vars, skipping verification", c.Name) return "" } pubKey, err := csh.getPubKeyFromEnv(&c, ns) if err != nil { - log.Debugf("Could not find pub key in container's %q environment: %v", c.Name, err) + slog.Debugf("Could not find pub key in container's %q environment: %v", c.Name, err) } // If no public key get here, try to load default secret if len(pubKey) == 0 { pubKey, err = csh.getSecretValue(ns, "cosignwebhook", CosignEnvVar) if err != nil { - log.Debugf("Could not find pub key from default secret: %v", err) + slog.Debugf("Could not find pub key from default secret: %v", err) } } // Still no public key, we don't care. Otherwise, POD won't start if we return with 403 // In future versions this should block the start of the container if len(pubKey) == 0 { - log.Debugf("No public key found, returning") + slog.Debugf("No public key found, returning") return "" } - log.Debugf("Found public key for container %q", c.Name) + slog.Debugf("Found public key for container %q", c.Name) return pubKey } // verifyContainer verifies the signature of the container image func (csh *CosignServerHandler) verifyContainer(c *corev1.Container, pubKey string) error { - log.Debugf("Verifying container %s", c.Name) + slog.Debugf("Verifying container %s", c.Name) // Lookup image name of current container image := c.Image refImage, err := name.ParseReference(image) if err != nil { - log.Errorf("Error parsing image reference: %v", err) + slog.Errorf("Error parsing image reference: %v", err) return fmt.Errorf("could parse image reference for image %q", image) } // Encrypt public key publicKey, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(pubKey)) if err != nil { - log.Errorf("Error unmarshalling public key: %v", err) + slog.Errorf("Error unmarshalling public key: %v", err) return fmt.Errorf("public key for image %q malformed", image) } // Load public key to verify cosignLoadKey, err := signature.LoadECDSAVerifier(publicKey.(*ecdsa.PublicKey), crypto.SHA256) if err != nil { - log.Errorf("Error loading ECDSA verifier: %v", err) + slog.Errorf("Error loading ECDSA verifier: %v", err) return errors.New("failed creating key verifier") } // Verify signature on remote image with the presented public key remoteOpts := []ociremote.Option{ociremote.WithRemoteOptions(remote.WithAuthFromKeychain(csh.kc))} - log.Debugf("Verifying image %q with public key %q", image, pubKey) + slog.Debugf("Verifying image %q with public key %q", image, pubKey) _, _, err = cosign.VerifyImageSignatures( context.Background(), refImage, @@ -345,13 +344,13 @@ func (csh *CosignServerHandler) verifyContainer(c *corev1.Container, pubKey stri // Verify Image failed, needs to reject container start if err != nil { - log.Errorf("Error verifying signature: %v", err) + slog.Errorf("Error verifying signature: %v", err) return fmt.Errorf("signature for %q couldn't be verified", image) } // count successful verifies for prometheus metric verifiedProcessed.Inc() - log.Infof("Image %q verified successfully", image) + slog.Infof("Image %q verified successfully", image) return nil } @@ -359,11 +358,11 @@ func (csh *CosignServerHandler) verifyContainer(c *corev1.Container, pubKey stri func deny(w http.ResponseWriter, msg string, uid types.UID) { resp, err := json.Marshal(admissionReview(403, false, "Failure", msg, uid)) if err != nil { - log.Errorf("Can't encode response: %v", err) + slog.Errorf("Can't encode response: %v", err) http.Error(w, fmt.Sprintf("could not encode response: %v", err), http.StatusInternalServerError) } if _, err := w.Write(resp); err != nil { - log.Errorf("Can't write response: %v", err) + slog.Errorf("Can't write response: %v", err) http.Error(w, fmt.Sprintf("could not write response: %v", err), http.StatusInternalServerError) } } @@ -372,11 +371,11 @@ func deny(w http.ResponseWriter, msg string, uid types.UID) { func accept(w http.ResponseWriter, msg string, uid types.UID) { resp, err := json.Marshal(admissionReview(200, true, "Success", msg, uid)) if err != nil { - log.Errorf("Can't encode response: %v", err) + slog.Errorf("Can't encode response: %v", err) http.Error(w, fmt.Sprintf("could not encode response: %v", err), http.StatusInternalServerError) } if _, err := w.Write(resp); err != nil { - log.Errorf("Can't write response: %v", err) + slog.Errorf("Can't write response: %v", err) http.Error(w, fmt.Sprintf("could not write response: %v", err), http.StatusInternalServerError) } } diff --git a/webhook/cosignwebhook_test.go b/webhook/cosignwebhook_test.go index 94679aa..b8de42d 100644 --- a/webhook/cosignwebhook_test.go +++ b/webhook/cosignwebhook_test.go @@ -141,7 +141,7 @@ func Test_getPubKeyFromEnv(t *testing.T) { } func TestCosignServerHandler_verifyPodContainer(t *testing.T) { - //tests := []struct { + // tests := []struct { // name string // pod *corev1.Pod // wantErr bool