From 08c12cea17e7f38bcbbf08a3f22697d08f66cd0d Mon Sep 17 00:00:00 2001 From: Srinivas Chippagiri Date: Fri, 23 Oct 2026 04:00:38 -0700 Subject: [PATCH] gitlab interceptor: warn when secretRef is not set Log a warning when the GitLab interceptor processes a request without a secretRef, since the token is then not verified. Document the behavior for the GitLab and Bitbucket server interceptors. Fixes #2030 Signed-off-by: Srinivas Chippagiri --- docs/interceptors.md | 7 ++++ pkg/interceptors/gitlab/gitlab.go | 4 ++ pkg/interceptors/gitlab/gitlab_test.go | 52 ++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/docs/interceptors.md b/docs/interceptors.md index 4bada8dcfc..95050517cc 100644 --- a/docs/interceptors.md +++ b/docs/interceptors.md @@ -340,6 +340,10 @@ To use a GitLab `Interceptor` as a GitLab webhook validator, do the following: 3. Create a Kubernetes secret containing your secret value. 4. Pass the Kubernetes secret as a reference to your GitLab `Interceptor`. +**Note:** if `secretRef` is omitted, the `Interceptor` does not verify the webhook +token and accepts every request, and it logs a warning for each request it processes. +Always set `secretRef` unless the `EventListener` is only reachable by trusted senders. + To use a GitLab `Interceptor` as a filter for event data, specify the event types you want the `Interceptor` to accept in the `eventTypes` field. The `Interceptor` accepts data event types listed in [Events](https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html). @@ -400,6 +404,9 @@ To use a Bitbucket `Interceptor` as a Bitbucket server webhook validator, do the 3. Create a Kubernetes secret containing your secret value. 4. Pass the Kubernetes secret as a reference to your Bitbucket `Interceptor`. +**Note:** if `secretRef` is omitted, the `Interceptor` does not verify the webhook +signature and accepts every request. + To use a Bitbucket `Interceptor` as a filter for event data, specify the event types you want the `Interceptor` to accept in the `eventTypes` field. The `Interceptor` accepts data event types listed in [Event payload](https://confluence.atlassian.com/bitbucketserver/event-payload-938025882.html). diff --git a/pkg/interceptors/gitlab/gitlab.go b/pkg/interceptors/gitlab/gitlab.go index ce17fca17d..fffac0a7fb 100644 --- a/pkg/interceptors/gitlab/gitlab.go +++ b/pkg/interceptors/gitlab/gitlab.go @@ -23,6 +23,7 @@ import ( triggersv1 "github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1" "github.com/tektoncd/triggers/pkg/interceptors" "google.golang.org/grpc/codes" + "knative.dev/pkg/logging" ) var _ triggersv1.InterceptorInterface = (*InterceptorImpl)(nil) @@ -93,6 +94,9 @@ func (w *InterceptorImpl) Process(ctx context.Context, r *triggersv1.Interceptor return interceptors.Fail(codes.InvalidArgument, "Invalid X-GitLab-Token") } } + if p.SecretRef == nil { + logging.FromContext(ctx).Warn("GitLab interceptor is running without signature verification. Set params.secretRef to enable webhook authentication.") + } return &triggersv1.InterceptorResponse{ Continue: true, } diff --git a/pkg/interceptors/gitlab/gitlab_test.go b/pkg/interceptors/gitlab/gitlab_test.go index 852640c079..e76e6581a9 100644 --- a/pkg/interceptors/gitlab/gitlab_test.go +++ b/pkg/interceptors/gitlab/gitlab_test.go @@ -17,15 +17,20 @@ limitations under the License. package gitlab import ( + "context" "net/http" "testing" triggersv1 "github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1" "github.com/tektoncd/triggers/pkg/interceptors" "github.com/tektoncd/triggers/test" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "go.uber.org/zap/zaptest/observer" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" fakekubeclient "knative.dev/pkg/client/injection/kube/client/fake" + "knative.dev/pkg/logging" ) func TestInterceptor_ExecuteTrigger_ShouldContinue(t *testing.T) { @@ -307,3 +312,50 @@ func TestInterceptor_Process_InvalidParams(t *testing.T) { t.Fatalf("Interceptor.Process() expected res.Continue to be false but got %t. \nStatus.Err(): %v", res.Continue, res.Status.Err()) } } + +func TestInterceptor_Process_WarnsWithoutSecretRef(t *testing.T) { + tests := []struct { + name string + params map[string]interface{} + wantWarn bool + }{{ + name: "no secretRef", + params: map[string]interface{}{}, + wantWarn: true, + }, { + name: "with secretRef", + params: map[string]interface{}{ + "secretRef": &triggersv1.SecretRef{SecretName: "mysecret", SecretKey: "token"}, + }, + wantWarn: false, + }} + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + core, logs := observer.New(zapcore.WarnLevel) + ctx := logging.WithLogger(context.Background(), zap.New(core).Sugar()) + ctx, clientset := fakekubeclient.With(ctx, &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "mysecret", Namespace: metav1.NamespaceDefault}, + Data: map[string][]byte{"token": []byte("secret")}, + }) + req := &triggersv1.InterceptorRequest{ + Body: "somepayload", + Header: http.Header{"X-Gitlab-Token": []string{"secret"}}, + InterceptorParams: tt.params, + Context: &triggersv1.TriggerContext{ + EventURL: "https://testing.example.com", + EventID: "abcde", + TriggerID: "namespaces/default/triggers/example-trigger", + }, + } + w := &InterceptorImpl{SecretGetter: interceptors.DefaultSecretGetter(clientset.CoreV1())} + res := w.Process(ctx, req) + if !res.Continue { + t.Fatalf("expected res.Continue to be true, got status %v", res.Status.Err()) + } + if got := logs.Len() > 0; got != tt.wantWarn { + t.Errorf("warning logged = %t, want %t", got, tt.wantWarn) + } + }) + } +}