|
|
|
@ -81,6 +81,9 @@ type (
|
|
|
|
|
httpClient *http.Client
|
|
|
|
|
plainHTTP bool
|
|
|
|
|
err error // pass any errors from the ClientOption functions
|
|
|
|
|
|
|
|
|
|
// credentialsFileTemp captures if the empty file / EOF work around is being used.
|
|
|
|
|
credentialsFileTemp bool
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ClientOption allows specifying various settings configurable by the user for overriding the defaults
|
|
|
|
@ -115,11 +118,26 @@ func NewClient(options ...ClientOption) (*Client, error) {
|
|
|
|
|
}
|
|
|
|
|
store, err := credentials.NewStore(client.credentialsFile, storeOptions)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
// If the file exists and is empty there will be an EOF error. This error is not wrapped so
|
|
|
|
|
// a check with errors.Is will not work. The only way to capture it is an EOF error is
|
|
|
|
|
// with string parsing.
|
|
|
|
|
// This handling passes no file location which will cause NewStore to invoke its
|
|
|
|
|
// fault tolerance for a file not existing. A bool records this bypass so that if the
|
|
|
|
|
// credential store needs to be written to it this work around can be handled. See the
|
|
|
|
|
// Login method for more details.
|
|
|
|
|
if strings.Contains(err.Error(), "invalid config format: EOF") {
|
|
|
|
|
var err2 error
|
|
|
|
|
store, err2 = credentials.NewStore("", storeOptions)
|
|
|
|
|
if err2 != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
client.credentialsFileTemp = true
|
|
|
|
|
} else {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
dockerStore, err := credentials.NewStoreFromDocker(storeOptions)
|
|
|
|
|
if err != nil {
|
|
|
|
|
// should only fail if user home directory can't be determined
|
|
|
|
|
client.credentialsStore = store
|
|
|
|
|
} else {
|
|
|
|
|
// use Helm credentials with fallback to Docker
|
|
|
|
@ -284,6 +302,31 @@ func (c *Client) Login(host string, options ...LoginOption) error {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
key := credentials.ServerAddressFromRegistry(host)
|
|
|
|
|
|
|
|
|
|
// The credentialsStore loader does not handle empty files. So, there is a workaround.
|
|
|
|
|
// This can be removed when the credentials loader can handle empty files.
|
|
|
|
|
// When Helm catches an empty file error it causes the loader to trigger its fault
|
|
|
|
|
// tolerance for a file not existing and records it with a bool. If that bool is set and the
|
|
|
|
|
// file needs to be written, the file needs to be put into a usable state and loaded
|
|
|
|
|
// properly.
|
|
|
|
|
// See the NewClient function for the bypass setup.
|
|
|
|
|
if c.credentialsFileTemp {
|
|
|
|
|
err = os.WriteFile(c.credentialsFile, []byte("{}"), 0600)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
storeOptions := credentials.StoreOptions{
|
|
|
|
|
AllowPlaintextPut: true,
|
|
|
|
|
DetectDefaultNativeStore: true,
|
|
|
|
|
}
|
|
|
|
|
store, err := credentials.NewStore(c.credentialsFile, storeOptions)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
c.credentialsStore = store
|
|
|
|
|
c.credentialsFileTemp = false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := c.credentialsStore.Put(ctx, key, cred); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|