diff --git a/pkg/model/anchors.go b/pkg/model/anchors.go index ce4809ab..a75ee944 100644 --- a/pkg/model/anchors.go +++ b/pkg/model/anchors.go @@ -21,7 +21,7 @@ func resolveAliasesExt(node *yaml.Node, path map[*yaml.Node]bool, skipCheck bool if err := resolveAliasesExt(node, path, true); err != nil { return err } - delete(path, aliasTarget) + delete(path, node) case yaml.DocumentNode, yaml.MappingNode, yaml.SequenceNode: for _, child := range node.Content { diff --git a/pkg/model/anchors_test.go b/pkg/model/anchors_test.go index 0240c843..b84945b8 100644 --- a/pkg/model/anchors_test.go +++ b/pkg/model/anchors_test.go @@ -7,29 +7,6 @@ import ( "gopkg.in/yaml.v3" ) -func TestVerifyCycleIsInvalid(t *testing.T) { - var node yaml.Node - err := yaml.Unmarshal([]byte(` -a: &a - ref: *b - -b: &b - ref: *a -`), &node) - assert.Error(t, err) -} - -func TestVerifyCycleIsInvalid2(t *testing.T) { - var node yaml.Node - err := yaml.Unmarshal([]byte(` -a: &a - ref: *a -`), &node) - assert.NoError(t, err) - err = resolveAliases(&node) - assert.Error(t, err) -} - func TestVerifyNilAliasError(t *testing.T) { var node yaml.Node err := yaml.Unmarshal([]byte(` @@ -44,3 +21,94 @@ test: err = resolveAliases(&node) assert.Error(t, err) } + +func TestVerifyNoRecursion(t *testing.T) { + table := []struct { + name string + yaml string + yamlErr bool + anchorErr bool + }{ + { + name: "no anchors", + yaml: ` +a: x +b: y +c: z +`, + yamlErr: false, + anchorErr: false, + }, + { + name: "simple anchors", + yaml: ` +a: &a x +b: &b y +c: *a +`, + yamlErr: false, + anchorErr: false, + }, + { + name: "nested anchors", + yaml: ` +a: &a + val: x +b: &b + val: y +c: *a +`, + yamlErr: false, + anchorErr: false, + }, + { + name: "circular anchors", + yaml: ` +a: &b + ref: *c +b: &c + ref: *b +`, + yamlErr: true, + anchorErr: false, + }, + { + name: "self-referencing anchor", + yaml: ` +a: &a + ref: *a +`, + yamlErr: false, + anchorErr: true, + }, + { + name: "reuse snippet with anchors", + yaml: ` +a: &b x +b: &a + ref: *b +c: *a +`, + yamlErr: false, + anchorErr: false, + }, + } + + for _, tt := range table { + t.Run(tt.name, func(t *testing.T) { + var node yaml.Node + err := yaml.Unmarshal([]byte(tt.yaml), &node) + if tt.yamlErr { + assert.Error(t, err) + return + } + assert.NoError(t, err) + err = resolveAliases(&node) + if tt.anchorErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} diff --git a/pkg/model/workflow_test.go b/pkg/model/workflow_test.go index 1d466625..47a9dd82 100644 --- a/pkg/model/workflow_test.go +++ b/pkg/model/workflow_test.go @@ -614,17 +614,21 @@ jobs: func TestReadWorkflow_Anchor(t *testing.T) { yaml := ` -on: push jobs: test: runs-on: &runner ubuntu-latest steps: - uses: &checkout actions/checkout@v5 - test2: + test2: &job runs-on: *runner steps: - uses: *checkout + - run: echo $TRIGGER + env: + TRIGGER: &trigger push + test3: *job +on: push #*trigger ` w, err := ReadWorkflow(strings.NewReader(yaml), false)