github.com/google/osv-scalibr@v0.4.1/veles/secrets/gitbasicauth/codecatalyst/validator_test.go (about)

     1  // Copyright 2025 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package codecatalyst_test
    16  
    17  import (
    18  	"context"
    19  	"net/http"
    20  	"net/http/httptest"
    21  	"net/url"
    22  	"strings"
    23  	"testing"
    24  
    25  	"github.com/google/go-cmp/cmp"
    26  	"github.com/google/go-cmp/cmp/cmpopts"
    27  	"github.com/google/osv-scalibr/veles"
    28  	"github.com/google/osv-scalibr/veles/secrets/gitbasicauth/codecatalyst"
    29  )
    30  
    31  var (
    32  	validatorTestURL         = "https://user:pat@git.region.codecatalyst.aws/v1/space/project/repo"
    33  	validatorTestBadCredsURL = "https://user:bad_pat@git.region.codecatalyst.aws/v1/space/project/repo"
    34  	validatorTestBadRepoURL  = "https://user:pat@git.region.codecatalyst.aws/v1/space/project/bad-repo"
    35  )
    36  
    37  type redirectTransport struct {
    38  	url string
    39  }
    40  
    41  func (t *redirectTransport) RoundTrip(req *http.Request) (*http.Response, error) {
    42  	if strings.HasSuffix(req.URL.Host, ".codecatalyst.aws") {
    43  		newURL, err := url.Parse(t.url)
    44  		if err != nil {
    45  			return nil, err
    46  		}
    47  		req.URL.Scheme = newURL.Scheme
    48  		req.URL.Host = newURL.Host
    49  	}
    50  	return http.DefaultTransport.RoundTrip(req)
    51  }
    52  
    53  func mockCodeCatalystHandler(t *testing.T, status int) http.HandlerFunc {
    54  	t.Helper()
    55  	return func(w http.ResponseWriter, r *http.Request) {
    56  		if r.Method != http.MethodGet {
    57  			t.Errorf("r.Method = %s, want %s", r.Method, http.MethodGet)
    58  		}
    59  		auth := r.Header.Get("Authorization")
    60  		if !strings.HasPrefix(auth, "Basic") {
    61  			t.Errorf("should use basic auth")
    62  		}
    63  		if status == 200 {
    64  			w.WriteHeader(status)
    65  			return
    66  		}
    67  		w.WriteHeader(status)
    68  		_, _ = w.Write([]byte(`<InvalidRequestException>
    69    <Message>The resource either does not exist, or you don’t have permission to access it.</Message>
    70  </InvalidRequestException>`))
    71  	}
    72  }
    73  
    74  func TestValidator(t *testing.T) {
    75  	cancelledContext, cancel := context.WithCancel(t.Context())
    76  	cancel()
    77  
    78  	cases := []struct {
    79  		//nolint:containedctx
    80  		ctx        context.Context
    81  		name       string
    82  		url        string
    83  		httpStatus int
    84  		want       veles.ValidationStatus
    85  		wantErr    error
    86  	}{
    87  		{
    88  			name:       "cancelled_context",
    89  			url:        validatorTestURL,
    90  			want:       veles.ValidationFailed,
    91  			ctx:        cancelledContext,
    92  			httpStatus: http.StatusOK,
    93  			wantErr:    cmpopts.AnyError,
    94  		},
    95  		{
    96  			name:       "valid_credentials",
    97  			url:        validatorTestURL,
    98  			httpStatus: http.StatusOK,
    99  			want:       veles.ValidationValid,
   100  		},
   101  		{
   102  			name:       "invalid_creds",
   103  			url:        validatorTestBadCredsURL,
   104  			httpStatus: http.StatusBadRequest,
   105  			want:       veles.ValidationInvalid,
   106  		},
   107  		{
   108  			name:       "bad_repository",
   109  			url:        validatorTestBadRepoURL,
   110  			httpStatus: http.StatusBadRequest,
   111  			want:       veles.ValidationInvalid,
   112  		},
   113  	}
   114  
   115  	for _, tt := range cases {
   116  		t.Run(tt.name, func(t *testing.T) {
   117  			if tt.ctx == nil {
   118  				tt.ctx = t.Context()
   119  			}
   120  			server := httptest.NewServer(mockCodeCatalystHandler(t, tt.httpStatus))
   121  			defer server.Close()
   122  
   123  			client := &http.Client{
   124  				Transport: &redirectTransport{
   125  					url: server.URL,
   126  				},
   127  			}
   128  
   129  			v := codecatalyst.NewValidator()
   130  			v.HTTPC = client
   131  
   132  			got, err := v.Validate(tt.ctx, codecatalyst.Credentials{FullURL: tt.url})
   133  
   134  			if !cmp.Equal(tt.wantErr, err, cmpopts.EquateErrors()) {
   135  				t.Fatalf("Validate() error: %v, want %v", err, tt.wantErr)
   136  			}
   137  
   138  			if diff := cmp.Diff(tt.want, got); diff != "" {
   139  				t.Errorf("v.Validate() returned diff (-want +got):\n%s", diff)
   140  			}
   141  		})
   142  	}
   143  }