ability to limit webhook delivery by event and action
This commit is contained in:
parent
2730e336d2
commit
443b369b91
9 changed files with 111 additions and 4 deletions
|
@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- support for legacy workspace based on repository name
|
||||
- support for github deployment hooks
|
||||
- provide base sha for github pull requests
|
||||
- option to filter webhooks by event and type
|
||||
|
||||
## [1.2.1] - 2019-06-11
|
||||
### Added
|
||||
|
|
|
@ -280,6 +280,7 @@ type (
|
|||
|
||||
// Webhook provides the webhook configuration.
|
||||
Webhook struct {
|
||||
Events []string `envconfig:"DRONE_WEBHOOK_EVENTS"`
|
||||
Endpoint []string `envconfig:"DRONE_WEBHOOK_ENDPOINT"`
|
||||
Secret string `envconfig:"DRONE_WEBHOOK_SECRET"`
|
||||
SkipVerify bool `envconfig:"DRONE_WEBHOOK_SKIP_VERIFY"`
|
||||
|
|
|
@ -97,6 +97,7 @@ func provideSecretPlugin(config spec.Config) core.SecretService {
|
|||
// a webhook plugin based on the environment configuration.
|
||||
func provideWebhookPlugin(config spec.Config, system *core.System) core.WebhookSender {
|
||||
return webhook.New(webhook.Config{
|
||||
Events: config.Webhook.Events,
|
||||
Endpoint: config.Webhook.Endpoint,
|
||||
Secret: config.Webhook.Secret,
|
||||
System: system,
|
||||
|
|
|
@ -44,7 +44,7 @@ type (
|
|||
|
||||
// WebhookData provides the webhook data.
|
||||
WebhookData struct {
|
||||
Event string `json:"-"`
|
||||
Event string `json:"event"`
|
||||
Action string `json:"action"`
|
||||
User *User `json:"user,omitempty"`
|
||||
Repo *Repository `json:"repo,omitempty"`
|
||||
|
|
8
go.mod
8
go.mod
|
@ -16,7 +16,7 @@ require (
|
|||
github.com/docker/distribution v2.7.1+incompatible
|
||||
github.com/docker/go-connections v0.3.0
|
||||
github.com/docker/go-units v0.3.3
|
||||
github.com/drone/drone-go v1.0.5-0.20190427184118-618e4496482e
|
||||
github.com/drone/drone-go v1.0.5
|
||||
github.com/drone/drone-runtime v1.0.6
|
||||
github.com/drone/drone-ui v0.0.0-20190530175131-92ba3df1e0a9
|
||||
github.com/drone/drone-yaml v1.2.2-0.20190719012529-c50000a465ee
|
||||
|
@ -35,7 +35,7 @@ require (
|
|||
github.com/golang/mock v1.1.1
|
||||
github.com/golang/protobuf v1.2.0
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c
|
||||
github.com/google/go-cmp v0.2.0
|
||||
github.com/google/go-cmp v0.3.0
|
||||
github.com/google/go-jsonnet v0.12.1
|
||||
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf
|
||||
github.com/google/wire v0.2.1
|
||||
|
@ -43,7 +43,7 @@ require (
|
|||
github.com/gorhill/cronexpr v0.0.0-20140423231348-a557574d6c02
|
||||
github.com/gosimple/slug v1.3.0
|
||||
github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f
|
||||
github.com/h2non/gock v1.0.10
|
||||
github.com/h2non/gock v1.0.15
|
||||
github.com/hashicorp/errwrap v1.0.0
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0
|
||||
github.com/hashicorp/go-multierror v1.0.0
|
||||
|
@ -97,3 +97,5 @@ require (
|
|||
k8s.io/klog v0.1.0
|
||||
sigs.k8s.io/yaml v1.1.0
|
||||
)
|
||||
|
||||
replace github.com/h2non/gock => gopkg.in/h2non/gock.v1 v1.0.14
|
||||
|
|
6
go.sum
6
go.sum
|
@ -40,6 +40,8 @@ github.com/drone/drone-go v0.0.0-20190217024616-3e8b71333e59/go.mod h1:qVb1k1w9X
|
|||
github.com/drone/drone-go v1.0.4 h1:Yom1lix1Lmk3KmKIsBSQJF1bw0YR2lDGaFQrXxqHMko=
|
||||
github.com/drone/drone-go v1.0.5-0.20190427184118-618e4496482e h1:Z9dJNcs1IpyS52xsf5vjXMq7vSuBt48Il2dJgOzyCFM=
|
||||
github.com/drone/drone-go v1.0.5-0.20190427184118-618e4496482e/go.mod h1:GxyeGClYohaKNYJv/ZpsmVHtMJ7WhoT+uDaJNcDIrk4=
|
||||
github.com/drone/drone-go v1.0.5 h1:KCDzcPoz5yo5DC4sGcLl+6FsUYbCXjBj9d//b5WP5J0=
|
||||
github.com/drone/drone-go v1.0.5/go.mod h1:GxyeGClYohaKNYJv/ZpsmVHtMJ7WhoT+uDaJNcDIrk4=
|
||||
github.com/drone/drone-runtime v0.0.0-20190210191445-ad403a0ca24e h1:Eq0QI9lKe6T5pziU/Kes1xX6QKAA6ZfnYvaZZeyY5TU=
|
||||
github.com/drone/drone-runtime v0.0.0-20190210191445-ad403a0ca24e/go.mod h1:I+wJO4yvngCUAro6wKjkMbuPPDI/jRynqU0LTW+8J44=
|
||||
github.com/drone/drone-runtime v1.0.3 h1:0p7ASt0WXbLZRzMOw20e1ahV3YkamRhtZFkm8UvM+JA=
|
||||
|
@ -141,6 +143,7 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCy
|
|||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-jsonnet v0.12.1 h1:v0iUm/b4SBz7lR/diMoz9tLAz8lqtnNRKIwMrmU2HEU=
|
||||
github.com/google/go-jsonnet v0.12.1/go.mod h1:gVu3UVSfOt5fRFq+dh9duBqXa5905QY8S1QvMNcEIVs=
|
||||
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck=
|
||||
|
@ -158,6 +161,7 @@ github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f/go.mod h1:Fecb
|
|||
github.com/h2non/gock v1.0.9/go.mod h1:CZMcB0Lg5IWnr9bF79pPMg9WeV6WumxQiUJ1UvdO1iE=
|
||||
github.com/h2non/gock v1.0.10 h1:EzHYzKKSLN4xk0w193uAy3tp8I3+L1jmaI2Mjg4lCgU=
|
||||
github.com/h2non/gock v1.0.10/go.mod h1:CZMcB0Lg5IWnr9bF79pPMg9WeV6WumxQiUJ1UvdO1iE=
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig=
|
||||
|
@ -202,6 +206,7 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLD
|
|||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/natessilva/dag v0.0.0-20180124060714-7194b8dcc5c4 h1:dnMxwus89s86tI8rcGVp2HwZzlz7c5o92VOy7dSckBQ=
|
||||
github.com/natessilva/dag v0.0.0-20180124060714-7194b8dcc5c4/go.mod h1:cojhOHk1gbMeklOyDP2oKKLftefXoJreOQGOrXk+Z38=
|
||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
|
||||
|
@ -270,6 +275,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQ
|
|||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/h2non/gock.v1 v1.0.14/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
|
|
|
@ -18,6 +18,7 @@ import "github.com/drone/drone/core"
|
|||
|
||||
// Config provides the webhook configuration.
|
||||
type Config struct {
|
||||
Events []string
|
||||
Endpoint []string
|
||||
Secret string
|
||||
System *core.System
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
|
@ -34,6 +35,7 @@ var signer = httpsignatures.NewSigner(
|
|||
// New returns a new Webhook sender.
|
||||
func New(config Config) core.WebhookSender {
|
||||
return &sender{
|
||||
Events: config.Events,
|
||||
Endpoints: config.Endpoint,
|
||||
Secret: config.Secret,
|
||||
System: config.System,
|
||||
|
@ -47,6 +49,7 @@ type payload struct {
|
|||
|
||||
type sender struct {
|
||||
Client *http.Client
|
||||
Events []string
|
||||
Endpoints []string
|
||||
Secret string
|
||||
System *core.System
|
||||
|
@ -58,6 +61,9 @@ func (s *sender) Send(ctx context.Context, in *core.WebhookData) error {
|
|||
if len(s.Endpoints) == 0 {
|
||||
return nil
|
||||
}
|
||||
if s.match(in.Event, in.Action) == false {
|
||||
return nil
|
||||
}
|
||||
wrapper := payload{
|
||||
WebhookData: in,
|
||||
System: s.System,
|
||||
|
@ -96,6 +102,25 @@ func (s *sender) send(endpoint, secret, event string, data []byte) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (s *sender) match(event, action string) bool {
|
||||
if len(s.Events) == 0 {
|
||||
return true
|
||||
}
|
||||
var name string
|
||||
switch {
|
||||
case action == "":
|
||||
name = event
|
||||
case action != "":
|
||||
name = event + ":" + action
|
||||
}
|
||||
for _, pattern := range s.Events {
|
||||
if ok, _ := filepath.Match(pattern, name); ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *sender) client() *http.Client {
|
||||
if s.Client == nil {
|
||||
return http.DefaultClient
|
||||
|
|
|
@ -91,3 +91,73 @@ func TestWebhook_NoEndpoints(t *testing.T) {
|
|||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWebhook_NoMatch(t *testing.T) {
|
||||
webhook := &core.WebhookData{
|
||||
Event: core.WebhookEventUser,
|
||||
Action: core.WebhookActionCreated,
|
||||
User: &core.User{Login: "octocat"},
|
||||
}
|
||||
|
||||
config := Config{
|
||||
Events: []string{"repo:disabled"},
|
||||
Endpoint: []string{"https://localhost:1234"},
|
||||
Secret: "correct-horse-battery-staple",
|
||||
}
|
||||
sender := New(config)
|
||||
err := sender.Send(noContext, webhook)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWebhook_Match(t *testing.T) {
|
||||
tests := []struct {
|
||||
events []string
|
||||
event string
|
||||
action string
|
||||
matched bool
|
||||
}{
|
||||
{
|
||||
event: "repo",
|
||||
action: "enabled",
|
||||
matched: true,
|
||||
},
|
||||
{
|
||||
events: []string{"user", "repo"},
|
||||
event: "repo",
|
||||
matched: true,
|
||||
},
|
||||
{
|
||||
events: []string{"repo:disabled", "repo:enabled"},
|
||||
event: "repo",
|
||||
action: "enabled",
|
||||
matched: true,
|
||||
},
|
||||
{
|
||||
events: []string{"repo:disabled", "repo:*"},
|
||||
event: "repo",
|
||||
action: "enabled",
|
||||
matched: true,
|
||||
},
|
||||
{
|
||||
events: []string{"repo:disabled", "user:created"},
|
||||
event: "repo",
|
||||
action: "enabled",
|
||||
matched: false,
|
||||
},
|
||||
{
|
||||
events: []string{"repo", "user"},
|
||||
event: "repo",
|
||||
action: "enabled",
|
||||
matched: false,
|
||||
},
|
||||
}
|
||||
for i, test := range tests {
|
||||
s := new(sender)
|
||||
s.Events = test.events
|
||||
if s.match(test.event, test.action) != test.matched {
|
||||
t.Errorf("Expect matched %v at index %d", test.matched, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue