Skip to content

Commit b2de238

Browse files
committedFeb 16, 2023
refactor param array indexing validation
This commit refactors param array indexing validation to extract all references first, then validate if references are out of bound. Previously we traverse all references and collect invalid references there. The benefit of this refactoring is that it would be convenient for other validation to reuse these references. Signed-off-by: Yongxuan Zhang [email protected]
1 parent f3e9fc1 commit b2de238

File tree

3 files changed

+126
-141
lines changed

3 files changed

+126
-141
lines changed
 

‎pkg/reconciler/pipelinerun/resources/validate_params.go

+16-72
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ import (
2424
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
2525
"github.com/tektoncd/pipeline/pkg/list"
2626
"github.com/tektoncd/pipeline/pkg/reconciler/taskrun"
27-
"github.com/tektoncd/pipeline/pkg/substitution"
28-
"k8s.io/apimachinery/pkg/util/sets"
2927
)
3028

3129
// ValidateParamTypesMatching validate that parameters in PipelineRun override corresponding parameters in Pipeline of the same type.
@@ -95,103 +93,49 @@ func ValidateParamArrayIndex(ctx context.Context, p *v1beta1.PipelineSpec, pr *v
9593
return nil
9694
}
9795

98-
arrayParams := extractParamIndexes(p.Params, pr.Spec.Params)
99-
100-
outofBoundParams := sets.String{}
96+
arrayParams := taskrun.ExtractParamArrayLengths(p.Params, pr.Spec.Params)
10197

98+
arrayIndexingParams := []string{}
10299
// collect all the references
103100
for i := range p.Tasks {
104-
findInvalidParamArrayReferences(p.Tasks[i].Params, arrayParams, &outofBoundParams)
101+
extractArrayIndexingReferencesFromParams(p.Tasks[i].Params, arrayParams, &arrayIndexingParams)
105102
if p.Tasks[i].IsMatrixed() {
106-
findInvalidParamArrayReferences(p.Tasks[i].Matrix.Params, arrayParams, &outofBoundParams)
103+
extractArrayIndexingReferencesFromParams(p.Tasks[i].Matrix.Params, arrayParams, &arrayIndexingParams)
107104
}
108105
for j := range p.Tasks[i].Workspaces {
109-
findInvalidParamArrayReference(p.Tasks[i].Workspaces[j].SubPath, arrayParams, &outofBoundParams)
106+
taskrun.ExtractArrayIndexingParamReference(p.Tasks[i].Workspaces[j].SubPath, arrayParams, &arrayIndexingParams)
110107
}
111108
for _, wes := range p.Tasks[i].WhenExpressions {
112-
findInvalidParamArrayReference(wes.Input, arrayParams, &outofBoundParams)
109+
taskrun.ExtractArrayIndexingParamReference(wes.Input, arrayParams, &arrayIndexingParams)
113110
for _, v := range wes.Values {
114-
findInvalidParamArrayReference(v, arrayParams, &outofBoundParams)
111+
taskrun.ExtractArrayIndexingParamReference(v, arrayParams, &arrayIndexingParams)
115112
}
116113
}
117114
}
118115

119116
for i := range p.Finally {
120-
findInvalidParamArrayReferences(p.Finally[i].Params, arrayParams, &outofBoundParams)
117+
extractArrayIndexingReferencesFromParams(p.Finally[i].Params, arrayParams, &arrayIndexingParams)
121118
if p.Finally[i].IsMatrixed() {
122-
findInvalidParamArrayReferences(p.Finally[i].Matrix.Params, arrayParams, &outofBoundParams)
119+
extractArrayIndexingReferencesFromParams(p.Finally[i].Matrix.Params, arrayParams, &arrayIndexingParams)
123120
}
124121
for _, wes := range p.Finally[i].WhenExpressions {
125122
for _, v := range wes.Values {
126-
findInvalidParamArrayReference(v, arrayParams, &outofBoundParams)
123+
taskrun.ExtractArrayIndexingParamReference(v, arrayParams, &arrayIndexingParams)
127124
}
128125
}
129126
}
130-
131-
if outofBoundParams.Len() > 0 {
132-
return fmt.Errorf("non-existent param references:%v", outofBoundParams.List())
133-
}
134-
return nil
127+
return taskrun.ValidateOutofBoundArrayParams(arrayIndexingParams, arrayParams)
135128
}
136129

137-
func extractParamIndexes(defaults []v1beta1.ParamSpec, params []v1beta1.Param) map[string]int {
138-
// Collect all array params
139-
arrayParams := make(map[string]int)
140-
141-
patterns := []string{
142-
"$(params.%s)",
143-
"$(params[%q])",
144-
"$(params['%s'])",
145-
}
146-
147-
// Collect array params lengths from defaults
148-
for _, p := range defaults {
149-
if p.Default != nil {
150-
if p.Default.Type == v1beta1.ParamTypeArray {
151-
for _, pattern := range patterns {
152-
for i := 0; i < len(p.Default.ArrayVal); i++ {
153-
arrayParams[fmt.Sprintf(pattern, p.Name)] = len(p.Default.ArrayVal)
154-
}
155-
}
156-
}
157-
}
158-
}
159-
160-
// Collect array params lengths from pipelinerun or taskrun
161-
for _, p := range params {
162-
if p.Value.Type == v1beta1.ParamTypeArray {
163-
for _, pattern := range patterns {
164-
for i := 0; i < len(p.Value.ArrayVal); i++ {
165-
arrayParams[fmt.Sprintf(pattern, p.Name)] = len(p.Value.ArrayVal)
166-
}
167-
}
168-
}
169-
}
170-
return arrayParams
171-
}
172-
173-
func findInvalidParamArrayReferences(params []v1beta1.Param, arrayParams map[string]int, outofBoundParams *sets.String) {
130+
// extractArrayIndexingReferencesFromParams get all array indexing references from params
131+
func extractArrayIndexingReferencesFromParams(params []v1beta1.Param, arrayParams map[string]int, arrayIndexingParams *[]string) {
174132
for i := range params {
175-
findInvalidParamArrayReference(params[i].Value.StringVal, arrayParams, outofBoundParams)
133+
taskrun.ExtractArrayIndexingParamReference(params[i].Value.StringVal, arrayParams, arrayIndexingParams)
176134
for _, v := range params[i].Value.ArrayVal {
177-
findInvalidParamArrayReference(v, arrayParams, outofBoundParams)
135+
taskrun.ExtractArrayIndexingParamReference(v, arrayParams, arrayIndexingParams)
178136
}
179137
for _, v := range params[i].Value.ObjectVal {
180-
findInvalidParamArrayReference(v, arrayParams, outofBoundParams)
181-
}
182-
}
183-
}
184-
185-
func findInvalidParamArrayReference(paramReference string, arrayParams map[string]int, outofBoundParams *sets.String) {
186-
list := substitution.ExtractParamsExpressions(paramReference)
187-
for _, val := range list {
188-
indexString := substitution.ExtractIndexString(paramReference)
189-
idx, _ := substitution.ExtractIndex(indexString)
190-
v := substitution.TrimArrayIndex(val)
191-
if paramLength, ok := arrayParams[v]; ok {
192-
if idx >= paramLength {
193-
outofBoundParams.Insert(val)
194-
}
138+
taskrun.ExtractArrayIndexingParamReference(v, arrayParams, arrayIndexingParams)
195139
}
196140
}
197141
}

‎pkg/reconciler/pipelinerun/resources/validate_params_test.go

+24-1
Original file line numberDiff line numberDiff line change
@@ -647,10 +647,15 @@ func TestValidateParamArrayIndex_invalid(t *testing.T) {
647647
Operator: selection.In,
648648
Values: []string{"$(params.second-param[2])"},
649649
}},
650+
Matrix: &v1beta1.Matrix{
651+
Params: []v1beta1.Param{
652+
{Name: "final-task-first-param", Value: *v1beta1.NewStructuredValues("$(params.first-param[4])")},
653+
{Name: "final-task-second-param", Value: *v1beta1.NewStructuredValues("$(params.second-param[4])")},
654+
}},
650655
}},
651656
},
652657
params: []v1beta1.Param{{Name: "second-param", Value: *v1beta1.NewStructuredValues("second-value", "second-value-again")}},
653-
expected: fmt.Errorf("non-existent param references:[$(params.first-param[2]) $(params.first-param[3]) $(params.second-param[2]) $(params.second-param[3])]"),
658+
expected: fmt.Errorf("non-existent param references:[$(params.first-param[2]) $(params.first-param[3]) $(params.first-param[4]) $(params.second-param[2]) $(params.second-param[3]) $(params.second-param[4])]"),
654659
}, {
655660
name: "parameter references with bracket notation and special characters reference out of bound",
656661
original: v1beta1.PipelineSpec{
@@ -698,6 +703,24 @@ func TestValidateParamArrayIndex_invalid(t *testing.T) {
698703
},
699704
params: []v1beta1.Param{{Name: "second-param", Value: *v1beta1.NewStructuredValues("second-value", "second-value-again")}},
700705
expected: fmt.Errorf("non-existent param references:[$(params.first-param[2]) $(params.second-param[3])]"),
706+
}, {
707+
name: "parameter in matrix reference out of bound",
708+
original: v1beta1.PipelineSpec{
709+
Params: []v1beta1.ParamSpec{
710+
{Name: "first-param", Type: v1beta1.ParamTypeArray, Default: v1beta1.NewStructuredValues("default-value", "default-value-again")},
711+
{Name: "second-param", Type: v1beta1.ParamTypeArray},
712+
},
713+
Tasks: []v1beta1.PipelineTask{{
714+
Matrix: &v1beta1.Matrix{
715+
Params: []v1beta1.Param{
716+
{Name: "first-task-first-param", Value: *v1beta1.NewStructuredValues("$(params.first-param[2])")},
717+
{Name: "first-task-second-param", Value: *v1beta1.NewStructuredValues("static value")},
718+
},
719+
},
720+
}},
721+
},
722+
params: []v1beta1.Param{{Name: "second-param", Value: *v1beta1.NewStructuredValues("second-value", "second-value-again")}},
723+
expected: fmt.Errorf("non-existent param references:[$(params.first-param[2])]"),
701724
},
702725
} {
703726
tt := tt // capture range variable

0 commit comments

Comments
 (0)
Please sign in to comment.