diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 415599673..c9702f2cd 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,6 +5,16 @@ updates: directory: "/" schedule: interval: "daily" + groups: + k8s.io: + patterns: + - "k8s.io/api" + - "k8s.io/apiextensions-apiserver" + - "k8s.io/apimachinery" + - "k8s.io/apiserver" + - "k8s.io/cli-runtime" + - "k8s.io/client-go" + - "k8s.io/kubectl" - package-ecosystem: "github-actions" directory: "/" schedule: diff --git a/.github/workflows/asset-transparency.yaml b/.github/workflows/asset-transparency.yaml new file mode 100644 index 000000000..ff58d1a5f --- /dev/null +++ b/.github/workflows/asset-transparency.yaml @@ -0,0 +1,18 @@ +name: Publish Release Assets to Asset Transparency Log + +on: + release: + types: [published, created, edited, released] + +jobs: + github_release_asset_transparency_log_publish_job: + runs-on: ubuntu-latest + name: Publish GitHub release asset digests to https://beta-asset.transparencylog.net + steps: + - name: Gather URLs from GitHub release and publish + id: asset-transparency + uses: transparencylog/github-releases-asset-transparency-verify-action@c77874b4514ae4003994ece9582675195fe012e2 # v11 + - name: List verified and published URLs + run: echo "Verified URLs ${{ steps.asset-transparency.outputs.verified }}" + - name: List failed URLs + run: echo "Failed URLs ${{ steps.asset-transparency.outputs.failed }}" diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 3a8fb215b..7696b4e21 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -13,9 +13,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout source code - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # pin@v3.5.3 + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # pin@v3.6.0 - name: Setup Go - uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # pin@4.0.1 + uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # pin@4.1.0 with: go-version: '1.20' - name: Install golangci-lint diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index c25beb83e..8fe45fd4e 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -35,11 +35,11 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # pin@v3.5.3 + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # pin@v3.6.0 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@1813ca74c3faaa3a2da2070b9b8a0b3e7373a0d8 # pinv2.21.0 + uses: github/codeql-action/init@04daf014b50eaf774287bf3f0f1869d4b4c4b913 # pinv2.21.7 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -50,7 +50,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@1813ca74c3faaa3a2da2070b9b8a0b3e7373a0d8 # pinv2.21.0 + uses: github/codeql-action/autobuild@04daf014b50eaf774287bf3f0f1869d4b4c4b913 # pinv2.21.7 # â„šī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -64,4 +64,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@1813ca74c3faaa3a2da2070b9b8a0b3e7373a0d8 # pinv2.21.0 + uses: github/codeql-action/analyze@04daf014b50eaf774287bf3f0f1869d4b4c4b913 # pinv2.21.7 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bd8a3e8d1..055d0eaa0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,10 +18,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout source code - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # pin@v3.5.3 + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # pin@v3.6.0 - name: Setup Go - uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # pin@4.0.1 + uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # pin@4.1.0 with: go-version: '1.20' @@ -49,10 +49,10 @@ jobs: if: github.ref == 'refs/heads/main' steps: - name: Checkout source code - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # pin@v3.5.3 + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # pin@v3.6.0 - name: Setup Go - uses: actions/setup-go@fac708d6674e30b6ba41289acaab6d4b75aa0753 # pin@4.0.1 + uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # pin@4.1.0 with: go-version: '1.20' diff --git a/OWNERS b/OWNERS index cbc2cfffc..cc18ea522 100644 --- a/OWNERS +++ b/OWNERS @@ -11,6 +11,7 @@ triage: - yxxhero - zonggen - gjenkins8 + - z4ce emeritus: - adamreese - bacongobbler diff --git a/README.md b/README.md index 736b7f296..a9e68790b 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,6 @@ Think of it like apt/yum/homebrew for Kubernetes. ## Install - Binary downloads of the Helm client can be found on [the Releases page](https://github.com/helm/helm/releases/latest). Unpack the `helm` binary and add it to your PATH and you are good to go! @@ -68,6 +67,10 @@ You can reach the Helm community and developers via the following channels: - [Helm Mailing List](https://lists.cncf.io/g/cncf-helm) - Developer Call: Thursdays at 9:30-10:00 Pacific ([meeting details](https://github.com/helm/community/blob/master/communication.md#meetings)) +### Contribution + +If you're interested in contributing, please refer to the [Contributing Guide](CONTRIBUTING.md) **before submitting a pull request**. + ### Code of conduct Participation in the Helm community is governed by the [Code of Conduct](code-of-conduct.md). diff --git a/cmd/helm/create_test.go b/cmd/helm/create_test.go index 4a3e0b33d..1a22d058f 100644 --- a/cmd/helm/create_test.go +++ b/cmd/helm/create_test.go @@ -30,9 +30,9 @@ import ( ) func TestCreateCmd(t *testing.T) { - defer ensure.HelmHome(t)() + ensure.HelmHome(t) cname := "testchart" - dir := ensure.TempDir(t) + dir := t.TempDir() defer testChdir(t, dir)() // Run a create @@ -61,7 +61,7 @@ func TestCreateCmd(t *testing.T) { } func TestCreateStarterCmd(t *testing.T) { - defer ensure.HelmHome(t)() + ensure.HelmHome(t) cname := "testchart" defer resetEnv()() os.MkdirAll(helmpath.CachePath(), 0755) @@ -127,7 +127,7 @@ func TestCreateStarterCmd(t *testing.T) { func TestCreateStarterAbsoluteCmd(t *testing.T) { defer resetEnv()() - defer ensure.HelmHome(t)() + ensure.HelmHome(t) cname := "testchart" // Create a starter. diff --git a/cmd/helm/dependency_update_test.go b/cmd/helm/dependency_update_test.go index 491f6a856..b94bb7819 100644 --- a/cmd/helm/dependency_update_test.go +++ b/cmd/helm/dependency_update_test.go @@ -149,7 +149,7 @@ func TestDependencyUpdateCmd(t *testing.T) { func TestDependencyUpdateCmd_DoNotDeleteOldChartsOnError(t *testing.T) { defer resetEnv()() - defer ensure.HelmHome(t)() + ensure.HelmHome(t) srv, err := repotest.NewTempServerWithCleanup(t, "testdata/testcharts/*.tgz") if err != nil { diff --git a/cmd/helm/flags.go b/cmd/helm/flags.go index 3f89aae29..a8f25cb35 100644 --- a/cmd/helm/flags.go +++ b/cmd/helm/flags.go @@ -61,6 +61,7 @@ func addChartPathOptionsFlags(f *pflag.FlagSet, c *action.ChartPathOptions) { f.StringVar(&c.CertFile, "cert-file", "", "identify HTTPS client using this SSL certificate file") f.StringVar(&c.KeyFile, "key-file", "", "identify HTTPS client using this SSL key file") f.BoolVar(&c.InsecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the chart download") + f.BoolVar(&c.PlainHTTP, "plain-http", false, "use insecure HTTP connections for the chart download") f.StringVar(&c.CaFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") f.BoolVar(&c.PassCredentialsAll, "pass-credentials", false, "pass credentials to all domains") } diff --git a/cmd/helm/get.go b/cmd/helm/get.go index 7c4854b59..727cdaf88 100644 --- a/cmd/helm/get.go +++ b/cmd/helm/get.go @@ -33,6 +33,7 @@ get extended information about the release, including: - The generated manifest file - The notes provided by the chart of the release - The hooks associated with the release +- The metadata of the release ` func newGetCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { @@ -48,6 +49,7 @@ func newGetCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { cmd.AddCommand(newGetManifestCmd(cfg, out)) cmd.AddCommand(newGetHooksCmd(cfg, out)) cmd.AddCommand(newGetNotesCmd(cfg, out)) + cmd.AddCommand(newGetMetadataCmd(cfg, out)) return cmd } diff --git a/cmd/helm/get_all.go b/cmd/helm/get_all.go index 2dbef97cf..e51d50536 100644 --- a/cmd/helm/get_all.go +++ b/cmd/helm/get_all.go @@ -59,7 +59,7 @@ func newGetAllCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { return tpl(template, data, out) } - return output.Table.Write(out, &statusPrinter{res, true, false, false}) + return output.Table.Write(out, &statusPrinter{res, true, false, false, true}) }, } diff --git a/cmd/helm/get_metadata.go b/cmd/helm/get_metadata.go new file mode 100644 index 000000000..adab891bd --- /dev/null +++ b/cmd/helm/get_metadata.go @@ -0,0 +1,94 @@ +/* +Copyright The Helm Authors. + +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. +*/ + +package main + +import ( + "fmt" + "io" + "log" + + "github.com/spf13/cobra" + + "helm.sh/helm/v3/cmd/helm/require" + "helm.sh/helm/v3/pkg/action" + "helm.sh/helm/v3/pkg/cli/output" +) + +type metadataWriter struct { + metadata *action.Metadata +} + +func newGetMetadataCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { + var outfmt output.Format + client := action.NewGetMetadata(cfg) + + cmd := &cobra.Command{ + Use: "metadata RELEASE_NAME", + Short: "This command fetches metadata for a given release", + Args: require.ExactArgs(1), + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 0 { + return nil, cobra.ShellCompDirectiveNoFileComp + } + return compListReleases(toComplete, args, cfg) + }, + RunE: func(cmd *cobra.Command, args []string) error { + releaseMetadata, err := client.Run(args[0]) + if err != nil { + return err + } + return outfmt.Write(out, &metadataWriter{releaseMetadata}) + }, + } + + f := cmd.Flags() + f.IntVar(&client.Version, "revision", 0, "specify release revision") + err := cmd.RegisterFlagCompletionFunc("revision", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) == 1 { + return compListRevisions(toComplete, cfg, args[0]) + } + return nil, cobra.ShellCompDirectiveNoFileComp + }) + + if err != nil { + log.Fatal(err) + } + + bindOutputFlag(cmd, &outfmt) + + return cmd +} + +func (w metadataWriter) WriteTable(out io.Writer) error { + _, _ = fmt.Fprintf(out, "NAME: %v\n", w.metadata.Name) + _, _ = fmt.Fprintf(out, "CHART: %v\n", w.metadata.Chart) + _, _ = fmt.Fprintf(out, "VERSION: %v\n", w.metadata.Version) + _, _ = fmt.Fprintf(out, "APP_VERSION: %v\n", w.metadata.AppVersion) + _, _ = fmt.Fprintf(out, "NAMESPACE: %v\n", w.metadata.Namespace) + _, _ = fmt.Fprintf(out, "REVISION: %v\n", w.metadata.Revision) + _, _ = fmt.Fprintf(out, "STATUS: %v\n", w.metadata.Status) + _, _ = fmt.Fprintf(out, "DEPLOYED_AT: %v\n", w.metadata.DeployedAt) + return nil +} + +func (w metadataWriter) WriteJSON(out io.Writer) error { + return output.EncodeJSON(out, w.metadata) +} + +func (w metadataWriter) WriteYAML(out io.Writer) error { + return output.EncodeYAML(out, w.metadata) +} diff --git a/cmd/helm/get_metadata_test.go b/cmd/helm/get_metadata_test.go new file mode 100644 index 000000000..b6f0ab9f2 --- /dev/null +++ b/cmd/helm/get_metadata_test.go @@ -0,0 +1,66 @@ +/* +Copyright The Helm Authors. + +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. +*/ + +package main + +import ( + "testing" + + "helm.sh/helm/v3/pkg/release" +) + +func TestGetMetadataCmd(t *testing.T) { + tests := []cmdTestCase{{ + name: "get metadata with a release", + cmd: "get metadata thomas-guide", + golden: "output/get-metadata.txt", + rels: []*release.Release{release.Mock(&release.MockReleaseOptions{Name: "thomas-guide"})}, + }, { + name: "get metadata requires release name arg", + cmd: "get metadata", + golden: "output/get-metadata-args.txt", + rels: []*release.Release{release.Mock(&release.MockReleaseOptions{Name: "thomas-guide"})}, + wantError: true, + }, { + name: "get metadata to json", + cmd: "get metadata thomas-guide --output json", + golden: "output/get-metadata.json", + rels: []*release.Release{release.Mock(&release.MockReleaseOptions{Name: "thomas-guide"})}, + }, { + name: "get metadata to yaml", + cmd: "get metadata thomas-guide --output yaml", + golden: "output/get-metadata.yaml", + rels: []*release.Release{release.Mock(&release.MockReleaseOptions{Name: "thomas-guide"})}, + }} + runTestCmd(t, tests) +} + +func TestGetMetadataCompletion(t *testing.T) { + checkReleaseCompletion(t, "get metadata", false) +} + +func TestGetMetadataRevisionCompletion(t *testing.T) { + revisionFlagCompletionTest(t, "get metadata") +} + +func TestGetMetadataOutputCompletion(t *testing.T) { + outputFlagCompletionTest(t, "get metadata") +} + +func TestGetMetadataFileCompletion(t *testing.T) { + checkFileCompletion(t, "get metadata", false) + checkFileCompletion(t, "get metadata myrelease", false) +} diff --git a/cmd/helm/install.go b/cmd/helm/install.go index bc095de77..d987d300f 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -136,7 +136,8 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { return compInstall(args, toComplete, client) }, RunE: func(_ *cobra.Command, args []string) error { - registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, client.InsecureSkipTLSverify) + registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, + client.InsecureSkipTLSverify, client.PlainHTTP) if err != nil { return fmt.Errorf("missing registry client: %w", err) } @@ -153,7 +154,7 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { return errors.Wrap(err, "INSTALLATION FAILED") } - return outfmt.Write(out, &statusPrinter{rel, settings.Debug, false, false}) + return outfmt.Write(out, &statusPrinter{rel, settings.Debug, false, false, false}) }, } @@ -188,6 +189,7 @@ func addInstallFlags(cmd *cobra.Command, f *pflag.FlagSet, client *action.Instal f.BoolVar(&client.Atomic, "atomic", false, "if set, the installation process deletes the installation on failure. The --wait flag will be set automatically if --atomic is used") f.BoolVar(&client.SkipCRDs, "skip-crds", false, "if set, no CRDs will be installed. By default, CRDs are installed if not already present") f.BoolVar(&client.SubNotes, "render-subchart-notes", false, "if set, render subchart notes along with the parent") + f.StringToStringVarP(&client.Labels, "labels", "l", nil, "Labels that would be added to release metadata. Should be divided by comma.") f.BoolVar(&client.EnableDNS, "enable-dns", false, "enable DNS lookups when rendering templates") addValueOptionsFlags(f, valueOpts) addChartPathOptionsFlags(f, &client.ChartPathOptions) diff --git a/cmd/helm/package_test.go b/cmd/helm/package_test.go index d7e01fb75..9093b510c 100644 --- a/cmd/helm/package_test.go +++ b/cmd/helm/package_test.go @@ -23,7 +23,6 @@ import ( "strings" "testing" - "helm.sh/helm/v3/internal/test/ensure" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" ) @@ -111,7 +110,7 @@ func TestPackage(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - cachePath := ensure.TempDir(t) + cachePath := t.TempDir() defer testChdir(t, cachePath)() if err := os.MkdirAll("toot", 0777); err != nil { @@ -170,7 +169,7 @@ func TestSetAppVersion(t *testing.T) { var ch *chart.Chart expectedAppVersion := "app-version-foo" chartToPackage := "testdata/testcharts/alpine" - dir := ensure.TempDir(t) + dir := t.TempDir() cmd := fmt.Sprintf("package %s --destination=%s --app-version=%s", chartToPackage, dir, expectedAppVersion) _, output, err := executeActionCommand(cmd) if err != nil { diff --git a/cmd/helm/pull.go b/cmd/helm/pull.go index 2d3747f28..af3092aff 100644 --- a/cmd/helm/pull.go +++ b/cmd/helm/pull.go @@ -64,7 +64,8 @@ func newPullCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client.Version = ">0.0.0-0" } - registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, client.InsecureSkipTLSverify) + registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, + client.InsecureSkipTLSverify, client.PlainHTTP) if err != nil { return fmt.Errorf("missing registry client: %w", err) } diff --git a/cmd/helm/push.go b/cmd/helm/push.go index b1e3e60af..3375155ed 100644 --- a/cmd/helm/push.go +++ b/cmd/helm/push.go @@ -39,6 +39,7 @@ type registryPushOptions struct { keyFile string caFile string insecureSkipTLSverify bool + plainHTTP bool } func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { @@ -67,7 +68,7 @@ func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { return nil, cobra.ShellCompDirectiveNoFileComp }, RunE: func(cmd *cobra.Command, args []string) error { - registryClient, err := newRegistryClient(o.certFile, o.keyFile, o.caFile, o.insecureSkipTLSverify) + registryClient, err := newRegistryClient(o.certFile, o.keyFile, o.caFile, o.insecureSkipTLSverify, o.plainHTTP) if err != nil { return fmt.Errorf("missing registry client: %w", err) } @@ -77,6 +78,7 @@ func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client := action.NewPushWithOpts(action.WithPushConfig(cfg), action.WithTLSClientConfig(o.certFile, o.keyFile, o.caFile), action.WithInsecureSkipTLSVerify(o.insecureSkipTLSverify), + action.WithPlainHTTP(o.plainHTTP), action.WithPushOptWriter(out)) client.Settings = settings output, err := client.Run(chartRef, remote) @@ -93,6 +95,7 @@ func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.StringVar(&o.keyFile, "key-file", "", "identify registry client using this SSL key file") f.StringVar(&o.caFile, "ca-file", "", "verify certificates of HTTPS-enabled servers using this CA bundle") f.BoolVar(&o.insecureSkipTLSverify, "insecure-skip-tls-verify", false, "skip tls certificate checks for the chart upload") + f.BoolVar(&o.plainHTTP, "plain-http", false, "use insecure HTTP connections for the chart upload") return cmd } diff --git a/cmd/helm/release_testing.go b/cmd/helm/release_testing.go index d9b8fa8c9..548ae2b8a 100644 --- a/cmd/helm/release_testing.go +++ b/cmd/helm/release_testing.go @@ -59,9 +59,9 @@ func newReleaseTestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command notName := regexp.MustCompile(`^!\s?name=`) for _, f := range filter { if strings.HasPrefix(f, "name=") { - client.Filters["name"] = append(client.Filters["name"], strings.TrimPrefix(f, "name=")) + client.Filters[action.IncludeNameFilter] = append(client.Filters[action.IncludeNameFilter], strings.TrimPrefix(f, "name=")) } else if notName.MatchString(f) { - client.Filters["!name"] = append(client.Filters["!name"], notName.ReplaceAllLiteralString(f, "")) + client.Filters[action.ExcludeNameFilter] = append(client.Filters[action.ExcludeNameFilter], notName.ReplaceAllLiteralString(f, "")) } } rel, runErr := client.Run(args[0]) @@ -72,7 +72,7 @@ func newReleaseTestCmd(cfg *action.Configuration, out io.Writer) *cobra.Command return runErr } - if err := outfmt.Write(out, &statusPrinter{rel, settings.Debug, false, false}); err != nil { + if err := outfmt.Write(out, &statusPrinter{rel, settings.Debug, false, false, false}); err != nil { return err } diff --git a/cmd/helm/repo_add_test.go b/cmd/helm/repo_add_test.go index 9475f056b..2386bb01f 100644 --- a/cmd/helm/repo_add_test.go +++ b/cmd/helm/repo_add_test.go @@ -27,7 +27,6 @@ import ( "sigs.k8s.io/yaml" - "helm.sh/helm/v3/internal/test/ensure" "helm.sh/helm/v3/pkg/helmpath" "helm.sh/helm/v3/pkg/helmpath/xdg" "helm.sh/helm/v3/pkg/repo" @@ -48,7 +47,7 @@ func TestRepoAddCmd(t *testing.T) { } defer srv2.Stop() - tmpdir := filepath.Join(ensure.TempDir(t), "path-component.yaml/data") + tmpdir := filepath.Join(t.TempDir(), "path-component.yaml/data") err = os.MkdirAll(tmpdir, 0777) if err != nil { t.Fatal(err) @@ -88,7 +87,7 @@ func TestRepoAdd(t *testing.T) { } defer ts.Stop() - rootDir := ensure.TempDir(t) + rootDir := t.TempDir() repoFile := filepath.Join(rootDir, "repositories.yaml") const testRepoName = "test-name" @@ -145,8 +144,8 @@ func TestRepoAddCheckLegalName(t *testing.T) { const testRepoName = "test-hub/test-name" - rootDir := ensure.TempDir(t) - repoFile := filepath.Join(ensure.TempDir(t), "repositories.yaml") + rootDir := t.TempDir() + repoFile := filepath.Join(t.TempDir(), "repositories.yaml") o := &repoAddOptions{ name: testRepoName, @@ -170,25 +169,25 @@ func TestRepoAddCheckLegalName(t *testing.T) { func TestRepoAddConcurrentGoRoutines(t *testing.T) { const testName = "test-name" - repoFile := filepath.Join(ensure.TempDir(t), "repositories.yaml") + repoFile := filepath.Join(t.TempDir(), "repositories.yaml") repoAddConcurrent(t, testName, repoFile) } func TestRepoAddConcurrentDirNotExist(t *testing.T) { const testName = "test-name-2" - repoFile := filepath.Join(ensure.TempDir(t), "foo", "repositories.yaml") + repoFile := filepath.Join(t.TempDir(), "foo", "repositories.yaml") repoAddConcurrent(t, testName, repoFile) } func TestRepoAddConcurrentNoFileExtension(t *testing.T) { const testName = "test-name-3" - repoFile := filepath.Join(ensure.TempDir(t), "repositories") + repoFile := filepath.Join(t.TempDir(), "repositories") repoAddConcurrent(t, testName, repoFile) } func TestRepoAddConcurrentHiddenFile(t *testing.T) { const testName = "test-name-4" - repoFile := filepath.Join(ensure.TempDir(t), ".repositories") + repoFile := filepath.Join(t.TempDir(), ".repositories") repoAddConcurrent(t, testName, repoFile) } @@ -254,7 +253,7 @@ func TestRepoAddWithPasswordFromStdin(t *testing.T) { t.Errorf("unexpected error, got '%v'", err) } - tmpdir := ensure.TempDir(t) + tmpdir := t.TempDir() repoFile := filepath.Join(tmpdir, "repositories.yaml") store := storageFixture() diff --git a/cmd/helm/repo_index.go b/cmd/helm/repo_index.go index 917acd442..3960380d1 100644 --- a/cmd/helm/repo_index.go +++ b/cmd/helm/repo_index.go @@ -43,6 +43,7 @@ type repoIndexOptions struct { dir string url string merge string + json bool } func newRepoIndexCmd(out io.Writer) *cobra.Command { @@ -70,6 +71,7 @@ func newRepoIndexCmd(out io.Writer) *cobra.Command { f := cmd.Flags() f.StringVar(&o.url, "url", "", "url of chart repository") f.StringVar(&o.merge, "merge", "", "merge the generated index into the given index") + f.BoolVar(&o.json, "json", false, "output in JSON format") return cmd } @@ -80,10 +82,10 @@ func (i *repoIndexOptions) run(out io.Writer) error { return err } - return index(path, i.url, i.merge) + return index(path, i.url, i.merge, i.json) } -func index(dir, url, mergeTo string) error { +func index(dir, url, mergeTo string, json bool) error { out := filepath.Join(dir, "index.yaml") i, err := repo.IndexDirectory(dir, url) @@ -95,7 +97,7 @@ func index(dir, url, mergeTo string) error { var i2 *repo.IndexFile if _, err := os.Stat(mergeTo); os.IsNotExist(err) { i2 = repo.NewIndexFile() - i2.WriteFile(mergeTo, 0644) + writeIndexFile(i2, mergeTo, json) } else { i2, err = repo.LoadIndexFile(mergeTo) if err != nil { @@ -105,5 +107,12 @@ func index(dir, url, mergeTo string) error { i.Merge(i2) } i.SortEntries() + return writeIndexFile(i, out, json) +} + +func writeIndexFile(i *repo.IndexFile, out string, json bool) error { + if json { + return i.WriteJSONFile(out, 0644) + } return i.WriteFile(out, 0644) } diff --git a/cmd/helm/repo_index_test.go b/cmd/helm/repo_index_test.go index ae3390154..554a3dadf 100644 --- a/cmd/helm/repo_index_test.go +++ b/cmd/helm/repo_index_test.go @@ -18,18 +18,18 @@ package main import ( "bytes" + "encoding/json" "io" "os" "path/filepath" "testing" - "helm.sh/helm/v3/internal/test/ensure" "helm.sh/helm/v3/pkg/repo" ) func TestRepoIndexCmd(t *testing.T) { - dir := ensure.TempDir(t) + dir := t.TempDir() comp := filepath.Join(dir, "compressedchart-0.1.0.tgz") if err := linkOrCopy("testdata/testcharts/compressedchart-0.1.0.tgz", comp); err != nil { @@ -68,6 +68,28 @@ func TestRepoIndexCmd(t *testing.T) { t.Errorf("expected %q, got %q", expectedVersion, vs[0].Version) } + b, err := os.ReadFile(destIndex) + if err != nil { + t.Fatal(err) + } + if json.Valid(b) { + t.Error("did not expect index file to be valid json") + } + + // Test with `--json` + + c.ParseFlags([]string{"--json", "true"}) + if err := c.RunE(c, []string{dir}); err != nil { + t.Error(err) + } + + if b, err = os.ReadFile(destIndex); err != nil { + t.Fatal(err) + } + if !json.Valid(b) { + t.Error("index file is not valid json") + } + // Test with `--merge` // Remove first two charts. diff --git a/cmd/helm/repo_remove_test.go b/cmd/helm/repo_remove_test.go index 768295655..e2795e738 100644 --- a/cmd/helm/repo_remove_test.go +++ b/cmd/helm/repo_remove_test.go @@ -24,7 +24,6 @@ import ( "strings" "testing" - "helm.sh/helm/v3/internal/test/ensure" "helm.sh/helm/v3/pkg/helmpath" "helm.sh/helm/v3/pkg/repo" "helm.sh/helm/v3/pkg/repo/repotest" @@ -37,7 +36,7 @@ func TestRepoRemove(t *testing.T) { } defer ts.Stop() - rootDir := ensure.TempDir(t) + rootDir := t.TempDir() repoFile := filepath.Join(rootDir, "repositories.yaml") const testRepoName = "test-name" @@ -169,7 +168,7 @@ func TestRepoRemoveCompletion(t *testing.T) { } defer ts.Stop() - rootDir := ensure.TempDir(t) + rootDir := t.TempDir() repoFile := filepath.Join(rootDir, "repositories.yaml") repoCache := filepath.Join(rootDir, "cache/") diff --git a/cmd/helm/repo_update_test.go b/cmd/helm/repo_update_test.go index a6fbc1b0d..645c68cfe 100644 --- a/cmd/helm/repo_update_test.go +++ b/cmd/helm/repo_update_test.go @@ -102,10 +102,9 @@ func TestUpdateCmdInvalid(t *testing.T) { } func TestUpdateCustomCacheCmd(t *testing.T) { - rootDir := ensure.TempDir(t) + rootDir := t.TempDir() cachePath := filepath.Join(rootDir, "updcustomcache") os.Mkdir(cachePath, os.ModePerm) - defer os.RemoveAll(cachePath) ts, err := repotest.NewTempServerWithCleanup(t, "testdata/testserver/*.*") if err != nil { @@ -129,7 +128,7 @@ func TestUpdateCustomCacheCmd(t *testing.T) { func TestUpdateCharts(t *testing.T) { defer resetEnv()() - defer ensure.HelmHome(t)() + ensure.HelmHome(t) ts, err := repotest.NewTempServerWithCleanup(t, "testdata/testserver/*.*") if err != nil { @@ -164,7 +163,7 @@ func TestRepoUpdateFileCompletion(t *testing.T) { func TestUpdateChartsFail(t *testing.T) { defer resetEnv()() - defer ensure.HelmHome(t)() + ensure.HelmHome(t) ts, err := repotest.NewTempServerWithCleanup(t, "testdata/testserver/*.*") if err != nil { @@ -197,7 +196,7 @@ func TestUpdateChartsFail(t *testing.T) { func TestUpdateChartsFailWithError(t *testing.T) { defer resetEnv()() - defer ensure.HelmHome(t)() + ensure.HelmHome(t) ts, err := repotest.NewTempServerWithCleanup(t, "testdata/testserver/*.*") if err != nil { diff --git a/cmd/helm/rollback.go b/cmd/helm/rollback.go index ea4b75cb1..7de98e404 100644 --- a/cmd/helm/rollback.go +++ b/cmd/helm/rollback.go @@ -32,8 +32,8 @@ const rollbackDesc = ` This command rolls back a release to a previous revision. The first argument of the rollback command is the name of a release, and the -second is a revision (version) number. If this argument is omitted, it will -roll back to the previous release. +second is a revision (version) number. If this argument is omitted or set to +0, it will roll back to the previous release. To see revision numbers, run 'helm history RELEASE'. ` diff --git a/cmd/helm/rollback_test.go b/cmd/helm/rollback_test.go index 9ca921557..6d38e16eb 100644 --- a/cmd/helm/rollback_test.go +++ b/cmd/helm/rollback_test.go @@ -64,6 +64,12 @@ func TestRollbackCmd(t *testing.T) { cmd: "rollback funny-honey", golden: "output/rollback-no-revision.txt", rels: rels, + }, { + name: "rollback a release with non-existent version", + cmd: "rollback funny-honey 3", + golden: "output/rollback-non-existent-version.txt", + rels: rels, + wantError: true, }, { name: "rollback a release without release name", cmd: "rollback", diff --git a/cmd/helm/root.go b/cmd/helm/root.go index 5bccdf5bf..dd95b1df2 100644 --- a/cmd/helm/root.go +++ b/cmd/helm/root.go @@ -152,7 +152,7 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string flags.ParseErrorsWhitelist.UnknownFlags = true flags.Parse(args) - registryClient, err := newDefaultRegistryClient() + registryClient, err := newDefaultRegistryClient(false) if err != nil { return nil, err } @@ -257,7 +257,7 @@ func checkForExpiredRepos(repofile string) { } -func newRegistryClient(certFile, keyFile, caFile string, insecureSkipTLSverify bool) (*registry.Client, error) { +func newRegistryClient(certFile, keyFile, caFile string, insecureSkipTLSverify, plainHTTP bool) (*registry.Client, error) { if certFile != "" && keyFile != "" || caFile != "" || insecureSkipTLSverify { registryClient, err := newRegistryClientWithTLS(certFile, keyFile, caFile, insecureSkipTLSverify) if err != nil { @@ -265,21 +265,26 @@ func newRegistryClient(certFile, keyFile, caFile string, insecureSkipTLSverify b } return registryClient, nil } - registryClient, err := newDefaultRegistryClient() + registryClient, err := newDefaultRegistryClient(plainHTTP) if err != nil { return nil, err } return registryClient, nil } -func newDefaultRegistryClient() (*registry.Client, error) { - // Create a new registry client - registryClient, err := registry.NewClient( +func newDefaultRegistryClient(plainHTTP bool) (*registry.Client, error) { + opts := []registry.ClientOption{ registry.ClientOptDebug(settings.Debug), registry.ClientOptEnableCache(true), registry.ClientOptWriter(os.Stderr), registry.ClientOptCredentialsFile(settings.RegistryConfig), - ) + } + if plainHTTP { + opts = append(opts, registry.ClientOptPlainHTTP()) + } + + // Create a new registry client + registryClient, err := registry.NewClient(opts...) if err != nil { return nil, err } diff --git a/cmd/helm/root_test.go b/cmd/helm/root_test.go index 075544971..65e6d66c7 100644 --- a/cmd/helm/root_test.go +++ b/cmd/helm/root_test.go @@ -77,7 +77,7 @@ func TestRootCmd(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - defer ensure.HelmHome(t)() + ensure.HelmHome(t) for k, v := range tt.envvars { os.Setenv(k, v) diff --git a/cmd/helm/show.go b/cmd/helm/show.go index a2edd1931..28eb9756d 100644 --- a/cmd/helm/show.go +++ b/cmd/helm/show.go @@ -226,7 +226,8 @@ func runShow(args []string, client *action.Show) (string, error) { } func addRegistryClient(client *action.Show) error { - registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, client.InsecureSkipTLSverify) + registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, + client.InsecureSkipTLSverify, client.PlainHTTP) if err != nil { return fmt.Errorf("missing registry client: %w", err) } diff --git a/cmd/helm/status.go b/cmd/helm/status.go index aa22aa02a..850862cd5 100644 --- a/cmd/helm/status.go +++ b/cmd/helm/status.go @@ -80,7 +80,7 @@ func newStatusCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { // strip chart metadata from the output rel.Chart = nil - return outfmt.Write(out, &statusPrinter{rel, false, client.ShowDescription, client.ShowResources}) + return outfmt.Write(out, &statusPrinter{rel, false, client.ShowDescription, client.ShowResources, false}) }, } @@ -112,6 +112,7 @@ type statusPrinter struct { debug bool showDescription bool showResources bool + showMetadata bool } func (s statusPrinter) WriteJSON(out io.Writer) error { @@ -126,15 +127,20 @@ func (s statusPrinter) WriteTable(out io.Writer) error { if s.release == nil { return nil } - fmt.Fprintf(out, "NAME: %s\n", s.release.Name) + _, _ = fmt.Fprintf(out, "NAME: %s\n", s.release.Name) if !s.release.Info.LastDeployed.IsZero() { - fmt.Fprintf(out, "LAST DEPLOYED: %s\n", s.release.Info.LastDeployed.Format(time.ANSIC)) + _, _ = fmt.Fprintf(out, "LAST DEPLOYED: %s\n", s.release.Info.LastDeployed.Format(time.ANSIC)) + } + _, _ = fmt.Fprintf(out, "NAMESPACE: %s\n", s.release.Namespace) + _, _ = fmt.Fprintf(out, "STATUS: %s\n", s.release.Info.Status.String()) + _, _ = fmt.Fprintf(out, "REVISION: %d\n", s.release.Version) + if s.showMetadata { + _, _ = fmt.Fprintf(out, "CHART: %s\n", s.release.Chart.Metadata.Name) + _, _ = fmt.Fprintf(out, "VERSION: %s\n", s.release.Chart.Metadata.Version) + _, _ = fmt.Fprintf(out, "APP_VERSION: %s\n", s.release.Chart.Metadata.AppVersion) } - fmt.Fprintf(out, "NAMESPACE: %s\n", s.release.Namespace) - fmt.Fprintf(out, "STATUS: %s\n", s.release.Info.Status.String()) - fmt.Fprintf(out, "REVISION: %d\n", s.release.Version) if s.showDescription { - fmt.Fprintf(out, "DESCRIPTION: %s\n", s.release.Info.Description) + _, _ = fmt.Fprintf(out, "DESCRIPTION: %s\n", s.release.Info.Description) } if s.showResources && s.release.Info.Resources != nil && len(s.release.Info.Resources) > 0 { @@ -149,31 +155,31 @@ func (s statusPrinter) WriteTable(out io.Writer) error { } for _, t := range keys { - fmt.Fprintf(buf, "==> %s\n", t) + _, _ = fmt.Fprintf(buf, "==> %s\n", t) vk := s.release.Info.Resources[t] for _, resource := range vk { if err := printer.PrintObj(resource, buf); err != nil { - fmt.Fprintf(buf, "failed to print object type %s: %v\n", t, err) + _, _ = fmt.Fprintf(buf, "failed to print object type %s: %v\n", t, err) } } buf.WriteString("\n") } - fmt.Fprintf(out, "RESOURCES:\n%s\n", buf.String()) + _, _ = fmt.Fprintf(out, "RESOURCES:\n%s\n", buf.String()) } executions := executionsByHookEvent(s.release) if tests, ok := executions[release.HookTest]; !ok || len(tests) == 0 { - fmt.Fprintln(out, "TEST SUITE: None") + _, _ = fmt.Fprintln(out, "TEST SUITE: None") } else { for _, h := range tests { // Don't print anything if hook has not been initiated if h.LastRun.StartedAt.IsZero() { continue } - fmt.Fprintf(out, "TEST SUITE: %s\n%s\n%s\n%s\n", + _, _ = fmt.Fprintf(out, "TEST SUITE: %s\n%s\n%s\n%s\n", h.Name, fmt.Sprintf("Last Started: %s", h.LastRun.StartedAt.Format(time.ANSIC)), fmt.Sprintf("Last Completed: %s", h.LastRun.CompletedAt.Format(time.ANSIC)), @@ -183,38 +189,38 @@ func (s statusPrinter) WriteTable(out io.Writer) error { } if s.debug { - fmt.Fprintln(out, "USER-SUPPLIED VALUES:") + _, _ = fmt.Fprintln(out, "USER-SUPPLIED VALUES:") err := output.EncodeYAML(out, s.release.Config) if err != nil { return err } // Print an extra newline - fmt.Fprintln(out) + _, _ = fmt.Fprintln(out) cfg, err := chartutil.CoalesceValues(s.release.Chart, s.release.Config) if err != nil { return err } - fmt.Fprintln(out, "COMPUTED VALUES:") + _, _ = fmt.Fprintln(out, "COMPUTED VALUES:") err = output.EncodeYAML(out, cfg.AsMap()) if err != nil { return err } // Print an extra newline - fmt.Fprintln(out) + _, _ = fmt.Fprintln(out) } if strings.EqualFold(s.release.Info.Description, "Dry run complete") || s.debug { - fmt.Fprintln(out, "HOOKS:") + _, _ = fmt.Fprintln(out, "HOOKS:") for _, h := range s.release.Hooks { - fmt.Fprintf(out, "---\n# Source: %s\n%s\n", h.Path, h.Manifest) + _, _ = fmt.Fprintf(out, "---\n# Source: %s\n%s\n", h.Path, h.Manifest) } - fmt.Fprintf(out, "MANIFEST:\n%s\n", s.release.Manifest) + _, _ = fmt.Fprintf(out, "MANIFEST:\n%s\n", s.release.Manifest) } if len(s.release.Info.Notes) > 0 { - fmt.Fprintf(out, "NOTES:\n%s\n", strings.TrimSpace(s.release.Info.Notes)) + _, _ = fmt.Fprintf(out, "NOTES:\n%s\n", strings.TrimSpace(s.release.Info.Notes)) } return nil } diff --git a/cmd/helm/status_test.go b/cmd/helm/status_test.go index 6d34d6db7..6722bf949 100644 --- a/cmd/helm/status_test.go +++ b/cmd/helm/status_test.go @@ -32,7 +32,7 @@ func TestStatusCmd(t *testing.T) { Name: "flummoxed-chickadee", Namespace: "default", Info: info, - Chart: &chart.Chart{}, + Chart: &chart.Chart{Metadata: &chart.Metadata{Name: "name", Version: "1.2.3", AppVersion: "3.2.1"}}, Hooks: hooks, }} } diff --git a/cmd/helm/template.go b/cmd/helm/template.go index f8cd8268b..a16cbc76e 100644 --- a/cmd/helm/template.go +++ b/cmd/helm/template.go @@ -73,7 +73,8 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { client.KubeVersion = parsedKubeVersion } - registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, client.InsecureSkipTLSverify) + registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, + client.InsecureSkipTLSverify, client.PlainHTTP) if err != nil { return fmt.Errorf("missing registry client: %w", err) } diff --git a/cmd/helm/testdata/output/get-metadata-args.txt b/cmd/helm/testdata/output/get-metadata-args.txt new file mode 100644 index 000000000..acd3f4c15 --- /dev/null +++ b/cmd/helm/testdata/output/get-metadata-args.txt @@ -0,0 +1,3 @@ +Error: "helm get metadata" requires 1 argument + +Usage: helm get metadata RELEASE_NAME [flags] diff --git a/cmd/helm/testdata/output/get-metadata.json b/cmd/helm/testdata/output/get-metadata.json new file mode 100644 index 000000000..1d5152b24 --- /dev/null +++ b/cmd/helm/testdata/output/get-metadata.json @@ -0,0 +1 @@ +{"name":"thomas-guide","chart":"foo","version":"0.1.0-beta.1","appVersion":"1.0","namespace":"default","revision":1,"status":"deployed","deployedAt":"1977-09-02T22:04:05Z"} diff --git a/cmd/helm/testdata/output/get-metadata.txt b/cmd/helm/testdata/output/get-metadata.txt new file mode 100644 index 000000000..b91f1b86a --- /dev/null +++ b/cmd/helm/testdata/output/get-metadata.txt @@ -0,0 +1,8 @@ +NAME: thomas-guide +CHART: foo +VERSION: 0.1.0-beta.1 +APP_VERSION: 1.0 +NAMESPACE: default +REVISION: 1 +STATUS: deployed +DEPLOYED_AT: 1977-09-02T22:04:05Z diff --git a/cmd/helm/testdata/output/get-metadata.yaml b/cmd/helm/testdata/output/get-metadata.yaml new file mode 100644 index 000000000..b6d49b038 --- /dev/null +++ b/cmd/helm/testdata/output/get-metadata.yaml @@ -0,0 +1,8 @@ +appVersion: "1.0" +chart: foo +deployedAt: "1977-09-02T22:04:05Z" +name: thomas-guide +namespace: default +revision: 1 +status: deployed +version: 0.1.0-beta.1 diff --git a/cmd/helm/testdata/output/get-release.txt b/cmd/helm/testdata/output/get-release.txt index f6c3b57eb..12b4a407a 100644 --- a/cmd/helm/testdata/output/get-release.txt +++ b/cmd/helm/testdata/output/get-release.txt @@ -3,6 +3,9 @@ LAST DEPLOYED: Fri Sep 2 22:04:05 1977 NAMESPACE: default STATUS: deployed REVISION: 1 +CHART: foo +VERSION: 0.1.0-beta.1 +APP_VERSION: 1.0 TEST SUITE: None USER-SUPPLIED VALUES: name: value diff --git a/cmd/helm/testdata/output/lint-chart-with-bad-subcharts-with-subcharts.txt b/cmd/helm/testdata/output/lint-chart-with-bad-subcharts-with-subcharts.txt index e77aa387f..d43c7c361 100644 --- a/cmd/helm/testdata/output/lint-chart-with-bad-subcharts-with-subcharts.txt +++ b/cmd/helm/testdata/output/lint-chart-with-bad-subcharts-with-subcharts.txt @@ -1,6 +1,6 @@ ==> Linting testdata/testcharts/chart-with-bad-subcharts [INFO] Chart.yaml: icon is recommended -[WARNING] templates/: directory not found +[ERROR] templates/: error unpacking bad-subchart in chart-with-bad-subcharts: validation: chart.metadata.name is required [ERROR] : unable to load chart error unpacking bad-subchart in chart-with-bad-subcharts: validation: chart.metadata.name is required @@ -9,12 +9,11 @@ [ERROR] Chart.yaml: apiVersion is required. The value must be either "v1" or "v2" [ERROR] Chart.yaml: version is required [INFO] Chart.yaml: icon is recommended -[WARNING] templates/: directory not found +[ERROR] templates/: validation: chart.metadata.name is required [ERROR] : unable to load chart validation: chart.metadata.name is required ==> Linting testdata/testcharts/chart-with-bad-subcharts/charts/good-subchart [INFO] Chart.yaml: icon is recommended -[WARNING] templates/: directory not found Error: 3 chart(s) linted, 2 chart(s) failed diff --git a/cmd/helm/testdata/output/lint-chart-with-bad-subcharts.txt b/cmd/helm/testdata/output/lint-chart-with-bad-subcharts.txt index 265e555f7..7c898b89f 100644 --- a/cmd/helm/testdata/output/lint-chart-with-bad-subcharts.txt +++ b/cmd/helm/testdata/output/lint-chart-with-bad-subcharts.txt @@ -1,6 +1,6 @@ ==> Linting testdata/testcharts/chart-with-bad-subcharts [INFO] Chart.yaml: icon is recommended -[WARNING] templates/: directory not found +[ERROR] templates/: error unpacking bad-subchart in chart-with-bad-subcharts: validation: chart.metadata.name is required [ERROR] : unable to load chart error unpacking bad-subchart in chart-with-bad-subcharts: validation: chart.metadata.name is required diff --git a/cmd/helm/testdata/output/lint-quiet-with-error.txt b/cmd/helm/testdata/output/lint-quiet-with-error.txt index a4e8575f8..e3d29a5a3 100644 --- a/cmd/helm/testdata/output/lint-quiet-with-error.txt +++ b/cmd/helm/testdata/output/lint-quiet-with-error.txt @@ -1,7 +1,7 @@ ==> Linting testdata/testcharts/chart-bad-requirements [ERROR] Chart.yaml: unable to parse YAML error converting YAML to JSON: yaml: line 6: did not find expected '-' indicator -[WARNING] templates/: directory not found +[ERROR] templates/: cannot load Chart.yaml: error converting YAML to JSON: yaml: line 6: did not find expected '-' indicator [ERROR] : unable to load chart cannot load Chart.yaml: error converting YAML to JSON: yaml: line 6: did not find expected '-' indicator diff --git a/cmd/helm/testdata/output/lint-quiet-with-warning.txt b/cmd/helm/testdata/output/lint-quiet-with-warning.txt index 02c6fa592..e69de29bb 100644 --- a/cmd/helm/testdata/output/lint-quiet-with-warning.txt +++ b/cmd/helm/testdata/output/lint-quiet-with-warning.txt @@ -1,4 +0,0 @@ -==> Linting testdata/testcharts/chart-with-only-crds -[WARNING] templates/: directory not found - -1 chart(s) linted, 0 chart(s) failed diff --git a/cmd/helm/testdata/output/rollback-non-existent-version.txt b/cmd/helm/testdata/output/rollback-non-existent-version.txt new file mode 100644 index 000000000..9c2e10e17 --- /dev/null +++ b/cmd/helm/testdata/output/rollback-non-existent-version.txt @@ -0,0 +1 @@ +Error: release has no 3 version diff --git a/cmd/helm/uninstall.go b/cmd/helm/uninstall.go index 1a47e972c..9ced8fef0 100644 --- a/cmd/helm/uninstall.go +++ b/cmd/helm/uninstall.go @@ -74,6 +74,7 @@ func newUninstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f := cmd.Flags() f.BoolVar(&client.DryRun, "dry-run", false, "simulate a uninstall") f.BoolVar(&client.DisableHooks, "no-hooks", false, "prevent hooks from running during uninstallation") + f.BoolVar(&client.IgnoreNotFound, "ignore-not-found", false, `Treat "release not found" as a successful uninstall`) f.BoolVar(&client.KeepHistory, "keep-history", false, "remove all associated resources and mark the release as deleted, but retain the release history") f.BoolVar(&client.Wait, "wait", false, "if set, will wait until all the resources are deleted before returning. It will wait for as long as --timeout") f.StringVar(&client.DeletionPropagation, "cascade", "background", "Must be \"background\", \"orphan\", or \"foreground\". Selects the deletion cascading strategy for the dependents. Defaults to background.") diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index 7e6082782..328497d7e 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -65,6 +65,13 @@ last (right-most) set specified. For example, if both 'bar' and 'newbar' values set for a key called 'foo', the 'newbar' value would take precedence: $ helm upgrade --set foo=bar --set foo=newbar redis ./redis + +You can update the values for an existing release with this command as well via the +'--reuse-values' flag. The 'RELEASE' and 'CHART' arguments should be set to the original +parameters, and existing values will be merged with any values set via '--values'/'-f' +or '--set' flags. Priority is given to new values. + + $ helm upgrade --reuse-values --set foo=bar --set foo=newbar redis ./redis ` func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { @@ -90,7 +97,8 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { client.Namespace = settings.Namespace() - registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, client.InsecureSkipTLSverify) + registryClient, err := newRegistryClient(client.CertFile, client.KeyFile, client.CaFile, + client.InsecureSkipTLSverify, client.PlainHTTP) if err != nil { return fmt.Errorf("missing registry client: %w", err) } @@ -132,13 +140,14 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { instClient.SubNotes = client.SubNotes instClient.Description = client.Description instClient.DependencyUpdate = client.DependencyUpdate + instClient.Labels = client.Labels instClient.EnableDNS = client.EnableDNS rel, err := runInstall(args, instClient, valueOpts, out) if err != nil { return err } - return outfmt.Write(out, &statusPrinter{rel, settings.Debug, false, false}) + return outfmt.Write(out, &statusPrinter{rel, settings.Debug, false, false, false}) } else if err != nil { return err } @@ -224,7 +233,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { fmt.Fprintf(out, "Release %q has been upgraded. Happy Helming!\n", args[0]) } - return outfmt.Write(out, &statusPrinter{rel, settings.Debug, false, false}) + return outfmt.Write(out, &statusPrinter{rel, settings.Debug, false, false, false}) }, } @@ -249,6 +258,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.IntVar(&client.MaxHistory, "history-max", settings.MaxHistory, "limit the maximum number of revisions saved per release. Use 0 for no limit") f.BoolVar(&client.CleanupOnFail, "cleanup-on-fail", false, "allow deletion of new resources created in this upgrade when upgrade fails") f.BoolVar(&client.SubNotes, "render-subchart-notes", false, "if set, render subchart notes along with the parent") + f.StringToStringVarP(&client.Labels, "labels", "l", nil, "Labels that would be added to release metadata. Should be separated by comma. Original release labels will be merged with upgrade labels. You can unset label using null.") f.StringVar(&client.Description, "description", "", "add a custom description") f.BoolVar(&client.DependencyUpdate, "dependency-update", false, "update dependencies if they are missing before installing the chart") f.BoolVar(&client.EnableDNS, "enable-dns", false, "enable DNS lookups when rendering templates") diff --git a/cmd/helm/upgrade_test.go b/cmd/helm/upgrade_test.go index e366f8d19..485267d1d 100644 --- a/cmd/helm/upgrade_test.go +++ b/cmd/helm/upgrade_test.go @@ -20,10 +20,10 @@ import ( "fmt" "os" "path/filepath" + "reflect" "strings" "testing" - "helm.sh/helm/v3/internal/test/ensure" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/chartutil" @@ -32,7 +32,7 @@ import ( func TestUpgradeCmd(t *testing.T) { - tmpChart := ensure.TempDir(t) + tmpChart := t.TempDir() cfile := &chart.Chart{ Metadata: &chart.Metadata{ APIVersion: chart.APIVersionV1, @@ -357,7 +357,7 @@ func TestUpgradeInstallWithValuesFromStdin(t *testing.T) { } func prepareMockRelease(releaseName string, t *testing.T) (func(n string, v int, ch *chart.Chart) *release.Release, *chart.Chart, string) { - tmpChart := ensure.TempDir(t) + tmpChart := t.TempDir() configmapData, err := os.ReadFile("testdata/testcharts/upgradetest/templates/configmap.yaml") if err != nil { t.Fatalf("Error loading template yaml %v", err) @@ -430,3 +430,31 @@ func TestUpgradeFileCompletion(t *testing.T) { checkFileCompletion(t, "upgrade myrelease", true) checkFileCompletion(t, "upgrade myrelease repo/chart", false) } + +func TestUpgradeInstallWithLabels(t *testing.T) { + releaseName := "funny-bunny-labels" + _, _, chartPath := prepareMockRelease(releaseName, t) + + defer resetEnv()() + + store := storageFixture() + + expectedLabels := map[string]string{ + "key1": "val1", + "key2": "val2", + } + cmd := fmt.Sprintf("upgrade %s --install --labels key1=val1,key2=val2 '%s'", releaseName, chartPath) + _, _, err := executeActionCommandC(store, cmd) + if err != nil { + t.Errorf("unexpected error, got '%v'", err) + } + + updatedRel, err := store.Get(releaseName, 1) + if err != nil { + t.Errorf("unexpected error, got '%v'", err) + } + + if !reflect.DeepEqual(updatedRel.Labels, expectedLabels) { + t.Errorf("Expected {%v}, got {%v}", expectedLabels, updatedRel.Labels) + } +} diff --git a/go.mod b/go.mod index ff7657174..21aa8a1e6 100644 --- a/go.mod +++ b/go.mod @@ -3,15 +3,15 @@ module helm.sh/helm/v3 go 1.19 require ( - github.com/BurntSushi/toml v1.2.1 + github.com/BurntSushi/toml v1.3.2 github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/Masterminds/semver/v3 v3.2.1 github.com/Masterminds/sprig/v3 v3.2.3 github.com/Masterminds/squirrel v1.5.4 github.com/Masterminds/vcs v1.13.3 github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 - github.com/containerd/containerd v1.7.0 - github.com/cyphar/filepath-securejoin v0.2.3 + github.com/containerd/containerd v1.7.3 + github.com/cyphar/filepath-securejoin v0.2.4 github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 github.com/evanphx/json-patch v5.6.0+incompatible github.com/foxcpp/go-mockdns v1.0.0 @@ -23,27 +23,27 @@ require ( github.com/lib/pq v1.10.9 github.com/mattn/go-shellwords v1.0.12 github.com/mitchellh/copystructure v1.2.0 - github.com/moby/term v0.0.0-20221205130635-1aeaba878587 - github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b + github.com/moby/term v0.5.0 + github.com/opencontainers/image-spec v1.1.0-rc4 github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 github.com/pkg/errors v0.9.1 - github.com/rubenv/sql-migrate v1.5.1 + github.com/rubenv/sql-migrate v1.5.2 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.7.0 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.8.4 github.com/xeipuuv/gojsonschema v1.2.0 golang.org/x/crypto v0.11.0 - golang.org/x/term v0.10.0 + golang.org/x/term v0.11.0 golang.org/x/text v0.11.0 - k8s.io/api v0.27.3 - k8s.io/apiextensions-apiserver v0.27.3 - k8s.io/apimachinery v0.27.3 - k8s.io/apiserver v0.27.3 - k8s.io/cli-runtime v0.27.3 - k8s.io/client-go v0.27.3 + k8s.io/api v0.28.2 + k8s.io/apiextensions-apiserver v0.28.2 + k8s.io/apimachinery v0.28.2 + k8s.io/apiserver v0.28.2 + k8s.io/cli-runtime v0.28.2 + k8s.io/client-go v0.28.2 k8s.io/klog/v2 v2.100.1 - k8s.io/kubectl v0.27.3 + k8s.io/kubectl v0.28.2 oras.land/oras-go v1.2.3 sigs.k8s.io/yaml v1.3.0 ) @@ -63,7 +63,7 @@ require ( github.com/chai2010/gettext-go v1.0.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/docker/cli v23.0.1+incompatible // indirect + github.com/docker/cli v23.0.3+incompatible // indirect github.com/docker/distribution v2.8.2+incompatible // indirect github.com/docker/docker v23.0.3+incompatible // indirect github.com/docker/docker-credential-helpers v0.7.0 // indirect @@ -76,19 +76,19 @@ require ( github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect github.com/fatih/color v1.13.0 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect - github.com/fvbommel/sortorder v1.0.1 // indirect + github.com/fvbommel/sortorder v1.1.0 // indirect github.com/go-errors/errors v1.4.2 // indirect github.com/go-gorp/gorp/v3 v3.1.0 // indirect - github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect - github.com/go-openapi/jsonreference v0.20.1 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/gomodule/redigo v1.8.2 // indirect github.com/google/btree v1.0.1 // indirect - github.com/google/gnostic v0.5.7-v3refs // indirect + github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect @@ -113,7 +113,7 @@ require ( github.com/mattn/go-runewidth v0.0.9 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/miekg/dns v1.1.25 // indirect - github.com/mitchellh/go-wordwrap v1.0.0 // indirect + github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/locker v1.0.1 // indirect github.com/moby/spdystream v0.2.0 // indirect @@ -125,39 +125,39 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect + github.com/prometheus/client_golang v1.16.0 // indirect + github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/common v0.44.0 // indirect + github.com/prometheus/procfs v0.10.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xlab/treeprint v1.1.0 // indirect + github.com/xlab/treeprint v1.2.0 // indirect github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 // indirect github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 // indirect github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f // indirect go.opentelemetry.io/otel v1.14.0 // indirect go.opentelemetry.io/otel/trace v1.14.0 // indirect - go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect - golang.org/x/net v0.10.0 // indirect - golang.org/x/oauth2 v0.4.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.10.0 // indirect - golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect + go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect + golang.org/x/net v0.13.0 // indirect + golang.org/x/oauth2 v0.8.0 // indirect + golang.org/x/sync v0.2.0 // indirect + golang.org/x/sys v0.11.0 // indirect + golang.org/x/time v0.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect - google.golang.org/grpc v1.53.0 // indirect - google.golang.org/protobuf v1.28.1 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect + google.golang.org/grpc v1.54.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/component-base v0.27.3 // indirect - k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect - k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 // indirect + k8s.io/component-base v0.28.2 // indirect + k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect + k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/kustomize/api v0.13.2 // indirect - sigs.k8s.io/kustomize/kyaml v0.14.1 // indirect + sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect + sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect ) diff --git a/go.sum b/go.sum index 02d9b7dbb..c6c9e5586 100644 --- a/go.sum +++ b/go.sum @@ -1,44 +1,11 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 h1:EKPd1INOIyr5hWOWhvpmQpY6tKjeG0hT1s3AMC/9fic= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1/go.mod h1:VzwV+t+dZ9j/H867F1M2ziD+yLHtB46oM35FxxMJ4d0= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= -github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= @@ -54,15 +21,12 @@ github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8 github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/Masterminds/vcs v1.13.3 h1:IIA2aBdXvfbIM+yl/eTnL4hb1XwdpvuQLglAix1gweE= github.com/Masterminds/vcs v1.13.3/go.mod h1:TiE7xuEjl1N4j016moRd6vezp6e6Lz23gypeXfzXeW8= -github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= -github.com/Microsoft/hcsshim v0.10.0-rc.7 h1:HBytQPxcv8Oy4244zbQbe6hnOnx544eL5QPUqhJldz8= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/hcsshim v0.10.0-rc.8 h1:YSZVvlIIDD1UxQpJp0h+dnpLUw+TrY0cx8obKsp3bek= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= @@ -80,8 +44,6 @@ github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0Bsq github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= @@ -90,24 +52,23 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= -github.com/containerd/containerd v1.7.0 h1:G/ZQr3gMZs6ZT0qPUZ15znx5QSdQdASW11nXTLTM2Pg= -github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc= -github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= +github.com/containerd/containerd v1.7.3 h1:cKwYKkP1eTj54bP3wCdXXBymmKRQMrWjkLSWZZJDa8o= +github.com/containerd/containerd v1.7.3/go.mod h1:32FOM4/O0RkNg7AjQj3hDzN9cUGtu+HMvaKUNiqCZB8= +github.com/containerd/continuity v0.4.1 h1:wQnVrjIyQ8vhU2sgOiL5T07jo+ouqc2bnKsv5/EqGhU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= -github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI= -github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= +github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc= github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2/go.mod h1:WHNsWjnIn2V1LYOrME7e8KxSeKunYHsxEm4am0BUtcI= -github.com/docker/cli v23.0.1+incompatible h1:LRyWITpGzl2C9e9uGxzisptnxAn1zfZKXy13Ul2Q5oM= -github.com/docker/cli v23.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v23.0.3+incompatible h1:Zcse1DuDqBdgI7OQDV8Go7b83xLgfhW1eza4HfEdxpY= +github.com/docker/cli v23.0.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v23.0.3+incompatible h1:9GhVsShNWz1hO//9BNg/dpMnZW25KydO4wtVxWAIbho= @@ -124,12 +85,9 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= -github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ= github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -143,39 +101,31 @@ github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI= github.com/foxcpp/go-mockdns v1.0.0/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/fvbommel/sortorder v1.0.1 h1:dSnXLt4mJYH25uDDGa3biZNQsozaUWDSWeKJ0qqFfzE= -github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= +github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw= +github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= -github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU= github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0= github.com/gobuffalo/packr/v2 v2.8.3 h1:xE1yzvnO56cUC0sTpKR3DIbxZgB54AftTFMhB2XEWlY= @@ -187,75 +137,44 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k= github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= -github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= @@ -270,14 +189,11 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= @@ -287,27 +203,18 @@ github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -350,8 +257,8 @@ github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKju github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f h1:2+myh5ml7lgEU/51gbeLHfKGNfgEQQIWrlbdaOsidbQ= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= @@ -361,8 +268,8 @@ github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQ github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= -github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= -github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -377,19 +284,17 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk= -github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= +github.com/onsi/ginkgo/v2 v2.9.4 h1:xR7vG4IXt5RWx6FfIjyAtsoMAtnc3C/rFXBBd2AjZwE= +github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b h1:YWuSjZCQAPM8UUBLkYUk1e+rZcvWHJmFb6i6rM44Xs8= -github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= +github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0= +github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -398,36 +303,25 @@ github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= +github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= +github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rubenv/sql-migrate v1.5.1 h1:WsZo4jPQfjmddDTh/suANP2aKPA7/ekN0LzuuajgQEo= -github.com/rubenv/sql-migrate v1.5.1/go.mod h1:H38GW8Vqf8F0Su5XignRyaRcbXbJunSWxs+kmzlg0Is= +github.com/rubenv/sql-migrate v1.5.2 h1:bMDqOnrJVV/6JQgQ/MxOpU+AdO8uzYYA/TxFUBzFtS0= +github.com/rubenv/sql-migrate v1.5.2/go.mod h1:H38GW8Vqf8F0Su5XignRyaRcbXbJunSWxs+kmzlg0Is= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= @@ -435,8 +329,6 @@ github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFR github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= @@ -446,7 +338,6 @@ github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 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.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -454,7 +345,6 @@ github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 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= @@ -469,11 +359,9 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -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.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= +github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI= @@ -482,22 +370,15 @@ github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMzt github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= -go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc= -go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= +go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= +go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -506,366 +387,169 @@ golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4 golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.13.0 h1:Nvo8UFsZ8X3BhAC9699Z1j7XQ3rsZnUUm7jfBEk1ueY= +golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M= -golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= -golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= +golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= -google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag= +google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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/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= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.27.3 h1:yR6oQXXnUEBWEWcvPWS0jQL575KoAboQPfJAuKNrw5Y= -k8s.io/api v0.27.3/go.mod h1:C4BNvZnQOF7JA/0Xed2S+aUyJSfTGkGFxLXz9MnpIpg= -k8s.io/apiextensions-apiserver v0.27.3 h1:xAwC1iYabi+TDfpRhxh4Eapl14Hs2OftM2DN5MpgKX4= -k8s.io/apiextensions-apiserver v0.27.3/go.mod h1:BH3wJ5NsB9XE1w+R6SSVpKmYNyIiyIz9xAmBl8Mb+84= -k8s.io/apimachinery v0.27.3 h1:Ubye8oBufD04l9QnNtW05idcOe9Z3GQN8+7PqmuVcUM= -k8s.io/apimachinery v0.27.3/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= -k8s.io/apiserver v0.27.3 h1:AxLvq9JYtveYWK+D/Dz/uoPCfz8JC9asR5z7+I/bbQ4= -k8s.io/apiserver v0.27.3/go.mod h1:Y61+EaBMVWUBJtxD5//cZ48cHZbQD+yIyV/4iEBhhNA= -k8s.io/cli-runtime v0.27.3 h1:h592I+2eJfXj/4jVYM+tu9Rv8FEc/dyCoD80UJlMW2Y= -k8s.io/cli-runtime v0.27.3/go.mod h1:LzXud3vFFuDFXn2LIrWnscPgUiEj7gQQcYZE2UPn9Kw= -k8s.io/client-go v0.27.3 h1:7dnEGHZEJld3lYwxvLl7WoehK6lAq7GvgjxpA3nv1E8= -k8s.io/client-go v0.27.3/go.mod h1:2MBEKuTo6V1lbKy3z1euEGnhPfGZLKTS9tiJ2xodM48= -k8s.io/component-base v0.27.3 h1:g078YmdcdTfrCE4fFobt7qmVXwS8J/3cI1XxRi/2+6k= -k8s.io/component-base v0.27.3/go.mod h1:JNiKYcGImpQ44iwSYs6dysxzR9SxIIgQalk4HaCNVUY= +k8s.io/api v0.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw= +k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg= +k8s.io/apiextensions-apiserver v0.28.2 h1:J6/QRWIKV2/HwBhHRVITMLYoypCoPY1ftigDM0Kn+QU= +k8s.io/apiextensions-apiserver v0.28.2/go.mod h1:5tnkxLGa9nefefYzWuAlWZ7RZYuN/765Au8cWLA6SRg= +k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ= +k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU= +k8s.io/apiserver v0.28.2 h1:rBeYkLvF94Nku9XfXyUIirsVzCzJBs6jMn3NWeHieyI= +k8s.io/apiserver v0.28.2/go.mod h1:f7D5e8wH8MWcKD7azq6Csw9UN+CjdtXIVQUyUhrtb+E= +k8s.io/cli-runtime v0.28.2 h1:64meB2fDj10/ThIMEJLO29a1oujSm0GQmKzh1RtA/uk= +k8s.io/cli-runtime v0.28.2/go.mod h1:bTpGOvpdsPtDKoyfG4EG041WIyFZLV9qq4rPlkyYfDA= +k8s.io/client-go v0.28.2 h1:DNoYI1vGq0slMBN/SWKMZMw0Rq+0EQW6/AK4v9+3VeY= +k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY= +k8s.io/component-base v0.28.2 h1:Yc1yU+6AQSlpJZyvehm/NkJBII72rzlEsd6MkBQ+G0E= +k8s.io/component-base v0.28.2/go.mod h1:4IuQPQviQCg3du4si8GpMrhAIegxpsgPngPRR/zWpzc= k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg= -k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg= -k8s.io/kubectl v0.27.3 h1:HyC4o+8rCYheGDWrkcOQHGwDmyLKR5bxXFgpvF82BOw= -k8s.io/kubectl v0.27.3/go.mod h1:g9OQNCC2zxT+LT3FS09ZYqnDhlvsKAfFq76oyarBcq4= -k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 h1:kmDqav+P+/5e1i9tFfHq1qcF3sOrDp+YEkVDAHu7Jwk= -k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= +k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= +k8s.io/kubectl v0.28.2 h1:fOWOtU6S0smdNjG1PB9WFbqEIMlkzU5ahyHkc7ESHgM= +k8s.io/kubectl v0.28.2/go.mod h1:6EQWTPySF1fn7yKoQZHYf9TPwIl2AygHEcJoxFekr64= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= oras.land/oras-go v1.2.3 h1:v8PJl+gEAntI1pJ/LCrDgsuk+1PKVavVEPsYIHFE5uY= oras.land/oras-go v1.2.3/go.mod h1:M/uaPdYklze0Vf3AakfarnpoEckvw0ESbRdN8Z1vdJg= -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/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/kustomize/api v0.13.2 h1:kejWfLeJhUsTGioDoFNJET5LQe/ajzXhJGYoU+pJsiA= -sigs.k8s.io/kustomize/api v0.13.2/go.mod h1:DUp325VVMFVcQSq+ZxyDisA8wtldwHxLZbr1g94UHsw= -sigs.k8s.io/kustomize/kyaml v0.14.1 h1:c8iibius7l24G2wVAGZn/Va2wNys03GXLjYVIcFVxKA= -sigs.k8s.io/kustomize/kyaml v0.14.1/go.mod h1:AN1/IpawKilWD7V+YvQwRGUvuUOOWpjsHu6uHwonSF4= +sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0= +sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY= +sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U= +sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= diff --git a/internal/test/ensure/ensure.go b/internal/test/ensure/ensure.go index 49c3cf1ef..ff2d180fe 100644 --- a/internal/test/ensure/ensure.go +++ b/internal/test/ensure/ensure.go @@ -26,41 +26,27 @@ import ( ) // HelmHome sets up a Helm Home in a temp dir. -func HelmHome(t *testing.T) func() { +func HelmHome(t *testing.T) { t.Helper() - base := TempDir(t) + base := t.TempDir() os.Setenv(xdg.CacheHomeEnvVar, base) os.Setenv(xdg.ConfigHomeEnvVar, base) os.Setenv(xdg.DataHomeEnvVar, base) os.Setenv(helmpath.CacheHomeEnvVar, "") os.Setenv(helmpath.ConfigHomeEnvVar, "") os.Setenv(helmpath.DataHomeEnvVar, "") - return func() { - os.RemoveAll(base) - } -} - -// TempDir ensures a scratch test directory for unit testing purposes. -func TempDir(t *testing.T) string { - t.Helper() - d, err := os.MkdirTemp("", "helm") - if err != nil { - t.Fatal(err) - } - return d } // TempFile ensures a temp file for unit testing purposes. // // It returns the path to the directory (to which you will still need to join the filename) // -// You must clean up the directory that is returned. +// The returned directory is automatically removed when the test and all its subtests complete. // // tempdir := TempFile(t, "foo", []byte("bar")) -// defer os.RemoveAll(tempdir) // filename := filepath.Join(tempdir, "foo") func TempFile(t *testing.T, name string, data []byte) string { - path := TempDir(t) + path := t.TempDir() filename := filepath.Join(path, name) if err := os.WriteFile(filename, data, 0755); err != nil { t.Fatal(err) diff --git a/pkg/action/get_metadata.go b/pkg/action/get_metadata.go new file mode 100644 index 000000000..ec096ae16 --- /dev/null +++ b/pkg/action/get_metadata.go @@ -0,0 +1,69 @@ +/* +Copyright The Helm Authors. + +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. +*/ + +package action + +import "time" + +// GetMetadata is the action for checking a given release's metadata. +// +// It provides the implementation of 'helm get metadata'. +type GetMetadata struct { + cfg *Configuration + + Version int +} + +type Metadata struct { + Name string `json:"name" yaml:"name"` + Chart string `json:"chart" yaml:"chart"` + Version string `json:"version" yaml:"version"` + AppVersion string `json:"appVersion" yaml:"appVersion"` + Namespace string `json:"namespace" yaml:"namespace"` + Revision int `json:"revision" yaml:"revision"` + Status string `json:"status" yaml:"status"` + DeployedAt string `json:"deployedAt" yaml:"deployedAt"` +} + +// NewGetMetadata creates a new GetMetadata object with the given configuration. +func NewGetMetadata(cfg *Configuration) *GetMetadata { + return &GetMetadata{ + cfg: cfg, + } +} + +// Run executes 'helm get metadata' against the given release. +func (g *GetMetadata) Run(name string) (*Metadata, error) { + if err := g.cfg.KubeClient.IsReachable(); err != nil { + return nil, err + } + + rel, err := g.cfg.releaseContent(name, g.Version) + if err != nil { + return nil, err + } + + return &Metadata{ + Name: rel.Name, + Chart: rel.Chart.Metadata.Name, + Version: rel.Chart.Metadata.Version, + AppVersion: rel.Chart.Metadata.AppVersion, + Namespace: rel.Namespace, + Revision: rel.Version, + Status: rel.Info.Status.String(), + DeployedAt: rel.Info.LastDeployed.Format(time.RFC3339), + }, nil +} diff --git a/pkg/action/install.go b/pkg/action/install.go index 7af161464..a5026266d 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -92,6 +92,7 @@ type Install struct { SubNotes bool DisableOpenAPIValidation bool IncludeCRDs bool + Labels map[string]string // KubeVersion allows specifying a custom kubernetes version to use and // APIVersions allows a manual set of supported API Versions to be passed // (for things like templating). These are ignored if ClientOnly is false @@ -115,6 +116,7 @@ type ChartPathOptions struct { CertFile string // --cert-file KeyFile string // --key-file InsecureSkipTLSverify bool // --insecure-skip-verify + PlainHTTP bool // --plain-http Keyring string // --keyring Password string // --password PassCredentialsAll bool // --pass-credentials @@ -289,7 +291,11 @@ func (i *Install) RunWithContext(ctx context.Context, chrt *chart.Chart, vals ma return nil, err } - rel := i.createRelease(chrt, vals) + if driver.ContainsSystemLabels(i.Labels) { + return nil, fmt.Errorf("user suplied labels contains system reserved label name. System labels: %+v", driver.GetSystemLabels()) + } + + rel := i.createRelease(chrt, vals, i.Labels) var manifestDoc *bytes.Buffer rel.Hooks, manifestDoc, rel.Info.Notes, err = i.cfg.renderResources(chrt, valuesToRender, i.ReleaseName, i.OutputDir, i.SubNotes, i.UseReleaseName, i.IncludeCRDs, i.PostRenderer, interactWithRemote, i.EnableDNS) @@ -533,7 +539,7 @@ func (i *Install) availableName() error { } // createRelease creates a new release object -func (i *Install) createRelease(chrt *chart.Chart, rawVals map[string]interface{}) *release.Release { +func (i *Install) createRelease(chrt *chart.Chart, rawVals map[string]interface{}, labels map[string]string) *release.Release { ts := i.cfg.Now() return &release.Release{ Name: i.ReleaseName, @@ -546,6 +552,7 @@ func (i *Install) createRelease(chrt *chart.Chart, rawVals map[string]interface{ Status: release.StatusUnknown, }, Version: 1, + Labels: labels, } } @@ -753,6 +760,7 @@ func (c *ChartPathOptions) LocateChart(name string, settings *cli.EnvSettings) ( getter.WithPassCredentialsAll(c.PassCredentialsAll), getter.WithTLSClientConfig(c.CertFile, c.KeyFile, c.CaFile), getter.WithInsecureSkipVerifyTLS(c.InsecureSkipTLSverify), + getter.WithPlainHTTP(c.PlainHTTP), }, RepositoryConfig: settings.RepositoryConfig, RepositoryCache: settings.RepositoryCache, diff --git a/pkg/action/install_test.go b/pkg/action/install_test.go index 5e3ae79c9..d49365b05 100644 --- a/pkg/action/install_test.go +++ b/pkg/action/install_test.go @@ -717,3 +717,33 @@ func TestNameAndChartGenerateName(t *testing.T) { }) } } + +func TestInstallWithLabels(t *testing.T) { + is := assert.New(t) + instAction := installAction(t) + instAction.Labels = map[string]string{ + "key1": "val1", + "key2": "val2", + } + res, err := instAction.Run(buildChart(), nil) + if err != nil { + t.Fatalf("Failed install: %s", err) + } + + is.Equal(instAction.Labels, res.Labels) +} + +func TestInstallWithSystemLabels(t *testing.T) { + is := assert.New(t) + instAction := installAction(t) + instAction.Labels = map[string]string{ + "owner": "val1", + "key2": "val2", + } + _, err := instAction.Run(buildChart(), nil) + if err == nil { + t.Fatal("expected an error") + } + + is.Equal(fmt.Errorf("user suplied labels contains system reserved label name. System labels: %+v", driver.GetSystemLabels()), err) +} diff --git a/pkg/action/lint_test.go b/pkg/action/lint_test.go index 1828461f3..ff69407ca 100644 --- a/pkg/action/lint_test.go +++ b/pkg/action/lint_test.go @@ -149,12 +149,12 @@ func TestLint_ChartWithWarnings(t *testing.T) { } }) - t.Run("should fail with errors when strict", func(t *testing.T) { + t.Run("should pass with no errors when strict", func(t *testing.T) { testCharts := []string{chartWithNoTemplatesDir} testLint := NewLint() testLint.Strict = true - if result := testLint.Run(testCharts, values); len(result.Errors) != 1 { - t.Error("expected one error, but got", len(result.Errors)) + if result := testLint.Run(testCharts, values); len(result.Errors) != 0 { + t.Error("expected no errors, but got", len(result.Errors)) } }) } diff --git a/pkg/action/package_test.go b/pkg/action/package_test.go index 0b62e7f8c..d04efdaa6 100644 --- a/pkg/action/package_test.go +++ b/pkg/action/package_test.go @@ -29,7 +29,6 @@ import ( func TestPassphraseFileFetcher(t *testing.T) { secret := "secret" directory := ensure.TempFile(t, "passphrase-file", []byte(secret)) - defer os.RemoveAll(directory) fetcher, err := passphraseFileFetcher(path.Join(directory, "passphrase-file"), nil) if err != nil { @@ -49,7 +48,6 @@ func TestPassphraseFileFetcher(t *testing.T) { func TestPassphraseFileFetcher_WithLineBreak(t *testing.T) { secret := "secret" directory := ensure.TempFile(t, "passphrase-file", []byte(secret+"\n\n.")) - defer os.RemoveAll(directory) fetcher, err := passphraseFileFetcher(path.Join(directory, "passphrase-file"), nil) if err != nil { @@ -67,8 +65,7 @@ func TestPassphraseFileFetcher_WithLineBreak(t *testing.T) { } func TestPassphraseFileFetcher_WithInvalidStdin(t *testing.T) { - directory := ensure.TempDir(t) - defer os.RemoveAll(directory) + directory := t.TempDir() stdin, err := os.CreateTemp(directory, "non-existing") if err != nil { diff --git a/pkg/action/pull.go b/pkg/action/pull.go index 37ff144de..787553125 100644 --- a/pkg/action/pull.go +++ b/pkg/action/pull.go @@ -90,6 +90,7 @@ func (p *Pull) Run(chartRef string) (string, error) { getter.WithPassCredentialsAll(p.PassCredentialsAll), getter.WithTLSClientConfig(p.CertFile, p.KeyFile, p.CaFile), getter.WithInsecureSkipVerifyTLS(p.InsecureSkipTLSverify), + getter.WithPlainHTTP(p.PlainHTTP), }, RegistryClient: p.cfg.RegistryClient, RepositoryConfig: p.Settings.RepositoryConfig, diff --git a/pkg/action/push.go b/pkg/action/push.go index 892006406..68d2ba42d 100644 --- a/pkg/action/push.go +++ b/pkg/action/push.go @@ -36,6 +36,7 @@ type Push struct { keyFile string caFile string insecureSkipTLSverify bool + plainHTTP bool out io.Writer } @@ -65,6 +66,13 @@ func WithInsecureSkipTLSVerify(insecureSkipTLSVerify bool) PushOpt { } } +// WithPlainHTTP configures the use of plain HTTP connections. +func WithPlainHTTP(plainHTTP bool) PushOpt { + return func(p *Push) { + p.plainHTTP = plainHTTP + } +} + // WithOptWriter sets the registryOut field on the push configuration object. func WithPushOptWriter(out io.Writer) PushOpt { return func(p *Push) { @@ -91,6 +99,7 @@ func (p *Push) Run(chartRef string, remote string) (string, error) { Options: []pusher.Option{ pusher.WithTLSClientConfig(p.certFile, p.keyFile, p.caFile), pusher.WithInsecureSkipTLSVerify(p.insecureSkipTLSverify), + pusher.WithPlainHTTP(p.plainHTTP), }, } diff --git a/pkg/action/release_testing.go b/pkg/action/release_testing.go index ecaeaf59f..3c10cecf8 100644 --- a/pkg/action/release_testing.go +++ b/pkg/action/release_testing.go @@ -20,6 +20,7 @@ import ( "context" "fmt" "io" + "sort" "time" "github.com/pkg/errors" @@ -29,6 +30,11 @@ import ( "helm.sh/helm/v3/pkg/release" ) +const ( + ExcludeNameFilter = "!name" + IncludeNameFilter = "name" +) + // ReleaseTesting is the action for testing a release. // // It provides the implementation of 'helm test'. @@ -66,9 +72,9 @@ func (r *ReleaseTesting) Run(name string) (*release.Release, error) { skippedHooks := []*release.Hook{} executingHooks := []*release.Hook{} - if len(r.Filters["!name"]) != 0 { + if len(r.Filters[ExcludeNameFilter]) != 0 { for _, h := range rel.Hooks { - if contains(r.Filters["!name"], h.Name) { + if contains(r.Filters[ExcludeNameFilter], h.Name) { skippedHooks = append(skippedHooks, h) } else { executingHooks = append(executingHooks, h) @@ -76,10 +82,10 @@ func (r *ReleaseTesting) Run(name string) (*release.Release, error) { } rel.Hooks = executingHooks } - if len(r.Filters["name"]) != 0 { + if len(r.Filters[IncludeNameFilter]) != 0 { executingHooks = nil for _, h := range rel.Hooks { - if contains(r.Filters["name"], h.Name) { + if contains(r.Filters[IncludeNameFilter], h.Name) { executingHooks = append(executingHooks, h) } else { skippedHooks = append(skippedHooks, h) @@ -107,9 +113,17 @@ func (r *ReleaseTesting) GetPodLogs(out io.Writer, rel *release.Release) error { return errors.Wrap(err, "unable to get kubernetes client to fetch pod logs") } - for _, h := range rel.Hooks { + hooksByWight := append([]*release.Hook{}, rel.Hooks...) + sort.Stable(hookByWeight(hooksByWight)) + for _, h := range hooksByWight { for _, e := range h.Events { if e == release.HookTest { + if contains(r.Filters[ExcludeNameFilter], h.Name) { + continue + } + if len(r.Filters[IncludeNameFilter]) > 0 && !contains(r.Filters[IncludeNameFilter], h.Name) { + continue + } req := client.CoreV1().Pods(r.Namespace).GetLogs(h.Name, &v1.PodLogOptions{}) logReader, err := req.Stream(context.Background()) if err != nil { diff --git a/pkg/action/rollback.go b/pkg/action/rollback.go index dda8c700b..f4ae896e3 100644 --- a/pkg/action/rollback.go +++ b/pkg/action/rollback.go @@ -110,6 +110,24 @@ func (r *Rollback) prepareRollback(name string) (*release.Release, *release.Rele previousVersion = currentRelease.Version - 1 } + historyReleases, err := r.cfg.Releases.History(name) + if err != nil { + return nil, nil, err + } + + // Check if the history version to be rolled back exists + previousVersionExist := false + for _, historyRelease := range historyReleases { + version := historyRelease.Version + if previousVersion == version { + previousVersionExist = true + break + } + } + if !previousVersionExist { + return nil, nil, errors.Errorf("release has no %d version", previousVersion) + } + r.cfg.Log("rolling back %s (current: v%d, target: v%d)", name, currentRelease.Version, previousVersion) previousRelease, err := r.cfg.Releases.Get(name, previousVersion) diff --git a/pkg/action/show.go b/pkg/action/show.go index 8cf231593..6ed855b83 100644 --- a/pkg/action/show.go +++ b/pkg/action/show.go @@ -153,6 +153,9 @@ func (s *Show) Run(chartpath string) (string, error) { func findReadme(files []*chart.File) (file *chart.File) { for _, file := range files { for _, n := range readmeFileNames { + if file == nil { + continue + } if strings.EqualFold(file.Name, n) { return file } diff --git a/pkg/action/uninstall.go b/pkg/action/uninstall.go index 801498544..40d82243e 100644 --- a/pkg/action/uninstall.go +++ b/pkg/action/uninstall.go @@ -21,6 +21,7 @@ import ( "time" "github.com/pkg/errors" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "helm.sh/helm/v3/pkg/chartutil" @@ -38,6 +39,7 @@ type Uninstall struct { DisableHooks bool DryRun bool + IgnoreNotFound bool KeepHistory bool Wait bool DeletionPropagation string @@ -73,6 +75,9 @@ func (u *Uninstall) Run(name string) (*release.UninstallReleaseResponse, error) rels, err := u.cfg.Releases.History(name) if err != nil { + if u.IgnoreNotFound { + return nil, nil + } return nil, errors.Wrapf(err, "uninstall: Release not loaded: %s", name) } if len(rels) < 1 { diff --git a/pkg/action/uninstall_test.go b/pkg/action/uninstall_test.go index 311a34923..869ffb8c7 100644 --- a/pkg/action/uninstall_test.go +++ b/pkg/action/uninstall_test.go @@ -32,6 +32,17 @@ func uninstallAction(t *testing.T) *Uninstall { return unAction } +func TestUninstallRelease_ignoreNotFound(t *testing.T) { + unAction := uninstallAction(t) + unAction.DryRun = false + unAction.IgnoreNotFound = true + + is := assert.New(t) + res, err := unAction.Run("release-non-exist") + is.Nil(res) + is.NoError(err) +} + func TestUninstallRelease_deleteRelease(t *testing.T) { is := assert.New(t) diff --git a/pkg/action/upgrade.go b/pkg/action/upgrade.go index ebe3dd2ee..9c837dc60 100644 --- a/pkg/action/upgrade.go +++ b/pkg/action/upgrade.go @@ -94,6 +94,7 @@ type Upgrade struct { SubNotes bool // Description is the description of this operation Description string + Labels map[string]string // PostRender is an optional post-renderer // // If this is non-nil, then after templates are rendered, they will be sent to the @@ -261,6 +262,11 @@ func (u *Upgrade) prepareUpgrade(name string, chart *chart.Chart, vals map[strin return nil, nil, err } + fmt.Println(driver.ContainsSystemLabels(u.Labels)) + if driver.ContainsSystemLabels(u.Labels) { + return nil, nil, fmt.Errorf("user suplied labels contains system reserved label name. System labels: %+v", driver.GetSystemLabels()) + } + // Store an upgraded release. upgradedRelease := &release.Release{ Name: name, @@ -276,6 +282,7 @@ func (u *Upgrade) prepareUpgrade(name string, chart *chart.Chart, vals map[strin Version: revision, Manifest: manifestDoc.String(), Hooks: hooks, + Labels: mergeCustomLabels(lastRelease.Labels, u.Labels), } if len(notesTxt) > 0 { @@ -598,3 +605,13 @@ func objectKey(r *resource.Info) string { gvk := r.Object.GetObjectKind().GroupVersionKind() return fmt.Sprintf("%s/%s/%s/%s", gvk.GroupVersion().String(), gvk.Kind, r.Namespace, r.Name) } + +func mergeCustomLabels(current, desired map[string]string) map[string]string { + labels := mergeStrStrMaps(current, desired) + for k, v := range labels { + if v == "null" { + delete(labels, k) + } + } + return labels +} diff --git a/pkg/action/upgrade_test.go b/pkg/action/upgrade_test.go index 62922b373..77656e1c5 100644 --- a/pkg/action/upgrade_test.go +++ b/pkg/action/upgrade_test.go @@ -19,10 +19,12 @@ package action import ( "context" "fmt" + "reflect" "testing" "time" "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/storage/driver" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -386,5 +388,97 @@ func TestUpgradeRelease_Interrupted_Atomic(t *testing.T) { is.NoError(err) // Should have rolled back to the previous is.Equal(updatedRes.Info.Status, release.StatusDeployed) +} + +func TestMergeCustomLabels(t *testing.T) { + var tests = [][3]map[string]string{ + {nil, nil, map[string]string{}}, + {map[string]string{}, map[string]string{}, map[string]string{}}, + {map[string]string{"k1": "v1", "k2": "v2"}, nil, map[string]string{"k1": "v1", "k2": "v2"}}, + {nil, map[string]string{"k1": "v1", "k2": "v2"}, map[string]string{"k1": "v1", "k2": "v2"}}, + {map[string]string{"k1": "v1", "k2": "v2"}, map[string]string{"k1": "null", "k2": "v3"}, map[string]string{"k2": "v3"}}, + } + for _, test := range tests { + if output := mergeCustomLabels(test[0], test[1]); !reflect.DeepEqual(test[2], output) { + t.Errorf("Expected {%v}, got {%v}", test[2], output) + } + } +} + +func TestUpgradeRelease_Labels(t *testing.T) { + is := assert.New(t) + upAction := upgradeAction(t) + + rel := releaseStub() + rel.Name = "labels" + // It's needed to check that suppressed release would keep original labels + rel.Labels = map[string]string{ + "key1": "val1", + "key2": "val2.1", + } + rel.Info.Status = release.StatusDeployed + + err := upAction.cfg.Releases.Create(rel) + is.NoError(err) + + upAction.Labels = map[string]string{ + "key1": "null", + "key2": "val2.2", + "key3": "val3", + } + // setting newValues and upgrading + res, err := upAction.Run(rel.Name, buildChart(), nil) + is.NoError(err) + + // Now make sure it is actually upgraded and labels were merged + updatedRes, err := upAction.cfg.Releases.Get(res.Name, 2) + is.NoError(err) + + if updatedRes == nil { + is.Fail("Updated Release is nil") + return + } + is.Equal(release.StatusDeployed, updatedRes.Info.Status) + is.Equal(mergeCustomLabels(rel.Labels, upAction.Labels), updatedRes.Labels) + + // Now make sure it is suppressed release still contains original labels + initialRes, err := upAction.cfg.Releases.Get(res.Name, 1) + is.NoError(err) + + if initialRes == nil { + is.Fail("Updated Release is nil") + return + } + is.Equal(initialRes.Info.Status, release.StatusSuperseded) + is.Equal(initialRes.Labels, rel.Labels) +} + +func TestUpgradeRelease_SystemLabels(t *testing.T) { + is := assert.New(t) + upAction := upgradeAction(t) + + rel := releaseStub() + rel.Name = "labels" + // It's needed to check that suppressed release would keep original labels + rel.Labels = map[string]string{ + "key1": "val1", + "key2": "val2.1", + } + rel.Info.Status = release.StatusDeployed + + err := upAction.cfg.Releases.Create(rel) + is.NoError(err) + upAction.Labels = map[string]string{ + "key1": "null", + "key2": "val2.2", + "owner": "val3", + } + // setting newValues and upgrading + _, err = upAction.Run(rel.Name, buildChart(), nil) + if err == nil { + t.Fatal("expected an error") + } + + is.Equal(fmt.Errorf("user suplied labels contains system reserved label name. System labels: %+v", driver.GetSystemLabels()), err) } diff --git a/pkg/chart/loader/archive.go b/pkg/chart/loader/archive.go index 8b38cb89f..196e5f81d 100644 --- a/pkg/chart/loader/archive.go +++ b/pkg/chart/loader/archive.go @@ -85,7 +85,10 @@ func ensureArchive(name string, raw *os.File) error { if err != nil && err != io.EOF { return fmt.Errorf("file '%s' cannot be read: %s", name, err) } - if contentType := http.DetectContentType(buffer); contentType != "application/x-gzip" { + + // Helm may identify achieve of the application/x-gzip as application/vnd.ms-fontobject. + // Fix for: https://github.com/helm/helm/issues/12261 + if contentType := http.DetectContentType(buffer); contentType != "application/x-gzip" && !isGZipApplication(buffer) { // TODO: Is there a way to reliably test if a file content is YAML? ghodss/yaml accepts a wide // variety of content (Makefile, .zshrc) as valid YAML without errors. @@ -98,6 +101,12 @@ func ensureArchive(name string, raw *os.File) error { return nil } +// isGZipApplication checks whether the achieve is of the application/x-gzip type. +func isGZipApplication(data []byte) bool { + sig := []byte("\x1F\x8B\x08") + return bytes.HasPrefix(data, sig) +} + // LoadArchiveFiles reads in files out of an archive into memory. This function // performs important path security checks and should always be used before // expanding a tarball diff --git a/pkg/chartutil/create.go b/pkg/chartutil/create.go index a625fc74a..e43aaf479 100644 --- a/pkg/chartutil/create.go +++ b/pkg/chartutil/create.go @@ -121,6 +121,8 @@ fullnameOverride: "" serviceAccount: # Specifies whether a service account should be created create: true + # Automatically mount a ServiceAccount's API credentials? + automount: true # Annotations to add to the service account annotations: {} # The name of the service account to use. @@ -128,6 +130,7 @@ serviceAccount: name: "" podAnnotations: {} +podLabels: {} podSecurityContext: {} # fsGroup: 2000 @@ -179,6 +182,19 @@ autoscaling: targetCPUUtilizationPercentage: 80 # targetMemoryUtilizationPercentage: 80 +# Additional volumes on the output Deployment definition. +volumes: [] +# - name: foo +# secret: +# secretName: mysecret +# optional: false + +# Additional volumeMounts on the output Deployment definition. +volumeMounts: [] +# - name: foo +# mountPath: "/etc/foo" +# readOnly: true + nodeSelector: {} tolerations: [] @@ -294,7 +310,10 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} labels: - {{- include ".selectorLabels" . | nindent 8 }} + {{- include ".labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} spec: {{- with .Values.imagePullSecrets }} imagePullSecrets: @@ -323,6 +342,14 @@ spec: port: http resources: {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.volumes }} + volumes: + {{- toYaml . | nindent 8 }} + {{- end }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} @@ -365,6 +392,7 @@ metadata: annotations: {{- toYaml . | nindent 4 }} {{- end }} + automountServiceAccountToken: {{ .Values.serviceAccount.automount }} {{- end }} ` diff --git a/pkg/chartutil/dependencies.go b/pkg/chartutil/dependencies.go index a84e9f3e3..c38a8b6c4 100644 --- a/pkg/chartutil/dependencies.go +++ b/pkg/chartutil/dependencies.go @@ -151,6 +151,9 @@ Loop: } for _, req := range c.Metadata.Dependencies { + if req == nil { + continue + } if chartDependency := getAliasDependency(c.Dependencies(), req); chartDependency != nil { chartDependencies = append(chartDependencies, chartDependency) } diff --git a/pkg/chartutil/save_test.go b/pkg/chartutil/save_test.go index b7f5c2ac0..db485c7cb 100644 --- a/pkg/chartutil/save_test.go +++ b/pkg/chartutil/save_test.go @@ -29,14 +29,12 @@ import ( "testing" "time" - "helm.sh/helm/v3/internal/test/ensure" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" ) func TestSave(t *testing.T) { - tmp := ensure.TempDir(t) - defer os.RemoveAll(tmp) + tmp := t.TempDir() for _, dest := range []string{tmp, filepath.Join(tmp, "newdir")} { t.Run("outDir="+dest, func(t *testing.T) { diff --git a/pkg/chartutil/testdata/three-level-dependent-chart/README.md b/pkg/chartutil/testdata/three-level-dependent-chart/README.md index a5fed642d..e6f586a5c 100644 --- a/pkg/chartutil/testdata/three-level-dependent-chart/README.md +++ b/pkg/chartutil/testdata/three-level-dependent-chart/README.md @@ -8,7 +8,7 @@ Consists of the following charts: - App Chart (Uses Library Chart as dependecy, 2x: app1/app2) - Umbrella Chart (Has all the app charts as dependencies) -The precendence is as follows: `library < app < umbrella` +The precedence is as follows: `library < app < umbrella` Catches two use-cases: diff --git a/pkg/downloader/chart_downloader_test.go b/pkg/downloader/chart_downloader_test.go index 8ff780daf..131e21306 100644 --- a/pkg/downloader/chart_downloader_test.go +++ b/pkg/downloader/chart_downloader_test.go @@ -269,10 +269,9 @@ func TestDownloadTo_TLS(t *testing.T) { } func TestDownloadTo_VerifyLater(t *testing.T) { - defer ensure.HelmHome(t)() + ensure.HelmHome(t) - dest := ensure.TempDir(t) - defer os.RemoveAll(dest) + dest := t.TempDir() // Set up a fake repo srv, err := repotest.NewTempServerWithCleanup(t, "testdata/*.tgz*") diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index 657d5767b..150be16b7 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -391,6 +391,9 @@ func recAllTpls(c *chart.Chart, templates map[string]renderable, vals chartutil. newParentID := c.ChartFullPath() for _, t := range c.Templates { + if t == nil { + continue + } if !isTemplateValid(c, t.Name) { continue } diff --git a/pkg/getter/getter.go b/pkg/getter/getter.go index 653b032fe..45ab4da7e 100644 --- a/pkg/getter/getter.go +++ b/pkg/getter/getter.go @@ -37,6 +37,7 @@ type options struct { caFile string unTar bool insecureSkipVerifyTLS bool + plainHTTP bool username string password string passCredentialsAll bool @@ -96,6 +97,12 @@ func WithTLSClientConfig(certFile, keyFile, caFile string) Option { } } +func WithPlainHTTP(plainHTTP bool) Option { + return func(opts *options) { + opts.plainHTTP = plainHTTP + } +} + // WithTimeout sets the timeout for requests func WithTimeout(timeout time.Duration) Option { return func(opts *options) { @@ -172,9 +179,21 @@ func (p Providers) ByScheme(scheme string) (Getter, error) { return nil, errors.Errorf("scheme %q not supported", scheme) } +const ( + // The cost timeout references curl's default connection timeout. + // https://github.com/curl/curl/blob/master/lib/connect.h#L40C21-L40C21 + // The helm commands are usually executed manually. Considering the acceptable waiting time, we reduced the entire request time to 120s. + DefaultHTTPTimeout = 120 +) + +var defaultOptions = []Option{WithTimeout(time.Second * DefaultHTTPTimeout)} + var httpProvider = Provider{ Schemes: []string{"http", "https"}, - New: NewHTTPGetter, + New: func(options ...Option) (Getter, error) { + options = append(options, defaultOptions...) + return NewHTTPGetter(options...) + }, } var ociProvider = Provider{ diff --git a/pkg/getter/ocigetter.go b/pkg/getter/ocigetter.go index 1705fca91..209786bd7 100644 --- a/pkg/getter/ocigetter.go +++ b/pkg/getter/ocigetter.go @@ -137,12 +137,15 @@ func (g *OCIGetter) newRegistryClient() (*registry.Client, error) { g.transport.TLSClientConfig = tlsConf } - client, err := registry.NewClient( - registry.ClientOptHTTPClient(&http.Client{ - Transport: g.transport, - Timeout: g.opts.timeout, - }), - ) + opts := []registry.ClientOption{registry.ClientOptHTTPClient(&http.Client{ + Transport: g.transport, + Timeout: g.opts.timeout, + })} + if g.opts.plainHTTP { + opts = append(opts, registry.ClientOptPlainHTTP()) + } + + client, err := registry.NewClient(opts...) if err != nil { return nil, err diff --git a/pkg/getter/ocigetter_test.go b/pkg/getter/ocigetter_test.go index fa2fa67a5..d0834d9fc 100644 --- a/pkg/getter/ocigetter_test.go +++ b/pkg/getter/ocigetter_test.go @@ -39,7 +39,8 @@ func TestOCIGetter(t *testing.T) { ca, pub, priv := join(cd, "rootca.crt"), join(cd, "crt.pem"), join(cd, "key.pem") timeout := time.Second * 5 transport := &http.Transport{} - insecureSkipTLSverify := false + insecureSkipVerifyTLS := false + plainHTTP := false // Test with options g, err = NewOCIGetter( @@ -47,7 +48,8 @@ func TestOCIGetter(t *testing.T) { WithTLSClientConfig(pub, priv, ca), WithTimeout(timeout), WithTransport(transport), - WithInsecureSkipVerifyTLS(insecureSkipTLSverify), + WithInsecureSkipVerifyTLS(insecureSkipVerifyTLS), + WithPlainHTTP(plainHTTP), ) if err != nil { t.Fatal(err) @@ -86,6 +88,14 @@ func TestOCIGetter(t *testing.T) { t.Errorf("Expected NewOCIGetter to contain %p as Transport, got %p", transport, og.opts.transport) } + if og.opts.plainHTTP != plainHTTP { + t.Errorf("Expected NewOCIGetter to have plainHTTP as %t, got %t", plainHTTP, og.opts.plainHTTP) + } + + if og.opts.insecureSkipVerifyTLS != insecureSkipVerifyTLS { + t.Errorf("Expected NewOCIGetter to have insecureSkipVerifyTLS as %t, got %t", insecureSkipVerifyTLS, og.opts.insecureSkipVerifyTLS) + } + // Test if setting registryClient is being passed to the ops registryClient, err := registry.NewClient() if err != nil { diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 7b3c803f9..0772678d1 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -69,6 +69,14 @@ var ManagedFieldsManager string // Client represents a client capable of communicating with the Kubernetes API. type Client struct { + // Factory provides a minimal version of the kubectl Factory interface. If + // you need the full Factory you can type switch to the full interface. + // Since Kubernetes Go API does not provide backwards compatibility across + // minor versions, this API does not follow Helm backwards compatibility. + // Helm is exposing Kubernetes in this property and cannot guarantee this + // will not change. The minimal interface only has the functions that Helm + // needs. The smaller surface area of the interface means there is a lower + // chance of it changing. Factory Factory Log func(string, ...interface{}) // Namespace allows to bypass the kubeconfig file for the choice of the namespace @@ -493,10 +501,8 @@ func delete(c *Client, resources ResourceList, propagation metav1.DeletionPropag return nil }) if err != nil { - // Rewrite the message from "no objects visited" if that is what we got - // back - if err == ErrNoObjectsVisited { - err = errors.New("object not found, skipping delete") + if errors.Is(err, ErrNoObjectsVisited) { + err = fmt.Errorf("object not found, skipping delete: %w", err) } errs = append(errs, err) } diff --git a/pkg/kube/factory.go b/pkg/kube/factory.go index 6c1b0f4e3..f19d62dc3 100644 --- a/pkg/kube/factory.go +++ b/pkg/kube/factory.go @@ -26,6 +26,12 @@ import ( // Factory provides abstractions that allow the Kubectl command to be extended across multiple types // of resources and different API sets. +// This interface is a minimal copy of the kubectl Factory interface containing only the functions +// needed by Helm. Since Kubernetes Go APIs, including interfaces, can change in any minor release +// this interface is not covered by the Helm backwards compatibility guarantee. The reasons for the +// minimal copy is that it does not include the full interface. Changes or additions to functions +// Helm does not need are not impacted or exposed. This minimizes the impact of Kubernetes changes +// being exposed. type Factory interface { // ToRawKubeConfigLoader return kubeconfig loader as-is ToRawKubeConfigLoader() clientcmd.ClientConfig diff --git a/pkg/lint/lint_test.go b/pkg/lint/lint_test.go index 236ad9121..5516ec668 100644 --- a/pkg/lint/lint_test.go +++ b/pkg/lint/lint_test.go @@ -43,19 +43,14 @@ func TestBadChart(t *testing.T) { t.Errorf("Number of errors %v", len(m)) t.Errorf("All didn't fail with expected errors, got %#v", m) } - // There should be one INFO, 2 WARNINGs and 2 ERROR messages, check for them - var i, w, e, e2, e3, e4, e5, e6 bool + // There should be one INFO, and 2 ERROR messages, check for them + var i, e, e2, e3, e4, e5, e6 bool for _, msg := range m { if msg.Severity == support.InfoSev { if strings.Contains(msg.Err.Error(), "icon is recommended") { i = true } } - if msg.Severity == support.WarningSev { - if strings.Contains(msg.Err.Error(), "directory not found") { - w = true - } - } if msg.Severity == support.ErrorSev { if strings.Contains(msg.Err.Error(), "version '0.0.0.0' is not a valid SemVer") { e = true @@ -81,7 +76,7 @@ func TestBadChart(t *testing.T) { } } } - if !e || !e2 || !e3 || !e4 || !e5 || !w || !i || !e6 { + if !e || !e2 || !e3 || !e4 || !e5 || !i || !e6 { t.Errorf("Didn't find all the expected errors, got %#v", m) } } diff --git a/pkg/lint/rules/dependencies_test.go b/pkg/lint/rules/dependencies_test.go index 67b160936..24c5faf7f 100644 --- a/pkg/lint/rules/dependencies_test.go +++ b/pkg/lint/rules/dependencies_test.go @@ -16,11 +16,9 @@ limitations under the License. package rules import ( - "os" "path/filepath" "testing" - "helm.sh/helm/v3/internal/test/ensure" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v3/pkg/lint/support" @@ -79,8 +77,7 @@ func TestValidateDependencyInMetadata(t *testing.T) { } func TestDependencies(t *testing.T) { - tmp := ensure.TempDir(t) - defer os.RemoveAll(tmp) + tmp := t.TempDir() c := chartWithBadDependencies() err := chartutil.SaveDir(&c, tmp) diff --git a/pkg/lint/rules/template.go b/pkg/lint/rules/template.go index 4016be42d..000f7ebcf 100644 --- a/pkg/lint/rules/template.go +++ b/pkg/lint/rules/template.go @@ -188,10 +188,10 @@ func validateTopIndentLevel(content string) error { // Validation functions func validateTemplatesDir(templatesPath string) error { - if fi, err := os.Stat(templatesPath); err != nil { - return errors.New("directory not found") - } else if !fi.IsDir() { - return errors.New("not a directory") + if fi, err := os.Stat(templatesPath); err == nil { + if !fi.IsDir() { + return errors.New("not a directory") + } } return nil } diff --git a/pkg/lint/rules/template_test.go b/pkg/lint/rules/template_test.go index f3aa641f2..80f9b28ed 100644 --- a/pkg/lint/rules/template_test.go +++ b/pkg/lint/rules/template_test.go @@ -23,7 +23,6 @@ import ( "strings" "testing" - "helm.sh/helm/v3/internal/test/ensure" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v3/pkg/lint/support" @@ -221,8 +220,7 @@ func TestDeprecatedAPIFails(t *testing.T) { }, }, } - tmpdir := ensure.TempDir(t) - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() if err := chartutil.SaveDir(&mychart, tmpdir); err != nil { t.Fatal(err) @@ -278,8 +276,7 @@ func TestStrictTemplateParsingMapError(t *testing.T) { }, }, } - dir := ensure.TempDir(t) - defer os.RemoveAll(dir) + dir := t.TempDir() if err := chartutil.SaveDir(&ch, dir); err != nil { t.Fatal(err) } @@ -408,8 +405,7 @@ func TestEmptyWithCommentsManifests(t *testing.T) { }, }, } - tmpdir := ensure.TempDir(t) - defer os.RemoveAll(tmpdir) + tmpdir := t.TempDir() if err := chartutil.SaveDir(&mychart, tmpdir); err != nil { t.Fatal(err) diff --git a/pkg/lint/rules/values_test.go b/pkg/lint/rules/values_test.go index 21eb875f4..faa29d48a 100644 --- a/pkg/lint/rules/values_test.go +++ b/pkg/lint/rules/values_test.go @@ -66,7 +66,6 @@ func TestValidateValuesFileWellFormed(t *testing.T) { not:well[]{}formed ` tmpdir := ensure.TempFile(t, "values.yaml", []byte(badYaml)) - defer os.RemoveAll(tmpdir) valfile := filepath.Join(tmpdir, "values.yaml") if err := validateValuesFile(valfile, map[string]interface{}{}); err == nil { t.Fatal("expected values file to fail parsing") @@ -76,7 +75,6 @@ func TestValidateValuesFileWellFormed(t *testing.T) { func TestValidateValuesFileSchema(t *testing.T) { yaml := "username: admin\npassword: swordfish" tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml)) - defer os.RemoveAll(tmpdir) createTestingSchema(t, tmpdir) valfile := filepath.Join(tmpdir, "values.yaml") @@ -89,7 +87,6 @@ func TestValidateValuesFileSchemaFailure(t *testing.T) { // 1234 is an int, not a string. This should fail. yaml := "username: 1234\npassword: swordfish" tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml)) - defer os.RemoveAll(tmpdir) createTestingSchema(t, tmpdir) valfile := filepath.Join(tmpdir, "values.yaml") @@ -108,7 +105,6 @@ func TestValidateValuesFileSchemaOverrides(t *testing.T) { "password": "swordfish", } tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml)) - defer os.RemoveAll(tmpdir) createTestingSchema(t, tmpdir) valfile := filepath.Join(tmpdir, "values.yaml") @@ -145,7 +141,6 @@ func TestValidateValuesFile(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tmpdir := ensure.TempFile(t, "values.yaml", []byte(tt.yaml)) - defer os.RemoveAll(tmpdir) createTestingSchema(t, tmpdir) valfile := filepath.Join(tmpdir, "values.yaml") diff --git a/pkg/plugin/installer/http_installer_test.go b/pkg/plugin/installer/http_installer_test.go index 165007af0..177227c5b 100644 --- a/pkg/plugin/installer/http_installer_test.go +++ b/pkg/plugin/installer/http_installer_test.go @@ -79,7 +79,7 @@ func mockArchiveServer() *httptest.Server { } func TestHTTPInstaller(t *testing.T) { - defer ensure.HelmHome(t)() + ensure.HelmHome(t) srv := mockArchiveServer() defer srv.Close() @@ -128,7 +128,7 @@ func TestHTTPInstaller(t *testing.T) { } func TestHTTPInstallerNonExistentVersion(t *testing.T) { - defer ensure.HelmHome(t)() + ensure.HelmHome(t) srv := mockArchiveServer() defer srv.Close() source := srv.URL + "/plugins/fake-plugin-0.0.1.tar.gz" @@ -164,7 +164,7 @@ func TestHTTPInstallerUpdate(t *testing.T) { srv := mockArchiveServer() defer srv.Close() source := srv.URL + "/plugins/fake-plugin-0.0.1.tar.gz" - defer ensure.HelmHome(t)() + ensure.HelmHome(t) if err := os.MkdirAll(helmpath.DataPath("plugins"), 0755); err != nil { t.Fatalf("Could not create %s: %s", helmpath.DataPath("plugins"), err) diff --git a/pkg/plugin/installer/vcs_installer_test.go b/pkg/plugin/installer/vcs_installer_test.go index 6785264b3..0bb0b6780 100644 --- a/pkg/plugin/installer/vcs_installer_test.go +++ b/pkg/plugin/installer/vcs_installer_test.go @@ -49,7 +49,7 @@ func (r *testRepo) UpdateVersion(version string) error { } func TestVCSInstaller(t *testing.T) { - defer ensure.HelmHome(t)() + ensure.HelmHome(t) if err := os.MkdirAll(helmpath.DataPath("plugins"), 0755); err != nil { t.Fatalf("Could not create %s: %s", helmpath.DataPath("plugins"), err) @@ -102,7 +102,7 @@ func TestVCSInstaller(t *testing.T) { } func TestVCSInstallerNonExistentVersion(t *testing.T) { - defer ensure.HelmHome(t)() + ensure.HelmHome(t) source := "https://github.com/adamreese/helm-env" version := "0.2.0" @@ -124,7 +124,7 @@ func TestVCSInstallerNonExistentVersion(t *testing.T) { } } func TestVCSInstallerUpdate(t *testing.T) { - defer ensure.HelmHome(t)() + ensure.HelmHome(t) source := "https://github.com/adamreese/helm-env" diff --git a/pkg/postrender/exec_test.go b/pkg/postrender/exec_test.go index 471acf112..19a6ec6c4 100644 --- a/pkg/postrender/exec_test.go +++ b/pkg/postrender/exec_test.go @@ -25,8 +25,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - "helm.sh/helm/v3/internal/test/ensure" ) const testingScript = `#!/bin/sh @@ -40,8 +38,7 @@ fi func TestGetFullPath(t *testing.T) { is := assert.New(t) t.Run("full path resolves correctly", func(t *testing.T) { - testpath, cleanup := setupTestingScript(t) - defer cleanup() + testpath := setupTestingScript(t) fullPath, err := getFullPath(testpath) is.NoError(err) @@ -49,8 +46,7 @@ func TestGetFullPath(t *testing.T) { }) t.Run("relative path resolves correctly", func(t *testing.T) { - testpath, cleanup := setupTestingScript(t) - defer cleanup() + testpath := setupTestingScript(t) currentDir, err := os.Getwd() require.NoError(t, err) @@ -62,8 +58,7 @@ func TestGetFullPath(t *testing.T) { }) t.Run("binary in PATH resolves correctly", func(t *testing.T) { - testpath, cleanup := setupTestingScript(t) - defer cleanup() + testpath := setupTestingScript(t) realPath := os.Getenv("PATH") os.Setenv("PATH", filepath.Dir(testpath)) @@ -116,8 +111,7 @@ func TestExecRun(t *testing.T) { t.Skip("skipping on windows") } is := assert.New(t) - testpath, cleanup := setupTestingScript(t) - defer cleanup() + testpath := setupTestingScript(t) renderer, err := NewExec(testpath) require.NoError(t, err) @@ -133,8 +127,7 @@ func TestNewExecWithOneArgsRun(t *testing.T) { t.Skip("skipping on windows") } is := assert.New(t) - testpath, cleanup := setupTestingScript(t) - defer cleanup() + testpath := setupTestingScript(t) renderer, err := NewExec(testpath, "ARG1") require.NoError(t, err) @@ -150,8 +143,7 @@ func TestNewExecWithTwoArgsRun(t *testing.T) { t.Skip("skipping on windows") } is := assert.New(t) - testpath, cleanup := setupTestingScript(t) - defer cleanup() + testpath := setupTestingScript(t) renderer, err := NewExec(testpath, "ARG1", "ARG2") require.NoError(t, err) @@ -161,10 +153,10 @@ func TestNewExecWithTwoArgsRun(t *testing.T) { is.Contains(output.String(), "ARG1 ARG2") } -func setupTestingScript(t *testing.T) (filepath string, cleanup func()) { +func setupTestingScript(t *testing.T) (filepath string) { t.Helper() - tempdir := ensure.TempDir(t) + tempdir := t.TempDir() f, err := os.CreateTemp(tempdir, "post-render-test.sh") if err != nil { @@ -186,7 +178,5 @@ func setupTestingScript(t *testing.T) (filepath string, cleanup func()) { t.Fatalf("unable to close tempfile after writing: %s", err) } - return f.Name(), func() { - os.RemoveAll(tempdir) - } + return f.Name() } diff --git a/pkg/pusher/ocipusher.go b/pkg/pusher/ocipusher.go index ea5e164c2..94154d389 100644 --- a/pkg/pusher/ocipusher.go +++ b/pkg/pusher/ocipusher.go @@ -139,9 +139,12 @@ func (pusher *OCIPusher) newRegistryClient() (*registry.Client, error) { return registryClient, nil } - registryClient, err := registry.NewClient( - registry.ClientOptEnableCache(true), - ) + opts := []registry.ClientOption{registry.ClientOptEnableCache(true)} + if pusher.opts.plainHTTP { + opts = append(opts, registry.ClientOptPlainHTTP()) + } + + registryClient, err := registry.NewClient(opts...) if err != nil { return nil, err } diff --git a/pkg/pusher/ocipusher_test.go b/pkg/pusher/ocipusher_test.go index 9390710a0..11842b4ae 100644 --- a/pkg/pusher/ocipusher_test.go +++ b/pkg/pusher/ocipusher_test.go @@ -36,11 +36,13 @@ func TestNewOCIPusher(t *testing.T) { join := filepath.Join ca, pub, priv := join(cd, "rootca.crt"), join(cd, "crt.pem"), join(cd, "key.pem") insecureSkipTLSverify := false + plainHTTP := false // Test with options p, err = NewOCIPusher( WithTLSClientConfig(pub, priv, ca), WithInsecureSkipTLSVerify(insecureSkipTLSverify), + WithPlainHTTP(plainHTTP), ) if err != nil { t.Fatal(err) @@ -63,6 +65,14 @@ func TestNewOCIPusher(t *testing.T) { t.Errorf("Expected NewOCIPusher to contain %q as the CA file, got %q", ca, op.opts.caFile) } + if op.opts.plainHTTP != plainHTTP { + t.Errorf("Expected NewOCIPusher to have plainHTTP as %t, got %t", plainHTTP, op.opts.plainHTTP) + } + + if op.opts.insecureSkipTLSverify != insecureSkipTLSverify { + t.Errorf("Expected NewOCIPusher to have insecureSkipVerifyTLS as %t, got %t", insecureSkipTLSverify, op.opts.insecureSkipTLSverify) + } + // Test if setting registryClient is being passed to the ops registryClient, err := registry.NewClient() if err != nil { diff --git a/pkg/pusher/pusher.go b/pkg/pusher/pusher.go index e325ce498..c99d97b35 100644 --- a/pkg/pusher/pusher.go +++ b/pkg/pusher/pusher.go @@ -32,6 +32,7 @@ type options struct { keyFile string caFile string insecureSkipTLSverify bool + plainHTTP bool } // Option allows specifying various settings configurable by the user for overriding the defaults @@ -61,6 +62,12 @@ func WithInsecureSkipTLSVerify(insecureSkipTLSVerify bool) Option { } } +func WithPlainHTTP(plainHTTP bool) Option { + return func(opts *options) { + opts.plainHTTP = plainHTTP + } +} + // Pusher is an interface to support upload to the specified URL. type Pusher interface { // Push file content by url string diff --git a/pkg/registry/client.go b/pkg/registry/client.go index 509f82d4a..0dfa6926f 100644 --- a/pkg/registry/client.go +++ b/pkg/registry/client.go @@ -59,8 +59,9 @@ type ( out io.Writer authorizer auth.Client registryAuthorizer *registryauth.Client - resolver remotes.Resolver + resolver func(ref registry.Reference) (remotes.Resolver, error) httpClient *http.Client + plainHTTP bool } // ClientOption allows specifying various settings configurable by the user for overriding the defaults @@ -86,18 +87,44 @@ func NewClient(options ...ClientOption) (*Client, error) { } client.authorizer = authClient } - if client.resolver == nil { + + resolverFn := client.resolver // copy for avoiding recursive call + client.resolver = func(ref registry.Reference) (remotes.Resolver, error) { + if resolverFn != nil { + // validate if the resolverFn returns a valid resolver + if resolver, err := resolverFn(ref); resolver != nil && err == nil { + return resolver, nil + } + } + headers := http.Header{} headers.Set("User-Agent", version.GetUserAgent()) + dockerClient, ok := client.authorizer.(*dockerauth.Client) + if ok { + username, password, err := dockerClient.Credential(ref.Registry) + if err != nil { + return nil, errors.New("unable to retrieve credentials") + } + // A blank returned username and password value is a bearer token + if username == "" && password != "" { + headers.Set("Authorization", fmt.Sprintf("Bearer %s", password)) + } else { + headers.Set("Authorization", fmt.Sprintf("Basic %s", basicAuth(username, password))) + } + } + opts := []auth.ResolverOption{auth.WithResolverHeaders(headers)} if client.httpClient != nil { opts = append(opts, auth.WithResolverClient(client.httpClient)) } + if client.plainHTTP { + opts = append(opts, auth.WithResolverPlainHTTP()) + } resolver, err := client.authorizer.ResolverWithOpts(opts...) if err != nil { return nil, err } - client.resolver = resolver + return resolver, nil } // allocate a cache if option is set @@ -117,7 +144,6 @@ func NewClient(options ...ClientOption) (*Client, error) { if !ok { return registryauth.EmptyCredential, errors.New("unable to obtain docker client") } - username, password, err := dockerClient.Credential(reg) if err != nil { return registryauth.EmptyCredential, errors.New("unable to retrieve credentials") @@ -177,6 +203,21 @@ func ClientOptHTTPClient(httpClient *http.Client) ClientOption { } } +func ClientOptPlainHTTP() ClientOption { + return func(c *Client) { + c.plainHTTP = true + } +} + +// ClientOptResolver returns a function that sets the resolver setting on a client options set +func ClientOptResolver(resolver remotes.Resolver) ClientOption { + return func(client *Client) { + client.resolver = func(ref registry.Reference) (remotes.Resolver, error) { + return resolver, nil + } + } +} + type ( // LoginOption allows specifying various settings on login LoginOption func(*loginOperation) @@ -265,21 +306,21 @@ type ( // PullResult is the result returned upon successful pull. PullResult struct { - Manifest *descriptorPullSummary `json:"manifest"` - Config *descriptorPullSummary `json:"config"` - Chart *descriptorPullSummaryWithMeta `json:"chart"` - Prov *descriptorPullSummary `json:"prov"` + Manifest *DescriptorPullSummary `json:"manifest"` + Config *DescriptorPullSummary `json:"config"` + Chart *DescriptorPullSummaryWithMeta `json:"chart"` + Prov *DescriptorPullSummary `json:"prov"` Ref string `json:"ref"` } - descriptorPullSummary struct { + DescriptorPullSummary struct { Data []byte `json:"-"` Digest string `json:"digest"` Size int64 `json:"size"` } - descriptorPullSummaryWithMeta struct { - descriptorPullSummary + DescriptorPullSummaryWithMeta struct { + DescriptorPullSummary Meta *chart.Metadata `json:"meta"` } @@ -324,7 +365,11 @@ func (c *Client) Pull(ref string, options ...PullOption) (*PullResult, error) { } var descriptors, layers []ocispec.Descriptor - registryStore := content.Registry{Resolver: c.resolver} + remotesResolver, err := c.resolver(parsedRef) + if err != nil { + return nil, err + } + registryStore := content.Registry{Resolver: remotesResolver} manifest, err := oras.Copy(ctx(c.out, c.debug), registryStore, parsedRef.String(), memoryStore, "", oras.WithPullEmptyNameAllowed(), @@ -378,16 +423,16 @@ func (c *Client) Pull(ref string, options ...PullOption) (*PullResult, error) { } } result := &PullResult{ - Manifest: &descriptorPullSummary{ + Manifest: &DescriptorPullSummary{ Digest: manifest.Digest.String(), Size: manifest.Size, }, - Config: &descriptorPullSummary{ + Config: &DescriptorPullSummary{ Digest: configDescriptor.Digest.String(), Size: configDescriptor.Size, }, - Chart: &descriptorPullSummaryWithMeta{}, - Prov: &descriptorPullSummary{}, + Chart: &DescriptorPullSummaryWithMeta{}, + Prov: &DescriptorPullSummary{}, Ref: parsedRef.String(), } var getManifestErr error @@ -562,8 +607,11 @@ func (c *Client) Push(data []byte, ref string, options ...PushOption) (*PushResu if err := memoryStore.StoreManifest(parsedRef.String(), manifest, manifestData); err != nil { return nil, err } - - registryStore := content.Registry{Resolver: c.resolver} + remotesResolver, err := c.resolver(parsedRef) + if err != nil { + return nil, err + } + registryStore := content.Registry{Resolver: remotesResolver} _, err = oras.Copy(ctx(c.out, c.debug), memoryStore, parsedRef.String(), registryStore, "", oras.WithNameValidation(nil)) if err != nil { @@ -634,23 +682,14 @@ func (c *Client) Tags(ref string) ([]string, error) { repository := registryremote.Repository{ Reference: parsedReference, Client: c.registryAuthorizer, + PlainHTTP: c.plainHTTP, } var registryTags []string - for { - registryTags, err = registry.Tags(ctx(c.out, c.debug), &repository) - if err != nil { - // Fallback to http based request - if !repository.PlainHTTP && strings.Contains(err.Error(), "server gave HTTP response") { - repository.PlainHTTP = true - continue - } - return nil, err - } - - break - + registryTags, err = registry.Tags(ctx(c.out, c.debug), &repository) + if err != nil { + return nil, err } var tagVersions []*semver.Version diff --git a/pkg/registry/client_http_test.go b/pkg/registry/client_http_test.go new file mode 100644 index 000000000..872d19fc9 --- /dev/null +++ b/pkg/registry/client_http_test.go @@ -0,0 +1,68 @@ +/* +Copyright The Helm Authors. + +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. +*/ + +package registry + +import ( + "fmt" + "os" + "testing" + + "github.com/containerd/containerd/errdefs" + "github.com/stretchr/testify/suite" +) + +type HTTPRegistryClientTestSuite struct { + TestSuite +} + +func (suite *HTTPRegistryClientTestSuite) SetupSuite() { + // init test client + dockerRegistry := setup(&suite.TestSuite, false, false) + + // Start Docker registry + go dockerRegistry.ListenAndServe() +} + +func (suite *HTTPRegistryClientTestSuite) TearDownSuite() { + teardown(&suite.TestSuite) + os.RemoveAll(suite.WorkspaceDir) +} + +func (suite *HTTPRegistryClientTestSuite) Test_1_Push() { + testPush(&suite.TestSuite) +} + +func (suite *HTTPRegistryClientTestSuite) Test_2_Pull() { + testPull(&suite.TestSuite) +} + +func (suite *HTTPRegistryClientTestSuite) Test_3_Tags() { + testTags(&suite.TestSuite) +} + +func (suite *HTTPRegistryClientTestSuite) Test_4_ManInTheMiddle() { + ref := fmt.Sprintf("%s/testrepo/supposedlysafechart:9.9.9", suite.CompromisedRegistryHost) + + // returns content that does not match the expected digest + _, err := suite.RegistryClient.Pull(ref) + suite.NotNil(err) + suite.True(errdefs.IsFailedPrecondition(err)) +} + +func TestHTTPRegistryClientTestSuite(t *testing.T) { + suite.Run(t, new(HTTPRegistryClientTestSuite)) +} diff --git a/pkg/registry/client_test.go b/pkg/registry/client_insecure_tls_test.go similarity index 52% rename from pkg/registry/client_test.go rename to pkg/registry/client_insecure_tls_test.go index 3bb4a991b..5ba79b2ea 100644 --- a/pkg/registry/client_test.go +++ b/pkg/registry/client_insecure_tls_test.go @@ -17,65 +17,54 @@ limitations under the License. package registry import ( - "fmt" "os" "testing" - "github.com/containerd/containerd/errdefs" "github.com/stretchr/testify/suite" ) -type RegistryClientTestSuite struct { +type InsecureTLSRegistryClientTestSuite struct { TestSuite } -func (suite *RegistryClientTestSuite) SetupSuite() { +func (suite *InsecureTLSRegistryClientTestSuite) SetupSuite() { // init test client - dockerRegistry := setup(&suite.TestSuite, false, false) + dockerRegistry := setup(&suite.TestSuite, true, true) // Start Docker registry go dockerRegistry.ListenAndServe() } -func (suite *RegistryClientTestSuite) TearDownSuite() { +func (suite *InsecureTLSRegistryClientTestSuite) TearDownSuite() { + teardown(&suite.TestSuite) os.RemoveAll(suite.WorkspaceDir) } -func (suite *RegistryClientTestSuite) Test_0_Login() { +func (suite *InsecureTLSRegistryClientTestSuite) Test_0_Login() { err := suite.RegistryClient.Login(suite.DockerRegistryHost, - LoginOptBasicAuth("badverybad", "ohsobad"), - LoginOptInsecure(false)) - suite.NotNil(err, "error logging into registry with bad credentials") - - err = suite.RegistryClient.Login(suite.DockerRegistryHost, LoginOptBasicAuth("badverybad", "ohsobad"), LoginOptInsecure(true)) - suite.NotNil(err, "error logging into registry with bad credentials, insecure mode") - - err = suite.RegistryClient.Login(suite.DockerRegistryHost, - LoginOptBasicAuth(testUsername, testPassword), - LoginOptInsecure(false)) - suite.Nil(err, "no error logging into registry with good credentials") + suite.NotNil(err, "error logging into registry with bad credentials") err = suite.RegistryClient.Login(suite.DockerRegistryHost, LoginOptBasicAuth(testUsername, testPassword), LoginOptInsecure(true)) - suite.Nil(err, "no error logging into registry with good credentials, insecure mode") + suite.Nil(err, "no error logging into registry with good credentials") } -func (suite *RegistryClientTestSuite) Test_1_Push() { +func (suite *InsecureTLSRegistryClientTestSuite) Test_1_Push() { testPush(&suite.TestSuite) } -func (suite *RegistryClientTestSuite) Test_2_Pull() { +func (suite *InsecureTLSRegistryClientTestSuite) Test_2_Pull() { testPull(&suite.TestSuite) } -func (suite *RegistryClientTestSuite) Test_3_Tags() { +func (suite *InsecureTLSRegistryClientTestSuite) Test_3_Tags() { testTags(&suite.TestSuite) } -func (suite *RegistryClientTestSuite) Test_4_Logout() { +func (suite *InsecureTLSRegistryClientTestSuite) Test_4_Logout() { err := suite.RegistryClient.Logout("this-host-aint-real:5000") suite.NotNil(err, "error logging out of registry that has no entry") @@ -83,15 +72,6 @@ func (suite *RegistryClientTestSuite) Test_4_Logout() { suite.Nil(err, "no error logging out of registry") } -func (suite *RegistryClientTestSuite) Test_5_ManInTheMiddle() { - ref := fmt.Sprintf("%s/testrepo/supposedlysafechart:9.9.9", suite.CompromisedRegistryHost) - - // returns content that does not match the expected digest - _, err := suite.RegistryClient.Pull(ref) - suite.NotNil(err) - suite.True(errdefs.IsFailedPrecondition(err)) -} - -func TestRegistryClientTestSuite(t *testing.T) { - suite.Run(t, new(RegistryClientTestSuite)) +func TestInsecureTLSRegistryClientTestSuite(t *testing.T) { + suite.Run(t, new(InsecureTLSRegistryClientTestSuite)) } diff --git a/pkg/registry/client_tls_test.go b/pkg/registry/client_tls_test.go index 9b981d35e..518cfced4 100644 --- a/pkg/registry/client_tls_test.go +++ b/pkg/registry/client_tls_test.go @@ -50,11 +50,6 @@ func (suite *TLSRegistryClientTestSuite) Test_0_Login() { LoginOptBasicAuth(testUsername, testPassword), LoginOptTLSClientConfig(tlsCert, tlsKey, tlsCA)) suite.Nil(err, "no error logging into registry with good credentials") - - err = suite.RegistryClient.Login(suite.DockerRegistryHost, - LoginOptBasicAuth(testUsername, testPassword), - LoginOptTLSClientConfig(tlsCert, tlsKey, tlsCA)) - suite.Nil(err, "no error logging into registry with good credentials, insecure mode") } func (suite *TLSRegistryClientTestSuite) Test_1_Push() { diff --git a/pkg/registry/testdata/tls/ca-cert.pem b/pkg/registry/testdata/tls/ca-cert.pem deleted file mode 100644 index b2f4fe107..000000000 --- a/pkg/registry/testdata/tls/ca-cert.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDhzCCAm+gAwIBAgIUdI/ees1mQ4N++1jpF5xI5fq6TSUwDQYJKoZIhvcNAQEL -BQAwUjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQHDAJTRjENMAsG -A1UECgwEaGVsbTEaMBgGA1UEAwwRcmVnaXN0cnktdGVzdC5jb20wIBcNMjIwOTIw -MDgyMDQ2WhgPMzAyMjAxMjEwODIwNDZaMFIxCzAJBgNVBAYTAlVTMQswCQYDVQQI -DAJDQTELMAkGA1UEBwwCU0YxDTALBgNVBAoMBGhlbG0xGjAYBgNVBAMMEXJlZ2lz -dHJ5LXRlc3QuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0mxP -WVkpDo3PnXalJhy9rSYuK8OIxcO1kBroEnILYrNWn5zpKioaBXZEYcaU6crc5N4j -wQRC16wucyQAQh/d3ty7j5Wyy79CgH5AAKDbCacii4BgGUJ2xY6UXuKvwdsROAXN -wEtXT5f3yO8bVboYrZRxJ4UuTUFndtuz2b230JFs2FzTv4QdLaPHo/S4FTW5xRn5 -Irhmcmkns+XY4AduscYtzydvIuuOS3CVmB8/sClo62F5DpBl68b+/WFwqLrkX5Sn -ZWKx/fJPIxln5SavPXHEEcI14ZGNUhsv+4+sABHzVjBPK8oKjoNo8QmxDWdeWPgR -sPj/H2oldE6KfgyoQQIDAQABo1MwUTAdBgNVHQ4EFgQUkkmPK6SIj4PY8YOw+Yer -hKCOS7owHwYDVR0jBBgwFoAUkkmPK6SIj4PY8YOw+YerhKCOS7owDwYDVR0TAQH/ -BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEADSz9s8rcObLrUo8DpVRptWUxK3NH -hvD7bYGQ9eJO9B4ojKSBKJRchP0m5kpVLorMRZDRw17T2GouKQn3g+Wcy+8CygxW -1JDO/1iCZ8QX3vfwIfHTaKuY6eYcJyVmxL58bRI3qQNRZIU4s18tKFIazBluxS3g -5Wp8kOCBssttsM+lEgC/cj7skl9CBKhUFupHPzXzha+1upJUK51Egc7M7nsrnpaZ -2SY+PBEhSY5Wcuzb5m9tw7PJnkdRDS/dUOY6kSzJXgNMVV0GnN+Smucqmvrez0M5 -vHFMiQjlRxViVLJDNOCJYIjWNygAOvhJyRU2cTodIhZ/jbYqpNGAPc5Eyg== ------END CERTIFICATE----- diff --git a/pkg/registry/testdata/tls/ca.crt b/pkg/registry/testdata/tls/ca.crt new file mode 100644 index 000000000..d5b845acb --- /dev/null +++ b/pkg/registry/testdata/tls/ca.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDhzCCAm+gAwIBAgIUEtjKXd8LxpkQf3C5LgdzM1++R3swDQYJKoZIhvcNAQEL +BQAwUzELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkdEMQswCQYDVQQHDAJTWjETMBEG +A1UECgwKQWNtZSwgSW5jLjEVMBMGA1UEAwwMQWNtZSBSb290IENBMB4XDTIzMDYw +ODEwNDkzOFoXDTI0MDYwNzEwNDkzOFowUzELMAkGA1UEBhMCQ04xCzAJBgNVBAgM +AkdEMQswCQYDVQQHDAJTWjETMBEGA1UECgwKQWNtZSwgSW5jLjEVMBMGA1UEAwwM +QWNtZSBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApgrX +Lv3k3trxje2JEoqusYN67Z3byZg69djRatfdboS3JKoTIHtcY7MMLdfhjAK97/wv +BaIMuVNgueu4qH6bea7FCP8XWz2BYBrH2GcKjVrBMkUrlIzjG9gnohkeknJQvQvl +oVbqLgZJn0HQcZtsPDnLwfjWDZrNkFBtvPSIMaRQbmtOFdSqAQjLKezbwlznBCJ5 +qpLsgc67ttDW5QAS+GszWPmypUlw8Ih7m8J95eT9aUESP0DbdraeUktWJQTdqukd +NflLaA2ZoV+uTX+wVE4yyXgSjD3Sd93+XhoSSzDzkzRnLsocRutxrTiNC/1S+qhb +Z72XLk0bvNwQhJjHDQIDAQABo1MwUTAdBgNVHQ4EFgQUoSKAVvuJDGszE361K7IF +RXOVj2YwHwYDVR0jBBgwFoAUoSKAVvuJDGszE361K7IFRXOVj2YwDwYDVR0TAQH/ +BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAOqH/JFuT1sqY/zVxCsATE1ze85/o +r6yPw3AuXsFzWtHe/XOFJzvbfOBWfocVLXTDc5933f1Ws/+PcxQKEQCwnUHrEAso +jLPzy+igHc07pi9PqHJ21Sn8FF5JVv+Y6CcZKaF5aEzUISsVjbF2vGK8FotMS9rs +Jw//dDfKhHjO9MHPBdkhOrM31LV6gwYPepno/YYygrJwHGQ5V9sdY8ifRBG6lX2a +xK4N2bl5q3Cpz+iERLNGP2c8OVQwLfSYLpFRSbHS8UiN4z6WqfgYHG7YurvbiMiJ +/AFkUatVJQ5YLmfCz4FMAiaxNtEOkZh5cvL1eCLK7nzvgAPCI33mEp6eoA== +-----END CERTIFICATE----- diff --git a/pkg/registry/testdata/tls/client-cert.pem b/pkg/registry/testdata/tls/client-cert.pem deleted file mode 100644 index f541fcd54..000000000 --- a/pkg/registry/testdata/tls/client-cert.pem +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDsTCCApmgAwIBAgIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzEL -MAkGA1UECAwCQ0ExCzAJBgNVBAcMAlNGMQ0wCwYDVQQKDARoZWxtMRowGAYDVQQD -DBFyZWdpc3RyeS10ZXN0LmNvbTAgFw0yMjA5MjAwODI4MzBaGA8yMTIyMDgyNzA4 -MjgzMFowWTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQHDAJTRjEN -MAsGA1UECgwEaGVsbTEhMB8GA1UEAwwYY2xpZW50LnJlZ2lzdHJ5LXRlc3QuY29t -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnvxfrJn8PeerlHJLnMVo -p1yOT/kvFAoNhObhtDUosDLjQBt+vICfjWoTNIabIiBRTwkVt5CdGvx1oKsbH3iT -VErL6N6MagIJdnOfBjxtlTL/TFtJ7U/VSUSxZwa+SV6HS4cmIntC/FV3MHjBlFJn -klSdDXa5YdYE2xuSPse+zlGRfmPTNmHsiNWphGC54U6WZ1UI0G22+L/yO8BuEkSq -47iCN6ZIw8ds+azl/woIEDJsVSgEapNsanBrJFnBUJBXh4lwpMB37U+6Ds1kUUuz -GXhVWz1pmRBt+vXWN802MqRg2RnCjTb2gWbmg7En4uFCTzx/GhRlJiV47O15n0g+ -tQIDAQABo4GIMIGFMB8GA1UdIwQYMBaAFJJJjyukiI+D2PGDsPmHq4Sgjku6MAkG -A1UdEwQCMAAwCwYDVR0PBAQDAgTwMCsGA1UdEQQkMCKCCWxvY2FsaG9zdIIKMHg3 -ZjAwMDAwMYIJMTI3LjAuMC4xMB0GA1UdDgQWBBT+cCGLyj5wOIMG7TVqPyxPQsBi -+DANBgkqhkiG9w0BAQsFAAOCAQEATIDXr3LmD1S+13lVG263rn21cDT3m4VycQCu -oGNDuxtFwd/Zn/XnZLk2r1msz6YXWUqErJ8C7Ea7fFdimoJR5V3m7LYrYRPeLYVn -aVqyNN4LD48Su3VO5sjTyFxXJJJ9C5HX8LU/Pw/517qzLOFrmsO/fXN/XE52erBE -+K6vX4lyxnZyPfl3A/X/33G2tsGtHFK1uBILpn29fpeC/Pgm3Nj8ZqQ8rtcLZbog -heqdKkHKWdL3i1deplwxT7xVnqsWszU6Znzm/C/VQSB4Isn4puQDKqVPwGobHgxY -1zZr5mueot8mX9Qmg8IcWOVZ2u7nz8lw6+wpabkyjjdTC6iizg== ------END CERTIFICATE----- diff --git a/pkg/registry/testdata/tls/client-key.pem b/pkg/registry/testdata/tls/client-key.pem deleted file mode 100644 index 7e7ace54f..000000000 --- a/pkg/registry/testdata/tls/client-key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCe/F+smfw956uU -ckucxWinXI5P+S8UCg2E5uG0NSiwMuNAG368gJ+NahM0hpsiIFFPCRW3kJ0a/HWg -qxsfeJNUSsvo3oxqAgl2c58GPG2VMv9MW0ntT9VJRLFnBr5JXodLhyYie0L8VXcw -eMGUUmeSVJ0Ndrlh1gTbG5I+x77OUZF+Y9M2YeyI1amEYLnhTpZnVQjQbbb4v/I7 -wG4SRKrjuII3pkjDx2z5rOX/CggQMmxVKARqk2xqcGskWcFQkFeHiXCkwHftT7oO -zWRRS7MZeFVbPWmZEG369dY3zTYypGDZGcKNNvaBZuaDsSfi4UJPPH8aFGUmJXjs -7XmfSD61AgMBAAECggEAKYp/5TWG9xXlezAyGZBrO++vL65IYtANoEBDkTainwds -4X9NqithhS3GPt89Abm4BRK2nfQnWLnGcmjC+YIj3M5+YSZlQf2uQ0kKsDJx354n -nufrdRp6/F36jJTye3E7oLx7dl8GrbAXKI8k5YByl4WMU8xFvA6TzjxyBf1jGb1E -8JBZpnqwSHgtH0zGPqgcIsqmQjiMJ+wHNZxdvtjPPC8exy/yLL9Hhj2UaqZSMMRi -afaAFXBLNvJ6Y/SUjRaL9liAyTQ0kJ+xR6TMDJ7ix0toGlylsK/3YesXEgAyui6c -UC3dmSC4UDJW+fGLrj/hVBLdpMRpgrWzwXnRyr0RMQKBgQDDnJqAtULhlo0W4E29 -Oo7XYFEcilzxB3hxEQSmts53GeQZHo1gI4wthyMzAgY3uOCIUtB2lPkNLV+dU86A -Cy1WTRL2vbwdM1qHz2tls4LNa+k+XTMWX7aqfCzOydBpV3Yehmnzb4NvFn9+QHjp -5omwwOaG7dhJCVet3CUJctoeOwKBgQDQETAVd4xfwQ/cBbKgoQhrkHOr+gTWcKYP -WD86EFDbRVboYDevU/dAj5Vwm5763zRsBFyL6/ZVUr9Wa1HHy0paE5YfdewMrRje -LhHeTbrLJ4Q3I0ix3bawv/04B66hw+Yaom0bQV3gBrNk+Cn8VFAo6IKNy7A0pK3i -KQmwoO+XzwKBgC3EqInQ33M07JIbrVTHLMDL8m6BGTn0C4Q4/SOcxjYrwqj18xI5 -fwTwB5ZZtOa4xSBgcBIuzQ7+PM7s2vYup073/aXpwuf6KgZ4y6IiHErAIvTKjbeA -cZb2Mu23XqInKqX9wTCKOPB3DSGXKDNiE3ldyRJs+BwuqWsuhSPu0YYdAoGADjd+ -b5kRkGFisgf5opweNStTnAajWfusfRPsjg0bWUAtpgcdBu/XzyOAdIdNn5qsvEy3 -/h+LX10eEcuXdO1hETKRaWjnTh5tupCvS99HyiXTFOlmSDD8EKuto6xytD7sdBlx -FxGqVmpey6FhTQp9x63LbeDjE1XFQ9TGArmcZWUCgYEAprSfhSemz9tP5tKKdYTc -LM5eWqK0aB1sN/hCZVx86VcNBxRbV+POEASTYO9AyVMjthGRe6UnCjwdXKTJ/ToX -KdtXINYeeK3hzANeCvtqg81qxi+8nmNLimtcjvFsB5g44LOFYyXqAD5FeQYTog1n -t/TLHYY+S8BbJ9cXfObXqyE= ------END PRIVATE KEY----- diff --git a/pkg/registry/testdata/tls/client.crt b/pkg/registry/testdata/tls/client.crt new file mode 100644 index 000000000..5b1daf278 --- /dev/null +++ b/pkg/registry/testdata/tls/client.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDWzCCAkOgAwIBAgIUdJ6uRYm6RYesJ3CRoLokemFFgX8wDQYJKoZIhvcNAQEL +BQAwUzELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkdEMQswCQYDVQQHDAJTWjETMBEG +A1UECgwKQWNtZSwgSW5jLjEVMBMGA1UEAwwMQWNtZSBSb290IENBMB4XDTIzMDYw +ODEwNTA0OFoXDTI0MDYwNzEwNTA0OFowWTELMAkGA1UEBhMCQ04xCzAJBgNVBAgM +AkdEMQswCQYDVQQHDAJTWjETMBEGA1UECgwKQWNtZSwgSW5jLjEbMBkGA1UEAwwS +aGVsbS10ZXN0LXJlZ2lzdHJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAxuVrOJyfUO71wlqe/ae8pNVf3z+6b7aCYRrKJ4l66RKMPz9uP5lHD9QImCTU +LddER48iRr5nzaUKqNUsPn4tTcdaH9EEra+PDp+YeToyZARO+coxCq8yt1NxXrlb +E/q9Ie9QUlruhthrgr+5DC+qogZA8kcVPOs2+ObqeCCO6QGpECxROO2ysXHyjy2b +nwGCzZRz90M4z0ifXcey9RLzbmEsYymq6RbaeQvdzevgXhzIANktILuB0D3wJ2ae +WWP2CfBrjaPbOBtzdDhyl4T1aqLiUpDELUJLVpf/h6xCh52Q0svpsGVGtyO+npPe +kZ1LSVAnVGS6JlWWhs7RL0eaPwIDAQABoyEwHzAdBgNVHREEFjAUghJoZWxtLXRl +c3QtcmVnaXN0cnkwDQYJKoZIhvcNAQELBQADggEBABbxtODFOAeTJg4Q3SXqJ8Gq +zh3/1DaAEnMGHILYuS9tK5lisTLiUerqeQaHKR6U90HK/P1vVxe7PvwfHBrVsGkR +4YC6nivf8LMySKBQmsPUHjdotNZZ8O1pqd+CMqZe2ZuvzLZ4pPdw25lKjhZ7qI+t +hQ8yotiJALzEUWLJSgP5Y8k4hFfRGSso1oAC+WppQeW6ITqDo1MrzH7gpjnp+CJG +NWM1oAQCB1qIdo6gY386w6yLyUhfHtAVa3vviQ0dkRLiK95He5xZcO11rlDNdmgF +cF6lElkci8gPuH8UkKAT5bP9dAEbHPSjAIvg5O9NviknLiNAdFRKeTri+hqNLhE= +-----END CERTIFICATE----- diff --git a/pkg/registry/testdata/tls/client.key b/pkg/registry/testdata/tls/client.key new file mode 100644 index 000000000..2f6a8aa12 --- /dev/null +++ b/pkg/registry/testdata/tls/client.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDG5Ws4nJ9Q7vXC +Wp79p7yk1V/fP7pvtoJhGsoniXrpEow/P24/mUcP1AiYJNQt10RHjyJGvmfNpQqo +1Sw+fi1Nx1of0QStr48On5h5OjJkBE75yjEKrzK3U3FeuVsT+r0h71BSWu6G2GuC +v7kML6qiBkDyRxU86zb45up4II7pAakQLFE47bKxcfKPLZufAYLNlHP3QzjPSJ9d +x7L1EvNuYSxjKarpFtp5C93N6+BeHMgA2S0gu4HQPfAnZp5ZY/YJ8GuNo9s4G3N0 +OHKXhPVqouJSkMQtQktWl/+HrEKHnZDSy+mwZUa3I76ek96RnUtJUCdUZLomVZaG +ztEvR5o/AgMBAAECggEBAKTaovRZXPOIHMrqsb0sun8lHEG+YJkXfRlfSw9aNDXa +2cPSn163fN7xr+3rGLKmKkHlsVNRnlgk46Dsj698hbBh+6FDbc1IJhrIzWgthHbB +23PO0rc4X6Dz2JParlLxELJ/2ONp2yqJVxMYNhiTqaqB5HLr1/6WNwo220CWO92D +vLz3rBHO5Vw5b5Y6Kt6MN6ciIHB2k+obhh4GQRJjUhvmmKCzbk1/R1PFYNwhhMN0 +Av6BdwFgngvNzJ8KMxGia7WJSvDYUk0++RRZ1esiZqwWRVCFFkm4Hj+gKJq6Xnz0 +a2nSvlC9k4GJvD9yY9VcDTJY+WsNN3Ny29gIFUeU9IECgYEA4norD3XakMthgOQk +3NE3HSvpZ22xtVgN9uN0b/JXbg7CLlYzn3tabpbQM/4uI6VG3Mk5Pk83QfKnr4W1 +aYO3YTEQ9B4g0eu3t4zfQOibY2+/Jb7Yfv/fH+pjkI26zYDQn61gsFdV9uxF7Pgu +NGNVe/eY+RkxEWsTtb40jcrbCgsCgYEA4NLWAdlrGKWZP5nLvM1hVB8r4WS82c0e +Orfyv2NhiqfRasARC1lQCqwbmCjb0c/eQiW7lJ7iSECc/8xW3HrJBYpG/tCxi9+m +SWxZXzRXDL8bmuoVvYeA/hFZayef5qCc8eiTYGQp6N5ozQHLXuPbNu7n6YSwvoU4 +ANrVBDRXxR0CgYEAmwbfhPS6iVT+yFjjNthrrqdJXQhElgrRfEfUg3DTEj4+A7P0 +IF4y1/KaUIzUjofrSuTfL1zQSW9OA6M2PCTymTAaF9CrzKZbGuTuSaMwAtASe0b5 +MW37EQDD6MZrsZJUvIjU38DY0m6Hqx9zmV7JvFMPPqxU30R5uHWbyderOmMCgYA5 +P3afIe3TaNeNCmyGtwWBli5mRnCQRVrdONnnQjckR3db52xvp15qWUjthfnzgyrl +TRZm0c5s94cC29WCbwGhF4Tcfee35ktBhwV66KkB5efxmonOqSJ/j4tlbcGZyGwu +bTqZ4OeLFJc7HKncj8jSRCNpoxAec22/SfnUCEARQQKBgAnwaN6kmGqIW2EsNOwB +DXCvG4HI9np5xN5Wo2dz7wqGtrt0TVtJ/PNBL3iadDLyPHahwoEVceFrQwqxjPsV +AoSwVDTdX96PKM/v/2ysw1JLf7UMT59mpxFoYiXCPn5Do4D1/25UfMOsJSmFo1Ij +Hkw1bqG8QneuME16BnDQfY3b +-----END PRIVATE KEY----- diff --git a/pkg/registry/testdata/tls/server-cert.pem b/pkg/registry/testdata/tls/server-cert.pem deleted file mode 100644 index 8d2eda528..000000000 --- a/pkg/registry/testdata/tls/server-cert.pem +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDsTCCApmgAwIBAgIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzEL -MAkGA1UECAwCQ0ExCzAJBgNVBAcMAlNGMQ0wCwYDVQQKDARoZWxtMRowGAYDVQQD -DBFyZWdpc3RyeS10ZXN0LmNvbTAgFw0yMjA5MjAwODI3NDZaGA8yMTIyMDgyNzA4 -Mjc0NlowWTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQHDAJTRjEN -MAsGA1UECgwEaGVsbTEhMB8GA1UEAwwYc2VydmVyLnJlZ2lzdHJ5LXRlc3QuY29t -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxve7spJ44uC/f6BCUEKQ -PA9Sqc+ulTXyptZROLa90o7GK9P1WW8hcDRIYaIU3Rh+o6E0QYwBwvspoEAKYP0q -kp16pD1Ezf5VTikVElq20qvYOaAjvxFltIAmrxoCokkwEIsgEY6RYHZedimKWtdg -kG7R0aNnwgognoz6j4GD/Z/HejCY54jckQczDdaxWrcbBdQ0h/WNjLwHmlids4H9 -ni4cas4An5TZ3cOA9ah+8PSRNYgSLFR34KuydLd8xx5E2fG8OuU5zCNaDQ4puYKP -u+D6GNCdwi+w+Ac/3MTAX8ORLrB/8BCIMwnYi7g7En4a47ck21VqhfE+CH10AR07 -nQIDAQABo4GIMIGFMB8GA1UdIwQYMBaAFJJJjyukiI+D2PGDsPmHq4Sgjku6MAkG -A1UdEwQCMAAwCwYDVR0PBAQDAgTwMCsGA1UdEQQkMCKCCWxvY2FsaG9zdIIKMHg3 -ZjAwMDAwMYIJMTI3LjAuMC4xMB0GA1UdDgQWBBRoIiJ5S3EJmcNUmjT+dxWO+14k -ADANBgkqhkiG9w0BAQsFAAOCAQEAb6UOBss8IA3uT76LIK9TSNSyn6BoYlTFGwgx -O2Cp4kqyKb370qAWV1QVVefQP1uftXpsdqhtwEL4jUptYO5yP4Udtg0QV0SsyMsg -jXgaeuC7589lcJpmTvPj/XlnAZE6vmTrVPG4c1wEC+qCTSHAu3EBRN8hHKZFmLON -254/6x2HlSTqwKzzJY5YEL8pP1kAIww40YMd5G5gFqCNdcg2FKB3ZWo9cFzCU3VK -HoeOUG286GuEN6AG/YT2DIFAZpP+SUgjY8mj1CxoIv9LMNyF1Tm8kzQDU0IA2dfW -1AY0edoHL2kLoUUKet/d7tayP9gnt0sOUrY2oZXrp+TvSHVTlw== ------END CERTIFICATE----- diff --git a/pkg/registry/testdata/tls/server-key.pem b/pkg/registry/testdata/tls/server-key.pem deleted file mode 100644 index 28bcbe214..000000000 --- a/pkg/registry/testdata/tls/server-key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDG97uyknji4L9/ -oEJQQpA8D1Kpz66VNfKm1lE4tr3SjsYr0/VZbyFwNEhhohTdGH6joTRBjAHC+ymg -QApg/SqSnXqkPUTN/lVOKRUSWrbSq9g5oCO/EWW0gCavGgKiSTAQiyARjpFgdl52 -KYpa12CQbtHRo2fCCiCejPqPgYP9n8d6MJjniNyRBzMN1rFatxsF1DSH9Y2MvAea -WJ2zgf2eLhxqzgCflNndw4D1qH7w9JE1iBIsVHfgq7J0t3zHHkTZ8bw65TnMI1oN -Dim5go+74PoY0J3CL7D4Bz/cxMBfw5EusH/wEIgzCdiLuDsSfhrjtyTbVWqF8T4I -fXQBHTudAgMBAAECggEAD13Tr7tzPaZ487znUjaJ2DGgwz+obpqvhmYX+MbYSzo+ -oOTqVoFoNje7fVrcvKSnJzEMjaFoA2yNbvRzOMFkt9UUwzl+JmClqvcuSvAZnZSr -CuxMxnVsAvBAzJY4LNt1LFnqXKDDpo0Nx5d2uYRXz1/XsZaqrUhF86jUsx+gF4bM -LYe6SjXWtf1sumgE1gbil8NDLbqHPMvimQhLu1WgVxiarlye2NMyHxk6MTqwYOX3 -iinf3cuRFYuFyD1IHorreVAdOH0zuYvqLFylBbRqEfeOozVytX73yKfRK4lPobc+ -Q1n/mPzwyc9aVWKRo4WId0mA2rhP8sL7BvMFRwYnSwKBgQDdUqlel4/Fj2WfcsKa -SMjmqM66tFDxH27Vp55RoS/Fr+RZSVYda7cdbMJaGVswbZevwsCS46l2BJJdJXHt -UE1viKkKiIxGJzpH9Q1vyUEf+21eESnkr7HKoUrSpopwqOlc1dYPvn47aJukcGee -vwMkiaG5IUaR5MCfLA8xQ89UPwKBgQDmJGWtrwcUIdEvRI1wg8Unj0chAyz+/KIR -9jkVIyu4SUfThQp6GsCHsvc5TGN6yieGLIfrVb7qb8F2gDPdg8L/13zqAorpcK6E -AagYLDgKWV4O2oGT4AGQrcz/66BYAfeD868r442bhyEkD7zLqZSbHlPTpy8bPKuC -nen88JGJIwKBgD/OawHYVByywKt9XFk6jqDhHeh5v7QkScHS9zO1cp5dnUmYePk2 -aq5TAp0THlUR419KmFZAyEQ8AS5Vc0jlk82J6qIcx8QZ3xWLsnn93Yao59jsvdUu -SeWPJpEgbl0YdV7MT1BurNnXyLdZqKX9j5xjCXrj+wJonpfFDgQ39nflAoGAd1bo -YuggA5CFqL0jmvS5h4oEmFnNO2xFnorPjuZuBWH6nPSgOjElJTjoeg3iiAnL9Qei -c6ZDGc5Zw9k3C+cHdyOG4tHutp534Hv7bo1/gd5Vp94m00eViDCX3R2SSBC9CO+U -Jm4ZQE0SImEGxZVqOgW/8kD/bGBJj7HTZBZbYYECgYEAoGwLnE2TiMLfXIKXsmII -h9+rZrPfFyDCM27+QIADpCv7Ae2cIGanqSbyPJrFWD4CRXBv+92L2LyG7yA9C498 -uyMJ98DVp4SAaNWFha+JCz5TO6KCXOuwGrQTSUitqxQ2rMv2WpXnO2T8puvXW8dD -mxfiHuvNMNHfA9Bd4tsbbPE= ------END PRIVATE KEY----- diff --git a/pkg/registry/testdata/tls/server.crt b/pkg/registry/testdata/tls/server.crt new file mode 100644 index 000000000..5fae09bb9 --- /dev/null +++ b/pkg/registry/testdata/tls/server.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDWzCCAkOgAwIBAgIUdJ6uRYm6RYesJ3CRoLokemFFgX4wDQYJKoZIhvcNAQEL +BQAwUzELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkdEMQswCQYDVQQHDAJTWjETMBEG +A1UECgwKQWNtZSwgSW5jLjEVMBMGA1UEAwwMQWNtZSBSb290IENBMB4XDTIzMDYw +ODEwNTAzM1oXDTI0MDYwNzEwNTAzM1owWTELMAkGA1UEBhMCQ04xCzAJBgNVBAgM +AkdEMQswCQYDVQQHDAJTWjETMBEGA1UECgwKQWNtZSwgSW5jLjEbMBkGA1UEAwwS +aGVsbS10ZXN0LXJlZ2lzdHJ5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA59jg4ml82uyvrg+tXf/0S8WHuayl5fB3k1lIPtOrTt5KBNh6z5XHZDogsQ3m +UEko4gVUvKL0Einm1i5c3C6KFFj0RNib0QpOZtxu54mx2Rxazkge0yjoTMwl/P1o +pvRI6qfRri8LdlqWwU9wBIYmKqEM8jPjxKcCOaR0WyQmEJ6KbayTzsVNHaQxG/f3 +aIDCkp3tFl+LaTJHjGdZN7tvJsZ1wXlQy6gXTJIPXHDTS/uh3Xp8jgqhlnQPIr44 +HikiAp9DMnOBGO4u4cZjCr04cQnLS9knsBAQCjja9J9DnZ5vKatBHF3nOVAtGoBM +o69HcYoX5F10Qg8YOa7QwIYjpQIDAQABoyEwHzAdBgNVHREEFjAUghJoZWxtLXRl +c3QtcmVnaXN0cnkwDQYJKoZIhvcNAQELBQADggEBABMYICc/rzijGhFPFOeSrXyk +xFX9SSrGMl0CzV44sxzJFJ89BrW9bUWf4rLuc2ugqWp78kRKGMKgaytDrmGGuZKy +Qy+xl3DTAoc9FYOBphtcH1QndWdbpKSc2sTKvdeV6SslKwWXlAvcqIain80fWAkn +J+9Fd/rq3sJxCYsYhEf17pDjHDnG5ZUsBAWWzN+YjtSAe4PzT1KdljUPCC1GbF+H +1dx+MwapV+atftzlGjld8H73MXrKRNUSZM5lEFvzCZz48J1Ml6UVnYO+QCybeJtQ +lBT3/wclJ86e0eNkZJI0WTmrqlaNS/J7mbZ+4BhfjuO5PyZbLg8DcWmaKeNtT8M= +-----END CERTIFICATE----- diff --git a/pkg/registry/testdata/tls/server.key b/pkg/registry/testdata/tls/server.key new file mode 100644 index 000000000..da44121a7 --- /dev/null +++ b/pkg/registry/testdata/tls/server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDn2ODiaXza7K+u +D61d//RLxYe5rKXl8HeTWUg+06tO3koE2HrPlcdkOiCxDeZQSSjiBVS8ovQSKebW +LlzcLooUWPRE2JvRCk5m3G7nibHZHFrOSB7TKOhMzCX8/Wim9Ejqp9GuLwt2WpbB +T3AEhiYqoQzyM+PEpwI5pHRbJCYQnoptrJPOxU0dpDEb9/dogMKSne0WX4tpMkeM +Z1k3u28mxnXBeVDLqBdMkg9ccNNL+6HdenyOCqGWdA8ivjgeKSICn0Myc4EY7i7h +xmMKvThxCctL2SewEBAKONr0n0Odnm8pq0EcXec5UC0agEyjr0dxihfkXXRCDxg5 +rtDAhiOlAgMBAAECggEBAJ6kfFzwqYpz4lJMT+i+Nz+RzilyxaHtRSUCNrkmxVWW +LTfbmU1pw6IFVFFSnYHaTas60pyxNCkpmtZ7qvbOsZTyuVJSlWwYjUU9GHY+df+F +s2zrVIxQtYO3PVc7Xty+0xYd9xAlCMbXfciQvqmZ0Yvh36Xrc7MgRBmFOkkTFyjO +xaT70D5jwK0QKU8sMY+b9XvvaX59jbRmYAHL0wNcke/E7J4NKEAYfRI+x7kuFhP4 +yDbs9YE0u51cHYAGV4EujZhnv2AwvDnAWs0yHqIbVOIWI9+JRYKmPScr7b1bJfd/ +yy24GXvBu7Ss4TkfsJ/FdGXESr0Gj0ZIPIneDn/vrQECgYEA9jHu4FjTbRff+4tV +3zJJe88+yByjC6Hhj223JmRpCXQrXl2WLAYXl94p7M5NFdkD5QG7jsNUogLb73dV +ekUjuQl7IhJZYcRAXcnlkF+8pKt1duA0uRa22VtlR2wyn8oSnLV/9088Moh35sCP +MjWQDlZ/BW7YUPrOtB14eUCvMjECgYEA8RSpmXZVQdGnIIm6gC3rEhtfHQqAoBn0 +JRvnRXC/LKeVSgVF3ijeT9P/0JQuM9uxubV314nY+fhXsM5kkMZUoXMMSoxE+xPw +cgArpzwsleMn7BQ/UF3GLpdkUgNFI8bolZFbIa54F7YSFNto0NBp3mkceCJwoWmZ +BPIoo4zpV7UCgYEAviK2L8GqF5jWvPhRK300z0+xVu725ObywsijKB1oGYsEa26v +qfRSiFFl46M4WWUu4tBBv/IPDMhUf06UT0fSXPd7h0bQjPb6FvT0PFoT4MEiiNqD +HWbzdE5nm49uUYXIdgqed6tT/Fr07ttMPCStysT2eIWwvmnU9bnE7zALniECgYAr +HM7XqtnEU4HXx8macpu/OTXhM6ec+gc3O644NNl7WtzPx/GesSBQllEBM/6vN3Kp +C1LLMNOkoEzOSZqiaVVpKfHgwwTzAbXWLUGhPpmalGznQxevf5WZb2l5YSxUIZYm +aUAq3dCMLPs+z54G+b51D8cPlNkfhIrg34108hYooQKBgQDWMbc6wY6frvJCmesx +i7F/JHJweqcQdW649RCvtK8M/O062/3vvSNTxqEjPaJOGiD4Cn+D5pYchVujqlTM +8DK77N97NzQvpHm81lpKVIg5sObarvT3RnCSRpOumbX5SCBoBUs+nVC01/zZz79c +AJFLAeHI1RjhB0AFpRDCvZZk6w== +-----END PRIVATE KEY----- diff --git a/pkg/registry/util.go b/pkg/registry/util.go index 8baf0852a..ca93297e6 100644 --- a/pkg/registry/util.go +++ b/pkg/registry/util.go @@ -19,6 +19,7 @@ package registry // import "helm.sh/helm/v3/pkg/registry" import ( "bytes" "context" + "encoding/base64" "fmt" "io" "net/http" @@ -245,3 +246,13 @@ func addToMap(inputMap map[string]string, newKey string, newValue string) map[st return inputMap } + +// See 2 (end of page 4) https://www.ietf.org/rfc/rfc2617.txt +// "To receive authorization, the client sends the userid and password, +// separated by a single colon (":") character, within a base64 +// encoded string in the credentials." +// It is not meant to be urlencoded. +func basicAuth(username, password string) string { + auth := username + ":" + password + return base64.StdEncoding.EncodeToString([]byte(auth)) +} diff --git a/pkg/registry/util_test.go b/pkg/registry/util_test.go index fdf09360b..f08c1fef1 100644 --- a/pkg/registry/util_test.go +++ b/pkg/registry/util_test.go @@ -238,3 +238,31 @@ func TestGenerateOCICreatedAnnotations(t *testing.T) { } } + +func Test_basicAuth(t *testing.T) { + type args struct { + username string + password string + } + tests := []struct { + name string + args args + want string + }{ + { + name: "Basic Auth", + args: args{ + username: "admin", + password: "passw0rd", + }, + want: "YWRtaW46cGFzc3cwcmQ=", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := basicAuth(tt.args.username, tt.args.password); got != tt.want { + t.Errorf("basicAuth() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/registry/utils_test.go b/pkg/registry/utils_test.go index 664a3d84c..74aa0dbc0 100644 --- a/pkg/registry/utils_test.go +++ b/pkg/registry/utils_test.go @@ -44,11 +44,11 @@ import ( ) const ( - tlsServerKey = "./testdata/tls/server-key.pem" - tlsServerCert = "./testdata/tls/server-cert.pem" - tlsCA = "./testdata/tls/ca-cert.pem" - tlsKey = "./testdata/tls/client-key.pem" - tlsCert = "./testdata/tls/client-cert.pem" + tlsServerKey = "./testdata/tls/server.key" + tlsServerCert = "./testdata/tls/server.crt" + tlsCA = "./testdata/tls/ca.crt" + tlsKey = "./testdata/tls/client.key" + tlsCert = "./testdata/tls/client.crt" ) var ( @@ -70,7 +70,7 @@ type TestSuite struct { srv *mockdns.Server } -func setup(suite *TestSuite, tlsEnabled bool, insecure bool) *registry.Registry { +func setup(suite *TestSuite, tlsEnabled, insecure bool) *registry.Registry { suite.WorkspaceDir = testWorkspaceDir os.RemoveAll(suite.WorkspaceDir) os.Mkdir(suite.WorkspaceDir, 0700) @@ -83,31 +83,33 @@ func setup(suite *TestSuite, tlsEnabled bool, insecure bool) *registry.Registry credentialsFile := filepath.Join(suite.WorkspaceDir, CredentialsFileBasename) // init test client + opts := []ClientOption{ + ClientOptDebug(true), + ClientOptEnableCache(true), + ClientOptWriter(suite.Out), + ClientOptCredentialsFile(credentialsFile), + ClientOptResolver(nil), + } + if tlsEnabled { var tlsConf *tls.Config - tlsConf, err = tlsutil.NewClientTLS(tlsCert, tlsKey, tlsCA, insecure) + if insecure { + tlsConf, err = tlsutil.NewClientTLS("", "", "", true) + } else { + tlsConf, err = tlsutil.NewClientTLS(tlsCert, tlsKey, tlsCA, false) + } httpClient := &http.Client{ Transport: &http.Transport{ TLSClientConfig: tlsConf, }, } - suite.Nil(err, "no error loading tlsconfog") - suite.RegistryClient, err = NewClient( - ClientOptDebug(true), - ClientOptEnableCache(true), - ClientOptWriter(suite.Out), - ClientOptCredentialsFile(credentialsFile), - ClientOptHTTPClient(httpClient), - ) + suite.Nil(err, "no error loading tls config") + opts = append(opts, ClientOptHTTPClient(httpClient)) } else { - suite.RegistryClient, err = NewClient( - ClientOptDebug(true), - ClientOptEnableCache(true), - ClientOptWriter(suite.Out), - ClientOptCredentialsFile(credentialsFile), - ) + opts = append(opts, ClientOptPlainHTTP()) } + suite.RegistryClient, err = NewClient(opts...) suite.Nil(err, "no error creating registry client") // create htpasswd file (w BCrypt, which is required) @@ -121,33 +123,30 @@ func setup(suite *TestSuite, tlsEnabled bool, insecure bool) *registry.Registry config := &configuration.Configuration{} port, err := freeport.GetFreePort() suite.Nil(err, "no error finding free port for test registry") - if tlsEnabled { - // docker has "MatchLocalhost is a host match function which returns true for - // localhost, and is used to enforce http for localhost requests." - // That function does not handle matching of ip addresses in octal, - // decimal or hex form. - suite.DockerRegistryHost = fmt.Sprintf("0x7f000001:%d", port) - - // As of Go 1.20, Go may lookup "0x7f000001" as a DNS entry and fail. - // Using a mock DNS server to handle the address. - suite.srv, _ = mockdns.NewServer(map[string]mockdns.Zone{ - "0x7f000001.": { - A: []string{"127.0.0.1"}, - }, - }, false) - suite.srv.PatchNet(net.DefaultResolver) - } else { - suite.DockerRegistryHost = fmt.Sprintf("localhost:%d", port) - } + + // Change the registry host to another host which is not localhost. + // This is required because Docker enforces HTTP if the registry + // host is localhost/127.0.0.1. + suite.DockerRegistryHost = fmt.Sprintf("helm-test-registry:%d", port) + suite.srv, _ = mockdns.NewServer(map[string]mockdns.Zone{ + "helm-test-registry.": { + A: []string{"127.0.0.1"}, + }, + }, false) + suite.srv.PatchNet(net.DefaultResolver) + config.HTTP.Addr = fmt.Sprintf(":%d", port) - // config.HTTP.Addr = fmt.Sprintf("127.0.0.1:%d", port) config.HTTP.DrainTimeout = time.Duration(10) * time.Second config.Storage = map[string]configuration.Parameters{"inmemory": map[string]interface{}{}} - config.Auth = configuration.Auth{ - "htpasswd": configuration.Parameters{ - "realm": "localhost", - "path": htpasswdPath, - }, + + // Basic auth is not possible if we are serving HTTP. + if tlsEnabled { + config.Auth = configuration.Auth{ + "htpasswd": configuration.Parameters{ + "realm": "localhost", + "path": htpasswdPath, + }, + } } // config tls @@ -157,7 +156,10 @@ func setup(suite *TestSuite, tlsEnabled bool, insecure bool) *registry.Registry // server tls config config.HTTP.TLS.Certificate = tlsServerCert config.HTTP.TLS.Key = tlsServerKey - config.HTTP.TLS.ClientCAs = []string{tlsCA} + // Skip client authentication if the registry is insecure. + if !insecure { + config.HTTP.TLS.ClientCAs = []string{tlsCA} + } } dockerRegistry, err := registry.NewRegistry(context.Background(), config) suite.Nil(err, "no error creating test registry") diff --git a/pkg/releaseutil/kind_sorter.go b/pkg/releaseutil/kind_sorter.go index 1d1874cfa..b5d75b88b 100644 --- a/pkg/releaseutil/kind_sorter.go +++ b/pkg/releaseutil/kind_sorter.go @@ -29,6 +29,7 @@ type KindSortOrder []string // // Those occurring earlier in the list get installed before those occurring later in the list. var InstallOrder KindSortOrder = []string{ + "PriorityClass", "Namespace", "NetworkPolicy", "ResourceQuota", @@ -105,6 +106,7 @@ var UninstallOrder KindSortOrder = []string{ "ResourceQuota", "NetworkPolicy", "Namespace", + "PriorityClass", } // sort manifests by kind. diff --git a/pkg/releaseutil/kind_sorter_test.go b/pkg/releaseutil/kind_sorter_test.go index afcae6d16..9e24c4399 100644 --- a/pkg/releaseutil/kind_sorter_test.go +++ b/pkg/releaseutil/kind_sorter_test.go @@ -169,6 +169,10 @@ func TestKindSorter(t *testing.T) { Name: "x", Head: &SimpleHead{Kind: "HorizontalPodAutoscaler"}, }, + { + Name: "F", + Head: &SimpleHead{Kind: "PriorityClass"}, + }, } for _, test := range []struct { @@ -176,8 +180,8 @@ func TestKindSorter(t *testing.T) { order KindSortOrder expected string }{ - {"install", InstallOrder, "aAbcC3deEf1gh2iIjJkKlLmnopqrxstuUvw!"}, - {"uninstall", UninstallOrder, "wvUmutsxrqponLlKkJjIi2hg1fEed3CcbAa!"}, + {"install", InstallOrder, "FaAbcC3deEf1gh2iIjJkKlLmnopqrxstuUvw!"}, + {"uninstall", UninstallOrder, "wvUmutsxrqponLlKkJjIi2hg1fEed3CcbAaF!"}, } { var buf bytes.Buffer t.Run(test.description, func(t *testing.T) { diff --git a/pkg/repo/chartrepo_test.go b/pkg/repo/chartrepo_test.go index b32834220..4d4395c2d 100644 --- a/pkg/repo/chartrepo_test.go +++ b/pkg/repo/chartrepo_test.go @@ -30,7 +30,6 @@ import ( "sigs.k8s.io/yaml" - "helm.sh/helm/v3/internal/test/ensure" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/cli" "helm.sh/helm/v3/pkg/getter" @@ -147,8 +146,7 @@ func TestIndexCustomSchemeDownload(t *testing.T) { if err != nil { t.Fatalf("Problem loading chart repository from %s: %v", repoURL, err) } - repo.CachePath = ensure.TempDir(t) - defer os.RemoveAll(repo.CachePath) + repo.CachePath = t.TempDir() tempIndexFile, err := os.CreateTemp("", "test-repo") if err != nil { @@ -349,7 +347,7 @@ func TestFindChartInRepoURL(t *testing.T) { func TestErrorFindChartInRepoURL(t *testing.T) { g := getter.All(&cli.EnvSettings{ - RepositoryCache: ensure.TempDir(t), + RepositoryCache: t.TempDir(), }) if _, err := FindChartInRepoURL("http://someserver/something", "nginx", "", "", "", "", g); err == nil { diff --git a/pkg/repo/index.go b/pkg/repo/index.go index ba2e365c8..8a23ba060 100644 --- a/pkg/repo/index.go +++ b/pkg/repo/index.go @@ -18,6 +18,7 @@ package repo import ( "bytes" + "encoding/json" "log" "os" "path" @@ -232,6 +233,18 @@ func (i IndexFile) WriteFile(dest string, mode os.FileMode) error { return fileutil.AtomicWriteFile(dest, bytes.NewReader(b), mode) } +// WriteJSONFile writes an index file in JSON format to the given destination +// path. +// +// The mode on the file is set to 'mode'. +func (i IndexFile) WriteJSONFile(dest string, mode os.FileMode) error { + b, err := json.MarshalIndent(i, "", " ") + if err != nil { + return err + } + return fileutil.AtomicWriteFile(dest, bytes.NewReader(b), mode) +} + // Merge merges the given index file into this index. // // This merges by name and version. @@ -336,7 +349,7 @@ func loadIndex(data []byte, source string) (*IndexFile, error) { return i, ErrEmptyIndexYaml } - if err := yaml.UnmarshalStrict(data, i); err != nil { + if err := jsonOrYamlUnmarshal(data, i); err != nil { return i, err } @@ -361,3 +374,17 @@ func loadIndex(data []byte, source string) (*IndexFile, error) { } return i, nil } + +// jsonOrYamlUnmarshal unmarshals the given byte slice containing JSON or YAML +// into the provided interface. +// +// It automatically detects whether the data is in JSON or YAML format by +// checking its validity as JSON. If the data is valid JSON, it will use the +// `encoding/json` package to unmarshal it. Otherwise, it will use the +// `sigs.k8s.io/yaml` package to unmarshal the YAML data. +func jsonOrYamlUnmarshal(b []byte, i interface{}) error { + if json.Valid(b) { + return json.Unmarshal(b, i) + } + return yaml.UnmarshalStrict(b, i) +} diff --git a/pkg/repo/index_test.go b/pkg/repo/index_test.go index bbc48c97e..efb50ba6a 100644 --- a/pkg/repo/index_test.go +++ b/pkg/repo/index_test.go @@ -19,6 +19,7 @@ package repo import ( "bufio" "bytes" + "encoding/json" "net/http" "os" "path/filepath" @@ -37,6 +38,7 @@ const ( annotationstestfile = "testdata/local-index-annotations.yaml" chartmuseumtestfile = "testdata/chartmuseum-index.yaml" unorderedTestfile = "testdata/local-index-unordered.yaml" + jsonTestfile = "testdata/local-index.json" testRepo = "test-repo" indexWithDuplicates = ` apiVersion: v1 @@ -145,6 +147,10 @@ func TestLoadIndex(t *testing.T) { Name: "chartmuseum index file", Filename: chartmuseumtestfile, }, + { + Name: "JSON index file", + Filename: jsonTestfile, + }, } for _, tc := range tests { @@ -548,6 +554,27 @@ func TestIndexWrite(t *testing.T) { } } +func TestIndexJSONWrite(t *testing.T) { + i := NewIndexFile() + if err := i.MustAdd(&chart.Metadata{APIVersion: "v2", Name: "clipper", Version: "0.1.0"}, "clipper-0.1.0.tgz", "http://example.com/charts", "sha256:1234567890"); err != nil { + t.Fatalf("unexpected error: %s", err) + } + dir := t.TempDir() + testpath := filepath.Join(dir, "test") + i.WriteJSONFile(testpath, 0600) + + got, err := os.ReadFile(testpath) + if err != nil { + t.Fatal(err) + } + if !json.Valid(got) { + t.Fatal("Index files doesn't contain valid JSON") + } + if !strings.Contains(string(got), "clipper-0.1.0.tgz") { + t.Fatal("Index files doesn't contain expected content") + } +} + func TestAddFileIndexEntriesNil(t *testing.T) { i := NewIndexFile() i.APIVersion = chart.APIVersionV1 diff --git a/pkg/repo/repotest/server_test.go b/pkg/repo/repotest/server_test.go index d16552897..a7d7f5b95 100644 --- a/pkg/repo/repotest/server_test.go +++ b/pkg/repo/repotest/server_test.go @@ -18,7 +18,6 @@ package repotest import ( "io" "net/http" - "os" "path/filepath" "testing" @@ -31,10 +30,9 @@ import ( // Young'n, in these here parts, we test our tests. func TestServer(t *testing.T) { - defer ensure.HelmHome(t)() + ensure.HelmHome(t) - rootDir := ensure.TempDir(t) - defer os.RemoveAll(rootDir) + rootDir := t.TempDir() srv := NewServer(rootDir) defer srv.Stop() @@ -99,7 +97,7 @@ func TestServer(t *testing.T) { } func TestNewTempServer(t *testing.T) { - defer ensure.HelmHome(t)() + ensure.HelmHome(t) srv, err := NewTempServerWithCleanup(t, "testdata/examplechart-0.1.0.tgz") if err != nil { diff --git a/pkg/repo/testdata/local-index.json b/pkg/repo/testdata/local-index.json new file mode 100644 index 000000000..25296d5ca --- /dev/null +++ b/pkg/repo/testdata/local-index.json @@ -0,0 +1,53 @@ +{ + "apiVersion": "v1", + "entries": { + "nginx": [ + { + "urls": ["https://charts.helm.sh/stable/nginx-0.2.0.tgz"], + "name": "nginx", + "description": "string", + "version": "0.2.0", + "home": "https://github.com/something/else", + "digest": "sha256:1234567890abcdef", + "keywords": ["popular", "web server", "proxy"], + "apiVersion": "v2" + }, + { + "urls": ["https://charts.helm.sh/stable/nginx-0.1.0.tgz"], + "name": "nginx", + "description": "string", + "version": "0.1.0", + "home": "https://github.com/something", + "digest": "sha256:1234567890abcdef", + "keywords": ["popular", "web server", "proxy"], + "apiVersion": "v2" + } + ], + "alpine": [ + { + "urls": [ + "https://charts.helm.sh/stable/alpine-1.0.0.tgz", + "http://storage2.googleapis.com/kubernetes-charts/alpine-1.0.0.tgz" + ], + "name": "alpine", + "description": "string", + "version": "1.0.0", + "home": "https://github.com/something", + "keywords": ["linux", "alpine", "small", "sumtin"], + "digest": "sha256:1234567890abcdef", + "apiVersion": "v2" + } + ], + "chartWithNoURL": [ + { + "name": "chartWithNoURL", + "description": "string", + "version": "1.0.0", + "home": "https://github.com/something", + "keywords": ["small", "sumtin"], + "digest": "sha256:1234567890abcdef", + "apiVersion": "v2" + } + ] + } +} diff --git a/pkg/storage/driver/cfgmaps.go b/pkg/storage/driver/cfgmaps.go index a63fec011..0f3ec38a0 100644 --- a/pkg/storage/driver/cfgmaps.go +++ b/pkg/storage/driver/cfgmaps.go @@ -78,6 +78,7 @@ func (cfgmaps *ConfigMaps) Get(key string) (*rspb.Release, error) { cfgmaps.Log("get: failed to decode data %q: %s", key, err) return nil, err } + r.Labels = filterSystemLabels(obj.ObjectMeta.Labels) // return the release object return r, nil } @@ -106,7 +107,7 @@ func (cfgmaps *ConfigMaps) List(filter func(*rspb.Release) bool) ([]*rspb.Releas continue } - rls.Labels = item.ObjectMeta.Labels + rls.Labels = filterSystemLabels(item.ObjectMeta.Labels) if filter(rls) { results = append(results, rls) @@ -145,6 +146,7 @@ func (cfgmaps *ConfigMaps) Query(labels map[string]string) ([]*rspb.Release, err cfgmaps.Log("query: failed to decode release: %s", err) continue } + rls.Labels = filterSystemLabels(item.ObjectMeta.Labels) results = append(results, rls) } return results, nil @@ -157,6 +159,7 @@ func (cfgmaps *ConfigMaps) Create(key string, rls *rspb.Release) error { var lbs labels lbs.init() + lbs.fromMap(rls.Labels) lbs.set("createdAt", strconv.Itoa(int(time.Now().Unix()))) // create a new configmap to hold the release @@ -184,6 +187,7 @@ func (cfgmaps *ConfigMaps) Update(key string, rls *rspb.Release) error { var lbs labels lbs.init() + lbs.fromMap(rls.Labels) lbs.set("modifiedAt", strconv.Itoa(int(time.Now().Unix()))) // create a new configmap object to hold the release @@ -239,6 +243,9 @@ func newConfigMapsObject(key string, rls *rspb.Release, lbs labels) (*v1.ConfigM lbs.init() } + // apply custom labels + lbs.fromMap(rls.Labels) + // apply labels lbs.set("name", rls.Name) lbs.set("owner", owner) diff --git a/pkg/storage/driver/mock_test.go b/pkg/storage/driver/mock_test.go index c0236ece8..7a1541a02 100644 --- a/pkg/storage/driver/mock_test.go +++ b/pkg/storage/driver/mock_test.go @@ -40,6 +40,10 @@ func releaseStub(name string, vers int, namespace string, status rspb.Status) *r Version: vers, Namespace: namespace, Info: &rspb.Info{Status: status}, + Labels: map[string]string{ + "key1": "val1", + "key2": "val2", + }, } } diff --git a/pkg/storage/driver/secrets.go b/pkg/storage/driver/secrets.go index 56df54040..224026b07 100644 --- a/pkg/storage/driver/secrets.go +++ b/pkg/storage/driver/secrets.go @@ -72,6 +72,7 @@ func (secrets *Secrets) Get(key string) (*rspb.Release, error) { } // found the secret, decode the base64 data string r, err := decodeRelease(string(obj.Data["release"])) + r.Labels = filterSystemLabels(obj.ObjectMeta.Labels) return r, errors.Wrapf(err, "get: failed to decode data %q", key) } @@ -98,7 +99,7 @@ func (secrets *Secrets) List(filter func(*rspb.Release) bool) ([]*rspb.Release, continue } - rls.Labels = item.ObjectMeta.Labels + rls.Labels = filterSystemLabels(item.ObjectMeta.Labels) if filter(rls) { results = append(results, rls) @@ -136,6 +137,7 @@ func (secrets *Secrets) Query(labels map[string]string) ([]*rspb.Release, error) secrets.Log("query: failed to decode release: %s", err) continue } + rls.Labels = filterSystemLabels(item.ObjectMeta.Labels) results = append(results, rls) } return results, nil @@ -148,6 +150,7 @@ func (secrets *Secrets) Create(key string, rls *rspb.Release) error { var lbs labels lbs.init() + lbs.fromMap(rls.Labels) lbs.set("createdAt", strconv.Itoa(int(time.Now().Unix()))) // create a new secret to hold the release @@ -173,6 +176,7 @@ func (secrets *Secrets) Update(key string, rls *rspb.Release) error { var lbs labels lbs.init() + lbs.fromMap(rls.Labels) lbs.set("modifiedAt", strconv.Itoa(int(time.Now().Unix()))) // create a new secret object to hold the release @@ -221,6 +225,9 @@ func newSecretsObject(key string, rls *rspb.Release, lbs labels) (*v1.Secret, er lbs.init() } + // apply custom labels + lbs.fromMap(rls.Labels) + // apply labels lbs.set("name", rls.Name) lbs.set("owner", owner) diff --git a/pkg/storage/driver/sql.go b/pkg/storage/driver/sql.go index c8a6ae04f..892f10bbb 100644 --- a/pkg/storage/driver/sql.go +++ b/pkg/storage/driver/sql.go @@ -49,6 +49,7 @@ const postgreSQLDialect = "postgres" const SQLDriverName = "SQL" const sqlReleaseTableName = "releases_v1" +const sqlCustomLabelsTableName = "custom_labels_v1" const ( sqlReleaseTableKeyColumn = "key" @@ -61,6 +62,17 @@ const ( sqlReleaseTableOwnerColumn = "owner" sqlReleaseTableCreatedAtColumn = "createdAt" sqlReleaseTableModifiedAtColumn = "modifiedAt" + + sqlCustomLabelsTableReleaseKeyColumn = "releaseKey" + sqlCustomLabelsTableReleaseNamespaceColumn = "releaseNamespace" + sqlCustomLabelsTableKeyColumn = "key" + sqlCustomLabelsTableValueColumn = "value" +) + +// Following limits based on k8s labels limits - https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#syntax-and-character-set +const ( + sqlCustomLabelsTableKeyMaxLenght = 253 + 1 + 63 + sqlCustomLabelsTableValueMaxLenght = 63 ) const ( @@ -82,8 +94,42 @@ func (s *SQL) Name() string { return SQLDriverName } +// Check if all migrations al +func (s *SQL) checkAlreadyApplied(migrations []*migrate.Migration) bool { + // make map (set) of ids for fast search + migrationsIds := make(map[string]struct{}) + for _, migration := range migrations { + migrationsIds[migration.Id] = struct{}{} + } + + // get list of applied migrations + migrate.SetDisableCreateTable(true) + records, err := migrate.GetMigrationRecords(s.db.DB, postgreSQLDialect) + migrate.SetDisableCreateTable(false) + if err != nil { + s.Log("checkAlreadyApplied: failed to get migration records: %v", err) + return false + } + + for _, record := range records { + if _, ok := migrationsIds[record.Id]; ok { + s.Log("checkAlreadyApplied: found previous migration (Id: %v) applied at %v", record.Id, record.AppliedAt) + delete(migrationsIds, record.Id) + } + } + + // check if all migrations appliyed + if len(migrationsIds) != 0 { + for id := range migrationsIds { + s.Log("checkAlreadyApplied: find unapplied migration (id: %v)", id) + } + return false + } + return true +} + func (s *SQL) ensureDBSetup() error { - // Populate the database with the relations we need if they don't exist yet + migrations := &migrate.MemoryMigrationSource{ Migrations: []*migrate.Migration{ { @@ -109,9 +155,9 @@ func (s *SQL) ensureDBSetup() error { CREATE INDEX ON %s (%s); CREATE INDEX ON %s (%s); CREATE INDEX ON %s (%s); - + GRANT ALL ON %s TO PUBLIC; - + ALTER TABLE %s ENABLE ROW LEVEL SECURITY; `, sqlReleaseTableName, @@ -150,9 +196,50 @@ func (s *SQL) ensureDBSetup() error { `, sqlReleaseTableName), }, }, + { + Id: "custom_labels", + Up: []string{ + fmt.Sprintf(` + CREATE TABLE %s ( + %s VARCHAR(64), + %s VARCHAR(67), + %s VARCHAR(%d), + %s VARCHAR(%d) + ); + CREATE INDEX ON %s (%s, %s); + + GRANT ALL ON %s TO PUBLIC; + ALTER TABLE %s ENABLE ROW LEVEL SECURITY; + `, + sqlCustomLabelsTableName, + sqlCustomLabelsTableReleaseKeyColumn, + sqlCustomLabelsTableReleaseNamespaceColumn, + sqlCustomLabelsTableKeyColumn, + sqlCustomLabelsTableKeyMaxLenght, + sqlCustomLabelsTableValueColumn, + sqlCustomLabelsTableValueMaxLenght, + sqlCustomLabelsTableName, + sqlCustomLabelsTableReleaseKeyColumn, + sqlCustomLabelsTableReleaseNamespaceColumn, + sqlCustomLabelsTableName, + sqlCustomLabelsTableName, + ), + }, + Down: []string{ + fmt.Sprintf(` + DELETE TABLE %s; + `, sqlCustomLabelsTableName), + }, + }, }, } + // Check that init migration already applied + if s.checkAlreadyApplied(migrations.Migrations) { + return nil + } + + // Populate the database with the relations we need if they don't exist yet _, err := migrate.Exec(s.db.DB, postgreSQLDialect, migrations, migrate.Up) return err } @@ -180,6 +267,13 @@ type SQLReleaseWrapper struct { ModifiedAt int `db:"modifiedAt"` } +type SQLReleaseCustomLabelWrapper struct { + ReleaseKey string `db:"release_key"` + ReleaseNamespace string `db:"release_namespace"` + Key string `db:"key"` + Value string `db:"value"` +} + // NewSQL initializes a new sql driver. func NewSQL(connectionString string, logger func(string, ...interface{}), namespace string) (*SQL, error) { db, err := sqlx.Connect(postgreSQLDialect, connectionString) @@ -230,13 +324,18 @@ func (s *SQL) Get(key string) (*rspb.Release, error) { return nil, err } + if release.Labels, err = s.getReleaseCustomLabels(key, s.namespace); err != nil { + s.Log("failed to get release %s/%s custom labels: %v", s.namespace, key, err) + return nil, err + } + return release, nil } // List returns the list of all releases such that filter(release) == true func (s *SQL) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error) { sb := s.statementBuilder. - Select(sqlReleaseTableBodyColumn). + Select(sqlReleaseTableKeyColumn, sqlReleaseTableNamespaceColumn, sqlReleaseTableBodyColumn). From(sqlReleaseTableName). Where(sq.Eq{sqlReleaseTableOwnerColumn: sqlReleaseDefaultOwner}) @@ -264,6 +363,12 @@ func (s *SQL) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error) { s.Log("list: failed to decode release: %v: %v", record, err) continue } + + if release.Labels, err = s.getReleaseCustomLabels(record.Key, record.Namespace); err != nil { + s.Log("failed to get release %s/%s custom labels: %v", record.Namespace, record.Key, err) + return nil, err + } + if filter(release) { releases = append(releases, release) } @@ -275,7 +380,7 @@ func (s *SQL) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error) { // Query returns the set of releases that match the provided set of labels. func (s *SQL) Query(labels map[string]string) ([]*rspb.Release, error) { sb := s.statementBuilder. - Select(sqlReleaseTableBodyColumn). + Select(sqlReleaseTableKeyColumn, sqlReleaseTableNamespaceColumn, sqlReleaseTableBodyColumn). From(sqlReleaseTableName) keys := make([]string, 0, len(labels)) @@ -321,6 +426,12 @@ func (s *SQL) Query(labels map[string]string) ([]*rspb.Release, error) { s.Log("list: failed to decode release: %v: %v", record, err) continue } + + if release.Labels, err = s.getReleaseCustomLabels(record.Key, record.Namespace); err != nil { + s.Log("failed to get release %s/%s custom labels: %v", record.Namespace, record.Key, err) + return nil, err + } + releases = append(releases, release) } @@ -403,6 +514,36 @@ func (s *SQL) Create(key string, rls *rspb.Release) error { s.Log("failed to store release %s in SQL database: %v", key, err) return err } + + // Filtering labels before insert cause in SQL storage driver system releases are stored in separate columns of release table + for k, v := range filterSystemLabels(rls.Labels) { + insertLabelsQuery, args, err := s.statementBuilder. + Insert(sqlCustomLabelsTableName). + Columns( + sqlCustomLabelsTableReleaseKeyColumn, + sqlCustomLabelsTableReleaseNamespaceColumn, + sqlCustomLabelsTableKeyColumn, + sqlCustomLabelsTableValueColumn, + ). + Values( + key, + namespace, + k, + v, + ).ToSql() + + if err != nil { + defer transaction.Rollback() + s.Log("failed to build insert query: %v", err) + return err + } + + if _, err := transaction.Exec(insertLabelsQuery, args...); err != nil { + defer transaction.Rollback() + s.Log("failed to write Labels: %v", err) + return err + } + } defer transaction.Commit() return nil @@ -487,10 +628,56 @@ func (s *SQL) Delete(key string) (*rspb.Release, error) { Where(sq.Eq{sqlReleaseTableNamespaceColumn: s.namespace}). ToSql() if err != nil { - s.Log("failed to build select query: %v", err) + s.Log("failed to build delete query: %v", err) return nil, err } _, err = transaction.Exec(deleteQuery, args...) + if err != nil { + s.Log("failed perform delete query: %v", err) + return release, err + } + + if release.Labels, err = s.getReleaseCustomLabels(key, s.namespace); err != nil { + s.Log("failed to get release %s/%s custom labels: %v", s.namespace, key, err) + return nil, err + } + + deleteCustomLabelsQuery, args, err := s.statementBuilder. + Delete(sqlCustomLabelsTableName). + Where(sq.Eq{sqlCustomLabelsTableReleaseKeyColumn: key}). + Where(sq.Eq{sqlCustomLabelsTableReleaseNamespaceColumn: s.namespace}). + ToSql() + + if err != nil { + s.Log("failed to build delete Labels query: %v", err) + return nil, err + } + _, err = transaction.Exec(deleteCustomLabelsQuery, args...) return release, err } + +// Get release custom labels from database +func (s *SQL) getReleaseCustomLabels(key string, namespace string) (map[string]string, error) { + query, args, err := s.statementBuilder. + Select(sqlCustomLabelsTableKeyColumn, sqlCustomLabelsTableValueColumn). + From(sqlCustomLabelsTableName). + Where(sq.Eq{sqlCustomLabelsTableReleaseKeyColumn: key, + sqlCustomLabelsTableReleaseNamespaceColumn: s.namespace}). + ToSql() + if err != nil { + return nil, err + } + + var labelsList = []SQLReleaseCustomLabelWrapper{} + if err := s.db.Select(&labelsList, query, args...); err != nil { + return nil, err + } + + labelsMap := make(map[string]string) + for _, i := range labelsList { + labelsMap[i.Key] = i.Value + } + + return filterSystemLabels(labelsMap), nil +} diff --git a/pkg/storage/driver/sql_test.go b/pkg/storage/driver/sql_test.go index 87b6315b8..067b3cf47 100644 --- a/pkg/storage/driver/sql_test.go +++ b/pkg/storage/driver/sql_test.go @@ -21,6 +21,7 @@ import ( "time" sqlmock "github.com/DATA-DOG/go-sqlmock" + migrate "github.com/rubenv/sql-migrate" rspb "helm.sh/helm/v3/pkg/release" ) @@ -62,6 +63,8 @@ func TestSQLGet(t *testing.T) { ), ).RowsWillBeClosed() + mockGetReleaseCustomLabels(mock, key, namespace, rel.Labels) + got, err := sqlDriver.Get(key) if err != nil { t.Fatalf("Failed to get release: %v", err) @@ -77,38 +80,42 @@ func TestSQLGet(t *testing.T) { } func TestSQLList(t *testing.T) { - body1, _ := encodeRelease(releaseStub("key-1", 1, "default", rspb.StatusUninstalled)) - body2, _ := encodeRelease(releaseStub("key-2", 1, "default", rspb.StatusUninstalled)) - body3, _ := encodeRelease(releaseStub("key-3", 1, "default", rspb.StatusDeployed)) - body4, _ := encodeRelease(releaseStub("key-4", 1, "default", rspb.StatusDeployed)) - body5, _ := encodeRelease(releaseStub("key-5", 1, "default", rspb.StatusSuperseded)) - body6, _ := encodeRelease(releaseStub("key-6", 1, "default", rspb.StatusSuperseded)) + releases := []*rspb.Release{} + releases = append(releases, releaseStub("key-1", 1, "default", rspb.StatusUninstalled)) + releases = append(releases, releaseStub("key-2", 1, "default", rspb.StatusUninstalled)) + releases = append(releases, releaseStub("key-3", 1, "default", rspb.StatusDeployed)) + releases = append(releases, releaseStub("key-4", 1, "default", rspb.StatusDeployed)) + releases = append(releases, releaseStub("key-5", 1, "default", rspb.StatusSuperseded)) + releases = append(releases, releaseStub("key-6", 1, "default", rspb.StatusSuperseded)) sqlDriver, mock := newTestFixtureSQL(t) for i := 0; i < 3; i++ { query := fmt.Sprintf( - "SELECT %s FROM %s WHERE %s = $1 AND %s = $2", + "SELECT %s, %s, %s FROM %s WHERE %s = $1 AND %s = $2", + sqlReleaseTableKeyColumn, + sqlReleaseTableNamespaceColumn, sqlReleaseTableBodyColumn, sqlReleaseTableName, sqlReleaseTableOwnerColumn, sqlReleaseTableNamespaceColumn, ) + rows := mock.NewRows([]string{ + sqlReleaseTableBodyColumn, + }) + for _, r := range releases { + body, _ := encodeRelease(r) + rows.AddRow(body) + } mock. ExpectQuery(regexp.QuoteMeta(query)). WithArgs(sqlReleaseDefaultOwner, sqlDriver.namespace). - WillReturnRows( - mock.NewRows([]string{ - sqlReleaseTableBodyColumn, - }). - AddRow(body1). - AddRow(body2). - AddRow(body3). - AddRow(body4). - AddRow(body5). - AddRow(body6), - ).RowsWillBeClosed() + WillReturnRows(rows).RowsWillBeClosed() + + for _, r := range releases { + mockGetReleaseCustomLabels(mock, "", r.Namespace, r.Labels) + } } // list all deleted releases @@ -181,6 +188,23 @@ func TestSqlCreate(t *testing.T) { ExpectExec(regexp.QuoteMeta(query)). WithArgs(key, sqlReleaseDefaultType, body, rel.Name, rel.Namespace, int(rel.Version), rel.Info.Status.String(), sqlReleaseDefaultOwner, int(time.Now().Unix())). WillReturnResult(sqlmock.NewResult(1, 1)) + + labelsQuery := fmt.Sprintf( + "INSERT INTO %s (%s,%s,%s,%s) VALUES ($1,$2,$3,$4)", + sqlCustomLabelsTableName, + sqlCustomLabelsTableReleaseKeyColumn, + sqlCustomLabelsTableReleaseNamespaceColumn, + sqlCustomLabelsTableKeyColumn, + sqlCustomLabelsTableValueColumn, + ) + + mock.MatchExpectationsInOrder(false) + for k, v := range filterSystemLabels(rel.Labels) { + mock. + ExpectExec(regexp.QuoteMeta(labelsQuery)). + WithArgs(key, rel.Namespace, k, v). + WillReturnResult(sqlmock.NewResult(1, 1)) + } mock.ExpectCommit() if err := sqlDriver.Create(key, rel); err != nil { @@ -316,7 +340,9 @@ func TestSqlQuery(t *testing.T) { sqlDriver, mock := newTestFixtureSQL(t) query := fmt.Sprintf( - "SELECT %s FROM %s WHERE %s = $1 AND %s = $2 AND %s = $3 AND %s = $4", + "SELECT %s, %s, %s FROM %s WHERE %s = $1 AND %s = $2 AND %s = $3 AND %s = $4", + sqlReleaseTableKeyColumn, + sqlReleaseTableNamespaceColumn, sqlReleaseTableBodyColumn, sqlReleaseTableName, sqlReleaseTableNameColumn, @@ -345,8 +371,12 @@ func TestSqlQuery(t *testing.T) { ), ).RowsWillBeClosed() + mockGetReleaseCustomLabels(mock, "", deployedRelease.Namespace, deployedRelease.Labels) + query = fmt.Sprintf( - "SELECT %s FROM %s WHERE %s = $1 AND %s = $2 AND %s = $3", + "SELECT %s, %s, %s FROM %s WHERE %s = $1 AND %s = $2 AND %s = $3", + sqlReleaseTableKeyColumn, + sqlReleaseTableNamespaceColumn, sqlReleaseTableBodyColumn, sqlReleaseTableName, sqlReleaseTableNameColumn, @@ -367,6 +397,9 @@ func TestSqlQuery(t *testing.T) { ), ).RowsWillBeClosed() + mockGetReleaseCustomLabels(mock, "", supersededRelease.Namespace, supersededRelease.Labels) + mockGetReleaseCustomLabels(mock, "", deployedRelease.Namespace, deployedRelease.Labels) + _, err := sqlDriver.Query(labelSetUnknown) if err == nil { t.Errorf("Expected error {%v}, got nil", ErrReleaseNotFound) @@ -447,6 +480,20 @@ func TestSqlDelete(t *testing.T) { ExpectExec(regexp.QuoteMeta(deleteQuery)). WithArgs(key, namespace). WillReturnResult(sqlmock.NewResult(0, 1)) + + mockGetReleaseCustomLabels(mock, key, namespace, rel.Labels) + + deleteLabelsQuery := fmt.Sprintf( + "DELETE FROM %s WHERE %s = $1 AND %s = $2", + sqlCustomLabelsTableName, + sqlCustomLabelsTableReleaseKeyColumn, + sqlCustomLabelsTableReleaseNamespaceColumn, + ) + mock. + ExpectExec(regexp.QuoteMeta(deleteLabelsQuery)). + WithArgs(key, namespace). + WillReturnResult(sqlmock.NewResult(0, 1)) + mock.ExpectCommit() deletedRelease, err := sqlDriver.Delete(key) @@ -461,3 +508,74 @@ func TestSqlDelete(t *testing.T) { t.Errorf("Expected release {%v}, got {%v}", rel, deletedRelease) } } + +func mockGetReleaseCustomLabels(mock sqlmock.Sqlmock, key string, namespace string, labels map[string]string) { + query := fmt.Sprintf( + regexp.QuoteMeta("SELECT %s, %s FROM %s WHERE %s = $1 AND %s = $2"), + sqlCustomLabelsTableKeyColumn, + sqlCustomLabelsTableValueColumn, + sqlCustomLabelsTableName, + sqlCustomLabelsTableReleaseKeyColumn, + sqlCustomLabelsTableReleaseNamespaceColumn, + ) + + eq := mock.ExpectQuery(query). + WithArgs(key, namespace) + + returnRows := mock.NewRows([]string{ + sqlCustomLabelsTableKeyColumn, + sqlCustomLabelsTableValueColumn, + }) + for k, v := range labels { + returnRows.AddRow(k, v) + } + eq.WillReturnRows(returnRows).RowsWillBeClosed() +} + +func TestSqlChechkAppliedMigrations(t *testing.T) { + cases := []struct { + migrationsToApply []*migrate.Migration + appliedMigrationsIds []string + expectedResult bool + errorExplanation string + }{ + { + migrationsToApply: []*migrate.Migration{{Id: "init1"}, {Id: "init2"}, {Id: "init3"}}, + appliedMigrationsIds: []string{"1", "2", "init1", "3", "init2", "4", "5"}, + expectedResult: false, + errorExplanation: "Has found one migration id \"init3\" as applied, that was not applied", + }, + { + migrationsToApply: []*migrate.Migration{{Id: "init1"}, {Id: "init2"}, {Id: "init3"}}, + appliedMigrationsIds: []string{"1", "2", "init1", "3", "init2", "4", "init3", "5"}, + expectedResult: true, + errorExplanation: "Has not found one or more migration ids, that was applied", + }, + { + migrationsToApply: []*migrate.Migration{{Id: "init"}}, + appliedMigrationsIds: []string{"1", "2", "3", "inits", "4", "tinit", "5"}, + expectedResult: false, + errorExplanation: "Has found single \"init\", that was not applied", + }, + { + migrationsToApply: []*migrate.Migration{{Id: "init"}}, + appliedMigrationsIds: []string{"1", "2", "init", "3", "init2", "4", "init3", "5"}, + expectedResult: true, + errorExplanation: "Has not found single migration id \"init\", that was applied", + }, + } + for i, c := range cases { + sqlDriver, mock := newTestFixtureSQL(t) + rows := sqlmock.NewRows([]string{"id", "applied_at"}) + for _, id := range c.appliedMigrationsIds { + rows.AddRow(id, time.Time{}) + } + mock. + ExpectQuery(""). + WillReturnRows(rows) + mock.ExpectCommit() + if sqlDriver.checkAlreadyApplied(c.migrationsToApply) != c.expectedResult { + t.Errorf("Test case: %v, Expected: %v, Have: %v, Explanation: %v", i, c.expectedResult, !c.expectedResult, c.errorExplanation) + } + } +} diff --git a/pkg/storage/driver/util.go b/pkg/storage/driver/util.go index 96a211e37..7bda5ec96 100644 --- a/pkg/storage/driver/util.go +++ b/pkg/storage/driver/util.go @@ -30,6 +30,8 @@ var b64 = base64.StdEncoding var magicGzip = []byte{0x1f, 0x8b, 0x08} +var systemLabels = []string{"name", "owner", "status", "version", "createdAt", "modifiedAt"} + // encodeRelease encodes a release returning a base64 encoded // gzipped string representation, or error. func encodeRelease(rls *rspb.Release) (string, error) { @@ -83,3 +85,38 @@ func decodeRelease(data string) (*rspb.Release, error) { } return &rls, nil } + +// Checks if label is system +func isSystemLabel(key string) bool { + for _, v := range GetSystemLabels() { + if key == v { + return true + } + } + return false +} + +// Removes system labels from labels map +func filterSystemLabels(lbs map[string]string) map[string]string { + result := make(map[string]string) + for k, v := range lbs { + if !isSystemLabel(k) { + result[k] = v + } + } + return result +} + +// Checks if labels array contains system labels +func ContainsSystemLabels(lbs map[string]string) bool { + for k := range lbs { + if isSystemLabel(k) { + return true + } + } + return false +} + +func GetSystemLabels() []string { + return systemLabels +} diff --git a/pkg/storage/driver/util_test.go b/pkg/storage/driver/util_test.go new file mode 100644 index 000000000..d16043924 --- /dev/null +++ b/pkg/storage/driver/util_test.go @@ -0,0 +1,108 @@ +/* +Copyright The Helm Authors. +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. +*/ + +package driver + +import ( + "reflect" + "testing" +) + +func TestGetSystemLabel(t *testing.T) { + if output := GetSystemLabels(); !reflect.DeepEqual(systemLabels, output) { + t.Errorf("Expected {%v}, got {%v}", systemLabels, output) + } +} + +func TestIsSystemLabel(t *testing.T) { + tests := map[string]bool{ + "name": true, + "owner": true, + "test": false, + "NaMe": false, + } + for label, result := range tests { + if output := isSystemLabel(label); output != result { + t.Errorf("Output %t not equal to expected %t", output, result) + } + } +} + +func TestFilterSystemLabels(t *testing.T) { + var tests = [][2]map[string]string{ + {nil, map[string]string{}}, + {map[string]string{}, map[string]string{}}, + {map[string]string{ + "name": "name", + "owner": "owner", + "status": "status", + "version": "version", + "createdAt": "createdAt", + "modifiedAt": "modifiedAt", + }, map[string]string{}}, + {map[string]string{ + "StaTus": "status", + "name": "name", + "owner": "owner", + "key": "value", + }, map[string]string{ + "StaTus": "status", + "key": "value", + }}, + {map[string]string{ + "key1": "value1", + "key2": "value2", + }, map[string]string{ + "key1": "value1", + "key2": "value2", + }}, + } + for _, test := range tests { + if output := filterSystemLabels(test[0]); !reflect.DeepEqual(test[1], output) { + t.Errorf("Expected {%v}, got {%v}", test[1], output) + } + } +} + +func TestContainsSystemLabels(t *testing.T) { + var tests = []struct { + input map[string]string + output bool + }{ + {nil, false}, + {map[string]string{}, false}, + {map[string]string{ + "name": "name", + "owner": "owner", + "status": "status", + "version": "version", + "createdAt": "createdAt", + "modifiedAt": "modifiedAt", + }, true}, + {map[string]string{ + "StaTus": "status", + "name": "name", + "owner": "owner", + "key": "value", + }, true}, + {map[string]string{ + "key1": "value1", + "key2": "value2", + }, false}, + } + for _, test := range tests { + if output := ContainsSystemLabels(test.input); !reflect.DeepEqual(test.output, output) { + t.Errorf("Expected {%v}, got {%v}", test.output, output) + } + } +} diff --git a/scripts/get b/scripts/get index fce6abd99..594fd92c3 100755 --- a/scripts/get +++ b/scripts/get @@ -207,6 +207,10 @@ while [[ $# -gt 0 ]]; do shift if [[ $# -ne 0 ]]; then export DESIRED_VERSION="${1}" + if [[ "$1" != "v"* ]]; then + echo "Expected version arg ('${DESIRED_VERSION}') to begin with 'v', fixing..." + export DESIRED_VERSION="v${1}" + fi else echo -e "Please provide the desired version. e.g. --version v2.4.0 or -v latest" exit 0 diff --git a/scripts/get-helm-3 b/scripts/get-helm-3 index 6177ba1a2..b5e53bafc 100755 --- a/scripts/get-helm-3 +++ b/scripts/get-helm-3 @@ -108,11 +108,17 @@ verifySupported() { checkDesiredVersion() { if [ "x$DESIRED_VERSION" == "x" ]; then # Get tag from release URL - local latest_release_url="https://github.com/helm/helm/releases" + local latest_release_url="https://api.github.com/repos/helm/helm/releases/latest" + local latest_release_response="" if [ "${HAS_CURL}" == "true" ]; then - TAG=$(curl -Ls $latest_release_url | grep 'href="/helm/helm/releases/tag/v3.[0-9]*.[0-9]*\"' | sed -E 's/.*\/helm\/helm\/releases\/tag\/(v[0-9\.]+)".*/\1/g' | head -1) + latest_release_response=$( curl -L --silent --show-error --fail "$latest_release_url" 2>&1 || true ) elif [ "${HAS_WGET}" == "true" ]; then - TAG=$(wget $latest_release_url -O - 2>&1 | grep 'href="/helm/helm/releases/tag/v3.[0-9]*.[0-9]*\"' | sed -E 's/.*\/helm\/helm\/releases\/tag\/(v[0-9\.]+)".*/\1/g' | head -1) + latest_release_response=$( wget "$latest_release_url" -O - 2>&1 || true ) + fi + TAG=$( echo "$latest_release_response" | grep '"tag_name"' | sed -E 's/.*"(v[0-9\.]+)".*/\1/g' ) + if [ "x$TAG" == "x" ]; then + printf "Could not retrieve the latest release tag information from %s: %s\n" "${latest_release_url}" "${latest_release_response}" + exit 1 fi else TAG=$DESIRED_VERSION @@ -299,6 +305,10 @@ while [[ $# -gt 0 ]]; do shift if [[ $# -ne 0 ]]; then export DESIRED_VERSION="${1}" + if [[ "$1" != "v"* ]]; then + echo "Expected version arg ('${DESIRED_VERSION}') to begin with 'v', fixing..." + export DESIRED_VERSION="v${1}" + fi else echo -e "Please provide the desired version. e.g. --version v3.0.0 or -v canary" exit 0