You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
runner-go/secret/external.go

104 lines
2.5 KiB
Go

// Copyright 2019 Drone.IO Inc. All rights reserved.
// Use of this source code is governed by the Polyform License
// that can be found in the LICENSE file.
package secret
import (
"context"
"time"
"git.awesome-for.me/liuzhiguo/runner-go/logger"
"git.awesome-for.me/liuzhiguo/runner-go/manifest"
"git.awesome-for.me/liuzhiguo/drone-go/drone"
"git.awesome-for.me/liuzhiguo/drone-go/plugin/secret"
)
// External returns a new external secret provider. The
// external secret provider makes an external API call to find
// and return a named secret.
func External(endpoint, token string, insecure bool) Provider {
provider := &external{}
if endpoint != "" {
provider.client = secret.Client(endpoint, token, insecure)
}
return provider
}
type external struct {
client secret.Plugin
}
func (p *external) Find(ctx context.Context, in *Request) (*drone.Secret, error) {
if p.client == nil {
return nil, nil
}
logger := logger.FromContext(ctx).
WithField("name", in.Name).
WithField("kind", "secret")
// lookup the named secret in the manifest. If the
// secret does not exist, return a nil variable,
// allowing the next secret controller in the chain
// to be invoked.
path, name, ok := getExternal(in.Conf, in.Name)
if !ok {
logger.Trace("secret: external: no matching secret")
return nil, nil
}
// include a timeout to prevent an API call from
// hanging the build process indefinitely. The
// external service must return a request within
// one minute.
ctx, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()
req := &secret.Request{
Name: name,
Path: path,
Repo: *in.Repo,
Build: *in.Build,
}
res, err := p.client.Find(ctx, req)
if err != nil {
logger.WithError(err).Debug("secret: external: cannot get secret")
return nil, err
}
// if no error is returned and the secret is empty,
// this indicates the client returned No Content,
// and we should exit with no secret, but no error.
if res.Data == "" {
logger.Trace("secret: external: secret is empty")
return nil, nil
}
logger.Trace("secret: external: found matching secret")
return &drone.Secret{
Name: in.Name,
Data: res.Data,
PullRequest: res.Pull,
}, nil
}
func getExternal(spec *manifest.Manifest, match string) (path, name string, ok bool) {
for _, resource := range spec.Resources {
secret, ok := resource.(*manifest.Secret)
if !ok {
continue
}
if secret.Name != match {
continue
}
if secret.Get.Name == "" && secret.Get.Path == "" {
continue
}
return secret.Get.Path, secret.Get.Name, true
}
return
}