From 79abe19b7db68200028b340964be07fa65a7a82a Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Tue, 11 Mar 2025 15:04:18 -0500 Subject: [PATCH] feat: add secret values to masked outputs (#465) * feat: add secret values to masked outputs * t.setenv --------- Co-authored-by: ecrupper --- cmd/secret-vault/read.go | 41 +++++++++++++++++++++++++++++++++++ cmd/secret-vault/read_test.go | 33 ++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/cmd/secret-vault/read.go b/cmd/secret-vault/read.go index 9ef677f..e6363f0 100644 --- a/cmd/secret-vault/read.go +++ b/cmd/secret-vault/read.go @@ -3,14 +3,17 @@ package main import ( + "bytes" "encoding/json" "errors" "fmt" + "os" "path/filepath" "strings" "github.com/go-vela/secret-vault/vault" "github.com/go-vela/types/raw" + "github.com/joho/godotenv" "github.com/sirupsen/logrus" "github.com/spf13/afero" ) @@ -66,6 +69,24 @@ func (r *Read) Exec(v *vault.Client) error { Fs: appFS, } + var outputs map[string]string + + outputsPath := os.Getenv("VELA_MASKED_OUTPUTS") + + // if the masked Vela outputs is configured, create a map to store the values to write later + if len(outputsPath) > 0 { + rawOutputs, err := a.ReadFile(outputsPath) + if err != nil { + logrus.Debugf("empty masked outputs file. creating one...") + } + + // godotenv has a Read, but for testing it will not read a memory map FS + outputs, err = godotenv.Parse(bytes.NewReader(rawOutputs)) + if err != nil { + return err + } + } + for _, item := range r.Items { for _, pth := range item.Path { // remove any leading slashes from path @@ -109,10 +130,30 @@ func (r *Read) Exec(v *vault.Client) error { if err != nil { return err } + + if len(outputsPath) > 0 { + // create key of VELA_SECRETS__ + envKey := strings.ReplaceAll(strings.ToUpper(strings.TrimPrefix(path, "/")), "/", "_") + + outputs[envKey] = v.(string) + } } } } + if len(outputsPath) > 0 { + // godotenv has a Write, but for testing it will not write to a memory map FS + content, err := godotenv.Marshal(outputs) + if err != nil { + return err + } + + err = a.WriteFile(outputsPath, []byte(content), 0600) + if err != nil { + return err + } + } + return nil } diff --git a/cmd/secret-vault/read_test.go b/cmd/secret-vault/read_test.go index ea68136..ddfaf79 100644 --- a/cmd/secret-vault/read_test.go +++ b/cmd/secret-vault/read_test.go @@ -3,10 +3,13 @@ package main import ( + "bytes" + "path/filepath" "reflect" "testing" "github.com/go-vela/secret-vault/vault" + "github.com/joho/godotenv" "github.com/spf13/afero" ) @@ -44,6 +47,36 @@ func TestVault_Read_Exec(t *testing.T) { if err != nil { t.Errorf("Exec returned err: %v", err) } + + t.Setenv("VELA_MASKED_OUTPUTS", "/vela/outputs/masked.env") + + err = appFS.MkdirAll(filepath.Dir("/vela/outputs/masked.env"), 0777) + if err != nil { + t.Error(err) + } + + err = r.Exec(vault) + if err != nil { + t.Errorf("Exec returned err: %v", err) + } + + a := &afero.Afero{ + Fs: appFS, + } + + rawOutputs, err := a.ReadFile("/vela/outputs/masked.env") + if err != nil { + t.Errorf("unable to read outputs file: %v", err) + } + + envMap, err := godotenv.Parse(bytes.NewReader(rawOutputs)) + if err != nil { + t.Errorf("unable to parse outputs file: %v", err) + } + + if envMap["VELA_SECRETS_FOOBAR_MY_SECRET"] != "bar" { + t.Errorf("Exec is %v, want %v", envMap["foobar_foobar2_secret"], "bar") + } } func TestVault_Read_Exec_Fail(t *testing.T) {