...

Source file src/github.com/sigstore/cosign/v2/pkg/providers/github/github.go

Documentation: github.com/sigstore/cosign/v2/pkg/providers/github

     1  //
     2  // Copyright 2021 The Sigstore 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  package github
    17  
    18  import (
    19  	"context"
    20  	"encoding/json"
    21  	"fmt"
    22  	"net/http"
    23  	"os"
    24  	"strings"
    25  	"time"
    26  
    27  	"github.com/sigstore/cosign/v2/pkg/cosign/env"
    28  	"github.com/sigstore/cosign/v2/pkg/providers"
    29  )
    30  
    31  const (
    32  	// Deprecated: use `env.VariableGitHubRequestToken` instead
    33  	RequestTokenEnvKey = env.VariableGitHubRequestToken
    34  	// Deprecated: use `env.VariableGitHubRequestURL` instead
    35  	RequestURLEnvKey = env.VariableGitHubRequestURL
    36  )
    37  
    38  func init() {
    39  	providers.Register("github-actions", &githubActions{})
    40  }
    41  
    42  type githubActions struct{}
    43  
    44  var _ providers.Interface = (*githubActions)(nil)
    45  
    46  // Enabled implements providers.Interface
    47  func (ga *githubActions) Enabled(_ context.Context) bool {
    48  	if env.Getenv(env.VariableGitHubRequestToken) == "" {
    49  		return false
    50  	}
    51  	if env.Getenv(env.VariableGitHubRequestURL) == "" {
    52  		return false
    53  	}
    54  	return true
    55  }
    56  
    57  // Provide implements providers.Interface
    58  func (ga *githubActions) Provide(ctx context.Context, audience string) (string, error) {
    59  	url := env.Getenv(env.VariableGitHubRequestURL) + "&audience=" + audience
    60  
    61  	req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
    62  	if err != nil {
    63  		return "", err
    64  	}
    65  
    66  	// May be replaced by a different client if we hit HTTP_1_1_REQUIRED.
    67  	client := http.DefaultClient
    68  
    69  	// Retry up to 3 times.
    70  	for i := 0; ; i++ {
    71  		req.Header.Add("Authorization", "bearer "+env.Getenv(env.VariableGitHubRequestToken))
    72  		resp, err := client.Do(req)
    73  		if err != nil {
    74  			if i == 2 {
    75  				return "", err
    76  			}
    77  
    78  			// This error isn't exposed by net/http, and retrying this with the
    79  			// DefaultClient will fail because it will just use HTTP2 again.
    80  			// I don't know why go doesn't do this for us.
    81  			if strings.Contains(err.Error(), "HTTP_1_1_REQUIRED") {
    82  				http1transport := http.DefaultTransport.(*http.Transport).Clone()
    83  				http1transport.ForceAttemptHTTP2 = false
    84  
    85  				client = &http.Client{
    86  					Transport: http1transport,
    87  				}
    88  			}
    89  
    90  			fmt.Fprintf(os.Stderr, "error fetching GitHub OIDC token (will retry): %v\n", err)
    91  			time.Sleep(time.Second)
    92  			continue
    93  		}
    94  		defer resp.Body.Close()
    95  
    96  		var payload struct {
    97  			Value string `json:"value"`
    98  		}
    99  		decoder := json.NewDecoder(resp.Body)
   100  		if err := decoder.Decode(&payload); err != nil {
   101  			return "", err
   102  		}
   103  		return payload.Value, nil
   104  	}
   105  }
   106  

View as plain text