oras.land/oras-go/v2@v2.5.1-0.20240520045656-aef90e4d04c4/registry/remote/credentials/internal/executer/executer.go (about) 1 /* 2 Copyright The ORAS Authors. 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 16 // Package executer is an abstraction for the docker credential helper protocol 17 // binaries. It is used by nativeStore to interact with installed binaries. 18 package executer 19 20 import ( 21 "bytes" 22 "context" 23 "errors" 24 "io" 25 "os" 26 "os/exec" 27 28 "oras.land/oras-go/v2/registry/remote/credentials/trace" 29 ) 30 31 // dockerDesktopHelperName is the name of the docker credentials helper 32 // execuatable. 33 const dockerDesktopHelperName = "docker-credential-desktop.exe" 34 35 // Executer is an interface that simulates an executable binary. 36 type Executer interface { 37 Execute(ctx context.Context, input io.Reader, action string) ([]byte, error) 38 } 39 40 // executable implements the Executer interface. 41 type executable struct { 42 name string 43 } 44 45 // New returns a new Executer instance. 46 func New(name string) Executer { 47 return &executable{ 48 name: name, 49 } 50 } 51 52 // Execute operates on an executable binary and supports context. 53 func (c *executable) Execute(ctx context.Context, input io.Reader, action string) ([]byte, error) { 54 cmd := exec.CommandContext(ctx, c.name, action) 55 cmd.Stdin = input 56 cmd.Stderr = os.Stderr 57 trace := trace.ContextExecutableTrace(ctx) 58 if trace != nil && trace.ExecuteStart != nil { 59 trace.ExecuteStart(c.name, action) 60 } 61 output, err := cmd.Output() 62 if trace != nil && trace.ExecuteDone != nil { 63 trace.ExecuteDone(c.name, action, err) 64 } 65 if err != nil { 66 switch execErr := err.(type) { 67 case *exec.ExitError: 68 if errMessage := string(bytes.TrimSpace(output)); errMessage != "" { 69 return nil, errors.New(errMessage) 70 } 71 case *exec.Error: 72 // check if the error is caused by Docker Desktop not running 73 if execErr.Err == exec.ErrNotFound && c.name == dockerDesktopHelperName { 74 return nil, errors.New("credentials store is configured to `desktop.exe` but Docker Desktop seems not running") 75 } 76 } 77 return nil, err 78 } 79 return output, nil 80 }