Skip to content

Commit

Permalink
feat: first working deployment test
Browse files Browse the repository at this point in the history
  • Loading branch information
puffitos committed Sep 23, 2023
1 parent f6caee9 commit a1a7942
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 22 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
cosignwebhook
grumpywebhook
chart/caas-values.yaml
test/keys

# the keypair used for test-signing of the webhook
*.key
*.pub
8 changes: 5 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,16 @@ test-busybox-images:

test-image:
@echo "Checking for cosign.key..."
@test -f test/keys/cosign.key || (echo "cosign.key not found. Run 'make generate-key' to generate one." && exit 1)
@test -f cosign.key || (echo "cosign.key not found. Run 'make generate-key' to generate one." && exit 1)
@echo "Building test image..."
@docker build -t k3d-registry.localhost:5000/cosignwebhook:dev .
@echo "Pushing test image..."
@docker push k3d-registry.localhost:5000/cosignwebhook:dev
@echo "Signing test image..."
@export COSIGN_PASSWORD="" && \
cosign sign --tlog-upload=false --key cosign.key k3d-registry.localhost:5000/cosignwebhook:dev
@SHA=$(shell docker inspect --format='{{index .RepoDigests 0}}' k3d-registry.localhost:5000/cosignwebhook:dev | cut -d '@' -f 2) && \
echo "Using image SHA: $${SHA}" && \
export COSIGN_PASSWORD="" && \
cosign sign --tlog-upload=false --key cosign.key k3d-registry.localhost:5000/cosignwebhook:dev@$${SHA}

test-deploy:
@echo "Deploying test image..."
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ kubectl -n cosignwebhook apply -f manifests/manifest.yaml

## Cert generation

Run the generate-certs script in the `hack` folder to generate the TLS key pair and the CA certificate for the webhook:

```bash
generate-certs.sh --service cosignwebhook --webhook cosignwebhook --namespace cosignwebhook --secret cosignwebhook
```
Expand Down
File renamed without changes.
97 changes: 79 additions & 18 deletions test/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func createKeys(t testing.TB, name string) (string, string) {
cmd.SetArgs(args)
err = cmd.Execute()
if err != nil {
cleanupKeys(t, name)
t.Fatalf("failed generating keypair: %v", err)
}

Expand All @@ -42,14 +43,67 @@ func createKeys(t testing.TB, name string) (string, string) {
return string(privateKey), string(pubKey)
}

// TestOneContainerPubKeyEnvVar tests that deployment with a single signed container,
// cleanupKeys removes all keypair files with the passed name from the testing directory
func cleanupKeys(t testing.TB, name string) {

t.Logf("cleaning up keypair files for %s", name)
// check if the keypair files exist
_, err := os.Stat(fmt.Sprintf("%s.key", name))
if err != nil {
t.Fatalf("failed reading private key: %v", err)
}

_, err = os.Stat(fmt.Sprintf("%s.pub", name))
if err != nil {
t.Fatalf("failed reading public key: %v", err)
}

err = os.Remove(fmt.Sprintf("%s.key", name))
if err != nil {
t.Fatalf("failed removing private key: %v", err)
}
err = os.Remove(fmt.Sprintf("%s.pub", name))
if err != nil {
t.Fatalf("failed removing public key: %v", err)
}
t.Logf("cleaned up keypair files for %s", name)
}

// signContainer signs the container with the provided private key
// TODO: find a way to simplify this function - maybe use cosing CLI directly?
func signContainer(t *testing.T, priv, img string) error {
args := []string{
"sign",
img,
}
t.Setenv("COSIGN_PASSWORD", "")
cmd := cli.New()
_ = cmd.Flags().Set("timeout", "30s")
cmd.SetArgs(args)

// find the sign subcommand in the commands slice
for _, c := range cmd.Commands() {
if c.Name() == "sign" {
cmd = c
break
}
}
_ = cmd.Flags().Set("key", fmt.Sprintf("%s.key", priv))
_ = cmd.Flags().Set("tlog-upload", "false")
_ = cmd.Flags().Set("yes", "true")
_ = cmd.Flags().Set("allow-http-registry", "true")
return cmd.Execute()
}

// TestOneContainerPubKeyEnvVar tests that a deployment with a single signed container,
// with a public key provided via an environment variable, succeeds.
func TestOneContainerPubKeyEnvVar(t *testing.T) {
// create a keypair to sign the container
_, pub := createKeys(t, "test")
os.Setenv("COSIGN_PASSWORD", "")
// sign the container
err := signContainer(t, "test")
t.Setenv("COSIGN_PASSWORD", "")

// sign the container with the ephemeral keypair
err := signContainer(t, "test", "k3d-registry.localhost:5000/busybox:dev@sha256:023917ec6a886d0e8e15f28fb543515a5fcd8d938edb091e8147db4efed388ee")
if err != nil {
t.Fatalf("failed signing container: %v", err)
}
Expand All @@ -72,7 +126,12 @@ func TestOneContainerPubKeyEnvVar(t *testing.T) {
Containers: []corev1.Container{
{
Name: "test-case-1",
Image: "image_name:tag",
Image: "k3d-registry.localhost:5000/busybox:dev@sha256:023917ec6a886d0e8e15f28fb543515a5fcd8d938edb091e8147db4efed388ee",
Command: []string{
"sh",
"-c",
"while true; do echo 'hello world, i am tired and will sleep now'; sleep 10; done",
},
Env: []corev1.EnvVar{
{
Name: webhook.CosignEnvVar,
Expand All @@ -89,25 +148,39 @@ func TestOneContainerPubKeyEnvVar(t *testing.T) {
// create clientset
k8sClient, err := createClientSet()
if err != nil {
cleanupKeys(t, "test")
t.Fatalf("failed creating clientset: %v", err)
}

// create the deployment
_, err = k8sClient.AppsV1().Deployments("test-cases").Create(context.Background(), &depl, metav1.CreateOptions{})
if err != nil {
cleanupKeys(t, "test")
t.Fatalf("failed creating deployment: %v", err)
}

// wait for the deployment to be ready
err = waitForDeploymentReady(t, k8sClient, "test-cases", "test-case-1")
if err != nil {
cleanupKeys(t, "test")
t.Fatalf("failed waiting for deployment to be ready: %v", err)
}

// delete the deployment
err = k8sClient.AppsV1().Deployments("test-cases").Delete(context.Background(), "test-case-1", metav1.DeleteOptions{})
if err != nil {
cleanupKeys(t, "test")
t.Fatalf("failed deleting deployment: %v", err)
}

// cleanup the keypair
cleanupKeys(t, "test")
}

// waitForDeploymentReady waits for the deployment to be ready
func waitForDeploymentReady(t *testing.T, k8sClient *kubernetes.Clientset, ns, name string) error {

t.Logf("waiting for deployment %s to be ready", name)
// wait until the deployment is ready
w, err := k8sClient.AppsV1().Deployments(ns).Watch(context.Background(), metav1.ListOptions{
FieldSelector: fmt.Sprintf("metadata.name=%s", name),
Expand All @@ -116,33 +189,21 @@ func waitForDeploymentReady(t *testing.T, k8sClient *kubernetes.Clientset, ns, n
if err != nil {
return err
}

for event := range w.ResultChan() {
deployment, ok := event.Object.(*appsv1.Deployment)
if !ok {
continue
}

if deployment.Status.ReadyReplicas == 1 {
t.Logf("deployment %s is ready", name)
return nil
}
}

return nil
}

func signContainer(t *testing.T, priv string) error {
args := []string{
"sign",
"--key", fmt.Sprintf("%s.key", priv),
"image_name:tag",
}
cmd := cli.Sign()
cmd.SetArgs(args)
return cmd.Execute()

}

func createClientSet() (k8sClient *kubernetes.Clientset, err error) {
kubeconfig := os.Getenv("KUBECONFIG")
if kubeconfig == "" {
Expand Down

0 comments on commit a1a7942

Please sign in to comment.