Repository: tektoncd/pipeline (language: go)

Issue:
Ignore certain Tekton annotations when creating resources
# Expected Behavior

When creating a TaskRun or PipelineRun resource, any annotation that starts with `*.tekton.dev/` should be removed.

# Actual Behavior

Chains completely ignores the resource because 

# Steps to Reproduce the Problem

1. Create a TaskRun or PipelineRun with the following annotation: `chains.tekton.dev/signed: 'true'`
2. Notice that Chains completely ignores the resource.

Furthermore, other annotations, like `chains.tekton.dev/transparency`, can cause confusion to users.

This is, of course, not isolated to Chains. Tekton Results is also affected by this issue.

# Additional Info

- Kubernetes version:

  **Output of `kubectl version`:**

```
🐚 kubectl version --short
Flag --short has been deprecated, and will be removed in the future. The --short output will become the default.
Client Version: v1.24.2
Kustomize Version: v4.5.4
Server Version: v1.25.4+77bec7a

```

- Tekton Pipeline version:

  **Output of `tkn version` or `kubectl get pods -n tekton-pipelines -l app=tekton-pipelines-controller -o=jsonpath='{.items[0].metadata.labels.version}'`**

```
🐚 tkn version
Client version: 0.29.0
Chains version: v0.13.1
Pipeline version: v0.41.1
Triggers version: v0.22.2
Operator version: v0.63.0

```


<!-- Any other additional information -->



Discussion / hints:
/assign
@lcarva I'm a bit confused why this is something that should be addressed in Pipelines rather than in chains/results? I'm not familiar with how chains deals with annotations
> @lcarva I'm a bit confused why this is something that should be addressed in Pipelines rather than in chains/results? I'm not familiar with how chains deals with annotations

@lbernick , Chains doesn't have an AdmissionController so it doesn't have a chance to reject/modify such resources. By the time Chains sees the resource, it's too late. I think something in the Tekton ecosystem should probably do this, and Tekton Pipeline seems like the right place. Wdyt?
That is my reading too. Note that #6441 tries to handle this for the "known cases" (aka anything with `*tekton.dev/*`) but that could as well be the same for any other tool (outside of tekton) that uses annotations to drive some behavior. A follow-up to #6441 could be to have a way to configure those "ignores" 🙃.
I think that sounds reasonable!
I think this makes sense, but I would not categorise it as bug, it looks more like a new feature to me.
Pipelines WG - @vdemeester please move this to the next milestone if we cannot merge the fix in time

Fix patch:
diff --git a/pkg/apis/pipeline/constant.go b/pkg/apis/pipeline/constant.go
new file mode 100644
index 00000000000..5fceccbf50b
--- /dev/null
+++ b/pkg/apis/pipeline/constant.go
@@ -0,0 +1,22 @@
+/*
+Copyright 2023 The Tekton Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package pipeline
+
+const (
+	// TektonReservedAnnotationExpr is the expression we use to filter out reserved key in annotation
+	TektonReservedAnnotationExpr = "(results.tekton.dev|chains.tekton.dev)/.*"
+)
diff --git a/pkg/apis/pipeline/v1/pipelinerun_defaults.go b/pkg/apis/pipeline/v1/pipelinerun_defaults.go
index e53efe5e5a9..19f00f700b8 100644
--- a/pkg/apis/pipeline/v1/pipelinerun_defaults.go
+++ b/pkg/apis/pipeline/v1/pipelinerun_defaults.go
@@ -18,19 +18,32 @@ package v1
 
 import (
 	"context"
+	"regexp"
 	"time"
 
 	"github.com/tektoncd/pipeline/pkg/apis/config"
+	"github.com/tektoncd/pipeline/pkg/apis/pipeline"
 	"github.com/tektoncd/pipeline/pkg/apis/pipeline/pod"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"knative.dev/pkg/apis"
+	"knative.dev/pkg/kmap"
 )
 
-var _ apis.Defaultable = (*PipelineRun)(nil)
+var (
+	_                              apis.Defaultable = (*PipelineRun)(nil)
+	filterReservedAnnotationRegexp                  = regexp.MustCompile(pipeline.TektonReservedAnnotationExpr)
+)
 
 // SetDefaults implements apis.Defaultable
 func (pr *PipelineRun) SetDefaults(ctx context.Context) {
 	pr.Spec.SetDefaults(ctx)
+
+	// Silently filtering out Tekton Reserved annotations at creation
+	if apis.IsInCreate(ctx) {
+		pr.ObjectMeta.Annotations = kmap.Filter(pr.ObjectMeta.Annotations, func(s string) bool {
+			return filterReservedAnnotationRegexp.MatchString(s)
+		})
+	}
 }
 
 // SetDefaults implements apis.Defaultable
diff --git a/pkg/apis/pipeline/v1/taskrun_defaults.go b/pkg/apis/pipeline/v1/taskrun_defaults.go
index 9f34e6b5c73..79fa50f3cdc 100644
--- a/pkg/apis/pipeline/v1/taskrun_defaults.go
+++ b/pkg/apis/pipeline/v1/taskrun_defaults.go
@@ -24,6 +24,7 @@ import (
 	pod "github.com/tektoncd/pipeline/pkg/apis/pipeline/pod"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"knative.dev/pkg/apis"
+	"knative.dev/pkg/kmap"
 )
 
 var _ apis.Defaultable = (*TaskRun)(nil)
@@ -36,6 +37,13 @@ func (tr *TaskRun) SetDefaults(ctx context.Context) {
 	ctx = apis.WithinParent(ctx, tr.ObjectMeta)
 	tr.Spec.SetDefaults(ctx)
 
+	// Silently filtering out Tekton Reserved annotations at creation
+	if apis.IsInCreate(ctx) {
+		tr.ObjectMeta.Annotations = kmap.Filter(tr.ObjectMeta.Annotations, func(s string) bool {
+			return filterReservedAnnotationRegexp.MatchString(s)
+		})
+	}
+
 	// If the TaskRun doesn't have a managed-by label, apply the default
 	// specified in the config.
 	cfg := config.FromContextOrDefaults(ctx)
diff --git a/pkg/apis/pipeline/v1beta1/pipelinerun_defaults.go b/pkg/apis/pipeline/v1beta1/pipelinerun_defaults.go
index 86592824a20..0b3efc8f122 100644
--- a/pkg/apis/pipeline/v1beta1/pipelinerun_defaults.go
+++ b/pkg/apis/pipeline/v1beta1/pipelinerun_defaults.go
@@ -18,19 +18,32 @@ package v1beta1
 
 import (
 	"context"
+	"regexp"
 	"time"
 
 	"github.com/tektoncd/pipeline/pkg/apis/config"
+	"github.com/tektoncd/pipeline/pkg/apis/pipeline"
 	pod "github.com/tektoncd/pipeline/pkg/apis/pipeline/pod"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"knative.dev/pkg/apis"
+	"knative.dev/pkg/kmap"
 )
 
-var _ apis.Defaultable = (*PipelineRun)(nil)
+var (
+	_                              apis.Defaultable = (*PipelineRun)(nil)
+	filterReservedAnnotationRegexp                  = regexp.MustCompile(pipeline.TektonReservedAnnotationExpr)
+)
 
 // SetDefaults implements apis.Defaultable
 func (pr *PipelineRun) SetDefaults(ctx context.Context) {
 	pr.Spec.SetDefaults(ctx)
+
+	// Silently filtering out Tekton Reserved annotations at creation
+	if apis.IsInCreate(ctx) {
+		pr.ObjectMeta.Annotations = kmap.Filter(pr.ObjectMeta.Annotations, func(s string) bool {
+			return filterReservedAnnotationRegexp.MatchString(s)
+		})
+	}
 }
 
 // SetDefaults implements apis.Defaultable
diff --git a/pkg/apis/pipeline/v1beta1/taskrun_defaults.go b/pkg/apis/pipeline/v1beta1/taskrun_defaults.go
index 61f3285decd..2e4896d47b9 100644
--- a/pkg/apis/pipeline/v1beta1/taskrun_defaults.go
+++ b/pkg/apis/pipeline/v1beta1/taskrun_defaults.go
@@ -24,6 +24,7 @@ import (
 	pod "github.com/tektoncd/pipeline/pkg/apis/pipeline/pod"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"knative.dev/pkg/apis"
+	"knative.dev/pkg/kmap"
 )
 
 var _ apis.Defaultable = (*TaskRun)(nil)
@@ -36,6 +37,13 @@ func (tr *TaskRun) SetDefaults(ctx context.Context) {
 	ctx = apis.WithinParent(ctx, tr.ObjectMeta)
 	tr.Spec.SetDefaults(ctx)
 
+	// Silently filtering out Tekton Reserved annotations at creation
+	if apis.IsInCreate(ctx) {
+		tr.ObjectMeta.Annotations = kmap.Filter(tr.ObjectMeta.Annotations, func(s string) bool {
+			return filterReservedAnnotationRegexp.MatchString(s)
+		})
+	}
+
 	// If the TaskRun doesn't have a managed-by label, apply the default
 	// specified in the config.
 	cfg := config.FromContextOrDefaults(ctx)
diff --git a/pkg/reconciler/pipelinerun/pipelinerun.go b/pkg/reconciler/pipelinerun/pipelinerun.go
index abfc4e71336..9169f9ff534 100644
--- a/pkg/reconciler/pipelinerun/pipelinerun.go
+++ b/pkg/reconciler/pipelinerun/pipelinerun.go
@@ -23,6 +23,7 @@ import (
 	"fmt"
 	"path/filepath"
 	"reflect"
+	"regexp"
 	"strings"
 
 	"github.com/hashicorp/go-multierror"
@@ -163,7 +164,8 @@ type Reconciler struct {
 
 var (
 	// Check that our Reconciler implements pipelinerunreconciler.Interface
-	_ pipelinerunreconciler.Interface = (*Reconciler)(nil)
+	_                              pipelinerunreconciler.Interface = (*Reconciler)(nil)
+	filterReservedAnnotationRegexp                                 = regexp.MustCompile(pipeline.TektonReservedAnnotationExpr)
 )
 
 // ReconcileKind compares the actual state with the desired, and attempts to
@@ -850,7 +852,8 @@ func (c *Reconciler) createTaskRun(ctx context.Context, taskRunName string, para
 			StepSpecs:          taskRunSpec.StepSpecs,
 			SidecarSpecs:       taskRunSpec.SidecarSpecs,
 			ComputeResources:   taskRunSpec.ComputeResources,
-		}}
+		},
+	}
 
 	// Add current spanContext as annotations to TaskRun
 	// so that tracing can be continued under the same traceId
@@ -1123,7 +1126,9 @@ func getTaskrunAnnotations(pr *v1.PipelineRun) map[string]string {
 	for key, val := range pr.ObjectMeta.Annotations {
 		annotations[key] = val
 	}
-	return annotations
+	return kmap.Filter(annotations, func(s string) bool {
+		return filterReservedAnnotationRegexp.MatchString(s)
+	})
 }
 
 func propagatePipelineNameLabelToPipelineRun(pr *v1.PipelineRun) error {
diff --git a/pkg/reconciler/taskrun/taskrun.go b/pkg/reconciler/taskrun/taskrun.go
index 3a0301836da..8f35bccdf86 100644
--- a/pkg/reconciler/taskrun/taskrun.go
+++ b/pkg/reconciler/taskrun/taskrun.go
@@ -888,7 +888,7 @@ func storeTaskSpecAndMergeMeta(ctx context.Context, tr *v1.TaskRun, ts *v1.TaskS
 		}
 
 		// Propagate annotations from Task to TaskRun. TaskRun annotations take precedences over Task.
-		tr.ObjectMeta.Annotations = kmap.Union(kmap.ExcludeKeys(meta.Annotations, "kubectl.kubernetes.io/last-applied-configuration"), tr.ObjectMeta.Annotations)
+		tr.ObjectMeta.Annotations = kmap.Union(kmap.ExcludeKeys(meta.Annotations, tknreconciler.KubectlLastAppliedAnnotationKey), tr.ObjectMeta.Annotations)
 		// Propagate labels from Task to TaskRun. TaskRun labels take precedences over Task.
 		tr.ObjectMeta.Labels = kmap.Union(meta.Labels, tr.ObjectMeta.Labels)
 		if tr.Spec.TaskRef != nil {


Test patch:
diff --git a/pkg/apis/pipeline/v1/pipelinerun_defaults_test.go b/pkg/apis/pipeline/v1/pipelinerun_defaults_test.go
index d0afe1d11a7..4972faf3de1 100644
--- a/pkg/apis/pipeline/v1/pipelinerun_defaults_test.go
+++ b/pkg/apis/pipeline/v1/pipelinerun_defaults_test.go
@@ -31,6 +31,7 @@ import (
 	"github.com/tektoncd/pipeline/test/diff"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"knative.dev/pkg/apis"
 )
 
 func TestPipelineRunSpec_SetDefaults(t *testing.T) {
@@ -314,15 +315,16 @@ func TestPipelineRunDefaulting(t *testing.T) {
 		in: &v1.PipelineRun{
 			Spec: v1.PipelineRunSpec{
 				PipelineRef: &v1.PipelineRef{Name: "foo"},
-				TaskRunTemplate: v1.PipelineTaskRunTemplate{PodTemplate: &pod.Template{
-					NodeSelector: map[string]string{
-						"label2": "value2",
-					},
-					SecurityContext: &corev1.PodSecurityContext{
-						RunAsNonRoot: &ttrue,
+				TaskRunTemplate: v1.PipelineTaskRunTemplate{
+					PodTemplate: &pod.Template{
+						NodeSelector: map[string]string{
+							"label2": "value2",
+						},
+						SecurityContext: &corev1.PodSecurityContext{
+							RunAsNonRoot: &ttrue,
+						},
+						HostNetwork: false,
 					},
-					HostNetwork: false,
-				},
 				},
 			},
 		},
@@ -401,6 +403,34 @@ func TestPipelineRunDefaulting(t *testing.T) {
 		defaults: map[string]string{
 			"default-resolver-type": "git",
 		},
+	}, {
+		name: "Reserved Tekton annotations are not filtered on update",
+		in: &v1.PipelineRun{
+			ObjectMeta: metav1.ObjectMeta{
+				Annotations: map[string]string{"chains.tekton.dev/signed": "true", "foo": "bar"},
+			},
+			Spec: v1.PipelineRunSpec{
+				PipelineRef: &v1.PipelineRef{
+					Name: "foo",
+				},
+			},
+		},
+		want: &v1.PipelineRun{
+			ObjectMeta: metav1.ObjectMeta{
+				Annotations: map[string]string{"chains.tekton.dev/signed": "true", "foo": "bar"},
+			},
+			Spec: v1.PipelineRunSpec{
+				TaskRunTemplate: v1.PipelineTaskRunTemplate{
+					ServiceAccountName: config.DefaultServiceAccountValue,
+				},
+				Timeouts: &v1.TimeoutFields{
+					Pipeline: &metav1.Duration{Duration: config.DefaultTimeoutMinutes * time.Minute},
+				},
+				PipelineRef: &v1.PipelineRef{
+					Name: "foo",
+				},
+			},
+		},
 	}}
 	for _, tc := range tests {
 		t.Run(tc.name, func(t *testing.T) {
@@ -414,3 +444,51 @@ func TestPipelineRunDefaulting(t *testing.T) {
 		})
 	}
 }
+
+func TestPipelineRunDefaultingOnCreate(t *testing.T) {
+	tests := []struct {
+		name     string
+		in       *v1.PipelineRun
+		want     *v1.PipelineRun
+		defaults map[string]string
+	}{{
+		name: "Reserved Tekton annotations are filtered on create",
+		in: &v1.PipelineRun{
+			ObjectMeta: metav1.ObjectMeta{
+				Annotations: map[string]string{"chains.tekton.dev/signed": "true", "results.tekton.dev/hello": "world", "tekton.dev/foo": "bar", "foo": "bar"},
+			},
+			Spec: v1.PipelineRunSpec{
+				PipelineRef: &v1.PipelineRef{
+					Name: "foo",
+				},
+			},
+		},
+		want: &v1.PipelineRun{
+			ObjectMeta: metav1.ObjectMeta{
+				Annotations: map[string]string{"tekton.dev/foo": "bar", "foo": "bar"},
+			},
+			Spec: v1.PipelineRunSpec{
+				TaskRunTemplate: v1.PipelineTaskRunTemplate{
+					ServiceAccountName: config.DefaultServiceAccountValue,
+				},
+				Timeouts: &v1.TimeoutFields{
+					Pipeline: &metav1.Duration{Duration: config.DefaultTimeoutMinutes * time.Minute},
+				},
+				PipelineRef: &v1.PipelineRef{
+					Name: "foo",
+				},
+			},
+		},
+	}}
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			ctx := apis.WithinCreate(cfgtesting.SetDefaults(context.Background(), t, tc.defaults))
+			got := tc.in
+			got.SetDefaults(ctx)
+			if !cmp.Equal(got, tc.want, ignoreUnexportedResources) {
+				d := cmp.Diff(got, tc.want, ignoreUnexportedResources)
+				t.Errorf("SetDefaults %s", diff.PrintWantGot(d))
+			}
+		})
+	}
+}
diff --git a/pkg/apis/pipeline/v1/taskrun_defaults_test.go b/pkg/apis/pipeline/v1/taskrun_defaults_test.go
index cb90af09d53..dbb8ebe84bb 100644
--- a/pkg/apis/pipeline/v1/taskrun_defaults_test.go
+++ b/pkg/apis/pipeline/v1/taskrun_defaults_test.go
@@ -29,6 +29,7 @@ import (
 	"github.com/tektoncd/pipeline/test/diff"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"knative.dev/pkg/apis"
 )
 
 var (
@@ -389,6 +390,32 @@ func TestTaskRunDefaulting(t *testing.T) {
 		defaults: map[string]string{
 			"default-resolver-type": "git",
 		},
+	}, {
+		name: "Reserved Tekton annotations are not filtered on updates",
+		in: &v1.TaskRun{
+			ObjectMeta: metav1.ObjectMeta{
+				Annotations: map[string]string{"chains.tekton.dev/signed": "true", "foo": "bar"},
+			},
+			Spec: v1.TaskRunSpec{
+				TaskRef: &v1.TaskRef{
+					Name: "foo",
+				},
+			},
+		},
+		want: &v1.TaskRun{
+			ObjectMeta: metav1.ObjectMeta{
+				Labels:      map[string]string{"app.kubernetes.io/managed-by": "tekton-pipelines"},
+				Annotations: map[string]string{"chains.tekton.dev/signed": "true", "foo": "bar"},
+			},
+			Spec: v1.TaskRunSpec{
+				TaskRef: &v1.TaskRef{
+					Kind: "Task",
+					Name: "foo",
+				},
+				Timeout:            &metav1.Duration{Duration: time.Hour},
+				ServiceAccountName: "default",
+			},
+		},
 	}}
 	for _, tc := range tests {
 		t.Run(tc.name, func(t *testing.T) {
@@ -402,3 +429,49 @@ func TestTaskRunDefaulting(t *testing.T) {
 		})
 	}
 }
+
+func TestTaskRunDefaultingOnCreate(t *testing.T) {
+	tests := []struct {
+		name     string
+		in       *v1.TaskRun
+		want     *v1.TaskRun
+		defaults map[string]string
+	}{{
+		name: "Reserved Tekton annotations are filtered on create",
+		in: &v1.TaskRun{
+			ObjectMeta: metav1.ObjectMeta{
+				Annotations: map[string]string{"chains.tekton.dev/signed": "true", "results.tekton.dev/hello": "world", "tekton.dev/foo": "bar", "foo": "bar"},
+			},
+			Spec: v1.TaskRunSpec{
+				TaskRef: &v1.TaskRef{
+					Name: "foo",
+				},
+			},
+		},
+		want: &v1.TaskRun{
+			ObjectMeta: metav1.ObjectMeta{
+				Labels:      map[string]string{"app.kubernetes.io/managed-by": "tekton-pipelines"},
+				Annotations: map[string]string{"tekton.dev/foo": "bar", "foo": "bar"},
+			},
+			Spec: v1.TaskRunSpec{
+				TaskRef: &v1.TaskRef{
+					Kind: "Task",
+					Name: "foo",
+				},
+				Timeout:            &metav1.Duration{Duration: time.Hour},
+				ServiceAccountName: "default",
+			},
+		},
+	}}
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			ctx := apis.WithinCreate(cfgtesting.SetDefaults(context.Background(), t, tc.defaults))
+			got := tc.in
+			got.SetDefaults(ctx)
+			if !cmp.Equal(got, tc.want, ignoreUnexportedResources) {
+				d := cmp.Diff(got, tc.want, ignoreUnexportedResources)
+				t.Errorf("SetDefaults %s", diff.PrintWantGot(d))
+			}
+		})
+	}
+}
diff --git a/pkg/apis/pipeline/v1beta1/pipelinerun_defaults_test.go b/pkg/apis/pipeline/v1beta1/pipelinerun_defaults_test.go
index 651df5bc430..d0c9eb576a5 100644
--- a/pkg/apis/pipeline/v1beta1/pipelinerun_defaults_test.go
+++ b/pkg/apis/pipeline/v1beta1/pipelinerun_defaults_test.go
@@ -30,6 +30,7 @@ import (
 	"github.com/tektoncd/pipeline/test/diff"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"knative.dev/pkg/apis"
 )
 
 func TestPipelineRunSpec_SetDefaults(t *testing.T) {
@@ -55,7 +56,8 @@ func TestPipelineRunSpec_SetDefaults(t *testing.T) {
 				ServiceAccountName: config.DefaultServiceAccountValue,
 				Timeout:            &metav1.Duration{Duration: 500 * time.Millisecond},
 			},
-		}, {
+		},
+		{
 			desc: "timeouts is nil",
 			prs:  &v1beta1.PipelineRunSpec{},
 			want: &v1beta1.PipelineRunSpec{
@@ -88,7 +90,8 @@ func TestPipelineRunSpec_SetDefaults(t *testing.T) {
 					Pipeline: &metav1.Duration{Duration: (config.DefaultTimeoutMinutes + 1) * time.Minute},
 				},
 			},
-		}, {
+		},
+		{
 			desc: "timeouts.pipeline is nil with timeouts.tasks and timeouts.finally",
 			prs: &v1beta1.PipelineRunSpec{
 				Timeouts: &v1beta1.TimeoutFields{
@@ -359,6 +362,30 @@ func TestPipelineRunDefaulting(t *testing.T) {
 		defaults: map[string]string{
 			"default-resolver-type": "git",
 		},
+	}, {
+		name: "Reserved Tekton annotations are not filtered on update",
+		in: &v1beta1.PipelineRun{
+			ObjectMeta: metav1.ObjectMeta{
+				Annotations: map[string]string{"chains.tekton.dev/signed": "true", "foo": "bar"},
+			},
+			Spec: v1beta1.PipelineRunSpec{
+				PipelineRef: &v1beta1.PipelineRef{
+					Name: "foo",
+				},
+			},
+		},
+		want: &v1beta1.PipelineRun{
+			ObjectMeta: metav1.ObjectMeta{
+				Annotations: map[string]string{"chains.tekton.dev/signed": "true", "foo": "bar"},
+			},
+			Spec: v1beta1.PipelineRunSpec{
+				ServiceAccountName: config.DefaultServiceAccountValue,
+				Timeout:            &metav1.Duration{Duration: config.DefaultTimeoutMinutes * time.Minute},
+				PipelineRef: &v1beta1.PipelineRef{
+					Name: "foo",
+				},
+			},
+		},
 	}}
 	for _, tc := range tests {
 		t.Run(tc.name, func(t *testing.T) {
@@ -372,3 +399,47 @@ func TestPipelineRunDefaulting(t *testing.T) {
 		})
 	}
 }
+
+func TestPipelineRunDefaultingOnCreate(t *testing.T) {
+	tests := []struct {
+		name     string
+		in       *v1beta1.PipelineRun
+		want     *v1beta1.PipelineRun
+		defaults map[string]string
+	}{{
+		name: "Reserved Tekton annotations are filtered on create",
+		in: &v1beta1.PipelineRun{
+			ObjectMeta: metav1.ObjectMeta{
+				Annotations: map[string]string{"chains.tekton.dev/signed": "true", "results.tekton.dev/hello": "world", "tekton.dev/foo": "bar", "foo": "bar"},
+			},
+			Spec: v1beta1.PipelineRunSpec{
+				PipelineRef: &v1beta1.PipelineRef{
+					Name: "foo",
+				},
+			},
+		},
+		want: &v1beta1.PipelineRun{
+			ObjectMeta: metav1.ObjectMeta{
+				Annotations: map[string]string{"tekton.dev/foo": "bar", "foo": "bar"},
+			},
+			Spec: v1beta1.PipelineRunSpec{
+				ServiceAccountName: config.DefaultServiceAccountValue,
+				Timeout:            &metav1.Duration{Duration: config.DefaultTimeoutMinutes * time.Minute},
+				PipelineRef: &v1beta1.PipelineRef{
+					Name: "foo",
+				},
+			},
+		},
+	}}
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			ctx := apis.WithinCreate(cfgtesting.SetDefaults(context.Background(), t, tc.defaults))
+			got := tc.in
+			got.SetDefaults(ctx)
+			if !cmp.Equal(got, tc.want, ignoreUnexportedResources) {
+				d := cmp.Diff(got, tc.want, ignoreUnexportedResources)
+				t.Errorf("SetDefaults %s", diff.PrintWantGot(d))
+			}
+		})
+	}
+}
diff --git a/pkg/apis/pipeline/v1beta1/taskrun_defaults_test.go b/pkg/apis/pipeline/v1beta1/taskrun_defaults_test.go
index 3a127cb6d07..58e421741cf 100644
--- a/pkg/apis/pipeline/v1beta1/taskrun_defaults_test.go
+++ b/pkg/apis/pipeline/v1beta1/taskrun_defaults_test.go
@@ -29,6 +29,7 @@ import (
 	"github.com/tektoncd/pipeline/test/diff"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"knative.dev/pkg/apis"
 )
 
 var (
@@ -412,3 +413,49 @@ func TestTaskRunDefaulting(t *testing.T) {
 		})
 	}
 }
+
+func TestTaskRunDefaultingOnCreate(t *testing.T) {
+	tests := []struct {
+		name     string
+		in       *v1beta1.TaskRun
+		want     *v1beta1.TaskRun
+		defaults map[string]string
+	}{{
+		name: "Reserved Tekton annotations are filtered on create",
+		in: &v1beta1.TaskRun{
+			ObjectMeta: metav1.ObjectMeta{
+				Annotations: map[string]string{"chains.tekton.dev/signed": "true", "results.tekton.dev/hello": "world", "tekton.dev/foo": "bar", "foo": "bar"},
+			},
+			Spec: v1beta1.TaskRunSpec{
+				TaskRef: &v1beta1.TaskRef{
+					Name: "foo",
+				},
+			},
+		},
+		want: &v1beta1.TaskRun{
+			ObjectMeta: metav1.ObjectMeta{
+				Labels:      map[string]string{"app.kubernetes.io/managed-by": "tekton-pipelines"},
+				Annotations: map[string]string{"tekton.dev/foo": "bar", "foo": "bar"},
+			},
+			Spec: v1beta1.TaskRunSpec{
+				TaskRef: &v1beta1.TaskRef{
+					Kind: "Task",
+					Name: "foo",
+				},
+				Timeout:            &metav1.Duration{Duration: time.Hour},
+				ServiceAccountName: "default",
+			},
+		},
+	}}
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			ctx := apis.WithinCreate(cfgtesting.SetDefaults(context.Background(), t, tc.defaults))
+			got := tc.in
+			got.SetDefaults(ctx)
+			if !cmp.Equal(got, tc.want, ignoreUnexportedResources) {
+				d := cmp.Diff(got, tc.want, ignoreUnexportedResources)
+				t.Errorf("SetDefaults %s", diff.PrintWantGot(d))
+			}
+		})
+	}
+}
diff --git a/pkg/reconciler/pipelinerun/pipelinerun_test.go b/pkg/reconciler/pipelinerun/pipelinerun_test.go
index e212055cf79..c806350a43a 100644
--- a/pkg/reconciler/pipelinerun/pipelinerun_test.go
+++ b/pkg/reconciler/pipelinerun/pipelinerun_test.go
@@ -11728,6 +11728,53 @@ spec:
 	}
 }
 
+func TestReconcile_FilterLabels(t *testing.T) {
+	prs := []*v1.PipelineRun{parse.MustParseV1PipelineRun(t, `metadata:
+  name: test-annotations
+  namespace: foo
+  annotations:
+    chains.tekton.dev/signed: "true"
+    results.tekton.dev/foo: "bar"
+    tekton.dev/foo: "bar"
+    foo: bar
+spec:
+  pipelineSpec:
+    tasks:
+      - name: hello
+        taskSpec:
+          steps:
+          - image: busybox
+            script: |
+              echo "hello"
+`)}
+
+	ts := []*v1.Task{}
+	cms := []*corev1.ConfigMap{newFeatureFlagsConfigMap()}
+
+	d := test.Data{
+		PipelineRuns: prs,
+		Tasks:        ts,
+		ConfigMaps:   cms,
+	}
+	prt := newPipelineRunTest(t, d)
+	defer prt.Cancel()
+
+	_, clients := prt.reconcileRun("foo", "test-annotations", []string{}, false)
+
+	taskRunList, err := clients.Pipeline.TektonV1().TaskRuns("foo").List(prt.TestAssets.Ctx, metav1.ListOptions{})
+	if err != nil {
+		t.Fatalf("Failure to list TaskRun's %s", err)
+	}
+	if len(taskRunList.Items) != 1 {
+		t.Fatalf("Should have only one TaskRun, got %d", len(taskRunList.Items))
+	}
+	tr := taskRunList.Items[0]
+	vFoo, okFoo := tr.ObjectMeta.Annotations["foo"]
+	vTektonFoo, okTektonFoo := tr.ObjectMeta.Annotations["tekton.dev/foo"]
+	if len(tr.ObjectMeta.Annotations) != 2 || !okFoo || !okTektonFoo || vFoo != "bar" || vTektonFoo != "bar" {
+		t.Fatalf("Should have filtered chains.tekton.dev/* and results.tekton.dev/* annotations and only have one annotations, got %v", tr.ObjectMeta.Annotations)
+	}
+}
 func TestReconcile_CancelUnscheduled(t *testing.T) {
 	pipelineRunName := "cancel-test-run"
 	prs := []*v1.PipelineRun{parse.MustParseV1PipelineRun(t, `metadata: