github.com/pdmccormick/importable-docker-buildx@v0.0.0-20240426161518-e47091289030/util/buildflags/cache.go (about)

     1  package buildflags
     2  
     3  import (
     4  	"context"
     5  	"encoding/csv"
     6  	"os"
     7  	"strings"
     8  
     9  	awsconfig "github.com/aws/aws-sdk-go-v2/config"
    10  	controllerapi "github.com/docker/buildx/controller/pb"
    11  	"github.com/pkg/errors"
    12  )
    13  
    14  func ParseCacheEntry(in []string) ([]*controllerapi.CacheOptionsEntry, error) {
    15  	outs := make([]*controllerapi.CacheOptionsEntry, 0, len(in))
    16  	for _, in := range in {
    17  		csvReader := csv.NewReader(strings.NewReader(in))
    18  		fields, err := csvReader.Read()
    19  		if err != nil {
    20  			return nil, err
    21  		}
    22  		if isRefOnlyFormat(fields) {
    23  			for _, field := range fields {
    24  				outs = append(outs, &controllerapi.CacheOptionsEntry{
    25  					Type:  "registry",
    26  					Attrs: map[string]string{"ref": field},
    27  				})
    28  			}
    29  			continue
    30  		}
    31  
    32  		out := controllerapi.CacheOptionsEntry{
    33  			Attrs: map[string]string{},
    34  		}
    35  		for _, field := range fields {
    36  			parts := strings.SplitN(field, "=", 2)
    37  			if len(parts) != 2 {
    38  				return nil, errors.Errorf("invalid value %s", field)
    39  			}
    40  			key := strings.ToLower(parts[0])
    41  			value := parts[1]
    42  			switch key {
    43  			case "type":
    44  				out.Type = value
    45  			default:
    46  				out.Attrs[key] = value
    47  			}
    48  		}
    49  		if out.Type == "" {
    50  			return nil, errors.Errorf("type required form> %q", in)
    51  		}
    52  		if !addGithubToken(&out) {
    53  			continue
    54  		}
    55  		addAwsCredentials(&out)
    56  		outs = append(outs, &out)
    57  	}
    58  	return outs, nil
    59  }
    60  
    61  func isRefOnlyFormat(in []string) bool {
    62  	for _, v := range in {
    63  		if strings.Contains(v, "=") {
    64  			return false
    65  		}
    66  	}
    67  	return true
    68  }
    69  
    70  func addGithubToken(ci *controllerapi.CacheOptionsEntry) bool {
    71  	if ci.Type != "gha" {
    72  		return true
    73  	}
    74  	if _, ok := ci.Attrs["token"]; !ok {
    75  		if v, ok := os.LookupEnv("ACTIONS_RUNTIME_TOKEN"); ok {
    76  			ci.Attrs["token"] = v
    77  		}
    78  	}
    79  	if _, ok := ci.Attrs["url"]; !ok {
    80  		if v, ok := os.LookupEnv("ACTIONS_CACHE_URL"); ok {
    81  			ci.Attrs["url"] = v
    82  		}
    83  	}
    84  	return ci.Attrs["token"] != "" && ci.Attrs["url"] != ""
    85  }
    86  
    87  func addAwsCredentials(ci *controllerapi.CacheOptionsEntry) {
    88  	if ci.Type != "s3" {
    89  		return
    90  	}
    91  	_, okAccessKeyID := ci.Attrs["access_key_id"]
    92  	_, okSecretAccessKey := ci.Attrs["secret_access_key"]
    93  	// If the user provides access_key_id, secret_access_key, do not override the session token.
    94  	if okAccessKeyID && okSecretAccessKey {
    95  		return
    96  	}
    97  	ctx := context.TODO()
    98  	awsConfig, err := awsconfig.LoadDefaultConfig(ctx)
    99  	if err != nil {
   100  		return
   101  	}
   102  	credentials, err := awsConfig.Credentials.Retrieve(ctx)
   103  	if err != nil {
   104  		return
   105  	}
   106  	if !okAccessKeyID && credentials.AccessKeyID != "" {
   107  		ci.Attrs["access_key_id"] = credentials.AccessKeyID
   108  	}
   109  	if !okSecretAccessKey && credentials.SecretAccessKey != "" {
   110  		ci.Attrs["secret_access_key"] = credentials.SecretAccessKey
   111  	}
   112  	if _, ok := ci.Attrs["session_token"]; !ok && credentials.SessionToken != "" {
   113  		ci.Attrs["session_token"] = credentials.SessionToken
   114  	}
   115  }