diff --git a/assets/export.tmpl b/assets/export.tmpl new file mode 100644 index 00000000..1a703990 --- /dev/null +++ b/assets/export.tmpl @@ -0,0 +1,5 @@ +{{- range $path, $secrets := . }} +{{- range $key, $value := $secrets }} +export {{ list $path $key | join "/" | replace "/" "_" | upper | trimPrefix "SECRET_" }}={{ $value | squote -}} +{{ end -}} +{{- end }} diff --git a/cmd/export.go b/cmd/export.go index 3f28e0ed..c30bf320 100644 --- a/cmd/export.go +++ b/cmd/export.go @@ -155,6 +155,7 @@ func (o *exportOptions) validateFlags(cmd *cobra.Command, args []string) error { o.outputFormat = prt.Template o.OnlyKeys = false o.OnlyPaths = false + o.ShowValues = true o.MaxValueLength = -1 if o.TemplateFile != "" && o.TemplateString != "" { diff --git a/cmd/import.go b/cmd/import.go index a058a26c..4d14cbe0 100644 --- a/cmd/import.go +++ b/cmd/import.go @@ -173,7 +173,7 @@ func (o *importOptions) parseInput(input []byte) (map[string]interface{}, error) func (o *importOptions) writeSecrets(secrets map[string]interface{}) error { transformedMap := make(map[string]interface{}) - utils.TransformMap(secrets, transformedMap, "") + utils.FlattenMap(secrets, transformedMap, "") for p, m := range transformedMap { secrets, ok := m.(map[string]interface{}) diff --git a/cmd/snapshot_restore.go b/cmd/snapshot_restore.go index 223d0315..00d23bc1 100644 --- a/cmd/snapshot_restore.go +++ b/cmd/snapshot_restore.go @@ -122,7 +122,7 @@ func (o *snapshotRestoreOptions) restoreSecrets(source string) error { func (o *snapshotRestoreOptions) writeSecrets(secrets map[string]interface{}, v *vault.Vault, ns, rootPath string) error { transformedMap := make(map[string]interface{}) - utils.TransformMap(secrets, transformedMap, "") + utils.FlattenMap(secrets, transformedMap, "") for p, m := range transformedMap { secrets, ok := m.(map[string]interface{}) diff --git a/docs/export.md b/docs/export.md index 856c3c5a..d00593ea 100644 --- a/docs/export.md +++ b/docs/export.md @@ -1,7 +1,7 @@ # Export `vkv export` requires an engine path (`--path` or `--engine-path`) and supports the following export formats (specify via `--format` flag). -See the [CLI Reference](https://github.com/FalcoSuessgott/vkv/cmd/vkv_export/) for more details on the supported flags and env vars. +See the [CLI Reference](https://falcosuessgott.github.io/vkv/cmd/vkv_export/) for more details on the supported flags and env vars. ## base ```bash @@ -89,7 +89,7 @@ echo $admin key ``` -### policy +## policy ```bash > vkv export -p secret -f=policy PATH CREATE READ UPDATE DELETE LIST ROOT @@ -99,7 +99,7 @@ secret/demo ✖ ✖ ✖ ✖ ✖ ✔ secret/sub/demo ✖ ✖ ✖ ✖ ✖ ✔ ``` -### markdown +## markdown ```bash > vkv export -p secret -f=markdown | PATH | KEY | VALUE | VERSION | METADATA | @@ -114,3 +114,41 @@ secret/sub/demo ✖ ✖ ✖ ✖ ✖ ✔ | | password | ******** | | | | | user | **** | | | ``` + +## template +`template` is a special output format that allows you, render the output using Golangs template engine. Format `template` requires either a `--template-file` or a `--template-string` flag or the equivalent env vars. + +The secrets are passed as map with the secret path as the key and the actual secrets as values: + +``` +# +secret/admin map[sub:password] +secret/demo map[foo:bar] +secret/sub/demo map[demo:hello world password:s3cre5< user:admin] +secret/sub/sub2/demo map[foo:bar password:password user:user] +``` + +Here is an advanced template that renders the secrets in a special env var export format. Note that within a `--template-file` or a `--template-string` the following functions are available: [http://masterminds.github.io/sprig/](http://masterminds.github.io/sprig/): + +```jinja +# export.tmpl +{{- range $path, $secrets := . }} +{{- range $key, $value := $secrets }} +export {{ list $path $key | join "/" | replace "/" "_" | upper | trimPrefix "SECRET_" }}={{ $value | squote -}} +{{ end -}} +{{- end }} +``` + +This would result in the following output: + +```bash +> vkv export -p secret -f=template --template-file=export.tmpl +export ADMIN_SUB='password' +export DEMO_FOO='bar' +export SUB_DEMO_DEMO='hello world' +export SUB_DEMO_PASSWORD='s3cre5<' +export SUB_DEMO_USER='admin' +export SUB_SUB2_DEMO_FOO='bar' +export SUB_SUB2_DEMO_PASSWORD='password' +export SUB_SUB2_DEMO_USER='user' +``` \ No newline at end of file diff --git a/go.mod b/go.mod index e762b2e0..745ef1e2 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.21 toolchain go1.21.1 require ( + github.com/Masterminds/sprig/v3 v3.2.1 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 github.com/gin-gonic/gin v1.10.0 github.com/hashicorp/vault/api v1.14.0 @@ -34,6 +35,7 @@ require ( github.com/Crocmagnon/fatcontext v0.2.2 // indirect github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect github.com/GaijinEntertainment/go-exhaustruct/v3 v3.2.0 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.2.1 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/Microsoft/hcsshim v0.11.4 // indirect @@ -130,6 +132,8 @@ require ( github.com/hashicorp/go-sockaddr v1.0.6 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect + github.com/huandu/xstrings v1.3.2 // indirect + github.com/imdario/mergo v0.3.11 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jgautheron/goconst v1.7.1 // indirect github.com/jingyugao/rowserrcheck v1.1.1 // indirect @@ -163,8 +167,10 @@ require ( github.com/mattn/go-runewidth v0.0.15 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mgechev/revive v1.3.7 // indirect + github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect @@ -208,6 +214,7 @@ require ( github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect github.com/shirou/gopsutil/v3 v3.24.5 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/shopspring/decimal v1.2.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/sivchari/containedctx v1.0.3 // indirect github.com/sivchari/tenv v1.7.1 // indirect diff --git a/go.sum b/go.sum index 0cf661c8..952c6127 100644 --- a/go.sum +++ b/go.sum @@ -61,8 +61,13 @@ github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rW github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= github.com/GaijinEntertainment/go-exhaustruct/v3 v3.2.0 h1:sATXp1x6/axKxz2Gjxv8MALP0bXaNRfQinEwyfMcx8c= github.com/GaijinEntertainment/go-exhaustruct/v3 v3.2.0/go.mod h1:Nl76DrGNJTA1KJ0LePKBw/vznBX1EHbAZX8mwjR82nI= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/sprig/v3 v3.2.1 h1:n6EPaDyLSvCEa3frruQvAiHuNp2dhBlMSmkEr+HuzGc= +github.com/Masterminds/sprig/v3 v3.2.1/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8= @@ -353,6 +358,7 @@ github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwg github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -405,7 +411,12 @@ github.com/hashicorp/vault/api v1.14.0 h1:Ah3CFLixD5jmjusOgm8grfN9M0d+Y8fVR2SW0K github.com/hashicorp/vault/api v1.14.0/go.mod h1:pV9YLxBGSz+cItFDd8Ii4G17waWOQ32zVjMWHe/cOqk= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= +github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jgautheron/goconst v1.7.1 h1:VpdAG7Ca7yvvJk5n8dMwQhfEZJh95kl/Hl9S1OI5Jkk= @@ -507,10 +518,14 @@ github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zk github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mgechev/revive v1.3.7 h1:502QY0vQGe9KtYJ9FpxMz9rL+Fc/P13CI5POL4uHCcE= github.com/mgechev/revive v1.3.7/go.mod h1:RJ16jUbF0OWC3co/+XTxmFNgEpUPwnnA0BRllX2aDNA= +github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= @@ -655,6 +670,8 @@ github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFt github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -672,6 +689,7 @@ github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCp github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= @@ -814,6 +832,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= diff --git a/pkg/printer/secret/markdown.go b/pkg/printer/secret/markdown.go index 01501302..846f344d 100644 --- a/pkg/printer/secret/markdown.go +++ b/pkg/printer/secret/markdown.go @@ -28,7 +28,7 @@ func (p *Printer) buildMarkdownTable(secrets map[string]interface{}) ([]string, headers := []string{} m := make(map[string]interface{}) - utils.TransformMap(secrets, m, "") + utils.FlattenMap(secrets, m, "") for _, k := range utils.SortMapKeys(m) { v := utils.ToMapStringInterface(m[k]) diff --git a/pkg/printer/secret/policy.go b/pkg/printer/secret/policy.go index 4d96eb86..dba4cc16 100644 --- a/pkg/printer/secret/policy.go +++ b/pkg/printer/secret/policy.go @@ -19,7 +19,7 @@ const ( func (p *Printer) printPolicy(secrets map[string]interface{}) error { transformMap := make(map[string]interface{}) - utils.TransformMap(secrets, transformMap, "") + utils.FlattenMap(secrets, transformMap, "") capMap := make(map[string]*vault.Capability) diff --git a/pkg/printer/secret/template.go b/pkg/printer/secret/template.go index 63978761..c8ef4e14 100644 --- a/pkg/printer/secret/template.go +++ b/pkg/printer/secret/template.go @@ -2,43 +2,22 @@ package secret import ( "fmt" + "strings" "github.com/FalcoSuessgott/vkv/pkg/render" "github.com/FalcoSuessgott/vkv/pkg/utils" ) func (p *Printer) printTemplate(secrets map[string]interface{}) error { - type entry struct { - Key string - Value interface{} - } - - data := map[string][]entry{} - - for _, k := range utils.SortMapKeys(secrets) { - m := utils.ToMapStringInterface(secrets[k]) - - for _, i := range utils.SortMapKeys(m) { - subMap, ok := m[i].(map[string]interface{}) - if !ok { - return fmt.Errorf("cannot convert %T to map[string]interface", m[i]) - } - - entries := []entry{} - for _, j := range utils.SortMapKeys(subMap) { - entries = append(entries, entry{Key: j, Value: subMap[j]}) - } - - data[i] = entries - } - } + m := make(map[string]interface{}) + utils.FlattenMap(secrets, m, "") - output, err := render.String([]byte(p.template), data) + output, err := render.Apply([]byte(p.template), m) if err != nil { return err } - fmt.Fprintln(p.writer, output.String()) + fmt.Fprintln(p.writer, strings.TrimSpace(output.String())) return nil } diff --git a/pkg/printer/secret/template_test.go b/pkg/printer/secret/template_test.go index 9f3cb45b..7aad20c5 100644 --- a/pkg/printer/secret/template_test.go +++ b/pkg/printer/secret/template_test.go @@ -20,26 +20,7 @@ func TestPrintTemplate(t *testing.T) { err bool }{ { - name: "test: template", - rootPath: "root", - s: map[string]interface{}{ - "root/secret": map[string]interface{}{ - "key": "value", - "user": "password", - }, - }, - opts: []Option{ - ToFormat(Template), - WithTemplate(`{{ range $path, $data := . }}{{ range $entry := $data }}{{ printf "%s:\t%s=%v\n" $path $entry.Key $entry.Value }}{{ end }}{{ end }}`, ""), - }, - output: `root/secret: key=***** -root/secret: user=******** - -`, - }, - { - name: "test: template show values", - rootPath: "root", + name: "test: template", s: map[string]interface{}{ "root/secret": map[string]interface{}{ "key": "value", @@ -49,16 +30,18 @@ root/secret: user=******** opts: []Option{ ToFormat(Template), ShowValues(true), - WithTemplate(`{{ range $path, $data := . }}{{ range $entry := $data }}{{ printf "%s:\t%s=%v\n" $path $entry.Key $entry.Value }}{{ end }}{{ end }}`, ""), + WithTemplate(`{{ range $path, $secret:= . }} +{{- range $key, $value := $secret -}} +{{ $key}}={{ $value }} +{{ end -}} +{{ end -}}`, ""), }, - output: `root/secret: key=value -root/secret: user=password - + output: `key=value +user=password `, }, { - name: "test: template file show values", - rootPath: "root", + name: "test: template file show values", s: map[string]interface{}{ "root/secret": map[string]interface{}{ "key": "value", @@ -70,12 +53,9 @@ root/secret: user=password ShowValues(true), WithTemplate("", "testdata/policies.tmpl"), }, - output: ` -path "root/secret/*" { + output: `path "root/secret/*" { capabilities = [ "create", "read" ] } - - `, }, } @@ -88,7 +68,7 @@ path "root/secret/*" { m := map[string]interface{}{} - m[tc.rootPath+"/"] = tc.s + m[tc.rootPath] = tc.s require.NoError(t, p.Out(m)) assert.Equal(t, tc.output, utils.RemoveCarriageReturns(b.String()), tc.name) } diff --git a/pkg/render/render.go b/pkg/render/render.go index 0a76f25c..f07b95d4 100644 --- a/pkg/render/render.go +++ b/pkg/render/render.go @@ -3,13 +3,18 @@ package render import ( "bytes" "text/template" + + "github.com/Masterminds/sprig/v3" ) // String renders byte array input with the given data. -func String(tmpl []byte, input interface{}) (bytes.Buffer, error) { +func Apply(tmpl []byte, input interface{}) (bytes.Buffer, error) { var buf bytes.Buffer - tpl, err := template.New("template").Option("missingkey=error").Parse(string(tmpl)) + tpl, err := template.New("template"). + Option("missingkey=error"). + Funcs(sprig.FuncMap()). + Parse(string(tmpl)) if err != nil { return buf, err } diff --git a/pkg/render/render_test.go b/pkg/render/render_test.go index 60ccf508..44ccd291 100644 --- a/pkg/render/render_test.go +++ b/pkg/render/render_test.go @@ -10,7 +10,7 @@ import ( var testTemplate = []byte("This is a {{ .Test }} template which replaces certain {{ .Values }}!") func TestRenderTemplate(t *testing.T) { - result, err := String(testTemplate, map[string]interface{}{ + result, err := Apply(testTemplate, map[string]interface{}{ "Test": "test", "Values": "values", }) @@ -20,7 +20,7 @@ func TestRenderTemplate(t *testing.T) { } func TestRenderInvalidString(t *testing.T) { - _, err := String([]byte("{{ invalid }"), map[string]interface{}{ + _, err := Apply([]byte("{{ invalid }"), map[string]interface{}{ "Test": "test", "Values": "values", }) @@ -29,7 +29,7 @@ func TestRenderInvalidString(t *testing.T) { } func TestRenderExpectError(t *testing.T) { - _, err := String(testTemplate, map[string]interface{}{ + _, err := Apply(testTemplate, map[string]interface{}{ "Test": "test", "WrongValue": "values", }) diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 40159917..7e9acbaa 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -22,14 +22,13 @@ const ( // Keys type for receiving all keys of a map. type Keys []string -// TransformMap takes a multi leveled map and returns a map with its combined paths -// as the keys and the map as its value. Also see TestTransformMap(). -func TransformMap(a, b map[string]interface{}, key string) { +// FlattenMap flattens a nested map into a single map with its. +func FlattenMap(a, b map[string]interface{}, key string) { for k, v := range a { // if its a map -> go deeper m, ok := v.(map[string]interface{}) if ok { - TransformMap(m, b, path.Join(key, k)) + FlattenMap(m, b, path.Join(key, k)) } else { // otherwise add the key and value to the map b[key] = a } diff --git a/pkg/utils/utils_test.go b/pkg/utils/utils_test.go index 6141a7f3..c1016df3 100644 --- a/pkg/utils/utils_test.go +++ b/pkg/utils/utils_test.go @@ -17,7 +17,7 @@ func TestRemoveCarriageReturn(t *testing.T) { assert.Equal(t, "new line\n", RemoveCarriageReturns(s)) } -func TestTransformMap(t *testing.T) { +func TestFlattenMap(t *testing.T) { testCases := []struct { name string m map[string]interface{} @@ -133,7 +133,7 @@ func TestTransformMap(t *testing.T) { for _, tc := range testCases { res := make(map[string]interface{}) - TransformMap(tc.m, res, "") + FlattenMap(tc.m, res, "") assert.Equal(t, tc.expected, res, tc.expected) }