Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add Validate function #190

Merged
merged 1 commit into from
Apr 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions fakes/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,10 @@ func (i *Image) Found() bool {
return !i.deleted
}

func (i *Image) Valid() bool {
return !i.deleted
}

func (i *Image) AnnotateRefName(refName string) error {
i.refName = refName
return nil
Expand Down
2 changes: 2 additions & 0 deletions image.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ type Image interface {
Env(key string) (string, error)
// Found tells whether the image exists in the repository by `Name()`.
Found() bool
// Valid returns true if the image is well formed (e.g. all manifest layers exist on the registry).
Valid() bool
GetAnnotateRefName() (string, error)
// GetLayer retrieves layer by diff id. Returns a reader of the uncompressed contents of the layer.
GetLayer(diffID string) (io.ReadCloser, error)
Expand Down
4 changes: 4 additions & 0 deletions layout/layout.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ func (i *Image) Found() bool {
return ImageExists(i.path)
}

func (i *Image) Valid() bool {
return i.Found()
}

func ImageExists(path string) bool {
if !pathExists(path) {
return false
Expand Down
47 changes: 47 additions & 0 deletions layout/layout_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -912,6 +912,53 @@ func testImage(t *testing.T, when spec.G, it spec.S) {
})
})

when("#Valid", func() {
var image *layout.Image

it.Before(func() {
imagePath = filepath.Join(tmpDir, "found-image")
image, err = layout.NewImage(imagePath)
h.AssertNil(t, err)
})

it.After(func() {
os.RemoveAll(imagePath)
})

when("image doesn't exist on disk", func() {
it.Before(func() {
imagePath = filepath.Join(tmpDir, "non-exist-image")
image, err = layout.NewImage(imagePath)
h.AssertNil(t, err)
})

it("returns false", func() {
h.AssertTrue(t, func() bool {
return !image.Found()
})
})
})

when("image exists on disk", func() {
it.Before(func() {
imagePath = filepath.Join(testDataDir, "my-previous-image")
image, err = layout.NewImage(imagePath)
h.AssertNil(t, err)
})

it.After(func() {
// We don't want to delete testdata/my-previous-image
imagePath = ""
})

it("returns true", func() {
h.AssertTrue(t, func() bool {
return image.Found()
})
})
})
})

when("#Delete", func() {
var image *layout.Image

Expand Down
4 changes: 4 additions & 0 deletions local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ func (i *Image) Found() bool {
return i.inspect.ID != ""
}

func (i *Image) Valid() bool {
return i.Found()
}

func (i *Image) GetAnnotateRefName() (string, error) {
return "", nil
}
Expand Down
19 changes: 19 additions & 0 deletions remote/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/google/go-containerregistry/pkg/v1/remote/transport"
"github.com/google/go-containerregistry/pkg/v1/tarball"
"github.com/google/go-containerregistry/pkg/v1/types"
"github.com/google/go-containerregistry/pkg/v1/validate"
"github.com/pkg/errors"

"github.com/buildpacks/imgutil"
Expand Down Expand Up @@ -92,6 +93,7 @@ func (i *Image) Env(key string) (string, error) {

func (i *Image) Found() bool {
_, err := i.found()

return err == nil
}

Expand All @@ -104,6 +106,23 @@ func (i *Image) found() (*v1.Descriptor, error) {
return remote.Head(ref, remote.WithAuth(auth), remote.WithTransport(http.DefaultTransport))
}

func (i *Image) Valid() bool {
return i.valid() == nil
}

func (i *Image) valid() error {
reg := getRegistry(i.repoName, i.registrySettings)
ref, auth, err := referenceForRepoName(i.keychain, i.repoName, reg.insecure)
if err != nil {
return err
}
img, err := remote.Image(ref, remote.WithAuth(auth), remote.WithTransport(http.DefaultTransport))
if err != nil {
return err
}
return validate.Image(img, validate.Fast)
}

func (i *Image) GetAnnotateRefName() (string, error) {
// TODO issue https://github.com/buildpacks/imgutil/issues/178
return "", errors.New("not yet implemented")
Expand Down
47 changes: 47 additions & 0 deletions remote/remote_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1595,6 +1595,53 @@ func testImage(t *testing.T, when spec.G, it spec.S) {
})
})

when("#Valid", func() {
when("it exists", func() {
it("returns true", func() {
origImage, err := remote.NewImage(repoName, authn.DefaultKeychain)
h.AssertNil(t, err)
h.AssertNil(t, origImage.Save())

image, err := remote.NewImage(repoName, authn.DefaultKeychain)
h.AssertNil(t, err)

h.AssertEq(t, image.Valid(), true)
})
})

when("it is corrupt", func() {
it("returns false", func() {
origImage, err := remote.NewImage(repoName, authn.DefaultKeychain)
h.AssertNil(t, err)
tarPath, _, _ := h.RandomLayer(t, t.TempDir())
defer os.Remove(tarPath)
h.AssertNil(t, origImage.AddLayer(tarPath))
h.AssertNil(t, origImage.Save())

// delete the top layer from the registry
layers, err := origImage.UnderlyingImage().Layers()
h.AssertNil(t, err)
digest, err := layers[0].Digest()
h.AssertNil(t, err)
h.DeleteRegistryBlob(t, repoName, digest, dockerRegistry.EncodedAuth())

image, err := remote.NewImage(repoName, authn.DefaultKeychain)
h.AssertNil(t, err)

h.AssertEq(t, image.Valid(), false)
})
})

when("it does not exist", func() {
it("returns false", func() {
image, err := remote.NewImage(repoName, authn.DefaultKeychain)
h.AssertNil(t, err)

h.AssertEq(t, image.Valid(), false)
})
})
})

when("#Delete", func() {
when("it exists", func() {
var img imgutil.Image
Expand Down
4 changes: 2 additions & 2 deletions testhelpers/docker_registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ func (r *DockerRegistry) Start(t *testing.T) {

if r.username != "" {
// Write Docker config and configure auth headers
writeDockerConfig(t, r.DockerDirectory, r.Host, r.Port, r.encodedAuth())
writeDockerConfig(t, r.DockerDirectory, r.Host, r.Port, r.EncodedAuth())
}
}

Expand Down Expand Up @@ -294,7 +294,7 @@ func DockerHostname(t *testing.T) string {
return "localhost"
}

func (r *DockerRegistry) encodedAuth() string {
func (r *DockerRegistry) EncodedAuth() string {
return base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", r.username, r.password)))
}

Expand Down
23 changes: 23 additions & 0 deletions testhelpers/testhelpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"io/ioutil"
"math/rand"
"net/http"
"net/url"
"os"
"path/filepath"
"regexp"
Expand Down Expand Up @@ -227,6 +228,28 @@ func PushImage(t *testing.T, dockerCli dockercli.CommonAPIClient, refStr string)
AssertNil(t, err)
}

// DeleteRegistryBlob deletes the blob with the given digest from the registry by issuing an HTTP DELETE request.
func DeleteRegistryBlob(t *testing.T, repoName string, digest v1.Hash, encodedAuth string) {
ref, err := name.ParseReference(repoName, name.WeakValidation)
AssertNil(t, err)
url := url.URL{
Scheme: ref.Context().Registry.Scheme(),
Host: ref.Context().RegistryStr(),
Path: fmt.Sprintf("/v2/%s/blobs/%s", ref.Context().RepositoryStr(), digest),
}
req, err := http.NewRequest(http.MethodDelete, url.String(), nil)
AssertNil(t, err)
req.Header.Add("Authorization", "Basic "+encodedAuth)
client := &http.Client{}
resp, err := client.Do(req)
AssertNil(t, err)
defer resp.Body.Close()

_, err = io.ReadAll(resp.Body)
AssertNil(t, err)
AssertEq(t, resp.StatusCode, http.StatusAccepted)
}

func ImageID(t *testing.T, repoName string) string {
t.Helper()
inspect, _, err := DockerCli(t).ImageInspectWithRaw(context.Background(), repoName)
Expand Down