Skip to content

Commit 59c0a65

Browse files
Merge pull request #2967 from czeslavo/1.18-backport-2954
[v1.18] Fix potential data races in RenderTemplate function
2 parents 0653570 + a460673 commit 59c0a65

File tree

2 files changed

+62
-2
lines changed

2 files changed

+62
-2
lines changed

pkg/assets/template.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,18 @@ func MakeMap(kvs ...any) (map[any]any, error) {
8585
return m, nil
8686
}
8787

88-
func RenderTemplate(tmpl *template.Template, inputs any) ([]byte, error) {
88+
func RenderTemplate(t *template.Template, inputs any) ([]byte, error) {
89+
// Clone the template to avoid mutating the original one (it could lead to race conditions).
90+
tmpl, err := t.Clone()
91+
if err != nil {
92+
return nil, fmt.Errorf("can't clone template %q: %w", t.Name(), err)
93+
}
94+
8995
// We always want correctness. (Accidentally missing a key might have side effects.)
9096
tmpl.Option("missingkey=error")
9197

9298
var buf bytes.Buffer
93-
err := tmpl.Execute(&buf, inputs)
99+
err = tmpl.Execute(&buf, inputs)
94100
if err != nil {
95101
return nil, fmt.Errorf("can't execute template %q: %w", tmpl.Name(), err)
96102
}

pkg/assets/template_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package assets
2+
3+
import (
4+
"errors"
5+
"testing"
6+
"text/template"
7+
)
8+
9+
func TestRenderTemplate(t *testing.T) {
10+
t.Parallel()
11+
12+
tpl, err := template.New("test").Parse("Hello, {{.Name}}!")
13+
if err != nil {
14+
t.Fatalf("can't parse template: %v", err)
15+
}
16+
17+
tests := []struct {
18+
name string
19+
data map[string]string
20+
want string
21+
wantErr error
22+
}{
23+
{
24+
name: "simple",
25+
data: map[string]string{"Name": "World"},
26+
want: "Hello, World!",
27+
},
28+
{
29+
name: "missing key",
30+
data: map[string]string{},
31+
wantErr: errors.New(`can't execute template "test": template: test:1:9: executing "test" at <.Name>: map has no entry for key "Name"`),
32+
},
33+
}
34+
35+
for _, tc := range tests {
36+
t.Run(tc.name, func(t *testing.T) {
37+
t.Parallel()
38+
39+
out, err := RenderTemplate(tpl, tc.data)
40+
if tc.wantErr != nil {
41+
if err == nil || err.Error() != tc.wantErr.Error() {
42+
t.Fatalf("expected error %q, got %v", tc.wantErr, err)
43+
}
44+
return
45+
}
46+
if err != nil {
47+
t.Fatalf("can't render template: %v", err)
48+
}
49+
if string(out) != tc.want {
50+
t.Fatalf("expected %q, got %q", tc.want, string(out))
51+
}
52+
})
53+
}
54+
}

0 commit comments

Comments
 (0)