diff --git a/loader/reset.go b/loader/reset.go index 8dd5e1bb..7f18f1b1 100644 --- a/loader/reset.go +++ b/loader/reset.go @@ -49,24 +49,12 @@ func (p *ResetProcessor) resolveReset(node *yaml.Node, path tree.Path) (*yaml.No path = tree.NewPath(strings.Replace(pathStr, ".<<", "", 1)) } - // Check for cycle - if p.visitedNodes == nil { - p.visitedNodes = make(map[*yaml.Node]string) - } - - // Check for cycle by seeing if the node has already been visited at this path - if previousPath, found := p.visitedNodes[node]; found { - // If the current node has been visited, we have a cycle if the previous path is a prefix - if strings.HasPrefix(pathStr, previousPath) { - return nil, fmt.Errorf("cycle detected at path: %s", pathStr) - } - } - - // Mark the current node as visited - p.visitedNodes[node] = pathStr + "." - // If the node is an alias, We need to process the alias field in order to consider the !override and !reset tags if node.Kind == yaml.AliasNode { + if err := p.checkForCycle(node.Alias, path); err != nil { + return nil, err + } + return p.resolveReset(node.Alias, path) } @@ -154,3 +142,22 @@ func (p *ResetProcessor) applyNullOverrides(target any, path tree.Path) error { } return nil } + +func (p *ResetProcessor) checkForCycle(node *yaml.Node, path tree.Path) error { + if p.visitedNodes == nil { + p.visitedNodes = make(map[*yaml.Node]string) + } + + // Check for cycle by seeing if the node has already been visited at this path + if previousPath, found := p.visitedNodes[node]; found { + // If the current node has been visited, we have a cycle if the previous path is a prefix + if strings.HasPrefix(path.String(), strings.TrimRight(previousPath, "<<")) { + return fmt.Errorf("cycle detected at path: %s", previousPath) + } + } + + // Mark the current node as visited + p.visitedNodes[node] = path.String() + + return nil +} diff --git a/loader/reset_test.go b/loader/reset_test.go index 57a24d94..1b459325 100644 --- a/loader/reset_test.go +++ b/loader/reset_test.go @@ -109,6 +109,26 @@ services: a2: &a image: alpine a: *a +`, + expectError: false, + errorMsg: "", + }, + { + name: "no cycle 2", + config: ` +name: blah +x-templates: + x-gluetun: &gluetun + environment: &gluetun_env + a: b + x-gluetun-pia: &gluetun_pia + <<: *gluetun + x-gluetun-env-pia: &gluetun_env_pia + <<: *gluetun_env + vp0: + <<: *gluetun_pia + environment: + <<: *gluetun_env_pia `, expectError: false, errorMsg: "",