From 8fd18099d6c9743055ed14181606599de7caf3be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Oct 2022 22:27:43 -0400 Subject: [PATCH] Bump sigs.k8s.io/kind from 0.16.0 to 0.17.0 (#875) Bumps [sigs.k8s.io/kind](https://github.com/kubernetes-sigs/kind) from 0.16.0 to 0.17.0. - [Release notes](https://github.com/kubernetes-sigs/kind/releases) - [Commits](https://github.com/kubernetes-sigs/kind/compare/v0.16.0...v0.17.0) --- updated-dependencies: - dependency-name: sigs.k8s.io/kind dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 3 +- go.sum | 7 +- vendor/github.com/google/safetext/LICENSE | 202 ++++++ .../google/safetext/common/common.go | 260 +++++++ .../safetext/yamltemplate/yamltemplate.go | 657 ++++++++++++++++++ vendor/modules.txt | 6 +- .../kind/pkg/apis/config/defaults/image.go | 2 +- .../internal/create/actions/installcni/cni.go | 5 +- .../pkg/cluster/internal/kubeadm/config.go | 42 +- .../kind/pkg/cluster/nodeutils/util.go | 2 +- .../kind/pkg/cmd/kind/version/version.go | 2 +- 11 files changed, 1163 insertions(+), 25 deletions(-) create mode 100644 vendor/github.com/google/safetext/LICENSE create mode 100644 vendor/github.com/google/safetext/common/common.go create mode 100644 vendor/github.com/google/safetext/yamltemplate/yamltemplate.go diff --git a/go.mod b/go.mod index be621c0451..5ae845e596 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( golang.org/x/tools v0.2.0 gopkg.in/yaml.v3 v3.0.1 k8s.io/apimachinery v0.25.3 - sigs.k8s.io/kind v0.16.0 + sigs.k8s.io/kind v0.17.0 ) require ( @@ -75,6 +75,7 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.4.2 // indirect github.com/golang/protobuf v1.5.2 // indirect + github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect diff --git a/go.sum b/go.sum index e6bc47ef4b..2cc61598f6 100644 --- a/go.sum +++ b/go.sum @@ -490,6 +490,8 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+IrK7d0gGgpjGGvd2kz+FzTHVzdqI= +github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg= github.com/google/trillian v1.3.11/go.mod h1:0tPraVHrSDkA3BO6vKX67zgLXs6SsOAbHEivX+9mPgw= github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -1600,6 +1602,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= @@ -1657,8 +1660,8 @@ mvdan.cc/unparam v0.0.0-20210104141923-aac4ce9116a7/go.mod h1:hBpJkZE8H/sb+VRFvw rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 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/kind v0.16.0 h1:GFXyyxtPnHFKqXr3ZG8/X0+0K9sl69lejStlPn2WQyM= -sigs.k8s.io/kind v0.16.0/go.mod h1:cKTqagdRyUQmihhBOd+7p43DpOPRn9rHsUC08K1Jbsk= +sigs.k8s.io/kind v0.17.0 h1:CScmGz/wX66puA06Gj8OZb76Wmk7JIjgWf5JDvY7msM= +sigs.k8s.io/kind v0.17.0/go.mod h1:Qqp8AiwOlMZmJWs37Hgs31xcbiYXjtXlRBSftcnZXQk= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/vendor/github.com/google/safetext/LICENSE b/vendor/github.com/google/safetext/LICENSE new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/vendor/github.com/google/safetext/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/google/safetext/common/common.go b/vendor/github.com/google/safetext/common/common.go new file mode 100644 index 0000000000..80a8bbd97a --- /dev/null +++ b/vendor/github.com/google/safetext/common/common.go @@ -0,0 +1,260 @@ +/* + * + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package common implements common functionality for dealing with text/template. +package common + +import ( + "bytes" + "reflect" + "strings" + "sync" + "text/template" + "text/template/parse" + "unicode" + "unicode/utf8" +) + +// ContainsStringsWithSpecialCharacters determines whether an object contains interface{} strings that contain special characters. +func ContainsStringsWithSpecialCharacters(data interface{}, special string) bool { + if data == nil { + return false + } + + switch reflect.TypeOf(data).Kind() { + case reflect.Ptr: + p := reflect.ValueOf(data) + return !p.IsNil() && ContainsStringsWithSpecialCharacters(p.Elem().Interface(), special) + case reflect.String: + return strings.ContainsAny(reflect.ValueOf(data).String(), special) + case reflect.Slice, reflect.Array: + for i := 0; i < reflect.ValueOf(data).Len(); i++ { + if ContainsStringsWithSpecialCharacters(reflect.ValueOf(data).Index(i).Interface(), special) { + return true + } + } + case reflect.Map: + dataIter := reflect.ValueOf(data).MapRange() + for dataIter.Next() { + if ContainsStringsWithSpecialCharacters(dataIter.Value().Interface(), special) { + return true + } + } + case reflect.Struct: + t := reflect.TypeOf(data) + v := reflect.ValueOf(data) + n := v.NumField() + for i := 0; i < n; i++ { + r, _ := utf8.DecodeRuneInString(t.Field(i).Name) + if unicode.IsUpper(r) && ContainsStringsWithSpecialCharacters(v.Field(i).Interface(), special) { + return true + } + } + } + + return false +} + +// FuncMap to register new template objects with. +var FuncMap = map[string]interface{}{ + "textTemplateRemediationFunc": textTemplateRemediationFunc, + "StructuralData": echo, +} + +func echo(in interface{}) interface{} { + return in +} + +// BaselineString is a string callback function that just returns a constant string, +// used to get a baseline of how the resultant YAML is structured. +func BaselineString(string) string { + return "baseline" +} + +// stringCallback provides the callback for how strings should be manipulated before +// being pasted into the template execution result. +var stringCallback func(string) string +var stringCallbackLock sync.Mutex + +func textTemplateRemediationFunc(data interface{}) interface{} { + return deepCopyMutateStrings(data, stringCallback) +} + +// ExecuteWithCallback performs an execution on a callback-applied template +// (WalkApplyFuncToNonDeclaractiveActions) with a specified callback. +func ExecuteWithCallback(tmpl *template.Template, cb func(string) string, result *bytes.Buffer, data interface{}) error { + stringCallbackLock.Lock() + defer stringCallbackLock.Unlock() + stringCallback = cb + + return tmpl.Execute(result, data) +} + +func makePointer(data interface{}) interface{} { + rtype := reflect.New(reflect.TypeOf(data)) + rtype.Elem().Set(reflect.ValueOf(data)) + return rtype.Interface() +} + +func dereference(data interface{}) interface{} { + return reflect.ValueOf(data).Elem().Interface() +} + +func deepCopyMutateStrings(data interface{}, mutateF func(string) string) interface{} { + var r interface{} + + if data == nil { + return nil + } + + switch reflect.TypeOf(data).Kind() { + case reflect.Ptr: + p := reflect.ValueOf(data) + if p.IsNil() { + r = data + } else { + c := deepCopyMutateStrings(dereference(data), mutateF) + r = makePointer(c) + + // Sometimes we accidentally introduce one too minterface{} layers of indirection (seems related to protobuf generated fields like ReleaseNamespace *ReleaseNamespace `... reflect:"unexport"`) + if reflect.TypeOf(r) != reflect.TypeOf(data) { + r = c + } + } + case reflect.String: + return mutateF(reflect.ValueOf(data).String()) + case reflect.Slice, reflect.Array: + rc := reflect.MakeSlice(reflect.TypeOf(data), reflect.ValueOf(data).Len(), reflect.ValueOf(data).Len()) + for i := 0; i < reflect.ValueOf(data).Len(); i++ { + rc.Index(i).Set(reflect.ValueOf(deepCopyMutateStrings(reflect.ValueOf(data).Index(i).Interface(), mutateF))) + } + r = rc.Interface() + case reflect.Map: + rc := reflect.MakeMap(reflect.TypeOf(data)) + dataIter := reflect.ValueOf(data).MapRange() + for dataIter.Next() { + rc.SetMapIndex(dataIter.Key(), reflect.ValueOf(deepCopyMutateStrings(dataIter.Value().Interface(), mutateF))) + } + r = rc.Interface() + case reflect.Struct: + s := reflect.New(reflect.TypeOf(data)) + + t := reflect.TypeOf(data) + v := reflect.ValueOf(data) + n := v.NumField() + for i := 0; i < n; i++ { + r, _ := utf8.DecodeRuneInString(t.Field(i).Name) + + // Don't copy unexported fields + if unicode.IsUpper(r) { + reflect.Indirect(s).Field(i).Set( + reflect.ValueOf(deepCopyMutateStrings(v.Field(i).Interface(), mutateF)), + ) + } + } + + r = s.Interface() + default: + // No other types need special handling (int, bool, etc) + r = data + } + + return r +} + +func applyPipeCmds(cmds []*parse.CommandNode) { + applyFunc := "textTemplateRemediationFunc" + + for _, c := range cmds { + newArgs := make([]parse.Node, 0) + for i, a := range c.Args { + switch a := a.(type) { + case *parse.DotNode, *parse.FieldNode, *parse.VariableNode: + if i == 0 && len(c.Args) > 1 { + // If this is the first "argument" of multiple, then it is really a function + newArgs = append(newArgs, a) + } else { + // If this node is an argument to a call to "StructuralData", then pass it through as-is + switch identifier := c.Args[0].(type) { + case *parse.IdentifierNode: + if identifier.Ident == "StructuralData" { + newArgs = append(newArgs, a) + continue + } + } + + newPipe := &parse.PipeNode{NodeType: parse.NodePipe, Decl: nil} + newPipe.Cmds = []*parse.CommandNode{ + &parse.CommandNode{NodeType: parse.NodeCommand, Args: []parse.Node{a}}, + &parse.CommandNode{NodeType: parse.NodeCommand, Args: []parse.Node{&parse.IdentifierNode{NodeType: parse.NodeIdentifier, Ident: applyFunc}}}, + } + newArgs = append(newArgs, newPipe) + } + case *parse.PipeNode: + applyPipeCmds(a.Cmds) + newArgs = append(newArgs, a) + default: + newArgs = append(newArgs, a) + } + } + + c.Args = newArgs + } +} + +func branchNode(node parse.Node) *parse.BranchNode { + switch node := node.(type) { + case *parse.IfNode: + return &node.BranchNode + case *parse.RangeNode: + return &node.BranchNode + case *parse.WithNode: + return &node.BranchNode + } + + return nil +} + +// WalkApplyFuncToNonDeclaractiveActions walks the AST, applying a pipeline function to interface{} "paste" nodes (non-declarative action nodes) +func WalkApplyFuncToNonDeclaractiveActions(template *template.Template, node parse.Node) { + switch node := node.(type) { + case *parse.ActionNode: + // Non-declarative actions are paste actions + if len(node.Pipe.Decl) == 0 { + applyPipeCmds(node.Pipe.Cmds) + } + + case *parse.IfNode, *parse.RangeNode, *parse.WithNode: + nodeBranch := branchNode(node) + WalkApplyFuncToNonDeclaractiveActions(template, nodeBranch.List) + if nodeBranch.ElseList != nil { + WalkApplyFuncToNonDeclaractiveActions(template, nodeBranch.ElseList) + } + case *parse.ListNode: + for _, node := range node.Nodes { + WalkApplyFuncToNonDeclaractiveActions(template, node) + } + case *parse.TemplateNode: + tmpl := template.Lookup(node.Name) + if tmpl != nil { + treeCopy := tmpl.Tree.Copy() + WalkApplyFuncToNonDeclaractiveActions(tmpl, treeCopy.Root) + template.AddParseTree(node.Name, treeCopy) + } + } +} diff --git a/vendor/github.com/google/safetext/yamltemplate/yamltemplate.go b/vendor/github.com/google/safetext/yamltemplate/yamltemplate.go new file mode 100644 index 0000000000..47d8f28389 --- /dev/null +++ b/vendor/github.com/google/safetext/yamltemplate/yamltemplate.go @@ -0,0 +1,657 @@ +/* + * + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package yamltemplate is a drop-in-replacement for using text/template to produce YAML, that adds automatic detection for YAML injection +package yamltemplate + +import ( + "bytes" + "errors" + "fmt" + "io" + "io/fs" + "os" + "path" + "path/filepath" + "reflect" + "text/template" + "text/template/parse" + "unicode" + "unicode/utf8" + + "gopkg.in/yaml.v3" + + "github.com/google/safetext/common" +) + +// ErrInvalidYAMLTemplate indicates the requested template is not valid YAML. +var ErrInvalidYAMLTemplate error = errors.New("Invalid YAML Template") + +// ErrYAMLInjection indicates the inputs resulted in YAML injection. +var ErrYAMLInjection error = errors.New("YAML Injection Detected") + +// ExecError is the custom error type returned when Execute has an +// error evaluating its template. (If a write error occurs, the actual +// error is returned; it will not be of type ExecError.) +type ExecError = template.ExecError + +// FuncMap is the type of the map defining the mapping from names to functions. +// Each function must have either a single return value, or two return values of +// which the second has type error. In that case, if the second (error) +// return value evaluates to non-nil during execution, execution terminates and +// Execute returns that error. +// +// Errors returned by Execute wrap the underlying error; call errors.As to +// uncover them. +// +// When template execution invokes a function with an argument list, that list +// must be assignable to the function's parameter types. Functions meant to +// apply to arguments of arbitrary type can use parameters of type interface{} or +// of type reflect.Value. Similarly, functions meant to return a result of arbitrary +// type can return interface{} or reflect.Value. +type FuncMap = template.FuncMap + +// Template is the representation of a parsed template. The *parse.Tree +// field is exported only for use by html/template and should be treated +// as unexported by all other clients. +type Template struct { + unsafeTemplate *template.Template +} + +// New allocates a new, undefined template with the given name. +func New(name string) *Template { + return &Template{unsafeTemplate: template.New(name).Funcs(common.FuncMap)} +} + +const yamlSpecialCharacters = "{}[]&*#?|-.<>=!%@:\"'`,\r\n" + +func mapOrArray(in interface{}) bool { + return in != nil && (reflect.TypeOf(in).Kind() == reflect.Map || reflect.TypeOf(in).Kind() == reflect.Slice || reflect.TypeOf(in).Kind() == reflect.Array) +} + +func allKeysMatch(base interface{}, a interface{}, b interface{}) bool { + if base == nil { + return a == nil && b == nil + } + + switch reflect.TypeOf(base).Kind() { + case reflect.Ptr: + if reflect.TypeOf(a).Kind() != reflect.Ptr || reflect.TypeOf(b).Kind() != reflect.Ptr { + return false + } + + if !allKeysMatch(reflect.ValueOf(base).Elem().Interface(), reflect.ValueOf(a).Elem().Interface(), reflect.ValueOf(b).Elem().Interface()) { + return true + } + case reflect.Map: + if reflect.TypeOf(a).Kind() != reflect.Map || reflect.TypeOf(b).Kind() != reflect.Map { + return false + } + + if reflect.ValueOf(a).Len() != reflect.ValueOf(base).Len() || reflect.ValueOf(b).Len() != reflect.ValueOf(base).Len() { + return false + } + + basei := reflect.ValueOf(base).MapRange() + for basei.Next() { + av := reflect.ValueOf(a).MapIndex(basei.Key()) + bv := reflect.ValueOf(b).MapIndex(basei.Key()) + if !av.IsValid() || !bv.IsValid() || + !allKeysMatch(basei.Value().Interface(), av.Interface(), bv.Interface()) { + return false + } + } + case reflect.Slice, reflect.Array: + if reflect.TypeOf(a).Kind() != reflect.Slice && reflect.TypeOf(a).Kind() != reflect.Array && + reflect.TypeOf(b).Kind() != reflect.Slice && reflect.TypeOf(b).Kind() != reflect.Array { + return false + } + + if reflect.ValueOf(a).Len() != reflect.ValueOf(base).Len() || reflect.ValueOf(b).Len() != reflect.ValueOf(base).Len() { + return false + } + + for i := 0; i < reflect.ValueOf(base).Len(); i++ { + if !allKeysMatch(reflect.ValueOf(base).Index(i).Interface(), reflect.ValueOf(a).Index(i).Interface(), reflect.ValueOf(b).Index(i).Interface()) { + return false + } + } + case reflect.Struct: + n := reflect.ValueOf(base).NumField() + for i := 0; i < n; i++ { + baseit := reflect.TypeOf(base).Field(i) + ait := reflect.TypeOf(a).Field(i) + bit := reflect.TypeOf(b).Field(i) + + if baseit.Name != ait.Name || baseit.Name != bit.Name { + return false + } + + // Only compare public members (private members cannot be overwritten by text/template) + decodedName, _ := utf8.DecodeRuneInString(baseit.Name) + if unicode.IsUpper(decodedName) { + basei := reflect.ValueOf(base).Field(i) + ai := reflect.ValueOf(a).Field(i) + bi := reflect.ValueOf(b).Field(i) + + if !allKeysMatch(basei.Interface(), ai.Interface(), bi.Interface()) { + return false + } + } + } + case reflect.String: + // Baseline type of string was chosen arbitrarily, so just check that there isn't a new a map or slice/array injected, which would change the structure of the YAML + if mapOrArray(a) || mapOrArray(b) { + return false + } + default: + if reflect.TypeOf(a) != reflect.TypeOf(base) || reflect.TypeOf(b) != reflect.TypeOf(base) { + return false + } + } + + return true +} + +func unmarshalYaml(data []byte) ([]interface{}, error) { + r := make([]interface{}, 0) + + decoder := yaml.NewDecoder(bytes.NewReader(data)) + for { + var t interface{} + err := decoder.Decode(&t) + + if err == io.EOF { + break + } else if err == nil { + r = append(r, t) + } else { + return nil, err + } + } + + return r, nil +} + +// Mutation algorithm +func mutateString(s string) string { + // Longest possible output string is 2x the original + out := make([]rune, len(s)*2) + + i := 0 + for _, r := range s { + out[i] = r + i++ + + // Don't repeat quoting-related characters so as to not allow YAML context change in the mutation result + if r != '\\' && r != '\'' && r != '"' { + out[i] = r + i++ + } + } + + return string(out[:i]) +} + +// Execute applies a parsed template to the specified data object, +// and writes the output to wr. +// If an error occurs executing the template or writing its output, +// execution stops, but partial results may already have been written to +// the output writer. +// A template may be executed safely in parallel, although if parallel +// executions share a Writer the output may be interleaved. +// +// If data is a reflect.Value, the template applies to the concrete +// value that the reflect.Value holds, as in fmt.Print. +func (t *Template) Execute(wr io.Writer, data interface{}) (err error) { + if data == nil { + return t.unsafeTemplate.Execute(wr, data) + } + + // An attacker may be able to cause type confusion or nil dereference panic during allKeysMatch + defer func() { + if r := recover(); r != nil { + err = ErrYAMLInjection + } + }() + + // Calculate requested result first + var requestedResult bytes.Buffer + + if err := t.unsafeTemplate.Execute(&requestedResult, data); err != nil { + return err + } + + // Fast path for if there are no YAML special characters in the input strings + if !common.ContainsStringsWithSpecialCharacters(data, yamlSpecialCharacters) { + // Note: We assume the result was valid YAML, and don't check for ErrInvalidYAMLTemplate + requestedResult.WriteTo(wr) + return nil + } + + walked, err := t.unsafeTemplate.Clone() + if err != nil { + return err + } + walked.Tree = walked.Tree.Copy() + + common.WalkApplyFuncToNonDeclaractiveActions(walked, walked.Tree.Root) + + // Get baseline + var baselineResult bytes.Buffer + if err = common.ExecuteWithCallback(walked, common.BaselineString, &baselineResult, data); err != nil { + return err + } + + parsedBaselineResult, err := unmarshalYaml(baselineResult.Bytes()) + if err != nil { + return ErrInvalidYAMLTemplate + } + + // If baseline was valid, request must also be valid YAML for no injection to have occurred + parsedRequestedResult, err := unmarshalYaml(requestedResult.Bytes()) + if err != nil { + return ErrYAMLInjection + } + + // Mutate the input + var mutatedResult bytes.Buffer + if err = common.ExecuteWithCallback(walked, mutateString, &mutatedResult, data); err != nil { + return err + } + + parsedMutatedResult, err := unmarshalYaml(mutatedResult.Bytes()) + if err != nil { + return ErrYAMLInjection + } + + // Compare results + if !allKeysMatch(parsedBaselineResult, parsedRequestedResult, parsedMutatedResult) { + return ErrYAMLInjection + } + + requestedResult.WriteTo(wr) + return nil +} + +// Name returns the name of the template. +func (t *Template) Name() string { + return t.unsafeTemplate.Name() +} + +// New allocates a new, undefined template associated with the given one and with the same +// delimiters. The association, which is transitive, allows one template to +// invoke another with a {{template}} action. +// +// Because associated templates share underlying data, template construction +// cannot be done safely in parallel. Once the templates are constructed, they +// can be executed in parallel. +func (t *Template) New(name string) *Template { + return &Template{unsafeTemplate: t.unsafeTemplate.New(name).Funcs(common.FuncMap)} +} + +// Clone returns a duplicate of the template, including all associated +// templates. The actual representation is not copied, but the name space of +// associated templates is, so further calls to Parse in the copy will add +// templates to the copy but not to the original. Clone can be used to prepare +// common templates and use them with variant definitions for other templates +// by adding the variants after the clone is made. +func (t *Template) Clone() (*Template, error) { + nt, err := t.unsafeTemplate.Clone() + return &Template{unsafeTemplate: nt}, err +} + +// AddParseTree associates the argument parse tree with the template t, giving +// it the specified name. If the template has not been defined, this tree becomes +// its definition. If it has been defined and already has that name, the existing +// definition is replaced; otherwise a new template is created, defined, and returned. +func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) { + nt, err := t.unsafeTemplate.AddParseTree(name, tree) + + if nt != t.unsafeTemplate { + return &Template{unsafeTemplate: nt}, err + } + return t, err +} + +// Option sets options for the template. Options are described by +// strings, either a simple string or "key=value". There can be at +// most one equals sign in an option string. If the option string +// is unrecognized or otherwise invalid, Option panics. +// +// Known options: +// +// missingkey: Control the behavior during execution if a map is +// indexed with a key that is not present in the map. +// +// "missingkey=default" or "missingkey=invalid" +// The default behavior: Do nothing and continue execution. +// If printed, the result of the index operation is the string +// "". +// "missingkey=zero" +// The operation returns the zero value for the map type's element. +// "missingkey=error" +// Execution stops immediately with an error. +func (t *Template) Option(opt ...string) *Template { + for _, s := range opt { + t.unsafeTemplate.Option(s) + } + return t +} + +// Templates returns a slice of defined templates associated with t. +func (t *Template) Templates() []*Template { + s := t.unsafeTemplate.Templates() + + var ns []*Template + for _, nt := range s { + ns = append(ns, &Template{unsafeTemplate: nt}) + } + + return ns +} + +// ExecuteTemplate applies the template associated with t that has the given name +// to the specified data object and writes the output to wr. +// If an error occurs executing the template or writing its output, +// execution stops, but partial results may already have been written to +// the output writer. +// A template may be executed safely in parallel, although if parallel +// executions share a Writer the output may be interleaved. +func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error { + tmpl := t.Lookup(name) + if tmpl == nil { + return fmt.Errorf("template: no template %q associated with template %q", name, t.Name()) + } + return tmpl.Execute(wr, data) +} + +// Delims sets the action delimiters to the specified strings, to be used in +// subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template +// definitions will inherit the settings. An empty delimiter stands for the +// corresponding default: {{ or }}. +// The return value is the template, so calls can be chained. +func (t *Template) Delims(left, right string) *Template { + t.unsafeTemplate.Delims(left, right) + return t +} + +// DefinedTemplates returns a string listing the defined templates, +// prefixed by the string "; defined templates are: ". If there are none, +// it returns the empty string. For generating an error message here +// and in html/template. +func (t *Template) DefinedTemplates() string { + return t.unsafeTemplate.DefinedTemplates() +} + +// Funcs adds the elements of the argument map to the template's function map. +// It must be called before the template is parsed. +// It panics if a value in the map is not a function with appropriate return +// type or if the name cannot be used syntactically as a function in a template. +// It is legal to overwrite elements of the map. The return value is the template, +// so calls can be chained. +func (t *Template) Funcs(funcMap FuncMap) *Template { + t.unsafeTemplate.Funcs(funcMap) + return t +} + +// Lookup returns the template with the given name that is associated with t. +// It returns nil if there is no such template or the template has no definition. +func (t *Template) Lookup(name string) *Template { + nt := t.unsafeTemplate.Lookup(name) + + if nt == nil { + return nil + } + + if nt != t.unsafeTemplate { + return &Template{unsafeTemplate: nt} + } + + return t +} + +// Parse parses text as a template body for t. +// Named template definitions ({{define ...}} or {{block ...}} statements) in text +// define additional templates associated with t and are removed from the +// definition of t itself. +// +// Templates can be redefined in successive calls to Parse. +// A template definition with a body containing only white space and comments +// is considered empty and will not replace an existing template's body. +// This allows using Parse to add new named template definitions without +// overwriting the main template body. +func (t *Template) Parse(text string) (*Template, error) { + nt, err := t.unsafeTemplate.Parse(text) + + if nt != t.unsafeTemplate { + return &Template{unsafeTemplate: nt}, err + } + + return t, err +} + +// Must is a helper that wraps a call to a function returning (*Template, error) +// and panics if the error is non-nil. It is intended for use in variable +// initializations such as +// +// var t = template.Must(template.New("name").Parse("text")) +func Must(t *Template, err error) *Template { + if err != nil { + panic(err) + } + return t +} + +func readFileOS(file string) (name string, b []byte, err error) { + name = filepath.Base(file) + b, err = os.ReadFile(file) + return +} + +func readFileFS(fsys fs.FS) func(string) (string, []byte, error) { + return func(file string) (name string, b []byte, err error) { + name = path.Base(file) + b, err = fs.ReadFile(fsys, file) + return + } +} + +func parseFiles(t *Template, readFile func(string) (string, []byte, error), filenames ...string) (*Template, error) { + if len(filenames) == 0 { + // Not really a problem, but be consistent. + return nil, fmt.Errorf("template: no files named in call to ParseFiles") + } + for _, filename := range filenames { + name, b, err := readFile(filename) + if err != nil { + return nil, err + } + s := string(b) + // First template becomes return value if not already defined, + // and we use that one for subsequent New calls to associate + // all the templates together. Also, if this file has the same name + // as t, this file becomes the contents of t, so + // t, err := New(name).Funcs(xxx).ParseFiles(name) + // works. Otherwise we create a new template associated with t. + var tmpl *Template + if t == nil { + t = New(name) + } + if name == t.Name() { + tmpl = t + } else { + tmpl = t.New(name) + } + _, err = tmpl.Parse(s) + if err != nil { + return nil, err + } + } + return t, nil +} + +// parseGlob is the implementation of the function and method ParseGlob. +func parseGlob(t *Template, pattern string) (*Template, error) { + filenames, err := filepath.Glob(pattern) + if err != nil { + return nil, err + } + if len(filenames) == 0 { + return nil, fmt.Errorf("template: pattern matches no files: %#q", pattern) + } + return parseFiles(t, readFileOS, filenames...) +} + +func parseFS(t *Template, fsys fs.FS, patterns []string) (*Template, error) { + var filenames []string + for _, pattern := range patterns { + list, err := fs.Glob(fsys, pattern) + if err != nil { + return nil, err + } + if len(list) == 0 { + return nil, fmt.Errorf("template: pattern matches no files: %#q", pattern) + } + filenames = append(filenames, list...) + } + return parseFiles(t, readFileFS(fsys), filenames...) +} + +// ParseFiles creates a new Template and parses the template definitions from +// the named files. The returned template's name will have the base name and +// parsed contents of the first file. There must be at least one file. +// If an error occurs, parsing stops and the returned *Template is nil. +// +// When parsing multiple files with the same name in different directories, +// the last one mentioned will be the one that results. +// For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template +// named "foo", while "a/foo" is unavailable. +func ParseFiles(filenames ...string) (*Template, error) { + return parseFiles(nil, readFileOS, filenames...) +} + +// ParseFiles parses the named files and associates the resulting templates with +// t. If an error occurs, parsing stops and the returned template is nil; +// otherwise it is t. There must be at least one file. +// Since the templates created by ParseFiles are named by the base +// names of the argument files, t should usually have the name of one +// of the (base) names of the files. If it does not, depending on t's +// contents before calling ParseFiles, t.Execute may fail. In that +// case use t.ExecuteTemplate to execute a valid template. +// +// When parsing multiple files with the same name in different directories, +// the last one mentioned will be the one that results. +func (t *Template) ParseFiles(filenames ...string) (*Template, error) { + // Ensure template is inited + t.Option() + + return parseFiles(t, readFileOS, filenames...) +} + +// ParseGlob creates a new Template and parses the template definitions from +// the files identified by the pattern. The files are matched according to the +// semantics of filepath.Match, and the pattern must match at least one file. +// The returned template will have the (base) name and (parsed) contents of the +// first file matched by the pattern. ParseGlob is equivalent to calling +// ParseFiles with the list of files matched by the pattern. +// +// When parsing multiple files with the same name in different directories, +// the last one mentioned will be the one that results. +func ParseGlob(pattern string) (*Template, error) { + return parseGlob(nil, pattern) +} + +// ParseGlob parses the template definitions in the files identified by the +// pattern and associates the resulting templates with t. The files are matched +// according to the semantics of filepath.Match, and the pattern must match at +// least one file. ParseGlob is equivalent to calling t.ParseFiles with the +// list of files matched by the pattern. +// +// When parsing multiple files with the same name in different directories, +// the last one mentioned will be the one that results. +func (t *Template) ParseGlob(pattern string) (*Template, error) { + // Ensure template is inited + t.Option() + + return parseGlob(t, pattern) +} + +// ParseFS is like ParseFiles or ParseGlob but reads from the file system fsys +// instead of the host operating system's file system. +// It accepts a list of glob patterns. +// (Note that most file names serve as glob patterns matching only themselves.) +func ParseFS(fsys fs.FS, patterns ...string) (*Template, error) { + return parseFS(nil, fsys, patterns) +} + +// ParseFS is like ParseFiles or ParseGlob but reads from the file system fsys +// instead of the host operating system's file system. +// It accepts a list of glob patterns. +// (Note that most file names serve as glob patterns matching only themselves.) +func (t *Template) ParseFS(fsys fs.FS, patterns ...string) (*Template, error) { + // Ensure template is inited + t.Option() + + return parseFS(t, fsys, patterns) +} + +// HTMLEscape writes to w the escaped HTML equivalent of the plain text data b. +func HTMLEscape(w io.Writer, b []byte) { + template.HTMLEscape(w, b) +} + +// HTMLEscapeString returns the escaped HTML equivalent of the plain text data s. +func HTMLEscapeString(s string) string { + return template.HTMLEscapeString(s) +} + +// HTMLEscaper returns the escaped HTML equivalent of the textual +// representation of its arguments. +func HTMLEscaper(args ...interface{}) string { + return template.HTMLEscaper(args) +} + +// IsTrue reports whether the value is 'true', in the sense of not the zero of its type, +// and whether the value has a meaningful truth value. This is the definition of +// truth used by if and other such actions. +func IsTrue(val interface{}) (truth, ok bool) { + return template.IsTrue(val) +} + +// JSEscape writes to w the escaped JavaScript equivalent of the plain text data b. +func JSEscape(w io.Writer, b []byte) { + template.JSEscape(w, b) +} + +// JSEscapeString returns the escaped JavaScript equivalent of the plain text data s. +func JSEscapeString(s string) string { + return template.JSEscapeString(s) +} + +// JSEscaper returns the escaped JavaScript equivalent of the textual +// representation of its arguments. +func JSEscaper(args ...interface{}) string { + return template.JSEscaper(args) +} + +// URLQueryEscaper returns the escaped value of the textual representation of +// its arguments in a form suitable for embedding in a URL query. +func URLQueryEscaper(args ...interface{}) string { + return template.URLQueryEscaper(args) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 47516a6fa2..76dd5fbb7a 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -316,6 +316,10 @@ github.com/google/go-containerregistry/pkg/v1/stream github.com/google/go-containerregistry/pkg/v1/tarball github.com/google/go-containerregistry/pkg/v1/types github.com/google/go-containerregistry/pkg/v1/validate +# github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 +## explicit; go 1.19 +github.com/google/safetext/common +github.com/google/safetext/yamltemplate # github.com/hashicorp/hcl v1.0.0 ## explicit github.com/hashicorp/hcl @@ -681,7 +685,7 @@ k8s.io/klog/v2/internal/severity k8s.io/utils/internal/third_party/forked/golang/net k8s.io/utils/net k8s.io/utils/strings/slices -# sigs.k8s.io/kind v0.16.0 +# sigs.k8s.io/kind v0.17.0 ## explicit; go 1.14 sigs.k8s.io/kind/pkg/apis/config/defaults sigs.k8s.io/kind/pkg/apis/config/v1alpha4 diff --git a/vendor/sigs.k8s.io/kind/pkg/apis/config/defaults/image.go b/vendor/sigs.k8s.io/kind/pkg/apis/config/defaults/image.go index 33354ac681..38777a4e80 100644 --- a/vendor/sigs.k8s.io/kind/pkg/apis/config/defaults/image.go +++ b/vendor/sigs.k8s.io/kind/pkg/apis/config/defaults/image.go @@ -18,4 +18,4 @@ limitations under the License. package defaults // Image is the default for the Config.Image field, aka the default node image. -const Image = "kindest/node:v1.25.2@sha256:9be91e9e9cdf116809841fc77ebdb8845443c4c72fe5218f3ae9eb57fdb4bace" +const Image = "kindest/node:v1.25.3@sha256:f52781bc0d7a19fb6c405c2af83abfeb311f130707a0e219175677e366cc45d1" diff --git a/vendor/sigs.k8s.io/kind/pkg/cluster/internal/create/actions/installcni/cni.go b/vendor/sigs.k8s.io/kind/pkg/cluster/internal/create/actions/installcni/cni.go index eeee6a2878..fc96751739 100644 --- a/vendor/sigs.k8s.io/kind/pkg/cluster/internal/create/actions/installcni/cni.go +++ b/vendor/sigs.k8s.io/kind/pkg/cluster/internal/create/actions/installcni/cni.go @@ -20,7 +20,8 @@ package installcni import ( "bytes" "strings" - "text/template" + + "github.com/google/safetext/yamltemplate" "sigs.k8s.io/kind/pkg/errors" "sigs.k8s.io/kind/pkg/internal/apis/config" @@ -69,7 +70,7 @@ func (a *action) Execute(ctx *actions.ActionContext) error { // their own, or use the default. The internal templating mechanism is // not intended for external usage and is unstable. if strings.Contains(manifest, "would you kindly template this file") { - t, err := template.New("cni-manifest").Parse(manifest) + t, err := yamltemplate.New("cni-manifest").Parse(manifest) if err != nil { return errors.Wrap(err, "failed to parse CNI manifest template") } diff --git a/vendor/sigs.k8s.io/kind/pkg/cluster/internal/kubeadm/config.go b/vendor/sigs.k8s.io/kind/pkg/cluster/internal/kubeadm/config.go index a45d9ff2a3..6aa1758197 100644 --- a/vendor/sigs.k8s.io/kind/pkg/cluster/internal/kubeadm/config.go +++ b/vendor/sigs.k8s.io/kind/pkg/cluster/internal/kubeadm/config.go @@ -21,7 +21,8 @@ import ( "fmt" "sort" "strings" - "text/template" + + "github.com/google/safetext/yamltemplate" "sigs.k8s.io/kind/pkg/errors" @@ -94,8 +95,8 @@ type DerivedConfigData struct { AdvertiseAddress string // DockerStableTag is automatically derived from KubernetesVersion DockerStableTag string - // SortedFeatureGateKeys allows us to iterate FeatureGates deterministically - SortedFeatureGateKeys []string + // SortedFeatureGates allows us to iterate FeatureGates deterministically + SortedFeatureGates []FeatureGate // FeatureGatesString is of the form `Foo=true,Baz=false` FeatureGatesString string // RuntimeConfigString is of the form `Foo=true,Baz=false` @@ -108,6 +109,11 @@ type DerivedConfigData struct { CgroupDriver string } +type FeatureGate struct { + Name string + Value bool +} + // Derive automatically derives DockerStableTag if not specified func (c *ConfigData) Derive() { // default cgroup driver @@ -130,13 +136,17 @@ func (c *ConfigData) Derive() { featureGateKeys = append(featureGateKeys, k) } sort.Strings(featureGateKeys) - c.SortedFeatureGateKeys = featureGateKeys // create a sorted key=value,... string of FeatureGates - var featureGates []string + c.SortedFeatureGates = make([]FeatureGate, 0, len(c.FeatureGates)) + featureGates := make([]string, 0, len(c.FeatureGates)) for _, k := range featureGateKeys { v := c.FeatureGates[k] featureGates = append(featureGates, fmt.Sprintf("%s=%t", k, v)) + c.SortedFeatureGates = append(c.SortedFeatureGates, FeatureGate{ + Name: k, + Value: v, + }) } c.FeatureGatesString = strings.Join(featureGates, ",") @@ -173,7 +183,7 @@ kubernetesVersion: {{.KubernetesVersion}} clusterName: "{{.ClusterName}}" {{ if .KubeadmFeatureGates}}featureGates: {{ range $key, $value := .KubeadmFeatureGates }} - "{{ $key }}": {{ $value }} + "{{ (StructuralData $key) }}": {{ $value }} {{end}}{{end}} controlPlaneEndpoint: "{{ .ControlPlaneEndpoint }}" # on docker for mac we have to expose the api server via port forward, @@ -272,8 +282,8 @@ evictionHard: nodefs.inodesFree: "0%" imagefs.available: "0%" {{if .FeatureGates}}featureGates: -{{ range $key := .SortedFeatureGateKeys }} - "{{ $key }}": {{ index $.FeatureGates $key }} +{{ range $index, $gate := .SortedFeatureGates }} + "{{ (StructuralData $gate.Name) }}": {{ $gate.Value }} {{end}}{{end}} {{if ne .KubeProxyMode "None"}} --- @@ -283,8 +293,8 @@ metadata: name: config mode: "{{ .KubeProxyMode }}" {{if .FeatureGates}}featureGates: -{{ range $key := .SortedFeatureGateKeys }} - "{{ $key }}": {{ index $.FeatureGates $key }} +{{ range $index, $gate := .SortedFeatureGates }} + "{{ (StructuralData $gate.Name) }}": {{ $gate.Value }} {{end}}{{end}} iptables: minSyncPeriod: 1s @@ -310,7 +320,7 @@ kubernetesVersion: {{.KubernetesVersion}} clusterName: "{{.ClusterName}}" {{ if .KubeadmFeatureGates}}featureGates: {{ range $key, $value := .KubeadmFeatureGates }} - "{{ $key }}": {{ $value }} + "{{ (StructuralData $key) }}": {{ $value }} {{end}}{{end}} controlPlaneEndpoint: "{{ .ControlPlaneEndpoint }}" # on docker for mac we have to expose the api server via port forward, @@ -409,8 +419,8 @@ evictionHard: nodefs.inodesFree: "0%" imagefs.available: "0%" {{if .FeatureGates}}featureGates: -{{ range $key := .SortedFeatureGateKeys }} - "{{ $key }}": {{ index $.FeatureGates $key }} +{{ range $index, $gate := .SortedFeatureGates }} + "{{ (StructuralData $gate.Name) }}": {{ $gate.Value }} {{end}}{{end}} {{if .DisableLocalStorageCapacityIsolation}}localStorageCapacityIsolation: false{{end}} {{if ne .KubeProxyMode "None"}} @@ -421,8 +431,8 @@ metadata: name: config mode: "{{ .KubeProxyMode }}" {{if .FeatureGates}}featureGates: -{{ range $key := .SortedFeatureGateKeys }} - "{{ $key }}": {{ index $.FeatureGates $key }} +{{ range $index, $gate := .SortedFeatureGates }} + "{{ (StructuralData $gate.Name) }}": {{ $gate.Value }} {{end}}{{end}} iptables: minSyncPeriod: 1s @@ -476,7 +486,7 @@ func Config(data ConfigData) (config string, err error) { templateSource = ConfigTemplateBetaV2 } - t, err := template.New("kubeadm-config").Parse(templateSource) + t, err := yamltemplate.New("kubeadm-config").Parse(templateSource) if err != nil { return "", errors.Wrap(err, "failed to parse config template") } diff --git a/vendor/sigs.k8s.io/kind/pkg/cluster/nodeutils/util.go b/vendor/sigs.k8s.io/kind/pkg/cluster/nodeutils/util.go index d07d0a6611..501681a2ce 100644 --- a/vendor/sigs.k8s.io/kind/pkg/cluster/nodeutils/util.go +++ b/vendor/sigs.k8s.io/kind/pkg/cluster/nodeutils/util.go @@ -82,7 +82,7 @@ func LoadImageArchive(n nodes.Node, image io.Reader) error { if err != nil { return err } - cmd := n.Command("ctr", "--namespace=k8s.io", "images", "import", "--digests", "--snapshotter="+snapshotter, "-").SetStdin(image) + cmd := n.Command("ctr", "--namespace=k8s.io", "images", "import", "--all-platforms", "--digests", "--snapshotter="+snapshotter, "-").SetStdin(image) if err := cmd.Run(); err != nil { return errors.Wrap(err, "failed to load image") } diff --git a/vendor/sigs.k8s.io/kind/pkg/cmd/kind/version/version.go b/vendor/sigs.k8s.io/kind/pkg/cmd/kind/version/version.go index c1a230a7db..a2a033376a 100644 --- a/vendor/sigs.k8s.io/kind/pkg/cmd/kind/version/version.go +++ b/vendor/sigs.k8s.io/kind/pkg/cmd/kind/version/version.go @@ -54,7 +54,7 @@ func DisplayVersion() string { } // versionCore is the core portion of the kind CLI version per Semantic Versioning 2.0.0 -const versionCore = "0.16.0" +const versionCore = "0.17.0" // versionPreRelease is the base pre-release portion of the kind CLI version per // Semantic Versioning 2.0.0