github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/creds/secret_var_lookup_rules.go (about)

     1  package creds
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"io/ioutil"
     7  	"text/template"
     8  	"text/template/parse"
     9  )
    10  
    11  // SecretLookupPath transforms variable name into full secret path
    12  type SecretLookupPath interface {
    13  	VariableToSecretPath(string) (string, error)
    14  }
    15  
    16  // SecretLookupWithPrefix is an implementation which returns [prefix][separator][varName]
    17  type SecretLookupWithPrefix struct {
    18  	Prefix string
    19  }
    20  
    21  func NewSecretLookupWithPrefix(prefix string) SecretLookupPath {
    22  	return &SecretLookupWithPrefix{
    23  		Prefix: prefix,
    24  	}
    25  }
    26  
    27  func (sl SecretLookupWithPrefix) VariableToSecretPath(path string) (string, error) {
    28  	return sl.Prefix + path, nil
    29  }
    30  
    31  // SecretLookupWithTemplate uses the given template to construct a lookup path specific
    32  // to a team and (optionally) pipeline
    33  type SecretTemplate struct {
    34  	*template.Template
    35  	pipelineDependent bool
    36  }
    37  
    38  type SecretLookupWithTemplate struct {
    39  	PathTemplate *SecretTemplate
    40  	TeamName     string
    41  	PipelineName string
    42  }
    43  
    44  func BuildSecretTemplate(name, tmpl string) (*SecretTemplate, error) {
    45  	t, err := template.New(name).Option("missingkey=error").Parse(tmpl)
    46  	if err != nil {
    47  		return nil, err
    48  	}
    49  
    50  	if parse.IsEmptyTree(t.Root) {
    51  		return nil, errors.New("secret template should not be empty")
    52  	}
    53  
    54  	// Validate that the template only consumes the expected keys
    55  	dummy := struct{ Team, Pipeline, Secret string }{"team", "pipeline", "secret"}
    56  	if err = t.Execute(ioutil.Discard, &dummy); err != nil {
    57  		return nil, err
    58  	}
    59  
    60  	// Detect whether this template requires "Pipeline", and therefore
    61  	// should only be expanded when there is a pipeline context
    62  	pipelineDependent := false
    63  	dummyNoPipeline := struct{ Team, Secret string }{"team", "secret"}
    64  	if t.Execute(ioutil.Discard, &dummyNoPipeline) != nil {
    65  		pipelineDependent = true
    66  	}
    67  
    68  	return &SecretTemplate{t, pipelineDependent}, nil
    69  }
    70  
    71  func NewSecretLookupWithTemplate(pathTemplate *SecretTemplate, teamName string, pipelineName string) SecretLookupPath {
    72  	if pathTemplate.pipelineDependent && len(pipelineName) == 0 {
    73  		return nil
    74  	}
    75  
    76  	return &SecretLookupWithTemplate{
    77  		PathTemplate: pathTemplate,
    78  		TeamName:     teamName,
    79  		PipelineName: pipelineName,
    80  	}
    81  }
    82  
    83  func (sl SecretLookupWithTemplate) VariableToSecretPath(path string) (string, error) {
    84  	var buf bytes.Buffer
    85  	data := struct {
    86  		Team     string
    87  		Pipeline string
    88  		Secret   string
    89  	}{
    90  		sl.TeamName,
    91  		sl.PipelineName,
    92  		path,
    93  	}
    94  
    95  	err := sl.PathTemplate.Execute(&buf, &data)
    96  	return buf.String(), err
    97  }