Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Use the untrusted flow when buildpacks are added to a trusted builder #30

Merged
merged 4 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions acceptance/acceptance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1627,6 +1627,7 @@ func testAcceptance(

it.Before(func() {
h.SkipIf(t, os.Getenv("DOCKER_HOST") != "", "cannot mount volume when DOCKER_HOST is set")
h.SkipIf(t, imageManager.HostOS() == "windows", "These tests are broken on Windows Containers on Windows when not using the creator; see https://github.com/buildpacks/pack/issues/2147")

if imageManager.HostOS() == "windows" {
volumeRoot = `c:\`
Expand Down
70 changes: 47 additions & 23 deletions pkg/client/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ func (c *Client) Build(ctx context.Context, opts BuildOptions) error {
return err
}

fetchedBPs, order, err := c.processBuildpacks(ctx, bldr.Buildpacks(), bldr.Order(), bldr.StackID, opts, targetToUse)
fetchedBPs, nInlineBPs, order, err := c.processBuildpacks(ctx, bldr.Buildpacks(), bldr.Order(), bldr.StackID, opts, targetToUse)
if err != nil {
return err
}
Expand Down Expand Up @@ -418,6 +418,19 @@ func (c *Client) Build(ctx context.Context, opts BuildOptions) error {
// Get the platform API version to use
lifecycleVersion := bldr.LifecycleDescriptor().Info.Version
useCreator := supportsCreator(lifecycleVersion) && opts.TrustBuilder(opts.Builder)
hasAdditionalModules := func() bool {
if len(fetchedBPs) == 0 && len(fetchedExs) == 0 {
return false
}
if len(fetchedBPs) == nInlineBPs && len(fetchedExs) == 0 {
return false
}
return true
}()
if useCreator && hasAdditionalModules {
c.logger.Warnf("Builder is trusted but additional modules were added; using the untrusted (5 phases) build flow")
useCreator = false
}
var (
lifecycleOptsLifecycleImage string
lifecycleAPIs []string
Expand Down Expand Up @@ -1140,18 +1153,21 @@ func (c *Client) processProxyConfig(config *ProxyConfig) ProxyConfig {
// ----------
// - group:
// - A
func (c *Client) processBuildpacks(ctx context.Context, builderBPs []dist.ModuleInfo, builderOrder dist.Order, stackID string, opts BuildOptions, targetToUse *dist.Target) (fetchedBPs []buildpack.BuildModule, order dist.Order, err error) {
func (c *Client) processBuildpacks(ctx context.Context, builderBPs []dist.ModuleInfo, builderOrder dist.Order, stackID string, opts BuildOptions, targetToUse *dist.Target) (fetchedBPs []buildpack.BuildModule, nInlineBPs int, order dist.Order, err error) {
relativeBaseDir := opts.RelativeBaseDir
declaredBPs := opts.Buildpacks

// declare buildpacks provided by project descriptor when no buildpacks are declared
// Buildpacks from --buildpack override buildpacks from project descriptor
if len(declaredBPs) == 0 && len(opts.ProjectDescriptor.Build.Buildpacks) != 0 {
relativeBaseDir = opts.ProjectDescriptorBaseDir

for _, bp := range opts.ProjectDescriptor.Build.Buildpacks {
buildpackLocator, err := getBuildpackLocator(bp, stackID)
buildpackLocator, isInline, err := getBuildpackLocator(bp, stackID)
if err != nil {
return nil, nil, err
return nil, 0, nil, err
}
if isInline {
nInlineBPs++
}
declaredBPs = append(declaredBPs, buildpackLocator)
}
Expand All @@ -1161,7 +1177,7 @@ func (c *Client) processBuildpacks(ctx context.Context, builderBPs []dist.Module
for _, bp := range declaredBPs {
locatorType, err := buildpack.GetLocatorType(bp, relativeBaseDir, builderBPs)
if err != nil {
return nil, nil, err
return nil, 0, nil, err
}

switch locatorType {
Expand All @@ -1171,7 +1187,7 @@ func (c *Client) processBuildpacks(ctx context.Context, builderBPs []dist.Module
order = builderOrder
case len(order) > 1:
// This should only ever be possible if they are using from=builder twice which we don't allow
return nil, nil, errors.New("buildpacks from builder can only be defined once")
return nil, 0, nil, errors.New("buildpacks from builder can only be defined once")
default:
newOrder := dist.Order{}
groupToAdd := order[0].Group
Expand All @@ -1185,7 +1201,7 @@ func (c *Client) processBuildpacks(ctx context.Context, builderBPs []dist.Module
default:
newFetchedBPs, moduleInfo, err := c.fetchBuildpack(ctx, bp, relativeBaseDir, builderBPs, opts, buildpack.KindBuildpack, targetToUse)
if err != nil {
return fetchedBPs, order, err
return fetchedBPs, 0, order, err
}
fetchedBPs = append(fetchedBPs, newFetchedBPs...)
order = appendBuildpackToOrder(order, *moduleInfo)
Expand All @@ -1195,20 +1211,28 @@ func (c *Client) processBuildpacks(ctx context.Context, builderBPs []dist.Module
if (len(order) == 0 || len(order[0].Group) == 0) && len(builderOrder) > 0 {
preBuildpacks := opts.PreBuildpacks
postBuildpacks := opts.PostBuildpacks
// Pre-buildpacks from --pre-buildpack override pre-buildpacks from project descriptor
if len(preBuildpacks) == 0 && len(opts.ProjectDescriptor.Build.Pre.Buildpacks) > 0 {
for _, bp := range opts.ProjectDescriptor.Build.Pre.Buildpacks {
buildpackLocator, err := getBuildpackLocator(bp, stackID)
buildpackLocator, isInline, err := getBuildpackLocator(bp, stackID)
if err != nil {
return nil, nil, errors.Wrap(err, "get pre-buildpack locator")
return nil, 0, nil, errors.Wrap(err, "get pre-buildpack locator")
}
if isInline {
nInlineBPs++
}
preBuildpacks = append(preBuildpacks, buildpackLocator)
}
}
// Post-buildpacks from --post-buildpack override post-buildpacks from project descriptor
if len(postBuildpacks) == 0 && len(opts.ProjectDescriptor.Build.Post.Buildpacks) > 0 {
for _, bp := range opts.ProjectDescriptor.Build.Post.Buildpacks {
buildpackLocator, err := getBuildpackLocator(bp, stackID)
buildpackLocator, isInline, err := getBuildpackLocator(bp, stackID)
if err != nil {
return nil, nil, errors.Wrap(err, "get post-buildpack locator")
return nil, 0, nil, errors.Wrap(err, "get post-buildpack locator")
}
if isInline {
nInlineBPs++
}
postBuildpacks = append(postBuildpacks, buildpackLocator)
}
Expand All @@ -1219,7 +1243,7 @@ func (c *Client) processBuildpacks(ctx context.Context, builderBPs []dist.Module
for _, bp := range preBuildpacks {
newFetchedBPs, moduleInfo, err := c.fetchBuildpack(ctx, bp, relativeBaseDir, builderBPs, opts, buildpack.KindBuildpack, targetToUse)
if err != nil {
return fetchedBPs, order, err
return fetchedBPs, 0, order, err
}
fetchedBPs = append(fetchedBPs, newFetchedBPs...)
order = prependBuildpackToOrder(order, *moduleInfo)
Expand All @@ -1228,15 +1252,15 @@ func (c *Client) processBuildpacks(ctx context.Context, builderBPs []dist.Module
for _, bp := range postBuildpacks {
newFetchedBPs, moduleInfo, err := c.fetchBuildpack(ctx, bp, relativeBaseDir, builderBPs, opts, buildpack.KindBuildpack, targetToUse)
if err != nil {
return fetchedBPs, order, err
return fetchedBPs, 0, order, err
}
fetchedBPs = append(fetchedBPs, newFetchedBPs...)
order = appendBuildpackToOrder(order, *moduleInfo)
}
}
}

return fetchedBPs, order, nil
return fetchedBPs, nInlineBPs, order, nil
}

func (c *Client) fetchBuildpack(ctx context.Context, bp string, relativeBaseDir string, builderBPs []dist.ModuleInfo, opts BuildOptions, kind string, targetToUse *dist.Target) ([]buildpack.BuildModule, *dist.ModuleInfo, error) {
Expand Down Expand Up @@ -1315,26 +1339,26 @@ func (c *Client) fetchBuildpackDependencies(ctx context.Context, bp string, pack
return nil, err
}

func getBuildpackLocator(bp projectTypes.Buildpack, stackID string) (string, error) {
func getBuildpackLocator(bp projectTypes.Buildpack, stackID string) (locator string, isInline bool, err error) {
switch {
case bp.ID != "" && bp.Script.Inline != "" && bp.URI == "":
if bp.Script.API == "" {
return "", errors.New("Missing API version for inline buildpack")
return "", false, errors.New("Missing API version for inline buildpack")
}

pathToInlineBuildpack, err := createInlineBuildpack(bp, stackID)
if err != nil {
return "", errors.Wrap(err, "Could not create temporary inline buildpack")
return "", false, errors.Wrap(err, "Could not create temporary inline buildpack")
}
return pathToInlineBuildpack, nil
return pathToInlineBuildpack, true, nil
case bp.URI != "":
return bp.URI, nil
return bp.URI, false, nil
case bp.ID != "" && bp.Version != "":
return fmt.Sprintf("%s@%s", bp.ID, bp.Version), nil
return fmt.Sprintf("%s@%s", bp.ID, bp.Version), false, nil
case bp.ID != "" && bp.Version == "":
return bp.ID, nil
return bp.ID, false, nil
default:
return "", errors.New("Invalid buildpack definition")
return "", false, errors.New("Invalid buildpack definition")
}
}

Expand Down
84 changes: 81 additions & 3 deletions pkg/client/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2050,9 +2050,6 @@ api = "0.2"
h.AssertEq(t, args.PullPolicy, image.PullAlways)
h.AssertEq(t, args.Target.ValuesAsPlatform(), "linux/amd64")
})
it("uses the api versions of the lifecycle image", func() {
h.AssertTrue(t, true)
})
it("parses the versions correctly", func() {
fakeLifecycleImage.SetLabel("io.buildpacks.lifecycle.apis", "{\"platform\":{\"deprecated\":[\"0.1\",\"0.2\",\"0.3\",\"0.4\",\"0.5\",\"0.6\"],\"supported\":[\"0.7\",\"0.8\",\"0.9\",\"0.10\",\"0.11\",\"0.12\"]}}")

Expand Down Expand Up @@ -2092,6 +2089,87 @@ api = "0.2"
args := fakeImageFetcher.FetchCalls[fakeLifecycleImage.Name()]
h.AssertNil(t, args)
})

when("additional buildpacks were added", func() {
it("uses the 5 phases with the lifecycle image", func() {
additionalBP := ifakes.CreateBuildpackTar(t, tmpDir, dist.BuildpackDescriptor{
WithAPI: api.MustParse("0.3"),
WithInfo: dist.ModuleInfo{
ID: "buildpack.add.1.id",
Version: "buildpack.add.1.version",
},
WithStacks: []dist.Stack{{ID: defaultBuilderStackID}},
WithOrder: nil,
})

h.AssertNil(t, subject.Build(context.TODO(), BuildOptions{
Image: "some/app",
Builder: defaultBuilderName,
Publish: true,
TrustBuilder: func(string) bool { return true },
Buildpacks: []string{additionalBP},
}))
h.AssertEq(t, fakeLifecycle.Opts.UseCreator, false)
h.AssertEq(t, fakeLifecycle.Opts.LifecycleImage, fakeLifecycleImage.Name())

h.AssertContains(t, outBuf.String(), "Builder is trusted but additional modules were added; using the untrusted (5 phases) build flow")
})

when("from project descriptor", func() {
it("uses the 5 phases with the lifecycle image", func() {
additionalBP := ifakes.CreateBuildpackTar(t, tmpDir, dist.BuildpackDescriptor{
WithAPI: api.MustParse("0.3"),
WithInfo: dist.ModuleInfo{
ID: "buildpack.add.1.id",
Version: "buildpack.add.1.version",
},
WithStacks: []dist.Stack{{ID: defaultBuilderStackID}},
WithOrder: nil,
})

h.AssertNil(t, subject.Build(context.TODO(), BuildOptions{
Image: "some/app",
Builder: defaultBuilderName,
Publish: true,
TrustBuilder: func(string) bool { return true },
ProjectDescriptor: projectTypes.Descriptor{Build: projectTypes.Build{
Buildpacks: []projectTypes.Buildpack{{
URI: additionalBP,
}},
}},
}))
h.AssertEq(t, fakeLifecycle.Opts.UseCreator, false)
h.AssertEq(t, fakeLifecycle.Opts.LifecycleImage, fakeLifecycleImage.Name())

h.AssertContains(t, outBuf.String(), "Builder is trusted but additional modules were added; using the untrusted (5 phases) build flow")
})

when("inline buildpack", func() {
it("uses the creator with the provided builder", func() {
h.AssertNil(t, subject.Build(context.TODO(), BuildOptions{
Image: "some/app",
Builder: defaultBuilderName,
Publish: true,
TrustBuilder: func(string) bool { return true },
ProjectDescriptor: projectTypes.Descriptor{Build: projectTypes.Build{
Buildpacks: []projectTypes.Buildpack{{
ID: "buildpack.add.1.id",
Version: "buildpack.add.1.version",
Script: projectTypes.Script{
API: "0.10",
Inline: "echo hello",
},
}},
}},
}))
h.AssertEq(t, fakeLifecycle.Opts.UseCreator, true)

args := fakeImageFetcher.FetchCalls[fakeLifecycleImage.Name()]
h.AssertNil(t, args)
})
})
})
})
})

when("lifecycle doesn't support creator", func() {
Expand Down
Loading