From 0bba81c160767a44d9e030e25003d3f65c50d9b7 Mon Sep 17 00:00:00 2001 From: Natalie Arellano Date: Tue, 9 Apr 2024 13:03:45 -0400 Subject: [PATCH 01/18] Fix https://github.com/buildpacks/pack/issues/2120 Signed-off-by: Natalie Arellano --- internal/commands/buildpack_new_test.go | 29 ++++++++++--------- internal/layer/writer_factory_test.go | 2 +- internal/target/parse.go | 11 +++++-- internal/target/parse_test.go | 38 ++++++++++++++++--------- pkg/dist/buildmodule.go | 6 ++-- pkg/dist/buildpack_descriptor.go | 33 +++++++++------------ pkg/dist/buildpack_descriptor_test.go | 18 ++++++------ 7 files changed, 75 insertions(+), 62 deletions(-) diff --git a/internal/commands/buildpack_new_test.go b/internal/commands/buildpack_new_test.go index 4a988672df..05a76f42b4 100644 --- a/internal/commands/buildpack_new_test.go +++ b/internal/commands/buildpack_new_test.go @@ -97,14 +97,14 @@ func testBuildpackNewCommand(t *testing.T, when spec.G, it spec.S) { Arch: "arm", ArchVariant: "v6", Distributions: []dist.Distribution{{ - Name: "ubuntu", - Versions: []string{"14.04", "16.04"}, + Name: "ubuntu", + Version: "14.04", }}, }}, }).Return(nil).MaxTimes(1) path := filepath.Join(tmpDir, "targets") - command.SetArgs([]string{"--path", path, "example/targets", "--targets", "linux/arm/v6:ubuntu@14.04@16.04"}) + command.SetArgs([]string{"--path", path, "example/targets", "--targets", "linux/arm/v6:ubuntu@14.04"}) err := command.Execute() h.AssertNil(t, err) @@ -120,8 +120,11 @@ func testBuildpackNewCommand(t *testing.T, when spec.G, it spec.S) { Arch: "arm", ArchVariant: "v6", Distributions: []dist.Distribution{{ - Name: "ubuntu", - Versions: []string{"14.04", "16.04"}, + Name: "ubuntu", + Version: "14.04", + }, { + Name: "ubuntu", + Version: "16.04", }}, }}, }).Return(nil).MaxTimes(1) @@ -133,7 +136,7 @@ func testBuildpackNewCommand(t *testing.T, when spec.G, it spec.S) { h.AssertNotNil(t, err) }) when("it should", func() { - it("support format [os][/arch][/variant]:[name@version@version2];[some-name@version@version2]", func() { + it("support format [os][/arch][/variant]:[name@version];[some-name@version]", func() { mockClient.EXPECT().NewBuildpack(gomock.Any(), client.NewBuildpackOptions{ API: "0.8", ID: "example/targets", @@ -146,12 +149,12 @@ func testBuildpackNewCommand(t *testing.T, when spec.G, it spec.S) { ArchVariant: "v6", Distributions: []dist.Distribution{ { - Name: "ubuntu", - Versions: []string{"14.04", "16.04"}, + Name: "ubuntu", + Version: "14.04", }, { - Name: "debian", - Versions: []string{"8.10", "10.9"}, + Name: "debian", + Version: "8.10", }, }, }, @@ -160,8 +163,8 @@ func testBuildpackNewCommand(t *testing.T, when spec.G, it spec.S) { Arch: "amd64", Distributions: []dist.Distribution{ { - Name: "windows-nano", - Versions: []string{"10.0.19041.1415"}, + Name: "windows-nano", + Version: "10.0.19041.1415", }, }, }, @@ -169,7 +172,7 @@ func testBuildpackNewCommand(t *testing.T, when spec.G, it spec.S) { }).Return(nil).MaxTimes(1) path := filepath.Join(tmpDir, "targets") - command.SetArgs([]string{"--path", path, "example/targets", "--targets", "linux/arm/v6:ubuntu@14.04@16.04;debian@8.10@10.9", "-t", "windows/amd64:windows-nano@10.0.19041.1415"}) + command.SetArgs([]string{"--path", path, "example/targets", "--targets", "linux/arm/v6:ubuntu@14.04;debian@8.10", "-t", "windows/amd64:windows-nano@10.0.19041.1415"}) err := command.Execute() h.AssertNil(t, err) diff --git a/internal/layer/writer_factory_test.go b/internal/layer/writer_factory_test.go index af9c5cfc59..d39dff77a2 100644 --- a/internal/layer/writer_factory_test.go +++ b/internal/layer/writer_factory_test.go @@ -1,7 +1,7 @@ package layer_test import ( - "archive/tar" + "archive/tar" //nolint "testing" ilayer "github.com/buildpacks/imgutil/layer" diff --git a/internal/target/parse.go b/internal/target/parse.go index f5ea955892..61a6f4da05 100644 --- a/internal/target/parse.go +++ b/internal/target/parse.go @@ -1,6 +1,7 @@ package target import ( + "fmt" "strings" "github.com/pkg/errors" @@ -66,11 +67,15 @@ func ParseDistro(distroString string, logger logging.Logger) (distro dist.Distri if d[0] == "" || len(d) == 0 { return distro, errors.Errorf("distro's versions %s cannot be specified without distro's name", style.Symbol("@"+strings.Join(d[1:], "@"))) } - if len(d) <= 2 && (strings.Contains(strings.Join(d[1:], ""), "") || d[1] == "") { + distro.Name = d[0] + if len(d) < 2 { logger.Warnf("distro with name %s has no specific version!", style.Symbol(d[0])) + return distro, err } - distro.Name = d[0] - distro.Versions = d[1:] + if len(d) > 2 { + return distro, fmt.Errorf("invalid distro: %s", distroString) + } + distro.Version = d[1] return distro, err } diff --git a/internal/target/parse_test.go b/internal/target/parse_test.go index 030f2c772d..f00c095fb3 100644 --- a/internal/target/parse_test.go +++ b/internal/target/parse_test.go @@ -67,7 +67,7 @@ func testParseTargets(t *testing.T, when spec.G, it spec.S) { h.AssertNotNil(t, err) }) it("should parse targets as expected", func() { - output, err := target.ParseTargets([]string{"linux/arm/v6", "linux/amd64:ubuntu@22.04;debian@8.10@10.06"}, logging.NewLogWithWriters(&outBuf, &outBuf)) + output, err := target.ParseTargets([]string{"linux/arm/v6", "linux/amd64:ubuntu@22.04;debian@8.10;debian@10.06"}, logging.NewLogWithWriters(&outBuf, &outBuf)) h.AssertNil(t, err) h.AssertEq(t, output, []dist.Target{ { @@ -80,12 +80,16 @@ func testParseTargets(t *testing.T, when spec.G, it spec.S) { Arch: "amd64", Distributions: []dist.Distribution{ { - Name: "ubuntu", - Versions: []string{"22.04"}, + Name: "ubuntu", + Version: "22.04", }, { - Name: "debian", - Versions: []string{"8.10", "10.06"}, + Name: "debian", + Version: "8.10", + }, + { + Name: "debian", + Version: "10.06", }, }, }, @@ -94,10 +98,10 @@ func testParseTargets(t *testing.T, when spec.G, it spec.S) { }) when("target#ParseDistro", func() { it("should parse distro as expected", func() { - output, err := target.ParseDistro("ubuntu@22.04@20.08", logging.NewLogWithWriters(&outBuf, &outBuf)) + output, err := target.ParseDistro("ubuntu@22.04", logging.NewLogWithWriters(&outBuf, &outBuf)) h.AssertEq(t, output, dist.Distribution{ - Name: "ubuntu", - Versions: []string{"22.04", "20.08"}, + Name: "ubuntu", + Version: "22.04", }) h.AssertNil(t, err) }) @@ -112,15 +116,23 @@ func testParseTargets(t *testing.T, when spec.G, it spec.S) { }) when("target#ParseDistros", func() { it("should parse distros as expected", func() { - output, err := target.ParseDistros("ubuntu@22.04@20.08;debian@8.10@10.06", logging.NewLogWithWriters(&outBuf, &outBuf)) + output, err := target.ParseDistros("ubuntu@22.04;ubuntu@20.08;debian@8.10;debian@10.06", logging.NewLogWithWriters(&outBuf, &outBuf)) h.AssertEq(t, output, []dist.Distribution{ { - Name: "ubuntu", - Versions: []string{"22.04", "20.08"}, + Name: "ubuntu", + Version: "22.04", + }, + { + Name: "ubuntu", + Version: "20.08", + }, + { + Name: "debian", + Version: "8.10", }, { - Name: "debian", - Versions: []string{"8.10", "10.06"}, + Name: "debian", + Version: "10.06", }, }) h.AssertNil(t, err) diff --git a/pkg/dist/buildmodule.go b/pkg/dist/buildmodule.go index 5126d988e0..ea34cb68ca 100644 --- a/pkg/dist/buildmodule.go +++ b/pkg/dist/buildmodule.go @@ -56,10 +56,10 @@ type Target struct { OS string `json:"os" toml:"os"` Arch string `json:"arch" toml:"arch"` ArchVariant string `json:"variant,omitempty" toml:"variant,omitempty"` - Distributions []Distribution `json:"distributions,omitempty" toml:"distributions,omitempty"` + Distributions []Distribution `json:"distros,omitempty" toml:"distros,omitempty"` } type Distribution struct { - Name string `json:"name,omitempty" toml:"name,omitempty"` - Versions []string `json:"versions,omitempty" toml:"versions,omitempty"` + Name string `json:"name,omitempty" toml:"name,omitempty"` + Version string `json:"version,omitempty" toml:"version,omitempty"` } diff --git a/pkg/dist/buildpack_descriptor.go b/pkg/dist/buildpack_descriptor.go index cf93daa2a2..77ed9028d4 100644 --- a/pkg/dist/buildpack_descriptor.go +++ b/pkg/dist/buildpack_descriptor.go @@ -54,32 +54,25 @@ func (b *BuildpackDescriptor) EnsureStackSupport(stackID string, providedMixins return nil } -func (b *BuildpackDescriptor) EnsureTargetSupport(os, arch, distroName, distroVersion string) error { +func (b *BuildpackDescriptor) EnsureTargetSupport(givenOS, givenArch, givenDistroName, givenDistroVersion string) error { if len(b.Targets()) == 0 { if (!b.WithLinuxBuild && !b.WithWindowsBuild) || len(b.Stacks()) > 0 { // nolint return nil // Order buildpack or stack buildpack, no validation required - } else if b.WithLinuxBuild && os == DefaultTargetOSLinux && arch == DefaultTargetArch { + } else if b.WithLinuxBuild && givenOS == DefaultTargetOSLinux && givenArch == DefaultTargetArch { return nil - } else if b.WithWindowsBuild && os == DefaultTargetOSWindows && arch == DefaultTargetArch { + } else if b.WithWindowsBuild && givenOS == DefaultTargetOSWindows && givenArch == DefaultTargetArch { return nil } } - for _, target := range b.Targets() { - if target.OS == os { - if target.Arch == "" || arch == "" || target.Arch == arch { - if len(target.Distributions) == 0 || distroName == "" || distroVersion == "" { + for _, bpTarget := range b.Targets() { + if bpTarget.OS == givenOS { + if bpTarget.Arch == "" || givenArch == "" || bpTarget.Arch == givenArch { + if len(bpTarget.Distributions) == 0 || givenDistroName == "" || givenDistroVersion == "" { return nil } - for _, distro := range target.Distributions { - if distro.Name == distroName { - if len(distro.Versions) == 0 { - return nil - } - for _, version := range distro.Versions { - if version == distroVersion { - return nil - } - } + for _, bpDistro := range bpTarget.Distributions { + if bpDistro.Name == givenDistroName && bpDistro.Version == givenDistroVersion { + return nil } } } @@ -97,9 +90,9 @@ func (b *BuildpackDescriptor) EnsureTargetSupport(os, arch, distroName, distroVe return fmt.Errorf( "unable to satisfy target os/arch constraints; build image: %s, buildpack %s: %s", toJSONMaybe(target{ - OS: os, - Arch: arch, - Distribution: osDistribution{Name: distroName, Version: distroVersion}, + OS: givenOS, + Arch: givenArch, + Distribution: osDistribution{Name: givenDistroName, Version: givenDistroVersion}, }), style.Symbol(b.Info().FullName()), toJSONMaybe(b.Targets()), diff --git a/pkg/dist/buildpack_descriptor_test.go b/pkg/dist/buildpack_descriptor_test.go index 1f755edb5d..99f2e91124 100644 --- a/pkg/dist/buildpack_descriptor_test.go +++ b/pkg/dist/buildpack_descriptor_test.go @@ -221,12 +221,12 @@ func testBuildpackDescriptor(t *testing.T, when spec.G, it spec.S) { Arch: "fake-arch", Distributions: []dist.Distribution{ { - Name: "fake-distro", - Versions: []string{"0.1"}, + Name: "fake-distro", + Version: "0.1", }, { - Name: "another-distro", - Versions: []string{"0.22"}, + Name: "another-distro", + Version: "0.22", }, }, }}, @@ -247,12 +247,12 @@ func testBuildpackDescriptor(t *testing.T, when spec.G, it spec.S) { Arch: "fake-arch", Distributions: []dist.Distribution{ { - Name: "fake-distro", - Versions: []string{"0.1"}, + Name: "fake-distro", + Version: "0.1", }, { - Name: "another-distro", - Versions: []string{"0.22"}, + Name: "another-distro", + Version: "0.22", }, }, }}, @@ -260,7 +260,7 @@ func testBuildpackDescriptor(t *testing.T, when spec.G, it spec.S) { h.AssertNil(t, bp.EnsureStackSupport("some.stack.id", []string{}, true)) h.AssertError(t, bp.EnsureTargetSupport("some-other-os", "fake-arch", "fake-distro", "0.0"), - `unable to satisfy target os/arch constraints; build image: {"os":"some-other-os","arch":"fake-arch","distribution":{"name":"fake-distro","version":"0.0"}}, buildpack 'some.buildpack.id@some.buildpack.version': [{"os":"fake-os","arch":"fake-arch","distributions":[{"name":"fake-distro","versions":["0.1"]},{"name":"another-distro","versions":["0.22"]}]}]`) + `unable to satisfy target os/arch constraints; build image: {"os":"some-other-os","arch":"fake-arch","distribution":{"name":"fake-distro","version":"0.0"}}, buildpack 'some.buildpack.id@some.buildpack.version': [{"os":"fake-os","arch":"fake-arch","distros":[{"name":"fake-distro","version":"0.1"},{"name":"another-distro","version":"0.22"}]}]`) }) it("succeeds with missing arch", func() { From 557527dec57eae719da3d25bd10a2b25a133084e Mon Sep 17 00:00:00 2001 From: Juan Bustamante Date: Mon, 15 Apr 2024 17:42:07 -0500 Subject: [PATCH 02/18] Removing experimental configuration for extensions starting with API version 0.13 Signed-off-by: Juan Bustamante --- internal/build/lifecycle_execution.go | 20 ++++++---- internal/build/lifecycle_execution_test.go | 44 +++++++++++++++++++++- pkg/client/build.go | 3 -- pkg/client/build_test.go | 39 ++++--------------- 4 files changed, 61 insertions(+), 45 deletions(-) diff --git a/internal/build/lifecycle_execution.go b/internal/build/lifecycle_execution.go index 0f5c9a49a4..4d9c58e4cb 100644 --- a/internal/build/lifecycle_execution.go +++ b/internal/build/lifecycle_execution.go @@ -265,7 +265,7 @@ func (l *LifecycleExecution) Run(ctx context.Context, phaseFactoryCreator PhaseF if l.platformAPI.AtLeast("0.10") && l.hasExtensionsForBuild() { group.Go(func() error { l.logger.Info(style.Step("EXTENDING (BUILD)")) - return l.ExtendBuild(ctx, kanikoCache, phaseFactory) + return l.ExtendBuild(ctx, kanikoCache, phaseFactory, l.extensionsAreExperimental()) }) } else { group.Go(func() error { @@ -277,7 +277,7 @@ func (l *LifecycleExecution) Run(ctx context.Context, phaseFactoryCreator PhaseF if l.platformAPI.AtLeast("0.12") && l.hasExtensionsForRun() { group.Go(func() error { l.logger.Info(style.Step("EXTENDING (RUN)")) - return l.ExtendRun(ctx, kanikoCache, phaseFactory, ephemeralRunImage) + return l.ExtendRun(ctx, kanikoCache, phaseFactory, ephemeralRunImage, l.extensionsAreExperimental()) }) } @@ -424,7 +424,7 @@ func (l *LifecycleExecution) Detect(ctx context.Context, phaseFactory PhaseFacto envOp := NullOp() if l.platformAPI.AtLeast("0.10") && l.hasExtensions() { - envOp = WithEnv("CNB_EXPERIMENTAL_MODE=warn") + envOp = If(l.extensionsAreExperimental(), WithEnv("CNB_EXPERIMENTAL_MODE=warn")) } configProvider := NewPhaseConfigProvider( @@ -453,6 +453,10 @@ func (l *LifecycleExecution) Detect(ctx context.Context, phaseFactory PhaseFacto return detect.Run(ctx) } +func (l *LifecycleExecution) extensionsAreExperimental() bool { + return l.PlatformAPI().AtLeast("0.10") && l.platformAPI.LessThan("0.13") +} + func (l *LifecycleExecution) Restore(ctx context.Context, buildCache Cache, kanikoCache Cache, phaseFactory PhaseFactory) error { // build up flags and ops var flags []string @@ -709,7 +713,7 @@ func (l *LifecycleExecution) Build(ctx context.Context, phaseFactory PhaseFactor return build.Run(ctx) } -func (l *LifecycleExecution) ExtendBuild(ctx context.Context, kanikoCache Cache, phaseFactory PhaseFactory) error { +func (l *LifecycleExecution) ExtendBuild(ctx context.Context, kanikoCache Cache, phaseFactory PhaseFactory, experimental bool) error { flags := []string{"-app", l.mountPaths.appDir()} configProvider := NewPhaseConfigProvider( @@ -718,7 +722,7 @@ func (l *LifecycleExecution) ExtendBuild(ctx context.Context, kanikoCache Cache, WithLogPrefix("extender (build)"), WithArgs(l.withLogLevel()...), WithBinds(l.opts.Volumes...), - WithEnv("CNB_EXPERIMENTAL_MODE=warn"), + If(experimental, WithEnv("CNB_EXPERIMENTAL_MODE=warn")), WithFlags(flags...), WithNetwork(l.opts.Network), WithRoot(), @@ -730,7 +734,7 @@ func (l *LifecycleExecution) ExtendBuild(ctx context.Context, kanikoCache Cache, return extend.Run(ctx) } -func (l *LifecycleExecution) ExtendRun(ctx context.Context, kanikoCache Cache, phaseFactory PhaseFactory, runImageName string) error { +func (l *LifecycleExecution) ExtendRun(ctx context.Context, kanikoCache Cache, phaseFactory PhaseFactory, runImageName string, experimental bool) error { flags := []string{"-app", l.mountPaths.appDir(), "-kind", "run"} configProvider := NewPhaseConfigProvider( @@ -739,7 +743,7 @@ func (l *LifecycleExecution) ExtendRun(ctx context.Context, kanikoCache Cache, p WithLogPrefix("extender (run)"), WithArgs(l.withLogLevel()...), WithBinds(l.opts.Volumes...), - WithEnv("CNB_EXPERIMENTAL_MODE=warn"), + If(experimental, WithEnv("CNB_EXPERIMENTAL_MODE=warn")), WithFlags(flags...), WithNetwork(l.opts.Network), WithRoot(), @@ -775,7 +779,7 @@ func (l *LifecycleExecution) Export(ctx context.Context, buildCache, launchCache } else { flags = append(flags, "-run", l.mountPaths.runPath()) if l.hasExtensionsForRun() { - expEnv = WithEnv("CNB_EXPERIMENTAL_MODE=warn") + expEnv = If(l.extensionsAreExperimental(), WithEnv("CNB_EXPERIMENTAL_MODE=warn")) kanikoCacheBindOp = WithBinds(fmt.Sprintf("%s:%s", kanikoCache.Name(), l.mountPaths.kanikoCacheDir())) } } diff --git a/internal/build/lifecycle_execution_test.go b/internal/build/lifecycle_execution_test.go index ed12a2e5b1..f8f21eec77 100644 --- a/internal/build/lifecycle_execution_test.go +++ b/internal/build/lifecycle_execution_test.go @@ -2024,8 +2024,10 @@ func testLifecycleExecution(t *testing.T, when spec.G, it spec.S) { }) when("#ExtendBuild", func() { + var experimental bool it.Before(func() { - err := lifecycle.ExtendBuild(context.Background(), fakeKanikoCache, fakePhaseFactory) + experimental = true + err := lifecycle.ExtendBuild(context.Background(), fakeKanikoCache, fakePhaseFactory, experimental) h.AssertNil(t, err) lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 @@ -2063,11 +2065,31 @@ func testLifecycleExecution(t *testing.T, when spec.G, it spec.S) { it("configures the phase with root", func() { h.AssertEq(t, configProvider.ContainerConfig().User, "root") }) + + when("experimental is false", func() { + it.Before(func() { + experimental = false + err := lifecycle.ExtendBuild(context.Background(), fakeKanikoCache, fakePhaseFactory, experimental) + h.AssertNil(t, err) + + lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 + h.AssertNotEq(t, lastCallIndex, -1) + + configProvider = fakePhaseFactory.NewCalledWithProvider[lastCallIndex] + h.AssertEq(t, configProvider.Name(), "extender") + }) + + it("CNB_EXPERIMENTAL_MODE=warn is not enable in the environment", func() { + h.AssertSliceNotContains(t, configProvider.ContainerConfig().Env, "CNB_EXPERIMENTAL_MODE=warn") + }) + }) }) when("#ExtendRun", func() { + var experimental bool it.Before(func() { - err := lifecycle.ExtendRun(context.Background(), fakeKanikoCache, fakePhaseFactory, "some-run-image") + experimental = true + err := lifecycle.ExtendRun(context.Background(), fakeKanikoCache, fakePhaseFactory, "some-run-image", experimental) h.AssertNil(t, err) lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 @@ -2111,6 +2133,24 @@ func testLifecycleExecution(t *testing.T, when spec.G, it spec.S) { it("configures the phase with root", func() { h.AssertEq(t, configProvider.ContainerConfig().User, "root") }) + + when("experimental is false", func() { + it.Before(func() { + experimental = false + err := lifecycle.ExtendRun(context.Background(), fakeKanikoCache, fakePhaseFactory, "some-run-image", experimental) + h.AssertNil(t, err) + + lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 + h.AssertNotEq(t, lastCallIndex, -1) + + configProvider = fakePhaseFactory.NewCalledWithProvider[lastCallIndex] + h.AssertEq(t, configProvider.Name(), "extender") + }) + + it("CNB_EXPERIMENTAL_MODE=warn is not enable in the environment", func() { + h.AssertSliceNotContains(t, configProvider.ContainerConfig().Env, "CNB_EXPERIMENTAL_MODE=warn") + }) + }) }) when("#Export", func() { diff --git a/pkg/client/build.go b/pkg/client/build.go index 670f53f2c8..6cdc58fb8b 100644 --- a/pkg/client/build.go +++ b/pkg/client/build.go @@ -467,9 +467,6 @@ func (c *Client) Build(ctx context.Context, opts BuildOptions) error { defer c.docker.ImageRemove(context.Background(), ephemeralBuilder.Name(), types.ImageRemoveOptions{Force: true}) if len(bldr.OrderExtensions()) > 0 || len(ephemeralBuilder.OrderExtensions()) > 0 { - if !c.experimental { - return fmt.Errorf("experimental features must be enabled when builder contains image extensions") - } if builderOS == "windows" { return fmt.Errorf("builder contains image extensions which are not supported for Windows builds") } diff --git a/pkg/client/build_test.go b/pkg/client/build_test.go index 27cd02d236..35ae06739d 100644 --- a/pkg/client/build_test.go +++ b/pkg/client/build_test.go @@ -3013,40 +3013,19 @@ api = "0.2" when("there are extensions", func() { withExtensionsLabel = true - when("experimental", func() { - when("false", func() { - it("errors", func() { - err := subject.Build(context.TODO(), BuildOptions{ - Image: "some/app", - Builder: defaultBuilderName, - }) - - h.AssertNotNil(t, err) - }) - }) - - when("true", func() { - it.Before(func() { - subject.experimental = true + when("default configuration", func() { + it("succeeds", func() { + err := subject.Build(context.TODO(), BuildOptions{ + Image: "some/app", + Builder: defaultBuilderName, }) - it("succeeds", func() { - err := subject.Build(context.TODO(), BuildOptions{ - Image: "some/app", - Builder: defaultBuilderName, - }) - - h.AssertNil(t, err) - h.AssertEq(t, fakeLifecycle.Opts.BuilderImage, defaultBuilderName) - }) + h.AssertNil(t, err) + h.AssertEq(t, fakeLifecycle.Opts.BuilderImage, defaultBuilderName) }) }) when("os", func() { - it.Before(func() { - subject.experimental = true - }) - when("windows", func() { it.Before(func() { h.SkipIf(t, runtime.GOOS != "windows", "Skipped on non-windows") @@ -3076,10 +3055,6 @@ api = "0.2" }) when("pull policy", func() { - it.Before(func() { - subject.experimental = true - }) - when("always", func() { it("succeeds", func() { err := subject.Build(context.TODO(), BuildOptions{ From 52adfe6eb9058db8cdbea140fde5de2046f21b4a Mon Sep 17 00:00:00 2001 From: Ozzy Osborne Date: Wed, 17 Apr 2024 14:24:17 -0400 Subject: [PATCH 03/18] add ephemeral lifecycle image Signed-off-by: Ozzy Osborne --- acceptance/acceptance_test.go | 17 ++- acceptance/assertions/lifecycle_output.go | 7 +- pkg/client/build.go | 136 +++++++++++++++++++++- pkg/client/build_test.go | 15 ++- 4 files changed, 163 insertions(+), 12 deletions(-) diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go index 6b030cb04c..8cb0e5551a 100644 --- a/acceptance/acceptance_test.go +++ b/acceptance/acceptance_test.go @@ -836,6 +836,8 @@ func testAcceptance( when("builder is untrusted", func() { it("uses the 5 phases, and runs the extender (build)", func() { + origLifecycle := lifecycle.Image() + output := pack.RunSuccessfully( "build", repoName, "-p", filepath.Join("testdata", "mock_app"), @@ -846,7 +848,7 @@ func testAcceptance( assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) assertOutput := assertions.NewLifecycleOutputAssertionManager(t, output) - assertOutput.IncludesLifecycleImageTag(lifecycle.Image()) + assertOutput.IncludesLifecycleImageTag(origLifecycle) assertOutput.IncludesSeparatePhasesWithBuildExtension() t.Log("inspecting image") @@ -886,6 +888,8 @@ func testAcceptance( }) it("uses the 5 phases, and runs the extender (run)", func() { + origLifecycle := lifecycle.Image() + output := pack.RunSuccessfully( "build", repoName, "-p", filepath.Join("testdata", "mock_app"), @@ -897,7 +901,8 @@ func testAcceptance( assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) assertOutput := assertions.NewLifecycleOutputAssertionManager(t, output) - assertOutput.IncludesLifecycleImageTag(lifecycle.Image()) + + assertOutput.IncludesLifecycleImageTag(origLifecycle) assertOutput.IncludesSeparatePhasesWithRunExtension() t.Log("inspecting image") @@ -977,6 +982,8 @@ func testAcceptance( when("daemon", func() { it("uses the 5 phases", func() { + origLifecycle := lifecycle.Image() + output := pack.RunSuccessfully( "build", repoName, "-p", filepath.Join("testdata", "mock_app"), @@ -986,13 +993,15 @@ func testAcceptance( assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) assertOutput := assertions.NewLifecycleOutputAssertionManager(t, output) - assertOutput.IncludesLifecycleImageTag(lifecycle.Image()) + assertOutput.IncludesLifecycleImageTag(origLifecycle) assertOutput.IncludesSeparatePhases() }) }) when("--publish", func() { it("uses the 5 phases", func() { + origLifecycle := lifecycle.Image() + buildArgs := []string{ repoName, "-p", filepath.Join("testdata", "mock_app"), @@ -1008,7 +1017,7 @@ func testAcceptance( assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) assertOutput := assertions.NewLifecycleOutputAssertionManager(t, output) - assertOutput.IncludesLifecycleImageTag(lifecycle.Image()) + assertOutput.IncludesLifecycleImageTag(origLifecycle) assertOutput.IncludesSeparatePhases() }) }) diff --git a/acceptance/assertions/lifecycle_output.go b/acceptance/assertions/lifecycle_output.go index 7cc57401c9..8b0b182184 100644 --- a/acceptance/assertions/lifecycle_output.go +++ b/acceptance/assertions/lifecycle_output.go @@ -6,6 +6,7 @@ package assertions import ( "fmt" "regexp" + "strings" "testing" h "github.com/buildpacks/pack/testhelpers" @@ -88,5 +89,9 @@ func (l LifecycleOutputAssertionManager) IncludesSeparatePhasesWithRunExtension( func (l LifecycleOutputAssertionManager) IncludesLifecycleImageTag(tag string) { l.testObject.Helper() - l.assert.Contains(l.output, tag) + if !strings.Contains(l.output, tag) { + if !strings.Contains(l.output, "pack.local/lifecyle") { + l.testObject.Fatalf("Unable to locate reference to lifecycle image within output") + } + } } diff --git a/pkg/client/build.go b/pkg/client/build.go index 670f53f2c8..add893eefa 100644 --- a/pkg/client/build.go +++ b/pkg/client/build.go @@ -13,6 +13,7 @@ import ( "path/filepath" "runtime" "sort" + "strconv" "strings" "time" @@ -32,6 +33,7 @@ import ( "github.com/buildpacks/pack/internal/build" "github.com/buildpacks/pack/internal/builder" internalConfig "github.com/buildpacks/pack/internal/config" + "github.com/buildpacks/pack/internal/layer" pname "github.com/buildpacks/pack/internal/name" "github.com/buildpacks/pack/internal/paths" "github.com/buildpacks/pack/internal/stack" @@ -425,6 +427,29 @@ func (c *Client) Build(ctx context.Context, opts BuildOptions) error { return fmt.Errorf("fetching lifecycle image: %w", err) } + // if lifecyle container os isn't windows, use ephemeral lifecycle to add /workspace with correct ownership + imageOS, err := lifecycleImage.OS() + if err != nil { + return errors.Wrap(err, "getting lifecycle image OS") + } + if imageOS != "windows" { + // obtain uid/gid from builder to use when extending lifecycle image + uid, gid, err := userAndGroupIDs(rawBuilderImage) + if err != nil { + return fmt.Errorf("obtaining build uid/gid from builder image: %w", err) + } + + c.logger.Debugf("Creating ephemeral lifecycle from %s with uid %d and gid %d. With workspace dir %s", lifecycleImage.Name(), uid, gid, opts.Workspace) + // extend lifecycle image with mountpoints, and use it instead of current lifecycle image + lifecycleImage, err = c.createEphemeralLifecycle(lifecycleImage, opts.Workspace, uid, gid) + if err != nil { + return err + } + c.logger.Debugf("Selecting ephemeral lifecycle image %s for build", lifecycleImage.Name()) + // cleanup the extended lifecycle image when done + defer c.docker.ImageRemove(context.Background(), lifecycleImage.Name(), types.ImageRemoveOptions{Force: true}) + } + lifecycleOptsLifecycleImage = lifecycleImage.Name() labels, err := lifecycleImage.Labels() if err != nil { @@ -639,7 +664,13 @@ func (c *Client) Build(ctx context.Context, opts BuildOptions) error { if len(manifestContents) < 1 { return "", errors.New("missing manifest entries") } - return manifestContents[0].Layers[len(manifestContents[0].Layers)-1], nil // we can assume the lifecycle layer is the last in the tar + // we can assume the lifecycle layer is the last in the tar, except if the lifecycle has been extended as an ephemeral lifecycle + layerOffset := 1 + if strings.Contains(lifecycleOpts.LifecycleImage, "pack.local/lifecycle") { + layerOffset = 2 + } + + return manifestContents[0].Layers[len(manifestContents[0].Layers)-layerOffset], nil }() if err != nil { return "", err @@ -1320,6 +1351,109 @@ func (c *Client) processExtensions(ctx context.Context, builderImage imgutil.Ima return fetchedExs, orderExtensions, nil } +func userAndGroupIDs(img imgutil.Image) (int, int, error) { + sUID, err := img.Env(builder.EnvUID) + if err != nil { + return 0, 0, errors.Wrap(err, "reading builder env variables") + } else if sUID == "" { + return 0, 0, fmt.Errorf("image %s missing required env var %s", style.Symbol(img.Name()), style.Symbol(builder.EnvUID)) + } + + sGID, err := img.Env(builder.EnvGID) + if err != nil { + return 0, 0, errors.Wrap(err, "reading builder env variables") + } else if sGID == "" { + return 0, 0, fmt.Errorf("image %s missing required env var %s", style.Symbol(img.Name()), style.Symbol(builder.EnvGID)) + } + + var uid, gid int + uid, err = strconv.Atoi(sUID) + if err != nil { + return 0, 0, fmt.Errorf("failed to parse %s, value %s should be an integer", style.Symbol(builder.EnvUID), style.Symbol(sUID)) + } + + gid, err = strconv.Atoi(sGID) + if err != nil { + return 0, 0, fmt.Errorf("failed to parse %s, value %s should be an integer", style.Symbol(builder.EnvGID), style.Symbol(sGID)) + } + + return uid, gid, nil +} + +func workspacePathForOS(os, workspace string) string { + if workspace == "" { + workspace = "workspace" + } + if os == "windows" { + // note we don't use ephemeral lifecycle when os is windows.. + return "c:\\" + workspace + } + return "/" + workspace +} + +func (c *Client) addUserMountpoints(lifecycleImage imgutil.Image, dest string, workspace string, uid int, gid int) (string, error) { + // today only workspace needs to be added, easy to add future dirs if required. + + imageOS, err := lifecycleImage.OS() + if err != nil { + return "", errors.Wrap(err, "getting image OS") + } + layerWriterFactory, err := layer.NewWriterFactory(imageOS) + if err != nil { + return "", err + } + + workspace = workspacePathForOS(imageOS, workspace) + + fh, err := os.Create(filepath.Join(dest, "dirs.tar")) + if err != nil { + return "", err + } + defer fh.Close() + + lw := layerWriterFactory.NewWriter(fh) + defer lw.Close() + + for _, path := range []string{workspace} { + if err := lw.WriteHeader(&tar.Header{ + Typeflag: tar.TypeDir, + Name: path, + Mode: 0755, + ModTime: archive.NormalizedDateTime, + Uid: uid, + Gid: gid, + }); err != nil { + return "", errors.Wrapf(err, "creating %s mountpoint dir in layer", style.Symbol(path)) + } + } + + return fh.Name(), nil +} + +func (c *Client) createEphemeralLifecycle(lifecycleImage imgutil.Image, workspace string, uid int, gid int) (imgutil.Image, error) { + lifecycleImage.Rename(fmt.Sprintf("pack.local/lifecycle/%x:latest", randString(10))) + + tmpDir, err := os.MkdirTemp("", "create-lifecycle-scratch") + if err != nil { + return nil, err + } + defer os.RemoveAll(tmpDir) + dirsTar, err := c.addUserMountpoints(lifecycleImage, tmpDir, workspace, uid, gid) + if err != nil { + return nil, err + } + if err := lifecycleImage.AddLayer(dirsTar); err != nil { + return nil, errors.Wrap(err, "adding mountpoint dirs layer") + } + + err = lifecycleImage.Save() + if err != nil { + return nil, err + } + + return lifecycleImage, nil +} + func (c *Client) createEphemeralBuilder( rawBuilderImage imgutil.Image, env map[string]string, diff --git a/pkg/client/build_test.go b/pkg/client/build_test.go index 27cd02d236..f1eff2a4f7 100644 --- a/pkg/client/build_test.go +++ b/pkg/client/build_test.go @@ -2101,6 +2101,8 @@ api = "0.2" when("builder is untrusted", func() { when("lifecycle image is available", func() { it("uses the 5 phases with the lifecycle image", func() { + origLifecyleName := fakeLifecycleImage.Name() + h.AssertNil(t, subject.Build(context.TODO(), BuildOptions{ Image: "some/app", Builder: defaultBuilderName, @@ -2108,9 +2110,9 @@ api = "0.2" TrustBuilder: func(string) bool { return false }, })) h.AssertEq(t, fakeLifecycle.Opts.UseCreator, false) - h.AssertEq(t, fakeLifecycle.Opts.LifecycleImage, fakeLifecycleImage.Name()) - - args := fakeImageFetcher.FetchCalls[fakeLifecycleImage.Name()] + h.AssertContains(t, fakeLifecycle.Opts.LifecycleImage, "pack.local/lifecycle") + args := fakeImageFetcher.FetchCalls[origLifecyleName] + h.AssertNotNil(t, args) h.AssertEq(t, args.Daemon, true) h.AssertEq(t, args.PullPolicy, image.PullAlways) h.AssertEq(t, args.Platform, "linux/amd64") @@ -2199,6 +2201,7 @@ api = "0.2" when("builder is untrusted", func() { when("lifecycle image is available", func() { it("uses the 5 phases with the lifecycle image", func() { + origLifecyleName := fakeLifecycleImage.Name() h.AssertNil(t, subject.Build(context.TODO(), BuildOptions{ Image: "some/app", Builder: defaultBuilderName, @@ -2206,9 +2209,9 @@ api = "0.2" TrustBuilder: func(string) bool { return false }, })) h.AssertEq(t, fakeLifecycle.Opts.UseCreator, false) - h.AssertEq(t, fakeLifecycle.Opts.LifecycleImage, fakeLifecycleImage.Name()) - - args := fakeImageFetcher.FetchCalls[fakeLifecycleImage.Name()] + h.AssertContains(t, fakeLifecycle.Opts.LifecycleImage, "pack.local/lifecycle") + args := fakeImageFetcher.FetchCalls[origLifecyleName] + h.AssertNotNil(t, args) h.AssertEq(t, args.Daemon, true) h.AssertEq(t, args.PullPolicy, image.PullAlways) h.AssertEq(t, args.Platform, "linux/amd64") From b9cccb713e19b2adc28eb9905be46db9f23f1f24 Mon Sep 17 00:00:00 2001 From: Natalie Arellano Date: Fri, 19 Apr 2024 15:04:33 -0400 Subject: [PATCH 04/18] Add warning when we detect wrong things in buildpack.toml or extension.toml Signed-off-by: Natalie Arellano --- pkg/buildpack/buildpack.go | 25 ++- pkg/buildpack/buildpack_test.go | 252 +++++++++++---------------- pkg/buildpack/downloader.go | 8 +- pkg/client/create_builder_test.go | 28 +-- pkg/client/package_buildpack.go | 2 +- pkg/client/package_buildpack_test.go | 8 +- pkg/client/package_extension.go | 2 +- 7 files changed, 145 insertions(+), 180 deletions(-) diff --git a/pkg/buildpack/buildpack.go b/pkg/buildpack/buildpack.go index e658c53e51..9c8e115451 100644 --- a/pkg/buildpack/buildpack.go +++ b/pkg/buildpack/buildpack.go @@ -71,12 +71,16 @@ func FromBlob(descriptor Descriptor, blob Blob) BuildModule { // FromBuildpackRootBlob constructs a buildpack from a blob. It is assumed that the buildpack contents reside at the // root of the blob. The constructed buildpack contents will be structured as per the distribution spec (currently // a tar with contents under '/cnb/buildpacks/{ID}/{version}/*'). -func FromBuildpackRootBlob(blob Blob, layerWriterFactory archive.TarWriterFactory) (BuildModule, error) { +func FromBuildpackRootBlob(blob Blob, layerWriterFactory archive.TarWriterFactory, logger Logger) (BuildModule, error) { descriptor := dist.BuildpackDescriptor{} descriptor.WithAPI = api.MustParse(dist.AssumedBuildpackAPIVersion) - if err := readDescriptor(KindBuildpack, &descriptor, blob); err != nil { + var undecodedKeys []string + if err := readDescriptor(KindBuildpack, &descriptor, blob, undecodedKeys); err != nil { return nil, err } + if len(undecodedKeys) > 0 { + logger.Warnf("Ignoring unexpected key(s) in buildpack descriptor: %s", strings.Join(undecodedKeys, ",")) + } if err := detectPlatformSpecificValues(&descriptor, blob); err != nil { return nil, err } @@ -89,19 +93,23 @@ func FromBuildpackRootBlob(blob Blob, layerWriterFactory archive.TarWriterFactor // FromExtensionRootBlob constructs an extension from a blob. It is assumed that the extension contents reside at the // root of the blob. The constructed extension contents will be structured as per the distribution spec (currently // a tar with contents under '/cnb/extensions/{ID}/{version}/*'). -func FromExtensionRootBlob(blob Blob, layerWriterFactory archive.TarWriterFactory) (BuildModule, error) { +func FromExtensionRootBlob(blob Blob, layerWriterFactory archive.TarWriterFactory, logger Logger) (BuildModule, error) { descriptor := dist.ExtensionDescriptor{} descriptor.WithAPI = api.MustParse(dist.AssumedBuildpackAPIVersion) - if err := readDescriptor(KindExtension, &descriptor, blob); err != nil { + var undecodedKeys []string + if err := readDescriptor(KindExtension, &descriptor, blob, undecodedKeys); err != nil { return nil, err } + if len(undecodedKeys) > 0 { + logger.Warnf("Ignoring unexpected key(s) in extension descriptor: %s", strings.Join(undecodedKeys, ",")) + } if err := validateExtensionDescriptor(descriptor); err != nil { return nil, err } return buildpackFrom(&descriptor, blob, layerWriterFactory) } -func readDescriptor(kind string, descriptor interface{}, blob Blob) error { +func readDescriptor(kind string, descriptor interface{}, blob Blob, undecoded []string) error { rc, err := blob.Open() if err != nil { return errors.Wrapf(err, "open %s", kind) @@ -115,11 +123,16 @@ func readDescriptor(kind string, descriptor interface{}, blob Blob) error { return errors.Wrapf(err, "reading %s", descriptorFile) } - _, err = toml.Decode(string(buf), descriptor) + md, err := toml.Decode(string(buf), descriptor) if err != nil { return errors.Wrapf(err, "decoding %s", descriptorFile) } + undecodedKeys := md.Undecoded() + for _, k := range undecodedKeys { + undecoded = append(undecoded, k.String()) + } + return nil } diff --git a/pkg/buildpack/buildpack_test.go b/pkg/buildpack/buildpack_test.go index 4536a5e79e..b44bbc94e9 100644 --- a/pkg/buildpack/buildpack_test.go +++ b/pkg/buildpack/buildpack_test.go @@ -54,11 +54,10 @@ func testBuildpack(t *testing.T, when spec.G, it spec.S) { when("#BuildpackFromRootBlob", func() { it("parses the descriptor file", func() { - bp, err := buildpack.FromBuildpackRootBlob( - &readerBlob{ - openFn: func() io.ReadCloser { - tarBuilder := archive.TarBuilder{} - tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(` + bp, err := buildpack.FromBuildpackRootBlob(&readerBlob{ + openFn: func() io.ReadCloser { + tarBuilder := archive.TarBuilder{} + tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(` api = "0.3" [buildpack] @@ -69,11 +68,9 @@ homepage = "http://geocities.com/cool-bp" [[stacks]] id = "some.stack.id" `)) - return tarBuilder.Reader(archive.DefaultTarWriterFactory()) - }, + return tarBuilder.Reader(archive.DefaultTarWriterFactory()) }, - archive.DefaultTarWriterFactory(), - ) + }, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) h.AssertEq(t, bp.Descriptor().API().String(), "0.3") @@ -84,11 +81,10 @@ id = "some.stack.id" }) it("translates blob to distribution format", func() { - bp, err := buildpack.FromBuildpackRootBlob( - &readerBlob{ - openFn: func() io.ReadCloser { - tarBuilder := archive.TarBuilder{} - tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(` + bp, err := buildpack.FromBuildpackRootBlob(&readerBlob{ + openFn: func() io.ReadCloser { + tarBuilder := archive.TarBuilder{} + tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(` api = "0.3" [buildpack] @@ -99,14 +95,12 @@ version = "1.2.3" id = "some.stack.id" `)) - tarBuilder.AddDir("bin", 0700, time.Now()) - tarBuilder.AddFile("bin/detect", 0700, time.Now(), []byte("detect-contents")) - tarBuilder.AddFile("bin/build", 0700, time.Now(), []byte("build-contents")) - return tarBuilder.Reader(archive.DefaultTarWriterFactory()) - }, + tarBuilder.AddDir("bin", 0700, time.Now()) + tarBuilder.AddFile("bin/detect", 0700, time.Now(), []byte("detect-contents")) + tarBuilder.AddFile("bin/build", 0700, time.Now(), []byte("build-contents")) + return tarBuilder.Reader(archive.DefaultTarWriterFactory()) }, - archive.DefaultTarWriterFactory(), - ) + }, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) h.AssertNil(t, bp.Descriptor().EnsureTargetSupport(dist.DefaultTargetOSLinux, dist.DefaultTargetArch, "", "")) @@ -151,11 +145,10 @@ id = "some.stack.id" }) it("translates blob to windows bat distribution format", func() { - bp, err := buildpack.FromBuildpackRootBlob( - &readerBlob{ - openFn: func() io.ReadCloser { - tarBuilder := archive.TarBuilder{} - tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(` + bp, err := buildpack.FromBuildpackRootBlob(&readerBlob{ + openFn: func() io.ReadCloser { + tarBuilder := archive.TarBuilder{} + tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(` api = "0.9" [buildpack] @@ -163,14 +156,12 @@ id = "bp.one" version = "1.2.3" `)) - tarBuilder.AddDir("bin", 0700, time.Now()) - tarBuilder.AddFile("bin/detect", 0700, time.Now(), []byte("detect-contents")) - tarBuilder.AddFile("bin/build.bat", 0700, time.Now(), []byte("build-contents")) - return tarBuilder.Reader(archive.DefaultTarWriterFactory()) - }, + tarBuilder.AddDir("bin", 0700, time.Now()) + tarBuilder.AddFile("bin/detect", 0700, time.Now(), []byte("detect-contents")) + tarBuilder.AddFile("bin/build.bat", 0700, time.Now(), []byte("build-contents")) + return tarBuilder.Reader(archive.DefaultTarWriterFactory()) }, - archive.DefaultTarWriterFactory(), - ) + }, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) bpDescriptor := bp.Descriptor().(*dist.BuildpackDescriptor) @@ -189,11 +180,10 @@ version = "1.2.3" }) it("translates blob to windows exe distribution format", func() { - bp, err := buildpack.FromBuildpackRootBlob( - &readerBlob{ - openFn: func() io.ReadCloser { - tarBuilder := archive.TarBuilder{} - tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(` + bp, err := buildpack.FromBuildpackRootBlob(&readerBlob{ + openFn: func() io.ReadCloser { + tarBuilder := archive.TarBuilder{} + tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(` api = "0.3" [buildpack] @@ -201,14 +191,12 @@ id = "bp.one" version = "1.2.3" `)) - tarBuilder.AddDir("bin", 0700, time.Now()) - tarBuilder.AddFile("bin/detect", 0700, time.Now(), []byte("detect-contents")) - tarBuilder.AddFile("bin/build.exe", 0700, time.Now(), []byte("build-contents")) - return tarBuilder.Reader(archive.DefaultTarWriterFactory()) - }, + tarBuilder.AddDir("bin", 0700, time.Now()) + tarBuilder.AddFile("bin/detect", 0700, time.Now(), []byte("detect-contents")) + tarBuilder.AddFile("bin/build.exe", 0700, time.Now(), []byte("build-contents")) + return tarBuilder.Reader(archive.DefaultTarWriterFactory()) }, - archive.DefaultTarWriterFactory(), - ) + }, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) bpDescriptor := bp.Descriptor().(*dist.BuildpackDescriptor) @@ -244,13 +232,10 @@ id = "some.stack.id" }, } - bp, err := buildpack.FromBuildpackRootBlob( - &errorBlob{ - realBlob: realBlob, - limit: 4, - }, - archive.DefaultTarWriterFactory(), - ) + bp, err := buildpack.FromBuildpackRootBlob(&errorBlob{ + realBlob: realBlob, + limit: 4, + }, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) bpReader, err := bp.Open() @@ -274,17 +259,14 @@ id = "some.stack.id" when("no exec bits set", func() { it("sets to 0755 if directory", func() { - bp, err := buildpack.FromBuildpackRootBlob( - &readerBlob{ - openFn: func() io.ReadCloser { - tarBuilder := archive.TarBuilder{} - tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(bpTOMLData)) - tarBuilder.AddDir("some-dir", 0600, time.Now()) - return tarBuilder.Reader(archive.DefaultTarWriterFactory()) - }, + bp, err := buildpack.FromBuildpackRootBlob(&readerBlob{ + openFn: func() io.ReadCloser { + tarBuilder := archive.TarBuilder{} + tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(bpTOMLData)) + tarBuilder.AddDir("some-dir", 0600, time.Now()) + return tarBuilder.Reader(archive.DefaultTarWriterFactory()) }, - archive.DefaultTarWriterFactory(), - ) + }, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) tarPath := writeBlobToFile(bp) @@ -299,18 +281,15 @@ id = "some.stack.id" when("no exec bits set", func() { it("sets to 0755 if 'bin/detect' or 'bin/build'", func() { - bp, err := buildpack.FromBuildpackRootBlob( - &readerBlob{ - openFn: func() io.ReadCloser { - tarBuilder := archive.TarBuilder{} - tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(bpTOMLData)) - tarBuilder.AddFile("bin/detect", 0600, time.Now(), []byte("detect-contents")) - tarBuilder.AddFile("bin/build", 0600, time.Now(), []byte("build-contents")) - return tarBuilder.Reader(archive.DefaultTarWriterFactory()) - }, + bp, err := buildpack.FromBuildpackRootBlob(&readerBlob{ + openFn: func() io.ReadCloser { + tarBuilder := archive.TarBuilder{} + tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(bpTOMLData)) + tarBuilder.AddFile("bin/detect", 0600, time.Now(), []byte("detect-contents")) + tarBuilder.AddFile("bin/build", 0600, time.Now(), []byte("build-contents")) + return tarBuilder.Reader(archive.DefaultTarWriterFactory()) }, - archive.DefaultTarWriterFactory(), - ) + }, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) bpDescriptor := bp.Descriptor().(*dist.BuildpackDescriptor) @@ -334,17 +313,14 @@ id = "some.stack.id" when("not directory, 'bin/detect', or 'bin/build'", func() { it("sets to 0755 if ANY exec bit is set", func() { - bp, err := buildpack.FromBuildpackRootBlob( - &readerBlob{ - openFn: func() io.ReadCloser { - tarBuilder := archive.TarBuilder{} - tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(bpTOMLData)) - tarBuilder.AddFile("some-file", 0700, time.Now(), []byte("some-data")) - return tarBuilder.Reader(archive.DefaultTarWriterFactory()) - }, + bp, err := buildpack.FromBuildpackRootBlob(&readerBlob{ + openFn: func() io.ReadCloser { + tarBuilder := archive.TarBuilder{} + tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(bpTOMLData)) + tarBuilder.AddFile("some-file", 0700, time.Now(), []byte("some-data")) + return tarBuilder.Reader(archive.DefaultTarWriterFactory()) }, - archive.DefaultTarWriterFactory(), - ) + }, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) tarPath := writeBlobToFile(bp) @@ -359,17 +335,14 @@ id = "some.stack.id" when("not directory, 'bin/detect', or 'bin/build'", func() { it("sets to 0644 if NO exec bits set", func() { - bp, err := buildpack.FromBuildpackRootBlob( - &readerBlob{ - openFn: func() io.ReadCloser { - tarBuilder := archive.TarBuilder{} - tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(bpTOMLData)) - tarBuilder.AddFile("some-file", 0600, time.Now(), []byte("some-data")) - return tarBuilder.Reader(archive.DefaultTarWriterFactory()) - }, + bp, err := buildpack.FromBuildpackRootBlob(&readerBlob{ + openFn: func() io.ReadCloser { + tarBuilder := archive.TarBuilder{} + tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(bpTOMLData)) + tarBuilder.AddFile("some-file", 0600, time.Now(), []byte("some-data")) + return tarBuilder.Reader(archive.DefaultTarWriterFactory()) }, - archive.DefaultTarWriterFactory(), - ) + }, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) tarPath := writeBlobToFile(bp) @@ -385,37 +358,31 @@ id = "some.stack.id" when("there is no descriptor file", func() { it("returns error", func() { - _, err := buildpack.FromBuildpackRootBlob( - &readerBlob{ - openFn: func() io.ReadCloser { - tarBuilder := archive.TarBuilder{} - return tarBuilder.Reader(archive.DefaultTarWriterFactory()) - }, + _, err := buildpack.FromBuildpackRootBlob(&readerBlob{ + openFn: func() io.ReadCloser { + tarBuilder := archive.TarBuilder{} + return tarBuilder.Reader(archive.DefaultTarWriterFactory()) }, - archive.DefaultTarWriterFactory(), - ) + }, archive.DefaultTarWriterFactory(), nil) h.AssertError(t, err, "could not find entry path 'buildpack.toml'") }) }) when("there is no api field", func() { it("assumes an api version", func() { - bp, err := buildpack.FromBuildpackRootBlob( - &readerBlob{ - openFn: func() io.ReadCloser { - tarBuilder := archive.TarBuilder{} - tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(` + bp, err := buildpack.FromBuildpackRootBlob(&readerBlob{ + openFn: func() io.ReadCloser { + tarBuilder := archive.TarBuilder{} + tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(` [buildpack] id = "bp.one" version = "1.2.3" [[stacks]] id = "some.stack.id"`)) - return tarBuilder.Reader(archive.DefaultTarWriterFactory()) - }, + return tarBuilder.Reader(archive.DefaultTarWriterFactory()) }, - archive.DefaultTarWriterFactory(), - ) + }, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) h.AssertEq(t, bp.Descriptor().API().String(), "0.1") }) @@ -423,55 +390,48 @@ id = "some.stack.id"`)) when("there is no id", func() { it("returns error", func() { - _, err := buildpack.FromBuildpackRootBlob( - &readerBlob{ - openFn: func() io.ReadCloser { - tarBuilder := archive.TarBuilder{} - tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(` + _, err := buildpack.FromBuildpackRootBlob(&readerBlob{ + openFn: func() io.ReadCloser { + tarBuilder := archive.TarBuilder{} + tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(` [buildpack] id = "" version = "1.2.3" [[stacks]] id = "some.stack.id"`)) - return tarBuilder.Reader(archive.DefaultTarWriterFactory()) - }, + return tarBuilder.Reader(archive.DefaultTarWriterFactory()) }, - archive.DefaultTarWriterFactory(), - ) + }, archive.DefaultTarWriterFactory(), nil) h.AssertError(t, err, "'buildpack.id' is required") }) }) when("there is no version", func() { it("returns error", func() { - _, err := buildpack.FromBuildpackRootBlob( - &readerBlob{ - openFn: func() io.ReadCloser { - tarBuilder := archive.TarBuilder{} - tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(` + _, err := buildpack.FromBuildpackRootBlob(&readerBlob{ + openFn: func() io.ReadCloser { + tarBuilder := archive.TarBuilder{} + tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(` [buildpack] id = "bp.one" version = "" [[stacks]] id = "some.stack.id"`)) - return tarBuilder.Reader(archive.DefaultTarWriterFactory()) - }, + return tarBuilder.Reader(archive.DefaultTarWriterFactory()) }, - archive.DefaultTarWriterFactory(), - ) + }, archive.DefaultTarWriterFactory(), nil) h.AssertError(t, err, "'buildpack.version' is required") }) }) when("both stacks and order are present", func() { it("returns error", func() { - _, err := buildpack.FromBuildpackRootBlob( - &readerBlob{ - openFn: func() io.ReadCloser { - tarBuilder := archive.TarBuilder{} - tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(` + _, err := buildpack.FromBuildpackRootBlob(&readerBlob{ + openFn: func() io.ReadCloser { + tarBuilder := archive.TarBuilder{} + tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(` [buildpack] id = "bp.one" version = "1.2.3" @@ -484,31 +444,26 @@ id = "some.stack.id" id = "bp.nested" version = "bp.nested.version" `)) - return tarBuilder.Reader(archive.DefaultTarWriterFactory()) - }, + return tarBuilder.Reader(archive.DefaultTarWriterFactory()) }, - archive.DefaultTarWriterFactory(), - ) + }, archive.DefaultTarWriterFactory(), nil) h.AssertError(t, err, "cannot have both 'targets'/'stacks' and an 'order' defined") }) }) when("missing stacks and order", func() { it("does not return an error", func() { - _, err := buildpack.FromBuildpackRootBlob( - &readerBlob{ - openFn: func() io.ReadCloser { - tarBuilder := archive.TarBuilder{} - tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(` + _, err := buildpack.FromBuildpackRootBlob(&readerBlob{ + openFn: func() io.ReadCloser { + tarBuilder := archive.TarBuilder{} + tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(` [buildpack] id = "bp.one" version = "1.2.3" `)) - return tarBuilder.Reader(archive.DefaultTarWriterFactory()) - }, + return tarBuilder.Reader(archive.DefaultTarWriterFactory()) }, - archive.DefaultTarWriterFactory(), - ) + }, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) }) }) @@ -528,10 +483,7 @@ version = "1.2.3" }) it("hardlink is preserved in the output tar file", func() { - bp, err := buildpack.FromBuildpackRootBlob( - blob.NewBlob(bpRootFolder), - archive.DefaultTarWriterFactory(), - ) + bp, err := buildpack.FromBuildpackRootBlob(blob.NewBlob(bpRootFolder), archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) tarPath := writeBlobToFile(bp) diff --git a/pkg/buildpack/downloader.go b/pkg/buildpack/downloader.go index 454afda0cb..d3a5eaea2c 100644 --- a/pkg/buildpack/downloader.go +++ b/pkg/buildpack/downloader.go @@ -141,7 +141,7 @@ func (c *buildpackDownloader) Download(ctx context.Context, moduleURI string, op return nil, nil, errors.Wrapf(err, "downloading %s from %s", kind, style.Symbol(moduleURI)) } - mainBP, depBPs, err = decomposeBlob(blob, kind, opts.ImageOS) + mainBP, depBPs, err = decomposeBlob(blob, kind, opts.ImageOS, c.logger) if err != nil { return nil, nil, errors.Wrapf(err, "extracting from %s", style.Symbol(moduleURI)) } @@ -153,7 +153,7 @@ func (c *buildpackDownloader) Download(ctx context.Context, moduleURI string, op // decomposeBlob decomposes a buildpack or extension blob into the main module (order buildpack or extension) and // (for buildpack blobs) its dependent buildpacks. -func decomposeBlob(blob blob.Blob, kind string, imageOS string) (mainModule BuildModule, depModules []BuildModule, err error) { +func decomposeBlob(blob blob.Blob, kind string, imageOS string, logger Logger) (mainModule BuildModule, depModules []BuildModule, err error) { isOCILayout, err := IsOCILayoutBlob(blob) if err != nil { return mainModule, depModules, errors.Wrapf(err, "inspecting %s blob", kind) @@ -171,9 +171,9 @@ func decomposeBlob(blob blob.Blob, kind string, imageOS string) (mainModule Buil } if kind == KindExtension { - mainModule, err = FromExtensionRootBlob(blob, layerWriterFactory) + mainModule, err = FromExtensionRootBlob(blob, layerWriterFactory, logger) } else { - mainModule, err = FromBuildpackRootBlob(blob, layerWriterFactory) + mainModule, err = FromBuildpackRootBlob(blob, layerWriterFactory, logger) } if err != nil { return mainModule, depModules, errors.Wrapf(err, "reading %s", kind) diff --git a/pkg/client/create_builder_test.go b/pkg/client/create_builder_test.go index 7c51fa3090..88e888d9c6 100644 --- a/pkg/client/create_builder_test.go +++ b/pkg/client/create_builder_test.go @@ -112,10 +112,10 @@ func testCreateBuilder(t *testing.T, when spec.G, it spec.S) { mockDownloader.EXPECT().Download(gomock.Any(), "file:///some-lifecycle").Return(blob.NewBlob(filepath.Join("testdata", "lifecycle", "platform-0.4")), nil).AnyTimes() mockDownloader.EXPECT().Download(gomock.Any(), "file:///some-lifecycle-platform-0-1").Return(blob.NewBlob(filepath.Join("testdata", "lifecycle-platform-0.1")), nil).AnyTimes() - bp, err := buildpack.FromBuildpackRootBlob(exampleBuildpackBlob, archive.DefaultTarWriterFactory()) + bp, err := buildpack.FromBuildpackRootBlob(exampleBuildpackBlob, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) mockBuildpackDownloader.EXPECT().Download(gomock.Any(), "https://example.fake/bp-one.tgz", gomock.Any()).Return(bp, nil, nil).AnyTimes() - ext, err := buildpack.FromExtensionRootBlob(exampleExtensionBlob, archive.DefaultTarWriterFactory()) + ext, err := buildpack.FromExtensionRootBlob(exampleExtensionBlob, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) mockBuildpackDownloader.EXPECT().Download(gomock.Any(), "https://example.fake/ext-one.tgz", gomock.Any()).Return(ext, nil, nil).AnyTimes() @@ -776,12 +776,12 @@ func testCreateBuilder(t *testing.T, when spec.G, it spec.S) { opts.Config.Extensions[0].URI = "https://example.fake/ext-one-with-api-9.tgz" buildpackBlob := blob.NewBlob(filepath.Join("testdata", "buildpack-api-0.4")) - bp, err := buildpack.FromBuildpackRootBlob(buildpackBlob, archive.DefaultTarWriterFactory()) + bp, err := buildpack.FromBuildpackRootBlob(buildpackBlob, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) mockBuildpackDownloader.EXPECT().Download(gomock.Any(), "https://example.fake/bp-one-with-api-4.tgz", gomock.Any()).Return(bp, nil, nil) extensionBlob := blob.NewBlob(filepath.Join("testdata", "extension-api-0.9")) - extension, err := buildpack.FromExtensionRootBlob(extensionBlob, archive.DefaultTarWriterFactory()) + extension, err := buildpack.FromExtensionRootBlob(extensionBlob, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) mockBuildpackDownloader.EXPECT().Download(gomock.Any(), "https://example.fake/ext-one-with-api-9.tgz", gomock.Any()).Return(extension, nil, nil) @@ -824,16 +824,16 @@ func testCreateBuilder(t *testing.T, when spec.G, it spec.S) { bp2v1Blob := blob.NewBlob(filepath.Join("testdata", "buildpack-non-deterministic", "buildpack-2-version-1")) bp2v2Blob := blob.NewBlob(filepath.Join("testdata", "buildpack-non-deterministic", "buildpack-2-version-2")) - bp1v1, err = buildpack.FromBuildpackRootBlob(bp1v1Blob, archive.DefaultTarWriterFactory()) + bp1v1, err = buildpack.FromBuildpackRootBlob(bp1v1Blob, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) - bp1v2, err = buildpack.FromBuildpackRootBlob(bp1v2Blob, archive.DefaultTarWriterFactory()) + bp1v2, err = buildpack.FromBuildpackRootBlob(bp1v2Blob, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) - bp2v1, err = buildpack.FromBuildpackRootBlob(bp2v1Blob, archive.DefaultTarWriterFactory()) + bp2v1, err = buildpack.FromBuildpackRootBlob(bp2v1Blob, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) - bp2v2, err = buildpack.FromBuildpackRootBlob(bp2v2Blob, archive.DefaultTarWriterFactory()) + bp2v2, err = buildpack.FromBuildpackRootBlob(bp2v2Blob, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) return []buildpack.BuildModule{bp2v2, bp2v1, bp1v1, bp1v2} @@ -855,7 +855,7 @@ func testCreateBuilder(t *testing.T, when spec.G, it spec.S) { bpDependencies := prepareBuildpackDependencies() buildpackBlob := blob.NewBlob(filepath.Join("testdata", "buildpack-api-0.4")) - bp, err := buildpack.FromBuildpackRootBlob(buildpackBlob, archive.DefaultTarWriterFactory()) + bp, err := buildpack.FromBuildpackRootBlob(buildpackBlob, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) mockBuildpackDownloader.EXPECT().Download(gomock.Any(), "https://example.fake/bp-one-with-api-4.tgz", gomock.Any()).DoAndReturn( func(ctx context.Context, buildpackURI string, opts buildpack.DownloadOptions) (buildpack.BuildModule, []buildpack.BuildModule, error) { @@ -865,7 +865,7 @@ func testCreateBuilder(t *testing.T, when spec.G, it spec.S) { }) extensionBlob := blob.NewBlob(filepath.Join("testdata", "extension-api-0.9")) - extension, err := buildpack.FromExtensionRootBlob(extensionBlob, archive.DefaultTarWriterFactory()) + extension, err := buildpack.FromExtensionRootBlob(extensionBlob, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) mockBuildpackDownloader.EXPECT().Download(gomock.Any(), "https://example.fake/ext-one-with-api-9.tgz", gomock.Any()).DoAndReturn( func(ctx context.Context, buildpackURI string, opts buildpack.DownloadOptions) (buildpack.BuildModule, []buildpack.BuildModule, error) { @@ -898,7 +898,7 @@ func testCreateBuilder(t *testing.T, when spec.G, it spec.S) { opts.Config.Buildpacks[0].URI = directoryPath buildpackBlob := blob.NewBlob(directoryPath) - buildpack, err := buildpack.FromBuildpackRootBlob(buildpackBlob, archive.DefaultTarWriterFactory()) + buildpack, err := buildpack.FromBuildpackRootBlob(buildpackBlob, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) mockBuildpackDownloader.EXPECT().Download(gomock.Any(), directoryPath, gomock.Any()).Return(buildpack, nil, nil) @@ -914,7 +914,7 @@ func testCreateBuilder(t *testing.T, when spec.G, it spec.S) { opts.Config.Extensions[0].URI = directoryPath extensionBlob := blob.NewBlob(directoryPath) - extension, err := buildpack.FromExtensionRootBlob(extensionBlob, archive.DefaultTarWriterFactory()) + extension, err := buildpack.FromExtensionRootBlob(extensionBlob, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) mockBuildpackDownloader.EXPECT().Download(gomock.Any(), directoryPath, gomock.Any()).Return(extension, nil, nil) @@ -1030,13 +1030,13 @@ func testCreateBuilder(t *testing.T, when spec.G, it spec.S) { blob1 := blob.NewBlob(filepath.Join("testdata", "buildpack-flatten", "buildpack-1")) for i := 2; i <= 7; i++ { b := blob.NewBlob(filepath.Join("testdata", "buildpack-flatten", fmt.Sprintf("buildpack-%d", i))) - bp, err := buildpack.FromBuildpackRootBlob(b, archive.DefaultTarWriterFactory()) + bp, err := buildpack.FromBuildpackRootBlob(b, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) depBPs = append(depBPs, bp) } mockDownloader.EXPECT().Download(gomock.Any(), "https://example.fake/flatten-bp-1.tgz").Return(blob1, nil).AnyTimes() - bp, err := buildpack.FromBuildpackRootBlob(blob1, archive.DefaultTarWriterFactory()) + bp, err := buildpack.FromBuildpackRootBlob(blob1, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) mockBuildpackDownloader.EXPECT().Download(gomock.Any(), "https://example.fake/flatten-bp-1.tgz", gomock.Any()).Return(bp, depBPs, nil).AnyTimes() diff --git a/pkg/client/package_buildpack.go b/pkg/client/package_buildpack.go index 49ca63882a..2cdcddb9ec 100644 --- a/pkg/client/package_buildpack.go +++ b/pkg/client/package_buildpack.go @@ -98,7 +98,7 @@ func (c *Client) PackageBuildpack(ctx context.Context, opts PackageBuildpackOpti return err } - bp, err := buildpack.FromBuildpackRootBlob(mainBlob, writerFactory) + bp, err := buildpack.FromBuildpackRootBlob(mainBlob, writerFactory, c.logger) if err != nil { return errors.Wrapf(err, "creating buildpack from %s", style.Symbol(bpURI)) } diff --git a/pkg/client/package_buildpack_test.go b/pkg/client/package_buildpack_test.go index b94662c7de..1810eb418a 100644 --- a/pkg/client/package_buildpack_test.go +++ b/pkg/client/package_buildpack_test.go @@ -462,25 +462,25 @@ func testPackageBuildpack(t *testing.T, when spec.G, it spec.S) { blob1 := blob.NewBlob(filepath.Join("testdata", "buildpack-flatten", "buildpack-1")) mockDownloader.EXPECT().Download(gomock.Any(), "https://example.fake/flatten-bp-1.tgz").Return(blob1, nil).AnyTimes() - bp, err := buildpack.FromBuildpackRootBlob(blob1, archive.DefaultTarWriterFactory()) + bp, err := buildpack.FromBuildpackRootBlob(blob1, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) mockBuildpackDownloader.EXPECT().Download(gomock.Any(), "https://example.fake/flatten-bp-1.tgz", gomock.Any()).Return(bp, nil, nil).AnyTimes() // flatten buildpack 2 blob2 := blob.NewBlob(filepath.Join("testdata", "buildpack-flatten", "buildpack-2")) - bp2, err := buildpack.FromBuildpackRootBlob(blob2, archive.DefaultTarWriterFactory()) + bp2, err := buildpack.FromBuildpackRootBlob(blob2, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) mockBuildpackDownloader.EXPECT().Download(gomock.Any(), "https://example.fake/flatten-bp-2.tgz", gomock.Any()).Return(bp2, nil, nil).AnyTimes() // flatten buildpack 3 blob3 := blob.NewBlob(filepath.Join("testdata", "buildpack-flatten", "buildpack-3")) - bp3, err := buildpack.FromBuildpackRootBlob(blob3, archive.DefaultTarWriterFactory()) + bp3, err := buildpack.FromBuildpackRootBlob(blob3, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) var depBPs []buildpack.BuildModule for i := 4; i <= 7; i++ { b := blob.NewBlob(filepath.Join("testdata", "buildpack-flatten", fmt.Sprintf("buildpack-%d", i))) - bp, err := buildpack.FromBuildpackRootBlob(b, archive.DefaultTarWriterFactory()) + bp, err := buildpack.FromBuildpackRootBlob(b, archive.DefaultTarWriterFactory(), nil) h.AssertNil(t, err) depBPs = append(depBPs, bp) } diff --git a/pkg/client/package_extension.go b/pkg/client/package_extension.go index 0e2c0e7317..690d12afba 100644 --- a/pkg/client/package_extension.go +++ b/pkg/client/package_extension.go @@ -42,7 +42,7 @@ func (c *Client) PackageExtension(ctx context.Context, opts PackageBuildpackOpti return err } - ex, err := buildpack.FromExtensionRootBlob(mainBlob, writerFactory) + ex, err := buildpack.FromExtensionRootBlob(mainBlob, writerFactory, c.logger) if err != nil { return errors.Wrapf(err, "creating extension from %s", style.Symbol(exURI)) } From 39fecde57621747181487ed0d564e405e651086c Mon Sep 17 00:00:00 2001 From: Natalie Arellano Date: Fri, 19 Apr 2024 15:17:57 -0400 Subject: [PATCH 05/18] Add test Signed-off-by: Natalie Arellano --- pkg/buildpack/buildpack.go | 28 ++++++++++++------------- pkg/buildpack/buildpack_test.go | 36 +++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/pkg/buildpack/buildpack.go b/pkg/buildpack/buildpack.go index 9c8e115451..c6f9778204 100644 --- a/pkg/buildpack/buildpack.go +++ b/pkg/buildpack/buildpack.go @@ -74,12 +74,12 @@ func FromBlob(descriptor Descriptor, blob Blob) BuildModule { func FromBuildpackRootBlob(blob Blob, layerWriterFactory archive.TarWriterFactory, logger Logger) (BuildModule, error) { descriptor := dist.BuildpackDescriptor{} descriptor.WithAPI = api.MustParse(dist.AssumedBuildpackAPIVersion) - var undecodedKeys []string - if err := readDescriptor(KindBuildpack, &descriptor, blob, undecodedKeys); err != nil { + undecodedKeys, err := readDescriptor(KindBuildpack, &descriptor, blob) + if err != nil { return nil, err } if len(undecodedKeys) > 0 { - logger.Warnf("Ignoring unexpected key(s) in buildpack descriptor: %s", strings.Join(undecodedKeys, ",")) + logger.Warnf("Ignoring unexpected key(s) in descriptor for buildpack %s: %s", descriptor.EscapedID(), strings.Join(undecodedKeys, ",")) } if err := detectPlatformSpecificValues(&descriptor, blob); err != nil { return nil, err @@ -96,12 +96,12 @@ func FromBuildpackRootBlob(blob Blob, layerWriterFactory archive.TarWriterFactor func FromExtensionRootBlob(blob Blob, layerWriterFactory archive.TarWriterFactory, logger Logger) (BuildModule, error) { descriptor := dist.ExtensionDescriptor{} descriptor.WithAPI = api.MustParse(dist.AssumedBuildpackAPIVersion) - var undecodedKeys []string - if err := readDescriptor(KindExtension, &descriptor, blob, undecodedKeys); err != nil { + undecodedKeys, err := readDescriptor(KindExtension, &descriptor, blob) + if err != nil { return nil, err } if len(undecodedKeys) > 0 { - logger.Warnf("Ignoring unexpected key(s) in extension descriptor: %s", strings.Join(undecodedKeys, ",")) + logger.Warnf("Ignoring unexpected key(s) in descriptor for extension %s: %s", descriptor.EscapedID(), strings.Join(undecodedKeys, ",")) } if err := validateExtensionDescriptor(descriptor); err != nil { return nil, err @@ -109,10 +109,10 @@ func FromExtensionRootBlob(blob Blob, layerWriterFactory archive.TarWriterFactor return buildpackFrom(&descriptor, blob, layerWriterFactory) } -func readDescriptor(kind string, descriptor interface{}, blob Blob, undecoded []string) error { +func readDescriptor(kind string, descriptor interface{}, blob Blob) (undecodedKeys []string, err error) { rc, err := blob.Open() if err != nil { - return errors.Wrapf(err, "open %s", kind) + return undecodedKeys, errors.Wrapf(err, "open %s", kind) } defer rc.Close() @@ -120,20 +120,20 @@ func readDescriptor(kind string, descriptor interface{}, blob Blob, undecoded [] _, buf, err := archive.ReadTarEntry(rc, descriptorFile) if err != nil { - return errors.Wrapf(err, "reading %s", descriptorFile) + return undecodedKeys, errors.Wrapf(err, "reading %s", descriptorFile) } md, err := toml.Decode(string(buf), descriptor) if err != nil { - return errors.Wrapf(err, "decoding %s", descriptorFile) + return undecodedKeys, errors.Wrapf(err, "decoding %s", descriptorFile) } - undecodedKeys := md.Undecoded() - for _, k := range undecodedKeys { - undecoded = append(undecoded, k.String()) + undecoded := md.Undecoded() + for _, k := range undecoded { + undecodedKeys = append(undecodedKeys, k.String()) } - return nil + return undecodedKeys, nil } func detectPlatformSpecificValues(descriptor *dist.BuildpackDescriptor, blob Blob) error { diff --git a/pkg/buildpack/buildpack_test.go b/pkg/buildpack/buildpack_test.go index b44bbc94e9..2de8975630 100644 --- a/pkg/buildpack/buildpack_test.go +++ b/pkg/buildpack/buildpack_test.go @@ -1,6 +1,7 @@ package buildpack_test import ( + "bytes" "fmt" "io" "os" @@ -20,6 +21,7 @@ import ( "github.com/buildpacks/pack/pkg/blob" "github.com/buildpacks/pack/pkg/buildpack" "github.com/buildpacks/pack/pkg/dist" + "github.com/buildpacks/pack/pkg/logging" h "github.com/buildpacks/pack/testhelpers" ) @@ -496,6 +498,40 @@ version = "1.2.3" ) }) }) + + when("there are wrong things in the file", func() { + it("warns", func() { + outBuf := bytes.Buffer{} + logger := logging.NewLogWithWriters(&outBuf, &outBuf) + _, err := buildpack.FromBuildpackRootBlob(&readerBlob{ + openFn: func() io.ReadCloser { + tarBuilder := archive.TarBuilder{} + tarBuilder.AddFile("buildpack.toml", 0700, time.Now(), []byte(` +api = "0.3" + +[buildpack] +id = "bp.one" +version = "1.2.3" +homepage = "http://geocities.com/cool-bp" + +[[targets]] +os = "some-os" +arch = "some-arch" +variant = "some-arch-variant" +[[targets.distributions]] +name = "some-distro-name" +version = "some-distro-version" +[[targets.distros]] +name = "some-distro-name" +versions = ["some-distro-version"] +`)) + return tarBuilder.Reader(archive.DefaultTarWriterFactory()) + }, + }, archive.DefaultTarWriterFactory(), logger) + h.AssertNil(t, err) + h.AssertContains(t, outBuf.String(), "Warning: Ignoring unexpected key(s) in descriptor for buildpack bp.one: targets.distributions,targets.distributions.name,targets.distributions.version,targets.distros.versions") + }) + }) }) when("#Match", func() { From 7949931b0438a1a929f94c4ca8eb82fc631731a2 Mon Sep 17 00:00:00 2001 From: Natalie Arellano Date: Fri, 19 Apr 2024 15:22:10 -0400 Subject: [PATCH 06/18] Add distro test Signed-off-by: Natalie Arellano --- internal/target/parse_test.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/internal/target/parse_test.go b/internal/target/parse_test.go index f00c095fb3..61b2c6e39e 100644 --- a/internal/target/parse_test.go +++ b/internal/target/parse_test.go @@ -61,6 +61,7 @@ func testParseTargets(t *testing.T, when spec.G, it spec.S) { h.AssertNotEq(t, outBuf.String(), "") }) }) + when("target#ParseTargets", func() { it("should throw an error when atleast one target throws error", func() { _, err := target.ParseTargets([]string{"linux/arm/v6", ":distro@version"}, logging.NewLogWithWriters(&outBuf, &outBuf)) @@ -96,6 +97,7 @@ func testParseTargets(t *testing.T, when spec.G, it spec.S) { }) }) }) + when("target#ParseDistro", func() { it("should parse distro as expected", func() { output, err := target.ParseDistro("ubuntu@22.04", logging.NewLogWithWriters(&outBuf, &outBuf)) @@ -105,15 +107,21 @@ func testParseTargets(t *testing.T, when spec.G, it spec.S) { }) h.AssertNil(t, err) }) - it("should return an error", func() { + it("should return an error when name is missing", func() { _, err := target.ParseDistro("@22.04@20.08", logging.NewLogWithWriters(&outBuf, &outBuf)) h.AssertNotNil(t, err) }) + it("should return an error when there are two versions", func() { + _, err := target.ParseDistro("some-distro@22.04@20.08", logging.NewLogWithWriters(&outBuf, &outBuf)) + h.AssertNotNil(t, err) + h.AssertError(t, err, "invalid distro") + }) it("should warn when distro version is not specified", func() { target.ParseDistro("ubuntu", logging.NewLogWithWriters(&outBuf, &outBuf)) h.AssertNotEq(t, outBuf.String(), "") }) }) + when("target#ParseDistros", func() { it("should parse distros as expected", func() { output, err := target.ParseDistros("ubuntu@22.04;ubuntu@20.08;debian@8.10;debian@10.06", logging.NewLogWithWriters(&outBuf, &outBuf)) From 81d9698496b4da9eb65c49f14e38a9b1d3bebf03 Mon Sep 17 00:00:00 2001 From: Juan Bustamante Date: Fri, 8 Mar 2024 12:56:34 -0500 Subject: [PATCH 07/18] Adding a nop-op when trying to check access for run-image against the daemon Signed-off-by: Juan Bustamante --- internal/fakes/fake_access_checker.go | 5 +++- pkg/client/client.go | 2 +- pkg/client/common.go | 9 ++++--- pkg/client/common_test.go | 27 ++++++++++++++++--- pkg/image/access_checker.go | 7 ++++- pkg/image/access_checker_test.go | 37 ++++++++++++++++++++++----- 6 files changed, 70 insertions(+), 17 deletions(-) diff --git a/internal/fakes/fake_access_checker.go b/internal/fakes/fake_access_checker.go index 9912df97dc..c4d731774f 100644 --- a/internal/fakes/fake_access_checker.go +++ b/internal/fakes/fake_access_checker.go @@ -8,7 +8,10 @@ func NewFakeAccessChecker() *FakeAccessChecker { return &FakeAccessChecker{} } -func (f *FakeAccessChecker) Check(repo string) bool { +func (f *FakeAccessChecker) Check(repo string, publish bool) bool { + if !publish { + return true + } for _, toFail := range f.RegistriesToFail { if toFail == repo { return false diff --git a/pkg/client/client.go b/pkg/client/client.go index d034851fc6..d46ccb2d2b 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -84,7 +84,7 @@ type BuildpackDownloader interface { // AccessChecker is an interface for checking remote images for read access type AccessChecker interface { - Check(repo string) bool + Check(repo string, publish bool) bool } // Client is an orchestration object, it contains all parameters needed to diff --git a/pkg/client/common.go b/pkg/client/common.go index d3c67d882b..ff824c5d3e 100644 --- a/pkg/client/common.go +++ b/pkg/client/common.go @@ -44,6 +44,7 @@ func (c *Client) resolveRunImage(runImage, imgRegistry, bldrRegistry string, run runImageMetadata.Image, runImageMetadata.Mirrors, additionalMirrors[runImageMetadata.Image], + publish, accessChecker, ) @@ -108,8 +109,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, publish bool, accessChecker AccessChecker) string { + runImageList := filterImageList(append(append(append([]string{}, preferredMirrors...), runImage), mirrors...), publish, accessChecker) for _, img := range runImageList { ref, err := name.ParseReference(img, name.WeakValidation) if err != nil { @@ -127,11 +128,11 @@ func getBestRunMirror(registry string, runImage string, mirrors []string, prefer return runImage } -func filterImageList(imageList []string, accessChecker AccessChecker) []string { +func filterImageList(imageList []string, publish bool, accessChecker AccessChecker) []string { var accessibleImages []string for i, img := range imageList { - if accessChecker.Check(img) { + if accessChecker.Check(img, publish) { accessibleImages = append(accessibleImages, imageList[i]) } } diff --git a/pkg/client/common_test.go b/pkg/client/common_test.go index 76138b5678..e610020760 100644 --- a/pkg/client/common_test.go +++ b/pkg/client/common_test.go @@ -131,9 +131,30 @@ func testCommon(t *testing.T, when spec.G, it spec.S) { accessChecker.RegistriesToFail = nil }) - it("selects the first accessible run-image", func() { - runImageName := subject.resolveRunImage("", gcrRegistry, defaultRegistry, stackInfo.RunImage, nil, true, accessChecker) - assert.Equal(runImageName, defaultMirror) + when("publish is true", func() { + it("selects the first accessible run-image", func() { + runImageName := subject.resolveRunImage("", gcrRegistry, defaultRegistry, stackInfo.RunImage, nil, true, accessChecker) + assert.Equal(runImageName, defaultMirror) + }) + }) + + when("publish is false", func() { + it.Before(func() { + stackInfo = builder.StackMetadata{ + RunImage: builder.RunImageMetadata{ + Image: "stack/run-image", + }, + } + accessChecker.RegistriesToFail = []string{ + stackInfo.RunImage.Image, + } + }) + + it("selects the given run-image", func() { + // issue: https://github.com/buildpacks/pack/issues/2078 + runImageName := subject.resolveRunImage("", "", "", stackInfo.RunImage, nil, false, accessChecker) + assert.Equal(runImageName, "stack/run-image") + }) }) }) }) diff --git a/pkg/image/access_checker.go b/pkg/image/access_checker.go index bc9ae55cd0..50401a104f 100644 --- a/pkg/image/access_checker.go +++ b/pkg/image/access_checker.go @@ -25,7 +25,12 @@ func NewAccessChecker(logger logging.Logger, keychain authn.Keychain) *Checker { return checker } -func (c *Checker) Check(repo string) bool { +func (c *Checker) Check(repo string, publish bool) bool { + if !publish { + // nop checker, we are running against the daemon + return true + } + img, err := remote.NewImage(repo, c.keychain) if err != nil { return false diff --git a/pkg/image/access_checker_test.go b/pkg/image/access_checker_test.go index 9b1bf3ebd6..d16de8b22a 100644 --- a/pkg/image/access_checker_test.go +++ b/pkg/image/access_checker_test.go @@ -18,17 +18,40 @@ func TestChecker(t *testing.T) { } func testChecker(t *testing.T, when spec.G, it spec.S) { + var publish bool + when("#Check", func() { - it("fails when checking dummy image", func() { - buf := &bytes.Buffer{} + when("publish is false", func() { + it.Before(func() { + publish = false + }) + + // issue: https://github.com/buildpacks/pack/issues/2078 + it("returns true", func() { + buf := &bytes.Buffer{} + keychain, err := auth.DefaultKeychain("pack-test/dummy") + h.AssertNil(t, err) + + ic := image.NewAccessChecker(logging.NewSimpleLogger(buf), keychain) + h.AssertTrue(t, ic.Check("pack.test/dummy", publish)) + }) + }) + + when("publish is true", func() { + it.Before(func() { + publish = true + }) - keychain, err := auth.DefaultKeychain("pack.test/dummy") - h.AssertNil(t, err) + it("fails when checking dummy image", func() { + buf := &bytes.Buffer{} + keychain, err := auth.DefaultKeychain("pack.test/dummy") + h.AssertNil(t, err) - ic := image.NewAccessChecker(logging.NewSimpleLogger(buf), keychain) + ic := image.NewAccessChecker(logging.NewSimpleLogger(buf), keychain) - h.AssertFalse(t, ic.Check("pack.test/dummy")) - h.AssertContains(t, buf.String(), "DEBUG: CheckReadAccess failed for the run image pack.test/dummy") + h.AssertFalse(t, ic.Check("pack.test/dummy", publish)) + h.AssertContains(t, buf.String(), "DEBUG: CheckReadAccess failed for the run image pack.test/dummy") + }) }) }) } From b53508619bf31c282de4a73158fe190e733b3ac2 Mon Sep 17 00:00:00 2001 From: Juan Bustamante Date: Wed, 3 Apr 2024 17:37:46 -0500 Subject: [PATCH 08/18] refactoring the logic, I moved the check read access to a method in the fetcher Signed-off-by: Juan Bustamante --- internal/builder/image_fetcher_wrapper.go | 5 + internal/fakes/fake_access_checker.go | 22 ---- internal/fakes/fake_image_fetcher.go | 6 + pkg/buildpack/downloader.go | 1 + pkg/client/build.go | 2 +- pkg/client/build_test.go | 3 - pkg/client/client.go | 22 +--- pkg/client/client_test.go | 10 -- pkg/client/common.go | 16 +-- pkg/client/common_test.go | 135 +++++++++++++--------- pkg/client/example_fetcher_test.go | 6 + pkg/client/rebase.go | 1 - pkg/client/rebase_test.go | 12 +- pkg/image/access_checker.go | 46 -------- pkg/image/access_checker_test.go | 57 --------- pkg/image/fetcher.go | 24 ++++ pkg/image/fetcher_test.go | 48 +++++++- pkg/testmocks/mock_image_fetcher.go | 14 +++ 18 files changed, 202 insertions(+), 228 deletions(-) delete mode 100644 internal/fakes/fake_access_checker.go delete mode 100644 pkg/image/access_checker.go delete mode 100644 pkg/image/access_checker_test.go diff --git a/internal/builder/image_fetcher_wrapper.go b/internal/builder/image_fetcher_wrapper.go index dfb0de4a83..613a9647d4 100644 --- a/internal/builder/image_fetcher_wrapper.go +++ b/internal/builder/image_fetcher_wrapper.go @@ -13,6 +13,7 @@ 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) + CheckReadAccessValidator(options image.FetchOptions) image.CheckReadAccess } type ImageFetcherWrapper struct { @@ -32,3 +33,7 @@ func (w *ImageFetcherWrapper) Fetch( ) (Inspectable, error) { return w.fetcher.Fetch(ctx, name, options) } + +func (w *ImageFetcherWrapper) CheckReadAccessValidator(options image.FetchOptions) image.CheckReadAccess { + return w.fetcher.CheckReadAccessValidator(options) +} diff --git a/internal/fakes/fake_access_checker.go b/internal/fakes/fake_access_checker.go deleted file mode 100644 index c4d731774f..0000000000 --- a/internal/fakes/fake_access_checker.go +++ /dev/null @@ -1,22 +0,0 @@ -package fakes - -type FakeAccessChecker struct { - RegistriesToFail []string -} - -func NewFakeAccessChecker() *FakeAccessChecker { - return &FakeAccessChecker{} -} - -func (f *FakeAccessChecker) Check(repo string, publish bool) bool { - if !publish { - return true - } - for _, toFail := range f.RegistriesToFail { - if toFail == repo { - return false - } - } - - return true -} diff --git a/internal/fakes/fake_image_fetcher.go b/internal/fakes/fake_image_fetcher.go index 3ae30f9610..e95ce824bc 100644 --- a/internal/fakes/fake_image_fetcher.go +++ b/internal/fakes/fake_image_fetcher.go @@ -55,6 +55,12 @@ func (f *FakeImageFetcher) Fetch(ctx context.Context, name string, options image return ri, nil } +func (f *FakeImageFetcher) CheckReadAccessValidator(_ image.FetchOptions) image.CheckReadAccess { + return func(_ string) bool { + return true + } +} + func shouldPull(localFound, remoteFound bool, policy image.PullPolicy) bool { if remoteFound && !localFound && policy == image.PullIfNotPresent { return true diff --git a/pkg/buildpack/downloader.go b/pkg/buildpack/downloader.go index d3a5eaea2c..45930342ed 100644 --- a/pkg/buildpack/downloader.go +++ b/pkg/buildpack/downloader.go @@ -29,6 +29,7 @@ type Logger interface { type ImageFetcher interface { Fetch(ctx context.Context, name string, options image.FetchOptions) (imgutil.Image, error) + CheckReadAccessValidator(options image.FetchOptions) image.CheckReadAccess } type Downloader interface { diff --git a/pkg/client/build.go b/pkg/client/build.go index 670f53f2c8..da58f580fe 100644 --- a/pkg/client/build.go +++ b/pkg/client/build.go @@ -340,7 +340,7 @@ 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) + runImageName := c.resolveRunImage(opts.RunImage, imgRegistry, builderRef.Context().RegistryStr(), bldr.DefaultRunImage(), opts.AdditionalMirrors, opts.Publish) fetchOptions := image.FetchOptions{ Daemon: !opts.Publish, diff --git a/pkg/client/build_test.go b/pkg/client/build_test.go index 27cd02d236..b01cb9b2be 100644 --- a/pkg/client/build_test.go +++ b/pkg/client/build_test.go @@ -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 @@ -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") @@ -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, diff --git a/pkg/client/client.go b/pkg/client/client.go index d46ccb2d2b..97fa306fa3 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -52,6 +52,8 @@ 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) + + CheckReadAccessValidator(options image.FetchOptions) image.CheckReadAccess } //go:generate mockgen -package testmocks -destination ../testmocks/mock_blob_downloader.go github.com/buildpacks/pack/pkg/client BlobDownloader @@ -80,13 +82,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, publish bool) 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. @@ -97,7 +92,6 @@ type Client struct { keychain authn.Keychain imageFactory ImageFactory imageFetcher ImageFetcher - accessChecker AccessChecker downloader BlobDownloader lifecycleExecutor LifecycleExecutor buildpackDownloader BuildpackDownloader @@ -133,14 +127,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 { @@ -241,10 +227,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, diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index 2ee6d8b2fe..0b40ec0a8f 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -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" @@ -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) - }) - }) } diff --git a/pkg/client/common.go b/pkg/client/common.go index ff824c5d3e..d23cb2e957 100644 --- a/pkg/client/common.go +++ b/pkg/client/common.go @@ -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" ) @@ -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) string { if runImage != "" { c.logger.Debugf("Using provided run-image %s", style.Symbol(runImage)) return runImage @@ -44,8 +45,9 @@ func (c *Client) resolveRunImage(runImage, imgRegistry, bldrRegistry string, run runImageMetadata.Image, runImageMetadata.Mirrors, additionalMirrors[runImageMetadata.Image], - publish, - accessChecker, + c.imageFetcher.CheckReadAccessValidator(image.FetchOptions{ + Daemon: !publish, + }), ) switch { @@ -109,8 +111,8 @@ func contains(slc []string, v string) bool { return false } -func getBestRunMirror(registry string, runImage string, mirrors []string, preferredMirrors []string, publish bool, accessChecker AccessChecker) string { - runImageList := filterImageList(append(append(append([]string{}, preferredMirrors...), runImage), mirrors...), publish, accessChecker) +func getBestRunMirror(registry string, runImage string, mirrors []string, preferredMirrors []string, accessChecker image.CheckReadAccess) string { + runImageList := filterImageList(append(append(append([]string{}, preferredMirrors...), runImage), mirrors...), accessChecker) for _, img := range runImageList { ref, err := name.ParseReference(img, name.WeakValidation) if err != nil { @@ -128,11 +130,11 @@ func getBestRunMirror(registry string, runImage string, mirrors []string, prefer return runImage } -func filterImageList(imageList []string, publish bool, accessChecker AccessChecker) []string { +func filterImageList(imageList []string, accessChecker image.CheckReadAccess) []string { var accessibleImages []string for i, img := range imageList { - if accessChecker.Check(img, publish) { + if accessChecker(img) { accessibleImages = append(accessibleImages, imageList[i]) } } diff --git a/pkg/client/common_test.go b/pkg/client/common_test.go index e610020760..09719f6199 100644 --- a/pkg/client/common_test.go +++ b/pkg/client/common_test.go @@ -4,13 +4,17 @@ import ( "bytes" "testing" + "github.com/buildpacks/lifecycle/auth" + "github.com/golang/mock/gomock" + "github.com/google/go-containerregistry/pkg/authn" "github.com/heroku/color" "github.com/sclevine/spec" "github.com/sclevine/spec/report" "github.com/buildpacks/pack/internal/builder" - ifakes "github.com/buildpacks/pack/internal/fakes" + "github.com/buildpacks/pack/pkg/image" "github.com/buildpacks/pack/pkg/logging" + "github.com/buildpacks/pack/pkg/testmocks" h "github.com/buildpacks/pack/testhelpers" ) @@ -26,21 +30,25 @@ func testCommon(t *testing.T, when spec.G, it spec.S) { subject *Client outBuf bytes.Buffer logger logging.Logger + keychain authn.Keychain runImageName string defaultRegistry string defaultMirror string gcrRegistry string gcrRunMirror string stackInfo builder.StackMetadata - accessChecker *ifakes.FakeAccessChecker assert = h.NewAssertionManager(t) + publish bool + err error ) it.Before(func() { logger = logging.NewLogWithWriters(&outBuf, &outBuf) - var err error - subject, err = NewClient(WithLogger(logger)) + keychain, err = auth.DefaultKeychain("pack-test/dummy") + h.AssertNil(t, err) + + subject, err = NewClient(WithLogger(logger), WithKeychain(keychain)) assert.Nil(err) defaultRegistry = "default.registry.io" @@ -56,46 +64,83 @@ func testCommon(t *testing.T, when spec.G, it spec.S) { }, }, } - accessChecker = ifakes.NewFakeAccessChecker() }) when("passed specific run image", func() { + it.Before(func() { + publish = false + }) + it("selects that run image", func() { runImgFlag := "flag/passed-run-image" - runImageName := subject.resolveRunImage(runImgFlag, defaultRegistry, "", stackInfo.RunImage, nil, false, accessChecker) + runImageName = subject.resolveRunImage(runImgFlag, defaultRegistry, "", stackInfo.RunImage, nil, publish) assert.Equal(runImageName, runImgFlag) }) }) when("publish is true", func() { - it("defaults to run-image in registry publishing to", func() { - runImageName := subject.resolveRunImage("", gcrRegistry, defaultRegistry, stackInfo.RunImage, nil, true, accessChecker) - assert.Equal(runImageName, gcrRunMirror) - }) + when("desirable run-image are accessible", func() { + it.Before(func() { + publish = true + mockFetcher := fetcherWithCheckReadAccess(t, publish, func(repo string) bool { + return true + }) + subject, err = NewClient(WithLogger(logger), WithKeychain(keychain), WithFetcher(mockFetcher)) + h.AssertNil(t, err) + }) - it("prefers config defined run image mirror to stack defined run image mirror", func() { - configMirrors := map[string][]string{ - runImageName: {defaultRegistry + "/unique-run-img"}, - } - runImageName := subject.resolveRunImage("", defaultRegistry, "", stackInfo.RunImage, configMirrors, true, accessChecker) - assert.NotEqual(runImageName, defaultMirror) - assert.Equal(runImageName, defaultRegistry+"/unique-run-img") + it("defaults to run-image in registry publishing to", func() { + runImageName = subject.resolveRunImage("", gcrRegistry, defaultRegistry, stackInfo.RunImage, nil, publish) + assert.Equal(runImageName, gcrRunMirror) + }) + + it("prefers config defined run image mirror to stack defined run image mirror", func() { + configMirrors := map[string][]string{ + runImageName: {defaultRegistry + "/unique-run-img"}, + } + runImageName = subject.resolveRunImage("", defaultRegistry, "", stackInfo.RunImage, configMirrors, publish) + assert.NotEqual(runImageName, defaultMirror) + assert.Equal(runImageName, defaultRegistry+"/unique-run-img") + }) + + it("returns a config mirror if no match to target registry", func() { + configMirrors := map[string][]string{ + runImageName: {defaultRegistry + "/unique-run-img"}, + } + runImageName = subject.resolveRunImage("", "test.registry.io", "", stackInfo.RunImage, configMirrors, publish) + assert.NotEqual(runImageName, defaultMirror) + assert.Equal(runImageName, defaultRegistry+"/unique-run-img") + }) }) - it("returns a config mirror if no match to target registry", func() { - configMirrors := map[string][]string{ - runImageName: {defaultRegistry + "/unique-run-img"}, - } - runImageName := subject.resolveRunImage("", "test.registry.io", "", stackInfo.RunImage, configMirrors, true, accessChecker) - assert.NotEqual(runImageName, defaultMirror) - assert.Equal(runImageName, defaultRegistry+"/unique-run-img") + when("desirable run-images are not accessible", func() { + it.Before(func() { + publish = true + mockFetcher := fetcherWithCheckReadAccess(t, publish, func(repo string) bool { + if repo == gcrRunMirror || repo == stackInfo.RunImage.Image { + return false + } + return true + }) + subject, err = NewClient(WithLogger(logger), WithKeychain(keychain), WithFetcher(mockFetcher)) + h.AssertNil(t, err) + }) + + it("selects the first accessible run-image", func() { + runImageName = subject.resolveRunImage("", gcrRegistry, defaultRegistry, stackInfo.RunImage, nil, publish) + assert.Equal(runImageName, defaultMirror) + }) }) }) // If publish is false, we are using the local daemon, and want to match to the builder registry when("publish is false", func() { + it.Before(func() { + publish = false + }) + it("defaults to run-image in registry publishing to", func() { - runImageName := subject.resolveRunImage("", gcrRegistry, defaultRegistry, stackInfo.RunImage, nil, false, accessChecker) + runImageName = subject.resolveRunImage("", gcrRegistry, defaultRegistry, stackInfo.RunImage, nil, publish) assert.Equal(runImageName, defaultMirror) assert.NotEqual(runImageName, gcrRunMirror) }) @@ -104,7 +149,7 @@ func testCommon(t *testing.T, when spec.G, it spec.S) { configMirrors := map[string][]string{ runImageName: {defaultRegistry + "/unique-run-img"}, } - runImageName := subject.resolveRunImage("", gcrRegistry, defaultRegistry, stackInfo.RunImage, configMirrors, false, accessChecker) + runImageName = subject.resolveRunImage("", gcrRegistry, defaultRegistry, stackInfo.RunImage, configMirrors, publish) assert.NotEqual(runImageName, defaultMirror) assert.Equal(runImageName, defaultRegistry+"/unique-run-img") }) @@ -113,49 +158,33 @@ func testCommon(t *testing.T, when spec.G, it spec.S) { configMirrors := map[string][]string{ runImageName: {defaultRegistry + "/unique-run-img"}, } - runImageName := subject.resolveRunImage("", defaultRegistry, "test.registry.io", stackInfo.RunImage, configMirrors, false, accessChecker) + runImageName = subject.resolveRunImage("", defaultRegistry, "test.registry.io", stackInfo.RunImage, configMirrors, publish) assert.NotEqual(runImageName, defaultMirror) assert.Equal(runImageName, defaultRegistry+"/unique-run-img") }) - }) - when("desirable run-image is not accessible", func() { - it.Before(func() { - accessChecker.RegistriesToFail = []string{ - gcrRunMirror, - stackInfo.RunImage.Image, - } - }) - - it.After(func() { - accessChecker.RegistriesToFail = nil - }) - - when("publish is true", func() { - it("selects the first accessible run-image", func() { - runImageName := subject.resolveRunImage("", gcrRegistry, defaultRegistry, stackInfo.RunImage, nil, true, accessChecker) - assert.Equal(runImageName, defaultMirror) - }) - }) - - when("publish is false", func() { + when("desirable run-image are empty", func() { it.Before(func() { stackInfo = builder.StackMetadata{ RunImage: builder.RunImageMetadata{ Image: "stack/run-image", }, } - accessChecker.RegistriesToFail = []string{ - stackInfo.RunImage.Image, - } }) - it("selects the given run-image", func() { + it("selects the builder run-image", func() { // issue: https://github.com/buildpacks/pack/issues/2078 - runImageName := subject.resolveRunImage("", "", "", stackInfo.RunImage, nil, false, accessChecker) + runImageName = subject.resolveRunImage("", "", "", stackInfo.RunImage, nil, publish) assert.Equal(runImageName, "stack/run-image") }) }) }) }) } + +func fetcherWithCheckReadAccess(t *testing.T, publish bool, checker image.CheckReadAccess) *testmocks.MockImageFetcher { + mockController := gomock.NewController(t) + mockFetcher := testmocks.NewMockImageFetcher(mockController) + mockFetcher.EXPECT().CheckReadAccessValidator(image.FetchOptions{Daemon: !publish}).Return(checker) + return mockFetcher +} diff --git a/pkg/client/example_fetcher_test.go b/pkg/client/example_fetcher_test.go index e8cf56ce65..246302f596 100644 --- a/pkg/client/example_fetcher_test.go +++ b/pkg/client/example_fetcher_test.go @@ -53,3 +53,9 @@ func (f *fetcher) Fetch(_ context.Context, imageName string, _ image.FetchOption fmt.Println("custom fetcher called") return nil, errors.New("not implemented") } + +func (f *fetcher) CheckReadAccessValidator(options image.FetchOptions) image.CheckReadAccess { + return func(_ string) bool { + return true + } +} diff --git a/pkg/client/rebase.go b/pkg/client/rebase.go index f493f6184a..c5fb7d946b 100644 --- a/pkg/client/rebase.go +++ b/pkg/client/rebase.go @@ -105,7 +105,6 @@ func (c *Client) Rebase(ctx context.Context, opts RebaseOptions) error { runImageMD, opts.AdditionalMirrors, opts.Publish, - c.accessChecker, ) if runImageName == "" { diff --git a/pkg/client/rebase_test.go b/pkg/client/rebase_test.go index ba6a9df86b..7ceff08df2 100644 --- a/pkg/client/rebase_test.go +++ b/pkg/client/rebase_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/buildpacks/imgutil/fakes" + "github.com/buildpacks/lifecycle/auth" "github.com/heroku/color" "github.com/sclevine/spec" "github.com/sclevine/spec/report" @@ -28,7 +29,6 @@ func testRebase(t *testing.T, when spec.G, it spec.S) { when("#Rebase", func() { var ( fakeImageFetcher *ifakes.FakeImageFetcher - fakeAccessChecker *ifakes.FakeAccessChecker subject *Client fakeAppImage *fakes.Image fakeRunImage *fakes.Image @@ -38,7 +38,6 @@ func testRebase(t *testing.T, when spec.G, it spec.S) { it.Before(func() { fakeImageFetcher = ifakes.NewFakeImageFetcher() - fakeAccessChecker = ifakes.NewFakeAccessChecker() fakeAppImage = fakes.NewImage("some/app", "", &fakeIdentifier{name: "app-image"}) h.AssertNil(t, fakeAppImage.SetLabel("io.buildpacks.lifecycle.metadata", @@ -54,11 +53,14 @@ func testRebase(t *testing.T, when spec.G, it spec.S) { h.AssertNil(t, fakeRunImageMirror.SetLabel("io.buildpacks.stack.id", "io.buildpacks.stacks.jammy")) fakeImageFetcher.LocalImages["example.com/some/run"] = fakeRunImageMirror + keychain, err := auth.DefaultKeychain("pack-test/dummy") + h.AssertNil(t, err) + fakeLogger := logging.NewLogWithWriters(&out, &out) subject = &Client{ - logger: fakeLogger, - imageFetcher: fakeImageFetcher, - accessChecker: fakeAccessChecker, + logger: fakeLogger, + imageFetcher: fakeImageFetcher, + keychain: keychain, } }) diff --git a/pkg/image/access_checker.go b/pkg/image/access_checker.go deleted file mode 100644 index 50401a104f..0000000000 --- a/pkg/image/access_checker.go +++ /dev/null @@ -1,46 +0,0 @@ -package image - -import ( - "github.com/buildpacks/imgutil/remote" - "github.com/google/go-containerregistry/pkg/authn" - - "github.com/buildpacks/pack/pkg/logging" -) - -type Checker struct { - logger logging.Logger - keychain authn.Keychain -} - -func NewAccessChecker(logger logging.Logger, keychain authn.Keychain) *Checker { - checker := &Checker{ - logger: logger, - keychain: keychain, - } - - if checker.keychain == nil { - checker.keychain = authn.DefaultKeychain - } - - return checker -} - -func (c *Checker) Check(repo string, publish bool) bool { - if !publish { - // nop checker, we are running against the daemon - return true - } - - img, err := remote.NewImage(repo, c.keychain) - if err != nil { - return false - } - - if ok, err := img.CheckReadAccess(); ok { - c.logger.Debugf("CheckReadAccess succeeded for the run image %s", repo) - return true - } else { - c.logger.Debugf("CheckReadAccess failed for the run image %s, error: %s", repo, err.Error()) - return false - } -} diff --git a/pkg/image/access_checker_test.go b/pkg/image/access_checker_test.go deleted file mode 100644 index d16de8b22a..0000000000 --- a/pkg/image/access_checker_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package image_test - -import ( - "bytes" - "testing" - - "github.com/buildpacks/lifecycle/auth" - "github.com/sclevine/spec" - "github.com/sclevine/spec/report" - - "github.com/buildpacks/pack/pkg/image" - "github.com/buildpacks/pack/pkg/logging" - h "github.com/buildpacks/pack/testhelpers" -) - -func TestChecker(t *testing.T) { - spec.Run(t, "Checker", testChecker, spec.Report(report.Terminal{})) -} - -func testChecker(t *testing.T, when spec.G, it spec.S) { - var publish bool - - when("#Check", func() { - when("publish is false", func() { - it.Before(func() { - publish = false - }) - - // issue: https://github.com/buildpacks/pack/issues/2078 - it("returns true", func() { - buf := &bytes.Buffer{} - keychain, err := auth.DefaultKeychain("pack-test/dummy") - h.AssertNil(t, err) - - ic := image.NewAccessChecker(logging.NewSimpleLogger(buf), keychain) - h.AssertTrue(t, ic.Check("pack.test/dummy", publish)) - }) - }) - - when("publish is true", func() { - it.Before(func() { - publish = true - }) - - it("fails when checking dummy image", func() { - buf := &bytes.Buffer{} - keychain, err := auth.DefaultKeychain("pack.test/dummy") - h.AssertNil(t, err) - - ic := image.NewAccessChecker(logging.NewSimpleLogger(buf), keychain) - - h.AssertFalse(t, ic.Check("pack.test/dummy", publish)) - h.AssertContains(t, buf.String(), "DEBUG: CheckReadAccess failed for the run image pack.test/dummy") - }) - }) - }) -} diff --git a/pkg/image/fetcher.go b/pkg/image/fetcher.go index 60548fcc1d..e9958653c6 100644 --- a/pkg/image/fetcher.go +++ b/pkg/image/fetcher.go @@ -53,6 +53,9 @@ type DockerClient interface { ImagePull(ctx context.Context, ref string, options types.ImagePullOptions) (io.ReadCloser, error) } +// CheckReadAccess is a method for checking remote images for read access +type CheckReadAccess func(repo string) bool + type Fetcher struct { docker DockerClient logger logging.Logger @@ -123,6 +126,27 @@ func (f *Fetcher) Fetch(ctx context.Context, name string, options FetchOptions) return f.fetchDaemonImage(name) } +func (f *Fetcher) CheckReadAccessValidator(options FetchOptions) CheckReadAccess { + return func(repo string) bool { + if !options.Daemon && (options.LayoutOption == LayoutOption{}) { + // remote access checker + img, err := remote.NewImage(repo, f.keychain) + if err != nil { + return false + } + if ok, err := img.CheckReadAccess(); ok { + f.logger.Debugf("CheckReadAccess succeeded for the run image %s", repo) + return true + } else { + f.logger.Debugf("CheckReadAccess failed for the run image %s, error: %s", repo, err.Error()) + return false + } + } + // no-op + return true + } +} + func (f *Fetcher) fetchDaemonImage(name string) (imgutil.Image, error) { image, err := local.NewImage(name, f.docker, local.FromBaseImage(name)) if err != nil { diff --git a/pkg/image/fetcher_test.go b/pkg/image/fetcher_test.go index 3b119e15f3..e12c859f92 100644 --- a/pkg/image/fetcher_test.go +++ b/pkg/image/fetcher_test.go @@ -10,7 +10,6 @@ import ( "testing" "github.com/buildpacks/imgutil" - "github.com/buildpacks/imgutil/local" "github.com/buildpacks/imgutil/remote" "github.com/docker/docker/client" @@ -42,7 +41,7 @@ func TestFetcher(t *testing.T) { var err error docker, err = client.NewClientWithOpts(client.FromEnv, client.WithVersion("1.38")) h.AssertNil(t, err) - spec.Run(t, "Fetcher", testFetcher, spec.Report(report.Terminal{})) + spec.Run(t, "Fetcher", testFetcher, spec.Parallel(), spec.Report(report.Terminal{})) } func testFetcher(t *testing.T, when spec.G, it spec.S) { @@ -57,7 +56,7 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { it.Before(func() { repo = "some-org/" + h.RandString(10) repoName = registryConfig.RepoName(repo) - imageFetcher = image.NewFetcher(logging.NewLogWithWriters(&outBuf, &outBuf), docker) + imageFetcher = image.NewFetcher(logging.NewLogWithWriters(&outBuf, &outBuf, logging.WithVerbose()), docker) info, err := docker.Info(context.TODO()) h.AssertNil(t, err) @@ -404,4 +403,47 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { }) }) }) + + when("#CheckReadAccessValidator", func() { + var daemon bool + + when("Daemon is true", func() { + it.Before(func() { + daemon = true + }) + + it("read access is always valid", func() { + accessChecker := imageFetcher.CheckReadAccessValidator(image.FetchOptions{Daemon: daemon}) + h.AssertTrue(t, accessChecker("pack.test/dummy")) + }) + }) + + when("Daemon is false", func() { + it.Before(func() { + daemon = false + }) + + when("remote image doesn't exists", func() { + it("fails when checking dummy image", func() { + accessChecker := imageFetcher.CheckReadAccessValidator(image.FetchOptions{Daemon: daemon}) + h.AssertFalse(t, accessChecker("pack.test/dummy")) + h.AssertContains(t, outBuf.String(), "CheckReadAccess failed for the run image pack.test/dummy") + }) + }) + + when("remote image exists", func() { + it.Before(func() { + img, err := remote.NewImage(repoName, authn.DefaultKeychain) + h.AssertNil(t, err) + h.AssertNil(t, img.Save()) + }) + + it("read access is valid", func() { + accessChecker := imageFetcher.CheckReadAccessValidator(image.FetchOptions{Daemon: daemon}) + h.AssertTrue(t, accessChecker(repoName)) + h.AssertContains(t, outBuf.String(), fmt.Sprintf("CheckReadAccess succeeded for the run image %s", repoName)) + }) + }) + }) + }) } diff --git a/pkg/testmocks/mock_image_fetcher.go b/pkg/testmocks/mock_image_fetcher.go index 281f28d04d..11177db224 100644 --- a/pkg/testmocks/mock_image_fetcher.go +++ b/pkg/testmocks/mock_image_fetcher.go @@ -37,6 +37,20 @@ func (m *MockImageFetcher) EXPECT() *MockImageFetcherMockRecorder { return m.recorder } +// CheckReadAccessValidator mocks base method. +func (m *MockImageFetcher) CheckReadAccessValidator(arg0 image.FetchOptions) image.CheckReadAccess { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CheckReadAccessValidator", arg0) + ret0, _ := ret[0].(image.CheckReadAccess) + return ret0 +} + +// CheckReadAccessValidator indicates an expected call of CheckReadAccessValidator. +func (mr *MockImageFetcherMockRecorder) CheckReadAccessValidator(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckReadAccessValidator", reflect.TypeOf((*MockImageFetcher)(nil).CheckReadAccessValidator), arg0) +} + // Fetch mocks base method. func (m *MockImageFetcher) Fetch(arg0 context.Context, arg1 string, arg2 image.FetchOptions) (imgutil.Image, error) { m.ctrl.T.Helper() From 56bcbce94cc180a4b2a867151b362b1dadc15697 Mon Sep 17 00:00:00 2001 From: Juan Bustamante Date: Mon, 8 Apr 2024 14:54:07 -0500 Subject: [PATCH 09/18] Adding Pull Policy into the logic to detect read access Signed-off-by: Juan Bustamante --- internal/builder/image_fetcher_wrapper.go | 13 ++- internal/fakes/fake_image_fetcher.go | 6 +- pkg/buildpack/downloader.go | 2 +- pkg/client/build.go | 4 +- pkg/client/client.go | 8 +- pkg/client/common.go | 15 ++- pkg/client/common_test.go | 129 ++++++++-------------- pkg/client/example_fetcher_test.go | 6 +- pkg/client/rebase.go | 14 ++- pkg/image/fetcher.go | 45 ++++---- pkg/image/fetcher_test.go | 57 ++++++++-- pkg/testmocks/mock_image_fetcher.go | 10 +- 12 files changed, 170 insertions(+), 139 deletions(-) diff --git a/internal/builder/image_fetcher_wrapper.go b/internal/builder/image_fetcher_wrapper.go index 613a9647d4..61ec4d40b5 100644 --- a/internal/builder/image_fetcher_wrapper.go +++ b/internal/builder/image_fetcher_wrapper.go @@ -13,7 +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) - CheckReadAccessValidator(options image.FetchOptions) image.CheckReadAccess + + // CheckReadAccessValidator verifies if an image accessible with read permissions + // When FetchOptions.Daemon is true and the image doesn't exist in the daemon, + // the behavior is dictated by the pullPolicy, 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. + CheckReadAccessValidator(repo string, options image.FetchOptions) bool } type ImageFetcherWrapper struct { @@ -34,6 +41,6 @@ func (w *ImageFetcherWrapper) Fetch( return w.fetcher.Fetch(ctx, name, options) } -func (w *ImageFetcherWrapper) CheckReadAccessValidator(options image.FetchOptions) image.CheckReadAccess { - return w.fetcher.CheckReadAccessValidator(options) +func (w *ImageFetcherWrapper) CheckReadAccessValidator(repo string, options image.FetchOptions) bool { + return w.fetcher.CheckReadAccessValidator(repo, options) } diff --git a/internal/fakes/fake_image_fetcher.go b/internal/fakes/fake_image_fetcher.go index e95ce824bc..e2c21722bf 100644 --- a/internal/fakes/fake_image_fetcher.go +++ b/internal/fakes/fake_image_fetcher.go @@ -55,10 +55,8 @@ func (f *FakeImageFetcher) Fetch(ctx context.Context, name string, options image return ri, nil } -func (f *FakeImageFetcher) CheckReadAccessValidator(_ image.FetchOptions) image.CheckReadAccess { - return func(_ string) bool { - return true - } +func (f *FakeImageFetcher) CheckReadAccessValidator(_ string, _ image.FetchOptions) bool { + return true } func shouldPull(localFound, remoteFound bool, policy image.PullPolicy) bool { diff --git a/pkg/buildpack/downloader.go b/pkg/buildpack/downloader.go index 45930342ed..91cd597815 100644 --- a/pkg/buildpack/downloader.go +++ b/pkg/buildpack/downloader.go @@ -29,7 +29,7 @@ type Logger interface { type ImageFetcher interface { Fetch(ctx context.Context, name string, options image.FetchOptions) (imgutil.Image, error) - CheckReadAccessValidator(options image.FetchOptions) image.CheckReadAccess + CheckReadAccessValidator(repo string, options image.FetchOptions) bool } type Downloader interface { diff --git a/pkg/client/build.go b/pkg/client/build.go index da58f580fe..43c82e0196 100644 --- a/pkg/client/build.go +++ b/pkg/client/build.go @@ -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) - 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 { diff --git a/pkg/client/client.go b/pkg/client/client.go index 97fa306fa3..8d0272d2ef 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -53,7 +53,13 @@ type ImageFetcher interface { // 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) - CheckReadAccessValidator(options image.FetchOptions) image.CheckReadAccess + // CheckReadAccessValidator 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 pullPolicy, 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. + CheckReadAccessValidator(repo string, options image.FetchOptions) bool } //go:generate mockgen -package testmocks -destination ../testmocks/mock_blob_downloader.go github.com/buildpacks/pack/pkg/client BlobDownloader diff --git a/pkg/client/common.go b/pkg/client/common.go index d23cb2e957..8ca77edd0e 100644 --- a/pkg/client/common.go +++ b/pkg/client/common.go @@ -29,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) 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 @@ -45,9 +45,8 @@ func (c *Client) resolveRunImage(runImage, imgRegistry, bldrRegistry string, run runImageMetadata.Image, runImageMetadata.Mirrors, additionalMirrors[runImageMetadata.Image], - c.imageFetcher.CheckReadAccessValidator(image.FetchOptions{ - Daemon: !publish, - }), + c.imageFetcher, + options, ) switch { @@ -111,8 +110,8 @@ func contains(slc []string, v string) bool { return false } -func getBestRunMirror(registry string, runImage string, mirrors []string, preferredMirrors []string, accessChecker image.CheckReadAccess) 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 { @@ -130,11 +129,11 @@ func getBestRunMirror(registry string, runImage string, mirrors []string, prefer return runImage } -func filterImageList(imageList []string, accessChecker image.CheckReadAccess) []string { +func filterImageList(imageList []string, fetcher ImageFetcher, options image.FetchOptions) []string { var accessibleImages []string for i, img := range imageList { - if accessChecker(img) { + if fetcher.CheckReadAccessValidator(img, options) { accessibleImages = append(accessibleImages, imageList[i]) } } diff --git a/pkg/client/common_test.go b/pkg/client/common_test.go index 09719f6199..baa4f0b645 100644 --- a/pkg/client/common_test.go +++ b/pkg/client/common_test.go @@ -73,83 +73,31 @@ func testCommon(t *testing.T, when spec.G, it spec.S) { it("selects that run image", func() { runImgFlag := "flag/passed-run-image" - runImageName = subject.resolveRunImage(runImgFlag, defaultRegistry, "", stackInfo.RunImage, nil, publish) + runImageName = subject.resolveRunImage(runImgFlag, defaultRegistry, "", stackInfo.RunImage, nil, publish, image.FetchOptions{Daemon: !publish, PullPolicy: image.PullAlways}) assert.Equal(runImageName, runImgFlag) }) }) - when("publish is true", func() { - when("desirable run-image are accessible", func() { - it.Before(func() { - publish = true - mockFetcher := fetcherWithCheckReadAccess(t, publish, func(repo string) bool { - return true - }) - subject, err = NewClient(WithLogger(logger), WithKeychain(keychain), WithFetcher(mockFetcher)) - h.AssertNil(t, err) - }) - - it("defaults to run-image in registry publishing to", func() { - runImageName = subject.resolveRunImage("", gcrRegistry, defaultRegistry, stackInfo.RunImage, nil, publish) - assert.Equal(runImageName, gcrRunMirror) - }) - - it("prefers config defined run image mirror to stack defined run image mirror", func() { - configMirrors := map[string][]string{ - runImageName: {defaultRegistry + "/unique-run-img"}, - } - runImageName = subject.resolveRunImage("", defaultRegistry, "", stackInfo.RunImage, configMirrors, publish) - assert.NotEqual(runImageName, defaultMirror) - assert.Equal(runImageName, defaultRegistry+"/unique-run-img") - }) - - it("returns a config mirror if no match to target registry", func() { - configMirrors := map[string][]string{ - runImageName: {defaultRegistry + "/unique-run-img"}, - } - runImageName = subject.resolveRunImage("", "test.registry.io", "", stackInfo.RunImage, configMirrors, publish) - assert.NotEqual(runImageName, defaultMirror) - assert.Equal(runImageName, defaultRegistry+"/unique-run-img") - }) - }) - - when("desirable run-images are not accessible", func() { - it.Before(func() { - publish = true - mockFetcher := fetcherWithCheckReadAccess(t, publish, func(repo string) bool { - if repo == gcrRunMirror || repo == stackInfo.RunImage.Image { - return false - } - return true - }) - subject, err = NewClient(WithLogger(logger), WithKeychain(keychain), WithFetcher(mockFetcher)) - h.AssertNil(t, err) - }) - - it("selects the first accessible run-image", func() { - runImageName = subject.resolveRunImage("", gcrRegistry, defaultRegistry, stackInfo.RunImage, nil, publish) - assert.Equal(runImageName, defaultMirror) - }) - }) - }) - - // If publish is false, we are using the local daemon, and want to match to the builder registry - when("publish is false", func() { + when("desirable run-image are accessible", func() { it.Before(func() { - publish = false + publish = true + mockController := gomock.NewController(t) + mockFetcher := testmocks.NewMockImageFetcher(mockController) + mockFetcher.EXPECT().CheckReadAccessValidator(gomock.Any(), gomock.Any()).Return(true).AnyTimes() + subject, err = NewClient(WithLogger(logger), WithKeychain(keychain), WithFetcher(mockFetcher)) + h.AssertNil(t, err) }) it("defaults to run-image in registry publishing to", func() { - runImageName = subject.resolveRunImage("", gcrRegistry, defaultRegistry, stackInfo.RunImage, nil, publish) - assert.Equal(runImageName, defaultMirror) - assert.NotEqual(runImageName, gcrRunMirror) + runImageName = subject.resolveRunImage("", gcrRegistry, defaultRegistry, stackInfo.RunImage, nil, publish, image.FetchOptions{}) + assert.Equal(runImageName, gcrRunMirror) }) it("prefers config defined run image mirror to stack defined run image mirror", func() { configMirrors := map[string][]string{ runImageName: {defaultRegistry + "/unique-run-img"}, } - runImageName = subject.resolveRunImage("", gcrRegistry, defaultRegistry, stackInfo.RunImage, configMirrors, publish) + runImageName = subject.resolveRunImage("", defaultRegistry, "", stackInfo.RunImage, configMirrors, publish, image.FetchOptions{}) assert.NotEqual(runImageName, defaultMirror) assert.Equal(runImageName, defaultRegistry+"/unique-run-img") }) @@ -158,33 +106,54 @@ func testCommon(t *testing.T, when spec.G, it spec.S) { configMirrors := map[string][]string{ runImageName: {defaultRegistry + "/unique-run-img"}, } - runImageName = subject.resolveRunImage("", defaultRegistry, "test.registry.io", stackInfo.RunImage, configMirrors, publish) + runImageName = subject.resolveRunImage("", "test.registry.io", "", stackInfo.RunImage, configMirrors, publish, image.FetchOptions{}) assert.NotEqual(runImageName, defaultMirror) assert.Equal(runImageName, defaultRegistry+"/unique-run-img") }) + }) + + when("desirable run-images are not accessible", func() { + it.Before(func() { + publish = true + + mockController := gomock.NewController(t) + mockFetcher := testmocks.NewMockImageFetcher(mockController) + mockFetcher.EXPECT().CheckReadAccessValidator(gcrRunMirror, gomock.Any()).Return(false) + mockFetcher.EXPECT().CheckReadAccessValidator(stackInfo.RunImage.Image, gomock.Any()).Return(false) + mockFetcher.EXPECT().CheckReadAccessValidator(defaultMirror, gomock.Any()).Return(true) + + subject, err = NewClient(WithLogger(logger), WithKeychain(keychain), WithFetcher(mockFetcher)) + h.AssertNil(t, err) + }) + + it("selects the first accessible run-image", func() { + runImageName = subject.resolveRunImage("", gcrRegistry, defaultRegistry, stackInfo.RunImage, nil, publish, image.FetchOptions{}) + assert.Equal(runImageName, defaultMirror) + }) + }) + + when("desirable run-image are empty", func() { + it.Before(func() { + publish = false + stackInfo = builder.StackMetadata{ + RunImage: builder.RunImageMetadata{ + Image: "stack/run-image", + }, + } + }) - when("desirable run-image are empty", func() { - it.Before(func() { - stackInfo = builder.StackMetadata{ - RunImage: builder.RunImageMetadata{ - Image: "stack/run-image", - }, - } - }) - - it("selects the builder run-image", func() { - // issue: https://github.com/buildpacks/pack/issues/2078 - runImageName = subject.resolveRunImage("", "", "", stackInfo.RunImage, nil, publish) - assert.Equal(runImageName, "stack/run-image") - }) + it("selects the builder run-image", func() { + // issue: https://github.com/buildpacks/pack/issues/2078 + runImageName = subject.resolveRunImage("", "", "", stackInfo.RunImage, nil, publish, image.FetchOptions{}) + assert.Equal(runImageName, "stack/run-image") }) }) }) } -func fetcherWithCheckReadAccess(t *testing.T, publish bool, checker image.CheckReadAccess) *testmocks.MockImageFetcher { +func fetcherWithCheckReadAccess(t *testing.T, publish bool, value bool) *testmocks.MockImageFetcher { mockController := gomock.NewController(t) mockFetcher := testmocks.NewMockImageFetcher(mockController) - mockFetcher.EXPECT().CheckReadAccessValidator(image.FetchOptions{Daemon: !publish}).Return(checker) + mockFetcher.EXPECT().CheckReadAccessValidator(gomock.Any(), image.FetchOptions{Daemon: !publish}).Return(value).AnyTimes() return mockFetcher } diff --git a/pkg/client/example_fetcher_test.go b/pkg/client/example_fetcher_test.go index 246302f596..12a1b65f10 100644 --- a/pkg/client/example_fetcher_test.go +++ b/pkg/client/example_fetcher_test.go @@ -54,8 +54,6 @@ func (f *fetcher) Fetch(_ context.Context, imageName string, _ image.FetchOption return nil, errors.New("not implemented") } -func (f *fetcher) CheckReadAccessValidator(options image.FetchOptions) image.CheckReadAccess { - return func(_ string) bool { - return true - } +func (f *fetcher) CheckReadAccessValidator(_ string, _ FetchOptions) bool { + return true } diff --git a/pkg/client/rebase.go b/pkg/client/rebase.go index c5fb7d946b..3d7e6532da 100644 --- a/pkg/client/rebase.go +++ b/pkg/client/rebase.go @@ -98,6 +98,13 @@ func (c *Client) Rebase(ctx context.Context, opts RebaseOptions) error { Mirrors: md.Stack.RunImage.Mirrors, } } + + fetchOptions := image.FetchOptions{ + Daemon: !opts.Publish, + PullPolicy: opts.PullPolicy, + Platform: fmt.Sprintf("%s/%s", appOS, appArch), + } + runImageName := c.resolveRunImage( opts.RunImage, imageRef.Context().RegistryStr(), @@ -105,17 +112,14 @@ func (c *Client) Rebase(ctx context.Context, opts RebaseOptions) error { runImageMD, opts.AdditionalMirrors, opts.Publish, + fetchOptions, ) if runImageName == "" { return errors.New("run image must be specified") } - baseImage, err := c.imageFetcher.Fetch(ctx, runImageName, image.FetchOptions{ - Daemon: !opts.Publish, - PullPolicy: opts.PullPolicy, - Platform: fmt.Sprintf("%s/%s", appOS, appArch), - }) + baseImage, err := c.imageFetcher.Fetch(ctx, runImageName, fetchOptions) if err != nil { return err } diff --git a/pkg/image/fetcher.go b/pkg/image/fetcher.go index e9958653c6..2e941e3ce1 100644 --- a/pkg/image/fetcher.go +++ b/pkg/image/fetcher.go @@ -53,9 +53,6 @@ type DockerClient interface { ImagePull(ctx context.Context, ref string, options types.ImagePullOptions) (io.ReadCloser, error) } -// CheckReadAccess is a method for checking remote images for read access -type CheckReadAccess func(repo string) bool - type Fetcher struct { docker DockerClient logger logging.Logger @@ -126,24 +123,34 @@ func (f *Fetcher) Fetch(ctx context.Context, name string, options FetchOptions) return f.fetchDaemonImage(name) } -func (f *Fetcher) CheckReadAccessValidator(options FetchOptions) CheckReadAccess { - return func(repo string) bool { - if !options.Daemon && (options.LayoutOption == LayoutOption{}) { - // remote access checker - img, err := remote.NewImage(repo, f.keychain) - if err != nil { - return false - } - if ok, err := img.CheckReadAccess(); ok { - f.logger.Debugf("CheckReadAccess succeeded for the run image %s", repo) - return true - } else { - f.logger.Debugf("CheckReadAccess failed for the run image %s, error: %s", repo, err.Error()) - return false - } +func (f *Fetcher) CheckReadAccessValidator(repo string, options FetchOptions) bool { + if !options.Daemon { + return f.checkRemoteReadAccess(repo) + } + if _, err := f.fetchDaemonImage(repo); err != nil { + // Image doesn't exist in the daemon + // Pull Never: should failed + // Pull Always or Pull If Not Present: need to check the registry + if options.PullPolicy == PullNever { + return false } - // no-op + return f.checkRemoteReadAccess(repo) + } + // no-op + return true +} + +func (f *Fetcher) checkRemoteReadAccess(repo string) bool { + img, err := remote.NewImage(repo, f.keychain) + if err != nil { + return false + } + if ok, err := img.CheckReadAccess(); ok { + f.logger.Debugf("CheckReadAccess succeeded for the run image %s", repo) return true + } else { + f.logger.Debugf("CheckReadAccess failed for the run image %s, error: %s", repo, err.Error()) + return false } } diff --git a/pkg/image/fetcher_test.go b/pkg/image/fetcher_test.go index e12c859f92..f07598a489 100644 --- a/pkg/image/fetcher_test.go +++ b/pkg/image/fetcher_test.go @@ -412,9 +412,54 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { daemon = true }) - it("read access is always valid", func() { - accessChecker := imageFetcher.CheckReadAccessValidator(image.FetchOptions{Daemon: daemon}) - h.AssertTrue(t, accessChecker("pack.test/dummy")) + when("image exists only in the daemon", func() { + it.Before(func() { + img, err := local.NewImage("pack.test/dummy", docker) + h.AssertNil(t, err) + h.AssertNil(t, img.Save()) + }) + when("PullAlways", func() { + it("read access must be true", func() { + h.AssertTrue(t, imageFetcher.CheckReadAccessValidator("pack.test/dummy", image.FetchOptions{Daemon: daemon, PullPolicy: image.PullAlways})) + }) + }) + + when("PullNever", func() { + it("read access must be true", func() { + h.AssertTrue(t, imageFetcher.CheckReadAccessValidator("pack.test/dummy", image.FetchOptions{Daemon: daemon, PullPolicy: image.PullNever})) + }) + }) + + when("PullIfNotPresent", func() { + it("read access must be true", func() { + h.AssertTrue(t, imageFetcher.CheckReadAccessValidator("pack.test/dummy", image.FetchOptions{Daemon: daemon, PullPolicy: image.PullIfNotPresent})) + }) + }) + }) + + when("image doesn't exist in the daemon but in remote", func() { + it.Before(func() { + img, err := remote.NewImage(repoName, authn.DefaultKeychain) + h.AssertNil(t, err) + h.AssertNil(t, img.Save()) + }) + when("PullAlways", func() { + it("read access must be true", func() { + h.AssertTrue(t, imageFetcher.CheckReadAccessValidator(repoName, image.FetchOptions{Daemon: daemon, PullPolicy: image.PullAlways})) + }) + }) + + when("PullNever", func() { + it("read access must be false", func() { + h.AssertFalse(t, imageFetcher.CheckReadAccessValidator(repoName, image.FetchOptions{Daemon: daemon, PullPolicy: image.PullNever})) + }) + }) + + when("PullIfNotPresent", func() { + it("read access must be true", func() { + h.AssertTrue(t, imageFetcher.CheckReadAccessValidator(repoName, image.FetchOptions{Daemon: daemon, PullPolicy: image.PullIfNotPresent})) + }) + }) }) }) @@ -425,8 +470,7 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { when("remote image doesn't exists", func() { it("fails when checking dummy image", func() { - accessChecker := imageFetcher.CheckReadAccessValidator(image.FetchOptions{Daemon: daemon}) - h.AssertFalse(t, accessChecker("pack.test/dummy")) + h.AssertFalse(t, imageFetcher.CheckReadAccessValidator("pack.test/dummy", image.FetchOptions{Daemon: daemon})) h.AssertContains(t, outBuf.String(), "CheckReadAccess failed for the run image pack.test/dummy") }) }) @@ -439,8 +483,7 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { }) it("read access is valid", func() { - accessChecker := imageFetcher.CheckReadAccessValidator(image.FetchOptions{Daemon: daemon}) - h.AssertTrue(t, accessChecker(repoName)) + h.AssertTrue(t, imageFetcher.CheckReadAccessValidator(repoName, image.FetchOptions{Daemon: daemon})) h.AssertContains(t, outBuf.String(), fmt.Sprintf("CheckReadAccess succeeded for the run image %s", repoName)) }) }) diff --git a/pkg/testmocks/mock_image_fetcher.go b/pkg/testmocks/mock_image_fetcher.go index 11177db224..02bb715041 100644 --- a/pkg/testmocks/mock_image_fetcher.go +++ b/pkg/testmocks/mock_image_fetcher.go @@ -38,17 +38,17 @@ func (m *MockImageFetcher) EXPECT() *MockImageFetcherMockRecorder { } // CheckReadAccessValidator mocks base method. -func (m *MockImageFetcher) CheckReadAccessValidator(arg0 image.FetchOptions) image.CheckReadAccess { +func (m *MockImageFetcher) CheckReadAccessValidator(arg0 string, arg1 image.FetchOptions) bool { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CheckReadAccessValidator", arg0) - ret0, _ := ret[0].(image.CheckReadAccess) + ret := m.ctrl.Call(m, "CheckReadAccessValidator", arg0, arg1) + ret0, _ := ret[0].(bool) return ret0 } // CheckReadAccessValidator indicates an expected call of CheckReadAccessValidator. -func (mr *MockImageFetcherMockRecorder) CheckReadAccessValidator(arg0 interface{}) *gomock.Call { +func (mr *MockImageFetcherMockRecorder) CheckReadAccessValidator(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckReadAccessValidator", reflect.TypeOf((*MockImageFetcher)(nil).CheckReadAccessValidator), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckReadAccessValidator", reflect.TypeOf((*MockImageFetcher)(nil).CheckReadAccessValidator), arg0, arg1) } // Fetch mocks base method. From bcc4a5fc2a933301cb6879d8f680dabd48017b52 Mon Sep 17 00:00:00 2001 From: Juan Bustamante Date: Tue, 9 Apr 2024 09:57:15 -0500 Subject: [PATCH 10/18] Removing unused method Signed-off-by: Juan Bustamante --- pkg/client/common_test.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/pkg/client/common_test.go b/pkg/client/common_test.go index baa4f0b645..9a14ed0c24 100644 --- a/pkg/client/common_test.go +++ b/pkg/client/common_test.go @@ -150,10 +150,3 @@ func testCommon(t *testing.T, when spec.G, it spec.S) { }) }) } - -func fetcherWithCheckReadAccess(t *testing.T, publish bool, value bool) *testmocks.MockImageFetcher { - mockController := gomock.NewController(t) - mockFetcher := testmocks.NewMockImageFetcher(mockController) - mockFetcher.EXPECT().CheckReadAccessValidator(gomock.Any(), image.FetchOptions{Daemon: !publish}).Return(value).AnyTimes() - return mockFetcher -} From a9bb1ca905c40ae1e71e5d0753b8a47991e08884 Mon Sep 17 00:00:00 2001 From: Juan Bustamante Date: Mon, 15 Apr 2024 15:02:49 -0500 Subject: [PATCH 11/18] renaming method interface to CheckReadAccess and adding some tests cases Signed-off-by: Juan Bustamante --- internal/builder/image_fetcher_wrapper.go | 6 +-- internal/fakes/fake_image_fetcher.go | 2 +- pkg/buildpack/downloader.go | 2 +- pkg/client/client.go | 4 +- pkg/client/common.go | 2 +- pkg/client/example_fetcher_test.go | 2 +- pkg/image/fetcher.go | 21 +++++++---- pkg/image/fetcher_test.go | 46 ++++++++++++++++++----- pkg/testmocks/mock_image_fetcher.go | 6 +-- 9 files changed, 61 insertions(+), 30 deletions(-) diff --git a/internal/builder/image_fetcher_wrapper.go b/internal/builder/image_fetcher_wrapper.go index 61ec4d40b5..71fbebf54d 100644 --- a/internal/builder/image_fetcher_wrapper.go +++ b/internal/builder/image_fetcher_wrapper.go @@ -14,13 +14,13 @@ type ImageFetcher interface { // attempt to pull a remote image first. Fetch(ctx context.Context, name string, options image.FetchOptions) (imgutil.Image, error) - // CheckReadAccessValidator verifies if an image accessible with read permissions + // CheckReadAccess verifies if an image accessible with read permissions // When FetchOptions.Daemon is true and the image doesn't exist in the daemon, // the behavior is dictated by the pullPolicy, 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. - CheckReadAccessValidator(repo string, options image.FetchOptions) bool + CheckReadAccess(repo string, options image.FetchOptions) bool } type ImageFetcherWrapper struct { @@ -42,5 +42,5 @@ func (w *ImageFetcherWrapper) Fetch( } func (w *ImageFetcherWrapper) CheckReadAccessValidator(repo string, options image.FetchOptions) bool { - return w.fetcher.CheckReadAccessValidator(repo, options) + return w.fetcher.CheckReadAccess(repo, options) } diff --git a/internal/fakes/fake_image_fetcher.go b/internal/fakes/fake_image_fetcher.go index e2c21722bf..9e09ecfde2 100644 --- a/internal/fakes/fake_image_fetcher.go +++ b/internal/fakes/fake_image_fetcher.go @@ -55,7 +55,7 @@ func (f *FakeImageFetcher) Fetch(ctx context.Context, name string, options image return ri, nil } -func (f *FakeImageFetcher) CheckReadAccessValidator(_ string, _ image.FetchOptions) bool { +func (f *FakeImageFetcher) CheckReadAccess(_ string, _ image.FetchOptions) bool { return true } diff --git a/pkg/buildpack/downloader.go b/pkg/buildpack/downloader.go index 91cd597815..0a8a0d64cf 100644 --- a/pkg/buildpack/downloader.go +++ b/pkg/buildpack/downloader.go @@ -29,7 +29,7 @@ type Logger interface { type ImageFetcher interface { Fetch(ctx context.Context, name string, options image.FetchOptions) (imgutil.Image, error) - CheckReadAccessValidator(repo string, options image.FetchOptions) bool + CheckReadAccess(repo string, options image.FetchOptions) bool } type Downloader interface { diff --git a/pkg/client/client.go b/pkg/client/client.go index 8d0272d2ef..fe8ebbd8a9 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -53,13 +53,13 @@ type ImageFetcher interface { // 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) - // CheckReadAccessValidator verifies if an image is accessible with read permissions + // 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 pullPolicy, 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. - CheckReadAccessValidator(repo string, options image.FetchOptions) bool + 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 diff --git a/pkg/client/common.go b/pkg/client/common.go index 8ca77edd0e..e8e7f07ab8 100644 --- a/pkg/client/common.go +++ b/pkg/client/common.go @@ -133,7 +133,7 @@ func filterImageList(imageList []string, fetcher ImageFetcher, options image.Fet var accessibleImages []string for i, img := range imageList { - if fetcher.CheckReadAccessValidator(img, options) { + if fetcher.CheckReadAccess(img, options) { accessibleImages = append(accessibleImages, imageList[i]) } } diff --git a/pkg/client/example_fetcher_test.go b/pkg/client/example_fetcher_test.go index 12a1b65f10..d649e842d7 100644 --- a/pkg/client/example_fetcher_test.go +++ b/pkg/client/example_fetcher_test.go @@ -54,6 +54,6 @@ func (f *fetcher) Fetch(_ context.Context, imageName string, _ image.FetchOption return nil, errors.New("not implemented") } -func (f *fetcher) CheckReadAccessValidator(_ string, _ FetchOptions) bool { +func (f *fetcher) CheckReadAccess(_ string, _ FetchOptions) bool { return true } diff --git a/pkg/image/fetcher.go b/pkg/image/fetcher.go index 2e941e3ce1..aa6a1b7200 100644 --- a/pkg/image/fetcher.go +++ b/pkg/image/fetcher.go @@ -123,18 +123,22 @@ func (f *Fetcher) Fetch(ctx context.Context, name string, options FetchOptions) return f.fetchDaemonImage(name) } -func (f *Fetcher) CheckReadAccessValidator(repo string, options FetchOptions) bool { - if !options.Daemon { +func (f *Fetcher) CheckReadAccess(repo string, options FetchOptions) bool { + if !options.Daemon || options.PullPolicy == PullAlways { return f.checkRemoteReadAccess(repo) } if _, err := f.fetchDaemonImage(repo); err != nil { - // Image doesn't exist in the daemon - // Pull Never: should failed - // Pull Always or Pull If Not Present: need to check the registry - if options.PullPolicy == PullNever { - return false + if errors.Is(err, ErrNotFound) { + // Image doesn't exist in the daemon + // Pull Never: should failed + // Pull If Not Present: need to check the registry + if options.PullPolicy == PullNever { + return false + } + return f.checkRemoteReadAccess(repo) } - return f.checkRemoteReadAccess(repo) + f.logger.Debugf("failed reading image from the daemon %s, error: %s", repo, err.Error()) + return false } // no-op return true @@ -143,6 +147,7 @@ func (f *Fetcher) CheckReadAccessValidator(repo string, options FetchOptions) bo func (f *Fetcher) checkRemoteReadAccess(repo string) bool { img, err := remote.NewImage(repo, f.keychain) if err != nil { + f.logger.Debugf("failed accessing remote image %s, error: %s", repo, err.Error()) return false } if ok, err := img.CheckReadAccess(); ok { diff --git a/pkg/image/fetcher_test.go b/pkg/image/fetcher_test.go index f07598a489..a120ac053b 100644 --- a/pkg/image/fetcher_test.go +++ b/pkg/image/fetcher_test.go @@ -12,14 +12,18 @@ import ( "github.com/buildpacks/imgutil" "github.com/buildpacks/imgutil/local" "github.com/buildpacks/imgutil/remote" + "github.com/docker/docker/api/types" "github.com/docker/docker/client" + "github.com/golang/mock/gomock" "github.com/google/go-containerregistry/pkg/authn" "github.com/heroku/color" + "github.com/pkg/errors" "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" ) @@ -404,7 +408,7 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { }) }) - when("#CheckReadAccessValidator", func() { + when("#CheckReadAccess", func() { var daemon bool when("Daemon is true", func() { @@ -412,6 +416,28 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { daemon = true }) + when("an error is thrown by the daemon", func() { + it.Before(func() { + mockController := gomock.NewController(t) + mockDockerClient := testmocks.NewMockCommonAPIClient(mockController) + mockDockerClient.EXPECT().ServerVersion(gomock.Any()).Return(types.Version{}, errors.New("something wrong happened")) + imageFetcher = image.NewFetcher(logging.NewLogWithWriters(&outBuf, &outBuf, logging.WithVerbose()), mockDockerClient) + }) + when("PullNever", func() { + it("read access must be false", func() { + h.AssertFalse(t, imageFetcher.CheckReadAccess("pack.test/dummy", image.FetchOptions{Daemon: daemon, PullPolicy: image.PullNever})) + h.AssertContains(t, outBuf.String(), "failed reading image from the daemon") + }) + }) + + when("PullIfNotPresent", func() { + it("read access must be false", func() { + h.AssertFalse(t, imageFetcher.CheckReadAccess("pack.test/dummy", image.FetchOptions{Daemon: daemon, PullPolicy: image.PullIfNotPresent})) + h.AssertContains(t, outBuf.String(), "failed reading image from the daemon") + }) + }) + }) + when("image exists only in the daemon", func() { it.Before(func() { img, err := local.NewImage("pack.test/dummy", docker) @@ -419,20 +445,20 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { h.AssertNil(t, img.Save()) }) when("PullAlways", func() { - it("read access must be true", func() { - h.AssertTrue(t, imageFetcher.CheckReadAccessValidator("pack.test/dummy", image.FetchOptions{Daemon: daemon, PullPolicy: image.PullAlways})) + it("read access must be false", func() { + h.AssertFalse(t, imageFetcher.CheckReadAccess("pack.test/dummy", image.FetchOptions{Daemon: daemon, PullPolicy: image.PullAlways})) }) }) when("PullNever", func() { it("read access must be true", func() { - h.AssertTrue(t, imageFetcher.CheckReadAccessValidator("pack.test/dummy", image.FetchOptions{Daemon: daemon, PullPolicy: image.PullNever})) + h.AssertTrue(t, imageFetcher.CheckReadAccess("pack.test/dummy", image.FetchOptions{Daemon: daemon, PullPolicy: image.PullNever})) }) }) when("PullIfNotPresent", func() { it("read access must be true", func() { - h.AssertTrue(t, imageFetcher.CheckReadAccessValidator("pack.test/dummy", image.FetchOptions{Daemon: daemon, PullPolicy: image.PullIfNotPresent})) + h.AssertTrue(t, imageFetcher.CheckReadAccess("pack.test/dummy", image.FetchOptions{Daemon: daemon, PullPolicy: image.PullIfNotPresent})) }) }) }) @@ -445,19 +471,19 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { }) when("PullAlways", func() { it("read access must be true", func() { - h.AssertTrue(t, imageFetcher.CheckReadAccessValidator(repoName, image.FetchOptions{Daemon: daemon, PullPolicy: image.PullAlways})) + h.AssertTrue(t, imageFetcher.CheckReadAccess(repoName, image.FetchOptions{Daemon: daemon, PullPolicy: image.PullAlways})) }) }) when("PullNever", func() { it("read access must be false", func() { - h.AssertFalse(t, imageFetcher.CheckReadAccessValidator(repoName, image.FetchOptions{Daemon: daemon, PullPolicy: image.PullNever})) + h.AssertFalse(t, imageFetcher.CheckReadAccess(repoName, image.FetchOptions{Daemon: daemon, PullPolicy: image.PullNever})) }) }) when("PullIfNotPresent", func() { it("read access must be true", func() { - h.AssertTrue(t, imageFetcher.CheckReadAccessValidator(repoName, image.FetchOptions{Daemon: daemon, PullPolicy: image.PullIfNotPresent})) + h.AssertTrue(t, imageFetcher.CheckReadAccess(repoName, image.FetchOptions{Daemon: daemon, PullPolicy: image.PullIfNotPresent})) }) }) }) @@ -470,7 +496,7 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { when("remote image doesn't exists", func() { it("fails when checking dummy image", func() { - h.AssertFalse(t, imageFetcher.CheckReadAccessValidator("pack.test/dummy", image.FetchOptions{Daemon: daemon})) + h.AssertFalse(t, imageFetcher.CheckReadAccess("pack.test/dummy", image.FetchOptions{Daemon: daemon})) h.AssertContains(t, outBuf.String(), "CheckReadAccess failed for the run image pack.test/dummy") }) }) @@ -483,7 +509,7 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { }) it("read access is valid", func() { - h.AssertTrue(t, imageFetcher.CheckReadAccessValidator(repoName, image.FetchOptions{Daemon: daemon})) + h.AssertTrue(t, imageFetcher.CheckReadAccess(repoName, image.FetchOptions{Daemon: daemon})) h.AssertContains(t, outBuf.String(), fmt.Sprintf("CheckReadAccess succeeded for the run image %s", repoName)) }) }) diff --git a/pkg/testmocks/mock_image_fetcher.go b/pkg/testmocks/mock_image_fetcher.go index 02bb715041..6fd890db2b 100644 --- a/pkg/testmocks/mock_image_fetcher.go +++ b/pkg/testmocks/mock_image_fetcher.go @@ -38,9 +38,9 @@ func (m *MockImageFetcher) EXPECT() *MockImageFetcherMockRecorder { } // CheckReadAccessValidator mocks base method. -func (m *MockImageFetcher) CheckReadAccessValidator(arg0 string, arg1 image.FetchOptions) bool { +func (m *MockImageFetcher) CheckReadAccess(arg0 string, arg1 image.FetchOptions) bool { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CheckReadAccessValidator", arg0, arg1) + ret := m.ctrl.Call(m, "CheckReadAccess", arg0, arg1) ret0, _ := ret[0].(bool) return ret0 } @@ -48,7 +48,7 @@ func (m *MockImageFetcher) CheckReadAccessValidator(arg0 string, arg1 image.Fetc // CheckReadAccessValidator indicates an expected call of CheckReadAccessValidator. func (mr *MockImageFetcherMockRecorder) CheckReadAccessValidator(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckReadAccessValidator", reflect.TypeOf((*MockImageFetcher)(nil).CheckReadAccessValidator), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckReadAccess", reflect.TypeOf((*MockImageFetcher)(nil).CheckReadAccess), arg0, arg1) } // Fetch mocks base method. From e85ddee1f5fb2b41262a6ca51a1100f999e100e0 Mon Sep 17 00:00:00 2001 From: Juan Bustamante Date: Fri, 26 Apr 2024 17:00:19 -0500 Subject: [PATCH 12/18] Apply suggestions from code review Co-authored-by: Natalie Arellano Co-authored-by: Ralf Pannemans Signed-off-by: Juan Bustamante Signed-off-by: Juan Bustamante --- internal/builder/image_fetcher_wrapper.go | 6 +++--- pkg/client/client.go | 4 ++-- pkg/image/fetcher.go | 5 ++--- pkg/image/fetcher_test.go | 4 ++-- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/internal/builder/image_fetcher_wrapper.go b/internal/builder/image_fetcher_wrapper.go index 71fbebf54d..16bf39b2a7 100644 --- a/internal/builder/image_fetcher_wrapper.go +++ b/internal/builder/image_fetcher_wrapper.go @@ -14,11 +14,11 @@ type ImageFetcher interface { // attempt to pull a remote image first. Fetch(ctx context.Context, name string, options image.FetchOptions) (imgutil.Image, error) - // CheckReadAccess verifies if an image accessible with read permissions + // 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 pullPolicy, which can have the following behavior + // 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. + // - 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 } diff --git a/pkg/client/client.go b/pkg/client/client.go index fe8ebbd8a9..7dd899b20a 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -55,9 +55,9 @@ type ImageFetcher interface { // 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 pullPolicy, which can have the following behavior + // 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. + // - 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 } diff --git a/pkg/image/fetcher.go b/pkg/image/fetcher.go index aa6a1b7200..9b8d0886b2 100644 --- a/pkg/image/fetcher.go +++ b/pkg/image/fetcher.go @@ -130,17 +130,16 @@ func (f *Fetcher) CheckReadAccess(repo string, options FetchOptions) bool { if _, err := f.fetchDaemonImage(repo); err != nil { if errors.Is(err, ErrNotFound) { // Image doesn't exist in the daemon - // Pull Never: should failed + // Pull Never: should fail // Pull If Not Present: need to check the registry if options.PullPolicy == PullNever { return false } return f.checkRemoteReadAccess(repo) } - f.logger.Debugf("failed reading image from the daemon %s, error: %s", repo, err.Error()) + f.logger.Debugf("failed reading image '%s' from the daemon, error: %s", repo, err.Error()) return false } - // no-op return true } diff --git a/pkg/image/fetcher_test.go b/pkg/image/fetcher_test.go index a120ac053b..b9491b24c2 100644 --- a/pkg/image/fetcher_test.go +++ b/pkg/image/fetcher_test.go @@ -426,14 +426,14 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { when("PullNever", func() { it("read access must be false", func() { h.AssertFalse(t, imageFetcher.CheckReadAccess("pack.test/dummy", image.FetchOptions{Daemon: daemon, PullPolicy: image.PullNever})) - h.AssertContains(t, outBuf.String(), "failed reading image from the daemon") + h.AssertContains(t, outBuf.String(), "failed reading image 'pack.test/dummy' from the daemon") }) }) when("PullIfNotPresent", func() { it("read access must be false", func() { h.AssertFalse(t, imageFetcher.CheckReadAccess("pack.test/dummy", image.FetchOptions{Daemon: daemon, PullPolicy: image.PullIfNotPresent})) - h.AssertContains(t, outBuf.String(), "failed reading image from the daemon") + h.AssertContains(t, outBuf.String(), "failed reading image 'pack.test/dummy' from the daemon") }) }) }) From 8760202076af9fd4683b673d49493b47efb2eb93 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Apr 2024 13:59:14 +0000 Subject: [PATCH 13/18] build(deps): bump the go-dependencies group across 1 directory with 9 updates Bumps the go-dependencies group with 7 updates in the / directory: | Package | From | To | | --- | --- | --- | | [github.com/Microsoft/go-winio](https://github.com/Microsoft/go-winio) | `0.6.1` | `0.6.2` | | [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) | `5.11.0` | `5.12.0` | | [github.com/onsi/gomega](https://github.com/onsi/gomega) | `1.32.0` | `1.33.0` | | [golang.org/x/crypto](https://github.com/golang/crypto) | `0.21.0` | `0.22.0` | | [golang.org/x/mod](https://github.com/golang/mod) | `0.16.0` | `0.17.0` | | [golang.org/x/oauth2](https://github.com/golang/oauth2) | `0.18.0` | `0.19.0` | | [golang.org/x/sync](https://github.com/golang/sync) | `0.6.0` | `0.7.0` | Updates `github.com/Microsoft/go-winio` from 0.6.1 to 0.6.2 - [Release notes](https://github.com/Microsoft/go-winio/releases) - [Commits](https://github.com/Microsoft/go-winio/compare/v0.6.1...v0.6.2) Updates `github.com/go-git/go-git/v5` from 5.11.0 to 5.12.0 - [Release notes](https://github.com/go-git/go-git/releases) - [Commits](https://github.com/go-git/go-git/compare/v5.11.0...v5.12.0) Updates `github.com/onsi/gomega` from 1.32.0 to 1.33.0 - [Release notes](https://github.com/onsi/gomega/releases) - [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md) - [Commits](https://github.com/onsi/gomega/compare/v1.32.0...v1.33.0) Updates `golang.org/x/crypto` from 0.21.0 to 0.22.0 - [Commits](https://github.com/golang/crypto/compare/v0.21.0...v0.22.0) Updates `golang.org/x/mod` from 0.16.0 to 0.17.0 - [Commits](https://github.com/golang/mod/compare/v0.16.0...v0.17.0) Updates `golang.org/x/oauth2` from 0.18.0 to 0.19.0 - [Commits](https://github.com/golang/oauth2/compare/v0.18.0...v0.19.0) Updates `golang.org/x/sync` from 0.6.0 to 0.7.0 - [Commits](https://github.com/golang/sync/compare/v0.6.0...v0.7.0) Updates `golang.org/x/sys` from 0.18.0 to 0.19.0 - [Commits](https://github.com/golang/sys/compare/v0.18.0...v0.19.0) Updates `golang.org/x/term` from 0.18.0 to 0.19.0 - [Commits](https://github.com/golang/term/compare/v0.18.0...v0.19.0) --- updated-dependencies: - dependency-name: github.com/Microsoft/go-winio dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go-dependencies - dependency-name: github.com/go-git/go-git/v5 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-dependencies - dependency-name: github.com/onsi/gomega dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-dependencies - dependency-name: golang.org/x/crypto dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-dependencies - dependency-name: golang.org/x/mod dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-dependencies - dependency-name: golang.org/x/oauth2 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-dependencies - dependency-name: golang.org/x/sync dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-dependencies - dependency-name: golang.org/x/sys dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-dependencies - dependency-name: golang.org/x/term dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-dependencies ... Signed-off-by: dependabot[bot] --- go.mod | 28 +++++++++++------------- go.sum | 69 +++++++++++++++++++++++++++------------------------------- 2 files changed, 45 insertions(+), 52 deletions(-) diff --git a/go.mod b/go.mod index d074fe0eb6..1d77f5a645 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/buildpacks/pack require ( github.com/BurntSushi/toml v1.3.2 github.com/Masterminds/semver v1.5.0 - github.com/Microsoft/go-winio v0.6.1 + github.com/Microsoft/go-winio v0.6.2 github.com/apex/log v1.9.0 github.com/buildpacks/imgutil v0.0.0-20240206215312-f8d38e1de03d github.com/buildpacks/lifecycle v0.19.3 @@ -12,7 +12,7 @@ require ( github.com/docker/go-connections v0.5.0 github.com/dustin/go-humanize v1.0.1 github.com/gdamore/tcell/v2 v2.7.4 - github.com/go-git/go-git/v5 v5.11.0 + github.com/go-git/go-git/v5 v5.12.0 github.com/golang/mock v1.6.0 github.com/google/go-cmp v0.6.0 github.com/google/go-containerregistry v0.19.1 @@ -20,7 +20,7 @@ require ( github.com/hectane/go-acl v0.0.0-20190604041725-da78bae5fc95 github.com/heroku/color v0.0.6 github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e - github.com/onsi/gomega v1.32.0 + github.com/onsi/gomega v1.33.0 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0 github.com/pelletier/go-toml v1.9.5 @@ -29,12 +29,12 @@ require ( github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 github.com/sclevine/spec v1.4.0 github.com/spf13/cobra v1.8.0 - golang.org/x/crypto v0.21.0 - golang.org/x/mod v0.16.0 - golang.org/x/oauth2 v0.18.0 - golang.org/x/sync v0.6.0 - golang.org/x/sys v0.18.0 - golang.org/x/term v0.18.0 + golang.org/x/crypto v0.22.0 + golang.org/x/mod v0.17.0 + golang.org/x/oauth2 v0.19.0 + golang.org/x/sync v0.7.0 + golang.org/x/sys v0.19.0 + golang.org/x/term v0.19.0 golang.org/x/text v0.14.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -51,7 +51,7 @@ require ( github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect - github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect + github.com/ProtonMail/go-crypto v1.0.0 // indirect github.com/agext/levenshtein v1.2.3 // indirect github.com/aws/aws-sdk-go-v2 v1.25.2 // indirect github.com/aws/aws-sdk-go-v2/config v1.27.4 // indirect @@ -122,9 +122,9 @@ require ( github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/rivo/uniseg v0.4.3 // indirect - github.com/sergi/go-diff v1.2.0 // indirect + github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/skeema/knownhosts v1.2.1 // indirect + github.com/skeema/knownhosts v1.2.2 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/vbatts/tar-split v0.11.5 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect @@ -132,9 +132,7 @@ require ( go.opentelemetry.io/otel v1.23.0 // indirect go.opentelemetry.io/otel/metric v1.23.0 // indirect go.opentelemetry.io/otel/trace v1.23.0 // indirect - golang.org/x/net v0.22.0 // indirect - golang.org/x/tools v0.17.0 // indirect - google.golang.org/appengine v1.6.8 // indirect + golang.org/x/net v0.23.0 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect ) diff --git a/go.sum b/go.sum index 88c9cf662a..7cc9ae8caa 100644 --- a/go.sum +++ b/go.sum @@ -34,12 +34,12 @@ github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8= github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w= -github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= -github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= +github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -156,16 +156,16 @@ github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo github.com/gdamore/tcell/v2 v2.4.1-0.20210905002822-f057f0a857a1/go.mod h1:Az6Jt+M5idSED2YPGtwnfJV0kXohgdCBPmHGSYc1r04= github.com/gdamore/tcell/v2 v2.7.4 h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAYU= github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg= -github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= -github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= +github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= +github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= -github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= +github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= +github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= @@ -192,7 +192,6 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -292,11 +291,11 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= -github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= +github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8= +github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk= -github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg= +github.com/onsi/gomega v1.33.0 h1:snPCflnZrpMsy94p4lXVEkHo12lmPnc3vY5XBbreexE= +github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= @@ -345,14 +344,14 @@ github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+e github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8= github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= -github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= -github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= +github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= @@ -372,8 +371,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= @@ -417,15 +416,15 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= -golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -441,11 +440,11 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= -golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= +golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg= +golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -455,8 +454,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -484,8 +483,8 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -494,14 +493,13 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= @@ -523,8 +521,6 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k= google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= @@ -548,7 +544,6 @@ gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= From c3be6a9a9a68fcea23028b7c4e16ab457c8123c6 Mon Sep 17 00:00:00 2001 From: Juan Bustamante Date: Thu, 18 Apr 2024 09:15:43 -0500 Subject: [PATCH 14/18] Updating go version to 1.22.x Signed-off-by: Juan Bustamante Signed-off-by: Ozzy Osborne --- .github/workflows/benchmark.yml | 2 +- .github/workflows/build.yml | 4 ++-- .github/workflows/compatibility.yml | 2 +- Makefile | 4 ++-- go.mod | 2 +- tools/go.mod | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index e0cdca24d0..e19d4d9a19 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -17,7 +17,7 @@ jobs: - name: Set up go uses: actions/setup-go@v5 with: - go-version: "1.21" + go-version: "1.22" - name: Set up go env run: | echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 831051c9c4..67d1a78707 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -74,7 +74,7 @@ jobs: - name: Set up go uses: actions/setup-go@v5 with: - go-version: "1.21" + go-version: "1.22" check-latest: true - name: Set up go env for Unix if: runner.os != 'Windows' @@ -186,7 +186,7 @@ jobs: - name: Set up go uses: actions/setup-go@v5 with: - go-version: "1.21" + go-version: "1.22" check-latest: true - name: Build run: | diff --git a/.github/workflows/compatibility.yml b/.github/workflows/compatibility.yml index 5fe6fbb194..2f6b519220 100644 --- a/.github/workflows/compatibility.yml +++ b/.github/workflows/compatibility.yml @@ -46,7 +46,7 @@ jobs: - name: Set up go uses: actions/setup-go@v5 with: - go-version: "1.21" + go-version: "1.22" check-latest: true - name: Set up go env run: | diff --git a/Makefile b/Makefile index 928e1de5a6..0d1246ea27 100644 --- a/Makefile +++ b/Makefile @@ -164,8 +164,8 @@ install-golangci-lint: ## mod-tidy: Tidy Go modules mod-tidy: - $(GOCMD) mod tidy -compat=1.21 - cd tools && $(GOCMD) mod tidy -compat=1.21 + $(GOCMD) mod tidy -compat=1.22 + cd tools && $(GOCMD) mod tidy -compat=1.22 ## tidy: Tidy modules and format the code tidy: mod-tidy format diff --git a/go.mod b/go.mod index cc35a81bbb..f285127707 100644 --- a/go.mod +++ b/go.mod @@ -139,4 +139,4 @@ require ( gopkg.in/warnings.v0 v0.1.2 // indirect ) -go 1.21 +go 1.22 diff --git a/tools/go.mod b/tools/go.mod index 3d6bac6b3d..984efd80f5 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -1,6 +1,6 @@ module github.com/buildpacks/pack/tools -go 1.21 +go 1.22 require ( github.com/golang/mock v1.6.0 From 579608074d66ac92ef1c0975e49cc2789b59a1a6 Mon Sep 17 00:00:00 2001 From: Ozzy Osborne Date: Mon, 29 Apr 2024 09:24:59 -0400 Subject: [PATCH 15/18] Updates from Review comments Signed-off-by: Ozzy Osborne --- acceptance/acceptance_test.go | 8 ++++---- acceptance/assertions/lifecycle_output.go | 2 +- pkg/client/build.go | 4 ++++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go index 8cb0e5551a..3dc46ef7b5 100644 --- a/acceptance/acceptance_test.go +++ b/acceptance/acceptance_test.go @@ -848,7 +848,7 @@ func testAcceptance( assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) assertOutput := assertions.NewLifecycleOutputAssertionManager(t, output) - assertOutput.IncludesLifecycleImageTag(origLifecycle) + assertOutput.IncludesTagOrEphemeralLifecycle(origLifecycle) assertOutput.IncludesSeparatePhasesWithBuildExtension() t.Log("inspecting image") @@ -902,7 +902,7 @@ func testAcceptance( assertOutput := assertions.NewLifecycleOutputAssertionManager(t, output) - assertOutput.IncludesLifecycleImageTag(origLifecycle) + assertOutput.IncludesTagOrEphemeralLifecycle(origLifecycle) assertOutput.IncludesSeparatePhasesWithRunExtension() t.Log("inspecting image") @@ -993,7 +993,7 @@ func testAcceptance( assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) assertOutput := assertions.NewLifecycleOutputAssertionManager(t, output) - assertOutput.IncludesLifecycleImageTag(origLifecycle) + assertOutput.IncludesTagOrEphemeralLifecycle(origLifecycle) assertOutput.IncludesSeparatePhases() }) }) @@ -1017,7 +1017,7 @@ func testAcceptance( assertions.NewOutputAssertionManager(t, output).ReportsSuccessfulImageBuild(repoName) assertOutput := assertions.NewLifecycleOutputAssertionManager(t, output) - assertOutput.IncludesLifecycleImageTag(origLifecycle) + assertOutput.IncludesTagOrEphemeralLifecycle(origLifecycle) assertOutput.IncludesSeparatePhases() }) }) diff --git a/acceptance/assertions/lifecycle_output.go b/acceptance/assertions/lifecycle_output.go index 8b0b182184..fca7b7eec9 100644 --- a/acceptance/assertions/lifecycle_output.go +++ b/acceptance/assertions/lifecycle_output.go @@ -86,7 +86,7 @@ func (l LifecycleOutputAssertionManager) IncludesSeparatePhasesWithRunExtension( l.assert.ContainsAll(l.output, "[detector]", "[analyzer]", "[extender (run)]", "[exporter]") } -func (l LifecycleOutputAssertionManager) IncludesLifecycleImageTag(tag string) { +func (l LifecycleOutputAssertionManager) IncludesTagOrEphemeralLifecycle(tag string) { l.testObject.Helper() if !strings.Contains(l.output, tag) { diff --git a/pkg/client/build.go b/pkg/client/build.go index add893eefa..1772f15876 100644 --- a/pkg/client/build.go +++ b/pkg/client/build.go @@ -670,6 +670,10 @@ func (c *Client) Build(ctx context.Context, opts BuildOptions) error { layerOffset = 2 } + if (len(manifestContent[0].layers) - layerOffset) < 0 { + return "", errors.New("Lifecycle image did not contain expected layer count") + } + return manifestContents[0].Layers[len(manifestContents[0].Layers)-layerOffset], nil }() if err != nil { From 29192dd49010c2dd1253d8245205ef1676f4d4fd Mon Sep 17 00:00:00 2001 From: Juan Bustamante Date: Thu, 18 Apr 2024 10:15:47 -0500 Subject: [PATCH 16/18] Updating default lifecycle version to 0.19.3 Signed-off-by: Juan Bustamante Signed-off-by: Ozzy Osborne --- .../testdata/pack_fixtures/report_output.txt | 2 +- go.mod | 48 +++---- go.sum | 130 +++++++++--------- internal/builder/lifecycle.go | 2 +- 4 files changed, 91 insertions(+), 91 deletions(-) diff --git a/acceptance/testdata/pack_fixtures/report_output.txt b/acceptance/testdata/pack_fixtures/report_output.txt index 63c9e81ed0..4239830438 100644 --- a/acceptance/testdata/pack_fixtures/report_output.txt +++ b/acceptance/testdata/pack_fixtures/report_output.txt @@ -2,7 +2,7 @@ Pack: Version: {{ .Version }} OS/Arch: {{ .OS }}/{{ .Arch }} -Default Lifecycle Version: 0.18.5 +Default Lifecycle Version: 0.19.3 Supported Platform APIs: 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.10, 0.11, 0.12 diff --git a/go.mod b/go.mod index f285127707..d074fe0eb6 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,8 @@ require ( github.com/Masterminds/semver v1.5.0 github.com/Microsoft/go-winio v0.6.1 github.com/apex/log v1.9.0 - github.com/buildpacks/imgutil v0.0.0-20240118145509-e94a1b7de8a9 - github.com/buildpacks/lifecycle v0.18.5 + github.com/buildpacks/imgutil v0.0.0-20240206215312-f8d38e1de03d + github.com/buildpacks/lifecycle v0.19.3 github.com/docker/cli v25.0.3+incompatible github.com/docker/docker v25.0.5+incompatible github.com/docker/go-connections v0.5.0 @@ -53,29 +53,29 @@ require ( github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect github.com/agext/levenshtein v1.2.3 // indirect - github.com/aws/aws-sdk-go-v2 v1.24.1 // indirect - github.com/aws/aws-sdk-go-v2/config v1.26.6 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.16.16 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 // indirect + github.com/aws/aws-sdk-go-v2 v1.25.2 // indirect + github.com/aws/aws-sdk-go-v2/config v1.27.4 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.4 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.2 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.2 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.2 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect github.com/aws/aws-sdk-go-v2/service/ecr v1.24.5 // indirect github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.21.5 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 // indirect - github.com/aws/smithy-go v1.19.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.20.1 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.1 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.28.1 // indirect + github.com/aws/smithy-go v1.20.1 // indirect github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231213181459-b0fcec718dc6 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect github.com/cloudflare/circl v1.3.7 // indirect - github.com/containerd/containerd v1.7.12 // indirect + github.com/containerd/containerd v1.7.14 // indirect github.com/containerd/log v0.1.0 // indirect - github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect + github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect github.com/containerd/typeurl/v2 v2.1.1 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/dimchansky/utfbom v1.1.1 // indirect @@ -96,20 +96,20 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/uuid v1.5.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect - github.com/klauspost/compress v1.17.2 // indirect + github.com/klauspost/compress v1.17.4 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/moby/buildkit v0.12.5 // indirect + github.com/moby/buildkit v0.13.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect github.com/moby/sys/user v0.1.0 // indirect @@ -128,10 +128,10 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/vbatts/tar-split v0.11.5 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect - go.opentelemetry.io/otel v1.22.0 // indirect - go.opentelemetry.io/otel/metric v1.22.0 // indirect - go.opentelemetry.io/otel/trace v1.22.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0 // indirect + go.opentelemetry.io/otel v1.23.0 // indirect + go.opentelemetry.io/otel/metric v1.23.0 // indirect + go.opentelemetry.io/otel/trace v1.23.0 // indirect golang.org/x/net v0.22.0 // indirect golang.org/x/tools v0.17.0 // indirect google.golang.org/appengine v1.6.8 // indirect diff --git a/go.sum b/go.sum index abeb5781fb..88c9cf662a 100644 --- a/go.sum +++ b/go.sum @@ -54,36 +54,36 @@ github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3st github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go-v2 v1.24.1 h1:xAojnj+ktS95YZlDf0zxWBkbFtymPeDP+rvUQIH3uAU= -github.com/aws/aws-sdk-go-v2 v1.24.1/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4= -github.com/aws/aws-sdk-go-v2/config v1.26.6 h1:Z/7w9bUqlRI0FFQpetVuFYEsjzE3h7fpU6HuGmfPL/o= -github.com/aws/aws-sdk-go-v2/config v1.26.6/go.mod h1:uKU6cnDmYCvJ+pxO9S4cWDb2yWWIH5hra+32hVh1MI4= -github.com/aws/aws-sdk-go-v2/credentials v1.16.16 h1:8q6Rliyv0aUFAVtzaldUEcS+T5gbadPbWdV1WcAddK8= -github.com/aws/aws-sdk-go-v2/credentials v1.16.16/go.mod h1:UHVZrdUsv63hPXFo1H7c5fEneoVo9UXiz36QG1GEPi0= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 h1:c5I5iH+DZcH3xOIMlz3/tCKJDaHFwYEmxvlh2fAcFo8= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11/go.mod h1:cRrYDYAMUohBJUtUnOhydaMHtiK/1NZ0Otc9lIb6O0Y= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 h1:vF+Zgd9s+H4vOXd5BMaPWykta2a6Ih0AKLq/X6NYKn4= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10/go.mod h1:6BkRjejp/GR4411UGqkX8+wFMbFbqsUIimfK4XjOKR4= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 h1:nYPe006ktcqUji8S2mqXf9c/7NdiKriOwMvWQHgYztw= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10/go.mod h1:6UV4SZkVvmODfXKql4LCbaZUpF7HO2BX38FgBf9ZOLw= -github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 h1:n3GDfwqF2tzEkXlv5cuy4iy7LpKDtqDMcNLfZDu9rls= -github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= +github.com/aws/aws-sdk-go-v2 v1.25.2 h1:/uiG1avJRgLGiQM9X3qJM8+Qa6KRGK5rRPuXE0HUM+w= +github.com/aws/aws-sdk-go-v2 v1.25.2/go.mod h1:Evoc5AsmtveRt1komDwIsjHFyrP5tDuF1D1U+6z6pNo= +github.com/aws/aws-sdk-go-v2/config v1.27.4 h1:AhfWb5ZwimdsYTgP7Od8E9L1u4sKmDW2ZVeLcf2O42M= +github.com/aws/aws-sdk-go-v2/config v1.27.4/go.mod h1:zq2FFXK3A416kiukwpsd+rD4ny6JC7QSkp4QdN1Mp2g= +github.com/aws/aws-sdk-go-v2/credentials v1.17.4 h1:h5Vztbd8qLppiPwX+y0Q6WiwMZgpd9keKe2EAENgAuI= +github.com/aws/aws-sdk-go-v2/credentials v1.17.4/go.mod h1:+30tpwrkOgvkJL1rUZuRLoxcJwtI/OkeBLYnHxJtVe0= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.2 h1:AK0J8iYBFeUk2Ax7O8YpLtFsfhdOByh2QIkHmigpRYk= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.2/go.mod h1:iRlGzMix0SExQEviAyptRWRGdYNo3+ufW/lCzvKVTUc= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.2 h1:bNo4LagzUKbjdxE0tIcR9pMzLR2U/Tgie1Hq1HQ3iH8= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.2/go.mod h1:wRQv0nN6v9wDXuWThpovGQjqF1HFdcgWjporw14lS8k= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.2 h1:EtOU5jsPdIQNP+6Q2C5e3d65NKT1PeCiQk+9OdzO12Q= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.2/go.mod h1:tyF5sKccmDz0Bv4NrstEr+/9YkSPJHrcO7UsUKf7pWM= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= github.com/aws/aws-sdk-go-v2/service/ecr v1.24.5 h1:wLPDAUFT50NEXGXpywRU3AA74pg35RJjWol/68ruvQQ= github.com/aws/aws-sdk-go-v2/service/ecr v1.24.5/go.mod h1:AOHmGMoPtSY9Zm2zBuwUJQBisIvYAZeA1n7b6f4e880= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.21.5 h1:PQp21GBlGNaQ+AVJAB8w2KTmLx0DkFS2fDET2Iy3+f0= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.21.5/go.mod h1:WMntdAol8KgeYsa5sDZPsRTXs4jVZIMYu0eQVVIQxnc= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 h1:DBYTXwIGQSGs9w4jKm60F5dmCQ3EEruxdc0MFh+3EY4= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10/go.mod h1:wohMUQiFdzo0NtxbBg0mSRGZ4vL3n0dKjLTINdcIino= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 h1:eajuO3nykDPdYicLlP3AGgOyVN3MOlFmZv7WGTuJPow= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.7/go.mod h1:+mJNDdF+qiUlNKNC3fxn74WWNN+sOiGOEImje+3ScPM= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 h1:QPMJf+Jw8E1l7zqhZmMlFw6w1NmfkfiSK8mS4zOx3BA= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7/go.mod h1:ykf3COxYI0UJmxcfcxcVuz7b6uADi1FkiUz6Eb7AgM8= -github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 h1:NzO4Vrau795RkUdSHKEwiR01FaGzGOH1EETJ+5QHnm0= -github.com/aws/aws-sdk-go-v2/service/sts v1.26.7/go.mod h1:6h2YuIoxaMSCFf5fi1EgZAwdfkGMgDY+DVfa61uLe4U= -github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM= -github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 h1:EyBZibRTVAs6ECHZOw5/wlylS9OcTzwyjeQMudmREjE= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1/go.mod h1:JKpmtYhhPs7D97NL/ltqz7yCkERFW5dOlHyVl66ZYF8= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.2 h1:5ffmXjPtwRExp1zc7gENLgCPyHFbhEPwVTkTiH9niSk= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.2/go.mod h1:Ru7vg1iQ7cR4i7SZ/JTLYN9kaXtbL69UdgG0OQWQxW0= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.1 h1:utEGkfdQ4L6YW/ietH7111ZYglLJvS+sLriHJ1NBJEQ= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.1/go.mod h1:RsYqzYr2F2oPDdpy+PdhephuZxTfjHQe7SOBcZGoAU8= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.1 h1:9/GylMS45hGGFCcMrUZDVayQE1jYSIN6da9jo7RAYIw= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.1/go.mod h1:YjAPFn4kGFqKC54VsHs5fn5B6d+PCY2tziEa3U/GB5Y= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.1 h1:3I2cBEYgKhrWlwyZgfpSO2BpaMY1LHPqXYk/QGlu2ew= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.1/go.mod h1:uQ7YYKZt3adCRrdCBREm1CD3efFLOUNH77MrUCvx5oA= +github.com/aws/smithy-go v1.20.1 h1:4SZlSlMr36UEqC7XOyRVb27XMeZubNcBNN+9IgEPIQw= +github.com/aws/smithy-go v1.20.1/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231213181459-b0fcec718dc6 h1:PlJRmqKlSlEUlwem1c3zdPaEMtJc/ktnV7naD5Qvsx4= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231213181459-b0fcec718dc6/go.mod h1:08sPJIlDHu4HwQ1xScPgsBWezvM6U10ghGKBJu0mowA= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= @@ -91,10 +91,10 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/buildpacks/imgutil v0.0.0-20240118145509-e94a1b7de8a9 h1:kxe31xfMWJAIAzDfGQ3lL0j8QSSRfEHyLg7dRWIHA8I= -github.com/buildpacks/imgutil v0.0.0-20240118145509-e94a1b7de8a9/go.mod h1:PsazEB9yz+NG/cgm0Z1oQ0Xq6rD/U7eNMt5Su41afYY= -github.com/buildpacks/lifecycle v0.18.5 h1:lfoUX8jYCUZ2/Tr2AopaRjinqDivkNkcTChzysQTo00= -github.com/buildpacks/lifecycle v0.18.5/go.mod h1:Kvuu9IWABPLXc6yHCMtbdmgrGEi7QEiVzi5GGtcAkW0= +github.com/buildpacks/imgutil v0.0.0-20240206215312-f8d38e1de03d h1:b/tiReZf9jorbpaOwVw9MX3n99w7Ta4u+SVV7yy6XCE= +github.com/buildpacks/imgutil v0.0.0-20240206215312-f8d38e1de03d/go.mod h1:7zUmt4wkVJNuXCZhQndEd3kvVGmWLVyzRFIQXTaeXlU= +github.com/buildpacks/lifecycle v0.19.3 h1:T6dwX+/Nq7Q41Pb2zVu54MLrJPt93KEMNj4dHkXINbA= +github.com/buildpacks/lifecycle v0.19.3/go.mod h1:BoLvGP1fjOqab59dariHDhVh5uIQuQ7yoIfj0orvL8M= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= @@ -105,12 +105,12 @@ github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb2 github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= -github.com/containerd/containerd v1.7.12 h1:+KQsnv4VnzyxWcfO9mlxxELaoztsDEjOuCMPAuPqgU0= -github.com/containerd/containerd v1.7.12/go.mod h1:/5OMpE1p0ylxtEUGY8kuCYkDRzJm9NO1TFMWjUpdevk= +github.com/containerd/containerd v1.7.14 h1:H/XLzbnGuenZEGK+v0RkwTdv2u1QFAruMe5N0GNPJwA= +github.com/containerd/containerd v1.7.14/go.mod h1:YMC9Qt5yzNqXx/fO4j/5yYVIHXSRrlB3H7sxkUTvspg= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= -github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= -github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= +github.com/containerd/stargz-snapshotter/estargz v0.15.1 h1:eXJjw9RbkLFgioVaTG+G/ZW/0kEe2oEKCdS/ZxIyoCU= +github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk= github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4= github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -208,11 +208,11 @@ github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20230323073829-e72429f035bd h1:r8yyd+DJDmsUhGrRBxH5Pj7KeFK5l+Y3FsgT8keqKtk= +github.com/google/pprof v0.0.0-20230323073829-e72429f035bd/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= @@ -239,8 +239,8 @@ github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4 github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= -github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= +github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -273,8 +273,8 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e h1:Qa6dnn8DlasdXRnacluu8HzPts0S1I9zvvUPDbBnXFI= github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e/go.mod h1:waEya8ee1Ro/lgxpVhkJI4BVASzkm3UZqkx/cFJiYHM= -github.com/moby/buildkit v0.12.5 h1:RNHH1l3HDhYyZafr5EgstEu8aGNCwyfvMtrQDtjH9T0= -github.com/moby/buildkit v0.12.5/go.mod h1:YGwjA2loqyiYfZeEo8FtI7z4x5XponAaIWsWcSjWwso= +github.com/moby/buildkit v0.13.1 h1:L8afOFhPq2RPJJSr/VyzbufwID7jquZVB7oFHbPRcPE= +github.com/moby/buildkit v0.13.1/go.mod h1:aNmNQKLBFYAOFuzQjR3VA27/FijlvtBD1pjNwTSN37k= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= @@ -389,20 +389,20 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= -go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y= -go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= -go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg= -go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= -go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= -go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= -go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0= -go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0 h1:doUP+ExOpH3spVTLS0FcWGLnQrPct/hD/bCPbDRUEAU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0/go.mod h1:rdENBZMT2OE6Ne/KLwpiXudnAsbdrdBaqBvTN8M8BgA= +go.opentelemetry.io/otel v1.23.0 h1:Df0pqjqExIywbMCMTxkAwzjLZtRf+bBKLbUcpxO2C9E= +go.opentelemetry.io/otel v1.23.0/go.mod h1:YCycw9ZeKhcJFrb34iVSkyT0iczq/zYDtZYFufObyB0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I= +go.opentelemetry.io/otel/metric v1.23.0 h1:pazkx7ss4LFVVYSxYew7L5I6qvLXHA0Ap2pwV+9Cnpo= +go.opentelemetry.io/otel/metric v1.23.0/go.mod h1:MqUW2X2a6Q8RN96E2/nqNoT+z9BSms20Jb7Bbp+HiTo= +go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= +go.opentelemetry.io/otel/trace v1.23.0 h1:37Ik5Ib7xfYVb4V1UtnT97T1jI+AoIYkJyPkuL4iJgI= +go.opentelemetry.io/otel/trace v1.23.0/go.mod h1:GSGTbIClEsuZrGIzoEHqsVfxgn5UkggkflQwDScNUsk= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -525,13 +525,13 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 h1:nz5NESFLZbJGPFxDT/HCn+V1mZ8JGNoY4nUpmW/Y2eg= -google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw= -google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac h1:nUQEQmH/csSvFECKYRv6HWEyypysidKl2I6Qpsglq/0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= -google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= -google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= +google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k= +google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 h1:hZB7eLIaYlW9qXRfCq/qDaPdbeY3757uARz5Vvfv+cY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:YUWgXUFRPfoYK1IHMuxH5K6nPEXSCzIMljnQ59lLRCk= +google.golang.org/grpc v1.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY= +google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= @@ -556,5 +556,5 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= -gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= diff --git a/internal/builder/lifecycle.go b/internal/builder/lifecycle.go index 29aa945c63..c41799198e 100644 --- a/internal/builder/lifecycle.go +++ b/internal/builder/lifecycle.go @@ -14,7 +14,7 @@ import ( // A snapshot of the latest tested lifecycle version values const ( - DefaultLifecycleVersion = "0.18.5" + DefaultLifecycleVersion = "0.19.3" DefaultBuildpackAPIVersion = "0.2" ) From 869bc63d6276792ccb92ec8ffe8da5e967c294ca Mon Sep 17 00:00:00 2001 From: Natalie Arellano Date: Mon, 29 Apr 2024 11:20:52 -0400 Subject: [PATCH 17/18] Platform 0.13: look for build Dockerfiles in /generated//Dockerfile.build Newer platforms don't copy the Dockerfile from where extensions output them Signed-off-by: Natalie Arellano --- internal/build/lifecycle_execution.go | 13 ++++++- internal/build/lifecycle_execution_test.go | 45 ++++++++++++++++++---- internal/build/lifecycle_executor.go | 3 +- 3 files changed, 52 insertions(+), 9 deletions(-) diff --git a/internal/build/lifecycle_execution.go b/internal/build/lifecycle_execution.go index 0f5c9a49a4..50d170cdb2 100644 --- a/internal/build/lifecycle_execution.go +++ b/internal/build/lifecycle_execution.go @@ -892,10 +892,21 @@ func (l *LifecycleExecution) hasExtensionsForBuild() bool { } // the directory is /generated/build inside the build container, but `CopyOutTo` only copies the directory fis, err := os.ReadDir(filepath.Join(l.tmpDir, "build")) + if err == nil && len(fis) > 0 { + return true + } + // on newer platforms, we need to find a file such as /generated//Dockerfile.build + fis, err = os.ReadDir(l.tmpDir) if err != nil { + l.logger.Warnf("failed to read generated directory, assuming no build image extensions: %s", err) return false } - return len(fis) > 0 + for _, fi := range fis { + if _, err := os.Stat(filepath.Join(l.tmpDir, fi.Name(), "Dockerfile.build")); err == nil { + return true + } + } + return false } func (l *LifecycleExecution) hasExtensionsForRun() bool { diff --git a/internal/build/lifecycle_execution_test.go b/internal/build/lifecycle_execution_test.go index ed12a2e5b1..afd9569d05 100644 --- a/internal/build/lifecycle_execution_test.go +++ b/internal/build/lifecycle_execution_test.go @@ -136,11 +136,17 @@ func testLifecycleExecution(t *testing.T, when spec.G, it spec.S) { // construct fixtures for extensions if extensionsForBuild { - // the directory is /generated/build inside the build container, but `CopyOutTo` only copies the directory - err = os.MkdirAll(filepath.Join(tmpDir, "build"), 0755) - h.AssertNil(t, err) - _, err = os.Create(filepath.Join(tmpDir, "build", "some-dockerfile")) - h.AssertNil(t, err) + if platformAPI.LessThan("0.13") { + // the directory is /generated/build inside the build container, but `CopyOutTo` only copies the directory + err = os.MkdirAll(filepath.Join(tmpDir, "build", "some-buildpack-id"), 0755) + h.AssertNil(t, err) + } else { + // the directory is /generated/some-buildpack-id inside the build container, but `CopyOutTo` only copies the directory + err = os.MkdirAll(filepath.Join(tmpDir, "some-buildpack-id"), 0755) + h.AssertNil(t, err) + _, err = os.Create(filepath.Join(tmpDir, "some-buildpack-id", "Dockerfile.build")) + h.AssertNil(t, err) + } } amd := files.Analyzed{RunImage: &files.RunImage{ Extend: false, @@ -579,7 +585,32 @@ func testLifecycleExecution(t *testing.T, when spec.G, it spec.S) { providedOrderExt = dist.Order{dist.OrderEntry{Group: []dist.ModuleRef{ /* don't care */ }}} when("for build", func() { - when("present /generated/build", func() { + when("present in /generated/", func() { + extensionsForBuild = true + + when("platform >= 0.13", func() { + platformAPI = api.MustParse("0.13") + + it("runs the extender (build)", func() { + err := lifecycle.Run(context.Background(), func(execution *build.LifecycleExecution) build.PhaseFactory { + return fakePhaseFactory + }) + h.AssertNil(t, err) + + h.AssertEq(t, len(fakePhaseFactory.NewCalledWithProvider), 5) + + var found bool + for _, entry := range fakePhaseFactory.NewCalledWithProvider { + if entry.Name() == "extender" { + found = true + } + } + h.AssertEq(t, found, true) + }) + }) + }) + + when("present in /generated/build", func() { extensionsForBuild = true when("platform < 0.10", func() { @@ -603,7 +634,7 @@ func testLifecycleExecution(t *testing.T, when spec.G, it spec.S) { }) }) - when("platform >= 0.10", func() { + when("platform 0.10 to 0.12", func() { platformAPI = api.MustParse("0.10") it("runs the extender (build)", func() { diff --git a/internal/build/lifecycle_executor.go b/internal/build/lifecycle_executor.go index 09d9011f0c..6394f89472 100644 --- a/internal/build/lifecycle_executor.go +++ b/internal/build/lifecycle_executor.go @@ -32,6 +32,7 @@ var ( api.MustParse("0.10"), api.MustParse("0.11"), api.MustParse("0.12"), + api.MustParse("0.13"), } ) @@ -71,7 +72,7 @@ type LifecycleOptions struct { Builder Builder BuilderImage string // differs from Builder.Name() and Builder.Image().Name() in that it includes the registry context LifecycleImage string - LifecycleApis []string // optional - populated only if custom lifecycle image is downloaded, from that lifecycle's container's Labels. + LifecycleApis []string // optional - populated only if custom lifecycle image is downloaded, from that lifecycle image's labels. RunImage string FetchRunImageWithLifecycleLayer func(name string) (string, error) ProjectMetadata files.ProjectMetadata From c1ad91c93472ba76adc37088b869c1c5adca409d Mon Sep 17 00:00:00 2001 From: Natalie Arellano Date: Fri, 3 May 2024 14:14:09 -0400 Subject: [PATCH 18/18] Fix acceptance Signed-off-by: Natalie Arellano --- acceptance/acceptance_test.go | 2 +- .../testdata/pack_fixtures/report_output.txt | 2 +- internal/build/lifecycle_execution.go | 14 ++++++++------ internal/build/lifecycle_execution_test.go | 8 +++----- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go index 6b030cb04c..d103b55f86 100644 --- a/acceptance/acceptance_test.go +++ b/acceptance/acceptance_test.go @@ -834,7 +834,7 @@ func testAcceptance( launchCacheVolume.Clear(context.TODO()) }) - when("builder is untrusted", func() { + when("there are build image extensions", func() { it("uses the 5 phases, and runs the extender (build)", func() { output := pack.RunSuccessfully( "build", repoName, diff --git a/acceptance/testdata/pack_fixtures/report_output.txt b/acceptance/testdata/pack_fixtures/report_output.txt index 4239830438..6161c9216f 100644 --- a/acceptance/testdata/pack_fixtures/report_output.txt +++ b/acceptance/testdata/pack_fixtures/report_output.txt @@ -4,7 +4,7 @@ Pack: Default Lifecycle Version: 0.19.3 -Supported Platform APIs: 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.10, 0.11, 0.12 +Supported Platform APIs: 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.10, 0.11, 0.12, 0.13 Config: default-builder-image = "{{ .DefaultBuilder }}" diff --git a/internal/build/lifecycle_execution.go b/internal/build/lifecycle_execution.go index 50d170cdb2..8150ead355 100644 --- a/internal/build/lifecycle_execution.go +++ b/internal/build/lifecycle_execution.go @@ -444,7 +444,7 @@ func (l *LifecycleExecution) Detect(ctx context.Context, phaseFactory PhaseFacto If(l.hasExtensions(), WithPostContainerRunOperations( CopyOutToMaybe(filepath.Join(l.mountPaths.layersDir(), "analyzed.toml"), l.tmpDir))), If(l.hasExtensions(), WithPostContainerRunOperations( - CopyOutToMaybe(filepath.Join(l.mountPaths.layersDir(), "generated", "build"), l.tmpDir))), + CopyOutToMaybe(filepath.Join(l.mountPaths.layersDir(), "generated"), l.tmpDir))), envOp, ) @@ -890,19 +890,21 @@ func (l *LifecycleExecution) hasExtensionsForBuild() bool { if !l.hasExtensions() { return false } - // the directory is /generated/build inside the build container, but `CopyOutTo` only copies the directory - fis, err := os.ReadDir(filepath.Join(l.tmpDir, "build")) + generatedDir := filepath.Join(l.tmpDir, "generated") + fis, err := os.ReadDir(filepath.Join(generatedDir, "build")) if err == nil && len(fis) > 0 { + // on older platforms, we need to find a file such as /generated/build//Dockerfile + // on newer platforms, /generated/build doesn't exist return true } - // on newer platforms, we need to find a file such as /generated//Dockerfile.build - fis, err = os.ReadDir(l.tmpDir) + // on newer platforms, we need to find a file such as /generated//build.Dockerfile + fis, err = os.ReadDir(generatedDir) if err != nil { l.logger.Warnf("failed to read generated directory, assuming no build image extensions: %s", err) return false } for _, fi := range fis { - if _, err := os.Stat(filepath.Join(l.tmpDir, fi.Name(), "Dockerfile.build")); err == nil { + if _, err := os.Stat(filepath.Join(generatedDir, fi.Name(), "build.Dockerfile")); err == nil { return true } } diff --git a/internal/build/lifecycle_execution_test.go b/internal/build/lifecycle_execution_test.go index afd9569d05..eee480aae8 100644 --- a/internal/build/lifecycle_execution_test.go +++ b/internal/build/lifecycle_execution_test.go @@ -137,14 +137,12 @@ func testLifecycleExecution(t *testing.T, when spec.G, it spec.S) { // construct fixtures for extensions if extensionsForBuild { if platformAPI.LessThan("0.13") { - // the directory is /generated/build inside the build container, but `CopyOutTo` only copies the directory - err = os.MkdirAll(filepath.Join(tmpDir, "build", "some-buildpack-id"), 0755) + err = os.MkdirAll(filepath.Join(tmpDir, "generated", "build", "some-buildpack-id"), 0755) h.AssertNil(t, err) } else { - // the directory is /generated/some-buildpack-id inside the build container, but `CopyOutTo` only copies the directory - err = os.MkdirAll(filepath.Join(tmpDir, "some-buildpack-id"), 0755) + err = os.MkdirAll(filepath.Join(tmpDir, "generated", "some-buildpack-id"), 0755) h.AssertNil(t, err) - _, err = os.Create(filepath.Join(tmpDir, "some-buildpack-id", "Dockerfile.build")) + _, err = os.Create(filepath.Join(tmpDir, "generated", "some-buildpack-id", "build.Dockerfile")) h.AssertNil(t, err) } }