-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add feature gate validation for param array indexing #6280
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3339,14 +3339,11 @@ func getTaskSpec() TaskSpec { | |
} | ||
|
||
func TestValidateParamArrayIndex_valid(t *testing.T) { | ||
ctx := context.Background() | ||
cfg := config.FromContextOrDefaults(ctx) | ||
cfg.FeatureFlags.EnableAPIFields = config.BetaAPIFields | ||
ctx = config.ToContext(ctx, cfg) | ||
for _, tt := range []struct { | ||
name string | ||
original PipelineSpec | ||
params []Param | ||
name string | ||
original PipelineSpec | ||
params []Param | ||
apiFields string | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not related to this PR. I'm not sure why we call it 'apiFields' from beginning instead of |
||
}{{ | ||
name: "single parameter", | ||
original: PipelineSpec{ | ||
|
@@ -3362,7 +3359,8 @@ func TestValidateParamArrayIndex_valid(t *testing.T) { | |
}, | ||
}}, | ||
}, | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
apiFields: config.BetaAPIFields, | ||
}, { | ||
name: "single parameter with when expression", | ||
original: PipelineSpec{ | ||
|
@@ -3378,7 +3376,8 @@ func TestValidateParamArrayIndex_valid(t *testing.T) { | |
}}, | ||
}}, | ||
}, | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
apiFields: config.BetaAPIFields, | ||
}, { | ||
name: "pipeline parameter nested inside task parameter", | ||
original: PipelineSpec{ | ||
|
@@ -3393,7 +3392,8 @@ func TestValidateParamArrayIndex_valid(t *testing.T) { | |
}, | ||
}}, | ||
}, | ||
params: nil, // no parameter values. | ||
params: nil, // no parameter values. | ||
apiFields: config.BetaAPIFields, | ||
}, { | ||
name: "array parameter", | ||
original: PipelineSpec{ | ||
|
@@ -3411,6 +3411,7 @@ func TestValidateParamArrayIndex_valid(t *testing.T) { | |
params: []Param{ | ||
{Name: "second-param", Value: *NewStructuredValues("second-value", "array")}, | ||
}, | ||
apiFields: config.BetaAPIFields, | ||
}, { | ||
name: "parameter evaluation with final tasks", | ||
original: PipelineSpec{ | ||
|
@@ -3430,7 +3431,8 @@ func TestValidateParamArrayIndex_valid(t *testing.T) { | |
}}, | ||
}}, | ||
}, | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
apiFields: config.BetaAPIFields, | ||
}, { | ||
name: "parameter evaluation with both tasks and final tasks", | ||
original: PipelineSpec{ | ||
|
@@ -3456,7 +3458,8 @@ func TestValidateParamArrayIndex_valid(t *testing.T) { | |
}}, | ||
}}, | ||
}, | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
apiFields: config.BetaAPIFields, | ||
}, { | ||
name: "parameter references with bracket notation and special characters", | ||
original: PipelineSpec{ | ||
|
@@ -3480,6 +3483,7 @@ func TestValidateParamArrayIndex_valid(t *testing.T) { | |
{Name: "second/param", Value: *NewStructuredValues("second-value", "second-value-again")}, | ||
{Name: "fourth/param", Value: *NewStructuredValues("fourth-value", "fourth-value-again")}, | ||
}, | ||
apiFields: config.BetaAPIFields, | ||
}, { | ||
name: "single parameter in workspace subpath", | ||
original: PipelineSpec{ | ||
|
@@ -3501,10 +3505,29 @@ func TestValidateParamArrayIndex_valid(t *testing.T) { | |
}, | ||
}}, | ||
}, | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
apiFields: config.BetaAPIFields, | ||
}, { | ||
name: "validation with alpha gate", | ||
original: PipelineSpec{ | ||
Params: []ParamSpec{ | ||
{Name: "first-param", Type: ParamTypeArray, Default: NewStructuredValues("default-value", "default-value-again")}, | ||
{Name: "second-param", Type: ParamTypeString}, | ||
}, | ||
Tasks: []PipelineTask{{ | ||
Params: []Param{ | ||
{Name: "first-task-first-param", Value: *NewStructuredValues("$(params.first-param[1])")}, | ||
{Name: "first-task-second-param", Value: *NewStructuredValues("$(params.second-param[0])")}, | ||
{Name: "first-task-third-param", Value: *NewStructuredValues("static value")}, | ||
}, | ||
}}, | ||
}, | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
apiFields: config.AlphaAPIFields, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you also add a test for beta api fields? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. beta api fields is a default value in this test function, that's why I didn't add a specific case for that. Do you think we should add that one? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm I'm not really seeing where the default is set to beta, can you point me to it? |
||
}, | ||
} { | ||
tt := tt // capture range variable | ||
ctx := config.SetEnableAPIFields(context.Background(), tt.apiFields) | ||
t.Run(tt.name, func(t *testing.T) { | ||
t.Parallel() | ||
err := tt.original.ValidateParamArrayIndex(ctx, tt.params) | ||
|
@@ -3516,15 +3539,12 @@ func TestValidateParamArrayIndex_valid(t *testing.T) { | |
} | ||
|
||
func TestValidateParamArrayIndex_invalid(t *testing.T) { | ||
ctx := context.Background() | ||
cfg := config.FromContextOrDefaults(ctx) | ||
cfg.FeatureFlags.EnableAPIFields = config.BetaAPIFields | ||
ctx = config.ToContext(ctx, cfg) | ||
for _, tt := range []struct { | ||
name string | ||
original PipelineSpec | ||
params []Param | ||
expected error | ||
name string | ||
original PipelineSpec | ||
params []Param | ||
apiFields string | ||
expected error | ||
}{{ | ||
name: "single parameter reference out of bound", | ||
original: PipelineSpec{ | ||
|
@@ -3540,8 +3560,9 @@ func TestValidateParamArrayIndex_invalid(t *testing.T) { | |
}, | ||
}}, | ||
}, | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
expected: fmt.Errorf("non-existent param references:[$(params.first-param[2]) $(params.second-param[2])]"), | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
apiFields: config.BetaAPIFields, | ||
expected: fmt.Errorf("non-existent param references:[$(params.first-param[2]) $(params.second-param[2])]"), | ||
}, { | ||
name: "single parameter reference with when expression out of bound", | ||
original: PipelineSpec{ | ||
|
@@ -3557,8 +3578,9 @@ func TestValidateParamArrayIndex_invalid(t *testing.T) { | |
}}, | ||
}}, | ||
}, | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
expected: fmt.Errorf("non-existent param references:[$(params.first-param[2]) $(params.second-param[2])]"), | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
apiFields: config.BetaAPIFields, | ||
expected: fmt.Errorf("non-existent param references:[$(params.first-param[2]) $(params.second-param[2])]"), | ||
}, { | ||
name: "pipeline parameter reference nested inside task parameter out of bound", | ||
original: PipelineSpec{ | ||
|
@@ -3573,8 +3595,9 @@ func TestValidateParamArrayIndex_invalid(t *testing.T) { | |
}, | ||
}}, | ||
}, | ||
params: nil, // no parameter values. | ||
expected: fmt.Errorf("non-existent param references:[$(params.first-param[2]) $(params.second-param[2])]"), | ||
params: nil, // no parameter values. | ||
apiFields: config.BetaAPIFields, | ||
expected: fmt.Errorf("non-existent param references:[$(params.first-param[2]) $(params.second-param[2])]"), | ||
}, { | ||
name: "array parameter reference out of bound", | ||
original: PipelineSpec{ | ||
|
@@ -3592,7 +3615,8 @@ func TestValidateParamArrayIndex_invalid(t *testing.T) { | |
params: []Param{ | ||
{Name: "second-param", Value: *NewStructuredValues("second-value", "array")}, | ||
}, | ||
expected: fmt.Errorf("non-existent param references:[$(params.first-param[3]) $(params.second-param[4])]"), | ||
apiFields: config.BetaAPIFields, | ||
expected: fmt.Errorf("non-existent param references:[$(params.first-param[3]) $(params.second-param[4])]"), | ||
}, { | ||
name: "object parameter reference out of bound", | ||
original: PipelineSpec{ | ||
|
@@ -3612,7 +3636,8 @@ func TestValidateParamArrayIndex_invalid(t *testing.T) { | |
params: []Param{ | ||
{Name: "second-param", Value: *NewStructuredValues("second-value", "array")}, | ||
}, | ||
expected: fmt.Errorf("non-existent param references:[$(params.first-param[4]) $(params.second-param[4])]"), | ||
apiFields: config.BetaAPIFields, | ||
expected: fmt.Errorf("non-existent param references:[$(params.first-param[4]) $(params.second-param[4])]"), | ||
}, { | ||
name: "parameter evaluation with final tasks reference out of bound", | ||
original: PipelineSpec{ | ||
|
@@ -3632,8 +3657,9 @@ func TestValidateParamArrayIndex_invalid(t *testing.T) { | |
}}, | ||
}}, | ||
}, | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
expected: fmt.Errorf("non-existent param references:[$(params.first-param[2]) $(params.second-param[2])]"), | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
apiFields: config.BetaAPIFields, | ||
expected: fmt.Errorf("non-existent param references:[$(params.first-param[2]) $(params.second-param[2])]"), | ||
}, { | ||
name: "parameter evaluation with both tasks and final tasks reference out of bound", | ||
original: PipelineSpec{ | ||
|
@@ -3664,8 +3690,9 @@ func TestValidateParamArrayIndex_invalid(t *testing.T) { | |
}}, | ||
}}, | ||
}, | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
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])]"), | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
apiFields: config.BetaAPIFields, | ||
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])]"), | ||
}, { | ||
name: "parameter in matrix reference out of bound", | ||
original: PipelineSpec{ | ||
|
@@ -3682,8 +3709,9 @@ func TestValidateParamArrayIndex_invalid(t *testing.T) { | |
}, | ||
}}, | ||
}, | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
expected: fmt.Errorf("non-existent param references:[$(params.first-param[2])]"), | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
apiFields: config.BetaAPIFields, | ||
expected: fmt.Errorf("non-existent param references:[$(params.first-param[2])]"), | ||
}, { | ||
name: "parameter references with bracket notation and special characters reference out of bound", | ||
original: PipelineSpec{ | ||
|
@@ -3707,7 +3735,8 @@ func TestValidateParamArrayIndex_invalid(t *testing.T) { | |
{Name: "second/param", Value: *NewStructuredValues("second-value", "second-value-again")}, | ||
{Name: "fourth/param", Value: *NewStructuredValues("fourth-value", "fourth-value-again")}, | ||
}, | ||
expected: fmt.Errorf("non-existent param references:[$(params[\"first.param\"][2]) $(params[\"second/param\"][2]) $(params['fourth/param'][2]) $(params['third.param'][2])]"), | ||
apiFields: config.BetaAPIFields, | ||
expected: fmt.Errorf("non-existent param references:[$(params[\"first.param\"][2]) $(params[\"second/param\"][2]) $(params['fourth/param'][2]) $(params['third.param'][2])]"), | ||
}, { | ||
name: "single parameter in workspace subpath reference out of bound", | ||
original: PipelineSpec{ | ||
|
@@ -3729,13 +3758,57 @@ func TestValidateParamArrayIndex_invalid(t *testing.T) { | |
}, | ||
}}, | ||
}, | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
expected: fmt.Errorf("non-existent param references:[$(params.first-param[2]) $(params.second-param[3])]"), | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
apiFields: config.BetaAPIFields, | ||
expected: fmt.Errorf("non-existent param references:[$(params.first-param[2]) $(params.second-param[3])]"), | ||
}, { | ||
name: "validation alpha feature gate", | ||
original: PipelineSpec{ | ||
Params: []ParamSpec{ | ||
{Name: "first-param", Type: ParamTypeArray, Default: NewStructuredValues("default-value", "default-value-again")}, | ||
{Name: "second-param", Type: ParamTypeArray}, | ||
}, | ||
Tasks: []PipelineTask{{ | ||
Params: []Param{ | ||
{Name: "first-task-first-param", Value: *NewStructuredValues("$(params.first-param[2])")}, | ||
{Name: "first-task-second-param", Value: *NewStructuredValues("static value")}, | ||
}, | ||
Workspaces: []WorkspacePipelineTaskBinding{ | ||
{ | ||
Name: "first-workspace", | ||
Workspace: "first-workspace", | ||
SubPath: "$(params.second-param[3])", | ||
}, | ||
}, | ||
}}, | ||
}, | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
apiFields: config.AlphaAPIFields, | ||
expected: fmt.Errorf("non-existent param references:[$(params.first-param[2]) $(params.second-param[3])]"), | ||
}, { | ||
name: "stable gate not allowed", | ||
original: PipelineSpec{ | ||
Params: []ParamSpec{ | ||
{Name: "first-param", Type: ParamTypeArray, Default: NewStructuredValues("default-value", "default-value-again")}, | ||
{Name: "second-param", Type: ParamTypeString}, | ||
}, | ||
Tasks: []PipelineTask{{ | ||
Params: []Param{ | ||
{Name: "first-task-first-param", Value: *NewStructuredValues("$(params.first-param[2])")}, | ||
{Name: "first-task-second-param", Value: *NewStructuredValues("$(params.second-param[2])")}, | ||
{Name: "first-task-third-param", Value: *NewStructuredValues("static value")}, | ||
}, | ||
}}, | ||
}, | ||
params: []Param{{Name: "second-param", Value: *NewStructuredValues("second-value", "second-value-again")}}, | ||
apiFields: config.StableAPIFields, | ||
expected: fmt.Errorf(`invalid parameter expression %s: indexing into array params requires "enable-api-fields" feature gate to be "alpha" or "beta"`, []string{"$(params.first-param[2])", "$(params.second-param[2])"}), | ||
}, | ||
} { | ||
tt := tt // capture range variable | ||
t.Run(tt.name, func(t *testing.T) { | ||
t.Parallel() | ||
Yongxuanzhang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
ctx := config.SetEnableAPIFields(context.Background(), tt.apiFields) | ||
err := tt.original.ValidateParamArrayIndex(ctx, tt.params) | ||
if d := cmp.Diff(tt.expected.Error(), err.Error()); d != "" { | ||
t.Errorf("ValidateParamArrayIndex() errors diff %s", diff.PrintWantGot(d)) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like this function and the above wrapper functions are only used for testing purpose. We may want to refactor this part of code to the
testing
package like: https://github.com/tektoncd/pipeline/blob/main/pkg/apis/config/testing/defaults.goThis gets more necessary when we expose this function, as the value set here is not validated at all. The risk is mitigated if this is in
testing
package, as production code should not reference it. WDYT?(But this can be addressed in separate PR)