diff --git a/docs/pipeline-api.md b/docs/pipeline-api.md index a2656ffaef2..29a72a924ab 100644 --- a/docs/pipeline-api.md +++ b/docs/pipeline-api.md @@ -3437,7 +3437,7 @@ ParamType

Provenance

-(Appears on:PipelineRunStatusFields, TaskRunStatusFields) +(Appears on:PipelineRunStatusFields, StepState, TaskRunStatusFields)

Provenance contains metadata about resources used in the TaskRun/PipelineRun @@ -4841,6 +4841,18 @@ string +provenance
+ + +Provenance + + + + + + + + terminationReason
string @@ -12759,7 +12771,7 @@ ParamType

Provenance

-(Appears on:PipelineRunStatusFields, TaskRunStatusFields) +(Appears on:PipelineRunStatusFields, StepState, TaskRunStatusFields)

Provenance contains metadata about resources used in the TaskRun/PipelineRun @@ -14410,6 +14422,18 @@ string +provenance
+ + +Provenance + + + + + + + + inputs
diff --git a/go.mod b/go.mod index d3eec4c37eb..445e464ee3e 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,7 @@ module github.com/tektoncd/pipeline go 1.22 + toolchain go1.22.4 require ( diff --git a/pkg/apis/pipeline/v1/openapi_generated.go b/pkg/apis/pipeline/v1/openapi_generated.go index 928f446c294..bfeb3fe979e 100644 --- a/pkg/apis/pipeline/v1/openapi_generated.go +++ b/pkg/apis/pipeline/v1/openapi_generated.go @@ -3274,6 +3274,11 @@ func schema_pkg_apis_pipeline_v1_StepState(ref common.ReferenceCallback) common. }, }, }, + "provenance": { + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/tektoncd/pipeline/pkg/apis/pipeline/v1.Provenance"), + }, + }, "terminationReason": { SchemaProps: spec.SchemaProps{ Type: []string{"string"}, @@ -3310,7 +3315,7 @@ func schema_pkg_apis_pipeline_v1_StepState(ref common.ReferenceCallback) common. }, }, Dependencies: []string{ - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1.Artifact", "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1.TaskRunResult", "k8s.io/api/core/v1.ContainerStateRunning", "k8s.io/api/core/v1.ContainerStateTerminated", "k8s.io/api/core/v1.ContainerStateWaiting"}, + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1.Artifact", "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1.Provenance", "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1.TaskRunResult", "k8s.io/api/core/v1.ContainerStateRunning", "k8s.io/api/core/v1.ContainerStateTerminated", "k8s.io/api/core/v1.ContainerStateWaiting"}, } } diff --git a/pkg/apis/pipeline/v1/swagger.json b/pkg/apis/pipeline/v1/swagger.json index 4ece3c37804..bb7ec2abed2 100644 --- a/pkg/apis/pipeline/v1/swagger.json +++ b/pkg/apis/pipeline/v1/swagger.json @@ -1671,6 +1671,9 @@ "$ref": "#/definitions/v1.Artifact" } }, + "provenance": { + "$ref": "#/definitions/v1.Provenance" + }, "results": { "type": "array", "items": { diff --git a/pkg/apis/pipeline/v1/taskrun_types.go b/pkg/apis/pipeline/v1/taskrun_types.go index f2ae83a91fc..ea6e517649e 100644 --- a/pkg/apis/pipeline/v1/taskrun_types.go +++ b/pkg/apis/pipeline/v1/taskrun_types.go @@ -364,6 +364,7 @@ type StepState struct { Container string `json:"container,omitempty"` ImageID string `json:"imageID,omitempty"` Results []TaskRunStepResult `json:"results,omitempty"` + Provenance *Provenance `json:"provenance,omitempty"` TerminationReason string `json:"terminationReason,omitempty"` Inputs []TaskRunStepArtifact `json:"inputs,omitempty"` Outputs []TaskRunStepArtifact `json:"outputs,omitempty"` diff --git a/pkg/apis/pipeline/v1/zz_generated.deepcopy.go b/pkg/apis/pipeline/v1/zz_generated.deepcopy.go index 5b8ca4bb07c..780ac13907c 100644 --- a/pkg/apis/pipeline/v1/zz_generated.deepcopy.go +++ b/pkg/apis/pipeline/v1/zz_generated.deepcopy.go @@ -1455,6 +1455,11 @@ func (in *StepState) DeepCopyInto(out *StepState) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.Provenance != nil { + in, out := &in.Provenance, &out.Provenance + *out = new(Provenance) + (*in).DeepCopyInto(*out) + } if in.Inputs != nil { in, out := &in.Inputs, &out.Inputs *out = make([]Artifact, len(*in)) diff --git a/pkg/apis/pipeline/v1beta1/openapi_generated.go b/pkg/apis/pipeline/v1beta1/openapi_generated.go index dde2863832c..0939abfb962 100644 --- a/pkg/apis/pipeline/v1beta1/openapi_generated.go +++ b/pkg/apis/pipeline/v1beta1/openapi_generated.go @@ -4435,6 +4435,11 @@ func schema_pkg_apis_pipeline_v1beta1_StepState(ref common.ReferenceCallback) co }, }, }, + "provenance": { + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1.Provenance"), + }, + }, "inputs": { SchemaProps: spec.SchemaProps{ Type: []string{"array"}, @@ -4465,7 +4470,7 @@ func schema_pkg_apis_pipeline_v1beta1_StepState(ref common.ReferenceCallback) co }, }, Dependencies: []string{ - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1.Artifact", "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1.TaskRunResult", "k8s.io/api/core/v1.ContainerStateRunning", "k8s.io/api/core/v1.ContainerStateTerminated", "k8s.io/api/core/v1.ContainerStateWaiting"}, + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1.Artifact", "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1.Provenance", "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1.TaskRunResult", "k8s.io/api/core/v1.ContainerStateRunning", "k8s.io/api/core/v1.ContainerStateTerminated", "k8s.io/api/core/v1.ContainerStateWaiting"}, } } diff --git a/pkg/apis/pipeline/v1beta1/swagger.json b/pkg/apis/pipeline/v1beta1/swagger.json index e17ab8e0f33..ef37183febd 100644 --- a/pkg/apis/pipeline/v1beta1/swagger.json +++ b/pkg/apis/pipeline/v1beta1/swagger.json @@ -2433,6 +2433,9 @@ "$ref": "#/definitions/v1beta1.Artifact" } }, + "provenance": { + "$ref": "#/definitions/v1beta1.Provenance" + }, "results": { "type": "array", "items": { diff --git a/pkg/apis/pipeline/v1beta1/taskrun_conversion.go b/pkg/apis/pipeline/v1beta1/taskrun_conversion.go index e9b1bed4f7a..7b749ac5afb 100644 --- a/pkg/apis/pipeline/v1beta1/taskrun_conversion.go +++ b/pkg/apis/pipeline/v1beta1/taskrun_conversion.go @@ -345,6 +345,12 @@ func (ss StepState) convertTo(ctx context.Context, sink *v1.StepState) { sink.ImageID = ss.ImageID sink.Results = nil + if ss.Provenance != nil { + new := v1.Provenance{} + ss.Provenance.convertTo(ctx, &new) + sink.Provenance = &new + } + if ss.ContainerState.Terminated != nil { sink.TerminationReason = ss.ContainerState.Terminated.Reason } @@ -379,6 +385,11 @@ func (ss *StepState) convertFrom(ctx context.Context, source v1.StepState) { new.convertFrom(ctx, r) ss.Results = append(ss.Results, new) } + if source.Provenance != nil { + new := Provenance{} + new.convertFrom(ctx, *source.Provenance) + ss.Provenance = &new + } for _, o := range source.Outputs { new := TaskRunStepArtifact{} new.convertFrom(ctx, o) diff --git a/pkg/apis/pipeline/v1beta1/taskrun_conversion_test.go b/pkg/apis/pipeline/v1beta1/taskrun_conversion_test.go index 9bf4eae0cda..bc7d0247364 100644 --- a/pkg/apis/pipeline/v1beta1/taskrun_conversion_test.go +++ b/pkg/apis/pipeline/v1beta1/taskrun_conversion_test.go @@ -126,6 +126,27 @@ func TestTaskRunConversion(t *testing.T) { }, }, }, + }, { + name: "taskrun with provenance in step state", + in: &v1beta1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + }, + Spec: v1beta1.TaskRunSpec{}, + Status: v1beta1.TaskRunStatus{ + TaskRunStatusFields: v1beta1.TaskRunStatusFields{ + Steps: []v1beta1.StepState{{ + Provenance: &v1beta1.Provenance{ + RefSource: &v1beta1.RefSource{ + URI: "test-uri", + Digest: map[string]string{"sha256": "digest"}, + }, + }, + }}, + }, + }, + }, }, { name: "taskrun conversion all non deprecated fields", in: &v1beta1.TaskRun{ diff --git a/pkg/apis/pipeline/v1beta1/taskrun_types.go b/pkg/apis/pipeline/v1beta1/taskrun_types.go index 551a5856ed6..26707ff337f 100644 --- a/pkg/apis/pipeline/v1beta1/taskrun_types.go +++ b/pkg/apis/pipeline/v1beta1/taskrun_types.go @@ -372,6 +372,7 @@ type StepState struct { ContainerName string `json:"container,omitempty"` ImageID string `json:"imageID,omitempty"` Results []TaskRunStepResult `json:"results,omitempty"` + Provenance *Provenance `json:"provenance,omitempty"` Inputs []TaskRunStepArtifact `json:"inputs,omitempty"` Outputs []TaskRunStepArtifact `json:"outputs,omitempty"` } diff --git a/pkg/apis/pipeline/v1beta1/zz_generated.deepcopy.go b/pkg/apis/pipeline/v1beta1/zz_generated.deepcopy.go index e2e55e8f8d9..69ecd283769 100644 --- a/pkg/apis/pipeline/v1beta1/zz_generated.deepcopy.go +++ b/pkg/apis/pipeline/v1beta1/zz_generated.deepcopy.go @@ -2024,6 +2024,11 @@ func (in *StepState) DeepCopyInto(out *StepState) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.Provenance != nil { + in, out := &in.Provenance, &out.Provenance + *out = new(Provenance) + (*in).DeepCopyInto(*out) + } if in.Inputs != nil { in, out := &in.Inputs, &out.Inputs *out = make([]Artifact, len(*in)) diff --git a/pkg/pod/entrypoint.go b/pkg/pod/entrypoint.go index e6117c0defc..17830a27dab 100644 --- a/pkg/pod/entrypoint.go +++ b/pkg/pod/entrypoint.go @@ -352,8 +352,8 @@ func IsContainerStep(name string) bool { return strings.HasPrefix(name, stepPref // represents a sidecar. func IsContainerSidecar(name string) bool { return strings.HasPrefix(name, sidecarPrefix) } -// trimStepPrefix returns the container name, stripped of its step prefix. -func trimStepPrefix(name string) string { return strings.TrimPrefix(name, stepPrefix) } +// TrimStepPrefix returns the container name, stripped of its step prefix. +func TrimStepPrefix(name string) string { return strings.TrimPrefix(name, stepPrefix) } // TrimSidecarPrefix returns the container name, stripped of its sidecar // prefix. diff --git a/pkg/pod/status.go b/pkg/pod/status.go index bee46ebcf90..9f2e74cbf52 100644 --- a/pkg/pod/status.go +++ b/pkg/pod/status.go @@ -139,7 +139,6 @@ func MakeTaskRunStatus(ctx context.Context, logger *zap.SugaredLogger, tr v1.Tas } trs.PodName = pod.Name - trs.Steps = []v1.StepState{} trs.Sidecars = []v1.SidecarState{} var stepStatuses []corev1.ContainerStatus @@ -360,17 +359,28 @@ func setTaskRunStatusBasedOnStepStatus(ctx context.Context, logger *zap.SugaredL terminationReason = getTerminationReason(state.Terminated.Reason, terminationFromResults, exitCode) } } - - trs.Steps = append(trs.Steps, v1.StepState{ + stepState := v1.StepState{ ContainerState: *state, - Name: trimStepPrefix(s.Name), + Name: TrimStepPrefix(s.Name), Container: s.Name, ImageID: s.ImageID, Results: taskRunStepResults, TerminationReason: terminationReason, Inputs: sas.Inputs, Outputs: sas.Outputs, - }) + } + foundStep := false + for i, ss := range trs.Steps { + if ss.Name == stepState.Name { + stepState.Provenance = ss.Provenance + trs.Steps[i] = stepState + foundStep = true + break + } + } + if !foundStep { + trs.Steps = append(trs.Steps, stepState) + } } return merr diff --git a/pkg/pod/status_test.go b/pkg/pod/status_test.go index 12fb0c80809..e11b9946208 100644 --- a/pkg/pod/status_test.go +++ b/pkg/pod/status_test.go @@ -490,6 +490,177 @@ func TestMakeTaskRunStatus_StepResults(t *testing.T) { } } +func TestMakeTaskRunStatus_StepProvenance(t *testing.T) { + for _, c := range []struct { + desc string + podStatus corev1.PodStatus + pod corev1.Pod + tr v1.TaskRun + want v1.TaskRunStatus + }{{ + desc: "provenance in step", + podStatus: corev1.PodStatus{ + Phase: corev1.PodSucceeded, + ContainerStatuses: []corev1.ContainerStatus{{ + Name: "step-one", + State: corev1.ContainerState{ + Terminated: &corev1.ContainerStateTerminated{}, + }, + }}, + }, + tr: v1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "task-run", + Namespace: "foo", + }, + Spec: v1.TaskRunSpec{ + TaskSpec: &v1.TaskSpec{ + Steps: []v1.Step{{ + Name: "one", + Image: "bash", + }}, + }, + }, + Status: v1.TaskRunStatus{ + TaskRunStatusFields: v1.TaskRunStatusFields{ + Steps: []v1.StepState{{ + Name: "one", + Provenance: &v1.Provenance{RefSource: &v1.RefSource{ + URI: "pkg://foo/bar", + Digest: map[string]string{"sha256": "digest"}, + }}, + }}, + }, + }, + }, + want: v1.TaskRunStatus{ + Status: statusSuccess(), + TaskRunStatusFields: v1.TaskRunStatusFields{ + Steps: []v1.StepState{{ + ContainerState: corev1.ContainerState{ + Terminated: &corev1.ContainerStateTerminated{}, + }, + Name: "one", + Container: "step-one", + Results: []v1.TaskRunResult{}, + Provenance: &v1.Provenance{RefSource: &v1.RefSource{ + URI: "pkg://foo/bar", + Digest: map[string]string{"sha256": "digest"}, + }}, + }}, + Sidecars: []v1.SidecarState{}, + // We don't actually care about the time, just that it's not nil + CompletionTime: &metav1.Time{Time: time.Now()}, + }, + }, + }, { + desc: "provenance in some steps", + podStatus: corev1.PodStatus{ + Phase: corev1.PodSucceeded, + ContainerStatuses: []corev1.ContainerStatus{{ + Name: "step-one", + State: corev1.ContainerState{ + Terminated: &corev1.ContainerStateTerminated{}, + }, + }, { + Name: "step-two", + State: corev1.ContainerState{ + Terminated: &corev1.ContainerStateTerminated{}, + }, + }}, + }, + tr: v1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "task-run", + Namespace: "foo", + }, + Spec: v1.TaskRunSpec{ + TaskSpec: &v1.TaskSpec{ + Steps: []v1.Step{{ + Name: "one", + Image: "bash", + }, { + Name: "two", + Image: "bash", + }}, + }, + }, + Status: v1.TaskRunStatus{ + TaskRunStatusFields: v1.TaskRunStatusFields{ + Steps: []v1.StepState{{ + Name: "one", + Provenance: &v1.Provenance{RefSource: &v1.RefSource{ + URI: "pkg://foo/bar", + Digest: map[string]string{"sha256": "digest"}, + }}, + }}, + }, + }, + }, + want: v1.TaskRunStatus{ + Status: statusSuccess(), + TaskRunStatusFields: v1.TaskRunStatusFields{ + Steps: []v1.StepState{{ + ContainerState: corev1.ContainerState{ + Terminated: &corev1.ContainerStateTerminated{}, + }, + Name: "one", + Container: "step-one", + Results: []v1.TaskRunResult{}, + Provenance: &v1.Provenance{RefSource: &v1.RefSource{ + URI: "pkg://foo/bar", + Digest: map[string]string{"sha256": "digest"}, + }}, + }, { + ContainerState: corev1.ContainerState{ + Terminated: &corev1.ContainerStateTerminated{}, + }, + Name: "two", + Container: "step-two", + Results: []v1.TaskRunResult{}, + }}, + Sidecars: []v1.SidecarState{}, + // We don't actually care about the time, just that it's not nil + CompletionTime: &metav1.Time{Time: time.Now()}, + }, + }, + }} { + t.Run(c.desc, func(t *testing.T) { + now := metav1.Now() + if cmp.Diff(c.pod, corev1.Pod{}) == "" { + c.pod = corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod", + Namespace: "foo", + CreationTimestamp: now, + }, + Status: c.podStatus, + } + } + + logger, _ := logging.NewLogger("", "status") + kubeclient := fakek8s.NewSimpleClientset() + got, err := MakeTaskRunStatus(context.Background(), logger, c.tr, &c.pod, kubeclient, c.tr.Spec.TaskSpec) + if err != nil { + t.Errorf("MakeTaskRunResult: %s", err) + } + + // Common traits, set for test case brevity. + c.want.PodName = "pod" + + ensureTimeNotNil := cmp.Comparer(func(x, y *metav1.Time) bool { + if x == nil { + return y == nil + } + return y != nil + }) + if d := cmp.Diff(c.want, got, ignoreVolatileTime, ensureTimeNotNil); d != "" { + t.Errorf("Diff %s", diff.PrintWantGot(d)) + } + }) + } +} + func TestMakeTaskRunStatus_StepArtifacts(t *testing.T) { for _, c := range []struct { desc string @@ -640,7 +811,6 @@ func TestMakeTaskRunStatus(t *testing.T) { want: v1.TaskRunStatus{ Status: statusRunning(), TaskRunStatusFields: v1.TaskRunStatusFields{ - Steps: []v1.StepState{}, Sidecars: []v1.SidecarState{}, }, }, @@ -810,7 +980,6 @@ func TestMakeTaskRunStatus(t *testing.T) { want: v1.TaskRunStatus{ Status: statusFailure(v1.TaskRunReasonFailed.String(), "boom"), TaskRunStatusFields: v1.TaskRunStatusFields{ - Steps: []v1.StepState{}, Sidecars: []v1.SidecarState{}, // We don't actually care about the time, just that it's not nil CompletionTime: &metav1.Time{Time: time.Now()}, @@ -855,7 +1024,6 @@ func TestMakeTaskRunStatus(t *testing.T) { want: v1.TaskRunStatus{ Status: statusFailure(v1.TaskRunReasonFailed.String(), "build failed for unspecified reasons."), TaskRunStatusFields: v1.TaskRunStatusFields{ - Steps: []v1.StepState{}, Sidecars: []v1.SidecarState{}, // We don't actually care about the time, just that it's not nil CompletionTime: &metav1.Time{Time: time.Now()}, @@ -905,7 +1073,6 @@ func TestMakeTaskRunStatus(t *testing.T) { want: v1.TaskRunStatus{ Status: statusPending("Pending", `pod status "the type":"Unknown"; message: "the message"`), TaskRunStatusFields: v1.TaskRunStatusFields{ - Steps: []v1.StepState{}, Sidecars: []v1.SidecarState{}, }, }, @@ -918,7 +1085,6 @@ func TestMakeTaskRunStatus(t *testing.T) { want: v1.TaskRunStatus{ Status: statusPending("Pending", "pod status message"), TaskRunStatusFields: v1.TaskRunStatusFields{ - Steps: []v1.StepState{}, Sidecars: []v1.SidecarState{}, }, }, @@ -928,7 +1094,6 @@ func TestMakeTaskRunStatus(t *testing.T) { want: v1.TaskRunStatus{ Status: statusPending("Pending", "Pending"), TaskRunStatusFields: v1.TaskRunStatusFields{ - Steps: []v1.StepState{}, Sidecars: []v1.SidecarState{}, }, }, @@ -944,7 +1109,6 @@ func TestMakeTaskRunStatus(t *testing.T) { want: v1.TaskRunStatus{ Status: statusPending(ReasonExceededNodeResources, "TaskRun Pod exceeded available resources"), TaskRunStatusFields: v1.TaskRunStatusFields{ - Steps: []v1.StepState{}, Sidecars: []v1.SidecarState{}, }, }, @@ -963,7 +1127,6 @@ func TestMakeTaskRunStatus(t *testing.T) { want: v1.TaskRunStatus{ Status: statusFailure(ReasonCreateContainerConfigError, "Failed to create pod due to config error"), TaskRunStatusFields: v1.TaskRunStatusFields{ - Steps: []v1.StepState{}, Sidecars: []v1.SidecarState{}, }, }, diff --git a/pkg/reconciler/taskrun/resources/taskspec.go b/pkg/reconciler/taskrun/resources/taskspec.go index 33275935010..ae4e89c3f2c 100644 --- a/pkg/reconciler/taskrun/resources/taskspec.go +++ b/pkg/reconciler/taskrun/resources/taskspec.go @@ -25,6 +25,7 @@ import ( "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" clientset "github.com/tektoncd/pipeline/pkg/client/clientset/versioned" resolutionutil "github.com/tektoncd/pipeline/pkg/internal/resolution" + "github.com/tektoncd/pipeline/pkg/pod" remoteresource "github.com/tektoncd/pipeline/pkg/remoteresolution/resource" "github.com/tektoncd/pipeline/pkg/trustedresources" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -103,14 +104,40 @@ func GetTaskData(ctx context.Context, taskRun *v1.TaskRun, getTask GetTask) (*re // GetStepActionsData extracts the StepActions and merges them with the inlined Step specification. func GetStepActionsData(ctx context.Context, taskSpec v1.TaskSpec, taskRun *v1.TaskRun, tekton clientset.Interface, k8s kubernetes.Interface, requester remoteresource.Requester) ([]v1.Step, error) { steps := []v1.Step{} - for _, step := range taskSpec.Steps { + for i, step := range taskSpec.Steps { s := step.DeepCopy() if step.Ref != nil { getStepAction := GetStepActionFunc(tekton, k8s, requester, taskRun, s) - stepAction, _, err := getStepAction(ctx, s.Ref.Name) + stepAction, source, err := getStepAction(ctx, s.Ref.Name) if err != nil { return nil, err } + // update stepstate with remote origin information + if source != nil { + found := false + for i, st := range taskRun.Status.Steps { + if st.Name == s.Name { + found = true + if st.Provenance != nil { + taskRun.Status.Steps[i].Provenance.RefSource = source + } else { + taskRun.Status.Steps[i].Provenance = &v1.Provenance{RefSource: source} + } + break + } + } + if !found { + stp := v1.StepState{ + Name: pod.TrimStepPrefix(pod.StepName(s.Name, i)), + Provenance: &v1.Provenance{RefSource: source}, + } + if len(taskRun.Status.Steps) == 0 { + taskRun.Status.Steps = []v1.StepState{stp} + } else { + taskRun.Status.Steps = append(taskRun.Status.Steps, stp) + } + } + } stepActionSpec := stepAction.StepActionSpec() stepActionSpec.SetDefaults(ctx) diff --git a/pkg/reconciler/taskrun/resources/taskspec_test.go b/pkg/reconciler/taskrun/resources/taskspec_test.go index 5bf7716eceb..95aca44ed84 100644 --- a/pkg/reconciler/taskrun/resources/taskspec_test.go +++ b/pkg/reconciler/taskrun/resources/taskspec_test.go @@ -28,10 +28,14 @@ import ( "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" "github.com/tektoncd/pipeline/pkg/client/clientset/versioned/fake" "github.com/tektoncd/pipeline/pkg/reconciler/taskrun/resources" + "github.com/tektoncd/pipeline/pkg/remoteresolution/resource" "github.com/tektoncd/pipeline/pkg/trustedresources" "github.com/tektoncd/pipeline/test/diff" + "github.com/tektoncd/pipeline/test/parse" + test "github.com/tektoncd/pipeline/test/remoteresolution" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/yaml" ) func TestGetTaskSpec_Ref(t *testing.T) { @@ -297,6 +301,342 @@ func TestGetTaskData_VerificationResult(t *testing.T) { } } +func TestGetStepActionsData_Provenance(t *testing.T) { + source := v1.RefSource{ + URI: "ref-source", + Digest: map[string]string{"sha256": "abcd123456"}, + } + stepAction := parse.MustParseV1beta1StepAction(t, ` +metadata: + name: stepAction + namespace: foo +spec: + image: myImage + command: ["ls"] +`) + + stepActionBytes, err := yaml.Marshal(stepAction) + if err != nil { + t.Fatal("failed to marshal StepAction", err) + } + rr := test.NewResolvedResource(stepActionBytes, map[string]string{}, &source, nil) + requester := test.NewRequester(rr, nil, resource.ResolverPayload{}) + tests := []struct { + name string + tr *v1.TaskRun + want *v1.TaskRun + }{{ + name: "remote-step-action-with-provenance", + tr: &v1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mytaskrun", + Namespace: "default", + }, + Spec: v1.TaskRunSpec{ + TaskSpec: &v1.TaskSpec{ + Steps: []v1.Step{{ + Name: "stepname", + Ref: &v1.Ref{ + ResolverRef: v1.ResolverRef{ + Resolver: "foo", + Params: []v1.Param{{ + Name: "bar", + Value: v1.ParamValue{ + Type: v1.ParamTypeString, + StringVal: "baz", + }, + }}, + }, + }, + }}, + }, + }, + }, + want: &v1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mytaskrun", + Namespace: "default", + }, + Spec: v1.TaskRunSpec{ + TaskSpec: &v1.TaskSpec{ + Steps: []v1.Step{{ + Name: "stepname", + Ref: &v1.Ref{ + ResolverRef: v1.ResolverRef{ + Resolver: "foo", + Params: []v1.Param{{ + Name: "bar", + Value: v1.ParamValue{ + Type: v1.ParamTypeString, + StringVal: "baz", + }, + }}, + }, + }, + }}, + }, + }, + Status: v1.TaskRunStatus{ + TaskRunStatusFields: v1.TaskRunStatusFields{ + Steps: []v1.StepState{{ + Name: "stepname", + Provenance: &v1.Provenance{ + RefSource: &source, + }, + }}, + }, + }, + }, + }, { + name: "multiple-remote-step-actions-with-provenance", + tr: &v1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mytaskrun", + Namespace: "default", + }, + Spec: v1.TaskRunSpec{ + TaskSpec: &v1.TaskSpec{ + Steps: []v1.Step{{ + Name: "step1", + Ref: &v1.Ref{ + ResolverRef: v1.ResolverRef{ + Resolver: "foo", + Params: []v1.Param{{ + Name: "bar", + Value: v1.ParamValue{ + Type: v1.ParamTypeString, + StringVal: "baz", + }, + }}, + }, + }, + }, { + Name: "step2", + Ref: &v1.Ref{ + ResolverRef: v1.ResolverRef{ + Resolver: "foo", + Params: []v1.Param{{ + Name: "bar", + Value: v1.ParamValue{ + Type: v1.ParamTypeString, + StringVal: "baz", + }, + }}, + }, + }, + }}, + }, + }, + }, + want: &v1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mytaskrun", + Namespace: "default", + }, + Spec: v1.TaskRunSpec{ + TaskSpec: &v1.TaskSpec{ + Steps: []v1.Step{{ + Name: "step1", + Ref: &v1.Ref{ + ResolverRef: v1.ResolverRef{ + Resolver: "foo", + Params: []v1.Param{{ + Name: "bar", + Value: v1.ParamValue{ + Type: v1.ParamTypeString, + StringVal: "baz", + }, + }}, + }, + }, + }, { + Name: "step2", + Ref: &v1.Ref{ + ResolverRef: v1.ResolverRef{ + Resolver: "foo", + Params: []v1.Param{{ + Name: "bar", + Value: v1.ParamValue{ + Type: v1.ParamTypeString, + StringVal: "baz", + }, + }}, + }, + }, + }}, + }, + }, + Status: v1.TaskRunStatus{ + TaskRunStatusFields: v1.TaskRunStatusFields{ + Steps: []v1.StepState{{ + Name: "step1", + Provenance: &v1.Provenance{ + RefSource: &source, + }, + }, { + Name: "step2", + Provenance: &v1.Provenance{ + RefSource: &source, + }, + }}, + }, + }, + }, + }, { + name: "remote-step-action-with-existing-provenance", + tr: &v1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mytaskrun", + Namespace: "default", + }, + Spec: v1.TaskRunSpec{ + TaskSpec: &v1.TaskSpec{ + Steps: []v1.Step{{ + Name: "step1", + Ref: &v1.Ref{ + ResolverRef: v1.ResolverRef{ + Resolver: "foo", + Params: []v1.Param{{ + Name: "bar", + Value: v1.ParamValue{ + Type: v1.ParamTypeString, + StringVal: "baz", + }, + }}, + }, + }, + }}, + }, + }, + Status: v1.TaskRunStatus{ + TaskRunStatusFields: v1.TaskRunStatusFields{ + Steps: []v1.StepState{{ + Name: "step1", + Provenance: &v1.Provenance{ + RefSource: &source, + }, + }}, + }, + }, + }, + want: &v1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mytaskrun", + Namespace: "default", + }, + Spec: v1.TaskRunSpec{ + TaskSpec: &v1.TaskSpec{ + Steps: []v1.Step{{ + Name: "step1", + Ref: &v1.Ref{ + ResolverRef: v1.ResolverRef{ + Resolver: "foo", + Params: []v1.Param{{ + Name: "bar", + Value: v1.ParamValue{ + Type: v1.ParamTypeString, + StringVal: "baz", + }, + }}, + }, + }, + }}, + }, + }, + Status: v1.TaskRunStatus{ + TaskRunStatusFields: v1.TaskRunStatusFields{ + Steps: []v1.StepState{{ + Name: "step1", + Provenance: &v1.Provenance{ + RefSource: &source, + }, + }}, + }, + }, + }, + }, { + name: "remote-step-action-with-missing-provenance", + tr: &v1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mytaskrun", + Namespace: "default", + }, + Spec: v1.TaskRunSpec{ + TaskSpec: &v1.TaskSpec{ + Steps: []v1.Step{{ + Name: "step1", + Ref: &v1.Ref{ + ResolverRef: v1.ResolverRef{ + Resolver: "foo", + Params: []v1.Param{{ + Name: "bar", + Value: v1.ParamValue{ + Type: v1.ParamTypeString, + StringVal: "baz", + }, + }}, + }, + }, + }}, + }, + }, + Status: v1.TaskRunStatus{ + TaskRunStatusFields: v1.TaskRunStatusFields{ + Steps: []v1.StepState{{ + Name: "step1", + }}, + }, + }, + }, + want: &v1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mytaskrun", + Namespace: "default", + }, + Spec: v1.TaskRunSpec{ + TaskSpec: &v1.TaskSpec{ + Steps: []v1.Step{{ + Name: "step1", + Ref: &v1.Ref{ + ResolverRef: v1.ResolverRef{ + Resolver: "foo", + Params: []v1.Param{{ + Name: "bar", + Value: v1.ParamValue{ + Type: v1.ParamTypeString, + StringVal: "baz", + }, + }}, + }, + }, + }}, + }, + }, + Status: v1.TaskRunStatus{ + TaskRunStatusFields: v1.TaskRunStatusFields{ + Steps: []v1.StepState{{ + Name: "step1", + Provenance: &v1.Provenance{ + RefSource: &source, + }, + }}, + }, + }, + }, + }} + for _, tt := range tests { + ctx := context.Background() + tektonclient := fake.NewSimpleClientset(stepAction) + _, err := resources.GetStepActionsData(ctx, *tt.tr.Spec.TaskSpec, tt.tr, tektonclient, nil, requester) + if err != nil { + t.Fatalf("Did not expect an error but got : %s", err) + } + if d := cmp.Diff(tt.want, tt.tr); d != "" { + t.Errorf("the taskrun did not match what was expected diff: %s", diff.PrintWantGot(d)) + } + } +} + func TestGetStepActionsData(t *testing.T) { taskRunUser := int64(1001) stepActionUser := int64(1000)