mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-12-27 02:40:30 +00:00
Get secrets in settings (#604)
* Get secrets in settings Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add error test Signed-off-by: jolheiser <john.olheiser@gmail.com> * Add docs Signed-off-by: jolheiser <john.olheiser@gmail.com>
This commit is contained in:
parent
3bee9044f1
commit
9e8d1a9294
4 changed files with 80 additions and 6 deletions
|
@ -14,6 +14,21 @@ pipeline:
|
|||
+ secrets: [ docker_username, docker_password ]
|
||||
```
|
||||
|
||||
Alternatively, you can get a `setting` from secrets using the `from_secret` syntax.
|
||||
In this example, the secret named `secret_token` would be passed to the pipeline as `PLUGIN_TOKEN`.
|
||||
|
||||
**NOTE:** the `from_secret` syntax only works with the newer `settings` block.
|
||||
|
||||
```diff
|
||||
pipeline:
|
||||
docker:
|
||||
image: my-plugin
|
||||
settings:
|
||||
+ token:
|
||||
+ from_secret: secret_token
|
||||
```
|
||||
|
||||
|
||||
Please note parameter expressions are subject to pre-processing. When using secrets in parameter expressions they should be escaped.
|
||||
|
||||
```diff
|
||||
|
|
|
@ -72,7 +72,7 @@ func (c *Compiler) createProcess(name string, container *yaml.Container, section
|
|||
}
|
||||
|
||||
if !detached {
|
||||
if err := paramsToEnv(container.Settings, environment); err != nil {
|
||||
if err := paramsToEnv(container.Settings, environment, c.secrets); err != nil {
|
||||
log.Error().Err(err).Msg("paramsToEnv")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
|
||||
// paramsToEnv uses reflection to convert a map[string]interface to a list
|
||||
// of environment variables.
|
||||
func paramsToEnv(from map[string]interface{}, to map[string]string) (err error) {
|
||||
func paramsToEnv(from map[string]interface{}, to map[string]string, secrets map[string]Secret) (err error) {
|
||||
if to == nil {
|
||||
return fmt.Errorf("no map to write to")
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ func paramsToEnv(from map[string]interface{}, to map[string]string) (err error)
|
|||
if v == nil || len(k) == 0 {
|
||||
continue
|
||||
}
|
||||
to[sanitizeParamKey(k)], err = sanitizeParamValue(v)
|
||||
to[sanitizeParamKey(k)], err = sanitizeParamValue(v, secrets)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ func isComplex(t reflect.Kind) bool {
|
|||
}
|
||||
}
|
||||
|
||||
func sanitizeParamValue(v interface{}) (string, error) {
|
||||
func sanitizeParamValue(v interface{}, secrets map[string]Secret) (string, error) {
|
||||
t := reflect.TypeOf(v)
|
||||
vv := reflect.ValueOf(v)
|
||||
|
||||
|
@ -66,6 +66,16 @@ func sanitizeParamValue(v interface{}) (string, error) {
|
|||
return fmt.Sprintf("%v", vv.Float()), nil
|
||||
|
||||
case reflect.Map:
|
||||
if fromSecret, ok := v.(map[string]interface{}); ok {
|
||||
if secretNameI, ok := fromSecret["from_secret"]; ok {
|
||||
if secretName, ok := secretNameI.(string); ok {
|
||||
if secret, ok := secrets[secretName]; ok {
|
||||
return secret.Value, nil
|
||||
}
|
||||
return "", fmt.Errorf("no secret found for %q", secretName)
|
||||
}
|
||||
}
|
||||
}
|
||||
ymlOut, _ := yaml.Marshal(vv.Interface())
|
||||
out, _ := yml.ToJSON(ymlOut)
|
||||
return string(out), nil
|
||||
|
@ -78,7 +88,7 @@ func sanitizeParamValue(v interface{}) (string, error) {
|
|||
in := make([]string, vv.Len())
|
||||
for i := 0; i < vv.Len(); i++ {
|
||||
var err error
|
||||
if in[i], err = sanitizeParamValue(vv.Index(i).Interface()); err != nil {
|
||||
if in[i], err = sanitizeParamValue(vv.Index(i).Interface(), secrets); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func TestParamsToEnv(t *testing.T) {
|
||||
|
@ -20,6 +21,7 @@ func TestParamsToEnv(t *testing.T) {
|
|||
"from.address": "noreply@example.com",
|
||||
"tags": stringsToInterface("next", "latest"),
|
||||
"tag": stringsToInterface("next"),
|
||||
"my_secret": map[string]interface{}{"from_secret": "secret_token"},
|
||||
}
|
||||
want := map[string]string{
|
||||
"PLUGIN_STRING": "stringz",
|
||||
|
@ -33,12 +35,59 @@ func TestParamsToEnv(t *testing.T) {
|
|||
"PLUGIN_FROM_ADDRESS": "noreply@example.com",
|
||||
"PLUGIN_TAG": "next",
|
||||
"PLUGIN_TAGS": "next,latest",
|
||||
"PLUGIN_MY_SECRET": "FooBar",
|
||||
}
|
||||
secrets := map[string]Secret{
|
||||
"secret_token": {Name: "secret_token", Value: "FooBar", Match: nil},
|
||||
}
|
||||
got := map[string]string{}
|
||||
assert.NoError(t, paramsToEnv(from, got))
|
||||
assert.NoError(t, paramsToEnv(from, got, secrets))
|
||||
assert.EqualValues(t, want, got, "Problem converting plugin parameters to environment variables")
|
||||
}
|
||||
|
||||
func TestYAMLToParamsToEnv(t *testing.T) {
|
||||
fromYAML := []byte(`skip: ~
|
||||
string: stringz
|
||||
int: 1
|
||||
float: 1.2
|
||||
bool: true
|
||||
slice: [1, 2, 3]
|
||||
my_secret:
|
||||
from_secret: secret_token
|
||||
`)
|
||||
var from map[string]interface{}
|
||||
err := yaml.Unmarshal(fromYAML, &from)
|
||||
assert.NoError(t, err)
|
||||
|
||||
want := map[string]string{
|
||||
"PLUGIN_STRING": "stringz",
|
||||
"PLUGIN_INT": "1",
|
||||
"PLUGIN_FLOAT": "1.2",
|
||||
"PLUGIN_BOOL": "true",
|
||||
"PLUGIN_SLICE": "1,2,3",
|
||||
"PLUGIN_MY_SECRET": "FooBar",
|
||||
}
|
||||
secrets := map[string]Secret{
|
||||
"secret_token": {Name: "secret_token", Value: "FooBar", Match: nil},
|
||||
}
|
||||
got := map[string]string{}
|
||||
assert.NoError(t, paramsToEnv(from, got, secrets))
|
||||
assert.EqualValues(t, want, got, "Problem converting plugin parameters to environment variables")
|
||||
}
|
||||
|
||||
func TestYAMLToParamsToEnvError(t *testing.T) {
|
||||
fromYAML := []byte(`my_secret:
|
||||
from_secret: not_a_secret
|
||||
`)
|
||||
var from map[string]interface{}
|
||||
err := yaml.Unmarshal(fromYAML, &from)
|
||||
assert.NoError(t, err)
|
||||
secrets := map[string]Secret{
|
||||
"secret_token": {Name: "secret_token", Value: "FooBar", Match: nil},
|
||||
}
|
||||
assert.Error(t, paramsToEnv(from, make(map[string]string), secrets))
|
||||
}
|
||||
|
||||
func stringsToInterface(val ...string) []interface{} {
|
||||
res := make([]interface{}, len(val))
|
||||
for i := range val {
|
||||
|
|
Loading…
Reference in a new issue