github.com/zppinho/prow@v0.0.0-20240510014325-1738badeb017/pkg/hook/hook_test.go (about)

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package hook
    18  
    19  import (
    20  	"encoding/json"
    21  	"net/http/httptest"
    22  	"testing"
    23  	"time"
    24  
    25  	"sigs.k8s.io/prow/pkg/bugzilla"
    26  	"sigs.k8s.io/prow/pkg/config"
    27  	"sigs.k8s.io/prow/pkg/github"
    28  	"sigs.k8s.io/prow/pkg/githubeventserver"
    29  	"sigs.k8s.io/prow/pkg/jira/fakejira"
    30  	"sigs.k8s.io/prow/pkg/phony"
    31  	"sigs.k8s.io/prow/pkg/plugins"
    32  	"sigs.k8s.io/prow/pkg/plugins/ownersconfig"
    33  	"sigs.k8s.io/prow/pkg/repoowners"
    34  )
    35  
    36  var ice = github.IssueCommentEvent{
    37  	Action: "reopened",
    38  	Repo: github.Repo{
    39  		Owner: github.User{
    40  			Login: "foo",
    41  		},
    42  		Name:     "bar",
    43  		FullName: "foo/bar",
    44  	},
    45  }
    46  
    47  var repoLevelSecret = `
    48  '*':
    49    - value: key1
    50      created_at: 2019-10-02T15:00:00Z
    51    - value: key2
    52      created_at: 2020-10-02T15:00:00Z
    53  foo/bar:
    54    - value: 123abc
    55      created_at: 2019-10-02T15:00:00Z
    56    - value: key6
    57      created_at: 2020-10-02T15:00:00Z
    58  `
    59  
    60  var orgLevelSecret = `
    61  '*':
    62    - value: key1
    63      created_at: 2019-10-02T15:00:00Z
    64    - value: key2
    65      created_at: 2020-10-02T15:00:00Z
    66  foo:
    67    - value: 123abc
    68      created_at: 2019-10-02T15:00:00Z
    69    - value: key4
    70      created_at: 2020-10-02T15:00:00Z
    71  `
    72  
    73  var globalSecret = `
    74  '*':
    75    - value: 123abc
    76      created_at: 2019-10-02T15:00:00Z
    77    - value: key2
    78      created_at: 2020-10-02T15:00:00Z
    79  `
    80  
    81  var missingMatchingSecret = `
    82  somerandom:
    83    - value: 123abc
    84      created_at: 2019-10-02T15:00:00Z
    85    - value: key2
    86      created_at: 2020-10-02T15:00:00Z
    87  `
    88  
    89  var secretInOldFormat = `123abc`
    90  
    91  // TestHook sets up a hook.Server and then sends a fake webhook at it. It then
    92  // ensures that a fake plugin is called.
    93  func TestHook(t *testing.T) {
    94  	called := make(chan bool, 1)
    95  	payload, err := json.Marshal(&ice)
    96  	if err != nil {
    97  		t.Fatalf("Marshalling ICE: %v", err)
    98  	}
    99  	plugins.RegisterIssueHandler(
   100  		"baz",
   101  		func(pc plugins.Agent, ie github.IssueEvent) error {
   102  			called <- true
   103  			return nil
   104  		},
   105  		nil,
   106  	)
   107  	pa := &plugins.ConfigAgent{}
   108  	pa.Set(&plugins.Configuration{Plugins: plugins.Plugins{"foo/bar": {Plugins: []string{"baz"}}}})
   109  	ca := &config.Agent{}
   110  	clientAgent := &plugins.ClientAgent{
   111  		GitHubClient:   github.NewFakeClient(),
   112  		OwnersClient:   repoowners.NewClient(nil, nil, func(org, repo string) bool { return false }, func(org, repo string) bool { return false }, func() *config.OwnersDirDenylist { return &config.OwnersDirDenylist{} }, ownersconfig.FakeResolver),
   113  		JiraClient:     &fakejira.FakeClient{},
   114  		BugzillaClient: &bugzilla.Fake{},
   115  	}
   116  	metrics := githubeventserver.NewMetrics()
   117  	var testcases = []struct {
   118  		name           string
   119  		secret         []byte
   120  		tokenGenerator func() []byte
   121  		shouldSucceed  bool
   122  	}{
   123  		{
   124  			name:   "Token present at repository level.",
   125  			secret: []byte("123abc"),
   126  			tokenGenerator: func() []byte {
   127  				return []byte(repoLevelSecret)
   128  			},
   129  			shouldSucceed: true,
   130  		},
   131  		{
   132  			name:   "Token present at org level.",
   133  			secret: []byte("123abc"),
   134  			tokenGenerator: func() []byte {
   135  				return []byte(orgLevelSecret)
   136  			},
   137  			shouldSucceed: true,
   138  		},
   139  		{
   140  			name:   "Token present at global level.",
   141  			secret: []byte("123abc"),
   142  			tokenGenerator: func() []byte {
   143  				return []byte(globalSecret)
   144  			},
   145  			shouldSucceed: true,
   146  		},
   147  		{
   148  			name:   "Token not matching anywhere (wildcard token missing).",
   149  			secret: []byte("123abc"),
   150  			tokenGenerator: func() []byte {
   151  				return []byte(missingMatchingSecret)
   152  			},
   153  			shouldSucceed: false,
   154  		},
   155  		{
   156  			name:   "Secret in old format.",
   157  			secret: []byte("123abc"),
   158  			tokenGenerator: func() []byte {
   159  				return []byte(secretInOldFormat)
   160  			},
   161  			shouldSucceed: true,
   162  		},
   163  	}
   164  
   165  	for _, tc := range testcases {
   166  		t.Logf("Running scenario %q", tc.name)
   167  
   168  		s := httptest.NewServer(&Server{
   169  			ClientAgent:    clientAgent,
   170  			Plugins:        pa,
   171  			ConfigAgent:    ca,
   172  			Metrics:        metrics,
   173  			RepoEnabled:    func(org, repo string) bool { return true },
   174  			TokenGenerator: tc.tokenGenerator,
   175  		})
   176  		defer s.Close()
   177  		if err := phony.SendHook(s.URL, "issues", payload, tc.secret); (err != nil) == tc.shouldSucceed {
   178  			t.Fatalf("Error sending hook: %v", err)
   179  		}
   180  	}
   181  
   182  	select {
   183  	case <-called: // All good.
   184  	case <-time.After(time.Second):
   185  		t.Error("Plugin not called after one second.")
   186  	}
   187  }