Skip to content

Commit

Permalink
Add end-to-end tests for Builder/ClusterBuilder signing.
Browse files Browse the repository at this point in the history
Add a new test suite to the end-to-end tests to verify that once a Builder or
ClusterBuilder is created, if a cosign secret is present, then the image will
be signed and the signature will be verifiable.
  • Loading branch information
stormqueen1990 committed Jun 12, 2023
1 parent 4bcac5e commit 10108d0
Show file tree
Hide file tree
Showing 3 changed files with 706 additions and 74 deletions.
101 changes: 28 additions & 73 deletions pkg/cosign/image_signer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package cosign
import (
"bufio"
"context"
"crypto"
"encoding/base64"
"fmt"
"io/ioutil"
"log"
Expand All @@ -30,10 +28,8 @@ import (
"github.com/sigstore/cosign/v2/cmd/cosign/cli/download"
"github.com/sigstore/cosign/v2/cmd/cosign/cli/options"
"github.com/sigstore/cosign/v2/cmd/cosign/cli/sign"
verifypkg "github.com/sigstore/cosign/v2/cmd/cosign/cli/verify"
sigstoreCosign "github.com/sigstore/cosign/v2/pkg/cosign"
ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote"
"github.com/sigstore/cosign/v2/pkg/signature"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -150,10 +146,10 @@ func testImageSigner(t *testing.T, when spec.G, it spec.S) {
assert.Equal(t, 1, password1Count)
assert.Equal(t, 1, password2Count)

err = verify(publicKey1, expectedImageName, nil)
err = Verify(t, publicKey1, expectedImageName, nil)
assert.Nil(t, err)

err = verify(publicKey2, expectedImageName, nil)
err = Verify(t, publicKey2, expectedImageName, nil)
assert.Nil(t, err)

err = download.SignatureCmd(context.Background(), options.RegistryOptions{}, expectedImageName)
Expand Down Expand Up @@ -194,21 +190,21 @@ func testImageSigner(t *testing.T, when spec.G, it spec.S) {
assert.Equal(t, 2, cliSignCmdCallCount)

// Should error when validating annotations that dont exist
err = verify(publicKey1, expectedImageName, unexpectedAnnotation)
err = Verify(t, publicKey1, expectedImageName, unexpectedAnnotation)
assert.Error(t, err)
err = verify(publicKey2, expectedImageName, unexpectedAnnotation)
err = Verify(t, publicKey2, expectedImageName, unexpectedAnnotation)
assert.Error(t, err)

// Should not error when validating annotations that exist
err = verify(publicKey1, expectedImageName, expectedAnnotation)
err = Verify(t, publicKey1, expectedImageName, expectedAnnotation)
assert.Nil(t, err)
err = verify(publicKey2, expectedImageName, expectedAnnotation)
err = Verify(t, publicKey2, expectedImageName, expectedAnnotation)
assert.Nil(t, err)

// Should not error when not validating annotations
err = verify(publicKey1, expectedImageName, nil)
err = Verify(t, publicKey1, expectedImageName, nil)
assert.Nil(t, err)
err = verify(publicKey2, expectedImageName, nil)
err = Verify(t, publicKey2, expectedImageName, nil)
assert.Nil(t, err)

err = download.SignatureCmd(context.Background(), options.RegistryOptions{}, expectedImageName)
Expand Down Expand Up @@ -304,9 +300,9 @@ func testImageSigner(t *testing.T, when spec.G, it spec.S) {

assertUnset(t, cosignRepositoryEnv)

err = verify(publicKey1, expectedImageName, nil)
err = Verify(t, publicKey1, expectedImageName, nil)
assert.Nil(t, err)
err = verify(publicKey2, expectedImageName, nil)
err = Verify(t, publicKey2, expectedImageName, nil)
assert.Error(t, err)
err = download.SignatureCmd(context.Background(), options.RegistryOptions{}, expectedImageName)
assert.Nil(t, err)
Expand All @@ -315,9 +311,9 @@ func testImageSigner(t *testing.T, when spec.G, it spec.S) {
// on a registry that does not contain the image
os.Setenv(cosignRepositoryEnv, altImageName)
defer os.Unsetenv(cosignRepositoryEnv)
err = verify(publicKey1, expectedImageName, nil)
err = Verify(t, publicKey1, expectedImageName, nil)
assert.Error(t, err)
err = verify(publicKey2, expectedImageName, nil)
err = Verify(t, publicKey2, expectedImageName, nil)
assert.Nil(t, err)
})

Expand Down Expand Up @@ -463,7 +459,7 @@ func testImageSigner(t *testing.T, when spec.G, it spec.S) {

ctx := context.Background()
// Verify+download should fail at first
err := verify(pubKeyPath, imgName, nil)
err := Verify(t, pubKeyPath, imgName, nil)
assert.Error(t, err)
err = download.SignatureCmd(ctx, options.RegistryOptions{}, imgName)
assert.Error(t, err)
Expand All @@ -488,14 +484,20 @@ func testImageSigner(t *testing.T, when spec.G, it spec.S) {
assert.Nil(t, err)

// Verify+download should pass
err = verify(pubKeyPath, imgName, nil)
err = Verify(t, pubKeyPath, imgName, nil)
assert.Nil(t, err)
err = download.SignatureCmd(ctx, options.RegistryOptions{}, imgName)
assert.Nil(t, err)
})
})

when("#SignBuilder", func() {
const (
cosignSecretName = "cosign-creds"
testNamespaceName = "test-namespace"
cosignServiceAccountName = "cosign-sa"
)

it("resolves the digest of a signature correctly", func() {
var (
signCallCount = 0
Expand All @@ -521,12 +523,12 @@ func testImageSigner(t *testing.T, when spec.G, it spec.S) {
},
}

fakeSecret := generateFakeKeyPair(t, "", nil)
fakeSecret := GenerateFakeKeyPair(t, cosignSecretName, testNamespaceName, "", nil)
cosignCreds := []corev1.Secret{fakeSecret}
cosignSA := corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Name: "cosign-sa",
Namespace: "test-namespace",
Name: cosignServiceAccountName,
Namespace: testNamespaceName,
},
Secrets: []corev1.ObjectReference{
{
Expand Down Expand Up @@ -599,12 +601,12 @@ func testImageSigner(t *testing.T, when spec.G, it spec.S) {
"kpack.io/cosign.docker-media-types": dockerMediaTypesValue,
}

fakeSecret := generateFakeKeyPair(t, "", annotations)
fakeSecret := GenerateFakeKeyPair(t, cosignSecretName, testNamespaceName, "", annotations)
cosignCreds := []corev1.Secret{fakeSecret}
cosignSA := corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Name: "cosign-sa",
Namespace: "test-namespace",
Name: cosignServiceAccountName,
Namespace: testNamespaceName,
},
Secrets: []corev1.ObjectReference{
{
Expand Down Expand Up @@ -637,41 +639,6 @@ func testImageSigner(t *testing.T, when spec.G, it spec.S) {
})
}

func generateFakeKeyPair(t *testing.T, password string, annotations map[string]string) corev1.Secret {
passFunc := func(_ bool) ([]byte, error) {
return []byte(password), nil
}

keys, err := sigstoreCosign.GenerateKeyPair(passFunc)
require.NoError(t, err)

encodedPublicKey := make([]byte, base64.StdEncoding.EncodedLen(len(keys.PublicBytes)))
base64.StdEncoding.Encode(encodedPublicKey, keys.PublicBytes)

encodedPrivateKey := make([]byte, base64.StdEncoding.EncodedLen(len(keys.PrivateBytes)))
base64.StdEncoding.Encode(encodedPrivateKey, keys.PrivateBytes)

encodedPassword := make([]byte, base64.StdEncoding.EncodedLen(len([]byte(password))))
base64.StdEncoding.Encode(encodedPassword, []byte(password))

data := map[string][]byte{
SecretDataCosignPublicKey: encodedPublicKey,
SecretDataCosignKey: encodedPrivateKey,
SecretDataCosignPassword: encodedPassword,
}

secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "cosign-creds",
Namespace: "test-namespace",
Annotations: annotations,
},
Data: data,
}

return secret
}

func mockLogger(t *testing.T) (*bufio.Scanner, *os.File, *os.File) {
reader, writer, err := os.Pipe()
if err != nil {
Expand Down Expand Up @@ -763,6 +730,8 @@ func registryClientOpts(ctx context.Context) []remote.Option {
}

func keypair(t *testing.T, dirPath, secretName, password string) {
t.Helper()

passFunc := func(_ bool) ([]byte, error) {
return []byte(password), nil
}
Expand All @@ -786,17 +755,3 @@ func keypair(t *testing.T, dirPath, secretName, password string) {
err = ioutil.WriteFile(passwordPath, passwordBytes, 0600)
assert.Nil(t, err)
}

func verify(keyRef, imageRef string, annotations map[string]interface{}) error {
cmd := verifypkg.VerifyCommand{
KeyRef: keyRef,
Annotations: signature.AnnotationsMap{Annotations: annotations},
CheckClaims: true,
HashAlgorithm: crypto.SHA256,
IgnoreTlog: true,
}

args := []string{imageRef}

return cmd.Exec(context.Background(), args)
}
57 changes: 57 additions & 0 deletions pkg/cosign/test_util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package cosign

import (
"context"
"crypto"
cosignVerify "github.com/sigstore/cosign/v2/cmd/cosign/cli/verify"
"github.com/sigstore/cosign/v2/pkg/cosign"
"github.com/sigstore/cosign/v2/pkg/signature"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"testing"
)

func GenerateFakeKeyPair(t *testing.T, secretName string, secretNamespace string, password string, annotations map[string]string) corev1.Secret {
t.Helper()

passFunc := func(_ bool) ([]byte, error) {
return []byte(password), nil
}

keys, err := cosign.GenerateKeyPair(passFunc)
require.NoError(t, err)

data := map[string][]byte{
SecretDataCosignPublicKey: keys.PublicBytes,
SecretDataCosignKey: keys.PrivateBytes,
SecretDataCosignPassword: []byte(password),
}

secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: secretNamespace,
Annotations: annotations,
},
Data: data,
}

return secret
}

func Verify(t *testing.T, keyRef, imageRef string, annotations map[string]interface{}) error {
t.Helper()

cmd := cosignVerify.VerifyCommand{
KeyRef: keyRef,
Annotations: signature.AnnotationsMap{Annotations: annotations},
CheckClaims: true,
HashAlgorithm: crypto.SHA256,
IgnoreTlog: true,
}

args := []string{imageRef}

return cmd.Exec(context.Background(), args)
}
Loading

0 comments on commit 10108d0

Please sign in to comment.