Skip to content

Commit

Permalink
support v1 for sign command
Browse files Browse the repository at this point in the history
  • Loading branch information
Yongxuanzhang committed Jan 17, 2024
1 parent 95548d3 commit c50b3a2
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 63 deletions.
13 changes: 11 additions & 2 deletions pkg/cmd/pipeline/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ import (
"github.com/spf13/cobra"
"github.com/tektoncd/cli/pkg/cli"
"github.com/tektoncd/cli/pkg/trustedresources"
v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
cliopts "k8s.io/cli-runtime/pkg/genericclioptions"
"sigs.k8s.io/yaml"
)
Expand All @@ -31,6 +33,7 @@ type signOptions struct {
keyfile string
kmsKey string
targetFile string
apiVersion string
}

func signCommand() *cobra.Command {
Expand Down Expand Up @@ -70,7 +73,13 @@ or using kms
return err
}

crd := &v1beta1.Pipeline{}
var crd metav1.Object
if opts.apiVersion == "v1beta1" {
crd = &v1beta1.Pipeline{}
} else {
crd = &v1.Pipeline{}
}

if err := yaml.Unmarshal(b, &crd); err != nil {
return fmt.Errorf("error unmarshalling Pipeline: %v", err)
}
Expand All @@ -87,7 +96,7 @@ or using kms
c.Flags().StringVarP(&opts.keyfile, "key-file", "K", "", "Key file")
c.Flags().StringVarP(&opts.kmsKey, "kms-key", "m", "", "KMS key url")
c.Flags().StringVarP(&opts.targetFile, "file-name", "f", "", "Fle name of the signed pipeline, using the original file name will overwrite the file")

c.Flags().StringVarP(&opts.apiVersion, "version", "v", "v1", "apiVersion of the Pipeline to be signed")
return c
}

Expand Down
70 changes: 43 additions & 27 deletions pkg/cmd/pipeline/sign_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package pipeline

import (
"context"
"fmt"
"os"
"path/filepath"
"testing"
Expand All @@ -28,37 +29,52 @@ import (
func TestSign(t *testing.T) {
ctx := context.Background()
p := &test.Params{}

task := Command(p)

pipeline := Command(p)
os.Setenv("PRIVATE_PASSWORD", "1234")
tmpDir := t.TempDir()
targetFile := filepath.Join(tmpDir, "signed.yaml")
out, err := test.ExecuteCommand(task, "sign", "testdata/pipeline.yaml", "-K", "testdata/cosign.key", "-f", targetFile)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
expected := "*Warning*: This is an experimental command, it's usage and behavior can change in the next release(s)\nPipeline testdata/pipeline.yaml is signed successfully \n"
test.AssertOutput(t, expected, out)

// verify the signed task
verifier, err := cosignsignature.LoadPublicKey(ctx, "testdata/cosign.pub")
if err != nil {
t.Errorf("error getting verifier from key file: %v", err)
}
testcases := []struct {
name string
taskFile string
apiVersion string
}{{
name: "sign and verify v1beta1 Pipeline",
taskFile: "testdata/pipeline.yaml",
apiVersion: "v1beta1",
}, {
name: "sign and verify v1 Pipeline",
taskFile: "testdata/pipeline-v1.yaml",
apiVersion: "v1",
}}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
tmpDir := t.TempDir()
targetFile := filepath.Join(tmpDir, "signed.yaml")
out, err := test.ExecuteCommand(pipeline, "sign", tc.taskFile, "-K", "testdata/cosign.key", "-f", targetFile, "-v", tc.apiVersion)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
expected := fmt.Sprintf("*Warning*: This is an experimental command, it's usage and behavior can change in the next release(s)\nPipeline %s is signed successfully \n", tc.taskFile)
test.AssertOutput(t, expected, out)

signed, err := os.ReadFile(targetFile)
if err != nil {
t.Fatalf("error reading file: %v", err)
}
// verify the signed task
verifier, err := cosignsignature.LoadPublicKey(ctx, "testdata/cosign.pub")
if err != nil {
t.Errorf("error getting verifier from key file: %v", err)
}

target, signature, err := trustedresources.UnmarshalCRD(signed, "Pipeline")
if err != nil {
t.Fatalf("error unmarshalling crd: %v", err)
}
signed, err := os.ReadFile(targetFile)
if err != nil {
t.Fatalf("error reading file: %v", err)
}

if err := trustedresources.VerifyInterface(target, verifier, signature); err != nil {
t.Fatalf("VerifyInterface get error: %v", err)
}
target, signature, err := trustedresources.UnmarshalCRD(signed, "Pipeline", tc.apiVersion)
if err != nil {
t.Fatalf("error unmarshalling crd: %v", err)
}

if err := trustedresources.VerifyInterface(target, verifier, signature); err != nil {
t.Fatalf("VerifyInterface get error: %v", err)
}
})
}
}
12 changes: 10 additions & 2 deletions pkg/cmd/task/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ import (
"github.com/spf13/cobra"
"github.com/tektoncd/cli/pkg/cli"
"github.com/tektoncd/cli/pkg/trustedresources"
v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
cliopts "k8s.io/cli-runtime/pkg/genericclioptions"
"sigs.k8s.io/yaml"
)
Expand All @@ -36,6 +38,7 @@ type signOptions struct {
keyfile string
kmsKey string
targetFile string
apiVersion string
}

func signCommand() *cobra.Command {
Expand Down Expand Up @@ -74,8 +77,13 @@ or using kms
log.Fatalf("error reading file: %v", err)
return err
}
var crd metav1.Object
if opts.apiVersion == "v1beta1" {
crd = &v1beta1.Task{}
} else {
crd = &v1.Task{}
}

crd := &v1beta1.Task{}
if err := yaml.Unmarshal(b, &crd); err != nil {
return fmt.Errorf("error unmarshalling Task: %v", err)
}
Expand All @@ -91,6 +99,6 @@ or using kms
c.Flags().StringVarP(&opts.keyfile, "key-file", "K", "", "Key file")
c.Flags().StringVarP(&opts.kmsKey, "kms-key", "m", "", "KMS key url")
c.Flags().StringVarP(&opts.targetFile, "file-name", "f", "", "file name of the signed task, using the original file name will overwrite the file")

c.Flags().StringVarP(&opts.apiVersion, "version", "v", "v1", "apiVersion of the Task to be signed")
return c
}
67 changes: 43 additions & 24 deletions pkg/cmd/task/sign_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package task

import (
"context"
"fmt"
"os"
"path/filepath"
"testing"
Expand All @@ -32,32 +33,50 @@ func TestSign(t *testing.T) {
task := Command(p)

os.Setenv("PRIVATE_PASSWORD", "1234")
tmpDir := t.TempDir()
targetFile := filepath.Join(tmpDir, "signed.yaml")
out, err := test.ExecuteCommand(task, "sign", "testdata/task.yaml", "-K", "testdata/cosign.key", "-f", targetFile)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
expected := "*Warning*: This is an experimental command, it's usage and behavior can change in the next release(s)\nTask testdata/task.yaml is signed successfully \n"
test.AssertOutput(t, expected, out)

// verify the signed task
verifier, err := cosignsignature.LoadPublicKey(ctx, "testdata/cosign.pub")
if err != nil {
t.Errorf("error getting verifier from key file: %v", err)
}
testcases := []struct {
name string
taskFile string
apiVersion string
}{{
name: "sign and verify v1beta1 Task",
taskFile: "testdata/task.yaml",
apiVersion: "v1beta1",
}, {
name: "sign and verify v1 Task",
taskFile: "testdata/task-v1.yaml",
apiVersion: "v1",
}}

signed, err := os.ReadFile(targetFile)
if err != nil {
t.Fatalf("error reading file: %v", err)
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
tmpDir := t.TempDir()
targetFile := filepath.Join(tmpDir, "signed.yaml")
out, err := test.ExecuteCommand(task, "sign", tc.taskFile, "-K", "testdata/cosign.key", "-f", targetFile, "-v", tc.apiVersion)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
expected := fmt.Sprintf("*Warning*: This is an experimental command, it's usage and behavior can change in the next release(s)\nTask %s is signed successfully \n", tc.taskFile)
test.AssertOutput(t, expected, out)

target, signature, err := trustedresources.UnmarshalCRD(signed, "Task")
if err != nil {
t.Fatalf("error unmarshalling crd: %v", err)
}
if err := trustedresources.VerifyInterface(target, verifier, signature); err != nil {
t.Fatalf("VerifyTaskOCIBundle get error: %v", err)
}
// verify the signed task
verifier, err := cosignsignature.LoadPublicKey(ctx, "testdata/cosign.pub")
if err != nil {
t.Errorf("error getting verifier from key file: %v", err)
}

signed, err := os.ReadFile(targetFile)
if err != nil {
t.Fatalf("error reading file: %v", err)
}

target, signature, err := trustedresources.UnmarshalCRD(signed, "Task", tc.apiVersion)
if err != nil {
t.Fatalf("error unmarshalling crd: %v", err)
}
if err := trustedresources.VerifyInterface(target, verifier, signature); err != nil {
t.Fatalf("VerifyInterface get error: %v", err)
}
})
}
}
29 changes: 22 additions & 7 deletions pkg/trustedresources/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (

"github.com/sigstore/sigstore/pkg/signature"
"github.com/sigstore/sigstore/pkg/signature/kms"
v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
"golang.org/x/term"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -114,20 +115,34 @@ func signInterface(signer signature.Signer, i interface{}) ([]byte, error) {
}

// UnmarshalCRD will get the task/pipeline from buffer and extract the signature.
func UnmarshalCRD(buf []byte, kind string) (metav1.Object, []byte, error) {
func UnmarshalCRD(buf []byte, kind string, version string) (metav1.Object, []byte, error) {
var resource metav1.Object
var signature []byte

switch kind {
case "Task":
resource = &v1beta1.Task{}
if err := yaml.Unmarshal(buf, &resource); err != nil {
return nil, nil, err
if version == "v1beta1" {
resource = &v1beta1.Task{}
if err := yaml.Unmarshal(buf, &resource); err != nil {
return nil, nil, err
}
} else {
resource = &v1.Task{}
if err := yaml.Unmarshal(buf, &resource); err != nil {
return nil, nil, err
}
}
case "Pipeline":
resource = &v1beta1.Pipeline{}
if err := yaml.Unmarshal(buf, &resource); err != nil {
return nil, nil, err
if version == "v1beta1" {
resource = &v1beta1.Pipeline{}
if err := yaml.Unmarshal(buf, &resource); err != nil {
return nil, nil, err
}
} else {
resource = &v1.Pipeline{}
if err := yaml.Unmarshal(buf, &resource); err != nil {
return nil, nil, err
}
}
}
annotations := resource.GetAnnotations()
Expand Down
5 changes: 4 additions & 1 deletion pkg/trustedresources/sign_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,19 @@ func TestSign(t *testing.T) {
resource metav1.Object
kind string
targetFile string
apiVersion string
}{{
name: "Task Sign and pass verification",
resource: getTask(),
kind: "Task",
targetFile: "signed-task.yaml",
apiVersion: "v1beta1",
}, {
name: "Pipeline Sign and pass verification",
resource: getPipeline(),
kind: "Pipeline",
targetFile: "signed-pipeline.yaml",
apiVersion: "v1beta1",
},
}

Expand All @@ -101,7 +104,7 @@ func TestSign(t *testing.T) {
t.Fatalf("error reading file: %v", err)
}

target, signature, err := UnmarshalCRD(signed, tc.kind)
target, signature, err := UnmarshalCRD(signed, tc.kind, tc.apiVersion)
if err != nil {
t.Fatalf("error unmarshalling crd: %v", err)
}
Expand Down

0 comments on commit c50b3a2

Please sign in to comment.