From 2dfcf7c7f77f48a576bbc78e6f80271a12713e92 Mon Sep 17 00:00:00 2001 From: Kevin Fox Date: Tue, 22 Oct 2024 13:28:59 -0700 Subject: [PATCH] Add sprig functions Fixes: #5575 Signed-off-by: Kevin Fox --- go.mod | 11 +- go.sum | 23 ++-- pkg/common/agentpathtemplate/template.go | 139 ++++++++++++++++++++++- pkg/common/plugin/sshpop/sshpop_test.go | 7 +- 4 files changed, 159 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index 063fe1726c..068be43181 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 github.com/GoogleCloudPlatform/cloudsql-proxy v1.37.0 github.com/Keyfactor/ejbca-go-client-sdk v1.0.2 + github.com/Masterminds/sprig/v3 v3.3.0 github.com/Microsoft/go-winio v0.6.2 github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 github.com/aws/aws-sdk-go-v2 v1.32.2 @@ -104,6 +105,7 @@ require ( cloud.google.com/go/compute/metadata v0.5.2 // indirect cloud.google.com/go/longrunning v0.6.1 // indirect cloud.google.com/go/monitoring v1.21.1 // indirect + dario.cat/mergo v1.0.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect @@ -113,8 +115,7 @@ require ( github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver/v3 v3.2.1 // indirect - github.com/Masterminds/sprig/v3 v3.2.3 // indirect + github.com/Masterminds/semver/v3 v3.3.0 // indirect github.com/OneOfOne/xxhash v1.2.8 // indirect github.com/agnivade/levenshtein v1.2.0 // indirect github.com/armon/go-radix v1.0.0 // indirect @@ -207,7 +208,7 @@ require ( github.com/hashicorp/go-sockaddr v1.0.6 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/yamux v0.1.1 // indirect - github.com/huandu/xstrings v1.3.3 // indirect + github.com/huandu/xstrings v1.5.0 // indirect github.com/in-toto/in-toto-golang v0.9.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect @@ -268,12 +269,12 @@ require ( github.com/segmentio/asm v1.2.0 // indirect github.com/shibumi/go-pathspec v1.3.0 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect - github.com/shopspring/decimal v1.2.0 // indirect + github.com/shopspring/decimal v1.4.0 // indirect github.com/sigstore/protobuf-specs v0.3.2 // indirect github.com/sigstore/timestamp-authority v1.2.2 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect - github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/cast v1.7.0 // indirect github.com/spf13/cobra v1.8.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.19.0 // indirect diff --git a/go.sum b/go.sum index dc11950110..e62febdea1 100644 --- a/go.sum +++ b/go.sum @@ -421,6 +421,8 @@ cuelabs.dev/go/oci/ociregistry v0.0.0-20240404174027-a39bec0462d2 h1:BnG6pr9TTr6 cuelabs.dev/go/oci/ociregistry v0.0.0-20240404174027-a39bec0462d2/go.mod h1:pK23AUVXuNzzTpfMCA06sxZGeVQ/75FdVtW249de9Uo= cuelang.org/go v0.9.2 h1:pfNiry2PdRBr02G/aKm5k2vhzmqbAOoaB4WurmEbWvs= cuelang.org/go v0.9.2/go.mod h1:qpAYsLOf7gTM1YdEg6cxh553uZ4q9ZDWlPbtZr9q1Wk= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= @@ -499,12 +501,11 @@ github.com/Keyfactor/ejbca-go-client-sdk v1.0.2/go.mod h1:4Sv/KGVgRV4VXKko1ajfTa 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.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -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/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= +github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Masterminds/sprig/v3 v3.2.1/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= -github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= -github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= +github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= +github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= @@ -1083,8 +1084,8 @@ github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef/go.mod h1:lADxMC39cJ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= -github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= +github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -1368,8 +1369,9 @@ 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/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sigstore/cosign/v2 v2.4.1 h1:b8UXEfJFks3hmTwyxrRNrn6racpmccUycBHxDMkEPvU= github.com/sigstore/cosign/v2 v2.4.1/go.mod h1:GvzjBeUKigI+XYnsoVQDmMAsMMc6engxztRSuxE+x9I= github.com/sigstore/fulcio v1.6.3 h1:Mvm/bP6ELHgazqZehL8TANS1maAkRoM23CRAdkM4xQI= @@ -1409,8 +1411,8 @@ github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcD 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.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= -github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= +github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -1562,7 +1564,6 @@ golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= diff --git a/pkg/common/agentpathtemplate/template.go b/pkg/common/agentpathtemplate/template.go index 2ae54ef724..159066cbe0 100644 --- a/pkg/common/agentpathtemplate/template.go +++ b/pkg/common/agentpathtemplate/template.go @@ -2,15 +2,152 @@ package agentpathtemplate import ( "bytes" + "fmt" "text/template" + + sprig "github.com/Masterminds/sprig/v3" ) +var funcList = []string{ + "abbrev", + "abbrevboth", + "trunc", + "trim", + "upper", + "lower", + "title", + "untitle", + "substr", + "repeat", + "trimAll", + "trimSuffix", + "trimPrefix", + "nospace", + "initials", + "swapcase", + "snakecase", + "camelcase", + "kebabcase", + "wrap", + "wrapWith", + "contains", + "hasPrefix", + "hasSuffix", + "quote", + "squote", + "cat", + "indent", + "nindent", + "replace", + "plural", + "sha1sum", + "sha256sum", + "adler32sum", + "toString", + "seq", + "splitList", + "toStrings", + "join", + "sortAlpha", + "default", + "empty", + "coalesce", + "all", + "any", + "compact", + "mustCompact", + "ternary", + "base", + "dir", + "clean", + "ext", + "isAbs", + "b64enc", + "b64dec", + "b32enc", + "b32dec", + "tuple", + "list", + "dict", + "get", + "set", + "unset", + "hasKey", + "pluck", + "keys", + "pick", + "omit", + "merge", + "mergeOverwrite", + "mustMerge", + "mustMergeOverwrite", + "values", + "append", + "push", + "mustAppend", + "mustPush", + "prepend", + "mustPrepend", + "first", + "mustFirst", + "rest", + "mustRest", + "last", + "mustLast", + "initial", + "mustInitial", + "reverse", + "mustReverse", + "uniq", + "mustUniq", + "without", + "mustWithout", + "has", + "mustHas", + "slice", + "mustSlice", + "concat", + "dig", + "chunk", + "mustChunk", + "uuidv4", + "fail", + "regexMatch", + "mustRegexMatch", + "regexFindAll", + "mustRegexFindAll", + "regexFind", + "mustRegexFind", + "regexReplaceAll", + "mustRegexReplaceAll", + "regexReplaceAllLiteral", + "mustRegexReplaceAllLiteral", + "regexSplit", + "mustRegexSplit", + "regexQuoteMeta", + "urlParse", + "urlJoin", +} + +var ourMap = make(template.FuncMap) + +func init() { + sprigMap := sprig.TxtFuncMap() + for _, f := range funcList { + if fn, ok := sprigMap[f]; ok { + ourMap[f] = fn + } else { + panic(fmt.Errorf("missing sprig function %q", f)) + } + } +} + // Parse parses an agent path template. It changes the behavior for missing // keys to return an error instead of the default behavior, which renders a // value that requires percent-encoding to include in a URI, which is against // the SPIFFE specification. func Parse(text string) (*Template, error) { - tmpl, err := template.New("agent-path").Option("missingkey=error").Parse(text) + tmpl, err := template.New("agent-path").Option("missingkey=error").Funcs(ourMap).Parse(text) if err != nil { return nil, err } diff --git a/pkg/common/plugin/sshpop/sshpop_test.go b/pkg/common/plugin/sshpop/sshpop_test.go index 4bd32d8bd7..1a551f21b6 100644 --- a/pkg/common/plugin/sshpop/sshpop_test.go +++ b/pkg/common/plugin/sshpop/sshpop_test.go @@ -106,14 +106,13 @@ func TestNewServer(t *testing.T) { { desc: "success", configString: fmt.Sprintf(`cert_authorities = [%q] - canonical_domain = "local" - agent_path_template = "/{{ .PluginName}}/{{ .Fingerprint }}"`, testCertAuthority), + canonical_domain = "local"`, testCertAuthority), trustDomain: "foo.test", requireServer: func(t *testing.T, s *Server) { require.NotNil(t, s) require.Equal(t, "foo.test", s.trustDomain.Name()) require.Equal(t, "local", s.canonicalDomain) - require.Equal(t, DefaultAgentPathTemplate, s.agentPathTemplate) + require.Same(t, DefaultAgentPathTemplate, s.agentPathTemplate) pubkey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(testCertAuthority)) require.NoError(t, err) require.True(t, s.certChecker.IsHostAuthority(pubkey, "")) @@ -128,7 +127,7 @@ func TestNewServer(t *testing.T) { requireServer: func(t *testing.T, s *Server) { require.NotNil(t, s) require.Equal(t, "foo.test", s.trustDomain.Name()) - require.Equal(t, DefaultAgentPathTemplate, s.agentPathTemplate) + require.NotSame(t, DefaultAgentPathTemplate, s.agentPathTemplate) pubkey := requireParsePubkey(t, testCertAuthority) pubkey2 := requireParsePubkey(t, testCertAuthority2) pubkey3 := requireParsePubkey(t, testCertAuthority3)