Skip to content

Commit

Permalink
Fix BuildKit and BuildAh image digest extraction
Browse files Browse the repository at this point in the history
  • Loading branch information
SaschaSchwarze0 committed Mar 28, 2022
1 parent 204731d commit 3e5b6d7
Show file tree
Hide file tree
Showing 9 changed files with 203 additions and 130 deletions.
16 changes: 12 additions & 4 deletions samples/buildstrategy/buildah/buildstrategy_buildah_cr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,18 @@ spec:
"${image}" \
"docker://${image}"
# Store the digest result
buildah images \
--format='{{.Digest}}' \
"${image}" | tr -d "\n" > '$(results.shp-image-digest.path)'
# Store the digest result. This is more complex than expected. BuildAh locally calculates a wrong digest.
# We therefore tag the image to a dummy name so that the layers are still present. Then we remove the local
# tag. Then we pull again. Then the local digest is correct.
# This should be validated again with a newer BuildAh version.
# https://github.com/containers/buildah/issues/3866
buildah tag "${image}" dummy
buildah rmi "${image}"
buildah pull --tls-verify="${tlsVerify}" "${image}"
buildah inspect \
--type=image \
--format='{{.FromImageDigest}}' \
"${image}" > '$(results.shp-image-digest.path)'
# That's the separator between the shell script and its args
- --
- --context
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ spec:
/tmp/run.sh
# Store the image digest
sed -E 's/.*containerimage.digest":"([^"]*).*/\1/' < /tmp/image-metadata.json > '$(results.shp-image-digest.path)'
grep containerimage.digest /tmp/image-metadata.json | sed -E 's/.*containerimage.digest":\s*"([^"]*).*/\1/' | tr -d '\n' > '$(results.shp-image-digest.path)'
# That's the separator between the shell script and its args
- --
- --build-args
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,21 @@ spec:
# Push the image
echo "[INFO] Pushing image ${image}"
buildah push \
--tls-verify="${tlsVerify}" \
"docker://${image}"
# Store the digest result
buildah images \
--format='{{.Digest}}' \
"${image}" | tr -d "\n" > '$(results.shp-image-digest.path)'
# Store the digest result. This is more complex than expected. BuildAh locally calculates a wrong digest.
# We therefore tag the image to a dummy name so that the layers are still present. Then we remove the local
# tag. Then we pull again. Then the local digest is correct.
# This should be validated again with a newer BuildAh version.
# https://github.com/containers/buildah/issues/3866
buildah tag "${image}" dummy
buildah rmi "${image}"
buildah pull --tls-verify="${tlsVerify}" "${image}"
buildah inspect \
--type=image \
--format='{{.FromImageDigest}}' \
"${image}" > '$(results.shp-image-digest.path)'
# That's the separator between the shell script and its args
- --
- --image
Expand Down
9 changes: 6 additions & 3 deletions test/e2e/e2e_bundle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,9 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun
Create()
Expect(err).ToNot(HaveOccurred())

validateBuildRunToSucceed(testBuild, buildRun)
buildRun = validateBuildRunToSucceed(testBuild, buildRun)
validateBuildRunResultsFromBundleSource(buildRun)
testBuild.ValidateImageDigest(buildRun)
})

It("should work with Buildpacks build strategy", func() {
Expand All @@ -99,8 +100,9 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun
Create()
Expect(err).ToNot(HaveOccurred())

validateBuildRunToSucceed(testBuild, buildRun)
buildRun = validateBuildRunToSucceed(testBuild, buildRun)
validateBuildRunResultsFromBundleSource(buildRun)
testBuild.ValidateImageDigest(buildRun)
})

It("should work with Buildah build strategy", func() {
Expand Down Expand Up @@ -130,8 +132,9 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun
Create()
Expect(err).ToNot(HaveOccurred())

validateBuildRunToSucceed(testBuild, buildRun)
buildRun = validateBuildRunToSucceed(testBuild, buildRun)
validateBuildRunResultsFromBundleSource(buildRun)
testBuild.ValidateImageDigest(buildRun)
})
})
})
74 changes: 6 additions & 68 deletions test/e2e/e2e_image_mutate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,9 @@
package e2e_test

import (
"encoding/json"
"log"
"strings"

"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name"
containerreg "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/remote"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"k8s.io/apimachinery/pkg/types"

buildv1alpha1 "github.com/shipwright-io/build/pkg/apis/build/v1alpha1"
)
Expand Down Expand Up @@ -66,76 +58,22 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun
Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data")
appendRegistryInsecureParamValue(build, buildRun)

validateBuildRunToSucceed(testBuild, buildRun)
buildRun = validateBuildRunToSucceed(testBuild, buildRun)
testBuild.ValidateImageDigest(buildRun)

image := testBuild.GetImage(buildRun)

Expect(
getImageAnnotation(getImage(build), "org.opencontainers.image.url"),
getImageAnnotation(image, "org.opencontainers.image.url"),
).To(Equal("https://my-company.com/images"))

Expect(
getImageLabel(getImage(build), "maintainer"),
getImageLabel(image, "maintainer"),
).To(Equal("team@my-company.com"))
})
})
})

func getRegistryAuthentication(
build *buildv1alpha1.Build,
ref name.Reference,
) authn.Authenticator {
// In case no secret is mounted, use anonymous
if build.Spec.Output.Credentials == nil || build.Spec.Output.Credentials.Name == "" {
log.Printf("No access credentials provided, using anonymous mode")
return authn.Anonymous
}

secret, err := testBuild.LookupSecret(
types.NamespacedName{
Namespace: build.Namespace,
Name: build.Spec.Output.Credentials.Name,
},
)
Expect(err).ToNot(HaveOccurred(), "Error retrieving registry secret")

type auth struct {
Auths map[string]authn.AuthConfig `json:"auths,omitempty"`
}

var authConfig auth

Expect(json.Unmarshal(secret.Data[".dockerconfigjson"], &authConfig)).
ToNot(HaveOccurred())

// Look-up the respective registry server inside the credentials
registryName := ref.Context().RegistryStr()
if registryName == name.DefaultRegistry {
registryName = authn.DefaultAuthKey
}

return authn.FromConfig(authConfig.Auths[registryName])
}

func getImage(build *buildv1alpha1.Build) containerreg.Image {
// In the GitHub action, we are using a registry inside the cluster to
// push the image created by `buildRun`. The registry inside the cluster
// is not directly accessible from the local, so that we have mapped
// the cluster registry port to the local system
// by providing `test/kind/config.yaml` config to the kind
image := strings.Replace(
build.Spec.Output.Image,
"registry.registry.svc.cluster.local",
"localhost", 1,
)

ref, err := name.ParseReference(image)
Expect(err).To(BeNil())

img, err := remote.Image(ref, remote.WithAuth(getRegistryAuthentication(build, ref)))
Expect(err).To(BeNil())

return img
}

func getImageAnnotation(img containerreg.Image, annotation string) string {
manifest, err := img.Manifest()
Expect(err).To(BeNil())
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/e2e_params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun
Create()
Expect(err).ToNot(HaveOccurred())

validateBuildRunToSucceed(testBuild, buildRun)
buildRun = validateBuildRunToSucceed(testBuild, buildRun)

// we verify the image digest here which is mis-used by the strategy to store a calculated sum
// 13 (env1) + 21 (env2 = 2${a-configmap:number1}) + 2 (env3 = ${a-secret:number2}) + 39 (args[0] = ${a-secret:number3}9) + 47 (args[1]) = 122
Expand Down
Loading

0 comments on commit 3e5b6d7

Please sign in to comment.