-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Sync checksum between trusted resources and cluster resolver
Prior to this, trusted resources computed the checksum of the task/pipeline object (after some preprocessing ). However, the cluster resolver computed the checksum of the Spec instead of the pre-processed object, which made it incomplete. This PR syncs up the checksum computation of the task/pipeline in the cluster resolver to be the same as what trusted resources does i.e. step1: preprocessing, step2: compute checksum of the object. It addresses issue #6958
- Loading branch information
1 parent
51bfe94
commit 1f5c137
Showing
15 changed files
with
611 additions
and
300 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package checksum | ||
|
||
import ( | ||
"crypto/sha256" | ||
"encoding/json" | ||
"fmt" | ||
|
||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
) | ||
|
||
const ( | ||
// SignatureAnnotation is the key of signature in annotation map | ||
SignatureAnnotation = "tekton.dev/signature" | ||
) | ||
|
||
// PrepareObjectMeta will remove annotations not configured from user side -- "kubectl-client-side-apply" and "kubectl.kubernetes.io/last-applied-configuration" | ||
// (added when an object is created with `kubectl apply`) to avoid verification failure and extract the signature. | ||
// Returns a copy of the input object metadata with the annotations removed and the object's signature, | ||
// if it is present in the metadata. | ||
func PrepareObjectMeta(in metav1.Object) metav1.ObjectMeta { | ||
outMeta := metav1.ObjectMeta{} | ||
|
||
// exclude the fields populated by system. | ||
outMeta.Name = in.GetName() | ||
outMeta.GenerateName = in.GetGenerateName() | ||
outMeta.Namespace = in.GetNamespace() | ||
|
||
if in.GetLabels() != nil { | ||
outMeta.Labels = make(map[string]string) | ||
for k, v := range in.GetLabels() { | ||
outMeta.Labels[k] = v | ||
} | ||
} | ||
|
||
outMeta.Annotations = make(map[string]string) | ||
for k, v := range in.GetAnnotations() { | ||
outMeta.Annotations[k] = v | ||
} | ||
|
||
// exclude the annotations added by other components | ||
delete(outMeta.Annotations, "kubectl-client-side-apply") | ||
delete(outMeta.Annotations, "kubectl.kubernetes.io/last-applied-configuration") | ||
delete(outMeta.Annotations, SignatureAnnotation) | ||
|
||
return outMeta | ||
} | ||
|
||
// ComputeSha256Checksum computes the sha256 checksum of the tekton object. | ||
func ComputeSha256Checksum(obj interface{}) ([]byte, error) { | ||
ts, err := json.Marshal(obj) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to marshal the object: %w", err) | ||
} | ||
h := sha256.New() | ||
h.Write(ts) | ||
return h.Sum(nil), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
/* | ||
Copyright 2022 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 checksum | ||
|
||
import ( | ||
"encoding/hex" | ||
"testing" | ||
|
||
"github.com/google/go-cmp/cmp" | ||
|
||
"github.com/tektoncd/pipeline/test/diff" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
) | ||
|
||
func TestPrepareObjectMeta(t *testing.T) { | ||
unsigned := metav1.ObjectMeta{ | ||
Name: "test-task", | ||
Annotations: map[string]string{"foo": "bar"}, | ||
} | ||
namespace := "" | ||
signed := unsigned.DeepCopy() | ||
sig := "tY805zV53PtwDarK3VD6dQPx5MbIgctNcg/oSle+MG0=" | ||
signed.Annotations = map[string]string{SignatureAnnotation: sig} | ||
|
||
signedWithLabels := signed.DeepCopy() | ||
signedWithLabels.Labels = map[string]string{"label": "foo"} | ||
|
||
signedWithExtraAnnotations := signed.DeepCopy() | ||
signedWithExtraAnnotations.Annotations["kubectl-client-side-apply"] = "client" | ||
signedWithExtraAnnotations.Annotations["kubectl.kubernetes.io/last-applied-configuration"] = "config" | ||
|
||
tcs := []struct { | ||
name string | ||
objectmeta *metav1.ObjectMeta | ||
expected metav1.ObjectMeta | ||
}{{ | ||
name: "Prepare signed objectmeta without labels", | ||
objectmeta: signed, | ||
expected: metav1.ObjectMeta{ | ||
Name: "test-task", | ||
Namespace: namespace, | ||
Annotations: map[string]string{}, | ||
}, | ||
}, { | ||
name: "Prepare signed objectmeta with labels", | ||
objectmeta: signedWithLabels, | ||
expected: metav1.ObjectMeta{ | ||
Name: "test-task", | ||
Namespace: namespace, | ||
Labels: map[string]string{"label": "foo"}, | ||
Annotations: map[string]string{}, | ||
}, | ||
}, { | ||
name: "Prepare signed objectmeta with extra annotations", | ||
objectmeta: signedWithExtraAnnotations, | ||
expected: metav1.ObjectMeta{ | ||
Name: "test-task", | ||
Namespace: namespace, | ||
Annotations: map[string]string{}, | ||
}, | ||
}, { | ||
name: "resource without signature shouldn't fail", | ||
objectmeta: &unsigned, | ||
expected: metav1.ObjectMeta{ | ||
Name: "test-task", | ||
Namespace: namespace, | ||
Annotations: map[string]string{"foo": "bar"}, | ||
}, | ||
}} | ||
|
||
for _, tc := range tcs { | ||
t.Run(tc.name, func(t *testing.T) { | ||
task := PrepareObjectMeta(tc.objectmeta) | ||
if d := cmp.Diff(task, tc.expected); d != "" { | ||
t.Error(diff.PrintWantGot(d)) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestComputeSha256Checksum(t *testing.T) { | ||
sha, err := ComputeSha256Checksum("hello") | ||
if err != nil { | ||
t.Fatalf("Could not marshal hello %v", err) | ||
} | ||
if d := cmp.Diff(hex.EncodeToString(sha), "5aa762ae383fbb727af3c7a36d4940a5b8c40a989452d2304fc958ff3f354e7a"); d != "" { | ||
t.Error(diff.PrintWantGot(d)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
/* | ||
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 v1_test | ||
|
||
import ( | ||
"encoding/hex" | ||
"testing" | ||
|
||
"github.com/google/go-cmp/cmp" | ||
v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" | ||
"github.com/tektoncd/pipeline/test/diff" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
) | ||
|
||
func TestTask_Checksum(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
task *v1.Task | ||
}{{ | ||
name: "task ignore uid", | ||
task: &v1.Task{ | ||
TypeMeta: metav1.TypeMeta{ | ||
APIVersion: "tekton.dev/v1", | ||
Kind: "Task"}, | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: "task", | ||
Namespace: "task-ns", | ||
UID: "abc", | ||
Labels: map[string]string{"label": "foo"}, | ||
Annotations: map[string]string{"foo": "bar"}, | ||
}, | ||
Spec: v1.TaskSpec{ | ||
Steps: []v1.Step{{ | ||
Image: "ubuntu", | ||
Name: "echo", | ||
}}, | ||
}, | ||
}, | ||
}, { | ||
name: "task ignore system annotations", | ||
task: &v1.Task{ | ||
TypeMeta: metav1.TypeMeta{ | ||
APIVersion: "tekton.dev/v1", | ||
Kind: "Task"}, | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: "task", | ||
Namespace: "task-ns", | ||
UID: "abc", | ||
Labels: map[string]string{"label": "foo"}, | ||
Annotations: map[string]string{ | ||
"foo": "bar", | ||
"kubectl-client-side-apply": "client", | ||
"kubectl.kubernetes.io/last-applied-configuration": "config", | ||
}, | ||
}, | ||
Spec: v1.TaskSpec{ | ||
Steps: []v1.Step{{ | ||
Image: "ubuntu", | ||
Name: "echo", | ||
}}, | ||
}, | ||
}, | ||
}} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
sha, err := tt.task.Checksum() | ||
if err != nil { | ||
t.Fatalf("Error computing checksuum: %v", err) | ||
} | ||
|
||
if d := cmp.Diff(hex.EncodeToString(sha), "0cf41a775529eaaa55ff115eebe5db01a3b6bf2f4b924606888736274ceb267a"); d != "" { | ||
t.Error(diff.PrintWantGot(d)) | ||
} | ||
}) | ||
} | ||
} |
Oops, something went wrong.