From f2565c9614e7239cc4781cd6ee560a24116bcafd Mon Sep 17 00:00:00 2001 From: Christoph Maser Date: Wed, 20 Mar 2024 18:53:17 +0100 Subject: [PATCH] add sprig template functions fixes #3726 fixes #3762 fixes #603 Signed-off-by: Christoph Maser --- docs/notifications.md | 26 +++++++++++++++++++++++--- go.mod | 9 +++++++++ go.sum | 22 ++++++++++++++++++++++ template/template.go | 31 +++++++++++++++++++++++++++++-- template/template_test.go | 38 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 121 insertions(+), 5 deletions(-) diff --git a/docs/notifications.md b/docs/notifications.md index 1a70d4aa0d..a45ed21e16 100644 --- a/docs/notifications.md +++ b/docs/notifications.md @@ -78,9 +78,8 @@ In addition to direct access of data (labels and annotations) stored as KV, ther # Functions -Note the [default -functions](http://golang.org/pkg/text/template/#hdr-Functions) also provided by Go -templating. +For templating the [default functions](http://golang.org/pkg/text/template/#hdr-Functions) are provided by Go +templating and the following custom functions. ## Strings @@ -97,3 +96,24 @@ templating. | stringSlice | ...string | Returns the passed strings as a slice of strings. | | date | string, time.Time | Returns the text representation of the time in the specified format. For documentation on formats refer to [pkg.go.dev/time](https://pkg.go.dev/time#pkg-constants). | | tz | string, time.Time | Returns the time in the timezone. For example, Europe/Paris. | + +Additionally a selection of functions provided by the [sprig library](https://masterminds.github.io/sprig/) is available. +The selection list of theses functinons is the following: + +```text +"ago", "date", "dateInZone", "dateModify", "duration", "durationRound", "htmlDate", "htmlDateInZone", "toDate", +"unixEpoch", "abbrev", "abbrevboth", "trunc", "untitle", "substr", "repeat", "trimAll", "trimSuffix", "trimPrefix", "nospace", +"initials", "randAlphaNum", "randAlpha", "randAscii", "randNumeric", "swapcase", "shuffle", "snakecase", "camelcase", +"kebabcase", "wrap", "wrapWith", "contains", "hasPrefix", "hasSuffix", "quote", "squote", "cat", "indent", "nindent", +"replace", "plural", "sha1sum", "sha256sum", "adler32sum", "toString", "atoi", "int64", "int", "float64", "seq", "toDecimal", +"split", "splitList", "splitn", "toStrings", "until", "untilStep", "add1", "add", "sub", "div", "mod", "mul", "randInt", +"add1f", "addf", "subf", "divf", "mulf", "biggest", "max", "min", "maxf", "minf", "ceil", "floor", "round", "sortAlpha", +"default", "empty", "coalesce", "all", "any", "compact", "fromJson", "toJson", "toPrettyJson", "toRawJson", "ternary", +"deepCopy", "typeOf", "typeIs", "typeIsLike", "kindOf", "kindIs", "deepEqual", "b64enc", "b64dec", "b32enc", "b32dec", "tuple", +"list", "dict", "get", "set", "unset", "hasKey", "pluck", "keys", "pick", "omit", "merge", "mergeOverwrite", "values", "prepend", +"first", "rest", "last", "initial", "reverse", "uniq", "without", "has", "concat", "dig", "chunk", "randBytes", "uuidv4", +"semver", "semverCompare", "regexFindAll", "regexFind", "regexReplaceAll", "regexReplaceAllLiteral", "regexSplit", +"regexQuoteMeta", "urlParse", "urlJoin", +``` + +When using sprig date functions it is advised to always use its timezone aware versions, like `dateInZone` or `htmlDateInZone`. diff --git a/go.mod b/go.mod index 4b98484c3b..068024a271 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/prometheus/alertmanager go 1.21 require ( + github.com/Masterminds/sprig/v3 v3.2.1 github.com/alecthomas/kingpin/v2 v2.4.0 github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 github.com/aws/aws-sdk-go v1.52.3 @@ -48,6 +49,8 @@ require ( ) require ( + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver/v3 v3.1.1 // indirect github.com/armon/go-metrics v0.3.10 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -67,19 +70,25 @@ require ( github.com/hashicorp/go-msgpack/v2 v2.1.1 // indirect github.com/hashicorp/go-multierror v1.1.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/huandu/xstrings v1.3.2 // indirect + github.com/imdario/mergo v0.3.11 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/julienschmidt/httprouter v1.3.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/miekg/dns v1.1.41 // indirect + github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.0 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.6.0 // indirect github.com/prometheus/procfs v0.14.0 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect + github.com/shopspring/decimal v1.2.0 // indirect + github.com/spf13/cast v1.5.0 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect go.mongodb.org/mongo-driver v1.14.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect diff --git a/go.sum b/go.sum index 29d828ce5c..3a3097a72e 100644 --- a/go.sum +++ b/go.sum @@ -57,6 +57,12 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +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 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +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/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY= github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= @@ -133,6 +139,7 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -260,6 +267,7 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/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= @@ -315,8 +323,13 @@ github.com/hashicorp/memberlist v0.5.1 h1:mk5dRuzeDNis2bi6LLoQIXfMH7JQvAzt3mQD0v github.com/hashicorp/memberlist v0.5.1/go.mod h1:zGDXV6AqbDTKTM6yxW0I4+JtFzZAJVoIPvss4hV8F24= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +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/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/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/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= @@ -377,6 +390,8 @@ github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKju github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +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/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -384,6 +399,8 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -456,6 +473,8 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +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/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk= github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 h1:pXY9qYc/MP5zdvqWEUH6SjNiu7VhSjuVFTFiTcphaLU= @@ -465,6 +484,8 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +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/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -527,6 +548,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= 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-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= diff --git a/template/template.go b/template/template.go index a34403d8f4..f5371dced2 100644 --- a/template/template.go +++ b/template/template.go @@ -21,11 +21,13 @@ import ( "path" "path/filepath" "regexp" + "slices" "sort" "strings" tmpltext "text/template" "time" + "github.com/Masterminds/sprig/v3" "github.com/prometheus/common/model" "golang.org/x/text/cases" "golang.org/x/text/language" @@ -58,8 +60,8 @@ func New(options ...Option) (*Template, error) { o(t.text, t.html) } - t.text.Funcs(tmpltext.FuncMap(DefaultFuncs)) - t.html.Funcs(tmplhtml.FuncMap(DefaultFuncs)) + t.text.Funcs(tmpltext.FuncMap(DefaultFuncs)).Funcs(tmpltext.FuncMap(filteredSprigFuncMap())) + t.html.Funcs(tmplhtml.FuncMap(DefaultFuncs)).Funcs(tmplhtml.FuncMap(filteredSprigFuncMap())) return t, nil } @@ -420,3 +422,28 @@ func (t *Template) Data(recv string, groupLabels model.LabelSet, alerts ...*type return data } + +func filteredSprigFuncMap() tmpltext.FuncMap { + allowlist := []string{ + "ago", "date", "dateInZone", "dateModify", "duration", "durationRound", "htmlDate", "htmlDateInZone", "toDate", + "unixEpoch", "abbrev", "abbrevboth", "trunc", "untitle", "substr", "repeat", "trimAll", "trimSuffix", "trimPrefix", "nospace", + "initials", "randAlphaNum", "randAlpha", "randAscii", "randNumeric", "swapcase", "shuffle", "snakecase", "camelcase", + "kebabcase", "wrap", "wrapWith", "contains", "hasPrefix", "hasSuffix", "quote", "squote", "cat", "indent", "nindent", + "replace", "plural", "sha1sum", "sha256sum", "adler32sum", "toString", "atoi", "int64", "int", "float64", "seq", "toDecimal", + "split", "splitList", "splitn", "toStrings", "until", "untilStep", "add1", "add", "sub", "div", "mod", "mul", "randInt", + "add1f", "addf", "subf", "divf", "mulf", "biggest", "max", "min", "maxf", "minf", "ceil", "floor", "round", "sortAlpha", + "default", "empty", "coalesce", "all", "any", "compact", "fromJson", "toJson", "toPrettyJson", "toRawJson", "ternary", + "deepCopy", "typeOf", "typeIs", "typeIsLike", "kindOf", "kindIs", "deepEqual", "b64enc", "b64dec", "b32enc", "b32dec", "tuple", + "list", "dict", "get", "set", "unset", "hasKey", "pluck", "keys", "pick", "omit", "merge", "mergeOverwrite", "values", "prepend", + "first", "rest", "last", "initial", "reverse", "uniq", "without", "has", "concat", "dig", "chunk", "randBytes", "uuidv4", + "semver", "semverCompare", "regexFindAll", "regexFind", "regexReplaceAll", "regexReplaceAllLiteral", "regexSplit", + "regexQuoteMeta", "urlParse", "urlJoin", + } + sprigFuncMap := sprig.FuncMap() + for function := range sprigFuncMap { + if !slices.Contains(allowlist, function) { + delete(sprigFuncMap, function) + } + } + return sprigFuncMap +} diff --git a/template/template_test.go b/template/template_test.go index 103dd08430..a15d9161e0 100644 --- a/template/template_test.go +++ b/template/template_test.go @@ -522,6 +522,10 @@ func TestTemplateFuncs(t *testing.T) { in: `{{ . | tz "Invalid/Timezone" }}`, data: time.Date(2024, 1, 1, 8, 15, 30, 0, time.UTC), expErr: "template: :1:7: executing \"\" at : error calling tz: unknown time zone Invalid/Timezone", + }, { + title: "Template using a sprig function", + in: `{{ list 1 2 3 4 5 }}`, + exp: "[1 2 3 4 5]", }} { tc := tc t.Run(tc.title, func(t *testing.T) { @@ -544,3 +548,37 @@ func TestTemplateFuncs(t *testing.T) { }) } } + +func TestDisallowedTemplateFuncs(t *testing.T) { + tmpl, err := FromGlobs([]string{}) + require.NoError(t, err) + + for _, tc := range []struct { + title string + in string + data interface{} + exp string + }{{ + title: "Template using env", + in: `{{ env "HOME" }}`, + exp: "ABC", + }, { + title: "Template using expandenv", + in: `{{ expandenv "Your path is set to $PATH"}}`, + exp: "abc", + }} { + tc := tc + t.Run(tc.title, func(t *testing.T) { + wg := sync.WaitGroup{} + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + defer wg.Done() + _, err := tmpl.ExecuteTextString(tc.in, tc.data) + require.ErrorContainsf(t, err, "not defined", "error message %s", "formatted") + }() + } + wg.Wait() + }) + } +}