Skip to content

Commit

Permalink
Merge pull request #47 from buildpacks/feat/validate-image-name-on-da…
Browse files Browse the repository at this point in the history
…emon

Validate image name
  • Loading branch information
AidanDelaney authored Jul 11, 2024
2 parents 16f4932 + 8c60837 commit 57c0368
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 8 deletions.
60 changes: 60 additions & 0 deletions internal/commands/build.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package commands

import (
"fmt"
"os"
"path/filepath"
"strconv"
Expand Down Expand Up @@ -143,6 +144,11 @@ func Build(logger logging.Logger, cfg config.Config, packClient PackClient) *cob
lifecycleImage = ref.Name()
}

err = isForbiddenTag(cfg, inputImageName.Name(), lifecycleImage, builder)
if err != nil {
return errors.Wrapf(err, "forbidden image name")
}

var gid = -1
if cmd.Flags().Changed("gid") {
gid = flags.GID
Expand Down Expand Up @@ -385,3 +391,57 @@ func parseProjectToml(appPath, descriptorPath string, logger logging.Logger) (pr
descriptor, err := project.ReadProjectDescriptor(actualPath, logger)
return descriptor, actualPath, err
}

func isForbiddenTag(cfg config.Config, input, lifecycle, builder string) error {
inputImage, err := name.ParseReference(input)
if err != nil {
return errors.Wrapf(err, "invalid image name %s", input)
}

if builder != "" {
builderImage, err := name.ParseReference(builder)
if err != nil {
return errors.Wrapf(err, "parsing builder image %s", builder)
}
if inputImage.Context().RepositoryStr() == builderImage.Context().RepositoryStr() {
return fmt.Errorf("name must not match builder image name")
}
}

if lifecycle != "" {
lifecycleImage, err := name.ParseReference(lifecycle)
if err != nil {
return errors.Wrapf(err, "parsing lifecycle image %s", lifecycle)
}
if inputImage.Context().RepositoryStr() == lifecycleImage.Context().RepositoryStr() {
return fmt.Errorf("name must not match lifecycle image name")
}
}

trustedBuilders := getTrustedBuilders(cfg)
for _, trustedBuilder := range trustedBuilders {
builder, err := name.ParseReference(trustedBuilder)
if err != nil {
return err
}
if inputImage.Context().RepositoryStr() == builder.Context().RepositoryStr() {
return fmt.Errorf("name must not match trusted builder name")
}
}

if inputImage.Context().RepositoryStr() == config.DefaultLifecycleImageRepo {
return fmt.Errorf("name must not match default lifecycle image name")
}

if cfg.DefaultBuilder != "" {
defaultBuilderImage, err := name.ParseReference(cfg.DefaultBuilder)
if err != nil {
return errors.Wrapf(err, "parsing default builder %s", cfg.DefaultBuilder)
}
if inputImage.Context().RepositoryStr() == defaultBuilderImage.Context().RegistryStr() {
return fmt.Errorf("name must not match default builder image name")
}
}

return nil
}
33 changes: 28 additions & 5 deletions internal/commands/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,33 @@ func testBuildCommand(t *testing.T, when spec.G, it spec.S) {
})
})

when("the image name matches a builder name", func() {
it("refuses to build", func() {
logger.WantVerbose(true)
command.SetArgs([]string{"heroku/builder:test", "--builder", "heroku/builder:24"})
h.AssertNotNil(t, command.Execute())
h.AssertContains(t, outBuf.String(), "name must not match builder image name")
})
})

when("the image name matches a trusted-builder name", func() {
it("refuses to build", func() {
logger.WantVerbose(true)
command.SetArgs([]string{"heroku/builder:test", "--builder", "test", "--trust-builder"})
h.AssertNotNil(t, command.Execute())
h.AssertContains(t, outBuf.String(), "name must not match trusted builder name")
})
})

when("the image name matches a lifecycle image name", func() {
it("refuses to build", func() {
logger.WantVerbose(true)
command.SetArgs([]string{"buildpacksio/lifecycle:test", "--builder", "test", "--trust-builder"})
h.AssertNotNil(t, command.Execute())
h.AssertContains(t, outBuf.String(), "name must not match default lifecycle image name")
})
})

when("the builder is not trusted", func() {
it("warns the user that the builder is untrusted", func() {
mockClient.EXPECT().
Expand Down Expand Up @@ -803,13 +830,9 @@ builder = "my-builder"
when("previous-image flag is provided", func() {
when("image is invalid", func() {
it("error must be thrown", func() {
mockClient.EXPECT().
Build(gomock.Any(), EqBuildOptionsWithPreviousImage("previous-image")).
Return(errors.New(""))

command.SetArgs([]string{"--builder", "my-builder", "/x@/y/?!z", "--previous-image", "previous-image"})
err := command.Execute()
h.AssertError(t, err, "failed to build")
h.AssertError(t, err, "forbidden image name")
})
})

Expand Down
10 changes: 7 additions & 3 deletions internal/commands/config_trusted_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,7 @@ func removeTrustedBuilder(args []string, logger logging.Logger, cfg config.Confi
return nil
}

func listTrustedBuilders(args []string, logger logging.Logger, cfg config.Config) {
logger.Info("Trusted Builders:")

func getTrustedBuilders(cfg config.Config) []string {
var trustedBuilders []string
for _, knownBuilder := range bldr.KnownBuilders {
if knownBuilder.Trusted {
Expand All @@ -113,7 +111,13 @@ func listTrustedBuilders(args []string, logger logging.Logger, cfg config.Config
}

sort.Strings(trustedBuilders)
return trustedBuilders
}

func listTrustedBuilders(args []string, logger logging.Logger, cfg config.Config) {
logger.Info("Trusted Builders:")

trustedBuilders := getTrustedBuilders(cfg)
for _, builder := range trustedBuilders {
logger.Infof(" %s", builder)
}
Expand Down

0 comments on commit 57c0368

Please sign in to comment.