diff --git a/pkg/apis/config/contexts.go b/pkg/apis/config/contexts.go index 8d0b4bb10e6..29b59c497f8 100644 --- a/pkg/apis/config/contexts.go +++ b/pkg/apis/config/contexts.go @@ -23,6 +23,9 @@ import ( // isSubstituted is used for associating the parameter substitution inside the context.Context. type isSubstituted struct{} +// validateEmbeddedVariables is used for deciding whether to validate or skip parameters and workspaces inside the contect.Context. +type validateEmbeddedVariables string + // WithinSubstituted is used to note that it is calling within // the context of a substitute variable operation. func WithinSubstituted(ctx context.Context) context.Context { @@ -33,3 +36,13 @@ func WithinSubstituted(ctx context.Context) context.Context { func IsSubstituted(ctx context.Context) bool { return ctx.Value(isSubstituted{}) != nil } + +// SetValidateParameterVariablesAndWorkspaces sets the context to skip validation of parameters when embedded vs referenced to true or false. +func SetValidateParameterVariablesAndWorkspaces(ctx context.Context, validate bool) context.Context { + return context.WithValue(ctx, validateEmbeddedVariables("ValidateParameterVariablesAndWorkspaces"), validate) +} + +// ValidateParameterVariablesAndWorkspaces indicates if validation of paramater variables and workspaces should be conducted. +func ValidateParameterVariablesAndWorkspaces(ctx context.Context) bool { + return ctx.Value(validateEmbeddedVariables("ValidateParameterVariablesAndWorkspaces")) == true +} diff --git a/pkg/apis/pipeline/v1/task_validation.go b/pkg/apis/pipeline/v1/task_validation.go index eddcc56e1ef..8133330c950 100644 --- a/pkg/apis/pipeline/v1/task_validation.go +++ b/pkg/apis/pipeline/v1/task_validation.go @@ -56,6 +56,7 @@ func (t *Task) Validate(ctx context.Context) *apis.FieldError { return nil } errs := validate.ObjectMetadata(t.GetObjectMeta()).ViaField("metadata") + ctx = config.SetValidateParameterVariablesAndWorkspaces(ctx, true) return errs.Also(t.Spec.Validate(apis.WithinSpec(ctx)).ViaField("spec")) } @@ -361,7 +362,9 @@ func ValidateParameterVariables(ctx context.Context, steps []Step, params []Para } errs = errs.Also(validateNameFormat(stringParameterNames.Insert(arrayParameterNames.List()...), objectParamSpecs)) - errs = errs.Also(validateVariables(ctx, steps, "params", allParameterNames)) + if config.ValidateParameterVariablesAndWorkspaces(ctx) == true { + errs = errs.Also(validateVariables(ctx, steps, "params", allParameterNames)) + } errs = errs.Also(validateArrayUsage(steps, "params", arrayParameterNames)) errs = errs.Also(validateObjectDefault(objectParamSpecs)) return errs.Also(validateObjectUsage(ctx, steps, objectParamSpecs)) @@ -563,9 +566,7 @@ func validateStepVariables(ctx context.Context, step Step, prefix string, vars s errs := validateTaskVariable(step.Name, prefix, vars).ViaField("name") errs = errs.Also(validateTaskVariable(step.Image, prefix, vars).ViaField("image")) errs = errs.Also(validateTaskVariable(step.WorkingDir, prefix, vars).ViaField("workingDir")) - if !(config.FromContextOrDefaults(ctx).FeatureFlags.EnableAPIFields == "alpha" && prefix == "params") { - errs = errs.Also(validateTaskVariable(step.Script, prefix, vars).ViaField("script")) - } + errs = errs.Also(validateTaskVariable(step.Script, prefix, vars).ViaField("script")) for i, cmd := range step.Command { errs = errs.Also(validateTaskVariable(cmd, prefix, vars).ViaFieldIndex("command", i)) } diff --git a/pkg/apis/pipeline/v1/task_validation_test.go b/pkg/apis/pipeline/v1/task_validation_test.go index c35314b3cd1..fee9ec14d45 100644 --- a/pkg/apis/pipeline/v1/task_validation_test.go +++ b/pkg/apis/pipeline/v1/task_validation_test.go @@ -53,6 +53,20 @@ func TestTaskValidate(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Name: "task"}, }, wc: apis.WithinDelete, + }, { + name: "valid task", + t: &v1.Task{ + ObjectMeta: metav1.ObjectMeta{Name: "task"}, + Spec: v1.TaskSpec{ + Steps: []v1.Step{{ + Name: "my-step", + Image: "my-image", + Script: ` + #!/usr/bin/env bash + echo hello`, + }}, + }, + }, }} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -68,6 +82,58 @@ func TestTaskValidate(t *testing.T) { } } +func TestTaskSpecValidatePropagatedParamsAndWorkspaces(t *testing.T) { + type fields struct { + Params []v1.ParamSpec + Steps []v1.Step + StepTemplate *v1.StepTemplate + Workspaces []v1.WorkspaceDeclaration + Results []v1.TaskResult + } + tests := []struct { + name string + fields fields + }{{ + name: "propagating params valid step with script", + fields: fields{ + Steps: []v1.Step{{ + Name: "propagatingparams", + Image: "my-image", + Script: ` + #!/usr/bin/env bash + $(params.message)`, + }}, + }, + }, { + name: "propagating params valid step with args", + fields: fields{ + Steps: []v1.Step{{ + Name: "propagatingparams", + Image: "my-image", + Command: []string{"$(params.command)"}, + Args: []string{"$(params.message)"}, + }}, + }, + }} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ts := &v1.TaskSpec{ + Params: tt.fields.Params, + Steps: tt.fields.Steps, + StepTemplate: tt.fields.StepTemplate, + Workspaces: tt.fields.Workspaces, + Results: tt.fields.Results, + } + ctx := config.EnableAlphaAPIFields(context.Background()) + ts.SetDefaults(ctx) + ctx = config.SetValidateParameterVariablesAndWorkspaces(ctx, false) + if err := ts.Validate(ctx); err != nil { + t.Errorf("TaskSpec.Validate() = %v", err) + } + }) + } +} + func TestTaskSpecValidate(t *testing.T) { type fields struct { Params []v1.ParamSpec @@ -1197,6 +1263,7 @@ func TestTaskSpecValidateError(t *testing.T) { } ctx := config.EnableAlphaAPIFields(context.Background()) ts.SetDefaults(ctx) + ctx = config.SetValidateParameterVariablesAndWorkspaces(ctx, true) err := ts.Validate(ctx) if err == nil { t.Fatalf("Expected an error, got nothing for %v", ts) @@ -1301,6 +1368,7 @@ func TestStepAndSidecarWorkspacesErrors(t *testing.T) { ctx := config.EnableAlphaAPIFields(context.Background()) ts.SetDefaults(ctx) + ctx = config.SetValidateParameterVariablesAndWorkspaces(ctx, false) err := ts.Validate(ctx) if err == nil { t.Fatalf("Expected an error, got nothing for %v", ts) @@ -1352,6 +1420,7 @@ func TestStepOnError(t *testing.T) { } ctx := context.Background() ts.SetDefaults(ctx) + ctx = config.SetValidateParameterVariablesAndWorkspaces(ctx, false) err := ts.Validate(ctx) if tt.expectedError == nil && err != nil { t.Errorf("TaskSpec.Validate() = %v", err) @@ -1445,8 +1514,8 @@ func TestIncompatibleAPIVersions(t *testing.T) { if version == "alpha" { ctx = config.EnableAlphaAPIFields(ctx) } - ts.SetDefaults(ctx) + ctx = config.SetValidateParameterVariablesAndWorkspaces(ctx, false) err := ts.Validate(ctx) if tt.requiredVersion != version && err == nil { @@ -1530,6 +1599,7 @@ func TestSubstitutedContext(t *testing.T) { } ctx := context.Background() ts.SetDefaults(ctx) + ctx = config.SetValidateParameterVariablesAndWorkspaces(ctx, true) if tt.fields.SubstitutionContext { ctx = config.WithinSubstituted(ctx) } diff --git a/pkg/apis/pipeline/v1beta1/cluster_task_validation.go b/pkg/apis/pipeline/v1beta1/cluster_task_validation.go index 127f94a0ea7..7ac617333c0 100644 --- a/pkg/apis/pipeline/v1beta1/cluster_task_validation.go +++ b/pkg/apis/pipeline/v1beta1/cluster_task_validation.go @@ -19,6 +19,7 @@ package v1beta1 import ( "context" + "github.com/tektoncd/pipeline/pkg/apis/config" "github.com/tektoncd/pipeline/pkg/apis/validate" "knative.dev/pkg/apis" ) @@ -31,5 +32,6 @@ func (t *ClusterTask) Validate(ctx context.Context) *apis.FieldError { return nil } errs := validate.ObjectMetadata(t.GetObjectMeta()).ViaField("metadata") + ctx = config.SetValidateParameterVariablesAndWorkspaces(ctx, true) return errs.Also(t.Spec.Validate(apis.WithinSpec(ctx)).ViaField("spec")) } diff --git a/pkg/apis/pipeline/v1beta1/task_validation.go b/pkg/apis/pipeline/v1beta1/task_validation.go index 335ecd52c49..4fd2b048efc 100644 --- a/pkg/apis/pipeline/v1beta1/task_validation.go +++ b/pkg/apis/pipeline/v1beta1/task_validation.go @@ -56,6 +56,7 @@ func (t *Task) Validate(ctx context.Context) *apis.FieldError { return nil } errs := validate.ObjectMetadata(t.GetObjectMeta()).ViaField("metadata") + ctx = config.SetValidateParameterVariablesAndWorkspaces(ctx, true) return errs.Also(t.Spec.Validate(apis.WithinSpec(ctx)).ViaField("spec")) } @@ -362,9 +363,10 @@ func ValidateParameterVariables(ctx context.Context, steps []Step, params []Para stringParameterNames.Insert(p.Name) } } - errs = errs.Also(validateNameFormat(stringParameterNames.Insert(arrayParameterNames.List()...), objectParamSpecs)) - errs = errs.Also(validateVariables(ctx, steps, "params", allParameterNames)) + if config.ValidateParameterVariablesAndWorkspaces(ctx) == true { + errs = errs.Also(validateVariables(ctx, steps, "params", allParameterNames)) + } errs = errs.Also(validateArrayUsage(steps, "params", arrayParameterNames)) errs = errs.Also(validateObjectDefault(objectParamSpecs)) return errs.Also(validateObjectUsage(ctx, steps, objectParamSpecs)) @@ -585,9 +587,7 @@ func validateStepVariables(ctx context.Context, step Step, prefix string, vars s errs := validateTaskVariable(step.Name, prefix, vars).ViaField("name") errs = errs.Also(validateTaskVariable(step.Image, prefix, vars).ViaField("image")) errs = errs.Also(validateTaskVariable(step.WorkingDir, prefix, vars).ViaField("workingDir")) - if !(config.FromContextOrDefaults(ctx).FeatureFlags.EnableAPIFields == "alpha" && prefix == "params") { - errs = errs.Also(validateTaskVariable(step.Script, prefix, vars).ViaField("script")) - } + errs = errs.Also(validateTaskVariable(step.Script, prefix, vars).ViaField("script")) for i, cmd := range step.Command { errs = errs.Also(validateTaskVariable(cmd, prefix, vars).ViaFieldIndex("command", i)) } diff --git a/pkg/apis/pipeline/v1beta1/task_validation_test.go b/pkg/apis/pipeline/v1beta1/task_validation_test.go index 3d69ad6ae00..4d3127fa953 100644 --- a/pkg/apis/pipeline/v1beta1/task_validation_test.go +++ b/pkg/apis/pipeline/v1beta1/task_validation_test.go @@ -67,6 +67,20 @@ func TestTaskValidate(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Name: "task"}, }, wc: apis.WithinDelete, + }, { + name: "valid task", + t: &v1beta1.Task{ + ObjectMeta: metav1.ObjectMeta{Name: "task"}, + Spec: v1beta1.TaskSpec{ + Steps: []v1beta1.Step{{ + Name: "my-step", + Image: "my-image", + Script: ` + #!/usr/bin/env bash + echo hello`, + }}, + }, + }, }} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -82,6 +96,60 @@ func TestTaskValidate(t *testing.T) { } } +func TestTaskSpecValidatePropagatedParamsAndWorkspaces(t *testing.T) { + type fields struct { + Params []v1beta1.ParamSpec + Resources *v1beta1.TaskResources + Steps []v1beta1.Step + StepTemplate *v1beta1.StepTemplate + Workspaces []v1beta1.WorkspaceDeclaration + Results []v1beta1.TaskResult + } + tests := []struct { + name string + fields fields + }{{ + name: "propagating params valid step with script", + fields: fields{ + Steps: []v1beta1.Step{{ + Name: "propagatingparams", + Image: "my-image", + Script: ` + #!/usr/bin/env bash + $(params.message)`, + }}, + }, + }, { + name: "propagating params valid step with args", + fields: fields{ + Steps: []v1beta1.Step{{ + Name: "propagatingparams", + Image: "my-image", + Command: []string{"$(params.command)"}, + Args: []string{"$(params.message)"}, + }}, + }, + }} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ts := &v1beta1.TaskSpec{ + Params: tt.fields.Params, + Resources: tt.fields.Resources, + Steps: tt.fields.Steps, + StepTemplate: tt.fields.StepTemplate, + Workspaces: tt.fields.Workspaces, + Results: tt.fields.Results, + } + ctx := config.EnableAlphaAPIFields(context.Background()) + ts.SetDefaults(ctx) + ctx = config.SetValidateParameterVariablesAndWorkspaces(ctx, false) + if err := ts.Validate(ctx); err != nil { + t.Errorf("TaskSpec.Validate() = %v", err) + } + }) + } +} + func TestTaskSpecValidate(t *testing.T) { type fields struct { Params []v1beta1.ParamSpec @@ -1305,6 +1373,7 @@ func TestTaskSpecValidateError(t *testing.T) { } ctx := config.EnableAlphaAPIFields(context.Background()) ts.SetDefaults(ctx) + ctx = config.SetValidateParameterVariablesAndWorkspaces(ctx, true) err := ts.Validate(ctx) if err == nil { t.Fatalf("Expected an error, got nothing for %v", ts) @@ -1352,6 +1421,7 @@ func TestStepAndSidecarWorkspaces(t *testing.T) { } ctx := config.EnableAlphaAPIFields(context.Background()) ts.SetDefaults(ctx) + ctx = config.SetValidateParameterVariablesAndWorkspaces(ctx, false) if err := ts.Validate(ctx); err != nil { t.Errorf("TaskSpec.Validate() = %v", err) } @@ -1409,6 +1479,7 @@ func TestStepAndSidecarWorkspacesErrors(t *testing.T) { ctx := config.EnableAlphaAPIFields(context.Background()) ts.SetDefaults(ctx) + ctx = config.SetValidateParameterVariablesAndWorkspaces(ctx, false) err := ts.Validate(ctx) if err == nil { t.Fatalf("Expected an error, got nothing for %v", ts) @@ -1460,6 +1531,7 @@ func TestStepOnError(t *testing.T) { } ctx := context.Background() ts.SetDefaults(ctx) + ctx = config.SetValidateParameterVariablesAndWorkspaces(ctx, true) err := ts.Validate(ctx) if tt.expectedError == nil && err != nil { t.Errorf("TaskSpec.Validate() = %v", err) @@ -1553,8 +1625,8 @@ func TestIncompatibleAPIVersions(t *testing.T) { if version == "alpha" { ctx = config.EnableAlphaAPIFields(ctx) } - ts.SetDefaults(ctx) + ctx = config.SetValidateParameterVariablesAndWorkspaces(ctx, false) err := ts.Validate(ctx) if tt.requiredVersion != version && err == nil { @@ -1638,6 +1710,7 @@ func TestSubstitutedContext(t *testing.T) { } ctx := context.Background() ts.SetDefaults(ctx) + ctx = config.SetValidateParameterVariablesAndWorkspaces(ctx, true) if tt.fields.SubstitutionContext { ctx = config.WithinSubstituted(ctx) } diff --git a/pkg/apis/pipeline/v1beta1/taskrun_validation.go b/pkg/apis/pipeline/v1beta1/taskrun_validation.go index 7e432ea4c8d..06ae0200149 100644 --- a/pkg/apis/pipeline/v1beta1/taskrun_validation.go +++ b/pkg/apis/pipeline/v1beta1/taskrun_validation.go @@ -55,10 +55,15 @@ func (ts *TaskRunSpec) Validate(ctx context.Context) (errs *apis.FieldError) { } // Validate TaskSpec if it's present. if ts.TaskSpec != nil { + // skip validation of parameter and workspaces variables since we validate them via taskrunspec below. + ctx = config.SetValidateParameterVariablesAndWorkspaces(ctx, false) errs = errs.Also(ts.TaskSpec.Validate(ctx).ViaField("taskSpec")) } errs = errs.Also(ValidateParameters(ctx, ts.Params).ViaField("params")) + + // Validate propagated parameters + errs = errs.Also(ts.validateInlineParameters(ctx)) errs = errs.Also(ValidateWorkspaceBindings(ctx, ts.Workspaces).ViaField("workspaces")) errs = errs.Also(ts.Resources.Validate(ctx).ViaField("resources")) if ts.Debug != nil { @@ -99,6 +104,42 @@ func (ts *TaskRunSpec) Validate(ctx context.Context) (errs *apis.FieldError) { return errs } +// validateInlineParameters validates that any parameters called in the +// Task spec are declared in the TaskRun. +// This is crucial for propagated parameters because the parameters could +// be defined under taskRun and then called directly in the task steps. +// In this case, parameters cannot be validated by the underlying taskSpec +// since they may not have the parameters declared because of propagation. +func (ts *TaskRunSpec) validateInlineParameters(ctx context.Context) (errs *apis.FieldError) { + if ts.TaskSpec == nil { + return errs + } + var paramSpec []ParamSpec + for _, p := range ts.Params { + pSpec := ParamSpec{ + Name: p.Name, + Default: &p.Value, + } + paramSpec = append(paramSpec, pSpec) + } + for _, p := range ts.TaskSpec.Params { + skip := false + for _, ps := range paramSpec { + if ps.Name == p.Name { + skip = true + break + } + } + if !skip { + paramSpec = append(paramSpec, p) + } + } + if ts.TaskSpec != nil && ts.TaskSpec.Steps != nil { + errs = errs.Also(ValidateParameterVariables(config.SetValidateParameterVariablesAndWorkspaces(ctx, true), ts.TaskSpec.Steps, paramSpec)) + } + return errs +} + // validateDebug func validateDebug(db *TaskRunDebug) (errs *apis.FieldError) { breakpointOnFailure := "onFailure" diff --git a/pkg/apis/pipeline/v1beta1/taskrun_validation_test.go b/pkg/apis/pipeline/v1beta1/taskrun_validation_test.go index 0c2ebcd41fe..2792bd34b8c 100644 --- a/pkg/apis/pipeline/v1beta1/taskrun_validation_test.go +++ b/pkg/apis/pipeline/v1beta1/taskrun_validation_test.go @@ -38,15 +38,40 @@ func TestTaskRun_Invalidate(t *testing.T) { name string taskRun *v1beta1.TaskRun want *apis.FieldError + wc func(context.Context) context.Context }{{ name: "invalid taskspec", taskRun: &v1beta1.TaskRun{}, want: apis.ErrMissingOneOf("spec.taskRef", "spec.taskSpec").Also( apis.ErrGeneric(`invalid resource name "": must be a valid DNS label`, "metadata.name")), + }, { + name: "propagating params not provided but used by step", + taskRun: &v1beta1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{Name: "tr"}, + Spec: v1beta1.TaskRunSpec{ + TaskSpec: &v1beta1.TaskSpec{ + Steps: []v1beta1.Step{{ + Name: "echo", + Image: "ubuntu", + Command: []string{"echo"}, + Args: []string{"$(params.task-words[*])"}, + }}, + }, + }, + }, + want: &apis.FieldError{ + Message: `non-existent variable in "$(params.task-words[*])"`, + Paths: []string{"spec.steps[0].args[0]"}, + }, + wc: config.EnableAlphaAPIFields, }} for _, ts := range tests { t.Run(ts.name, func(t *testing.T) { - err := ts.taskRun.Validate(context.Background()) + ctx := context.Background() + if ts.wc != nil { + ctx = ts.wc(ctx) + } + err := ts.taskRun.Validate(ctx) if d := cmp.Diff(ts.want.Error(), err.Error()); d != "" { t.Error(diff.PrintWantGot(d)) } @@ -65,6 +90,119 @@ func TestTaskRun_Validate(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Name: "taskrname"}, }, wc: apis.WithinDelete, + }, { + name: "propagating params with taskrun", + taskRun: &v1beta1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{Name: "tr"}, + Spec: v1beta1.TaskRunSpec{ + Params: []v1beta1.Param{{ + Name: "task-words", + Value: v1beta1.ArrayOrString{ + ArrayVal: []string{"hello", "task run"}, + }, + }}, + TaskSpec: &v1beta1.TaskSpec{ + Steps: []v1beta1.Step{{ + Name: "echo", + Image: "ubuntu", + Command: []string{"echo"}, + Args: []string{"$(params.task-words[*])"}, + }}, + }, + }, + }, + wc: config.EnableAlphaAPIFields, + }, { + name: "propagating partial params with different provided and default names", + taskRun: &v1beta1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{Name: "tr"}, + Spec: v1beta1.TaskRunSpec{ + Params: []v1beta1.Param{{ + Name: "task-words", + Value: v1beta1.ArrayOrString{ + ArrayVal: []string{"hello", "task run"}, + }, + }}, + TaskSpec: &v1beta1.TaskSpec{ + Params: []v1beta1.ParamSpec{{ + Name: "task-words-2", + Type: v1beta1.ParamTypeArray, + }}, + Steps: []v1beta1.Step{{ + Name: "task-echo", + Image: "ubuntu", + Command: []string{"echo"}, + Args: []string{"$(params.task-words[*])"}, + }, { + Name: "task-echo-2", + Image: "ubuntu", + Command: []string{"echo"}, + Args: []string{"$(params.task-words-2[*])"}, + }}, + }, + }, + }, + wc: config.EnableAlphaAPIFields, + }, { + name: "propagating partial params in taskrun", + taskRun: &v1beta1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{Name: "tr"}, + Spec: v1beta1.TaskRunSpec{ + Params: []v1beta1.Param{{ + Name: "task-words", + Value: v1beta1.ArrayOrString{ + ArrayVal: []string{"hello", "task run"}, + }, + }}, + TaskSpec: &v1beta1.TaskSpec{ + Params: []v1beta1.ParamSpec{{ + Name: "task-words-2", + Type: v1beta1.ParamTypeArray, + }, { + Name: "task-words", + Type: v1beta1.ParamTypeArray, + }}, + Steps: []v1beta1.Step{{ + Name: "echo", + Image: "ubuntu", + Command: []string{"echo"}, + Args: []string{"$(params.task-words[*])"}, + }, { + Name: "echo-2", + Image: "ubuntu", + Command: []string{"echo"}, + Args: []string{"$(params.task-words-2[*])"}, + }}, + }, + }, + }, + wc: config.EnableAlphaAPIFields, + }, { + name: "propagating params with taskrun same names", + taskRun: &v1beta1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{Name: "tr"}, + Spec: v1beta1.TaskRunSpec{ + Params: []v1beta1.Param{{ + Name: "task-words", + Value: v1beta1.ArrayOrString{ + ArrayVal: []string{"hello", "task run"}, + }, + }}, + TaskSpec: &v1beta1.TaskSpec{ + Params: []v1beta1.ParamSpec{{ + Name: "task-words", + Type: v1beta1.ParamTypeArray, + }}, + Steps: []v1beta1.Step{{ + Name: "echo", + Image: "ubuntu", + Command: []string{"echo"}, + Args: []string{"$(params.task-words[*])"}, + }}, + }, + }, + }, + wc: config.EnableAlphaAPIFields, }, { name: "alpha feature: valid step and sidecar overrides", taskRun: &v1beta1.TaskRun{ diff --git a/pkg/reconciler/taskrun/taskrun.go b/pkg/reconciler/taskrun/taskrun.go index 5947130224b..65181b918dc 100644 --- a/pkg/reconciler/taskrun/taskrun.go +++ b/pkg/reconciler/taskrun/taskrun.go @@ -704,6 +704,9 @@ func (c *Reconciler) createPod(ctx context.Context, ts *v1beta1.TaskSpec, tr *v1 // Apply workspace resource substitution ts = resources.ApplyWorkspaces(ctx, ts, ts.Workspaces, tr.Spec.Workspaces, workspaceVolumes) + // By this time, params and workspaces should be propagated down so we can + // validate that all parameter variables and workspaces used in the TaskSpec are declared by the Task. + ctx = config.SetValidateParameterVariablesAndWorkspaces(ctx, true) if validateErr := ts.Validate(ctx); validateErr != nil { logger.Errorf("Failed to create a pod for taskrun: %s due to task validation error %v", tr.Name, validateErr) return nil, validateErr