mirror of
https://github.com/go-gitea/gitea.git
synced 2026-08-21 07:30:36 +00:00
d8e179f28f
Backport https://github.com/go-gitea/gitea/pull/38984 Workflows using YAML anchors are rejected as invalid, because a workflow is split into one document per job and an alias whose anchor lands in another job's document no longer resolves. Node walkers such as `on:` parsing have no alias case either. Aliases are now expanded once, right after the workflow is parsed and before anything reads or splits it, bounded like GitHub's parser so nested aliases cannot expand without limit. Merge keys stay unsupported, as they are upstream. Fixes: https://github.com/go-gitea/gitea/issues/38983
86 lines
2.2 KiB
Go
86 lines
2.2 KiB
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package jobparser
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestParseResolvesAliases(t *testing.T) {
|
|
got, err := Parse([]byte(`on: push
|
|
env: &common_env
|
|
SHARED: "1"
|
|
jobs:
|
|
a:
|
|
runs-on: linux
|
|
env: *common_env
|
|
steps: &common_steps [{run: echo hi}]
|
|
b:
|
|
runs-on: linux
|
|
env: *common_env
|
|
steps: *common_steps
|
|
`))
|
|
require.NoError(t, err)
|
|
require.Len(t, got, 2)
|
|
|
|
for _, workflow := range got {
|
|
_, job := workflow.Job()
|
|
var env map[string]string
|
|
require.NoError(t, job.Env.Decode(&env))
|
|
assert.Equal(t, map[string]string{"SHARED": "1"}, env)
|
|
require.Len(t, job.Steps, 1)
|
|
|
|
payload, err := workflow.Marshal()
|
|
require.NoError(t, err)
|
|
assert.NotContains(t, string(payload), "common_")
|
|
}
|
|
}
|
|
|
|
func TestParseRejectsAliases(t *testing.T) {
|
|
job := func(body string) []byte {
|
|
return []byte("on: push\njobs:\n a:\n runs-on: linux\n" + body)
|
|
}
|
|
|
|
for _, tt := range []struct {
|
|
name, wantErr string
|
|
content []byte
|
|
}{
|
|
{
|
|
name: "nested aliases exceed the node limit",
|
|
content: []byte(`on: push
|
|
x0: &x0 [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
x1: &x1 [*x0, *x0, *x0, *x0, *x0, *x0, *x0, *x0, *x0]
|
|
x2: &x2 [*x1, *x1, *x1, *x1, *x1, *x1, *x1, *x1, *x1]
|
|
x3: &x3 [*x2, *x2, *x2, *x2, *x2, *x2, *x2, *x2, *x2]
|
|
x4: &x4 [*x3, *x3, *x3, *x3, *x3, *x3, *x3, *x3, *x3]
|
|
jobs: {a: {runs-on: linux, steps: [{run: echo}]}}
|
|
`),
|
|
wantErr: "maximum YAML nodes exceeded",
|
|
},
|
|
{
|
|
name: "anchor aliased from inside itself",
|
|
content: job(" steps: &s [{run: echo}, *s]\n"),
|
|
wantErr: "maximum YAML nodes exceeded",
|
|
},
|
|
{
|
|
name: "merge key",
|
|
content: job(" env: &e {X: \"1\"}\n container:\n image: alpine\n env:\n <<: *e\n"),
|
|
wantErr: "merge keys (`<<`) are not supported",
|
|
},
|
|
{
|
|
name: "alias before its anchor",
|
|
content: job(" env: *e\n container: {image: alpine, env: &e {X: \"1\"}}\n"),
|
|
wantErr: "unknown anchor 'e' referenced",
|
|
},
|
|
} {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
_, err := Parse(tt.content)
|
|
require.ErrorContains(t, err, tt.wantErr)
|
|
})
|
|
}
|
|
}
|