Merge pull request #7471 from bacongobbler/backport-7443

fix(engine): allow limited recursion in templates
pull/7810/head
Matthew Fisher 5 years ago committed by GitHub
commit c35b2b1cce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -32,6 +32,8 @@ import (
"k8s.io/helm/pkg/proto/hapi/chart"
)
const recursionMaxNums = 1000
// Engine is an implementation of 'cmd/tiller/environment'.Engine that uses Go templates.
type Engine struct {
// FuncMap contains the template functions that will be passed to each
@ -145,21 +147,23 @@ func (e *Engine) alterFuncMap(t *template.Template, referenceTpls map[string]ren
funcMap[k] = v
}
includedNames := make([]string, 0)
includedNames := make(map[string]int)
// Add the 'include' function here so we can close over t.
funcMap["include"] = func(name string, data interface{}) (string, error) {
buf := bytes.NewBuffer(nil)
for _, n := range includedNames {
if n == name {
return "", errors.Wrapf(fmt.Errorf("unable to excute template"), "rendering template has a nested reference name: %s", name)
if v, ok := includedNames[name]; ok {
if v > recursionMaxNums {
return "", errors.Wrapf(fmt.Errorf("unable to execute template"), "rendering template has a nested reference name: %s", name)
}
includedNames[name]++
} else {
includedNames[name] = 1
}
includedNames = append(includedNames, name)
if err := t.ExecuteTemplate(buf, name, data); err != nil {
return "", err
}
includedNames = includedNames[:len(includedNames)-1]
includedNames[name]--
return buf.String(), nil
}

@ -18,6 +18,7 @@ package engine
import (
"fmt"
"strings"
"sync"
"testing"
@ -604,3 +605,58 @@ func TestAlterFuncMap(t *testing.T) {
}
}
func TestRenderRecursionLimit(t *testing.T) {
// endless recursion should produce an error
c := &chart.Chart{
Metadata: &chart.Metadata{Name: "bad"},
Templates: []*chart.Template{
{Name: "templates/base", Data: []byte(`{{include "recursion" . }}`)},
{Name: "templates/recursion", Data: []byte(`{{define "recursion"}}{{include "recursion" . }}{{end}}`)},
},
}
v := chartutil.Values{
"Values": "",
"Chart": c.Metadata,
"Release": chartutil.Values{
"Name": "TestRelease",
},
}
expectErr := "rendering template has a nested reference name: recursion: unable to execute template"
e := New()
_, err := e.Render(c, v)
if err == nil || !strings.HasSuffix(err.Error(), expectErr) {
t.Errorf("Expected err with suffix: %s", expectErr)
}
// calling the same function many times is ok
times := 4000
phrase := "All work and no play makes Jack a dull boy"
printFunc := `{{define "overlook"}}{{printf "` + phrase + `\n"}}{{end}}`
var repeatedIncl string
for i := 0; i < times; i++ {
repeatedIncl += `{{include "overlook" . }}`
}
d := &chart.Chart{
Metadata: &chart.Metadata{Name: "overlook"},
Templates: []*chart.Template{
{Name: "templates/quote", Data: []byte(repeatedIncl)},
{Name: "templates/_function", Data: []byte(printFunc)},
},
}
out, err := e.Render(d, v)
if err != nil {
t.Fatal(err)
}
var expect string
for i := 0; i < times; i++ {
expect += phrase + "\n"
}
if got := out["overlook/templates/quote"]; got != expect {
t.Errorf("Expected %q, got %q (%v)", expect, got, out)
}
}

Loading…
Cancel
Save