From 8f6b16f6b5c122d2cc1a22a344ccde288dc035ed Mon Sep 17 00:00:00 2001 From: Gabriel Cipriano Date: Sun, 19 Nov 2023 14:54:18 -0300 Subject: [PATCH] feat: validate ko's main path (#4429) closes #4382 --- internal/pipe/ko/ko.go | 23 +++++++++++++++- internal/pipe/ko/ko_test.go | 52 ++++++++++++++++++++++++++++++++++++ www/docs/customization/ko.md | 1 + 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/internal/pipe/ko/ko.go b/internal/pipe/ko/ko.go index 26e8f5a37ca..de96202559a 100644 --- a/internal/pipe/ko/ko.go +++ b/internal/pipe/ko/ko.go @@ -8,6 +8,7 @@ import ( "fmt" "io" "path/filepath" + "regexp" "strconv" "strings" "sync" @@ -48,7 +49,8 @@ var ( azureKeychain, ) - errNoRepository = errors.New("ko: missing repository: please set either the repository field or a $KO_DOCKER_REPO environment variable") + errNoRepository = errors.New("ko: missing repository: please set either the repository field or a $KO_DOCKER_REPO environment variable") + errInvalidMainPath = errors.New("ko: invalid Main path: ko.main (or build.main if ko.main is not set) should be a relative path.") ) // Pipe that build OCI compliant images with ko. @@ -93,6 +95,10 @@ func (Pipe) Default(ctx *context.Context) error { ko.Main = build.Main } + if err := validateMainPath(ko.Main); err != nil { + return err + } + if ko.WorkingDir == "" { ko.WorkingDir = build.Dir } @@ -420,3 +426,18 @@ func getTimeFromTemplate(ctx *context.Context, t string) (*v1.Time, error) { } return &v1.Time{Time: time.Unix(seconds, 0)}, nil } + +func validateMainPath(path string) error { + // if the path is empty, it's probably fine as ko will use the default value + if path == "" { + return nil + } + if matched, _ := regexp.MatchString(`^\.?(\.\/[^\/]?.*)?$`, path); !matched { + return errInvalidMainPath + } + // paths sure can have dots in them, but if the path ends in .go, it's propably a file that one misundertood as a valid value + if strings.HasSuffix(path, ".go") { + return errInvalidMainPath + } + return nil +} diff --git a/internal/pipe/ko/ko_test.go b/internal/pipe/ko/ko_test.go index 43485abcc03..4ed31953bdc 100644 --- a/internal/pipe/ko/ko_test.go +++ b/internal/pipe/ko/ko_test.go @@ -340,6 +340,58 @@ func TestPublishPipeSuccess(t *testing.T) { } } +func TestKoValidateMainPathIssue4382(t *testing.T) { + // testing the validation of the main path directly to cover many cases + require.NoError(t, validateMainPath("")) + require.NoError(t, validateMainPath(".")) + require.NoError(t, validateMainPath("./...")) + require.NoError(t, validateMainPath("./app")) + require.NoError(t, validateMainPath("../../../...")) + require.NoError(t, validateMainPath("../../app/")) + require.NoError(t, validateMainPath("./testdata/app/main")) + require.NoError(t, validateMainPath("./testdata/app/folder.with.dots")) + + require.ErrorIs(t, validateMainPath("app/"), errInvalidMainPath) + require.ErrorIs(t, validateMainPath("/src/"), errInvalidMainPath) + require.ErrorIs(t, validateMainPath("/src/app"), errInvalidMainPath) + require.ErrorIs(t, validateMainPath("./testdata/app/main.go"), errInvalidMainPath) + + // testing with real context + ctxOk := testctx.NewWithCfg(config.Project{ + Builds: []config.Build{ + { + ID: "foo", + Main: "./...", + }, + }, + Kos: []config.Ko{ + { + ID: "default", + Build: "foo", + Repository: "fakerepo", + }, + }, + }) + require.NoError(t, Pipe{}.Default(ctxOk)) + + ctxWithInvalidMainPath := testctx.NewWithCfg(config.Project{ + Builds: []config.Build{ + { + ID: "foo", + Main: "/some/non/relative/path", + }, + }, + Kos: []config.Ko{ + { + ID: "default", + Build: "foo", + Repository: "fakerepo", + }, + }, + }) + require.ErrorIs(t, Pipe{}.Default(ctxWithInvalidMainPath), errInvalidMainPath) +} + func TestPublishPipeError(t *testing.T) { makeCtx := func() *context.Context { return testctx.NewWithCfg(config.Project{ diff --git a/www/docs/customization/ko.md b/www/docs/customization/ko.md index 30c1108f46c..edd03a8b01a 100644 --- a/www/docs/customization/ko.md +++ b/www/docs/customization/ko.md @@ -25,6 +25,7 @@ kos: build: build-id # Main path to build. + # It must be a relative path # # Default: build.main main: ./cmd/...