Skip to content

Commit

Permalink
support v1 for sign and verofy command
Browse files Browse the repository at this point in the history
This commit adds v1 support for sign and verify.

Signed-off-by: Yongxuan Zhang [email protected]
  • Loading branch information
Yongxuanzhang committed Jan 17, 2024
1 parent 95548d3 commit 6db0851
Show file tree
Hide file tree
Showing 12 changed files with 255 additions and 81 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)
}
})
}
}
25 changes: 25 additions & 0 deletions pkg/cmd/pipeline/testdata/signed-v1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
annotations:
tekton.dev/signature: MEUCIQD3tcptnk2F+9ru5gNUi91K2NPe59Dk28lwaHEQzScnOQIgL+KpDuGBf67FHGrh34cZRHVmPuYzOzPUbmvealAJPvE=
creationTimestamp: null
name: test-pipeline
spec:
tasks:
- name: build-skaffold-web
params:
- name: pathToDockerFile
value: Dockerfile
- name: pathToContext
value: /workspace/docker-source/examples/microservices/leeroy-web
taskRef:
name: build-docker-image-from-git-source
- name: deploy-web
params:
- name: path
value: /workspace/source/examples/microservices/leeroy-web/kubernetes/deployment.yaml
- name: yamlPathToImage
value: spec.template.spec.containers[0].image
taskRef:
name: deploy-using-kubectl
15 changes: 12 additions & 3 deletions pkg/cmd/pipeline/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,17 @@ 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"
)

type verifyOptions struct {
keyfile string
kmsKey string
keyfile string
kmsKey string
apiVersion string
}

func verifyCommand() *cobra.Command {
Expand Down Expand Up @@ -68,7 +71,12 @@ 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 {
log.Fatalf("error unmarshalling Pipeline: %v", err)
return err
Expand All @@ -85,5 +93,6 @@ or using kms
f.AddFlags(c)
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.apiVersion, "version", "v", "v1", "apiVersion of the Pipeline to be verified")
return c
}
28 changes: 23 additions & 5 deletions pkg/cmd/pipeline/verify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package pipeline

import (
"fmt"
"os"
"testing"

Expand All @@ -28,10 +29,27 @@ func TestVerify(t *testing.T) {

os.Setenv("PRIVATE_PASSWORD", "1234")

out, err := test.ExecuteCommand(pipeline, "verify", "testdata/signed.yaml", "-K", "testdata/cosign.pub")
if err != nil {
t.Errorf("Unexpected error: %v", err)
testcases := []struct {
name string
taskFile string
apiVersion string
}{{
name: "verify v1beta1 Pipeline",
taskFile: "testdata/signed.yaml",
apiVersion: "v1beta1",
}, {
name: "verify v1 Pipeline",
taskFile: "testdata/signed-v1.yaml",
apiVersion: "v1",
}}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
out, err := test.ExecuteCommand(pipeline, "verify", tc.taskFile, "-K", "testdata/cosign.pub", "-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 passes verification \n", tc.taskFile)
test.AssertOutput(t, expected, out)
})
}
expected := "*Warning*: This is an experimental command, it's usage and behavior can change in the next release(s)\nPipeline testdata/signed.yaml passes verification \n"
test.AssertOutput(t, expected, out)
}
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)
}
})
}
}
26 changes: 26 additions & 0 deletions pkg/cmd/task/testdata/signed-v1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
apiVersion: tekton.dev/v1
kind: Task
metadata:
annotations:
tekton.dev/signature: MEUCIESVeQ7mC8hxSLrmcQhVsnc0ErIjZ9NLaKv2MifSrHYtAiEA1KfI181TCK2eJ8XH5fboBvbr2/YBVGqlgrkS7vfY9mw=
creationTimestamp: null
name: task-v1
spec:
params:
- name: foobar
type: string
results:
- name: url
steps:
- computeResources: {}
env:
- name: PARAM_URL
value: $(params.foobar)
image: alpine
name: build-sources
script: |
#!/bin/sh
printf "%s" "${PARAM_URL}" > "$(results.url.path)"
workspaces:
- name: temporary
Loading

0 comments on commit 6db0851

Please sign in to comment.