Skip to content

Commit

Permalink
Merge pull request #2092 from buildpacks/bugfix/jjbustamante/issue-2078
Browse files Browse the repository at this point in the history
Adding a nop-op when trying to check access for run-image against the daemon
  • Loading branch information
jjbustamante authored Apr 26, 2024
2 parents 12b7d24 + e85ddee commit d7c6f0e
Show file tree
Hide file tree
Showing 18 changed files with 272 additions and 191 deletions.
12 changes: 12 additions & 0 deletions internal/builder/image_fetcher_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ type ImageFetcher interface {
// If daemon is true, it will look return a `local.Image`. Pull, applicable only when daemon is true, will
// attempt to pull a remote image first.
Fetch(ctx context.Context, name string, options image.FetchOptions) (imgutil.Image, error)

// CheckReadAccess verifies if an image is accessible with read permissions
// When FetchOptions.Daemon is true and the image doesn't exist in the daemon,
// the behavior is dictated by the pull policy, which can have the following behavior
// - PullNever: returns false
// - PullAlways Or PullIfNotPresent: it will check read access for the remote image.
// When FetchOptions.Daemon is false it will check read access for the remote image.
CheckReadAccess(repo string, options image.FetchOptions) bool
}

type ImageFetcherWrapper struct {
Expand All @@ -32,3 +40,7 @@ func (w *ImageFetcherWrapper) Fetch(
) (Inspectable, error) {
return w.fetcher.Fetch(ctx, name, options)
}

func (w *ImageFetcherWrapper) CheckReadAccessValidator(repo string, options image.FetchOptions) bool {
return w.fetcher.CheckReadAccess(repo, options)
}
19 changes: 0 additions & 19 deletions internal/fakes/fake_access_checker.go

This file was deleted.

4 changes: 4 additions & 0 deletions internal/fakes/fake_image_fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ func (f *FakeImageFetcher) Fetch(ctx context.Context, name string, options image
return ri, nil
}

func (f *FakeImageFetcher) CheckReadAccess(_ string, _ image.FetchOptions) bool {
return true
}

func shouldPull(localFound, remoteFound bool, policy image.PullPolicy) bool {
if remoteFound && !localFound && policy == image.PullIfNotPresent {
return true
Expand Down
1 change: 1 addition & 0 deletions pkg/buildpack/downloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type Logger interface {

type ImageFetcher interface {
Fetch(ctx context.Context, name string, options image.FetchOptions) (imgutil.Image, error)
CheckReadAccess(repo string, options image.FetchOptions) bool
}

type Downloader interface {
Expand Down
4 changes: 2 additions & 2 deletions pkg/client/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,13 +340,13 @@ func (c *Client) Build(ctx context.Context, opts BuildOptions) error {
return errors.Wrapf(err, "invalid builder %s", style.Symbol(opts.Builder))
}

runImageName := c.resolveRunImage(opts.RunImage, imgRegistry, builderRef.Context().RegistryStr(), bldr.DefaultRunImage(), opts.AdditionalMirrors, opts.Publish, c.accessChecker)

fetchOptions := image.FetchOptions{
Daemon: !opts.Publish,
PullPolicy: opts.PullPolicy,
Platform: fmt.Sprintf("%s/%s", builderOS, builderArch),
}
runImageName := c.resolveRunImage(opts.RunImage, imgRegistry, builderRef.Context().RegistryStr(), bldr.DefaultRunImage(), opts.AdditionalMirrors, opts.Publish, fetchOptions)

if opts.Layout() {
targetRunImagePath, err := layout.ParseRefToPath(runImageName)
if err != nil {
Expand Down
3 changes: 0 additions & 3 deletions pkg/client/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ func testBuild(t *testing.T, when spec.G, it spec.S) {
subject *Client
fakeImageFetcher *ifakes.FakeImageFetcher
fakeLifecycle *ifakes.FakeLifecycle
fakeAccessChecker *ifakes.FakeAccessChecker
defaultBuilderStackID = "some.stack.id"
defaultWindowsBuilderStackID = "some.windows.stack.id"
defaultBuilderImage *fakes.Image
Expand All @@ -81,7 +80,6 @@ func testBuild(t *testing.T, when spec.G, it spec.S) {
var err error

fakeImageFetcher = ifakes.NewFakeImageFetcher()
fakeAccessChecker = ifakes.NewFakeAccessChecker()
fakeLifecycle = &ifakes.FakeLifecycle{}

tmpDir, err = os.MkdirTemp("", "build-test")
Expand Down Expand Up @@ -138,7 +136,6 @@ func testBuild(t *testing.T, when spec.G, it spec.S) {
logger: logger,
imageFetcher: fakeImageFetcher,
downloader: blobDownloader,
accessChecker: fakeAccessChecker,
lifecycleExecutor: fakeLifecycle,
docker: docker,
buildpackDownloader: buildpackDownloader,
Expand Down
28 changes: 8 additions & 20 deletions pkg/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ type ImageFetcher interface {
// PullIfNotPresent and daemon = false, gives us the same behavior as PullAlways.
// There is a single invalid configuration, PullNever and daemon = false, this will always fail.
Fetch(ctx context.Context, name string, options image.FetchOptions) (imgutil.Image, error)

// CheckReadAccess verifies if an image is accessible with read permissions
// When FetchOptions.Daemon is true and the image doesn't exist in the daemon,
// the behavior is dictated by the pull policy, which can have the following behavior
// - PullNever: returns false
// - PullAlways Or PullIfNotPresent: it will check read access for the remote image.
// When FetchOptions.Daemon is false it will check read access for the remote image.
CheckReadAccess(repo string, options image.FetchOptions) bool
}

//go:generate mockgen -package testmocks -destination ../testmocks/mock_blob_downloader.go github.com/buildpacks/pack/pkg/client BlobDownloader
Expand Down Expand Up @@ -80,13 +88,6 @@ type BuildpackDownloader interface {
Download(ctx context.Context, buildpackURI string, opts buildpack.DownloadOptions) (buildpack.BuildModule, []buildpack.BuildModule, error)
}

//go:generate mockgen -package testmocks -destination ../testmocks/mock_access_checker.go github.com/buildpacks/pack/pkg/client AccessChecker

// AccessChecker is an interface for checking remote images for read access
type AccessChecker interface {
Check(repo string) bool
}

// Client is an orchestration object, it contains all parameters needed to
// build an app image using Cloud Native Buildpacks.
// All settings on this object should be changed through ClientOption functions.
Expand All @@ -97,7 +98,6 @@ type Client struct {
keychain authn.Keychain
imageFactory ImageFactory
imageFetcher ImageFetcher
accessChecker AccessChecker
downloader BlobDownloader
lifecycleExecutor LifecycleExecutor
buildpackDownloader BuildpackDownloader
Expand Down Expand Up @@ -133,14 +133,6 @@ func WithFetcher(f ImageFetcher) Option {
}
}

// WithAccessChecker supply your own AccessChecker.
// A AccessChecker returns true if an image is accessible for reading.
func WithAccessChecker(f AccessChecker) Option {
return func(c *Client) {
c.accessChecker = f
}
}

// WithDownloader supply your own downloader.
// A Downloader is used to gather buildpacks from both remote urls, or local sources.
func WithDownloader(d BlobDownloader) Option {
Expand Down Expand Up @@ -241,10 +233,6 @@ func NewClient(opts ...Option) (*Client, error) {
}
}

if client.accessChecker == nil {
client.accessChecker = image.NewAccessChecker(client.logger, client.keychain)
}

if client.buildpackDownloader == nil {
client.buildpackDownloader = buildpack.NewDownloader(
client.logger,
Expand Down
10 changes: 0 additions & 10 deletions pkg/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"github.com/sclevine/spec"
"github.com/sclevine/spec/report"

"github.com/buildpacks/pack/pkg/image"
"github.com/buildpacks/pack/pkg/logging"
"github.com/buildpacks/pack/pkg/testmocks"
h "github.com/buildpacks/pack/testhelpers"
Expand Down Expand Up @@ -123,13 +122,4 @@ func testClient(t *testing.T, when spec.G, it spec.S) {
h.AssertEq(t, cl.registryMirrors, registryMirrors)
})
})

when("#WithAccessChecker", func() {
it("uses AccessChecker provided", func() {
ac := &image.Checker{}
cl, err := NewClient(WithAccessChecker(ac))
h.AssertNil(t, err)
h.AssertSameInstance(t, cl.accessChecker, ac)
})
})
}
14 changes: 8 additions & 6 deletions pkg/client/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/buildpacks/pack/internal/config"
"github.com/buildpacks/pack/internal/registry"
"github.com/buildpacks/pack/internal/style"
"github.com/buildpacks/pack/pkg/image"
"github.com/buildpacks/pack/pkg/logging"
)

Expand All @@ -28,7 +29,7 @@ func (c *Client) parseTagReference(imageName string) (name.Reference, error) {
return ref, nil
}

func (c *Client) resolveRunImage(runImage, imgRegistry, bldrRegistry string, runImageMetadata builder.RunImageMetadata, additionalMirrors map[string][]string, publish bool, accessChecker AccessChecker) string {
func (c *Client) resolveRunImage(runImage, imgRegistry, bldrRegistry string, runImageMetadata builder.RunImageMetadata, additionalMirrors map[string][]string, publish bool, options image.FetchOptions) string {
if runImage != "" {
c.logger.Debugf("Using provided run-image %s", style.Symbol(runImage))
return runImage
Expand All @@ -44,7 +45,8 @@ func (c *Client) resolveRunImage(runImage, imgRegistry, bldrRegistry string, run
runImageMetadata.Image,
runImageMetadata.Mirrors,
additionalMirrors[runImageMetadata.Image],
accessChecker,
c.imageFetcher,
options,
)

switch {
Expand Down Expand Up @@ -108,8 +110,8 @@ func contains(slc []string, v string) bool {
return false
}

func getBestRunMirror(registry string, runImage string, mirrors []string, preferredMirrors []string, accessChecker AccessChecker) string {
runImageList := filterImageList(append(append(append([]string{}, preferredMirrors...), runImage), mirrors...), accessChecker)
func getBestRunMirror(registry string, runImage string, mirrors []string, preferredMirrors []string, fetcher ImageFetcher, options image.FetchOptions) string {
runImageList := filterImageList(append(append(append([]string{}, preferredMirrors...), runImage), mirrors...), fetcher, options)
for _, img := range runImageList {
ref, err := name.ParseReference(img, name.WeakValidation)
if err != nil {
Expand All @@ -127,11 +129,11 @@ func getBestRunMirror(registry string, runImage string, mirrors []string, prefer
return runImage
}

func filterImageList(imageList []string, accessChecker AccessChecker) []string {
func filterImageList(imageList []string, fetcher ImageFetcher, options image.FetchOptions) []string {
var accessibleImages []string

for i, img := range imageList {
if accessChecker.Check(img) {
if fetcher.CheckReadAccess(img, options) {
accessibleImages = append(accessibleImages, imageList[i])
}
}
Expand Down
Loading

0 comments on commit d7c6f0e

Please sign in to comment.