Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add event type filtering to the gitlab interceptor. #235

Merged
merged 1 commit into from
Nov 26, 2019
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
17 changes: 12 additions & 5 deletions docs/eventlisteners.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,17 @@ spec:

### GitLab Interceptors

GitLab interceptors contain logic to validate that a webhook actually came from Gitlab,
using the logic outlined in GitLab [documentation](https://docs.gitlab.com/ee/user/project/integrations/webhooks.html/).
GitLab interceptors contain logic to validate and filter requests that come from Gitlab.
Supported features include validating that a webhook actually came from Gitlab, using the logic outlined
in GitLab [documentation](https://docs.gitlab.com/ee/user/project/integrations/webhooks.html/),
and to filter incoming events based on the event types.
Event types can be found in Gitlab [documentation](https://docs.gitlab.com/ee/user/project/integrations/webhooks.html#events).

To use this interceptor, create a secret string using the method of your choice, and configure the Gitlab
webhook to use that secret value.
Create a Kubernetes secret containing this value, and pass that as a reference to the `gitlab` interceptor:
To use this interceptor as a validator, create a secret string using the method of your choice, and configure
the Gitlab webhook to use that secret value.
Create a Kubernetes secret containing this value, and pass that as a reference to the `gitlab` interceptor.

To use this interceptor as a filter, add the event types you would like to accept to the `eventTypes` field.

<!-- FILE: examples/eventlisteners/gitlab-eventlistener-interceptor.yaml -->
```YAML
Expand All @@ -182,6 +187,8 @@ spec:
secretName: foo
secretKey: bar
namespace: baz
eventTypes:
- Push Hook
bindings:
- name: pipeline-binding
template:
Expand Down
2 changes: 2 additions & 0 deletions examples/eventlisteners/gitlab-eventlistener-interceptor.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ spec:
secretName: foo
secretKey: bar
namespace: baz
eventTypes:
- Push Hook
bindings:
- name: pipeline-binding
template:
Expand Down
3 changes: 2 additions & 1 deletion pkg/apis/triggers/v1alpha1/event_listener_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ type GithubInterceptor struct {

// GitlabInterceptor provides a webhook to intercept and pre-process events
type GitlabInterceptor struct {
SecretRef *SecretRef `json:"secretRef,omitempty"`
SecretRef *SecretRef `json:"secretRef,omitempty"`
EventTypes []string `json:"eventTypes,omitempty"`
}

// SecretRef contains the information required to reference a single secret string
Expand Down
5 changes: 5 additions & 0 deletions pkg/apis/triggers/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 28 additions & 15 deletions pkg/interceptors/gitlab/gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package gitlab
import (
"crypto/subtle"
"errors"
"fmt"
"net/http"

"github.com/tektoncd/triggers/pkg/interceptors"
Expand Down Expand Up @@ -46,23 +47,35 @@ func NewInterceptor(gl *triggersv1.GitlabInterceptor, k kubernetes.Interface, ns
}

func (w *Interceptor) ExecuteTrigger(payload []byte, request *http.Request, _ *triggersv1.EventListenerTrigger, _ string) ([]byte, error) {
// No secret set, just continue
if w.Gitlab.SecretRef == nil {
return payload, nil
}
header := request.Header.Get("X-Gitlab-Token")
if header == "" {
return nil, errors.New("no X-Gitlab-Token header set")
}
// Validate the secret first, if set.
if w.Gitlab.SecretRef != nil {
header := request.Header.Get("X-Gitlab-Token")
if header == "" {
return nil, errors.New("no X-Gitlab-Token header set")
}

secretToken, err := interceptors.GetSecretToken(w.KubeClientSet, w.Gitlab.SecretRef, w.EventListenerNamespace)
if err != nil {
return nil, err
}
secretToken, err := interceptors.GetSecretToken(w.KubeClientSet, w.Gitlab.SecretRef, w.EventListenerNamespace)
if err != nil {
return nil, err
}

// Make sure to use a constant time comparison here.
if subtle.ConstantTimeCompare([]byte(header), secretToken) == 0 {
return nil, errors.New("Invalid X-Gitlab-Token")
// Make sure to use a constant time comparison here.
if subtle.ConstantTimeCompare([]byte(header), secretToken) == 0 {
Copy link
Member

Choose a reason for hiding this comment

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

Nice!!

return nil, errors.New("Invalid X-Gitlab-Token")
}
}
if w.Gitlab.EventTypes != nil {
actualEvent := request.Header.Get("X-Gitlab-Event")
isAllowed := false
for _, allowedEvent := range w.Gitlab.EventTypes {
if actualEvent == allowedEvent {
isAllowed = true
break
}
}
if !isAllowed {
return nil, fmt.Errorf("event type %s is not allowed", actualEvent)
}
}

return payload, nil
Expand Down
105 changes: 102 additions & 3 deletions pkg/interceptors/gitlab/gitlab_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ import (

func TestInterceptor_ExecuteTrigger(t *testing.T) {
type args struct {
payload []byte
secret *corev1.Secret
token string
payload []byte
secret *corev1.Secret
token string
eventType string
}
tests := []struct {
name string
Expand Down Expand Up @@ -100,6 +101,101 @@ func TestInterceptor_ExecuteTrigger(t *testing.T) {
wantErr: false,
want: []byte("somepayload"),
},
{
name: "valid event",
Gitlab: &triggersv1.GitlabInterceptor{
EventTypes: []string{"foo", "bar"},
},
args: args{
eventType: "foo",
payload: []byte("somepayload"),
},
wantErr: false,
want: []byte("somepayload"),
},
{
name: "invalid event",
Gitlab: &triggersv1.GitlabInterceptor{
EventTypes: []string{"foo", "bar"},
},
args: args{
eventType: "baz",
payload: []byte("somepayload"),
},
wantErr: true,
},
{
name: "valid event, invalid secret",
Gitlab: &triggersv1.GitlabInterceptor{
EventTypes: []string{"foo", "bar"},
SecretRef: &triggersv1.SecretRef{
SecretName: "mysecret",
SecretKey: "token",
},
},
args: args{
eventType: "bar",
payload: []byte("somepayload"),
token: "foo",
secret: &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "mysecret",
},
Data: map[string][]byte{
"token": []byte("secrettoken"),
},
},
},
wantErr: true,
},
{
name: "invalid event, valid secret",
Gitlab: &triggersv1.GitlabInterceptor{
EventTypes: []string{"foo", "bar"},
SecretRef: &triggersv1.SecretRef{
SecretName: "mysecret",
SecretKey: "token",
},
},
args: args{
eventType: "baz",
payload: []byte("somepayload"),
token: "secrettoken",
secret: &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "mysecret",
},
Data: map[string][]byte{
"token": []byte("secrettoken"),
},
},
},
wantErr: true,
},
{
name: "valid event, valid secret",
Gitlab: &triggersv1.GitlabInterceptor{
EventTypes: []string{"foo", "bar"},
SecretRef: &triggersv1.SecretRef{
SecretName: "mysecret",
SecretKey: "token",
},
},
args: args{
eventType: "bar",
payload: []byte("somepayload"),
token: "secrettoken",
secret: &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "mysecret",
},
Data: map[string][]byte{
"token": []byte("secrettoken"),
},
},
},
want: []byte("somepayload"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand All @@ -115,6 +211,9 @@ func TestInterceptor_ExecuteTrigger(t *testing.T) {
if tt.args.token != "" {
request.Header.Add("X-Gitlab-Token", tt.args.token)
}
if tt.args.eventType != "" {
request.Header.Add("X-Gitlab-Event", tt.args.eventType)
}
if tt.args.secret != nil {
ns := tt.Gitlab.SecretRef.Namespace
if ns == "" {
Expand Down
1 change: 0 additions & 1 deletion third_party/VENDOR-LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -7517,4 +7517,3 @@ Import: github.com/tektoncd/triggers/vendor/knative.dev/pkg
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Copy link
Member

Choose a reason for hiding this comment

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

Not sure if this was intentional?