Skip to content

Commit d2c9f1e

Browse files
ndeloofglours
authored andcommitted
detect misuse of !reset tag
Signed-off-by: Nicolas De Loof <[email protected]>
1 parent c7613e2 commit d2c9f1e

File tree

2 files changed

+89
-0
lines changed

2 files changed

+89
-0
lines changed

loader/merge_reset_test.go

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
Copyright 2020 The Compose Specification Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package loader
18+
19+
import (
20+
"context"
21+
"testing"
22+
23+
"github.com/compose-spec/compose-go/v2/types"
24+
"gotest.tools/v3/assert"
25+
)
26+
27+
func Test_LoadWithReset(t *testing.T) {
28+
p, err := LoadWithContext(context.TODO(), types.ConfigDetails{
29+
ConfigFiles: []types.ConfigFile{
30+
{
31+
Filename: "base.yml",
32+
Content: []byte(`
33+
name: test
34+
services:
35+
foo:
36+
build:
37+
context: .
38+
dockerfile: foo.Dockerfile
39+
environment:
40+
FOO: BAR`),
41+
},
42+
{
43+
Filename: "override.yml",
44+
Content: []byte(`
45+
services:
46+
foo:
47+
image: foo
48+
build: !reset
49+
environment:
50+
FOO: !reset
51+
`),
52+
},
53+
},
54+
}, func(options *Options) {
55+
options.SkipNormalization = true
56+
})
57+
assert.NilError(t, err)
58+
assert.DeepEqual(t, p.Services["foo"], types.ServiceConfig{
59+
Name: "foo",
60+
Image: "foo",
61+
Environment: types.MappingWithEquals{},
62+
})
63+
}
64+
65+
func Test_DuplicateReset(t *testing.T) {
66+
_, err := LoadWithContext(context.TODO(), types.ConfigDetails{
67+
ConfigFiles: []types.ConfigFile{
68+
{
69+
Filename: "duplicate.yml",
70+
Content: []byte(`
71+
name: test
72+
services:
73+
foo:
74+
command: hello
75+
command: !reset hello world
76+
`),
77+
},
78+
},
79+
}, func(options *Options) {
80+
options.SkipNormalization = true
81+
})
82+
assert.Error(t, err, "line 6: mapping key \"command\" already defined at line 5")
83+
}

loader/reset.go

+6
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ func (p *ResetProcessor) resolveReset(node *yaml.Node, path tree.Path) (*yaml.No
6767
p.paths = append(p.paths, path)
6868
return node, nil
6969
}
70+
71+
keys := map[string]int{}
7072
switch node.Kind {
7173
case yaml.SequenceNode:
7274
var nodes []*yaml.Node
@@ -87,6 +89,10 @@ func (p *ResetProcessor) resolveReset(node *yaml.Node, path tree.Path) (*yaml.No
8789
for idx, v := range node.Content {
8890
if idx%2 == 0 {
8991
key = v.Value
92+
if line, seen := keys[key]; seen {
93+
return nil, fmt.Errorf("line %d: mapping key %#v already defined at line %d", v.Line, key, line)
94+
}
95+
keys[key] = v.Line
9096
} else {
9197
resolved, err := p.resolveReset(v, path.Next(key))
9298
if err != nil {

0 commit comments

Comments
 (0)