github.com/drone/runner-go@v1.12.0/secret/external.go (about) 1 // Copyright 2019 Drone.IO Inc. All rights reserved. 2 // Use of this source code is governed by the Polyform License 3 // that can be found in the LICENSE file. 4 5 package secret 6 7 import ( 8 "context" 9 "time" 10 11 "github.com/drone/runner-go/logger" 12 "github.com/drone/runner-go/manifest" 13 14 "github.com/drone/drone-go/drone" 15 "github.com/drone/drone-go/plugin/secret" 16 ) 17 18 // External returns a new external secret provider. The 19 // external secret provider makes an external API call to find 20 // and return a named secret. 21 func External(endpoint, token string, insecure bool) Provider { 22 provider := &external{} 23 if endpoint != "" { 24 provider.client = secret.Client(endpoint, token, insecure) 25 } 26 return provider 27 } 28 29 type external struct { 30 client secret.Plugin 31 } 32 33 func (p *external) Find(ctx context.Context, in *Request) (*drone.Secret, error) { 34 if p.client == nil { 35 return nil, nil 36 } 37 38 logger := logger.FromContext(ctx). 39 WithField("name", in.Name). 40 WithField("kind", "secret") 41 42 // lookup the named secret in the manifest. If the 43 // secret does not exist, return a nil variable, 44 // allowing the next secret controller in the chain 45 // to be invoked. 46 path, name, ok := getExternal(in.Conf, in.Name) 47 if !ok { 48 logger.Trace("secret: external: no matching secret") 49 return nil, nil 50 } 51 52 // include a timeout to prevent an API call from 53 // hanging the build process indefinitely. The 54 // external service must return a request within 55 // one minute. 56 ctx, cancel := context.WithTimeout(ctx, time.Minute) 57 defer cancel() 58 59 req := &secret.Request{ 60 Name: name, 61 Path: path, 62 Repo: *in.Repo, 63 Build: *in.Build, 64 } 65 res, err := p.client.Find(ctx, req) 66 if err != nil { 67 logger.WithError(err).Debug("secret: external: cannot get secret") 68 return nil, err 69 } 70 71 // if no error is returned and the secret is empty, 72 // this indicates the client returned No Content, 73 // and we should exit with no secret, but no error. 74 if res.Data == "" { 75 logger.Trace("secret: external: secret is empty") 76 return nil, nil 77 } 78 79 logger.Trace("secret: external: found matching secret") 80 81 return &drone.Secret{ 82 Name: in.Name, 83 Data: res.Data, 84 PullRequest: res.Pull, 85 }, nil 86 } 87 88 func getExternal(spec *manifest.Manifest, match string) (path, name string, ok bool) { 89 for _, resource := range spec.Resources { 90 secret, ok := resource.(*manifest.Secret) 91 if !ok { 92 continue 93 } 94 if secret.Name != match { 95 continue 96 } 97 if secret.Get.Name == "" && secret.Get.Path == "" { 98 continue 99 } 100 return secret.Get.Path, secret.Get.Name, true 101 } 102 return 103 }