diff --git a/api/go.mod b/api/go.mod index e9e6816c9b..845f67ad42 100644 --- a/api/go.mod +++ b/api/go.mod @@ -8,7 +8,7 @@ require ( github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/imdario/mergo v0.3.6 github.com/pkg/errors v0.9.1 - github.com/stretchr/testify v1.7.0 + github.com/stretchr/testify v1.8.0 gopkg.in/yaml.v2 v2.4.0 k8s.io/kube-openapi v0.0.0-20220401212409-b28bf2818661 sigs.k8s.io/kustomize/kyaml v0.13.9 @@ -34,5 +34,5 @@ require ( golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect golang.org/x/text v0.3.7 // indirect google.golang.org/protobuf v1.28.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/api/go.sum b/api/go.sum index e4e10a60c2..3e9c3314bd 100644 --- a/api/go.sum +++ b/api/go.sum @@ -99,12 +99,15 @@ github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= +github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -199,8 +202,9 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= diff --git a/api/ifc/ifc.go b/api/ifc/ifc.go index 9fd297478a..4f47afb0ac 100644 --- a/api/ifc/ifc.go +++ b/api/ifc/ifc.go @@ -28,12 +28,20 @@ type KvLoader interface { // Loader interface exposes methods to read bytes. type Loader interface { + + // Repo returns the repo location and true if this Loader + // was created from a url; otherwise the empty string and false. + Repo() (string, bool) + // Root returns the root location for this Loader. Root() string + // New returns Loader located at newRoot. New(newRoot string) (Loader, error) + // Load returns the bytes read from the location or an error. Load(location string) ([]byte, error) + // Cleanup cleans the loader Cleanup() error } diff --git a/api/internal/git/repospec.go b/api/internal/git/repospec.go index 996f0cf239..017c66eb14 100644 --- a/api/internal/git/repospec.go +++ b/api/internal/git/repospec.go @@ -11,6 +11,7 @@ import ( "strings" "time" + "sigs.k8s.io/kustomize/kyaml/errors" "sigs.k8s.io/kustomize/kyaml/filesys" ) @@ -21,13 +22,18 @@ import ( // with a unique name that isn't created until clone time. const notCloned = filesys.ConfirmedDir("/notCloned") +// Schemes returns the schemes that repo urls may have +func Schemes() []string { + return []string{"https://", "http://", "ssh://"} +} + // RepoSpec specifies a git repository and a branch and path therein. type RepoSpec struct { // Raw, original spec, used to look for cycles. // TODO(monopole): Drop raw, use processed fields instead. raw string - // Host, e.g. github.com + // Host, e.g. https://github.com/ Host string // orgRepo name (organization/repoName), @@ -86,17 +92,14 @@ func NewRepoSpecFromURL(n string) (*RepoSpec, error) { if filepath.IsAbs(n) { return nil, fmt.Errorf("uri looks like abs path: %s", n) } - host, orgRepo, path, gitRef, gitSubmodules, suffix, gitTimeout := parseGitURL(n) - if orgRepo == "" { - return nil, fmt.Errorf("url lacks orgRepo: %s", n) + repoSpec := parseGitURL(n) + if repoSpec.Host == "" { + return nil, errors.Errorf("url lacks host: %s", n) } - if host == "" { - return nil, fmt.Errorf("url lacks host: %s", n) + if repoSpec.OrgRepo == "" { + return nil, errors.Errorf("url lacks orgRepo: %s", n) } - return &RepoSpec{ - raw: n, Host: host, OrgRepo: orgRepo, - Dir: notCloned, Path: path, Ref: gitRef, GitSuffix: suffix, - Submodules: gitSubmodules, Timeout: gitTimeout}, nil + return repoSpec, nil } const ( @@ -108,44 +111,47 @@ const ( // From strings like git@github.com:someOrg/someRepo.git or // https://github.com/someOrg/someRepo?ref=someHash, extract // the parts. -func parseGitURL(n string) ( - host string, orgRepo string, path string, gitRef string, gitSubmodules bool, gitSuff string, gitTimeout time.Duration) { +func parseGitURL(n string) *RepoSpec { + repoSpec := &RepoSpec{raw: n, Dir: notCloned} + if strings.Contains(n, gitDelimiter) { index := strings.Index(n, gitDelimiter) // Adding _git/ to host - host = normalizeGitHostSpec(n[:index+len(gitDelimiter)]) - orgRepo = strings.Split(strings.Split(n[index+len(gitDelimiter):], "/")[0], "?")[0] - path, gitRef, gitTimeout, gitSubmodules = peelQuery(n[index+len(gitDelimiter)+len(orgRepo):]) - return + repoSpec.Host = normalizeGitHostSpec(n[:index+len(gitDelimiter)]) + // url before next /, though make sure before ? query string delimiter + repoSpec.OrgRepo = strings.Split(strings.Split(n[index+len(gitDelimiter):], "/")[0], "?")[0] + repoSpec.Path, repoSpec.Ref, repoSpec.Timeout, repoSpec.Submodules = + peelQuery(n[index+len(gitDelimiter)+len(repoSpec.OrgRepo):]) + return repoSpec } - host, n = parseHostSpec(n) - gitSuff = gitSuffix + + repoSpec.Host, n = parseHostSpec(n) + + repoSpec.GitSuffix = gitSuffix if strings.Contains(n, gitSuffix) { index := strings.Index(n, gitSuffix) - orgRepo = n[0:index] + repoSpec.OrgRepo = n[0:index] n = n[index+len(gitSuffix):] + // always try to include / in previous component if len(n) > 0 && n[0] == '/' { n = n[1:] } - path, gitRef, gitTimeout, gitSubmodules = peelQuery(n) - return - } - - i := strings.Index(n, "/") - if i < 1 { - path, gitRef, gitTimeout, gitSubmodules = peelQuery(n) - return - } - j := strings.Index(n[i+1:], "/") - if j >= 0 { + } else if strings.Contains(n, "/") { + // there exist at least 2 components that we can interpret as org + repo + i := strings.Index(n, "/") + j := strings.Index(n[i+1:], "/") + // only 2 components, so can use peelQuery to group everything before ? query string delimiter as OrgRepo + if j == -1 { + repoSpec.OrgRepo, repoSpec.Ref, repoSpec.Timeout, repoSpec.Submodules = peelQuery(n) + return repoSpec + } + // extract first 2 components j += i + 1 - orgRepo = n[:j] - path, gitRef, gitTimeout, gitSubmodules = peelQuery(n[j+1:]) - return + repoSpec.OrgRepo = n[:j] + n = n[j+1:] } - path = "" - orgRepo, gitRef, gitTimeout, gitSubmodules = peelQuery(n) - return host, orgRepo, path, gitRef, gitSubmodules, gitSuff, gitTimeout + repoSpec.Path, repoSpec.Ref, repoSpec.Timeout, repoSpec.Submodules = peelQuery(n) + return repoSpec } // Clone git submodules by default. @@ -197,6 +203,7 @@ func peelQuery(arg string) (string, string, time.Duration, bool) { func parseHostSpec(n string) (string, string) { var host string + // TODO(annasong): handle ports, non-github ssh with userinfo, github.com sub-domains // Start accumulating the host part. for _, p := range []string{ // Order matters here. @@ -207,24 +214,29 @@ func parseHostSpec(n string) (string, string) { host += p } } + // ssh relative path if host == "git@" { - i := strings.Index(n, "/") - if i > -1 { + var i int + // git orgRepo delimiter for ssh relative path + j := strings.Index(n, ":") + // orgRepo delimiter only valid if not preceded by / + k := strings.Index(n, "/") + // orgRepo delimiter exists, so extend host + if j > -1 && (k == -1 || k > j) { + i = j + // should try to group / with previous component + // this is possible if git url username expansion follows + if k == i+1 { + i = k + } host += n[:i+1] n = n[i+1:] - } else { - i = strings.Index(n, ":") - if i > -1 { - host += n[:i+1] - n = n[i+1:] - } } return host, n } // If host is a http(s) or ssh URL, grab the domain part. - for _, p := range []string{ - "ssh://", "https://", "http://"} { + for _, p := range Schemes() { if strings.HasSuffix(host, p) { i := strings.Index(n, "/") if i > -1 { diff --git a/api/internal/git/repospec_test.go b/api/internal/git/repospec_test.go index 41e89ca31e..5fd72b9918 100644 --- a/api/internal/git/repospec_test.go +++ b/api/internal/git/repospec_test.go @@ -19,22 +19,25 @@ var pathNames = []string{"README.md", "foo/krusty.txt", ""} var hrefArgs = []string{"someBranch", "master", "v0.1.0", ""} -var hostNamesRawAndNormalized = [][]string{ - {"gh:", "gh:"}, - {"GH:", "gh:"}, - {"gitHub.com/", "https://github.com/"}, - {"github.com:", "https://github.com/"}, - {"http://github.com/", "https://github.com/"}, - {"https://github.com/", "https://github.com/"}, - {"hTTps://github.com/", "https://github.com/"}, - {"https://git-codecommit.us-east-2.amazonaws.com/", "https://git-codecommit.us-east-2.amazonaws.com/"}, - {"https://fabrikops2.visualstudio.com/", "https://fabrikops2.visualstudio.com/"}, - {"ssh://git.example.com:7999/", "ssh://git.example.com:7999/"}, - {"git::https://gitlab.com/", "https://gitlab.com/"}, - {"git::http://git.example.com/", "http://git.example.com/"}, - {"git::https://git.example.com/", "https://git.example.com/"}, - {"git@github.com:", "git@github.com:"}, - {"git@github.com/", "git@github.com:"}, +func hostsRawNormalizedAndDomain() [][]string { + return [][]string{ + {"gh:", "gh:"}, + {"GH:", "gh:"}, + {"gitHub.com/", "https://github.com/"}, + {"github.com:", "https://github.com/"}, + {"http://github.com/", "https://github.com/"}, + {"https://github.com/", "https://github.com/"}, + {"hTTps://github.com/", "https://github.com/"}, + {"https://git-codecommit.us-east-2.amazonaws.com/", "https://git-codecommit.us-east-2.amazonaws.com/"}, + {"https://fabrikops2.visualstudio.com/", "https://fabrikops2.visualstudio.com/"}, + {"ssh://git.example.com:7999/", "ssh://git.example.com:7999/"}, + {"git::https://gitlab.com/", "https://gitlab.com/"}, + {"git::http://git.example.com/", "http://git.example.com/"}, + {"git::https://git.example.com/", "https://git.example.com/"}, + {"git@github.com:", "git@github.com:"}, + {"git@github.com/", "git@github.com:"}, + {"git@gitlab.com:", "git@gitlab.com:"}, + } } func makeURL(hostFmt, orgRepo, path, href string) string { @@ -50,7 +53,7 @@ func makeURL(hostFmt, orgRepo, path, href string) string { func TestNewRepoSpecFromUrl(t *testing.T) { var bad [][]string - for _, tuple := range hostNamesRawAndNormalized { + for _, tuple := range hostsRawNormalizedAndDomain() { hostRaw := tuple[0] hostSpec := tuple[1] for _, orgRepo := range orgRepos { @@ -91,10 +94,10 @@ func TestNewRepoSpecFromUrl(t *testing.T) { var badData = [][]string{ {"/tmp", "uri looks like abs path"}, - {"iauhsdiuashduas", "url lacks orgRepo"}, + {"iauhsdiuashduas", "url lacks host"}, {"htxxxtp://github.com/", "url lacks host"}, {"ssh://git.example.com", "url lacks orgRepo"}, - {"git::___", "url lacks orgRepo"}, + {"git::___", "url lacks host"}, } func TestNewRepoSpecFromUrlErrors(t *testing.T) { @@ -147,6 +150,7 @@ func TestNewRepoSpecFromUrl_CloneSpecs(t *testing.T) { ref: "", }, "t6": { + // TODO(annasong): replace illegal test case with legal variations input: "git@gitlab2.sqtools.ru:10022/infra/kubernetes/thanos-base.git?ref=v0.1.0", cloneSpec: "git@gitlab2.sqtools.ru:10022/infra/kubernetes/thanos-base.git", absPath: notCloned.String(), diff --git a/api/internal/localizer/doc.go b/api/internal/localizer/doc.go new file mode 100644 index 0000000000..ebb8a699a8 --- /dev/null +++ b/api/internal/localizer/doc.go @@ -0,0 +1,7 @@ +// Copyright 2022 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +// This package contains utilities for the command kustomize localize, which is +// documented under proposals/localize-command or at +// https://github.com/kubernetes-sigs/kustomize/blob/master/proposals/22-04-localize-command.md +package localizer diff --git a/api/internal/localizer/locloader.go b/api/internal/localizer/locloader.go new file mode 100644 index 0000000000..08e0f88380 --- /dev/null +++ b/api/internal/localizer/locloader.go @@ -0,0 +1,147 @@ +// Copyright 2022 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package localizer + +import ( + "log" + "path/filepath" + + "sigs.k8s.io/kustomize/api/ifc" + "sigs.k8s.io/kustomize/api/internal/git" + "sigs.k8s.io/kustomize/api/loader" + "sigs.k8s.io/kustomize/kyaml/errors" + "sigs.k8s.io/kustomize/kyaml/filesys" +) + +const dstPrefix = "localized" + +// LocArgs holds localize arguments +type LocArgs struct { + + // target; local copy if remote + Target filesys.ConfirmedDir + + // directory that bounds target's local references, empty string if target is remote + Scope filesys.ConfirmedDir + + // localize destination + NewDir filesys.ConfirmedDir +} + +// locLoader is the Loader for kustomize localize. It is an ifc.Loader that enforces localize constraints. +type locLoader struct { + fSys filesys.FileSystem + + args *LocArgs + + // loader at locLoader's current directory + ifc.Loader + + // whether locLoader and all its ancestors are the result of local references + local bool +} + +var _ ifc.Loader = &locLoader{} + +// NewLocLoader is the factory method for Loader, under localize constraints, at targetArg. For invalid localize arguments, +// NewLocLoader returns an error. +func NewLocLoader(targetArg string, scopeArg string, newDirArg string, fSys filesys.FileSystem) (ifc.Loader, LocArgs, error) { + // check earlier to avoid cleanup + repoSpec, err := git.NewRepoSpecFromURL(targetArg) + if err == nil && repoSpec.Ref == "" { + return nil, LocArgs{}, + errors.Errorf("localize remote root '%s' missing ref query string parameter", targetArg) + } + + // for security, should enforce load restrictions + ldr, err := loader.NewLoader(loader.RestrictionRootOnly, targetArg, fSys) + if err != nil { + return nil, LocArgs{}, errors.WrapPrefixf(err, "unable to establish localize target '%s'", targetArg) + } + + scope, err := establishScope(scopeArg, targetArg, ldr, fSys) + if err != nil { + _ = ldr.Cleanup() + return nil, LocArgs{}, errors.WrapPrefixf(err, "invalid localize scope '%s'", scopeArg) + } + + newDir, err := createNewDir(newDirArg, ldr, repoSpec, fSys) + if err != nil { + _ = ldr.Cleanup() + return nil, LocArgs{}, errors.WrapPrefixf(err, "invalid localize destination '%s'", newDirArg) + } + + args := LocArgs{ + Target: filesys.ConfirmedDir(ldr.Root()), + Scope: scope, + NewDir: newDir, + } + return &locLoader{ + fSys: fSys, + args: &args, + Loader: ldr, + local: scope != "", + }, args, nil +} + +// Load returns the contents of path if path is a valid localize file. +// Otherwise, Load returns an error. +func (ll *locLoader) Load(path string) ([]byte, error) { + // checks in root, and thus in scope + content, err := ll.Loader.Load(path) + if err != nil { + return nil, errors.WrapPrefixf(err, "invalid file reference") + } + if filepath.IsAbs(path) { + return nil, errors.Errorf("absolute paths not yet supported in alpha: file path '%s' is absolute", path) + } + if ll.local { + abs := filepath.Join(ll.Root(), path) + dir, f, err := ll.fSys.CleanedAbs(abs) + if err != nil { + // should never happen + log.Fatalf(errors.WrapPrefixf(err, "cannot clean validated file path '%s'", abs).Error()) + } + // target cannot reference newDir, as this load would've failed prior to localize; + // not a problem if remote because then reference could only be in newDir if repo copy, + // which will be cleaned, is inside newDir + if dir.HasPrefix(ll.args.NewDir) { + return nil, errors.Errorf( + "file path '%s' references into localize destination '%s'", dir.Join(f), ll.args.NewDir) + } + } + return content, nil +} + +// New returns a Loader at path if path is a valid localize root. +// Otherwise, New returns an error. +func (ll *locLoader) New(path string) (ifc.Loader, error) { + repoSpec, err := git.NewRepoSpecFromURL(path) + if err == nil && repoSpec.Ref == "" { + return nil, errors.Errorf("localize remote root '%s' missing ref query string parameter", path) + } + + ldr, err := ll.Loader.New(path) + if err != nil { + return nil, errors.WrapPrefixf(err, "invalid root reference") + } + + var isRemote bool + if _, isRemote = ldr.Repo(); !isRemote { + if ll.local && !filesys.ConfirmedDir(ldr.Root()).HasPrefix(ll.args.Scope) { + return nil, errors.Errorf("root '%s' outside localize scope '%s'", ldr.Root(), ll.args.Scope) + } + if ll.local && filesys.ConfirmedDir(ldr.Root()).HasPrefix(ll.args.NewDir) { + return nil, errors.Errorf( + "root '%s' references into localize destination '%s'", ldr.Root(), ll.args.NewDir) + } + } + + return &locLoader{ + fSys: ll.fSys, + args: ll.args, + Loader: ldr, + local: ll.local && !isRemote, + }, nil +} diff --git a/api/internal/localizer/locloader_test.go b/api/internal/localizer/locloader_test.go new file mode 100644 index 0000000000..7d0f58858e --- /dev/null +++ b/api/internal/localizer/locloader_test.go @@ -0,0 +1,311 @@ +// Copyright 2022 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package localizer_test + +import ( + "bytes" + "log" + "testing" + + "github.com/stretchr/testify/require" + "sigs.k8s.io/kustomize/api/ifc" + lclzr "sigs.k8s.io/kustomize/api/internal/localizer" + "sigs.k8s.io/kustomize/kyaml/filesys" +) + +const dstPrefix = "localized" + +func makeMemoryFs(t *testing.T) filesys.FileSystem { + t.Helper() + req := require.New(t) + + fSys := filesys.MakeFsInMemory() + req.NoError(fSys.MkdirAll("/a/b")) + req.NoError(fSys.WriteFile("/a/kustomization.yaml", []byte("/a"))) + + dirChain := "/alpha/beta/gamma/delta" + req.NoError(fSys.MkdirAll(dirChain)) + req.NoError(fSys.WriteFile(dirChain+"/kustomization.yaml", []byte(dirChain))) + req.NoError(fSys.Mkdir("/alpha/beta/c")) + return fSys +} + +func checkNewLocLoader(req *require.Assertions, ldr ifc.Loader, args *lclzr.LocArgs, target string, scope string, newDir string, fSys filesys.FileSystem) { + checkLoader(req, ldr, target) + checkLocArgs(req, args, target, scope, newDir, fSys) +} + +func checkLoader(req *require.Assertions, ldr ifc.Loader, root string) { + req.Equal(root, ldr.Root()) + repo, isRemote := ldr.Repo() + req.Equal(false, isRemote) + req.Equal("", repo) +} + +func checkLocArgs(req *require.Assertions, args *lclzr.LocArgs, target string, scope string, newDir string, fSys filesys.FileSystem) { + req.Equal(target, args.Target.String()) + req.Equal(scope, args.Scope.String()) + req.Equal(newDir, args.NewDir.String()) + req.True(fSys.Exists(newDir)) +} + +func TestLocalLoadNewAndCleanup(t *testing.T) { + req := require.New(t) + fSys := makeMemoryFs(t) + + var buf bytes.Buffer + log.SetOutput(&buf) + // typical setup + ldr, args, err := lclzr.NewLocLoader("a", "/", "/newDir", fSys) + req.NoError(err) + checkNewLocLoader(req, ldr, &args, "/a", "/", "/newDir", fSys) + + fSysCopy := makeMemoryFs(t) + req.NoError(fSysCopy.Mkdir("/newDir")) + req.Equal(fSysCopy, fSys) + + // easy load directly in root + content, err := ldr.Load("kustomization.yaml") + req.NoError(err) + req.Equal([]byte("/a"), content) + + // typical sibling root reference + sibLdr, err := ldr.New("../alpha") + req.NoError(err) + checkLoader(req, sibLdr, "/alpha") + + // only need to test once, since don't need to call Cleanup() on local target + req.NoError(sibLdr.Cleanup()) + req.NoError(ldr.Cleanup()) + + // file system and buffer checks are also one-time + req.Equal(fSysCopy, fSys) + req.Empty(buf.String()) +} + +func TestNewLocLoaderDefaultForRootTarget(t *testing.T) { + cases := map[string]struct { + target string + scope string + }{ + "explicit": { + "/", + ".", + }, + "implicit": { + ".", + "", + }, + } + for name, params := range cases { + params := params + t.Run(name, func(t *testing.T) { + req := require.New(t) + fSys := makeMemoryFs(t) + + ldr, args, err := lclzr.NewLocLoader(params.target, params.scope, "", fSys) + req.NoError(err) + checkNewLocLoader(req, ldr, &args, "/", "/", "/"+dstPrefix, fSys) + + // file in root, but nested + content, err := ldr.Load("a/kustomization.yaml") + req.NoError(err) + req.Equal([]byte("/a"), content) + + childLdr, err := ldr.New("a") + req.NoError(err) + checkLoader(req, childLdr, "/a") + + // messy, uncleaned path + content, err = childLdr.Load("./../a/kustomization.yaml") + req.NoError(err) + req.Equal([]byte("/a"), content) + }) + } +} + +func TestNewMultiple(t *testing.T) { + req := require.New(t) + fSys := makeMemoryFs(t) + + // default destination for non-file system root target + // destination outside of scope + ldr, args, err := lclzr.NewLocLoader("/alpha/beta", "/alpha", "", fSys) + req.NoError(err) + checkNewLocLoader(req, ldr, &args, "/alpha/beta", "/alpha", "/"+dstPrefix+"-beta", fSys) + + // nested child root that isn't cleaned + descLdr, err := ldr.New("../beta/gamma/delta") + req.NoError(err) + checkLoader(req, descLdr, "/alpha/beta/gamma/delta") + + // upwards traversal + higherLdr, err := descLdr.New("../../c") + req.NoError(err) + checkLoader(req, higherLdr, "/alpha/beta/c") +} + +func makeWdFs(t *testing.T) map[string]filesys.FileSystem { + t.Helper() + req := require.New(t) + + root := filesys.MakeEmptyDirInMemory() + req.NoError(root.MkdirAll("a/b/c/d/e")) + + outer, err := root.Find("a") + req.NoError(err) + middle, err := root.Find("a/b/c") + req.NoError(err) + + return map[string]filesys.FileSystem{ + "a": outer, + "a/b/c": middle, + } +} + +func TestNewLocLoaderCwdNotRoot(t *testing.T) { + cases := map[string]struct { + wd string + target string + scope string + newDir string + }{ + // target not immediate child of scope + "outer dir": { + "a", + "b/c/d/e", + "b/c", + "b/newDir", + }, + "scope": { + "a/b/c", + "d/e", + ".", + "d/e/newDir", + }, + } + + for name, test := range cases { + test := test + t.Run(name, func(t *testing.T) { + req := require.New(t) + fSys := makeWdFs(t)[test.wd] + + ldr, args, err := lclzr.NewLocLoader(test.target, test.scope, test.newDir, fSys) + req.NoError(err) + checkLoader(req, ldr, "a/b/c/d/e") + + req.Equal("a/b/c/d/e", args.Target.String()) + req.Equal("a/b/c", args.Scope.String()) + req.Equal(test.wd+"/"+test.newDir, args.NewDir.String()) + // memory file system can only find paths rooted at current node + req.True(fSys.Exists(test.newDir)) + }) + } +} + +func TestNewLocLoaderFails(t *testing.T) { + cases := map[string]struct { + target string + scope string + dest string + }{ + "non-existent target": { + "/b", + "/", + "/newDir", + }, + "file target": { + "/a/kustomization.yaml", + "/", + "/newDir", + }, + "inner scope": { + "/alpha", + "/alpha/beta", + "/newDir", + }, + "side scope": { + "/alpha", + "/a", + "/newDir", + }, + "existing dst": { + "/alpha", + "/", + "/a", + }, + } + for name, params := range cases { + params := params + t.Run(name, func(t *testing.T) { + var buf bytes.Buffer + log.SetOutput(&buf) + _, _, err := lclzr.NewLocLoader(params.target, params.scope, params.dest, makeMemoryFs(t)) + require.Error(t, err) + require.Empty(t, buf.String()) + }) + } +} + +func TestNewFails(t *testing.T) { + req := require.New(t) + fSys := makeMemoryFs(t) + + ldr, args, err := lclzr.NewLocLoader("/alpha/beta/gamma", "alpha", "alpha/beta/gamma/newDir", fSys) + req.NoError(err) + checkNewLocLoader(req, ldr, &args, "/alpha/beta/gamma", "/alpha", "/alpha/beta/gamma/newDir", fSys) + + cases := map[string]string{ + "outside scope": "../../../a", + "at dst": "newDir", + "ancestor": "../../beta", + "non-existent root": "delt", + "file": "delta/kustomization.yaml", + } + for name, root := range cases { + root := root + t.Run(name, func(t *testing.T) { + fSys := makeMemoryFs(t) + + ldr, _, err := lclzr.NewLocLoader("/alpha/beta/gamma", "alpha", "alpha/beta/gamma/newDir", fSys) + require.NoError(t, err) + + _, err = ldr.New(root) + require.Error(t, err) + }) + } +} + +func TestLoadFails(t *testing.T) { + req := require.New(t) + fSys := makeMemoryFs(t) + + ldr, args, err := lclzr.NewLocLoader("./a/../a", "/a/../a", "/a/newDir", fSys) + req.NoError(err) + checkNewLocLoader(req, ldr, &args, "/a", "/a", "/a/newDir", fSys) + + cases := map[string]string{ + "absolute path": "/a/kustomization.yaml", + "directory": "b", + "non-existent file": "kubectl.yaml", + "file outside root": "../alpha/beta/gamma/delta/kustomization.yaml", + "inside dst": "newDir/kustomization.yaml", + } + for name, file := range cases { + file := file + t.Run(name, func(t *testing.T) { + req := require.New(t) + fSys := makeMemoryFs(t) + + ldr, _, err := lclzr.NewLocLoader("./a/../a", "/a/../a", "/a/newDir", fSys) + req.NoError(err) + + req.NoError(fSys.WriteFile("/a/newDir/kustomization.yaml", []byte("/a/newDir"))) + + _, err = ldr.Load(file) + req.Error(err) + }) + } +} diff --git a/api/internal/localizer/util.go b/api/internal/localizer/util.go new file mode 100644 index 0000000000..9c88b0912a --- /dev/null +++ b/api/internal/localizer/util.go @@ -0,0 +1,91 @@ +// Copyright 2022 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package localizer + +import ( + "log" + "path/filepath" + "strings" + + "sigs.k8s.io/kustomize/api/ifc" + "sigs.k8s.io/kustomize/api/internal/git" + "sigs.k8s.io/kustomize/kyaml/errors" + "sigs.k8s.io/kustomize/kyaml/filesys" +) + +// establishScope returns the scope given localize arguments and targetLdr at targetArg +func establishScope(scopeArg string, targetArg string, targetLdr ifc.Loader, fSys filesys.FileSystem) (filesys.ConfirmedDir, error) { + if _, isRemote := targetLdr.Repo(); isRemote { + if scopeArg != "" { + return "", errors.Errorf("scope '%s' specified for remote localize target '%s'", scopeArg, targetArg) + } + return "", nil + } + // default scope + if scopeArg == "" { + return filesys.ConfirmedDir(targetLdr.Root()), nil + } + scope, err := filesys.ConfirmDir(fSys, scopeArg) + if err != nil { + return "", errors.WrapPrefixf(err, "unable to establish localize scope") + } + if !filesys.ConfirmedDir(targetLdr.Root()).HasPrefix(scope) { + return scope, errors.Errorf("localize scope '%s' does not contain target '%s' at '%s'", + scopeArg, targetArg, targetLdr.Root()) + } + return scope, nil +} + +// createNewDir returns the localize destination directory or error. Note that spec is nil if targetLdr is at local +// target. +func createNewDir(newDirArg string, targetLdr ifc.Loader, spec *git.RepoSpec, fSys filesys.FileSystem) (filesys.ConfirmedDir, error) { + if newDirArg == "" { + newDirArg = defaultNewDir(targetLdr, spec) + } + if fSys.Exists(newDirArg) { + return "", errors.Errorf("localize destination '%s' already exists", newDirArg) + } + // destination directory must sit in an existing directory + if err := fSys.Mkdir(newDirArg); err != nil { + return "", errors.WrapPrefixf(err, "unable to create localize destination directory") + } + newDir, err := filesys.ConfirmDir(fSys, newDirArg) + if err != nil { + if errCleanup := fSys.RemoveAll(newDir.String()); errCleanup != nil { + log.Printf("%s", errors.WrapPrefixf(errCleanup, "unable to clean localize destination").Error()) + } + return "", errors.WrapPrefixf(err, "unable to establish localize destination") + } + + return newDir, nil +} + +// defaultNewDir calculates the default localize destination directory name from targetLdr at the localize target +// and spec of target, which is nil if target is local +func defaultNewDir(targetLdr ifc.Loader, spec *git.RepoSpec) string { + targetDir := filepath.Base(targetLdr.Root()) + if repo, isRemote := targetLdr.Repo(); isRemote { + // kustomize doesn't download repo into repo-named folder + // must find repo folder name from url + if repo == targetLdr.Root() { + targetDir = urlBase(spec.OrgRepo) + } + return strings.Join([]string{dstPrefix, targetDir, strings.ReplaceAll(spec.Ref, "/", "-")}, "-") + } + // special case for local target directory since destination directory cannot have "/" in name + if targetDir == string(filepath.Separator) { + return dstPrefix + } + return strings.Join([]string{dstPrefix, targetDir}, "-") +} + +// urlBase is the url equivalent of filepath.Base +func urlBase(url string) string { + cleaned := strings.TrimRight(url, "/") + i := strings.LastIndex(cleaned, "/") + if i < 0 { + return cleaned + } + return cleaned[i+1:] +} diff --git a/api/internal/localizer/util_test.go b/api/internal/localizer/util_test.go new file mode 100644 index 0000000000..ca8096e739 --- /dev/null +++ b/api/internal/localizer/util_test.go @@ -0,0 +1,18 @@ +// Copyright 2022 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package localizer //nolint:testpackage + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestUrlBase(t *testing.T) { + require.Equal(t, "repo", urlBase("https://github.com/org/repo")) +} + +func TestUrlBaseTrailingSlash(t *testing.T) { + require.Equal(t, "repo", urlBase("github.com/org/repo//")) +} diff --git a/api/internal/target/kusttarget.go b/api/internal/target/kusttarget.go index 4bbf7e98a6..283e6c6201 100644 --- a/api/internal/target/kusttarget.go +++ b/api/internal/target/kusttarget.go @@ -9,7 +9,6 @@ import ( "strings" "github.com/pkg/errors" - "sigs.k8s.io/kustomize/api/ifc" "sigs.k8s.io/kustomize/api/internal/accumulator" "sigs.k8s.io/kustomize/api/internal/builtins" diff --git a/api/krusty/kustomizer.go b/api/krusty/kustomizer.go index 5f1f27ff29..91b7e8abeb 100644 --- a/api/krusty/kustomizer.go +++ b/api/krusty/kustomizer.go @@ -46,8 +46,7 @@ func MakeKustomizer(o *Options) *Kustomizer { // a kustomization.yaml file, perform the kustomization it represents, // and return the resulting resources. // -// Any files referenced by the kustomization must be present on the -// filesystem. One may call Run any number of times, on any number +// One may call Run any number of times, on any number // of internal paths (e.g. the filesystem may contain multiple overlays, // and Run can be called on each of them). func (b *Kustomizer) Run( diff --git a/api/loader/fileloader.go b/api/loader/fileloader.go index 0cb7673bd1..df7def1e3b 100644 --- a/api/loader/fileloader.go +++ b/api/loader/fileloader.go @@ -18,6 +18,13 @@ import ( "sigs.k8s.io/kustomize/kyaml/filesys" ) +// HasRemoteFileScheme returns whether path has a url scheme that kustomize allows for +// remote files. See https://github.com/kubernetes-sigs/kustomize/blob/master/examples/remoteBuild.md +func HasRemoteFileScheme(path string) bool { + u, err := url.Parse(path) + return err == nil && (u.Scheme == "http" || u.Scheme == "https") +} + // fileLoader is a kustomization's interface to files. // // The directory in which a kustomization file sits @@ -114,6 +121,15 @@ func NewFileLoaderAtRoot(fSys filesys.FileSystem) *fileLoader { RestrictionRootOnly, fSys, filesys.Separator) } +// Repo returns the absolute path to the repo that contains Root and true +// if this fileLoader was created from a url; otherwise, the empty string and false +func (fl *fileLoader) Repo() (string, bool) { + if fl.repoSpec != nil { + return fl.repoSpec.Dir.String(), true + } + return "", false +} + // Root returns the absolute path that is prepended to any // relative paths used in Load. func (fl *fileLoader) Root() string { @@ -279,34 +295,37 @@ func (fl *fileLoader) errIfRepoCycle(newRepoSpec *git.RepoSpec) error { return fl.referrer.errIfRepoCycle(newRepoSpec) } +func loadURL(hc *http.Client, path string) ([]byte, error) { + resp, err := hc.Get(path) + if err != nil { + return nil, errors.WrapPrefixf(err, "cannot GET url") + } + defer resp.Body.Close() + if resp.StatusCode < 200 || resp.StatusCode > 299 { + if _, err = git.NewRepoSpecFromURL(path); err == nil { + return nil, errors.Errorf("URL is a git repository") + } + return nil, fmt.Errorf("%w: status code %d (%s)", ErrHTTP, resp.StatusCode, http.StatusText(resp.StatusCode)) + } + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, errors.WrapPrefixf(err, "cannot read url content") + } + return body, nil +} + // Load returns the content of file at the given path, // else an error. Relative paths are taken relative // to the root. func (fl *fileLoader) Load(path string) ([]byte, error) { - if u, err := url.Parse(path); err == nil && (u.Scheme == "http" || u.Scheme == "https") { + if HasRemoteFileScheme(path) { var hc *http.Client if fl.http != nil { hc = fl.http } else { hc = &http.Client{} } - resp, err := hc.Get(path) - if err != nil { - return nil, err - } - defer resp.Body.Close() - if resp.StatusCode < 200 || resp.StatusCode > 299 { - _, err := git.NewRepoSpecFromURL(path) - if err == nil { - return nil, errors.Errorf("URL is a git repository") - } - return nil, fmt.Errorf("%w: status code %d (%s)", ErrHTTP, resp.StatusCode, http.StatusText(resp.StatusCode)) - } - body, err := io.ReadAll(resp.Body) - if err != nil { - return nil, err - } - return body, nil + return loadURL(hc, path) } if !filepath.IsAbs(path) { path = fl.root.Join(path) diff --git a/api/loader/fileloader_test.go b/api/loader/fileloader_test.go index 9b8c33cc2a..8189cedc19 100644 --- a/api/loader/fileloader_test.go +++ b/api/loader/fileloader_test.go @@ -21,6 +21,40 @@ import ( "sigs.k8s.io/kustomize/kyaml/filesys" ) +func TestHasRemoteFileScheme(t *testing.T) { + cases := map[string]struct { + url string + valid bool + }{ + "https file": { + "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/examples/helloWorld/configMap.yaml", + true, + }, + "https dir": { + "https://github.com/kubernetes-sigs/kustomize//examples/helloWorld/", + true, + }, + "no scheme": { + "github.com/kubernetes-sigs/kustomize//examples/helloWorld/", + false, + }, + "ssh": { + "ssh://git@github.com/kubernetes-sigs/kustomize.git", + false, + }, + "local": { + "pod.yaml", + false, + }, + } + for name, test := range cases { + test := test + t.Run(name, func(t *testing.T) { + require.Equal(t, test.valid, HasRemoteFileScheme(test.url)) + }) + } +} + type testData struct { path string expectedContent string @@ -61,6 +95,8 @@ func TestLoaderLoad(t *testing.T) { require := require.New(t) l1 := makeLoader() + _, remote := l1.Repo() + require.False(remote) require.Equal("/", l1.Root()) for _, x := range testCases { @@ -73,6 +109,9 @@ func TestLoaderLoad(t *testing.T) { } l2, err := l1.New("foo/project") require.NoError(err) + + _, remote = l2.Repo() + require.False(remote) require.Equal("/foo/project", l2.Root()) for _, x := range testCases { @@ -322,6 +361,9 @@ whatever repoSpec, fSys, nil, git.DoNothingCloner(filesys.ConfirmedDir(coRoot))) require.NoError(err) + repo, remote := l.Repo() + require.True(remote) + require.Equal(coRoot, repo) require.Equal(coRoot+"/"+pathInRepo, l.Root()) _, err = l.New(url) @@ -335,6 +377,10 @@ whatever url = rootURL + "/" + pathInRepo l2, err := l.New(url) require.NoError(err) + + repo, remote = l2.Repo() + require.True(remote) + require.Equal(coRoot, repo) require.Equal(coRoot+"/"+pathInRepo, l2.Root()) } @@ -389,6 +435,8 @@ func TestLoaderDisallowsLocalBaseFromRemoteOverlay(t *testing.T) { // This is okay. l2, err = l1.New("../base") require.NoError(err) + _, remote := l2.Repo() + require.False(remote) require.Equal(cloneRoot+"/foo/base", l2.Root()) // This is not okay. @@ -414,6 +462,9 @@ func TestLocalLoaderReferencingGitBase(t *testing.T) { l2, err := l1.New("github.com/someOrg/someRepo/foo/base") require.NoError(err) + repo, remote := l2.Repo() + require.True(remote) + require.Equal(cloneRoot, repo) require.Equal(cloneRoot+"/foo/base", l2.Root()) } diff --git a/kustomize/commands/internal/util/util_test.go b/kustomize/commands/internal/util/util_test.go index ebb3742c73..2c1ba0c1e6 100644 --- a/kustomize/commands/internal/util/util_test.go +++ b/kustomize/commands/internal/util/util_test.go @@ -102,6 +102,9 @@ type fakeLoader struct { path string } +func (l fakeLoader) Repo() (string, bool) { + return "", false +} func (l fakeLoader) Root() string { return "" } diff --git a/kyaml/filesys/filesystem.go b/kyaml/filesys/filesystem.go index 79dfc53bf5..e88be90d06 100644 --- a/kyaml/filesys/filesystem.go +++ b/kyaml/filesys/filesystem.go @@ -23,10 +23,10 @@ type FileSystem interface { // Create a file. Create(path string) (File, error) - // MkDir makes a directory. + // Mkdir makes a directory. Mkdir(path string) error - // MkDirAll makes a directory path, creating intervening directories. + // MkdirAll makes a directory path, creating intervening directories. MkdirAll(path string) error // RemoveAll removes path and any children it contains. @@ -45,7 +45,7 @@ type FileSystem interface { // directory and a file name, where the directory // is represented as a ConfirmedDir and all that implies. // If the entire path is a directory, the file component - // is an empty string. + // is an empty string. Path can be relative. CleanedAbs(path string) (ConfirmedDir, string, error) // Exists is true if the path exists in the file system. diff --git a/kyaml/filesys/fsondisk_test.go b/kyaml/filesys/fsondisk_test.go index 54eff42dd6..10baf1d8f7 100644 --- a/kyaml/filesys/fsondisk_test.go +++ b/kyaml/filesys/fsondisk_test.go @@ -155,7 +155,6 @@ func TestConfirmDirDisk(t *testing.T) { func TestReadFilesRealFS(t *testing.T) { req := require.New(t) - fSys, testDir := makeTestDir(t) dir := filepath.Join(testDir, "dir") diff --git a/plugin/builtin/patchjson6902transformer/go.mod b/plugin/builtin/patchjson6902transformer/go.mod index f7dcd44fc9..95d79bceb6 100644 --- a/plugin/builtin/patchjson6902transformer/go.mod +++ b/plugin/builtin/patchjson6902transformer/go.mod @@ -28,6 +28,7 @@ require ( github.com/xlab/treeprint v1.1.0 // indirect go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect + golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect golang.org/x/text v0.3.7 // indirect google.golang.org/protobuf v1.28.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/plugin/builtin/patchjson6902transformer/go.sum b/plugin/builtin/patchjson6902transformer/go.sum index 594dd3b043..429fdec36a 100644 --- a/plugin/builtin/patchjson6902transformer/go.sum +++ b/plugin/builtin/patchjson6902transformer/go.sum @@ -449,6 +449,8 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -663,8 +665,9 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/kustomize/api v0.11.5 h1:vLDp++YAX7iy2y2CVPJNy9pk9CY8XaUKgHkjbVtnWag= sigs.k8s.io/kustomize/api v0.11.5/go.mod h1:2UDpxS6AonWXow2ZbySd4AjUxmdXLeTlvGBC46uSiq8= -sigs.k8s.io/kustomize/kyaml v0.13.7 h1:/EZ/nPaLUzeJKF/BuJ4QCuMVJWiEVoI8iftOHY3g3tk= sigs.k8s.io/kustomize/kyaml v0.13.7/go.mod h1:6K+IUOuir3Y7nucPRAjw9yth04KSWBnP5pqUTGwj/qU= +sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk= +sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/plugin/builtin/patchtransformer/go.mod b/plugin/builtin/patchtransformer/go.mod index 0a645c62aa..db7f074061 100644 --- a/plugin/builtin/patchtransformer/go.mod +++ b/plugin/builtin/patchtransformer/go.mod @@ -28,6 +28,7 @@ require ( github.com/xlab/treeprint v1.1.0 // indirect go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect + golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect golang.org/x/text v0.3.7 // indirect google.golang.org/protobuf v1.28.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/plugin/builtin/patchtransformer/go.sum b/plugin/builtin/patchtransformer/go.sum index 594dd3b043..429fdec36a 100644 --- a/plugin/builtin/patchtransformer/go.sum +++ b/plugin/builtin/patchtransformer/go.sum @@ -449,6 +449,8 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -663,8 +665,9 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/kustomize/api v0.11.5 h1:vLDp++YAX7iy2y2CVPJNy9pk9CY8XaUKgHkjbVtnWag= sigs.k8s.io/kustomize/api v0.11.5/go.mod h1:2UDpxS6AonWXow2ZbySd4AjUxmdXLeTlvGBC46uSiq8= -sigs.k8s.io/kustomize/kyaml v0.13.7 h1:/EZ/nPaLUzeJKF/BuJ4QCuMVJWiEVoI8iftOHY3g3tk= sigs.k8s.io/kustomize/kyaml v0.13.7/go.mod h1:6K+IUOuir3Y7nucPRAjw9yth04KSWBnP5pqUTGwj/qU= +sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk= +sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/plugin/builtin/prefixtransformer/go.mod b/plugin/builtin/prefixtransformer/go.mod index 25f9b48aa1..bbbf7730c4 100644 --- a/plugin/builtin/prefixtransformer/go.mod +++ b/plugin/builtin/prefixtransformer/go.mod @@ -27,6 +27,7 @@ require ( github.com/xlab/treeprint v1.1.0 // indirect go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect + golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect golang.org/x/text v0.3.7 // indirect google.golang.org/protobuf v1.28.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/plugin/builtin/prefixtransformer/go.sum b/plugin/builtin/prefixtransformer/go.sum index 594dd3b043..429fdec36a 100644 --- a/plugin/builtin/prefixtransformer/go.sum +++ b/plugin/builtin/prefixtransformer/go.sum @@ -449,6 +449,8 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -663,8 +665,9 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/kustomize/api v0.11.5 h1:vLDp++YAX7iy2y2CVPJNy9pk9CY8XaUKgHkjbVtnWag= sigs.k8s.io/kustomize/api v0.11.5/go.mod h1:2UDpxS6AonWXow2ZbySd4AjUxmdXLeTlvGBC46uSiq8= -sigs.k8s.io/kustomize/kyaml v0.13.7 h1:/EZ/nPaLUzeJKF/BuJ4QCuMVJWiEVoI8iftOHY3g3tk= sigs.k8s.io/kustomize/kyaml v0.13.7/go.mod h1:6K+IUOuir3Y7nucPRAjw9yth04KSWBnP5pqUTGwj/qU= +sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk= +sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/plugin/builtin/replicacounttransformer/go.mod b/plugin/builtin/replicacounttransformer/go.mod index d4fe3331d6..fdf6e772cb 100644 --- a/plugin/builtin/replicacounttransformer/go.mod +++ b/plugin/builtin/replicacounttransformer/go.mod @@ -28,6 +28,7 @@ require ( github.com/xlab/treeprint v1.1.0 // indirect go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect + golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect golang.org/x/text v0.3.7 // indirect google.golang.org/protobuf v1.28.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/plugin/builtin/replicacounttransformer/go.sum b/plugin/builtin/replicacounttransformer/go.sum index 594dd3b043..429fdec36a 100644 --- a/plugin/builtin/replicacounttransformer/go.sum +++ b/plugin/builtin/replicacounttransformer/go.sum @@ -449,6 +449,8 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -663,8 +665,9 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/kustomize/api v0.11.5 h1:vLDp++YAX7iy2y2CVPJNy9pk9CY8XaUKgHkjbVtnWag= sigs.k8s.io/kustomize/api v0.11.5/go.mod h1:2UDpxS6AonWXow2ZbySd4AjUxmdXLeTlvGBC46uSiq8= -sigs.k8s.io/kustomize/kyaml v0.13.7 h1:/EZ/nPaLUzeJKF/BuJ4QCuMVJWiEVoI8iftOHY3g3tk= sigs.k8s.io/kustomize/kyaml v0.13.7/go.mod h1:6K+IUOuir3Y7nucPRAjw9yth04KSWBnP5pqUTGwj/qU= +sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk= +sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/plugin/builtin/suffixtransformer/go.mod b/plugin/builtin/suffixtransformer/go.mod index 8a8ba622c2..1d9890321f 100644 --- a/plugin/builtin/suffixtransformer/go.mod +++ b/plugin/builtin/suffixtransformer/go.mod @@ -27,6 +27,7 @@ require ( github.com/xlab/treeprint v1.1.0 // indirect go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect + golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect golang.org/x/text v0.3.7 // indirect google.golang.org/protobuf v1.28.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/plugin/builtin/suffixtransformer/go.sum b/plugin/builtin/suffixtransformer/go.sum index 594dd3b043..429fdec36a 100644 --- a/plugin/builtin/suffixtransformer/go.sum +++ b/plugin/builtin/suffixtransformer/go.sum @@ -449,6 +449,8 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -663,8 +665,9 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/kustomize/api v0.11.5 h1:vLDp++YAX7iy2y2CVPJNy9pk9CY8XaUKgHkjbVtnWag= sigs.k8s.io/kustomize/api v0.11.5/go.mod h1:2UDpxS6AonWXow2ZbySd4AjUxmdXLeTlvGBC46uSiq8= -sigs.k8s.io/kustomize/kyaml v0.13.7 h1:/EZ/nPaLUzeJKF/BuJ4QCuMVJWiEVoI8iftOHY3g3tk= sigs.k8s.io/kustomize/kyaml v0.13.7/go.mod h1:6K+IUOuir3Y7nucPRAjw9yth04KSWBnP5pqUTGwj/qU= +sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk= +sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=