From 2e9cf782f72d0980e7c84542dc151f598ba5d6e1 Mon Sep 17 00:00:00 2001 From: derailed Date: Tue, 21 Nov 2023 09:01:09 -0700 Subject: [PATCH 01/22] Feat: Move shell pod cluster config to general config > BREAKING CHANGE! K9s configuration breaking change! Shellpod specification will no longer reside with a cluster configuration. It is now part of the global K9s configuration object. Shellpod configuration should be part of k9s config. Clusters admins will most likely use the same image and config to run shells on their nodes. Each cluster in turn will have the option to either enable/disable shelling into nodes. This not only DRYs up the k9s config but also allows user to consolidate their shell pod configuration in one central place. --- README.md | 45 +++++++++++------------------ internal/config/cluster.go | 7 ----- internal/config/config_test.go | 52 +++++++++------------------------- internal/config/k9s.go | 7 +++++ internal/config/plugin.go | 11 ++++--- internal/config/shell_pod.go | 16 +++++------ internal/view/exec.go | 25 +++++++--------- 7 files changed, 61 insertions(+), 102 deletions(-) diff --git a/README.md b/README.md index 3e78f7b8ab..1e58994f07 100644 --- a/README.md +++ b/README.md @@ -364,6 +364,16 @@ K9s uses aliases to navigate most K8s resources. currentCluster: minikube # KeepMissingClusters will keep clusters in the config if they are missing from the current kubeconfig file. Default false KeepMissingClusters: false + # Provide shell pod customization of feature gate is enabled + shellPod: + # The shell pod image to use. + image: killerAdmin + # The namespace to launch to shell pod into. + namespace: fred + # The resource limit to set on the shell pod. + limits: + cpu: 100m + memory: 100Mi # Persists per cluster preferences for favorite namespaces and view. clusters: coolio: @@ -379,21 +389,6 @@ K9s uses aliases to navigate most K8s resources. featureGates: # Toggles NodeShell support. Allow K9s to shell into nodes if needed. Default false. nodeShell: false - # Provide shell pod customization of feature gate is enabled - shellPod: - # The shell pod image to use. - image: killerAdmin - # The namespace to launch to shell pod into. - namespace: fred - # imagePullPolicy defaults to Always - imagePullPolicy: Always - # imagePullSecrets defaults to no secret - imagePullSecrets: - - name: my-regcred - # The resource limit to set on the shell pod. - limits: - cpu: 100m - memory: 100Mi # The IP Address to use when launching a port-forward. portForwardAddress: 1.2.3.4 kind: @@ -424,25 +419,19 @@ By enabling the nodeShell feature gate on a given cluster, K9s allows you to she ```yaml # $XDG_CONFIG_HOME/k9s/config.yml k9s: + # You can also further tune the shell pod specification + shellPod: + image: cool_kid_admin:42 + namespace: blee + limits: + cpu: 100m + memory: 100Mi clusters: # Configures node shell on cluster blee blee: featureGates: # You must enable the nodeShell feature gate to enable shelling into nodes nodeShell: true - # You can also further tune the shell pod specification - shellPod: - image: cool_kid_admin:42 - namespace: blee - # imagePullPolicy defaults to Always - imagePullPolicy: Always - # imagePullSecrets defaults to no secret - imagePullSecrets: - - name: my-regcred - # The resource limit to set on the shell pod. - limits: - cpu: 100m - memory: 100Mi ``` --- diff --git a/internal/config/cluster.go b/internal/config/cluster.go index e95150191b..295cd700d2 100644 --- a/internal/config/cluster.go +++ b/internal/config/cluster.go @@ -13,7 +13,6 @@ type Cluster struct { Namespace *Namespace `yaml:"namespace"` View *View `yaml:"view"` FeatureGates *FeatureGates `yaml:"featureGates"` - ShellPod *ShellPod `yaml:"shellPod"` PortForwardAddress string `yaml:"portForwardAddress"` } @@ -24,7 +23,6 @@ func NewCluster() *Cluster { View: NewView(), PortForwardAddress: DefaultPFAddress, FeatureGates: NewFeatureGates(), - ShellPod: NewShellPod(), } } @@ -49,9 +47,4 @@ func (c *Cluster) Validate(conn client.Connection, ks KubeSettings) { c.View = NewView() } c.View.Validate() - - if c.ShellPod == nil { - c.ShellPod = NewShellPod() - } - c.ShellPod.Validate(conn, ks) } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index f33b8aecfe..9e7ea0badd 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -290,11 +290,17 @@ var expectedConfig = `k9s: readOnly: true noExitOnCtrlC: false noIcons: false + shellPod: + image: busybox:1.35.0 + namespace: default + limits: + cpu: 100m + memory: 100Mi skipLatestRevCheck: false logger: tail: 500 buffer: 800 - sinceSeconds: 300 + sinceSeconds: -1 fullScreenLogs: false textWrap: false showTime: false @@ -312,15 +318,6 @@ var expectedConfig = `k9s: active: po featureGates: nodeShell: false - shellPod: - image: busybox:1.35.0 - command: [] - args: [] - namespace: default - limits: - cpu: 100m - memory: 100Mi - labels: {} portForwardAddress: localhost fred: namespace: @@ -336,15 +333,6 @@ var expectedConfig = `k9s: active: po featureGates: nodeShell: false - shellPod: - image: busybox:1.35.0 - command: [] - args: [] - namespace: default - limits: - cpu: 100m - memory: 100Mi - labels: {} portForwardAddress: localhost minikube: namespace: @@ -360,15 +348,6 @@ var expectedConfig = `k9s: active: ctx featureGates: nodeShell: false - shellPod: - image: busybox:1.35.0 - command: [] - args: [] - namespace: default - limits: - cpu: 100m - memory: 100Mi - labels: {} portForwardAddress: localhost thresholds: cpu: @@ -392,11 +371,17 @@ var resetConfig = `k9s: readOnly: false noExitOnCtrlC: false noIcons: false + shellPod: + image: busybox:1.35.0 + namespace: default + limits: + cpu: 100m + memory: 100Mi skipLatestRevCheck: false logger: tail: 200 buffer: 2000 - sinceSeconds: 300 + sinceSeconds: -1 fullScreenLogs: false textWrap: false showTime: false @@ -414,15 +399,6 @@ var resetConfig = `k9s: active: po featureGates: nodeShell: false - shellPod: - image: busybox:1.35.0 - command: [] - args: [] - namespace: default - limits: - cpu: 100m - memory: 100Mi - labels: {} portForwardAddress: localhost thresholds: cpu: diff --git a/internal/config/k9s.go b/internal/config/k9s.go index 0f1f2ddadb..9d090ad6e0 100644 --- a/internal/config/k9s.go +++ b/internal/config/k9s.go @@ -24,6 +24,7 @@ type K9s struct { ReadOnly bool `yaml:"readOnly"` NoExitOnCtrlC bool `yaml:"noExitOnCtrlC"` NoIcons bool `yaml:"noIcons"` + ShellPod *ShellPod `yaml:"shellPod"` SkipLatestRevCheck bool `yaml:"skipLatestRevCheck"` Logger *Logger `yaml:"logger"` CurrentContext string `yaml:"currentContext"` @@ -51,6 +52,7 @@ func NewK9s() *K9s { Clusters: make(map[string]*Cluster), Thresholds: NewThreshold(), ScreenDumpDir: K9sDefaultScreenDumpDir, + ShellPod: NewShellPod(), } } @@ -237,6 +239,11 @@ func (k *K9s) Validate(c client.Connection, ks KubeSettings) { } k.validateClusters(c, ks) + if k.ShellPod == nil { + k.ShellPod = NewShellPod() + } + k.ShellPod.Validate(c, ks) + if k.Logger == nil { k.Logger = NewLogger() } else { diff --git a/internal/config/plugin.go b/internal/config/plugin.go index b7b2fa67e0..99d9c0cf85 100644 --- a/internal/config/plugin.go +++ b/internal/config/plugin.go @@ -10,7 +10,6 @@ import ( "strings" "github.com/adrg/xdg" - "github.com/rs/zerolog/log" "gopkg.in/yaml.v2" ) @@ -52,6 +51,7 @@ func (p Plugins) Load() error { for _, dataDir := range xdg.DataDirs { pluginDirs = append(pluginDirs, filepath.Join(dataDir, K9sPluginDirectory)) } + return p.LoadPlugins(K9sPluginsFilePath, pluginDirs) } @@ -61,15 +61,18 @@ func (p Plugins) LoadPlugins(path string, pluginDirs []string) error { if err != nil { return err } + var pp Plugins if err := yaml.Unmarshal(f, &pp); err != nil { return err } + for k, v := range pp.Plugin { + p.Plugin[k] = v + } for _, pluginDir := range pluginDirs { pluginFiles, err := os.ReadDir(pluginDir) if err != nil { - log.Warn().Msgf("Failed reading plugin path %s; %s", pluginDir, err) continue } for _, file := range pluginFiles { @@ -88,9 +91,5 @@ func (p Plugins) LoadPlugins(path string, pluginDirs []string) error { } } - for k, v := range pp.Plugin { - p.Plugin[k] = v - } - return nil } diff --git a/internal/config/shell_pod.go b/internal/config/shell_pod.go index f4efe0bbb5..210922912c 100644 --- a/internal/config/shell_pod.go +++ b/internal/config/shell_pod.go @@ -15,14 +15,14 @@ type Limits map[v1.ResourceName]string // ShellPod represents k9s shell configuration. type ShellPod struct { - Image string `json:"image"` - ImagePullSecrets []v1.LocalObjectReference `json:"imagePullSecrets,omitempty" yaml:"imagePullSecrets,omitempty"` - ImagePullPolicy v1.PullPolicy `json:"imagePullPolicy,omitempty" yaml:"imagePullPolicy,omitempty"` - Command []string `json:"command,omitempty"` - Args []string `json:"args,omitempty"` - Namespace string `json:"namespace"` - Limits Limits `json:"resources,omitempty"` - Labels map[string]string `json:"labels,omitempty"` + Image string `yaml:"image"` + Command []string `yaml:"command,omitempty"` + Args []string `yaml:"args,omitempty"` + Namespace string `yaml:"namespace"` + Limits Limits `yaml:"limits,omitempty"` + Labels map[string]string `yaml:"labels,omitempty"` + ImagePullSecrets []v1.LocalObjectReference `yaml:"imagePullSecrets,omitempty"` + ImagePullPolicy v1.PullPolicy `yaml:"imagePullPolicy,omitempty"` } // NewShellPod returns a new instance. diff --git a/internal/view/exec.go b/internal/view/exec.go index 2a74dd1eb8..6888467296 100644 --- a/internal/view/exec.go +++ b/internal/view/exec.go @@ -249,19 +249,13 @@ func ssh(a *App, node string) error { if err := launchShellPod(a, node); err != nil { return err } - - cl := a.Config.K9s.ActiveCluster() - if cl == nil { - return fmt.Errorf("no active cluster detected") - } - ns := cl.ShellPod.Namespace + ns := a.Config.K9s.ShellPod.Namespace return sshIn(a, client.FQN(ns, k9sShellPodName()), k9sShell) } func sshIn(a *App, fqn, co string) error { - cl := a.Config.K9s.ActiveCluster() - cfg := cl.ShellPod + cfg := a.Config.K9s.ShellPod os, err := getPodOS(a.factory, fqn) if err != nil { return fmt.Errorf("os detect failed: %w", err) @@ -295,8 +289,7 @@ func nukeK9sShell(a *App) error { return nil } - cl := a.Config.K9s.ActiveCluster() - ns := cl.ShellPod.Namespace + ns := a.Config.K9s.ShellPod.Namespace ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) defer cancel() @@ -315,9 +308,11 @@ func nukeK9sShell(a *App) error { func launchShellPod(a *App, node string) error { a.Flash().Infof("Launching node shell on %s...", node) - cl := a.Config.K9s.ActiveCluster() - ns := cl.ShellPod.Namespace - spec := k9sShellPod(node, cl.ShellPod) + + var ( + spo = a.Config.K9s.ShellPod + spec = k9sShellPod(node, spo) + ) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() @@ -325,13 +320,13 @@ func launchShellPod(a *App, node string) error { if err != nil { return err } - conn := dial.CoreV1().Pods(ns) + conn := dial.CoreV1().Pods(spo.Namespace) if _, err := conn.Create(ctx, spec, metav1.CreateOptions{}); err != nil { return err } for i := 0; i < k9sShellRetryCount; i++ { - o, err := a.factory.Get("v1/pods", client.FQN(ns, k9sShellPodName()), true, labels.Everything()) + o, err := a.factory.Get("v1/pods", client.FQN(spo.Namespace, k9sShellPodName()), true, labels.Everything()) if err != nil { time.Sleep(k9sShellRetryDelay) continue From 304fde96047cdceadcb003615528b4d6eb5524d9 Mon Sep 17 00:00:00 2001 From: derailed Date: Tue, 21 Nov 2023 14:55:53 -0700 Subject: [PATCH 02/22] Fix #2290 - Add freebsd assets --- .goreleaser.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.goreleaser.yml b/.goreleaser.yml index dc7a1d2c56..0b179cc444 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -12,6 +12,7 @@ builds: - linux - darwin - windows + - freebsd goarch: - amd64 - arm64 @@ -33,6 +34,7 @@ archives: darwin: Darwin linux: Linux windows: Windows + freebsd: FreeBSD bit: Arm bitv6: Arm6 bitv7: Arm7 From 958ef589ad496497a4feeda3a6e77d3f5db773b4 Mon Sep 17 00:00:00 2001 From: derailed Date: Tue, 21 Nov 2023 14:56:03 -0700 Subject: [PATCH 03/22] Maintenance cleaning up --- internal/dao/registry.go | 28 ++------ internal/render/ofaas.go | 116 ---------------------------------- internal/render/ofaas_test.go | 39 ------------ 3 files changed, 5 insertions(+), 178 deletions(-) delete mode 100644 internal/render/ofaas.go delete mode 100644 internal/render/ofaas_test.go diff --git a/internal/dao/registry.go b/internal/dao/registry.go index 8a3eb212f0..0d60d990b4 100644 --- a/internal/dao/registry.go +++ b/internal/dao/registry.go @@ -95,12 +95,10 @@ func AccessorFor(f Factory, gvr client.GVR) (Accessor, error) { client.NewGVR("batch/v1beta1/cronjobs"): &CronJob{}, client.NewGVR("batch/v1/jobs"): &Job{}, client.NewGVR("v1/namespaces"): &Namespace{}, - // BOZO!! Revamp with latest... - // client.NewGVR("openfaas"): &OpenFaas{}, - client.NewGVR("popeye"): &Popeye{}, - client.NewGVR("sanitizer"): &Popeye{}, - client.NewGVR("helm"): &Helm{}, - client.NewGVR("dir"): &Dir{}, + client.NewGVR("popeye"): &Popeye{}, + client.NewGVR("sanitizer"): &Popeye{}, + client.NewGVR("helm"): &Helm{}, + client.NewGVR("dir"): &Dir{}, } r, ok := m[gvr] @@ -199,10 +197,6 @@ func loadNonResource(m ResourceMetas) { loadK9s(m) loadRBAC(m) loadHelm(m) - // BOZO!! Revamp with latest... - // if IsOpenFaasEnabled() { - // loadOpenFaas(m) - // } } func loadK9s(m ResourceMetas) { @@ -306,18 +300,6 @@ func loadHelm(m ResourceMetas) { } } -// BOZO!! revamp with latest... -// func loadOpenFaas(m ResourceMetas) { -// m[client.NewGVR("openfaas")] = metav1.APIResource{ -// Name: "openfaas", -// Kind: "OpenFaaS", -// ShortNames: []string{"ofaas", "ofa"}, -// Namespaced: true, -// Verbs: []string{"delete"}, -// Categories: []string{"faas"}, -// } -// } - func loadRBAC(m ResourceMetas) { m[client.NewGVR("rbac")] = metav1.APIResource{ Name: "rbacs", @@ -426,7 +408,7 @@ func extractMeta(o runtime.Object) (metav1.APIResource, []error) { crd, ok := o.(*unstructured.Unstructured) if !ok { - return m, append(errs, fmt.Errorf("Expected Unstructured, but got %T", o)) + return m, append(errs, fmt.Errorf("expected unstructured, but got %T", o)) } var spec map[string]interface{} diff --git a/internal/render/ofaas.go b/internal/render/ofaas.go deleted file mode 100644 index 0df5f904df..0000000000 --- a/internal/render/ofaas.go +++ /dev/null @@ -1,116 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright Authors of K9s - -package render - -// BOZO!! revamp with latest... - -// import ( -// "errors" -// "fmt" -// "strconv" -// "time" - -// "github.com/derailed/k9s/internal/client" -// "github.com/derailed/tview" -// "github.com/derailed/tcell/v2" - -// ofaas "github.com/openfaas/faas-provider/types" -// metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -// "k8s.io/apimachinery/pkg/runtime" -// "k8s.io/apimachinery/pkg/runtime/schema" -// ) - -// const ( -// fnStatusReady = "Ready" -// fnStatusNotReady = "Not Ready" -// ) - -// // OpenFaas renders an openfaas function to screen. -// type OpenFaas struct{} - -// // ColorerFunc colors a resource row. -// func (o OpenFaas) ColorerFunc() ColorerFunc { -// return func(ns string, h Header, re RowEvent) tcell.Color { -// if !Happy(ns, h, re.Row) { -// return ErrColor -// } - -// return tcell.ColorPaleTurquoise -// } -// } - -// // Header returns a header row. -// func (OpenFaas) Header(ns string) Header { -// return Header{ -// HeaderColumn{Name: "NAMESPACE"}, -// HeaderColumn{Name: "NAME"}, -// HeaderColumn{Name: "STATUS"}, -// HeaderColumn{Name: "IMAGE"}, -// HeaderColumn{Name: "LABELS"}, -// HeaderColumn{Name: "INVOCATIONS", Align: tview.AlignRight}, -// HeaderColumn{Name: "REPLICAS", Align: tview.AlignRight}, -// HeaderColumn{Name: "AVAILABLE", Align: tview.AlignRight}, -// HeaderColumn{Name: "VALID", Wide: true}, -// HeaderColumn{Name: "AGE", Time: true}, -// } -// } - -// // Render renders a chart to screen. -// func (o OpenFaas) Render(i interface{}, ns string, r *Row) error { -// fn, ok := i.(OpenFaasRes) -// if !ok { -// return fmt.Errorf("expected OpenFaasRes, but got %T", o) -// } - -// var labels string -// if fn.Function.Labels != nil { -// labels = mapToStr(*fn.Function.Labels) -// } -// status := fnStatusReady -// if fn.Function.AvailableReplicas == 0 { -// status = fnStatusNotReady -// } - -// r.ID = client.FQN(fn.Function.Namespace, fn.Function.Name) -// r.Fields = Fields{ -// fn.Function.Namespace, -// fn.Function.Name, -// status, -// fn.Function.Image, -// labels, -// strconv.Itoa(int(fn.Function.InvocationCount)), -// strconv.Itoa(int(fn.Function.Replicas)), -// strconv.Itoa(int(fn.Function.AvailableReplicas)), -// asStatus(o.diagnose(status)), -// toAge(metav1.Time{Time: time.Now()}), -// } - -// return nil -// } - -// func (OpenFaas) diagnose(status string) error { -// if status != "Ready" { -// return errors.New("function not ready") -// } - -// return nil -// } - -// // ---------------------------------------------------------------------------- -// // Helpers... - -// // OpenFaasRes represents an openfaas function resource. -// type OpenFaasRes struct { -// Function ofaas.FunctionStatus `json:"function"` -// } - -// // GetObjectKind returns a schema object. -// func (OpenFaasRes) GetObjectKind() schema.ObjectKind { -// return nil -// } - -// // DeepCopyObject returns a container copy. -// func (h OpenFaasRes) DeepCopyObject() runtime.Object { -// return h -// } diff --git a/internal/render/ofaas_test.go b/internal/render/ofaas_test.go deleted file mode 100644 index dbefa9d6d2..0000000000 --- a/internal/render/ofaas_test.go +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright Authors of K9s - -package render_test - -// BOZO!! revamp with latest... - -// import ( -// "testing" - -// "github.com/derailed/k9s/internal/render" -// ofaas "github.com/openfaas/faas-provider/types" -// "github.com/stretchr/testify/assert" -// ) - -// func TestOpenFaasRender(t *testing.T) { -// c := render.OpenFaas{} -// r := render.NewRow(9) -// c.Render(makeFn("blee"), "", &r) - -// assert.Equal(t, "default/blee", r.ID) -// assert.Equal(t, render.Fields{"default", "blee", "Ready", "nginx:0", "fred=blee", "10", "1", "1"}, r.Fields[:8]) -// } - -// // Helpers... - -// func makeFn(n string) render.OpenFaasRes { -// return render.OpenFaasRes{ -// Function: ofaas.FunctionStatus{ -// Name: n, -// Namespace: "default", -// Image: "nginx:0", -// InvocationCount: 10, -// Replicas: 1, -// AvailableReplicas: 1, -// Labels: &map[string]string{"fred": "blee"}, -// }, -// } -// } From 86843cb810ad134ef5842992663f09591398cad7 Mon Sep 17 00:00:00 2001 From: derailed Date: Wed, 22 Nov 2023 18:12:26 -0700 Subject: [PATCH 04/22] Fix #2166 - Add taint tracking column to node view --- internal/render/node.go | 2 ++ internal/render/node_test.go | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/render/node.go b/internal/render/node.go index 3fb2bd74ec..28395b50e2 100644 --- a/internal/render/node.go +++ b/internal/render/node.go @@ -35,6 +35,7 @@ func (Node) Header(_ string) Header { HeaderColumn{Name: "NAME"}, HeaderColumn{Name: "STATUS"}, HeaderColumn{Name: "ROLE"}, + HeaderColumn{Name: "TAINTS"}, HeaderColumn{Name: "VERSION"}, HeaderColumn{Name: "KERNEL", Wide: true}, HeaderColumn{Name: "INTERNAL-IP", Wide: true}, @@ -89,6 +90,7 @@ func (n Node) Render(o interface{}, ns string, r *Row) error { no.Name, join(statuses, ","), join(roles, ","), + strconv.Itoa(len(no.Spec.Taints)), no.Status.NodeInfo.KubeletVersion, no.Status.NodeInfo.KernelVersion, iIP, diff --git a/internal/render/node_test.go b/internal/render/node_test.go index 584670201a..de41891393 100644 --- a/internal/render/node_test.go +++ b/internal/render/node_test.go @@ -24,7 +24,7 @@ func TestNodeRender(t *testing.T) { assert.Nil(t, err) assert.Equal(t, "minikube", r.ID) - e := render.Fields{"minikube", "Ready", "master", "v1.15.2", "4.15.0", "192.168.64.107", "", "0", "10", "20", "0", "0", "4000", "7874"} + e := render.Fields{"minikube", "Ready", "0", "master", "v1.15.2", "4.15.0", "192.168.64.107", "", "0", "10", "20", "0", "0", "4000", "7874"} assert.Equal(t, e, r.Fields[:14]) } From 90256315d0e86a103cf4bc775b246adeabe19acf Mon Sep 17 00:00:00 2001 From: derailed Date: Thu, 23 Nov 2023 05:59:56 -0700 Subject: [PATCH 05/22] Fix #2009: Update screendump file names to contain resource info --- internal/render/screen_dump.go | 3 ++- internal/view/live_view.go | 18 +++++++++++++----- internal/view/live_view_test.go | 16 ++++++++++++++++ internal/view/yaml.go | 7 ++----- 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/internal/render/screen_dump.go b/internal/render/screen_dump.go index 36293fe6b7..9b237d7a07 100644 --- a/internal/render/screen_dump.go +++ b/internal/render/screen_dump.go @@ -12,6 +12,7 @@ import ( "github.com/derailed/tcell/v2" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/duration" ) // ScreenDump renders a screendumps to screen. @@ -58,7 +59,7 @@ func (b ScreenDump) Render(o interface{}, ns string, r *Row) error { // Helpers... func timeToAge(timestamp time.Time) string { - return time.Since(timestamp).String() + return duration.HumanDuration(time.Since(timestamp)) } // FileRes represents a file resource. diff --git a/internal/view/live_view.go b/internal/view/live_view.go index 40163d504e..596e4705f4 100644 --- a/internal/view/live_view.go +++ b/internal/view/live_view.go @@ -79,7 +79,9 @@ func (v *LiveView) Init(_ context.Context) error { v.bindKeys() v.SetInputCapture(v.keyboard) - v.model.AddListener(v) + if v.model != nil { + v.model.AddListener(v) + } return nil } @@ -198,7 +200,9 @@ func (v *LiveView) StylesChanged(s *config.Styles) { v.SetBackgroundColor(v.app.Styles.BgColor()) v.text.SetTextColor(v.app.Styles.FgColor()) v.SetBorderFocusColor(v.app.Styles.Frame().Border.FocusColor.Color()) - v.ResourceChanged(v.model.Peek(), nil) + if v.model != nil { + v.ResourceChanged(v.model.Peek(), nil) + } } // Actions returns menu actions. @@ -351,10 +355,11 @@ func (v *LiveView) resetCmd(evt *tcell.EventKey) *tcell.EventKey { } func (v *LiveView) saveCmd(evt *tcell.EventKey) *tcell.EventKey { - if path, err := saveYAML(v.app.Config.K9s.GetScreenDumpDir(), v.app.Config.K9s.CurrentContextDir(), v.title, v.text.GetText(true)); err != nil { + name := fmt.Sprintf("%s--%s", strings.Replace(v.model.GetPath(), "/", "-", 1), strings.ToLower(v.title)) + if _, err := saveYAML(v.app.Config.K9s.GetScreenDumpDir(), v.app.Config.K9s.CurrentContextDir(), name, sanitizeEsc(v.text.GetText(true))); err != nil { v.app.Flash().Err(err) } else { - v.app.Flash().Infof("Log %s saved successfully!", path) + v.app.Flash().Infof("File %q saved successfully!", name) } return nil @@ -364,7 +369,10 @@ func (v *LiveView) updateTitle() { if v.title == "" { return } - fmat := fmt.Sprintf(liveViewTitleFmt, v.title, v.model.GetPath()) + var fmat string + if v.model != nil { + fmat = fmt.Sprintf(liveViewTitleFmt, v.title, v.model.GetPath()) + } buff := v.cmdBuff.GetText() if buff == "" { diff --git a/internal/view/live_view_test.go b/internal/view/live_view_test.go index 045cfd4594..1df6cd43a0 100644 --- a/internal/view/live_view_test.go +++ b/internal/view/live_view_test.go @@ -4,9 +4,11 @@ package view import ( + "context" "strconv" "testing" + "github.com/derailed/k9s/internal/config" "github.com/sahilm/fuzzy" "github.com/stretchr/testify/assert" ) @@ -15,6 +17,20 @@ func matchTag(i int, s string) string { return `<<<"search_` + strconv.Itoa(i) + `">>>` + s + `<<<"">>>` } +func TestLiveViewSetText(t *testing.T) { + s := ` +apiVersion: v1 + data: + the secret name you want to quote to use tls.","title":"secretName","type":"string"}},"required":["http","class","classInSpec"],"type":"object"} +` + + v := NewLiveView(NewApp(config.NewConfig(nil)), "fred", nil) + v.Init(context.Background()) + v.text.SetText(colorizeYAML(config.Yaml{}, s)) + + assert.Equal(t, s, sanitizeEsc(v.text.GetText(true))) +} + func TestLiveView_linesWithRegions(t *testing.T) { uu := map[string]struct { lines []string diff --git a/internal/view/yaml.go b/internal/view/yaml.go index a1998a26e3..0fda208726 100644 --- a/internal/view/yaml.go +++ b/internal/view/yaml.go @@ -29,7 +29,6 @@ const ( func colorizeYAML(style config.Yaml, raw string) string { lines := strings.Split(tview.Escape(raw), "\n") - fullFmt := strings.Replace(yamlFullFmt, "[key", "["+style.KeyColor.String(), 1) fullFmt = strings.Replace(fullFmt, "[colon", "["+style.ColonColor.String(), 1) fullFmt = strings.Replace(fullFmt, "[val", "["+style.ValueColor.String(), 1) @@ -64,14 +63,12 @@ func enableRegion(str string) string { } func saveYAML(screenDumpDir, context, name, data string) (string, error) { - dir := filepath.Join(screenDumpDir, context) + dir := filepath.Join(screenDumpDir, config.SanitizeFilename(context)) if err := ensureDir(dir); err != nil { return "", err } - now := time.Now().UnixNano() - fName := fmt.Sprintf("%s-%d.yml", config.SanitizeFilename(name), now) - + fName := fmt.Sprintf("%s--%d.yml", config.SanitizeFilename(name), time.Now().Unix()) path := filepath.Join(dir, fName) mod := os.O_CREATE | os.O_WRONLY file, err := os.OpenFile(path, mod, 0600) From bcfc9dc5b781eac66ffa00fbdf5b2147b04c3eb0 Mon Sep 17 00:00:00 2001 From: derailed Date: Thu, 23 Nov 2023 06:11:24 -0700 Subject: [PATCH 06/22] Maintenance: Cleanup errror messages --- internal/render/benchmark.go | 6 +++--- internal/render/container.go | 2 +- internal/render/crb.go | 2 +- internal/render/crd.go | 4 ++-- internal/render/cronjob.go | 2 +- internal/render/dp.go | 2 +- internal/render/ds.go | 2 +- internal/render/ep.go | 2 +- internal/render/job.go | 2 +- internal/render/np.go | 2 +- internal/render/ns.go | 2 +- internal/render/pdb.go | 2 +- internal/render/pv.go | 2 +- internal/render/pvc.go | 2 +- internal/render/ro.go | 2 +- internal/render/rob.go | 2 +- internal/render/rs.go | 2 +- internal/render/sa.go | 2 +- internal/render/sc.go | 2 +- internal/render/sts.go | 2 +- internal/render/subject.go | 2 +- internal/render/svc.go | 2 +- internal/ui/dialog/error.go | 2 +- internal/view/app.go | 3 +-- internal/view/cow.go | 2 +- internal/xray/container.go | 2 +- internal/xray/dp.go | 2 +- internal/xray/ds.go | 2 +- internal/xray/ns.go | 2 +- internal/xray/pod.go | 2 +- internal/xray/rs.go | 2 +- internal/xray/section.go | 2 +- internal/xray/sts.go | 2 +- internal/xray/svc.go | 2 +- 34 files changed, 37 insertions(+), 38 deletions(-) diff --git a/internal/render/benchmark.go b/internal/render/benchmark.go index 9124e0d15a..76a9c1d931 100644 --- a/internal/render/benchmark.go +++ b/internal/render/benchmark.go @@ -61,12 +61,12 @@ func (Benchmark) Header(ns string) Header { func (b Benchmark) Render(o interface{}, ns string, r *Row) error { bench, ok := o.(BenchInfo) if !ok { - return fmt.Errorf("No benchmarks available %T", o) + return fmt.Errorf("no benchmarks available %T", o) } data, err := b.readFile(bench.Path) if err != nil { - return fmt.Errorf("Unable to load bench file %s", bench.Path) + return fmt.Errorf("unable to load bench file %s", bench.Path) } r.ID = bench.Path @@ -111,7 +111,7 @@ func (Benchmark) readFile(file string) (string, error) { func (b Benchmark) initRow(row Fields, f os.FileInfo) error { tokens := strings.Split(f.Name(), "_") if len(tokens) < 2 { - return fmt.Errorf("Invalid file name %s", f.Name()) + return fmt.Errorf("invalid file name %s", f.Name()) } row[0] = tokens[0] row[1] = tokens[1] diff --git a/internal/render/container.go b/internal/render/container.go index c32b64d9aa..6799fa6891 100644 --- a/internal/render/container.go +++ b/internal/render/container.go @@ -99,7 +99,7 @@ func (Container) Header(ns string) Header { func (c Container) Render(o interface{}, name string, r *Row) error { co, ok := o.(ContainerRes) if !ok { - return fmt.Errorf("Expected ContainerRes, but got %T", o) + return fmt.Errorf("expected ContainerRes, but got %T", o) } cur, res := gatherMetrics(co.Container, co.MX) diff --git a/internal/render/crb.go b/internal/render/crb.go index 04842356a3..1095f13fb7 100644 --- a/internal/render/crb.go +++ b/internal/render/crb.go @@ -33,7 +33,7 @@ func (ClusterRoleBinding) Header(string) Header { func (ClusterRoleBinding) Render(o interface{}, ns string, r *Row) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected ClusterRoleBinding, but got %T", o) + return fmt.Errorf("expected ClusterRoleBinding, but got %T", o) } var crb rbacv1.ClusterRoleBinding err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &crb) diff --git a/internal/render/crd.go b/internal/render/crd.go index b51f90b033..c9824856da 100644 --- a/internal/render/crd.go +++ b/internal/render/crd.go @@ -35,7 +35,7 @@ func (CustomResourceDefinition) Header(string) Header { func (c CustomResourceDefinition) Render(o interface{}, ns string, r *Row) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected CustomResourceDefinition, but got %T", o) + return fmt.Errorf("expected CustomResourceDefinition, but got %T", o) } var crd v1.CustomResourceDefinition @@ -87,7 +87,7 @@ func (c CustomResourceDefinition) diagnose(n string, vv []v1.CustomResourceDefin if v.DeprecationWarning != nil { ee = append(ee, fmt.Errorf("%s", *v.DeprecationWarning)) } else { - ee = append(ee, fmt.Errorf("%s[%s] is deprecated!", n, v.Name)) + ee = append(ee, fmt.Errorf("%s[%s] is deprecated", n, v.Name)) } } } diff --git a/internal/render/cronjob.go b/internal/render/cronjob.go index efaab7b355..dc9fd0c52e 100644 --- a/internal/render/cronjob.go +++ b/internal/render/cronjob.go @@ -42,7 +42,7 @@ func (CronJob) Header(ns string) Header { func (c CronJob) Render(o interface{}, ns string, r *Row) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected CronJob, but got %T", o) + return fmt.Errorf("expected CronJob, but got %T", o) } var cj batchv1.CronJob err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &cj) diff --git a/internal/render/dp.go b/internal/render/dp.go index 1e1b1738bc..6a0f58e0a1 100644 --- a/internal/render/dp.go +++ b/internal/render/dp.go @@ -42,7 +42,7 @@ func (Deployment) Header(ns string) Header { func (d Deployment) Render(o interface{}, ns string, r *Row) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected Deployment, but got %T", o) + return fmt.Errorf("expected Deployment, but got %T", o) } var dp appsv1.Deployment diff --git a/internal/render/ds.go b/internal/render/ds.go index dea0da35f2..e40c30faf9 100644 --- a/internal/render/ds.go +++ b/internal/render/ds.go @@ -39,7 +39,7 @@ func (DaemonSet) Header(ns string) Header { func (d DaemonSet) Render(o interface{}, ns string, r *Row) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected DaemonSet, but got %T", o) + return fmt.Errorf("expected DaemonSet, but got %T", o) } var ds appsv1.DaemonSet err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &ds) diff --git a/internal/render/ep.go b/internal/render/ep.go index 4a6b3640f2..2587caa208 100644 --- a/internal/render/ep.go +++ b/internal/render/ep.go @@ -33,7 +33,7 @@ func (Endpoints) Header(ns string) Header { func (e Endpoints) Render(o interface{}, ns string, r *Row) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected Endpoints, but got %T", o) + return fmt.Errorf("expected Endpoints, but got %T", o) } var ep v1.Endpoints err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &ep) diff --git a/internal/render/job.go b/internal/render/job.go index c036a82d45..edd030177e 100644 --- a/internal/render/job.go +++ b/internal/render/job.go @@ -42,7 +42,7 @@ func (Job) Header(ns string) Header { func (j Job) Render(o interface{}, ns string, r *Row) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected Job, but got %T", o) + return fmt.Errorf("expected Job, but got %T", o) } var job batchv1.Job err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &job) diff --git a/internal/render/np.go b/internal/render/np.go index 2904a353fb..03bd65c36a 100644 --- a/internal/render/np.go +++ b/internal/render/np.go @@ -40,7 +40,7 @@ func (NetworkPolicy) Header(ns string) Header { func (n NetworkPolicy) Render(o interface{}, ns string, r *Row) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected NetworkPolicy, but got %T", o) + return fmt.Errorf("expected NetworkPolicy, but got %T", o) } var np netv1.NetworkPolicy err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &np) diff --git a/internal/render/ns.go b/internal/render/ns.go index 6dcd2a6f9d..1b2c50c223 100644 --- a/internal/render/ns.go +++ b/internal/render/ns.go @@ -55,7 +55,7 @@ func (Namespace) Header(string) Header { func (n Namespace) Render(o interface{}, _ string, r *Row) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected Namespace, but got %T", o) + return fmt.Errorf("expected Namespace, but got %T", o) } var ns v1.Namespace err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &ns) diff --git a/internal/render/pdb.go b/internal/render/pdb.go index 357133b071..3b8366047d 100644 --- a/internal/render/pdb.go +++ b/internal/render/pdb.go @@ -41,7 +41,7 @@ func (PodDisruptionBudget) Header(ns string) Header { func (p PodDisruptionBudget) Render(o interface{}, ns string, r *Row) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected PodDisruptionBudget, but got %T", o) + return fmt.Errorf("expected PodDisruptionBudget, but got %T", o) } var pdb v1beta1.PodDisruptionBudget err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &pdb) diff --git a/internal/render/pv.go b/internal/render/pv.go index 72ee55e097..560a34548c 100644 --- a/internal/render/pv.go +++ b/internal/render/pv.go @@ -70,7 +70,7 @@ func (PersistentVolume) Header(string) Header { func (p PersistentVolume) Render(o interface{}, ns string, r *Row) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected PersistentVolume, but got %T", o) + return fmt.Errorf("expected PersistentVolume, but got %T", o) } var pv v1.PersistentVolume err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &pv) diff --git a/internal/render/pvc.go b/internal/render/pvc.go index 76414e12fb..5da78b2d18 100644 --- a/internal/render/pvc.go +++ b/internal/render/pvc.go @@ -37,7 +37,7 @@ func (PersistentVolumeClaim) Header(ns string) Header { func (p PersistentVolumeClaim) Render(o interface{}, ns string, r *Row) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected PersistentVolumeClaim, but got %T", o) + return fmt.Errorf("expected PersistentVolumeClaim, but got %T", o) } var pvc v1.PersistentVolumeClaim err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &pvc) diff --git a/internal/render/ro.go b/internal/render/ro.go index e88e084edb..b3dfd9ad36 100644 --- a/internal/render/ro.go +++ b/internal/render/ro.go @@ -36,7 +36,7 @@ func (Role) Header(ns string) Header { func (r Role) Render(o interface{}, ns string, row *Row) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected Role, but got %T", o) + return fmt.Errorf("expected Role, but got %T", o) } var ro rbacv1.Role err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &ro) diff --git a/internal/render/rob.go b/internal/render/rob.go index 1cb56adc05..adf9d8a090 100644 --- a/internal/render/rob.go +++ b/internal/render/rob.go @@ -40,7 +40,7 @@ func (RoleBinding) Header(ns string) Header { func (r RoleBinding) Render(o interface{}, ns string, row *Row) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected RoleBinding, but got %T", o) + return fmt.Errorf("expected RoleBinding, but got %T", o) } var rb rbacv1.RoleBinding err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &rb) diff --git a/internal/render/rs.go b/internal/render/rs.go index 59a1a16bdb..5f601e5004 100644 --- a/internal/render/rs.go +++ b/internal/render/rs.go @@ -42,7 +42,7 @@ func (ReplicaSet) Header(ns string) Header { func (r ReplicaSet) Render(o interface{}, ns string, row *Row) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected ReplicaSet, but got %T", o) + return fmt.Errorf("expected ReplicaSet, but got %T", o) } var rs appsv1.ReplicaSet err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &rs) diff --git a/internal/render/sa.go b/internal/render/sa.go index dfa276ad68..03cc821033 100644 --- a/internal/render/sa.go +++ b/internal/render/sa.go @@ -34,7 +34,7 @@ func (ServiceAccount) Header(ns string) Header { func (s ServiceAccount) Render(o interface{}, ns string, r *Row) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected ServiceAccount, but got %T", o) + return fmt.Errorf("expected ServiceAccount, but got %T", o) } var sa v1.ServiceAccount err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &sa) diff --git a/internal/render/sc.go b/internal/render/sc.go index 392c1c4e97..47e5ada41c 100644 --- a/internal/render/sc.go +++ b/internal/render/sc.go @@ -37,7 +37,7 @@ func (StorageClass) Header(ns string) Header { func (s StorageClass) Render(o interface{}, ns string, r *Row) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected StorageClass, but got %T", o) + return fmt.Errorf("expected StorageClass, but got %T", o) } var sc storagev1.StorageClass err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &sc) diff --git a/internal/render/sts.go b/internal/render/sts.go index 78be0c123f..bf99be703d 100644 --- a/internal/render/sts.go +++ b/internal/render/sts.go @@ -38,7 +38,7 @@ func (StatefulSet) Header(ns string) Header { func (s StatefulSet) Render(o interface{}, ns string, r *Row) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected StatefulSet, but got %T", o) + return fmt.Errorf("expected StatefulSet, but got %T", o) } var sts appsv1.StatefulSet err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &sts) diff --git a/internal/render/subject.go b/internal/render/subject.go index b61f95daaa..b58e0ba7b4 100644 --- a/internal/render/subject.go +++ b/internal/render/subject.go @@ -37,7 +37,7 @@ func (Subject) Header(ns string) Header { func (s Subject) Render(o interface{}, ns string, r *Row) error { res, ok := o.(SubjectRes) if !ok { - return fmt.Errorf("Expected SubjectRes, but got %T", s) + return fmt.Errorf("expected SubjectRes, but got %T", s) } r.ID = res.Name diff --git a/internal/render/svc.go b/internal/render/svc.go index 642c293c10..7b0e56c59e 100644 --- a/internal/render/svc.go +++ b/internal/render/svc.go @@ -40,7 +40,7 @@ func (Service) Header(ns string) Header { func (s Service) Render(o interface{}, ns string, r *Row) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected Service, but got %T", o) + return fmt.Errorf("expected Service, but got %T", o) } var svc v1.Service err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &svc) diff --git a/internal/ui/dialog/error.go b/internal/ui/dialog/error.go index 26fdebfa5b..1d81db5e77 100644 --- a/internal/ui/dialog/error.go +++ b/internal/ui/dialog/error.go @@ -41,7 +41,7 @@ func ShowError(styles config.Dialog, pages *ui.Pages, msg string) { } func cowTalk(says string) string { - msg := fmt.Sprintf("< Ruroh? %s >", says) + msg := fmt.Sprintf("< Ruroh? %s >", strings.TrimSuffix(says, "\n")) buff := make([]string, 0, len(cow)+3) buff = append(buff, msg) buff = append(buff, cow...) diff --git a/internal/view/app.go b/internal/view/app.go index 7de20d7888..f3a5ef0d0c 100644 --- a/internal/view/app.go +++ b/internal/view/app.go @@ -686,8 +686,7 @@ func (a *App) gotoResource(cmd, path string, clearStack bool) { func (a *App) inject(c model.Component, clearStack bool) error { ctx := context.WithValue(context.Background(), internal.KeyApp, a) if err := c.Init(ctx); err != nil { - log.Error().Err(err).Msgf("component init failed for %q", c.Name()) - //dialog.ShowError(a.Styles.Dialog(), a.Content.Pages, err.Error()) + log.Error().Err(err).Msgf("Component init failed for %q", c.Name()) return err } if clearStack { diff --git a/internal/view/cow.go b/internal/view/cow.go index d71f3e898e..6920f4dabc 100644 --- a/internal/view/cow.go +++ b/internal/view/cow.go @@ -74,7 +74,7 @@ func cowTalk(says string, w int) string { msg := fmt.Sprintf("[red::]< [::b]Ruroh? %s[::-] >", says) buff := make([]string, 0, len(cow)+3) buff = append(buff, "[red::] "+strings.Repeat("─", len(says)+8)) - buff = append(buff, msg) + buff = append(buff, strings.TrimSuffix(msg, "\n")) buff = append(buff, " "+strings.Repeat("─", len(says)+8)) rCount := w/2 - 8 if rCount < 0 { diff --git a/internal/xray/container.go b/internal/xray/container.go index 1f87336ccf..50a608607c 100644 --- a/internal/xray/container.go +++ b/internal/xray/container.go @@ -23,7 +23,7 @@ type Container struct{} func (c *Container) Render(ctx context.Context, ns string, o interface{}) error { co, ok := o.(render.ContainerRes) if !ok { - return fmt.Errorf("Expected ContainerRes, but got %T", o) + return fmt.Errorf("expected ContainerRes, but got %T", o) } f, ok := ctx.Value(internal.KeyFactory).(dao.Factory) diff --git a/internal/xray/dp.go b/internal/xray/dp.go index bfc47ef077..a32bbafd6f 100644 --- a/internal/xray/dp.go +++ b/internal/xray/dp.go @@ -25,7 +25,7 @@ type Deployment struct{} func (d *Deployment) Render(ctx context.Context, ns string, o interface{}) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected Unstructured, but got %T", o) + return fmt.Errorf("expected Unstructured, but got %T", o) } var dp appsv1.Deployment err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &dp) diff --git a/internal/xray/ds.go b/internal/xray/ds.go index fe55dc7158..d2ca86d65b 100644 --- a/internal/xray/ds.go +++ b/internal/xray/ds.go @@ -21,7 +21,7 @@ type DaemonSet struct{} func (d *DaemonSet) Render(ctx context.Context, ns string, o interface{}) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected Unstructured, but got %T", o) + return fmt.Errorf("expected Unstructured, but got %T", o) } var ds appsv1.DaemonSet err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &ds) diff --git a/internal/xray/ns.go b/internal/xray/ns.go index 647ada3d35..a39f141af0 100644 --- a/internal/xray/ns.go +++ b/internal/xray/ns.go @@ -20,7 +20,7 @@ type Namespace struct{} func (n *Namespace) Render(ctx context.Context, ns string, o interface{}) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected NamespaceWithMetrics, but got %T", o) + return fmt.Errorf("expected NamespaceWithMetrics, but got %T", o) } var nss v1.Namespace diff --git a/internal/xray/pod.go b/internal/xray/pod.go index ddac6d9193..69bb293f12 100644 --- a/internal/xray/pod.go +++ b/internal/xray/pod.go @@ -24,7 +24,7 @@ type Pod struct{} func (p *Pod) Render(ctx context.Context, ns string, o interface{}) error { pwm, ok := o.(*render.PodWithMetrics) if !ok { - return fmt.Errorf("Expected PodWithMetrics, but got %T", o) + return fmt.Errorf("expected PodWithMetrics, but got %T", o) } var po v1.Pod diff --git a/internal/xray/rs.go b/internal/xray/rs.go index 9dfda4c653..80c64f5b2d 100644 --- a/internal/xray/rs.go +++ b/internal/xray/rs.go @@ -21,7 +21,7 @@ type ReplicaSet struct{} func (r *ReplicaSet) Render(ctx context.Context, ns string, o interface{}) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected Unstructured, but got %T", o) + return fmt.Errorf("expected Unstructured, but got %T", o) } var rs appsv1.ReplicaSet err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &rs) diff --git a/internal/xray/section.go b/internal/xray/section.go index c458b5fdb7..7e171004ae 100644 --- a/internal/xray/section.go +++ b/internal/xray/section.go @@ -21,7 +21,7 @@ type Section struct { func (s *Section) Render(ctx context.Context, ns string, o interface{}) error { section, ok := o.(render.Section) if !ok { - return fmt.Errorf("Expected Section, but got %T", o) + return fmt.Errorf("expected Section, but got %T", o) } root := NewTreeNode(section.GVR, section.Title) parent, ok := ctx.Value(KeyParent).(*TreeNode) diff --git a/internal/xray/sts.go b/internal/xray/sts.go index 0917c1965e..819a2b5a21 100644 --- a/internal/xray/sts.go +++ b/internal/xray/sts.go @@ -21,7 +21,7 @@ type StatefulSet struct{} func (s *StatefulSet) Render(ctx context.Context, ns string, o interface{}) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected Unstructured, but got %T", o) + return fmt.Errorf("expected Unstructured, but got %T", o) } var sts appsv1.StatefulSet err := runtime.DefaultUnstructuredConverter.FromUnstructured(raw.Object, &sts) diff --git a/internal/xray/svc.go b/internal/xray/svc.go index af535c7c1d..9c0df61746 100644 --- a/internal/xray/svc.go +++ b/internal/xray/svc.go @@ -25,7 +25,7 @@ type Service struct{} func (s *Service) Render(ctx context.Context, ns string, o interface{}) error { raw, ok := o.(*unstructured.Unstructured) if !ok { - return fmt.Errorf("Expected Unstructured, but got %T", o) + return fmt.Errorf("expected Unstructured, but got %T", o) } var svc v1.Service From 45113690bf98bded75638152a8fdac0312e44414 Mon Sep 17 00:00:00 2001 From: derailed Date: Thu, 23 Nov 2023 06:15:50 -0700 Subject: [PATCH 07/22] Fix #1513: Change log default to tail vs last 5min --- README.md | 14 ++++++++------ internal/config/logger.go | 4 +++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 1e58994f07..abf2884bc3 100644 --- a/README.md +++ b/README.md @@ -313,7 +313,7 @@ K9s uses aliases to navigate most K8s resources. ## K9s Configuration - K9s keeps its configurations inside of a `k9s` directory and the location depends on your operating system. K9s leverages [XDG](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) to load its various configurations files. For information on the default locations for your OS please see [this link](https://github.com/adrg/xdg/blob/master/README.md). If you are still confused a quick `k9s info` will reveal where k9s is loading its configurations from. Alternatively, you can set `K9SCONFIG` to tell K9s the directory location to pull its configurations from. + K9s keeps its configurations as YAML files inside of a `k9s` directory and the location depends on your operating system. K9s leverages [XDG](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) to load its various configurations files. For information on the default locations for your OS please see [this link](https://github.com/adrg/xdg/blob/master/README.md). If you are still confused a quick `k9s info` will reveal where k9s is loading its configurations from. Alternatively, you can set `K9SCONFIG` to tell K9s the directory location to pull its configurations from. | Unix | macOS | Windows | |-----------------|------------------------------------|-----------------------| @@ -321,6 +321,8 @@ K9s uses aliases to navigate most K8s resources. > NOTE: This is still in flux and will change while in pre-release stage! + > NOTE! Thanks to [Mr Alexandru Placenta](https://github.com/placintaalexandru) the config files can now use either `.yml` or `.yaml` mimes. + ```yaml # $XDG_CONFIG_HOME/k9s/config.yml k9s: @@ -350,8 +352,8 @@ K9s uses aliases to navigate most K8s resources. tail: 200 # Defines the total number of log lines to allow in the view. Default 1000 buffer: 500 - # Represents how far to go back in the log timeline in seconds. Setting to -1 will show all available logs. Default is 5min. - sinceSeconds: 300 + # Represents how far to go back in the log timeline in seconds. Setting to -1 will tail logs. Default is -1. + sinceSeconds: 300 # => tail the last 5 mins # Go full screen while displaying logs. Default false fullScreenLogs: false # Toggles log line wrap. Default false @@ -364,12 +366,12 @@ K9s uses aliases to navigate most K8s resources. currentCluster: minikube # KeepMissingClusters will keep clusters in the config if they are missing from the current kubeconfig file. Default false KeepMissingClusters: false - # Provide shell pod customization of feature gate is enabled + # Provide shell pod customization when nodeShell feature gate is enabled! shellPod: # The shell pod image to use. image: killerAdmin # The namespace to launch to shell pod into. - namespace: fred + namespace: default # The resource limit to set on the shell pod. limits: cpu: 100m @@ -388,7 +390,7 @@ K9s uses aliases to navigate most K8s resources. active: po featureGates: # Toggles NodeShell support. Allow K9s to shell into nodes if needed. Default false. - nodeShell: false + nodeShell: true # The IP Address to use when launching a port-forward. portForwardAddress: 1.2.3.4 kind: diff --git a/internal/config/logger.go b/internal/config/logger.go index 93f6bbd418..13cb96b108 100644 --- a/internal/config/logger.go +++ b/internal/config/logger.go @@ -10,10 +10,12 @@ import ( const ( // DefaultLoggerTailCount tracks default log tail size. DefaultLoggerTailCount = 100 + // MaxLogThreshold sets the max value for log size. MaxLogThreshold = 5000 + // DefaultSinceSeconds tracks default log age. - DefaultSinceSeconds = 300 // all logs + DefaultSinceSeconds = -1 // tail logs by default ) // Logger tracks logger options. From 9675b17e4393f8bee604add0f190705e6353f3d4 Mon Sep 17 00:00:00 2001 From: derailed Date: Thu, 23 Nov 2023 06:16:31 -0700 Subject: [PATCH 08/22] Fix #2166: Add taint indicator on node view --- internal/render/node_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/render/node_test.go b/internal/render/node_test.go index de41891393..1b54ba919f 100644 --- a/internal/render/node_test.go +++ b/internal/render/node_test.go @@ -24,8 +24,8 @@ func TestNodeRender(t *testing.T) { assert.Nil(t, err) assert.Equal(t, "minikube", r.ID) - e := render.Fields{"minikube", "Ready", "0", "master", "v1.15.2", "4.15.0", "192.168.64.107", "", "0", "10", "20", "0", "0", "4000", "7874"} - assert.Equal(t, e, r.Fields[:14]) + e := render.Fields{"minikube", "Ready", "master", "0", "v1.15.2", "4.15.0", "192.168.64.107", "", "0", "10", "20", "0", "0", "4000", "7874"} + assert.Equal(t, e, r.Fields[:15]) } func BenchmarkNodeRender(b *testing.B) { From 6fc3e634cbc67be75b1c10c1305bf2d7b8339955 Mon Sep 17 00:00:00 2001 From: derailed Date: Thu, 23 Nov 2023 06:17:20 -0700 Subject: [PATCH 09/22] Fix #2165: Track init co restarts --- internal/render/pod.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/internal/render/pod.go b/internal/render/pod.go index dd33265842..a9288017c3 100644 --- a/internal/render/pod.go +++ b/internal/render/pod.go @@ -121,8 +121,10 @@ func (p Pod) Render(o interface{}, ns string, row *Row) error { return err } - ss := po.Status.ContainerStatuses - cr, _, rc := p.Statuses(ss) + ics := po.Status.InitContainerStatuses + _, _, irc := p.Statuses(ics) + cs := po.Status.ContainerStatuses + cr, _, rc := p.Statuses(cs) c, r := p.gatherPodMX(&po, pwm.MX) phase := p.Phase(&po) @@ -133,7 +135,7 @@ func (p Pod) Render(o interface{}, ns string, row *Row) error { "●", strconv.Itoa(cr) + "/" + strconv.Itoa(len(po.Spec.Containers)), phase, - strconv.Itoa(rc), + strconv.Itoa(rc + irc), na(po.Status.PodIP), na(po.Spec.NodeName), asNominated(po.Status.NominatedNodeName), @@ -148,7 +150,7 @@ func (p Pod) Render(o interface{}, ns string, row *Row) error { client.ToPercentageStr(c.mem, r.lmem), p.mapQOS(po.Status.QOSClass), mapToStr(po.Labels), - asStatus(p.diagnose(phase, cr, len(ss))), + asStatus(p.diagnose(phase, cr, len(cs))), toAge(po.GetCreationTimestamp()), } From 1b1c240606073a0f550d98c4430da7dd3817687b Mon Sep 17 00:00:00 2001 From: derailed Date: Thu, 23 Nov 2023 06:19:06 -0700 Subject: [PATCH 10/22] Fix #2308: Fix rbac auth checks --- internal/client/types.go | 3 +++ internal/view/browser.go | 4 ++-- internal/view/logs_extender.go | 2 +- internal/view/xray.go | 2 +- internal/watch/factory.go | 4 ++-- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/internal/client/types.go b/internal/client/types.go index fbeb657d77..fd814572da 100644 --- a/internal/client/types.go +++ b/internal/client/types.go @@ -58,10 +58,13 @@ const ( var ( // GetAccess reads a resource. GetAccess = []string{GetVerb} + // ListAccess list resources. ListAccess = []string{ListVerb} + // MonitorAccess monitors a collection of resources. MonitorAccess = []string{ListVerb, WatchVerb} + // ReadAllAccess represents an all read access to a resource. ReadAllAccess = []string{GetVerb, ListVerb, WatchVerb} ) diff --git a/internal/view/browser.go b/internal/view/browser.go index c5f46447d7..5d2ca2467e 100644 --- a/internal/view/browser.go +++ b/internal/view/browser.go @@ -62,7 +62,7 @@ func (b *Browser) Init(ctx context.Context) error { } ns := client.CleanseNamespace(b.app.Config.ActiveNamespace()) if dao.IsK8sMeta(b.meta) && b.app.ConOK() { - if _, e := b.app.factory.CanForResource(ns, b.GVR().String(), client.MonitorAccess); e != nil { + if _, e := b.app.factory.CanForResource(ns, b.GVR().String(), client.ListAccess); e != nil { return e } } @@ -404,7 +404,7 @@ func (b *Browser) switchNamespaceCmd(evt *tcell.EventKey) *tcell.EventKey { } ns := b.namespaces[i] - auth, err := b.App().factory.Client().CanI(ns, b.GVR().String(), client.MonitorAccess) + auth, err := b.App().factory.Client().CanI(ns, b.GVR().String(), client.ListAccess) if !auth { if err == nil { err = fmt.Errorf("current user can't access namespace %s", ns) diff --git a/internal/view/logs_extender.go b/internal/view/logs_extender.go index 151d28adfa..6c20a81848 100644 --- a/internal/view/logs_extender.go +++ b/internal/view/logs_extender.go @@ -58,7 +58,7 @@ func isResourcePath(p string) bool { func (l *LogsExtender) showLogs(path string, prev bool) { ns, _ := client.Namespaced(path) - _, err := l.App().factory.CanForResource(ns, "v1/pods", client.MonitorAccess) + _, err := l.App().factory.CanForResource(ns, "v1/pods", client.ListAccess) if err != nil { l.App().Flash().Err(err) return diff --git a/internal/view/xray.go b/internal/view/xray.go index d2ffd581e8..1d9c6de775 100644 --- a/internal/view/xray.go +++ b/internal/view/xray.go @@ -265,7 +265,7 @@ func (x *Xray) showLogs(spec *xray.NodeSpec, prev bool) { } ns, _ := client.Namespaced(path) - _, err := x.app.factory.CanForResource(ns, "v1/pods", client.MonitorAccess) + _, err := x.app.factory.CanForResource(ns, "v1/pods", client.ListAccess) if err != nil { x.app.Flash().Err(err) return diff --git a/internal/watch/factory.go b/internal/watch/factory.go index 70fbe5fb7f..fcd67300fe 100644 --- a/internal/watch/factory.go +++ b/internal/watch/factory.go @@ -70,7 +70,7 @@ func (f *Factory) Terminate() { // List returns a resource collection. func (f *Factory) List(gvr, ns string, wait bool, labels labels.Selector) ([]runtime.Object, error) { - inf, err := f.CanForResource(ns, gvr, client.MonitorAccess) + inf, err := f.CanForResource(ns, gvr, client.ListAccess) if err != nil { return nil, err } @@ -97,7 +97,7 @@ func (f *Factory) List(gvr, ns string, wait bool, labels labels.Selector) ([]run // HasSynced checks if given informer is up to date. func (f *Factory) HasSynced(gvr, ns string) (bool, error) { - inf, err := f.CanForResource(ns, gvr, client.MonitorAccess) + inf, err := f.CanForResource(ns, gvr, client.ListAccess) if err != nil { return false, err } From 002a843f5902b8187797adb73f03c711da08b4f5 Mon Sep 17 00:00:00 2001 From: derailed Date: Thu, 23 Nov 2023 06:20:05 -0700 Subject: [PATCH 11/22] Fix #2036: Fix npe on filtering CRDs --- internal/render/generic.go | 3 --- internal/ui/table_helper.go | 8 +++----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/internal/render/generic.go b/internal/render/generic.go index f72ae0dcfc..b8c02a9f9c 100644 --- a/internal/render/generic.go +++ b/internal/render/generic.go @@ -10,7 +10,6 @@ import ( "strings" "github.com/derailed/k9s/internal/client" - "github.com/rs/zerolog/log" metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1" ) @@ -99,8 +98,6 @@ func (g *Generic) Render(o interface{}, ns string, r *Row) error { } if d, ok := duration.(string); ok { r.Fields = append(r.Fields, d) - } else { - log.Warn().Msgf("No Duration detected on age field") } return nil diff --git a/internal/ui/table_helper.go b/internal/ui/table_helper.go index 0e89bf890e..5575c94528 100644 --- a/internal/ui/table_helper.go +++ b/internal/ui/table_helper.go @@ -165,14 +165,12 @@ func rxFilter(q string, inverse bool, data *render.TableData) (*render.TableData RowEvents: make(render.RowEvents, 0, len(data.RowEvents)), Namespace: data.Namespace, } - ageIndex := -1 - if data.Header.HasAge() { - ageIndex = data.Header.IndexOf("AGE", true) - } + ageIndex := data.Header.IndexOf("AGE", true) + const spacer = " " for _, re := range data.RowEvents { ff := re.Row.Fields - if ageIndex > 0 { + if ageIndex >= 0 && ageIndex+1 <= len(ff) { ff = append(ff[0:ageIndex], ff[ageIndex+1:]...) } fields := strings.Join(ff, spacer) From 1b7c31a4ae90269b0f2fa4b130709565a314e23d Mon Sep 17 00:00:00 2001 From: derailed Date: Thu, 23 Nov 2023 06:20:39 -0700 Subject: [PATCH 12/22] Fix #2219: Turn on TTY option on shellpod --- README.md | 2 ++ internal/config/shell_pod.go | 1 + internal/view/exec.go | 1 + 3 files changed, 4 insertions(+) diff --git a/README.md b/README.md index abf2884bc3..45c5f92136 100644 --- a/README.md +++ b/README.md @@ -376,6 +376,8 @@ K9s uses aliases to navigate most K8s resources. limits: cpu: 100m memory: 100Mi + # Enable TTY + tty: true # Persists per cluster preferences for favorite namespaces and view. clusters: coolio: diff --git a/internal/config/shell_pod.go b/internal/config/shell_pod.go index 210922912c..919cedae76 100644 --- a/internal/config/shell_pod.go +++ b/internal/config/shell_pod.go @@ -23,6 +23,7 @@ type ShellPod struct { Labels map[string]string `yaml:"labels,omitempty"` ImagePullSecrets []v1.LocalObjectReference `yaml:"imagePullSecrets,omitempty"` ImagePullPolicy v1.PullPolicy `yaml:"imagePullPolicy,omitempty"` + TTY bool `yaml:"tty,omitempty"` } // NewShellPod returns a new instance. diff --git a/internal/view/exec.go b/internal/view/exec.go index 6888467296..7bdcef004d 100644 --- a/internal/view/exec.go +++ b/internal/view/exec.go @@ -367,6 +367,7 @@ func k9sShellPod(node string, cfg *config.ShellPod) *v1.Pod { }, Resources: asResource(cfg.Limits), Stdin: true, + TTY: cfg.TTY, SecurityContext: &v1.SecurityContext{ Privileged: &priv, }, From 2a8524b679af7859ce8c3513436112028d23a01d Mon Sep 17 00:00:00 2001 From: derailed Date: Thu, 23 Nov 2023 06:21:36 -0700 Subject: [PATCH 13/22] Fix #2167: Update color escape sequence on copy --- internal/view/helpers.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/internal/view/helpers.go b/internal/view/helpers.go index dea7a10137..ef1cc73544 100644 --- a/internal/view/helpers.go +++ b/internal/view/helpers.go @@ -26,9 +26,13 @@ func clipboardWrite(text string) error { return clipboard.WriteAll(text) } +func sanitizeEsc(s string) string { + return strings.ReplaceAll(s, "[]", "]") +} + func cpCmd(flash *model.Flash, v *tview.TextView) func(*tcell.EventKey) *tcell.EventKey { return func(evt *tcell.EventKey) *tcell.EventKey { - if err := clipboardWrite(v.GetText(true)); err != nil { + if err := clipboardWrite(sanitizeEsc(v.GetText(true))); err != nil { flash.Err(err) return evt } From fe7c9709587f03e47865e3ebffbe120996629931 Mon Sep 17 00:00:00 2001 From: derailed Date: Thu, 23 Nov 2023 08:54:28 -0700 Subject: [PATCH 14/22] Fix #2297: Enable multi select on nodes --- internal/view/node.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/view/node.go b/internal/view/node.go index 82e9d33f80..9b9274b717 100644 --- a/internal/view/node.go +++ b/internal/view/node.go @@ -54,8 +54,6 @@ func (n *Node) bindDangerousKeys(aa ui.KeyActions) { } func (n *Node) bindKeys(aa ui.KeyActions) { - aa.Delete(ui.KeySpace, tcell.KeyCtrlSpace) - if !n.App().Config.K9s.IsReadOnly() { n.bindDangerousKeys(aa) } From 236f5636b0489f738ce709d1ecf40afde344ffba Mon Sep 17 00:00:00 2001 From: derailed Date: Fri, 24 Nov 2023 09:13:16 -0700 Subject: [PATCH 15/22] Cleanup headers --- internal/dao/benchmark.go | 3 --- internal/dao/cronjob.go | 3 --- internal/dao/dp.go | 3 --- internal/dao/generic.go | 3 --- internal/dao/helm.go | 3 --- internal/dao/log_item.go | 3 --- internal/dao/node.go | 3 --- internal/dao/pod.go | 3 --- main.go | 6 ------ 9 files changed, 30 deletions(-) diff --git a/internal/dao/benchmark.go b/internal/dao/benchmark.go index b5dbef1cba..75dcdc6a81 100644 --- a/internal/dao/benchmark.go +++ b/internal/dao/benchmark.go @@ -1,9 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Authors of K9s -// SPDX-License-Identifier: Apache-2.0 -// Copyright Authors of K9s - package dao import ( diff --git a/internal/dao/cronjob.go b/internal/dao/cronjob.go index 201f771369..2e1d013ed3 100644 --- a/internal/dao/cronjob.go +++ b/internal/dao/cronjob.go @@ -1,9 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Authors of K9s -// SPDX-License-Identifier: Apache-2.0 -// Copyright Authors of K9s - package dao import ( diff --git a/internal/dao/dp.go b/internal/dao/dp.go index 541415b180..9da3556a65 100644 --- a/internal/dao/dp.go +++ b/internal/dao/dp.go @@ -1,9 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Authors of K9s -// SPDX-License-Identifier: Apache-2.0 -// Copyright Authors of K9s - package dao import ( diff --git a/internal/dao/generic.go b/internal/dao/generic.go index e205e1f525..6d3e7f411d 100644 --- a/internal/dao/generic.go +++ b/internal/dao/generic.go @@ -1,9 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Authors of K9s -// SPDX-License-Identifier: Apache-2.0 -// Copyright Authors of K9s - package dao import ( diff --git a/internal/dao/helm.go b/internal/dao/helm.go index 5ec675bd89..3bd03edb93 100644 --- a/internal/dao/helm.go +++ b/internal/dao/helm.go @@ -1,9 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Authors of K9s -// SPDX-License-Identifier: Apache-2.0 -// Copyright Authors of K9s - package dao import ( diff --git a/internal/dao/log_item.go b/internal/dao/log_item.go index 2ef1ba3d43..ff90bbff3b 100644 --- a/internal/dao/log_item.go +++ b/internal/dao/log_item.go @@ -1,9 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Authors of K9s -// SPDX-License-Identifier: Apache-2.0 -// Copyright Authors of K9s - package dao import ( diff --git a/internal/dao/node.go b/internal/dao/node.go index 67b14f2feb..6d2984679d 100644 --- a/internal/dao/node.go +++ b/internal/dao/node.go @@ -1,9 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Authors of K9s -// SPDX-License-Identifier: Apache-2.0 -// Copyright Authors of K9s - package dao import ( diff --git a/internal/dao/pod.go b/internal/dao/pod.go index 70b7f3dc5e..9c5f669a0f 100644 --- a/internal/dao/pod.go +++ b/internal/dao/pod.go @@ -1,9 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Authors of K9s -// SPDX-License-Identifier: Apache-2.0 -// Copyright Authors of K9s - package dao import ( diff --git a/main.go b/main.go index 13ce9520c7..05ffae543a 100644 --- a/main.go +++ b/main.go @@ -1,12 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 // Copyright Authors of K9s -// SPDX-License-Identifier: Apache-2.0 -// Copyright Authors of K9s - -// SPDX-License-Identifier: Apache-2.0 -// Copyright Authors of K9s - package main import ( From 338366eeaded5bc451c23eca9c5424035c8dba27 Mon Sep 17 00:00:00 2001 From: derailed Date: Fri, 24 Nov 2023 09:20:01 -0700 Subject: [PATCH 16/22] Fix #2162: Allow edit when describing/viewing --- internal/model/describe.go | 5 ++++ internal/model/types.go | 1 + internal/model/values.go | 5 ++++ internal/model/yaml.go | 5 ++++ internal/view/browser.go | 47 +++++++++++++++++++++++--------------- internal/view/dir.go | 4 ++-- internal/view/live_view.go | 35 +++++++++++++++++++--------- internal/view/node.go | 4 ++-- internal/view/xray.go | 4 ++-- 9 files changed, 74 insertions(+), 36 deletions(-) diff --git a/internal/model/describe.go b/internal/model/describe.go index 96b5a6df00..c86c4001bb 100644 --- a/internal/model/describe.go +++ b/internal/model/describe.go @@ -39,6 +39,11 @@ func NewDescribe(gvr client.GVR, path string) *Describe { } } +// GVR returns the resource gvr. +func (d *Describe) GVR() client.GVR { + return d.gvr +} + // GetPath returns the active resource path. func (d *Describe) GetPath() string { return d.path diff --git a/internal/model/types.go b/internal/model/types.go index 3c9c8e3c2e..00ab43d7d8 100644 --- a/internal/model/types.go +++ b/internal/model/types.go @@ -33,6 +33,7 @@ type ViewerToggleOpts map[string]bool type ResourceViewer interface { GetPath() string Filter(string) + GVR() client.GVR ClearFilter() Peek() []string SetOptions(context.Context, ViewerToggleOpts) diff --git a/internal/model/values.go b/internal/model/values.go index ef1a898122..9a759bddc9 100644 --- a/internal/model/values.go +++ b/internal/model/values.go @@ -51,6 +51,11 @@ func getValues(path string, allValues bool) []string { return strings.Split(string(vals), "\n") } +// GVR returns the resource gvr. +func (v *Values) GVR() client.GVR { + return v.gvr +} + // ToggleValues toggles between user supplied values and computed values. func (v *Values) ToggleValues() { v.allValues = !v.allValues diff --git a/internal/model/yaml.go b/internal/model/yaml.go index dd914462d3..332af49af0 100644 --- a/internal/model/yaml.go +++ b/internal/model/yaml.go @@ -43,6 +43,11 @@ func NewYAML(gvr client.GVR, path string) *YAML { } } +// GVR returns the resource gvr. +func (y *YAML) GVR() client.GVR { + return y.gvr +} + // GetPath returns the active resource path. func (y *YAML) GetPath() string { return y.path diff --git a/internal/view/browser.go b/internal/view/browser.go index 5d2ca2467e..240f4dffb0 100644 --- a/internal/view/browser.go +++ b/internal/view/browser.go @@ -262,7 +262,7 @@ func (b *Browser) viewCmd(evt *tcell.EventKey) *tcell.EventKey { return evt } - v := NewLiveView(b.app, "YAML", model.NewYAML(b.GVR(), path)) + v := NewLiveView(b.app, yamlAction, model.NewYAML(b.GVR(), path)) if err := v.app.inject(v, false); err != nil { v.app.Flash().Err(err) } @@ -367,33 +367,42 @@ func (b *Browser) editCmd(evt *tcell.EventKey) *tcell.EventKey { if path == "" { return evt } + + b.Stop() + defer b.Start() + if err := editRes(b.app, b.GVR(), path); err != nil { + b.App().Flash().Err(err) + } + + return nil +} + +func editRes(app *App, gvr client.GVR, path string) error { + if path == "" { + return fmt.Errorf("nothing selected %q", path) + } ns, n := client.Namespaced(path) if client.IsClusterScoped(ns) { ns = client.AllNamespaces } - if b.GVR().String() == "v1/namespaces" { + if gvr.String() == "v1/namespaces" { ns = n } - if ok, err := b.app.Conn().CanI(ns, b.GVR().String(), []string{"patch"}); !ok || err != nil { - b.App().Flash().Errf("Current user can't edit resource %s", b.GVR()) - return nil + if ok, err := app.Conn().CanI(ns, gvr.String(), []string{"patch"}); !ok || err != nil { + return fmt.Errorf("current user can't edit resource %s", gvr) } - b.Stop() - defer b.Start() - { - args := make([]string, 0, 10) - args = append(args, "edit") - args = append(args, b.GVR().FQN(n)) - if ns != client.AllNamespaces { - args = append(args, "-n", ns) - } - if err := runK(b.app, shellOpts{clear: true, args: args}); err != nil { - b.app.Flash().Errf("Edit command failed: %s", err) - } + args := make([]string, 0, 10) + args = append(args, "edit") + args = append(args, gvr.FQN(n)) + if ns != client.AllNamespaces { + args = append(args, "-n", ns) + } + if err := runK(app, shellOpts{clear: true, args: args}); err != nil { + app.Flash().Errf("Edit command failed: %s", err) } - return evt + return nil } func (b *Browser) switchNamespaceCmd(evt *tcell.EventKey) *tcell.EventKey { @@ -488,7 +497,7 @@ func (b *Browser) refreshActions() { } if !dao.IsK9sMeta(b.meta) { - aa[ui.KeyY] = ui.NewKeyAction("YAML", b.viewCmd, true) + aa[ui.KeyY] = ui.NewKeyAction(yamlAction, b.viewCmd, true) aa[ui.KeyD] = ui.NewKeyAction("Describe", b.describeCmd, true) } diff --git a/internal/view/dir.go b/internal/view/dir.go index 061a72f327..699ba006e7 100644 --- a/internal/view/dir.go +++ b/internal/view/dir.go @@ -75,7 +75,7 @@ func (d *Dir) bindKeys(aa ui.KeyActions) { d.bindDangerousKeys(aa) } aa.Add(ui.KeyActions{ - ui.KeyY: ui.NewKeyAction("YAML", d.viewCmd, true), + ui.KeyY: ui.NewKeyAction(yamlAction, d.viewCmd, true), tcell.KeyEnter: ui.NewKeyAction("Goto", d.gotoCmd, true), }) } @@ -96,7 +96,7 @@ func (d *Dir) viewCmd(evt *tcell.EventKey) *tcell.EventKey { return nil } - details := NewDetails(d.App(), "YAML", sel, true).Update(string(yaml)) + details := NewDetails(d.App(), yamlAction, sel, true).Update(string(yaml)) if err := d.App().inject(details, false); err != nil { d.App().Flash().Err(err) } diff --git a/internal/view/live_view.go b/internal/view/live_view.go index 596e4705f4..a539c2c324 100644 --- a/internal/view/live_view.go +++ b/internal/view/live_view.go @@ -8,7 +8,6 @@ import ( "fmt" "strconv" "strings" - "time" "github.com/derailed/k9s/internal" "github.com/derailed/k9s/internal/config" @@ -20,7 +19,10 @@ import ( "github.com/sahilm/fuzzy" ) -const liveViewTitleFmt = "[fg:bg:b] %s([hilite:bg:b]%s[fg:bg:-])[fg:bg:-] " +const ( + liveViewTitleFmt = "[fg:bg:b] %s([hilite:bg:b]%s[fg:bg:-])[fg:bg:-] " + yamlAction = "YAML" +) // LiveView represents a live text viewer. type LiveView struct { @@ -116,10 +118,6 @@ func (*LiveView) linesWithRegions(lines []string, matches fuzzy.Matches) []strin // ResourceChanged notifies when the filter changes. func (v *LiveView) ResourceChanged(lines []string, matches fuzzy.Matches) { v.app.QueueUpdateDraw(func() { - defer func(t time.Time) { - log.Debug().Msgf("Live view render time: %v", time.Since(t)) - }(time.Now()) - v.text.SetTextAlign(tview.AlignLeft) v.maxRegions = len(matches) @@ -128,7 +126,6 @@ func (v *LiveView) ResourceChanged(lines []string, matches fuzzy.Matches) { } lines = v.linesWithRegions(lines, matches) - v.text.SetText(colorizeYAML(v.app.Styles.Views().Yaml, strings.Join(lines, "\n"))) v.text.Highlight() if v.currentRegion < v.maxRegions { @@ -166,13 +163,32 @@ func (v *LiveView) bindKeys() { tcell.KeyDelete: ui.NewSharedKeyAction("Erase", v.eraseCmd, false), }) - if v.title == "YAML" { + if !v.app.Config.K9s.IsReadOnly() { + v.actions.Add(ui.KeyActions{ + ui.KeyE: ui.NewKeyAction("Edit", v.editCmd, true), + }) + } + if v.title == yamlAction { v.actions.Add(ui.KeyActions{ ui.KeyM: ui.NewKeyAction("Toggle ManagedFields", v.toggleManagedCmd, true), }) } } +func (v *LiveView) editCmd(evt *tcell.EventKey) *tcell.EventKey { + path := v.model.GetPath() + if path == "" { + return evt + } + v.Stop() + defer v.Start() + if err := editRes(v.app, v.model.GVR(), path); err != nil { + v.app.Flash().Err(err) + } + + return nil +} + // ToggleRefreshCmd is used for pausing the refreshing of data on config map and secrets. func (v *LiveView) toggleRefreshCmd(evt *tcell.EventKey) *tcell.EventKey { v.autoRefresh = !v.autoRefresh @@ -200,9 +216,6 @@ func (v *LiveView) StylesChanged(s *config.Styles) { v.SetBackgroundColor(v.app.Styles.BgColor()) v.text.SetTextColor(v.app.Styles.FgColor()) v.SetBorderFocusColor(v.app.Styles.Frame().Border.FocusColor.Color()) - if v.model != nil { - v.ResourceChanged(v.model.Peek(), nil) - } } // Actions returns menu actions. diff --git a/internal/view/node.go b/internal/view/node.go index 9b9274b717..0743b88fe3 100644 --- a/internal/view/node.go +++ b/internal/view/node.go @@ -59,7 +59,7 @@ func (n *Node) bindKeys(aa ui.KeyActions) { } aa.Add(ui.KeyActions{ - ui.KeyY: ui.NewKeyAction("YAML", n.yamlCmd, true), + ui.KeyY: ui.NewKeyAction(yamlAction, n.yamlCmd, true), ui.KeyShiftC: ui.NewKeyAction("Sort CPU", n.GetTable().SortColCmd(cpuCol, false), false), ui.KeyShiftM: ui.NewKeyAction("Sort MEM", n.GetTable().SortColCmd(memCol, false), false), ui.KeyShift0: ui.NewKeyAction("Sort Pods", n.GetTable().SortColCmd("PODS", false), false), @@ -194,7 +194,7 @@ func (n *Node) yamlCmd(evt *tcell.EventKey) *tcell.EventKey { return nil } - details := NewDetails(n.App(), "YAML", sel, true).Update(raw) + details := NewDetails(n.App(), yamlAction, sel, true).Update(raw) if err := n.App().inject(details, false); err != nil { n.App().Flash().Err(err) } diff --git a/internal/view/xray.go b/internal/view/xray.go index 1d9c6de775..ea14e576ee 100644 --- a/internal/view/xray.go +++ b/internal/view/xray.go @@ -160,7 +160,7 @@ func (x *Xray) refreshActions() { aa[tcell.KeyCtrlD] = ui.NewKeyAction("Delete", x.deleteCmd, true) } if !dao.IsK9sMeta(x.meta) { - aa[ui.KeyY] = ui.NewKeyAction("YAML", x.viewCmd, true) + aa[ui.KeyY] = ui.NewKeyAction(yamlAction, x.viewCmd, true) aa[ui.KeyD] = ui.NewKeyAction("Describe", x.describeCmd, true) } @@ -341,7 +341,7 @@ func (x *Xray) viewCmd(evt *tcell.EventKey) *tcell.EventKey { return nil } - details := NewDetails(x.app, "YAML", spec.Path(), true).Update(raw) + details := NewDetails(x.app, yamlAction, spec.Path(), true).Update(raw) if err := x.app.inject(details, false); err != nil { x.app.Flash().Err(err) } From e8aa2a8affcceb3ad87c9c0adcd75fc82ba26e11 Mon Sep 17 00:00:00 2001 From: derailed Date: Sat, 25 Nov 2023 09:53:30 -0700 Subject: [PATCH 17/22] Feat: Add helm release history support --- internal/dao/{helm.go => helm_chart.go} | 55 +++++----- internal/dao/helm_history.go | 133 +++++++++++++++++++++++ internal/dao/registry.go | 67 +++++++----- internal/keys.go | 1 + internal/model/registry.go | 17 +-- internal/model/values.go | 4 +- internal/render/benchmark.go | 2 +- internal/render/container.go | 4 +- internal/render/cr.go | 2 +- internal/render/crb.go | 2 +- internal/render/crd.go | 4 +- internal/render/cronjob.go | 4 +- internal/render/dp.go | 4 +- internal/render/ds.go | 4 +- internal/render/ep.go | 2 +- internal/render/helm.go | 97 ----------------- internal/render/helm/chart.go | 91 ++++++++++++++++ internal/render/helm/history.go | 68 ++++++++++++ internal/render/helpers.go | 6 +- internal/render/helpers_test.go | 2 +- internal/render/job.go | 4 +- internal/render/node.go | 4 +- internal/render/np.go | 2 +- internal/render/ns.go | 4 +- internal/render/pdb.go | 4 +- internal/render/pod.go | 4 +- internal/render/pv.go | 4 +- internal/render/pvc.go | 4 +- internal/render/ro.go | 2 +- internal/render/rob.go | 2 +- internal/render/rs.go | 4 +- internal/render/sa.go | 2 +- internal/render/sc.go | 2 +- internal/render/sts.go | 4 +- internal/render/svc.go | 4 +- internal/view/{helm.go => helm_chart.go} | 56 +++++++--- internal/view/helm_history.go | 106 ++++++++++++++++++ internal/view/registrar.go | 6 +- 38 files changed, 566 insertions(+), 221 deletions(-) rename internal/dao/{helm.go => helm_chart.go} (56%) create mode 100644 internal/dao/helm_history.go delete mode 100644 internal/render/helm.go create mode 100644 internal/render/helm/chart.go create mode 100644 internal/render/helm/history.go rename internal/view/{helm.go => helm_chart.go} (50%) create mode 100644 internal/view/helm_history.go diff --git a/internal/dao/helm.go b/internal/dao/helm_chart.go similarity index 56% rename from internal/dao/helm.go rename to internal/dao/helm_chart.go index 3bd03edb93..8aa26dcafe 100644 --- a/internal/dao/helm.go +++ b/internal/dao/helm_chart.go @@ -9,7 +9,7 @@ import ( "os" "github.com/derailed/k9s/internal/client" - "github.com/derailed/k9s/internal/render" + "github.com/derailed/k9s/internal/render/helm" "github.com/rs/zerolog/log" "gopkg.in/yaml.v2" "helm.sh/helm/v3/pkg/action" @@ -18,19 +18,19 @@ import ( ) var ( - _ Accessor = (*Helm)(nil) - _ Nuker = (*Helm)(nil) - _ Describer = (*Helm)(nil) + _ Accessor = (*HelmChart)(nil) + _ Nuker = (*HelmChart)(nil) + _ Describer = (*HelmChart)(nil) ) -// Helm represents a helm chart. -type Helm struct { +// HelmChart represents a helm chart. +type HelmChart struct { NonResource } // List returns a collection of resources. -func (h *Helm) List(ctx context.Context, ns string) ([]runtime.Object, error) { - cfg, err := h.EnsureHelmConfig(ns) +func (h *HelmChart) List(ctx context.Context, ns string) ([]runtime.Object, error) { + cfg, err := ensureHelmConfig(h.Client(), ns) if err != nil { return nil, err } @@ -45,16 +45,16 @@ func (h *Helm) List(ctx context.Context, ns string) ([]runtime.Object, error) { oo := make([]runtime.Object, 0, len(rr)) for _, r := range rr { - oo = append(oo, render.HelmRes{Release: r}) + oo = append(oo, helm.ReleaseRes{Release: r}) } return oo, nil } // Get returns a resource. -func (h *Helm) Get(_ context.Context, path string) (runtime.Object, error) { +func (h *HelmChart) Get(_ context.Context, path string) (runtime.Object, error) { ns, n := client.Namespaced(path) - cfg, err := h.EnsureHelmConfig(ns) + cfg, err := ensureHelmConfig(h.Client(), ns) if err != nil { return nil, err } @@ -63,13 +63,13 @@ func (h *Helm) Get(_ context.Context, path string) (runtime.Object, error) { return nil, err } - return render.HelmRes{Release: resp}, nil + return helm.ReleaseRes{Release: resp}, nil } // GetValues returns values for a release -func (h *Helm) GetValues(path string, allValues bool) ([]byte, error) { +func (h *HelmChart) GetValues(path string, allValues bool) ([]byte, error) { ns, n := client.Namespaced(path) - cfg, err := h.EnsureHelmConfig(ns) + cfg, err := ensureHelmConfig(h.Client(), ns) if err != nil { return nil, err } @@ -84,9 +84,9 @@ func (h *Helm) GetValues(path string, allValues bool) ([]byte, error) { } // Describe returns the chart notes. -func (h *Helm) Describe(path string) (string, error) { +func (h *HelmChart) Describe(path string) (string, error) { ns, n := client.Namespaced(path) - cfg, err := h.EnsureHelmConfig(ns) + cfg, err := ensureHelmConfig(h.Client(), ns) if err != nil { return "", err } @@ -99,9 +99,9 @@ func (h *Helm) Describe(path string) (string, error) { } // ToYAML returns the chart manifest. -func (h *Helm) ToYAML(path string, showManaged bool) (string, error) { +func (h *HelmChart) ToYAML(path string, showManaged bool) (string, error) { ns, n := client.Namespaced(path) - cfg, err := h.EnsureHelmConfig(ns) + cfg, err := ensureHelmConfig(h.Client(), ns) if err != nil { return "", err } @@ -113,15 +113,20 @@ func (h *Helm) ToYAML(path string, showManaged bool) (string, error) { return resp.Manifest, nil } -// Delete uninstall a Helm. -func (h *Helm) Delete(_ context.Context, path string, _ *metav1.DeletionPropagation, _ Grace) error { +// Delete uninstall a HelmChart. +func (h *HelmChart) Delete(_ context.Context, path string, _ *metav1.DeletionPropagation, _ Grace) error { + return h.Uninstall(path, false) +} + +// Uninstall uninstalls a HelmChart. +func (h *HelmChart) Uninstall(path string, keepHist bool) error { ns, n := client.Namespaced(path) - cfg, err := h.EnsureHelmConfig(ns) + cfg, err := ensureHelmConfig(h.Client(), ns) if err != nil { return err } u := action.NewUninstall(cfg) - u.KeepHistory = true + u.KeepHistory = keepHist res, err := u.Run(n) if err != nil { return err @@ -133,10 +138,10 @@ func (h *Helm) Delete(_ context.Context, path string, _ *metav1.DeletionPropagat return nil } -// EnsureHelmConfig return a new configuration. -func (h *Helm) EnsureHelmConfig(ns string) (*action.Configuration, error) { +// ensureHelmConfig return a new configuration. +func ensureHelmConfig(c client.Connection, ns string) (*action.Configuration, error) { cfg := new(action.Configuration) - err := cfg.Init(h.Client().Config().Flags(), ns, os.Getenv("HELM_DRIVER"), helmLogger) + err := cfg.Init(c.Config().Flags(), ns, os.Getenv("HELM_DRIVER"), helmLogger) return cfg, err } diff --git a/internal/dao/helm_history.go b/internal/dao/helm_history.go new file mode 100644 index 0000000000..3699c4a82e --- /dev/null +++ b/internal/dao/helm_history.go @@ -0,0 +1,133 @@ +package dao + +import ( + "context" + "fmt" + "strconv" + + "github.com/derailed/k9s/internal" + "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/render/helm" + "helm.sh/helm/v3/pkg/action" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +var ( + _ Accessor = (*HelmHistory)(nil) + _ Nuker = (*HelmHistory)(nil) + _ Describer = (*HelmHistory)(nil) +) + +// HelmHistory represents a helm chart. +type HelmHistory struct { + NonResource +} + +// List returns a collection of resources. +func (h *HelmHistory) List(ctx context.Context, ns string) ([]runtime.Object, error) { + path, ok := ctx.Value(internal.KeyFQN).(string) + if !ok { + return nil, fmt.Errorf("expecting FQN in context") + } + ns, n := client.Namespaced(path) + + cfg, err := ensureHelmConfig(h.Client(), ns) + if err != nil { + return nil, err + } + + hh, err := action.NewHistory(cfg).Run(n) + if err != nil { + return nil, err + } + + oo := make([]runtime.Object, 0, len(hh)) + for _, r := range hh { + oo = append(oo, helm.ReleaseRes{Release: r}) + } + + return oo, nil +} + +// Get returns a resource. +func (h *HelmHistory) Get(_ context.Context, path string) (runtime.Object, error) { + ns, n := client.Namespaced(path) + cfg, err := ensureHelmConfig(h.Client(), ns) + if err != nil { + return nil, err + } + resp, err := action.NewGet(cfg).Run(n) + if err != nil { + return nil, err + } + + return helm.ReleaseRes{Release: resp}, nil +} + +// Describe returns the chart notes. +func (h *HelmHistory) Describe(path string) (string, error) { + ns, n := client.Namespaced(path) + cfg, err := ensureHelmConfig(h.Client(), ns) + if err != nil { + return "", err + } + resp, err := action.NewGet(cfg).Run(n) + if err != nil { + return "", err + } + + return resp.Info.Notes, nil +} + +// ToYAML returns the chart manifest. +func (h *HelmHistory) ToYAML(path string, showManaged bool) (string, error) { + ns, n := client.Namespaced(path) + cfg, err := ensureHelmConfig(h.Client(), ns) + if err != nil { + return "", err + } + resp, err := action.NewGet(cfg).Run(n) + if err != nil { + return "", err + } + + return resp.Manifest, nil +} + +func (h *HelmHistory) Rollback(_ context.Context, path, rev string) error { + ns, n := client.Namespaced(path) + cfg, err := ensureHelmConfig(h.Client(), ns) + if err != nil { + return err + } + + ver, err := strconv.Atoi(rev) + if err != nil { + return fmt.Errorf("could not convert revision to a number: %w", err) + } + client := action.NewRollback(cfg) + client.Version = ver + + return client.Run(n) +} + +// Delete uninstall a Helm. +func (h *HelmHistory) Delete(_ context.Context, path string, _ *metav1.DeletionPropagation, _ Grace) error { + ns, n := client.Namespaced(path) + cfg, err := ensureHelmConfig(h.Client(), ns) + if err != nil { + return err + } + + res, err := action.NewUninstall(cfg).Run(n) + if err != nil { + return err + } + + if res != nil && res.Info != "" { + return fmt.Errorf("%s", res.Info) + } + + return nil +} diff --git a/internal/dao/registry.go b/internal/dao/registry.go index 0d60d990b4..c67a94e5e8 100644 --- a/internal/dao/registry.go +++ b/internal/dao/registry.go @@ -17,8 +17,11 @@ import ( "k8s.io/apimachinery/pkg/runtime" ) -// CRD identifies a CRD. -const CRD = "crd" +const ( + crdCat = "crd" + k9sCat = "k9s" + helmCat = "helm" +) // MetaAccess tracks resources metadata. var MetaAccess = NewMeta() @@ -96,14 +99,13 @@ func AccessorFor(f Factory, gvr client.GVR) (Accessor, error) { client.NewGVR("batch/v1/jobs"): &Job{}, client.NewGVR("v1/namespaces"): &Namespace{}, client.NewGVR("popeye"): &Popeye{}, - client.NewGVR("sanitizer"): &Popeye{}, - client.NewGVR("helm"): &Helm{}, + client.NewGVR("helm"): &HelmChart{}, client.NewGVR("dir"): &Dir{}, } r, ok := m[gvr] if !ok { - r = &Generic{} + r = new(Generic) log.Debug().Msgf("No DAO registry entry for %q. Using generics!", gvr) } r.Init(f, gvr) @@ -136,7 +138,7 @@ func (m *Meta) AllGVRs() client.GVRs { // IsCRD checks if resource represents a CRD func IsCRD(r metav1.APIResource) bool { for _, c := range r.Categories { - if c == CRD { + if c == crdCat { return true } } @@ -158,7 +160,7 @@ func (m *Meta) MetaFor(gvr client.GVR) (metav1.APIResource, error) { // IsK8sMeta checks for non resource meta. func IsK8sMeta(m metav1.APIResource) bool { for _, c := range m.Categories { - if c == "k9s" || c == "helm" || c == "faas" { + if c == k9sCat || c == helmCat { return false } } @@ -169,7 +171,7 @@ func IsK8sMeta(m metav1.APIResource) bool { // IsK9sMeta checks for non resource meta. func IsK9sMeta(m metav1.APIResource) bool { for _, c := range m.Categories { - if c == "k9s" { + if c == k9sCat { return true } } @@ -205,33 +207,33 @@ func loadK9s(m ResourceMetas) { Kind: "Pulse", SingularName: "pulses", ShortNames: []string{"hz", "pu"}, - Categories: []string{"k9s"}, + Categories: []string{k9sCat}, } m[client.NewGVR("dir")] = metav1.APIResource{ Name: "dir", Kind: "Dir", SingularName: "dir", - Categories: []string{"k9s"}, + Categories: []string{k9sCat}, } m[client.NewGVR("xrays")] = metav1.APIResource{ Name: "xray", Kind: "XRays", SingularName: "xray", - Categories: []string{"k9s"}, + Categories: []string{k9sCat}, } m[client.NewGVR("references")] = metav1.APIResource{ Name: "references", Kind: "References", SingularName: "reference", Verbs: []string{}, - Categories: []string{"k9s"}, + Categories: []string{k9sCat}, } m[client.NewGVR("aliases")] = metav1.APIResource{ Name: "aliases", Kind: "Aliases", SingularName: "alias", Verbs: []string{}, - Categories: []string{"k9s"}, + Categories: []string{k9sCat}, } m[client.NewGVR("popeye")] = metav1.APIResource{ Name: "popeye", @@ -239,14 +241,14 @@ func loadK9s(m ResourceMetas) { SingularName: "popeye", Namespaced: true, Verbs: []string{}, - Categories: []string{"k9s"}, + Categories: []string{k9sCat}, } m[client.NewGVR("sanitizer")] = metav1.APIResource{ Name: "sanitizer", Kind: "Sanitizer", SingularName: "sanitizer", Verbs: []string{}, - Categories: []string{"k9s"}, + Categories: []string{k9sCat}, } m[client.NewGVR("contexts")] = metav1.APIResource{ Name: "contexts", @@ -254,7 +256,7 @@ func loadK9s(m ResourceMetas) { SingularName: "context", ShortNames: []string{"ctx"}, Verbs: []string{}, - Categories: []string{"k9s"}, + Categories: []string{k9sCat}, } m[client.NewGVR("screendumps")] = metav1.APIResource{ Name: "screendumps", @@ -262,7 +264,7 @@ func loadK9s(m ResourceMetas) { SingularName: "screendump", ShortNames: []string{"sd"}, Verbs: []string{"delete"}, - Categories: []string{"k9s"}, + Categories: []string{k9sCat}, } m[client.NewGVR("benchmarks")] = metav1.APIResource{ Name: "benchmarks", @@ -270,7 +272,7 @@ func loadK9s(m ResourceMetas) { SingularName: "benchmark", ShortNames: []string{"be"}, Verbs: []string{"delete"}, - Categories: []string{"k9s"}, + Categories: []string{k9sCat}, } m[client.NewGVR("portforwards")] = metav1.APIResource{ Name: "portforwards", @@ -279,24 +281,31 @@ func loadK9s(m ResourceMetas) { SingularName: "portforward", ShortNames: []string{"pf"}, Verbs: []string{"delete"}, - Categories: []string{"k9s"}, + Categories: []string{k9sCat}, } m[client.NewGVR("containers")] = metav1.APIResource{ Name: "containers", Kind: "Containers", SingularName: "container", Verbs: []string{}, - Categories: []string{"k9s"}, + Categories: []string{k9sCat}, } } func loadHelm(m ResourceMetas) { m[client.NewGVR("helm")] = metav1.APIResource{ - Name: "helm", - Kind: "Helm", + Name: "chart", + Kind: "Chart", + Namespaced: true, + Verbs: []string{"delete"}, + Categories: []string{helmCat}, + } + m[client.NewGVR("helm-history")] = metav1.APIResource{ + Name: "history", + Kind: "History", Namespaced: true, Verbs: []string{"delete"}, - Categories: []string{"helm"}, + Categories: []string{k9sCat}, } } @@ -304,23 +313,23 @@ func loadRBAC(m ResourceMetas) { m[client.NewGVR("rbac")] = metav1.APIResource{ Name: "rbacs", Kind: "Rules", - Categories: []string{"k9s"}, + Categories: []string{k9sCat}, } m[client.NewGVR("policy")] = metav1.APIResource{ Name: "policies", Kind: "Rules", Namespaced: true, - Categories: []string{"k9s"}, + Categories: []string{k9sCat}, } m[client.NewGVR("users")] = metav1.APIResource{ Name: "users", Kind: "User", - Categories: []string{"k9s"}, + Categories: []string{k9sCat}, } m[client.NewGVR("groups")] = metav1.APIResource{ Name: "groups", Kind: "Group", - Categories: []string{"k9s"}, + Categories: []string{k9sCat}, } } @@ -349,7 +358,7 @@ func loadPreferred(f Factory, m ResourceMetas) error { res.SingularName = strings.ToLower(res.Kind) } if !isStandardGroup(res.Group) { - res.Categories = append(res.Categories, CRD) + res.Categories = append(res.Categories, crdCat) } m[gvr] = res } @@ -394,7 +403,7 @@ func loadCRDs(f Factory, m ResourceMetas) { log.Error().Err(errs[0]).Msgf("Fail to extract CRD meta (%d) errors", len(errs)) continue } - meta.Categories = append(meta.Categories, CRD) + meta.Categories = append(meta.Categories, crdCat) gvr := client.NewGVRFromMeta(meta) m[gvr] = meta } diff --git a/internal/keys.go b/internal/keys.go index 1b53cfece6..db4aeda484 100644 --- a/internal/keys.go +++ b/internal/keys.go @@ -16,6 +16,7 @@ const ( KeyPath ContextKey = "path" KeySubject ContextKey = "subject" KeyGVR ContextKey = "gvr" + KeyFQN ContextKey = "fqn" KeyForwards ContextKey = "forwards" KeyContainers ContextKey = "containers" KeyBenchCfg ContextKey = "benchcfg" diff --git a/internal/model/registry.go b/internal/model/registry.go index cb4259792a..e0b0c93938 100644 --- a/internal/model/registry.go +++ b/internal/model/registry.go @@ -6,6 +6,7 @@ package model import ( "github.com/derailed/k9s/internal/dao" "github.com/derailed/k9s/internal/render" + "github.com/derailed/k9s/internal/render/helm" "github.com/derailed/k9s/internal/xray" ) @@ -25,14 +26,14 @@ var Registry = map[string]ResourceMeta{ DAO: &dao.Pulse{}, }, "helm": { - DAO: &dao.Helm{}, - Renderer: &render.Helm{}, - }, - // BOZO!! revamp with latest... - // "openfaas": { - // DAO: &dao.OpenFaas{}, - // Renderer: &render.OpenFaas{}, - // }, + DAO: &dao.HelmChart{}, + Renderer: &helm.Chart{}, + }, + "helm-history": { + DAO: &dao.HelmHistory{}, + Renderer: &helm.History{}, + }, + "containers": { DAO: &dao.Container{}, Renderer: &render.Container{}, diff --git a/internal/model/values.go b/internal/model/values.go index 9a759bddc9..7dce96c02d 100644 --- a/internal/model/values.go +++ b/internal/model/values.go @@ -39,8 +39,8 @@ func NewValues(gvr client.GVR, path string) *Values { } } -func getHelmDao() *dao.Helm { - return Registry["helm"].DAO.(*dao.Helm) +func getHelmDao() *dao.HelmChart { + return Registry["helm"].DAO.(*dao.HelmChart) } func getValues(path string, allValues bool) []string { diff --git a/internal/render/benchmark.go b/internal/render/benchmark.go index 76a9c1d931..0f60d4decf 100644 --- a/internal/render/benchmark.go +++ b/internal/render/benchmark.go @@ -75,7 +75,7 @@ func (b Benchmark) Render(o interface{}, ns string, r *Row) error { return err } b.augmentRow(r.Fields, data) - r.Fields[8] = asStatus(b.diagnose(ns, r.Fields)) + r.Fields[8] = AsStatus(b.diagnose(ns, r.Fields)) return nil } diff --git a/internal/render/container.go b/internal/render/container.go index 6799fa6891..662441c0e6 100644 --- a/internal/render/container.go +++ b/internal/render/container.go @@ -127,8 +127,8 @@ func (c Container) Render(o interface{}, name string, r *Row) error { client.ToPercentageStr(cur.mem, res.mem), client.ToPercentageStr(cur.mem, res.lmem), ToContainerPorts(co.Container.Ports), - asStatus(c.diagnose(state, ready)), - toAge(co.Age), + AsStatus(c.diagnose(state, ready)), + ToAge(co.Age), } return nil diff --git a/internal/render/cr.go b/internal/render/cr.go index 925b75350f..5a0a84fdbd 100644 --- a/internal/render/cr.go +++ b/internal/render/cr.go @@ -42,7 +42,7 @@ func (ClusterRole) Render(o interface{}, ns string, r *Row) error { r.Fields = Fields{ cr.Name, mapToStr(cr.Labels), - toAge(cr.GetCreationTimestamp()), + ToAge(cr.GetCreationTimestamp()), } return nil diff --git a/internal/render/crb.go b/internal/render/crb.go index 1095f13fb7..e051337dcf 100644 --- a/internal/render/crb.go +++ b/internal/render/crb.go @@ -50,7 +50,7 @@ func (ClusterRoleBinding) Render(o interface{}, ns string, r *Row) error { kind, ss, mapToStr(crb.Labels), - toAge(crb.GetCreationTimestamp()), + ToAge(crb.GetCreationTimestamp()), } return nil diff --git a/internal/render/crd.go b/internal/render/crd.go index c9824856da..bed197fbc3 100644 --- a/internal/render/crd.go +++ b/internal/render/crd.go @@ -63,8 +63,8 @@ func (c CustomResourceDefinition) Render(o interface{}, ns string, r *Row) error crd.GetName(), naStrings(versions), mapToIfc(crd.GetLabels()), - asStatus(c.diagnose(crd.GetName(), crd.Spec.Versions)), - toAge(crd.GetCreationTimestamp()), + AsStatus(c.diagnose(crd.GetName(), crd.Spec.Versions)), + ToAge(crd.GetCreationTimestamp()), } return nil diff --git a/internal/render/cronjob.go b/internal/render/cronjob.go index dc9fd0c52e..b0947bb888 100644 --- a/internal/render/cronjob.go +++ b/internal/render/cronjob.go @@ -52,7 +52,7 @@ func (c CronJob) Render(o interface{}, ns string, r *Row) error { lastScheduled := "" if cj.Status.LastScheduleTime != nil { - lastScheduled = toAge(*cj.Status.LastScheduleTime) + lastScheduled = ToAge(*cj.Status.LastScheduleTime) } r.ID = client.MetaFQN(cj.ObjectMeta) @@ -68,7 +68,7 @@ func (c CronJob) Render(o interface{}, ns string, r *Row) error { podImageNames(cj.Spec.JobTemplate.Spec.Template.Spec, true), mapToStr(cj.Labels), "", - toAge(cj.GetCreationTimestamp()), + ToAge(cj.GetCreationTimestamp()), } return nil diff --git a/internal/render/dp.go b/internal/render/dp.go index 6a0f58e0a1..79a3abb2ef 100644 --- a/internal/render/dp.go +++ b/internal/render/dp.go @@ -59,8 +59,8 @@ func (d Deployment) Render(o interface{}, ns string, r *Row) error { strconv.Itoa(int(dp.Status.UpdatedReplicas)), strconv.Itoa(int(dp.Status.AvailableReplicas)), mapToStr(dp.Labels), - asStatus(d.diagnose(dp.Status.Replicas, dp.Status.AvailableReplicas)), - toAge(dp.GetCreationTimestamp()), + AsStatus(d.diagnose(dp.Status.Replicas, dp.Status.AvailableReplicas)), + ToAge(dp.GetCreationTimestamp()), } return nil diff --git a/internal/render/ds.go b/internal/render/ds.go index e40c30faf9..161f68cb5a 100644 --- a/internal/render/ds.go +++ b/internal/render/ds.go @@ -57,8 +57,8 @@ func (d DaemonSet) Render(o interface{}, ns string, r *Row) error { strconv.Itoa(int(ds.Status.UpdatedNumberScheduled)), strconv.Itoa(int(ds.Status.NumberAvailable)), mapToStr(ds.Labels), - asStatus(d.diagnose(ds.Status.DesiredNumberScheduled, ds.Status.NumberReady)), - toAge(ds.GetCreationTimestamp()), + AsStatus(d.diagnose(ds.Status.DesiredNumberScheduled, ds.Status.NumberReady)), + ToAge(ds.GetCreationTimestamp()), } return nil diff --git a/internal/render/ep.go b/internal/render/ep.go index 2587caa208..15af70d1b4 100644 --- a/internal/render/ep.go +++ b/internal/render/ep.go @@ -47,7 +47,7 @@ func (e Endpoints) Render(o interface{}, ns string, r *Row) error { ep.Namespace, ep.Name, missing(toEPs(ep.Subsets)), - toAge(ep.GetCreationTimestamp()), + ToAge(ep.GetCreationTimestamp()), } return nil diff --git a/internal/render/helm.go b/internal/render/helm.go deleted file mode 100644 index 6ec905a6ac..0000000000 --- a/internal/render/helm.go +++ /dev/null @@ -1,97 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright Authors of K9s - -package render - -import ( - "fmt" - "strconv" - - "github.com/derailed/k9s/internal/client" - "github.com/derailed/tcell/v2" - "helm.sh/helm/v3/pkg/release" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -// Helm renders a helm chart to screen. -type Helm struct{} - -// IsGeneric identifies a generic handler. -func (Helm) IsGeneric() bool { - return false -} - -// ColorerFunc colors a resource row. -func (Helm) ColorerFunc() ColorerFunc { - return func(ns string, h Header, re RowEvent) tcell.Color { - if !Happy(ns, h, re.Row) { - return ErrColor - } - - return tcell.ColorMediumSpringGreen - } -} - -// Header returns a header row. -func (Helm) Header(_ string) Header { - return Header{ - HeaderColumn{Name: "NAMESPACE"}, - HeaderColumn{Name: "NAME"}, - HeaderColumn{Name: "REVISION"}, - HeaderColumn{Name: "STATUS"}, - HeaderColumn{Name: "CHART"}, - HeaderColumn{Name: "APP VERSION"}, - HeaderColumn{Name: "VALID", Wide: true}, - HeaderColumn{Name: "AGE", Time: true}, - } -} - -// Render renders a chart to screen. -func (c Helm) Render(o interface{}, ns string, r *Row) error { - h, ok := o.(HelmRes) - if !ok { - return fmt.Errorf("expected HelmRes, but got %T", o) - } - - r.ID = client.FQN(h.Release.Namespace, h.Release.Name) - r.Fields = Fields{ - h.Release.Namespace, - h.Release.Name, - strconv.Itoa(h.Release.Version), - h.Release.Info.Status.String(), - h.Release.Chart.Metadata.Name + "-" + h.Release.Chart.Metadata.Version, - h.Release.Chart.Metadata.AppVersion, - asStatus(c.diagnose(h.Release.Info.Status.String())), - toAge(metav1.Time{Time: h.Release.Info.LastDeployed.Time}), - } - - return nil -} - -func (c Helm) diagnose(s string) error { - if s != "deployed" { - return fmt.Errorf("chart is in an invalid state") - } - - return nil -} - -// ---------------------------------------------------------------------------- -// Helpers... - -// HelmRes represents an helm chart resource. -type HelmRes struct { - Release *release.Release -} - -// GetObjectKind returns a schema object. -func (HelmRes) GetObjectKind() schema.ObjectKind { - return nil -} - -// DeepCopyObject returns a container copy. -func (h HelmRes) DeepCopyObject() runtime.Object { - return h -} diff --git a/internal/render/helm/chart.go b/internal/render/helm/chart.go new file mode 100644 index 0000000000..b41d51f0b5 --- /dev/null +++ b/internal/render/helm/chart.go @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of K9s + +package helm + +import ( + "fmt" + "strconv" + + "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/render" + "helm.sh/helm/v3/pkg/release" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// Chart renders a helm chart to screen. +type Chart struct{} + +// IsGeneric identifies a generic handler. +func (Chart) IsGeneric() bool { + return false +} + +// ColorerFunc colors a resource row. +func (Chart) ColorerFunc() render.ColorerFunc { + return render.DefaultColorer +} + +// Header returns a header row. +func (Chart) Header(_ string) render.Header { + return render.Header{ + render.HeaderColumn{Name: "NAMESPACE"}, + render.HeaderColumn{Name: "NAME"}, + render.HeaderColumn{Name: "REVISION"}, + render.HeaderColumn{Name: "STATUS"}, + render.HeaderColumn{Name: "CHART"}, + render.HeaderColumn{Name: "APP VERSION"}, + render.HeaderColumn{Name: "VALID", Wide: true}, + render.HeaderColumn{Name: "AGE", Time: true}, + } +} + +// Render renders a chart to screen. +func (c Chart) Render(o interface{}, ns string, r *render.Row) error { + h, ok := o.(ReleaseRes) + if !ok { + return fmt.Errorf("expected ReleaseRes, but got %T", o) + } + + r.ID = client.FQN(h.Release.Namespace, h.Release.Name) + r.Fields = render.Fields{ + h.Release.Namespace, + h.Release.Name, + strconv.Itoa(h.Release.Version), + h.Release.Info.Status.String(), + h.Release.Chart.Metadata.Name + "-" + h.Release.Chart.Metadata.Version, + h.Release.Chart.Metadata.AppVersion, + render.AsStatus(c.diagnose(h.Release.Info.Status.String())), + render.ToAge(metav1.Time{Time: h.Release.Info.LastDeployed.Time}), + } + + return nil +} + +func (c Chart) diagnose(s string) error { + if s != "deployed" { + return fmt.Errorf("chart is in an invalid state") + } + + return nil +} + +// ---------------------------------------------------------------------------- +// Helpers... + +// ReleaseRes represents an helm chart resource. +type ReleaseRes struct { + Release *release.Release +} + +// GetObjectKind returns a schema object. +func (ReleaseRes) GetObjectKind() schema.ObjectKind { + return nil +} + +// DeepCopyObject returns a container copy. +func (h ReleaseRes) DeepCopyObject() runtime.Object { + return h +} diff --git a/internal/render/helm/history.go b/internal/render/helm/history.go new file mode 100644 index 0000000000..5fbbaf6d09 --- /dev/null +++ b/internal/render/helm/history.go @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of K9s + +package helm + +import ( + "context" + "fmt" + "strconv" + + "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/render" +) + +// History renders a History chart to screen. +type History struct{} + +// Healthy checks component health. +func (History) Healthy(ctx context.Context, o interface{}) error { + return nil +} + +// IsGeneric identifies a generic handler. +func (History) IsGeneric() bool { + return false +} + +// ColorerFunc colors a resource row. +func (History) ColorerFunc() render.ColorerFunc { + return render.DefaultColorer +} + +// Header returns a header row. +func (History) Header(_ string) render.Header { + return render.Header{ + render.HeaderColumn{Name: "REVISION"}, + render.HeaderColumn{Name: "STATUS"}, + render.HeaderColumn{Name: "CHART"}, + render.HeaderColumn{Name: "APP VERSION"}, + render.HeaderColumn{Name: "DESCRIPTION"}, + render.HeaderColumn{Name: "VALID", Wide: true}, + } +} + +// Render renders a chart to screen. +func (c History) Render(o interface{}, ns string, r *render.Row) error { + h, ok := o.(ReleaseRes) + if !ok { + return fmt.Errorf("expected HistoryRes, but got %T", o) + } + + r.ID = client.FQN(h.Release.Namespace, h.Release.Name) + r.ID += ":" + strconv.Itoa(h.Release.Version) + r.Fields = render.Fields{ + strconv.Itoa(h.Release.Version), + h.Release.Info.Status.String(), + h.Release.Chart.Metadata.Name + "-" + h.Release.Chart.Metadata.Version, + h.Release.Chart.Metadata.AppVersion, + h.Release.Info.Description, + render.AsStatus(c.diagnose(h.Release.Info.Status.String())), + } + + return nil +} + +func (c History) diagnose(s string) error { + return nil +} diff --git a/internal/render/helpers.go b/internal/render/helpers.go index cba70c9a71..2d2d345d4a 100644 --- a/internal/render/helpers.go +++ b/internal/render/helpers.go @@ -85,7 +85,8 @@ func Happy(ns string, h Header, r Row) bool { return strings.TrimSpace(r.Fields[validCol]) == "" } -func asStatus(err error) string { +// AsStatus returns error as string. +func AsStatus(err error) string { if err == nil { return "" } @@ -204,7 +205,8 @@ func boolToStr(b bool) string { } } -func toAge(t metav1.Time) string { +// ToAge converts time to human duration. +func ToAge(t metav1.Time) string { if t.IsZero() { return UnknownValue } diff --git a/internal/render/helpers_test.go b/internal/render/helpers_test.go index 8b220c2174..84c19a49cb 100644 --- a/internal/render/helpers_test.go +++ b/internal/render/helpers_test.go @@ -103,7 +103,7 @@ func TestToAge(t *testing.T) { for k := range uu { uc := uu[k] t.Run(k, func(t *testing.T) { - assert.Equal(t, uc.e, toAge(metav1.Time{Time: uc.t})) + assert.Equal(t, uc.e, ToAge(metav1.Time{Time: uc.t})) }) } } diff --git a/internal/render/job.go b/internal/render/job.go index edd030177e..5d9c3d0fbb 100644 --- a/internal/render/job.go +++ b/internal/render/job.go @@ -62,8 +62,8 @@ func (j Job) Render(o interface{}, ns string, r *Row) error { jobSelector(job.Spec), cc, ii, - asStatus(j.diagnose(ready, job.Status.CompletionTime)), - toAge(job.GetCreationTimestamp()), + AsStatus(j.diagnose(ready, job.Status.CompletionTime)), + ToAge(job.GetCreationTimestamp()), } return nil diff --git a/internal/render/node.go b/internal/render/node.go index 28395b50e2..17c80d947f 100644 --- a/internal/render/node.go +++ b/internal/render/node.go @@ -103,8 +103,8 @@ func (n Node) Render(o interface{}, ns string, r *Row) error { toMc(a.cpu), toMi(a.mem), mapToStr(no.Labels), - asStatus(n.diagnose(statuses)), - toAge(no.GetCreationTimestamp()), + AsStatus(n.diagnose(statuses)), + ToAge(no.GetCreationTimestamp()), } return nil diff --git a/internal/render/np.go b/internal/render/np.go index 03bd65c36a..26333aebfe 100644 --- a/internal/render/np.go +++ b/internal/render/np.go @@ -63,7 +63,7 @@ func (n NetworkPolicy) Render(o interface{}, ns string, r *Row) error { eb, mapToStr(np.Labels), "", - toAge(np.GetCreationTimestamp()), + ToAge(np.GetCreationTimestamp()), } return nil diff --git a/internal/render/ns.go b/internal/render/ns.go index 1b2c50c223..ddf34cf6e4 100644 --- a/internal/render/ns.go +++ b/internal/render/ns.go @@ -68,8 +68,8 @@ func (n Namespace) Render(o interface{}, _ string, r *Row) error { ns.Name, string(ns.Status.Phase), mapToStr(ns.Labels), - asStatus(n.diagnose(ns.Status.Phase)), - toAge(ns.GetCreationTimestamp()), + AsStatus(n.diagnose(ns.Status.Phase)), + ToAge(ns.GetCreationTimestamp()), } return nil diff --git a/internal/render/pdb.go b/internal/render/pdb.go index 3b8366047d..3b29962d56 100644 --- a/internal/render/pdb.go +++ b/internal/render/pdb.go @@ -60,8 +60,8 @@ func (p PodDisruptionBudget) Render(o interface{}, ns string, r *Row) error { strconv.Itoa(int(pdb.Status.DesiredHealthy)), strconv.Itoa(int(pdb.Status.ExpectedPods)), mapToStr(pdb.Labels), - asStatus(p.diagnose(pdb.Spec.MinAvailable, pdb.Status.CurrentHealthy)), - toAge(pdb.GetCreationTimestamp()), + AsStatus(p.diagnose(pdb.Spec.MinAvailable, pdb.Status.CurrentHealthy)), + ToAge(pdb.GetCreationTimestamp()), } return nil diff --git a/internal/render/pod.go b/internal/render/pod.go index a9288017c3..0740bc5feb 100644 --- a/internal/render/pod.go +++ b/internal/render/pod.go @@ -150,8 +150,8 @@ func (p Pod) Render(o interface{}, ns string, row *Row) error { client.ToPercentageStr(c.mem, r.lmem), p.mapQOS(po.Status.QOSClass), mapToStr(po.Labels), - asStatus(p.diagnose(phase, cr, len(cs))), - toAge(po.GetCreationTimestamp()), + AsStatus(p.diagnose(phase, cr, len(cs))), + ToAge(po.GetCreationTimestamp()), } return nil diff --git a/internal/render/pv.go b/internal/render/pv.go index 560a34548c..d91ea18b6e 100644 --- a/internal/render/pv.go +++ b/internal/render/pv.go @@ -105,8 +105,8 @@ func (p PersistentVolume) Render(o interface{}, ns string, r *Row) error { pv.Status.Reason, p.volumeMode(pv.Spec.VolumeMode), mapToStr(pv.Labels), - asStatus(p.diagnose(phase)), - toAge(pv.GetCreationTimestamp()), + AsStatus(p.diagnose(phase)), + ToAge(pv.GetCreationTimestamp()), } return nil diff --git a/internal/render/pvc.go b/internal/render/pvc.go index 5da78b2d18..bd3cc43b36 100644 --- a/internal/render/pvc.go +++ b/internal/render/pvc.go @@ -74,8 +74,8 @@ func (p PersistentVolumeClaim) Render(o interface{}, ns string, r *Row) error { accessModes, class, mapToStr(pvc.Labels), - asStatus(p.diagnose(string(phase))), - toAge(pvc.GetCreationTimestamp()), + AsStatus(p.diagnose(string(phase))), + ToAge(pvc.GetCreationTimestamp()), } return nil diff --git a/internal/render/ro.go b/internal/render/ro.go index b3dfd9ad36..3e90164627 100644 --- a/internal/render/ro.go +++ b/internal/render/ro.go @@ -53,7 +53,7 @@ func (r Role) Render(o interface{}, ns string, row *Row) error { ro.Name, mapToStr(ro.Labels), "", - toAge(ro.GetCreationTimestamp()), + ToAge(ro.GetCreationTimestamp()), ) return nil diff --git a/internal/render/rob.go b/internal/render/rob.go index adf9d8a090..46783a88f8 100644 --- a/internal/render/rob.go +++ b/internal/render/rob.go @@ -62,7 +62,7 @@ func (r RoleBinding) Render(o interface{}, ns string, row *Row) error { ss, mapToStr(rb.Labels), "", - toAge(rb.GetCreationTimestamp()), + ToAge(rb.GetCreationTimestamp()), ) return nil diff --git a/internal/render/rs.go b/internal/render/rs.go index 5f601e5004..b7f9d8c240 100644 --- a/internal/render/rs.go +++ b/internal/render/rs.go @@ -58,8 +58,8 @@ func (r ReplicaSet) Render(o interface{}, ns string, row *Row) error { strconv.Itoa(int(rs.Status.Replicas)), strconv.Itoa(int(rs.Status.ReadyReplicas)), mapToStr(rs.Labels), - asStatus(r.diagnose(rs)), - toAge(rs.GetCreationTimestamp()), + AsStatus(r.diagnose(rs)), + ToAge(rs.GetCreationTimestamp()), } return nil diff --git a/internal/render/sa.go b/internal/render/sa.go index 03cc821033..43f7c89861 100644 --- a/internal/render/sa.go +++ b/internal/render/sa.go @@ -49,7 +49,7 @@ func (s ServiceAccount) Render(o interface{}, ns string, r *Row) error { strconv.Itoa(len(sa.Secrets)), mapToStr(sa.Labels), "", - toAge(sa.GetCreationTimestamp()), + ToAge(sa.GetCreationTimestamp()), } return nil diff --git a/internal/render/sc.go b/internal/render/sc.go index 47e5ada41c..d5f5ecaaeb 100644 --- a/internal/render/sc.go +++ b/internal/render/sc.go @@ -54,7 +54,7 @@ func (s StorageClass) Render(o interface{}, ns string, r *Row) error { boolPtrToStr(sc.AllowVolumeExpansion), mapToStr(sc.Labels), "", - toAge(sc.GetCreationTimestamp()), + ToAge(sc.GetCreationTimestamp()), } return nil diff --git a/internal/render/sts.go b/internal/render/sts.go index bf99be703d..dee385cf12 100644 --- a/internal/render/sts.go +++ b/internal/render/sts.go @@ -56,8 +56,8 @@ func (s StatefulSet) Render(o interface{}, ns string, r *Row) error { podContainerNames(sts.Spec.Template.Spec, true), podImageNames(sts.Spec.Template.Spec, true), mapToStr(sts.Labels), - asStatus(s.diagnose(sts.Status.Replicas, sts.Status.ReadyReplicas)), - toAge(sts.GetCreationTimestamp()), + AsStatus(s.diagnose(sts.Status.Replicas, sts.Status.ReadyReplicas)), + ToAge(sts.GetCreationTimestamp()), } return nil diff --git a/internal/render/svc.go b/internal/render/svc.go index 7b0e56c59e..2f3cb30cf8 100644 --- a/internal/render/svc.go +++ b/internal/render/svc.go @@ -58,8 +58,8 @@ func (s Service) Render(o interface{}, ns string, r *Row) error { mapToStr(svc.Spec.Selector), ToPorts(svc.Spec.Ports), mapToStr(svc.Labels), - asStatus(s.diagnose()), - toAge(svc.GetCreationTimestamp()), + AsStatus(s.diagnose()), + ToAge(svc.GetCreationTimestamp()), } return nil diff --git a/internal/view/helm.go b/internal/view/helm_chart.go similarity index 50% rename from internal/view/helm.go rename to internal/view/helm_chart.go index 73e6df89a6..e6aba216e1 100644 --- a/internal/view/helm.go +++ b/internal/view/helm_chart.go @@ -14,41 +14,71 @@ import ( "github.com/rs/zerolog/log" ) -// Helm represents a helm chart view. -type Helm struct { +// HelmChart represents a helm chart view. +type HelmChart struct { ResourceViewer Values *model.Values } // NewHelm returns a new alias view. -func NewHelm(gvr client.GVR) ResourceViewer { - c := Helm{ +func NewHelmChart(gvr client.GVR) ResourceViewer { + c := HelmChart{ ResourceViewer: NewBrowser(gvr), } c.GetTable().SetBorderFocusColor(tcell.ColorMediumSpringGreen) - c.GetTable().SetSelectedStyle(tcell.StyleDefault.Foreground(tcell.ColorWhite).Background(tcell.ColorMediumSpringGreen).Attributes(tcell.AttrNone)) + c.GetTable().SetSelectedStyle(tcell.StyleDefault. + Foreground(tcell.ColorWhite). + Background(tcell.ColorMediumSpringGreen).Attributes(tcell.AttrNone)) c.AddBindKeysFn(c.bindKeys) + c.GetTable().SetEnterFn(c.viewReleases) c.SetContextFn(c.chartContext) return &c } -func (c *Helm) chartContext(ctx context.Context) context.Context { +func (c *HelmChart) chartContext(ctx context.Context) context.Context { return ctx } -func (c *Helm) bindKeys(aa ui.KeyActions) { - aa.Delete(ui.KeyShiftA, ui.KeyShiftN, tcell.KeyCtrlS, tcell.KeyCtrlSpace, ui.KeySpace) +func (c *HelmChart) bindKeys(aa ui.KeyActions) { + aa.Delete(tcell.KeyCtrlS) aa.Add(ui.KeyActions{ - ui.KeyShiftN: ui.NewKeyAction("Sort Name", c.GetTable().SortColCmd(nameCol, true), false), + ui.KeyR: ui.NewKeyAction("Releases", c.historyCmd, true), ui.KeyShiftS: ui.NewKeyAction("Sort Status", c.GetTable().SortColCmd(statusCol, true), false), - ui.KeyShiftA: ui.NewKeyAction("Sort Age", c.GetTable().SortColCmd(ageCol, true), false), ui.KeyV: ui.NewKeyAction("Values", c.getValsCmd(), true), }) } -func (c *Helm) getValsCmd() func(evt *tcell.EventKey) *tcell.EventKey { +func (c *HelmChart) viewReleases(app *App, model ui.Tabular, _, path string) { + v := NewHistory(client.NewGVR("helm-history")) + v.SetContextFn(c.helmContext) + if err := app.inject(v, false); err != nil { + app.Flash().Err(err) + } +} + +func (c *HelmChart) historyCmd(evt *tcell.EventKey) *tcell.EventKey { + path := c.GetTable().GetSelectedItem() + if path == "" { + return evt + } + c.viewReleases(c.App(), c.GetTable().GetModel(), c.GVR().String(), path) + + return nil +} + +func (c *HelmChart) helmContext(ctx context.Context) context.Context { + path := c.GetTable().GetSelectedItem() + if path == "" { + return ctx + } + ctx = context.WithValue(ctx, internal.KeyFQN, path) + + return context.WithValue(ctx, internal.KeyPath, path) +} + +func (c *HelmChart) getValsCmd() func(evt *tcell.EventKey) *tcell.EventKey { return func(evt *tcell.EventKey) *tcell.EventKey { path := c.GetTable().GetSelectedItem() if path == "" { @@ -66,7 +96,7 @@ func (c *Helm) getValsCmd() func(evt *tcell.EventKey) *tcell.EventKey { } } -func (c *Helm) toggleValuesCmd(evt *tcell.EventKey) *tcell.EventKey { +func (c *HelmChart) toggleValuesCmd(evt *tcell.EventKey) *tcell.EventKey { c.Values.ToggleValues() if err := c.Values.Refresh(c.defaultCtx()); err != nil { log.Error().Err(err).Msgf("helm refresh failed") @@ -76,6 +106,6 @@ func (c *Helm) toggleValuesCmd(evt *tcell.EventKey) *tcell.EventKey { return nil } -func (c *Helm) defaultCtx() context.Context { +func (c *HelmChart) defaultCtx() context.Context { return context.WithValue(context.Background(), internal.KeyFactory, c.App().factory) } diff --git a/internal/view/helm_history.go b/internal/view/helm_history.go new file mode 100644 index 0000000000..8074ad0b0d --- /dev/null +++ b/internal/view/helm_history.go @@ -0,0 +1,106 @@ +package view + +import ( + "context" + "fmt" + "strings" + + "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/dao" + "github.com/derailed/k9s/internal/render/helm" + "github.com/derailed/k9s/internal/ui" + "github.com/derailed/k9s/internal/ui/dialog" + "github.com/derailed/tcell/v2" +) + +// History represents a helm History view. +type History struct { + ResourceViewer +} + +// NewHelm returns a new alias view. +func NewHistory(gvr client.GVR) ResourceViewer { + h := History{ + ResourceViewer: NewBrowser(gvr), + } + h.GetTable().SetColorerFn(helm.History{}.ColorerFunc()) + h.GetTable().SetBorderFocusColor(tcell.ColorMediumSpringGreen) + h.GetTable().SetSelectedStyle(tcell.StyleDefault.Foreground(tcell.ColorWhite).Background(tcell.ColorMediumSpringGreen).Attributes(tcell.AttrNone)) + h.AddBindKeysFn(h.bindKeys) + h.SetContextFn(h.HistoryContext) + + return &h +} + +// Init initializes the vie +func (h *History) Init(ctx context.Context) error { + if err := h.ResourceViewer.Init(ctx); err != nil { + return err + } + h.GetTable().SetSortCol("REVISION", false) + + return nil +} + +func (h *History) HistoryContext(ctx context.Context) context.Context { + return ctx +} + +func (h *History) bindKeys(aa ui.KeyActions) { + if !h.App().Config.K9s.IsReadOnly() { + h.bindDangerousKeys(aa) + } + + aa.Delete(ui.KeyShiftA, ui.KeyShiftN, tcell.KeyCtrlS, tcell.KeyCtrlSpace, ui.KeySpace, tcell.KeyCtrlD) + aa.Add(ui.KeyActions{ + ui.KeyShiftN: ui.NewKeyAction("Sort Revision", h.GetTable().SortColCmd("REVISION", true), false), + ui.KeyShiftS: ui.NewKeyAction("Sort Status", h.GetTable().SortColCmd("STATUS", true), false), + ui.KeyShiftA: ui.NewKeyAction("Sort Age", h.GetTable().SortColCmd("AGE", true), false), + }) +} + +func (h *History) bindDangerousKeys(aa ui.KeyActions) { + aa.Add(ui.KeyActions{ + ui.KeyR: ui.NewKeyAction("RollBackTo...", h.rollbackCmd, true), + }) +} + +func (h *History) rollbackCmd(evt *tcell.EventKey) *tcell.EventKey { + path := h.GetTable().GetSelectedItem() + if path == "" { + return evt + } + + ns, nrev := client.Namespaced(path) + tt := strings.Split(nrev, ":") + n, rev := nrev, "" + if len(tt) == 2 { + n, rev = tt[0], tt[1] + } + + h.Stop() + defer h.Start() + msg := fmt.Sprintf("RollingBack chart [yellow::b]%s[-::-] to release <[orangered::b]%s[-::-]>?", n, rev) + dialog.ShowConfirmAck(h.App().App, h.App().Content.Pages, n, false, "Confirm Rollback", msg, func() { + ctx, cancel := context.WithTimeout(context.Background(), h.App().Conn().Config().CallTimeout()) + defer cancel() + if err := h.rollback(ctx, client.FQN(ns, n), rev); err != nil { + h.App().Flash().Err(err) + } else { + h.App().Flash().Infof("Rollout restart in progress for char `%s...", n) + } + }, func() {}) + + return nil +} + +func (h *History) rollback(ctx context.Context, path, rev string) error { + var hm dao.HelmHistory + hm.Init(h.App().factory, h.GVR()) + if err := hm.Rollback(ctx, path, rev); err != nil { + return err + } + h.Refresh() + + return nil +} diff --git a/internal/view/registrar.go b/internal/view/registrar.go index c5a226e590..b0495eca1e 100644 --- a/internal/view/registrar.go +++ b/internal/view/registrar.go @@ -23,7 +23,7 @@ func loadCustomViewers() MetaViewers { func helmViewers(vv MetaViewers) { vv[client.NewGVR("helm")] = MetaViewer{ - viewerFn: NewHelm, + viewerFn: NewHelmChart, } } @@ -64,10 +64,6 @@ func miscViewers(vv MetaViewers) { vv[client.NewGVR("contexts")] = MetaViewer{ viewerFn: NewContext, } - // BOZO!! revamp with latest... - // vv[client.NewGVR("openfaas")] = MetaViewer{ - // viewerFn: NewOpenFaas, - // } vv[client.NewGVR("containers")] = MetaViewer{ viewerFn: NewContainer, } From 8c3df98ffd08ee4cdc4db5defbcb03f19d2a10ee Mon Sep 17 00:00:00 2001 From: derailed Date: Sat, 25 Nov 2023 09:57:57 -0700 Subject: [PATCH 18/22] Fix #2039: Command Arrow up/down + enter support --- internal/ui/prompt.go | 11 +++++++++-- internal/view/command.go | 27 ++++++++++++--------------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/internal/ui/prompt.go b/internal/ui/prompt.go index bcc7271035..113f8cd531 100644 --- a/internal/ui/prompt.go +++ b/internal/ui/prompt.go @@ -149,24 +149,31 @@ func (p *Prompt) keyboard(evt *tcell.EventKey) *tcell.EventKey { switch evt.Key() { case tcell.KeyBackspace2, tcell.KeyBackspace, tcell.KeyDelete: p.model.Delete() + case tcell.KeyRune: p.model.Add(evt.Rune()) + case tcell.KeyEscape: p.model.ClearText(true) p.model.SetActive(false) + case tcell.KeyEnter, tcell.KeyCtrlE: p.model.SetText(p.model.GetText(), "") p.model.SetActive(false) + case tcell.KeyCtrlW, tcell.KeyCtrlU: p.model.ClearText(true) + case tcell.KeyUp: if s, ok := m.NextSuggestion(); ok { - p.suggest(p.model.GetText(), s) + p.model.SetText(s, "") } + case tcell.KeyDown: if s, ok := m.PrevSuggestion(); ok { - p.suggest(p.model.GetText(), s) + p.model.SetText(s, "") } + case tcell.KeyTab, tcell.KeyRight, tcell.KeyCtrlF: if s, ok := m.CurrentSuggestion(); ok { p.model.SetText(p.model.GetText()+s, "") diff --git a/internal/view/command.go b/internal/view/command.go index 0fc57bf099..2baae3ac80 100644 --- a/internal/view/command.go +++ b/internal/view/command.go @@ -66,21 +66,17 @@ func (c *Command) Reset(clear bool) error { } func allowedXRay(gvr client.GVR) bool { - gg := []string{ - "v1/pods", - "v1/services", - "apps/v1/deployments", - "apps/v1/daemonsets", - "apps/v1/statefulsets", - "apps/v1/replicasets", - } - for _, g := range gg { - if g == gvr.String() { - return true - } + gg := map[string]struct{}{ + "v1/pods": {}, + "v1/services": {}, + "apps/v1/deployments": {}, + "apps/v1/daemonsets": {}, + "apps/v1/statefulsets": {}, + "apps/v1/replicasets": {}, } - return false + _, ok := gg[gvr.String()] + return ok } func (c *Command) xrayCmd(cmd string) error { @@ -273,10 +269,11 @@ func (c *Command) exec(cmd, gvr string, comp model.Component, clearStack bool) ( return fmt.Errorf("no component found for %s", gvr) } c.app.Flash().Infof("Viewing %s...", client.NewGVR(gvr).R()) + command := cmd if tokens := strings.Split(cmd, " "); len(tokens) >= 2 { - cmd = tokens[0] + command = tokens[0] } - c.app.Config.SetActiveView(cmd) + c.app.Config.SetActiveView(command) if err := c.app.Config.Save(); err != nil { log.Error().Err(err).Msg("Config save failed!") } From 5931ad025b99008fd65df20ce0ebd2f628b198e8 Mon Sep 17 00:00:00 2001 From: derailed Date: Wed, 29 Nov 2023 09:09:37 -0700 Subject: [PATCH 19/22] Small refactor --- internal/dao/pod.go | 13 ++++++++++--- internal/view/live_view.go | 4 ++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/internal/dao/pod.go b/internal/dao/pod.go index 9c5f669a0f..3e30ebd52e 100644 --- a/internal/dao/pod.go +++ b/internal/dao/pod.go @@ -523,12 +523,19 @@ func (p *Pod) Sanitize(ctx context.Context, ns string) (int, error) { } log.Debug().Msgf("Pod status: %q", render.PodStatus(&pod)) switch render.PodStatus(&pod) { - case render.PhaseCompleted, render.PhaseCrashLoop, render.PhaseError, render.PhaseImagePullBackOff, render.PhaseOOMKilled: + case render.PhaseCompleted: + fallthrough + case render.PhaseCrashLoop: + fallthrough + case render.PhaseError: + fallthrough + case render.PhaseImagePullBackOff: + fallthrough + case render.PhaseOOMKilled: log.Debug().Msgf("Sanitizing %s:%s", pod.Namespace, pod.Name) fqn := client.FQN(pod.Namespace, pod.Name) if err := p.Resource.Delete(ctx, fqn, nil, NowGrace); err != nil { - log.Warn().Err(err).Msgf("Pod %s deletion failed", fqn) - continue + return count, err } count++ } diff --git a/internal/view/live_view.go b/internal/view/live_view.go index a539c2c324..46f5a82734 100644 --- a/internal/view/live_view.go +++ b/internal/view/live_view.go @@ -106,7 +106,11 @@ func (*LiveView) linesWithRegions(lines []string, matches fuzzy.Matches) []strin offsetForLine := make(map[int]int) for i, m := range matches { loc, line := m.MatchedIndexes, ll[m.Index] + if len(loc) < 2 { + continue + } offset := offsetForLine[m.Index] + loc[0], loc[1] = loc[0]+offset, loc[1]+offset regionStr := `<<<"search_` + strconv.Itoa(i) + `">>>` + line[loc[0]:loc[1]] + `<<<"">>>` ll[m.Index] = line[:loc[0]] + regionStr + line[loc[1]:] From e334c77a3fd153a876c3928d5b4fab0269eff652 Mon Sep 17 00:00:00 2001 From: derailed Date: Sat, 2 Dec 2023 09:26:32 -0700 Subject: [PATCH 20/22] Add img vulenerability scans support --- go.mod | 208 ++- go.sum | 1392 ++++++++++++++++- internal/client/metrics.go | 2 +- internal/config/config_test.go | 2 + internal/config/k9s.go | 1 + internal/dao/cronjob.go | 32 +- internal/dao/dp.go | 22 +- internal/dao/ds.go | 12 + internal/dao/img_scan.go | 67 + internal/dao/job.go | 33 +- internal/dao/pod.go | 11 + internal/dao/registry.go | 9 + internal/dao/rs.go | 19 +- internal/dao/sts.go | 12 + internal/dao/types.go | 6 + internal/keys.go | 55 +- internal/model/registry.go | 5 +- internal/render/cronjob.go | 14 +- internal/render/dp.go | 13 +- internal/render/ds.go | 13 +- internal/render/helpers.go | 12 + internal/render/img_scan.go | 107 ++ internal/render/job.go | 13 +- internal/render/pod.go | 25 +- internal/render/row.go | 28 +- internal/render/row_event.go | 47 - internal/render/rs.go | 13 +- internal/render/sts.go | 13 +- internal/view/app.go | 22 + internal/view/benchmark.go | 2 +- internal/view/cronjob.go | 2 +- internal/view/details.go | 35 +- internal/view/dir.go | 6 +- internal/view/dp.go | 24 +- internal/view/ds.go | 8 +- internal/view/img_scan.go | 85 + internal/view/job.go | 2 +- internal/view/live_view_test.go | 2 +- internal/view/node.go | 4 +- internal/view/pod.go | 6 +- internal/view/registrar.go | 3 + internal/view/rs.go | 2 +- internal/view/secret.go | 2 +- internal/view/sts.go | 10 +- internal/view/vul_extender.go | 50 + internal/view/xray.go | 4 +- internal/vul/scan.go | 81 + internal/vul/scanner.go | 220 +++ internal/vul/scorer.go | 45 + internal/vul/scorer_test.go | 96 ++ internal/vul/table.go | 184 +++ internal/vul/table_test.go | 86 + internal/vul/tally.go | 74 + internal/vul/tally_test.go | 57 + internal/vul/testdata/sort/dups/sc1.text | 9 + internal/vul/testdata/sort/dups/sc2.text | 6 + internal/vul/testdata/sort/full/sc1.text | 56 + internal/vul/testdata/sort/full/sc2.text | 29 + internal/vul/testdata/sort/no_dups/sc1.text | 2 + internal/vul/testdata/sort/no_dups/sc2.text | 2 + internal/vul/testdata/sort_sev/dups/sc1.text | 9 + internal/vul/testdata/sort_sev/dups/sc2.text | 6 + internal/vul/testdata/sort_sev/full/sc1.text | 56 + internal/vul/testdata/sort_sev/full/sc2.text | 29 + .../vul/testdata/sort_sev/no_dups/sc1.text | 2 + .../vul/testdata/sort_sev/no_dups/sc2.text | 2 + internal/vul/types.go | 24 + 67 files changed, 3288 insertions(+), 242 deletions(-) create mode 100644 internal/dao/img_scan.go create mode 100644 internal/render/img_scan.go create mode 100644 internal/view/img_scan.go create mode 100644 internal/view/vul_extender.go create mode 100644 internal/vul/scan.go create mode 100644 internal/vul/scanner.go create mode 100644 internal/vul/scorer.go create mode 100644 internal/vul/scorer_test.go create mode 100644 internal/vul/table.go create mode 100644 internal/vul/table_test.go create mode 100644 internal/vul/tally.go create mode 100644 internal/vul/tally_test.go create mode 100644 internal/vul/testdata/sort/dups/sc1.text create mode 100644 internal/vul/testdata/sort/dups/sc2.text create mode 100644 internal/vul/testdata/sort/full/sc1.text create mode 100644 internal/vul/testdata/sort/full/sc2.text create mode 100644 internal/vul/testdata/sort/no_dups/sc1.text create mode 100644 internal/vul/testdata/sort/no_dups/sc2.text create mode 100644 internal/vul/testdata/sort_sev/dups/sc1.text create mode 100644 internal/vul/testdata/sort_sev/dups/sc2.text create mode 100644 internal/vul/testdata/sort_sev/full/sc1.text create mode 100644 internal/vul/testdata/sort_sev/full/sc2.text create mode 100644 internal/vul/testdata/sort_sev/no_dups/sc1.text create mode 100644 internal/vul/testdata/sort_sev/no_dups/sc2.text create mode 100644 internal/vul/types.go diff --git a/go.mod b/go.mod index 02e8554801..89eb331940 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,13 @@ module github.com/derailed/k9s -go 1.21 +go 1.21.1 + +toolchain go1.21.4 require ( github.com/adrg/xdg v0.4.0 + github.com/anchore/clio v0.0.0-20231016125544-c98a83e1c7fc + github.com/anchore/grype v0.73.4 github.com/atotto/clipboard v0.1.4 github.com/cenkalti/backoff/v4 v4.2.1 github.com/derailed/popeye v0.11.1 @@ -13,7 +17,8 @@ require ( github.com/fsnotify/fsnotify v1.7.0 github.com/fvbommel/sortorder v1.1.0 github.com/mattn/go-colorable v0.1.13 - github.com/mattn/go-runewidth v0.0.14 + github.com/mattn/go-runewidth v0.0.15 + github.com/olekukonko/tablewriter v0.0.5 github.com/petergtz/pegomock v2.9.0+incompatible github.com/rakyll/hey v0.1.4 github.com/rs/zerolog v1.31.0 @@ -35,126 +40,281 @@ require ( ) require ( + cloud.google.com/go v0.110.10 // indirect + cloud.google.com/go/compute v1.23.3 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/iam v1.1.5 // indirect + cloud.google.com/go/storage v1.35.1 // indirect + dario.cat/mergo v1.0.0 // indirect github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect + github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/BurntSushi/toml v1.3.2 // indirect + github.com/CycloneDX/cyclonedx-go v0.7.2 // indirect + github.com/DataDog/zstd v1.4.5 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/semver/v3 v3.2.1 // indirect github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/Masterminds/squirrel v1.5.4 // indirect - github.com/Microsoft/hcsshim v0.11.0 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Microsoft/hcsshim v0.11.1 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect + github.com/acobaugh/osrelease v0.1.0 // indirect + github.com/anchore/fangs v0.0.0-20231106214039-d96c8f312db4 // indirect + github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a // indirect + github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb // indirect + github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect + github.com/anchore/go-version v1.2.2-0.20210903204242-51efa5b487c4 // indirect + github.com/anchore/packageurl-go v0.1.1-0.20230104203445-02e0a6721501 // indirect + github.com/anchore/stereoscope v0.0.0-20231117203853-3610f4ef3e83 // indirect + github.com/anchore/syft v0.98.0 // indirect + github.com/andybalholm/brotli v1.0.4 // indirect + github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect + github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 // indirect + github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492 // indirect github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect - github.com/aws/aws-sdk-go v1.38.49 // indirect + github.com/aws/aws-sdk-go v1.44.288 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/becheran/wildmatch-go v1.0.0 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect + github.com/bmatcuk/doublestar/v2 v2.0.4 // indirect + github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect - github.com/containerd/containerd v1.7.6 // indirect + github.com/charmbracelet/lipgloss v0.9.1 // indirect + github.com/cloudflare/circl v1.3.3 // indirect + github.com/containerd/cgroups v1.1.0 // indirect + github.com/containerd/containerd v1.7.8 // indirect + github.com/containerd/continuity v0.4.2 // indirect + github.com/containerd/fifo v1.1.0 // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect + github.com/containerd/ttrpc v1.2.2 // indirect + github.com/containerd/typeurl/v2 v2.1.1 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da // indirect + github.com/distribution/reference v0.5.0 // indirect github.com/docker/cli v24.0.6+incompatible // indirect - github.com/docker/distribution v2.8.2+incompatible // indirect + github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker v24.0.7+incompatible // indirect github.com/docker/docker-credential-helpers v0.7.0 // indirect github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/go-units v0.5.0 // indirect + github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/edsrzf/mmap-go v1.1.0 // indirect github.com/emicklei/go-restful/v3 v3.10.1 // indirect + github.com/emirpasic/gods v1.18.1 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect + github.com/facebookincubator/nvdtools v0.1.5 // indirect github.com/fatih/camelcase v1.0.0 // indirect + github.com/felixge/fgprof v0.9.3 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gdamore/encoding v1.0.0 // indirect + github.com/github/go-spdx/v2 v2.2.0 // indirect + github.com/glebarez/go-sqlite v1.21.2 // indirect + github.com/glebarez/sqlite v1.10.0 // indirect github.com/go-errors/errors v1.4.2 // indirect + github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect + github.com/go-git/go-billy/v5 v5.5.0 // indirect + github.com/go-git/go-git/v5 v5.10.1 // indirect github.com/go-gorp/gorp/v3 v3.1.0 // indirect github.com/go-logr/logr v1.3.0 // 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.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-restruct/restruct v1.2.0-alpha // indirect + github.com/go-test/deep v1.1.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.0.1 // indirect github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/go-containerregistry v0.16.1 // indirect github.com/google/gofuzz v1.2.0 // indirect + github.com/google/licensecheck v0.3.1 // indirect + github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 // indirect + github.com/google/s2a-go v0.1.7 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.4.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.0 // indirect + github.com/gookit/color v1.5.4 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/gosuri/uitable v0.0.4 // indirect github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect + github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b // indirect github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-getter v1.7.3 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-safetemp v1.0.0 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect github.com/huandu/xstrings v1.4.0 // indirect - github.com/imdario/mergo v0.3.13 // indirect + github.com/iancoleman/strcase v0.3.0 // indirect + github.com/imdario/mergo v0.3.15 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect + github.com/jinzhu/copier v0.4.0 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmoiron/sqlx v1.3.5 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.16.0 // indirect + github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953 // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect + github.com/klauspost/compress v1.17.0 // indirect + github.com/klauspost/pgzip v1.2.5 // indirect + github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f // indirect + github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d // indirect + github.com/knqyf263/go-rpmdb v0.0.0-20230301153543-ba94b245509b // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect + github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect + github.com/mholt/archiver/v3 v3.5.1 // indirect + github.com/microsoft/go-rustaudit v0.0.0-20220730194248-4b17361d90a5 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect + github.com/mitchellh/mapstructure v1.5.0 // 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 + github.com/moby/sys/mountinfo v0.6.2 // indirect + github.com/moby/sys/sequential v0.5.0 // indirect + github.com/moby/sys/signal v0.7.0 // indirect github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/morikuni/aec v1.0.0 // indirect + github.com/muesli/reflow v0.3.0 // indirect + github.com/muesli/termenv v0.15.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/onsi/ginkgo v1.16.5 // indirect - github.com/onsi/gomega v1.27.6 // indirect + github.com/nwaples/rardecode v1.1.0 // indirect + github.com/nxadm/tail v1.4.8 // indirect + github.com/onsi/gomega v1.27.10 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc5 // indirect + github.com/opencontainers/runc v1.1.5 // indirect + github.com/opencontainers/runtime-spec v1.1.0-rc.1 // indirect + github.com/opencontainers/selinux v1.11.0 // indirect + github.com/openvex/go-vex v0.2.5 // indirect + github.com/owenrumney/go-sarif v1.1.2-0.20231003122901-1000f5e05554 // indirect + github.com/package-url/packageurl-go v0.1.1 // indirect + github.com/pborman/indent v1.2.1 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect + github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect + github.com/pierrec/lz4/v4 v4.1.15 // indirect + github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pkg/profile v1.7.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // 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/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.4.3 // indirect github.com/rubenv/sql-migrate v1.5.2 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/saferwall/pe v1.4.7 // indirect + github.com/sagikazarmark/locafero v0.3.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect + github.com/sassoftware/go-rpmutils v0.2.0 // indirect + github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e // indirect + github.com/sergi/go-diff v1.3.1 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/spf13/cast v1.5.0 // indirect + github.com/skeema/knownhosts v1.2.1 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spdx/tools-golang v0.5.3 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.5.1 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.17.0 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/sylabs/sif/v2 v2.11.5 // indirect + github.com/sylabs/squashfs v0.6.1 // indirect + github.com/therootcompany/xz v1.0.1 // indirect + github.com/ulikunitz/xz v0.5.10 // indirect + github.com/vbatts/go-mtree v0.5.3 // indirect + github.com/vbatts/tar-split v0.11.3 // indirect + github.com/vifraa/gopom v1.0.0 // indirect + github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651 // indirect + github.com/wagoodman/go-presenter v0.0.0-20211015174752-f9c01afc824b // indirect + github.com/wagoodman/go-progress v0.0.0-20230925121702-07e42b3cdba0 // indirect + github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect + github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xlab/treeprint v1.2.0 // indirect + github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect + github.com/zclconf/go-cty v1.14.0 // indirect + go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect + go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/otel v1.14.0 // indirect go.opentelemetry.io/otel/trace v1.14.0 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect - golang.org/x/crypto v0.14.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.14.0 // indirect - golang.org/x/term v0.13.0 // indirect - golang.org/x/time v0.3.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/crypto v0.16.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/oauth2 v0.15.0 // indirect + golang.org/x/sync v0.5.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/term v0.15.0 // indirect + golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.13.0 // indirect + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect + google.golang.org/api v0.152.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect - google.golang.org/grpc v1.56.3 // indirect + google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect + google.golang.org/grpc v1.59.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/gorm v1.25.5 // indirect k8s.io/apiserver v0.28.3 // indirect k8s.io/component-base v0.28.4 // indirect k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect + modernc.org/libc v1.29.0 // indirect + modernc.org/mathutil v1.6.0 // indirect + modernc.org/memory v1.7.2 // indirect + modernc.org/sqlite v1.27.0 // indirect oras.land/oras-go v1.2.4 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect diff --git a/go.sum b/go.sum index 9d21d6ee8b..1156338289 100644 --- a/go.sum +++ b/go.sum @@ -1,17 +1,219 @@ 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 v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y= +cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= +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/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= +cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= +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/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= +cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI= +cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= +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/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= +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= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= +cloud.google.com/go/storage v1.35.1 h1:B59ahL//eDfx2IIKFBeT5Atm9wnNmj3+8xG/W4WB//w= +cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +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-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= +github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 h1:59MxjQVfjXsBpLy+dbd2/ELV5ofnUkUZBvWSC85sheA= +github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0/go.mod h1:OahwfttHWG6eJ0clwcfBAHoDI6X/LV/15hx/wlMZSrU= 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 v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/CycloneDX/cyclonedx-go v0.7.2 h1:kKQ0t1dPOlugSIYVOMiMtFqeXI2wp/f5DBIdfux8gnQ= +github.com/CycloneDX/cyclonedx-go v0.7.2/go.mod h1:K2bA+324+Og0X84fA8HhN2X066K7Bxz4rpMQ4ZhjtSk= 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/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= @@ -19,28 +221,90 @@ github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/Microsoft/hcsshim v0.11.0 h1:7EFNIY4igHEXUdj1zXgAyU3fLc7QfOKHbkldRVTBdiM= -github.com/Microsoft/hcsshim v0.11.0/go.mod h1:OEthFdQv/AD2RAdzR6Mm1N1KPCztGKDurW1Z8b8VGMM= +github.com/Microsoft/hcsshim v0.11.1 h1:hJ3s7GbWlGK4YVV92sO88BQSyF4ZLVy7/awqOlPxFbA= +github.com/Microsoft/hcsshim v0.11.1/go.mod h1:nFJmaO4Zr5Y7eADdFOpYswDDlNVbvcIJJNJLECr5JQg= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= 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/acobaugh/osrelease v0.1.0 h1:Yb59HQDGGNhCj4suHaFQQfBps5wyoKLSSX/J/+UifRE= +github.com/acobaugh/osrelease v0.1.0/go.mod h1:4bFEs0MtgHNHBrmHCt67gNisnabCRAlzdVasCEGHTWY= github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls= github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E= 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/anchore/clio v0.0.0-20231016125544-c98a83e1c7fc h1:A1KFO+zZZmbNlz1+WKsCF0RKVx6XRoxsAG3lrqH9hUQ= +github.com/anchore/clio v0.0.0-20231016125544-c98a83e1c7fc/go.mod h1:QeWvNzxsrUNxcs6haQo3OtISfXUXW0qAuiG4EQiz0GU= +github.com/anchore/fangs v0.0.0-20231106214039-d96c8f312db4 h1:3jHs159SUguPb0YMH/mKN2+eKKme76r+6iwAZ1xlu7c= +github.com/anchore/fangs v0.0.0-20231106214039-d96c8f312db4/go.mod h1:yPsN3NUGhU5dcBtYBa1dMNzGu1yT5ZAfSjKq9DY4aV8= +github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a h1:nJ2G8zWKASyVClGVgG7sfM5mwoZlZ2zYpIzN2OhjWkw= +github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a/go.mod h1:ubLFmlsv8/DFUQrZwY5syT5/8Er3ugSr4rDFwHsE3hg= +github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb h1:iDMnx6LIjtjZ46C0akqveX83WFzhpTD3eqOthawb5vU= +github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb/go.mod h1:DmTY2Mfcv38hsHbG78xMiTDdxFtkHpgYNVDPsF2TgHk= +github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 h1:aM1rlcoLz8y5B2r4tTLMiVTrMtpfY0O8EScKJxaSaEc= +github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092/go.mod h1:rYqSE9HbjzpHTI74vwPvae4ZVYZd1lue2ta6xHPdblA= +github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04 h1:VzprUTpc0vW0nnNKJfJieyH/TZ9UYAnTZs5/gHTdAe8= +github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04/go.mod h1:6dK64g27Qi1qGQZ67gFmBFvEHScy0/C8qhQhNe5B5pQ= +github.com/anchore/go-version v1.2.2-0.20210903204242-51efa5b487c4 h1:rmZG77uXgE+o2gozGEBoUMpX27lsku+xrMwlmBZJtbg= +github.com/anchore/go-version v1.2.2-0.20210903204242-51efa5b487c4/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E= +github.com/anchore/grype v0.73.4 h1:j8HzRHbXLLZ6U2lmDDRFILd+VZtWbsfg/RYhatRZW9E= +github.com/anchore/grype v0.73.4/go.mod h1:5kJSAsHPoK47DsGZLHHArCfhHVGFGRkCfL2H87GdrdY= +github.com/anchore/packageurl-go v0.1.1-0.20230104203445-02e0a6721501 h1:AV7qjwMcM4r8wFhJq3jLRztew3ywIyPTRapl2T1s9o8= +github.com/anchore/packageurl-go v0.1.1-0.20230104203445-02e0a6721501/go.mod h1:Blo6OgJNiYF41ufcgHKkbCKF2MDOMlrqhXv/ij6ocR4= +github.com/anchore/stereoscope v0.0.0-20231117203853-3610f4ef3e83 h1:mxGIOmj+asEm8LUkPTG3/v0hi27WIlDVjiEVsUB9eqY= +github.com/anchore/stereoscope v0.0.0-20231117203853-3610f4ef3e83/go.mod h1:GKAnytSVV1hoqB5r5Gd9M5Ph3Rzqq0zPdEJesewjC2w= +github.com/anchore/syft v0.98.0 h1:mPDah48zZCFeSiGweqPd2C2++rOUh3/cAZylEy1VPwU= +github.com/anchore/syft v0.98.0/go.mod h1:FMj8zZFF3mP4IAuTxb6n14CZ6ouWXpI9RZqXpnkLK+Y= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= +github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= +github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 h1:vmXNl+HDfqqXgr0uY1UgK1GAhps8nbAAtqHNBcgyf+4= +github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46/go.mod h1:olhPNdiiAAMiSujemd1O/sc6GcyePr23f/6uGKtthNg= +github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492 h1:rcEG5HI490FF0a7zuvxOxen52ddygCfNVjP0XOCMl+M= +github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492/go.mod h1:9Beu8XsUNNfzml7WBf3QmyPToP1wm1Gj/Vc5UJKqTzU= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= 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= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= -github.com/aws/aws-sdk-go v1.38.49 h1:E31vxjCe6a5I+mJLmUGaZobiWmg9KdWaud9IfceYeYQ= -github.com/aws/aws-sdk-go v1.38.49/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go v1.44.288 h1:Ln7fIao/nl0ACtelgR1I4AiEw/GLNkKcXfCaHupUW5Q= +github.com/aws/aws-sdk-go v1.44.288/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/becheran/wildmatch-go v1.0.0 h1:mE3dGGkTmpKtT4Z+88t8RStG40yN9T+kFEGj2PZFSzA= +github.com/becheran/wildmatch-go v1.0.0/go.mod h1:gbMvj0NtVdJ15Mg/mH9uxk2R1QCistMyU7d9KFzroX4= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bmatcuk/doublestar/v2 v2.0.4 h1:6I6oUiT/sU27eE2OFcWqBhL1SwjyvQuOssxT4a1yidI= +github.com/bmatcuk/doublestar/v2 v2.0.4/go.mod h1:QMmcs3H2AUQICWhfzLXz+IYln8lRQmTZRptLie8RgRw= +github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I= +github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= +github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M= +github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70= github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng= @@ -49,45 +313,92 @@ github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembj github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= 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/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +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= github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= +github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg= +github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= +github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 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/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= -github.com/containerd/containerd v1.7.6 h1:oNAVsnhPoy4BTPQivLgTzI9Oleml9l/+eYIDYXRCYo8= -github.com/containerd/containerd v1.7.6/go.mod h1:SY6lrkkuJT40BVNO37tlYTSnKJnP5AXBc0fhx0q+TJ4= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/containerd v1.7.8 h1:RkwgOW3AVUT3H/dyT0W03Dc8AzlpMG65lX48KftOFSM= +github.com/containerd/containerd v1.7.8/go.mod h1:L/Hn9qylJtUFT7cPeM0Sr3fATj+WjHwRQ0lyrYk3OPY= github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY= +github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= +github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= +github.com/containerd/ttrpc v1.2.2 h1:9vqZr0pxwOF5koz6N0N3kJ0zDHokrcPxIR/ZR2YFtOs= +github.com/containerd/ttrpc v1.2.2/go.mod h1:sIT6l32Ph/H9cvnJsfXM5drIVzTr5A2flTf1G5tYZak= +github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4= +github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.3/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/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da h1:ZOjWpVsFZ06eIhnh4mkaceTiVoktdU67+M7KDHJ268M= +github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da/go.mod h1:B3tI9iGHi4imdLi4Asdha1Sc6feLMTfPLXh9IUYmysk= github.com/derailed/popeye v0.11.1 h1:bjt5mXkcXY696ipuJqwY1sa5s3i431L9BlkQc6EuaqE= github.com/derailed/popeye v0.11.1/go.mod h1:NkvjHH1F94tE7Ui17PlYiagQcFt7yXUV2hIhPzSK+0w= github.com/derailed/tcell/v2 v2.3.1-rc.3 h1:9s1fmyRcSPRlwr/C9tcpJKCujbrtmPpST6dcMUD2piY= github.com/derailed/tcell/v2 v2.3.1-rc.3/go.mod h1:nf68BEL8fjmXQHJT3xZjoZFs2uXOzyJcNAQqGUEMrFY= github.com/derailed/tview v0.8.2 h1:8b+QwVECV1lZ6VV7Vf1tergpJxJ+ReA/JhIBYyUVSFI= github.com/derailed/tview v0.8.2/go.mod h1:q+odnnhO6QDPpBT+0dqaWj+X+uoJ6MJehXj9shgP+Cw= +github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4= 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/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= +github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/cli v24.0.6+incompatible h1:fF+XCQCgJjjQNIMjzaSmiKJSCcfcXb3TWTcc7GAneOY= github.com/docker/cli v24.0.6+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/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= +github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= @@ -98,41 +409,103 @@ github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= 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/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY= +github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= +github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= +github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= 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/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +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/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= 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= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= +github.com/facebookincubator/flog v0.0.0-20190930132826-d2511d0ce33c/go.mod h1:QGzNH9ujQ2ZUr/CjDGZGWeDAVStrWNjHeEcjJL96Nuk= +github.com/facebookincubator/nvdtools v0.1.5 h1:jbmDT1nd6+k+rlvKhnkgMokrCAzHoASWE5LtHbX2qFQ= +github.com/facebookincubator/nvdtools v0.1.5/go.mod h1:Kh55SAWnjckS96TBSrXI99KrEKH4iB0OJby3N8GRJO4= github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/fatih/set v0.2.1 h1:nn2CaJyknWE/6txyUDGwysr3G5QC6xWB/PtVjPBbeaA= +github.com/fatih/set v0.2.1/go.mod h1:+RKtMCH+favT2+3YecHGxcc0b4KyVWA1QWWJUs4E0CI= +github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= +github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= 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/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= 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/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/github/go-spdx/v2 v2.2.0 h1:yBBLMasHA70Ujd35OpL/OjJOWWVNXcJGbars0GinGRI= +github.com/github/go-spdx/v2 v2.2.0/go.mod h1:hMCrsFgT0QnCwn7G8gxy/MxMpy67WgZrwFeISTn0o6w= +github.com/gkampitakis/ciinfo v0.3.0 h1:gWZlOC2+RYYttL0hBqcoQhM7h1qNkVqvRCV1fOvpAv8= +github.com/gkampitakis/ciinfo v0.3.0/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo= +github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M= +github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk= +github.com/gkampitakis/go-snaps v0.4.12 h1:YeMgKOm0XW3f/Pt2rYpUlpyF8nG6lYGe9oXFJw5LdME= +github.com/gkampitakis/go-snaps v0.4.12/go.mod h1:PpnF1KPXQAHBdb/DHoi/1VmlwE+ZkVHzl+QHmgzMSz8= +github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo= +github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k= +github.com/glebarez/sqlite v1.10.0 h1:u4gt8y7OND/cCei/NMHmfbLxF6xP2wgKcT/BJf2pYkc= +github.com/glebarez/sqlite v1.10.0/go.mod h1:IJ+lfSOmiekhQsFTJRx/lHtGYmCdtAiTaf5wI9u5uHA= +github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= +github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= 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-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= +github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= +github.com/go-git/go-git/v5 v5.10.1 h1:tu8/D8i+TWxgKpzQ3Vc43e+kkhXqtsZCKI/egajKnxk= +github.com/go-git/go-git/v5 v5.10.1/go.mod h1:uEuHjxkHap8kAl//V5F/nNWwqIYtP/402ddd05mp0wg= +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-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-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -146,12 +519,15 @@ github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2Kv 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-restruct/restruct v1.2.0-alpha h1:2Lp474S/9660+SJjpVxoKuWX09JsXHSrdV7Nv3/gkvc= +github.com/go-restruct/restruct v1.2.0-alpha/go.mod h1:KqrpKpn4M8OLznErihXTGLlsXFGeLxHUrLRRI/1YjGk= 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/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU= github.com/gobuffalo/logger v1.0.6/go.mod h1:J31TBEHR1QLV2683OXTAItYIg8pv2JMHnF/quuAbMjs= github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0= @@ -161,16 +537,31 @@ github.com/gobuffalo/packr/v2 v2.8.3/go.mod h1:0SahksCVcx4IMnigTjiFuyldmTrdTctXs github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 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/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 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/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= 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= @@ -178,11 +569,20 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W 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.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +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/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 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-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= @@ -191,21 +591,80 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a 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.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/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.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-containerregistry v0.16.1 h1:rUEt426sR6nyrL3gt+18ibRcvYpKYdpsa5ZW7MA08dQ= +github.com/google/go-containerregistry v0.16.1/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= 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/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= +github.com/google/licensecheck v0.3.1 h1:QoxgoDkaeC4nFrtGN1jV7IPmDCHFNIVh54e5hSt6sPs= +github.com/google/licensecheck v0.3.1/go.mod h1:ORkR35t/JjW+emNKtfJDII0zlciG9JgbT7SmsohlHmY= +github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= +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/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +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-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= 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.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +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/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= +github.com/gookit/color v1.2.5/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg= +github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= +github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= 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= @@ -215,22 +674,75 @@ github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b h1:wDUNC2eKiL35DbLvsDhiblTUXHxcOPwQSCzi7xpQUN4= +github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b/go.mod h1:VzxiSdG6j1pi7rwGm/xYI5RbtpBgM8sARDXlvEvxlu0= +github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= +github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-getter v1.7.3 h1:bN2+Fw9XPFvOCjB0UOevFIMICZ7G2XSQHzfvLUyOM5E= +github.com/hashicorp/go-getter v1.7.3/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= 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/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= +github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +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/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= +github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= 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/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= +github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= 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= +github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= +github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= +github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -241,17 +753,41 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= 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.9/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/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= +github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953 h1:WdAeg/imY2JFPc/9CST4bZ80nNJbiBFCAdSZCSgrS5Y= +github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953/go.mod h1:6o+UrvuZWc4UTyBhQf0LGjW9Ld7qJxLz/OqvSOWWlEc= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= 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/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= +github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= +github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f h1:GvCU5GXhHq+7LeOzx/haG7HSIZokl3/0GkoUFzsRJjg= +github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f/go.mod h1:q59u9px8b7UTj0nIjEjvmTWekazka6xIt6Uogz5Dm+8= +github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d h1:X4cedH4Kn3JPupAwwWuo4AzYp16P0OyLO9d7OnMZc/c= +github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d/go.mod h1:o8sgWoz3JADecfc/cTYD92/Et1yMqMy0utV1z+VaZao= +github.com/knqyf263/go-rpmdb v0.0.0-20230301153543-ba94b245509b h1:boYyvL3tbUuKcMN029mpCl7oYYJ7yIXujLj+fiW4Alc= +github.com/knqyf263/go-rpmdb v0.0.0-20230301153543-ba94b245509b/go.mod h1:9LQcoMCMQ9vrF7HcDtXfvqGO4+ddxFQ8+YF/0CVGDww= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 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/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -270,10 +806,14 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 h1:bqDmpDG49ZRnB5PcgP0RXtQvnMSgIF14M7CBd2shtXs= +github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= +github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI= @@ -282,27 +822,67 @@ github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI= github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +github.com/maruel/natural v1.1.0 h1:2z1NgP/Vae+gYrtC0VuvrTJ6U35OuyUqDdfluLqMWuQ= +github.com/maruel/natural v1.1.0/go.mod h1:eFVhYCcUOfZFxXoDZam8Ktya72wa79fNC3lc/leA0DQ= +github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08 h1:AevUBW4cc99rAF8q8vmddIP8qd/0J5s/UyltGbp66dg= +github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08/go.mod h1:JOkBRrE1HvgTyjk6diFtNGgr8XJMtIfiBzkL5krqzVk= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= -github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= -github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/miekg/dns v1.1.25 h1:dFwPR6SfLtrSwgDcIq2bcU/gVutB4sNApq2HBdqcakg= -github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= +github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo= +github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= +github.com/microsoft/go-rustaudit v0.0.0-20220730194248-4b17361d90a5 h1:tQRHcLQwnwrPq2j2Qra/NnyjyESBGwdeBeVdAE9kXYg= +github.com/microsoft/go-rustaudit v0.0.0-20220730194248-4b17361d90a5/go.mod h1:vYT9HE7WCvL64iVeZylKmCsWKfE+JZ8105iuh2Trk8g= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= 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-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= 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/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= @@ -310,8 +890,13 @@ github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= 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.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= +github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= +github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/sys/signal v0.7.0 h1:25RW3d5TnQEoKvRbEKUGay6DCQ46IxAVTT9CUMgmsSI= +github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= 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= @@ -325,89 +910,184 @@ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= +github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= +github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= +github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= 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/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ= +github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.9.4 h1:xR7vG4IXt5RWx6FfIjyAtsoMAtnc3C/rFXBBd2AjZwE= -github.com/onsi/ginkgo/v2 v2.9.4/go.mod h1:gCQYp2Q+kSoIj7ykSVb9nskRSsR6PUj4AiLywzIhbKM= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= +github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= +github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= 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-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= +github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/GDEs= +github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.1.0-rc.1 h1:wHa9jroFfKGQqFHj0I1fMRKLl0pfj+ynAqBxo3v6u9w= +github.com/opencontainers/runtime-spec v1.1.0-rc.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU= +github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec= +github.com/openvex/go-vex v0.2.5 h1:41utdp2rHgAGCsG+UbjmfMG5CWQxs15nGqir1eRgSrQ= +github.com/openvex/go-vex v0.2.5/go.mod h1:j+oadBxSUELkrKh4NfNb+BPo77U3q7gdKME88IO/0Wo= +github.com/owenrumney/go-sarif v1.1.2-0.20231003122901-1000f5e05554 h1:FvA4bwjKpPqik5WsQ8+4z4DKWgA1tO1RTTtNKr5oYNA= +github.com/owenrumney/go-sarif v1.1.2-0.20231003122901-1000f5e05554/go.mod h1:n73K/hcuJ50MiVznXyN4rde6fZY7naGKWBXOLFTyc94= +github.com/package-url/packageurl-go v0.1.1 h1:KTRE0bK3sKbFKAk3yy63DpeskU7Cvs/x/Da5l+RtzyU= +github.com/package-url/packageurl-go v0.1.1/go.mod h1:uQd4a7Rh3ZsVg5j0lNyAfyxIeGde9yrlhjF78GzeW0c= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/indent v1.2.1 h1:lFiviAbISHv3Rf0jcuh489bi06hj98JsVMtIDZQb9yM= +github.com/pborman/indent v1.2.1/go.mod h1:FitS+t35kIYtB5xWTZAPhnmrxcciEEOdbyrrpz5K6Vw= +github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= +github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= 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/petergtz/pegomock v2.9.0+incompatible h1:BKfb5XfkJfehe5T+O1xD4Zm26Sb9dnRj7tHxLYwUPiI= github.com/petergtz/pegomock v2.9.0+incompatible/go.mod h1:nuBLWZpVyv/fLo56qTwt/AUau7jgouO1h7bEvZCq82o= 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/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0= +github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= +github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= 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= +github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA= +github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= 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.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= 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.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.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= 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.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= 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/rakyll/hey v0.1.4 h1:hhc8GIqHN4+rPFZvkM9lkCQGi7da0sINM83xxpFkbPA= github.com/rakyll/hey v0.1.4/go.mod h1:nAOTOo+L52KB9SZq/M6J18kxjto4yVtXQDjU2HgjUPI= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A= github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= 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.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 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/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/saferwall/pe v1.4.7 h1:A+G3DxX49paJ5OsxBfHKskhyDtmTjShlDmBd81IsHlQ= +github.com/saferwall/pe v1.4.7/go.mod h1:SNzv3cdgk8SBI0UwHfyTcdjawfdnN+nbydnEL7GZ25s= +github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= +github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ= +github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI= github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= -github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA= +github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= +github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo= +github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U= +github.com/sassoftware/go-rpmutils v0.2.0 h1:pKW0HDYMFWQ5b4JQPiI3WI12hGsVoW0V8+GMoZiI/JE= +github.com/sassoftware/go-rpmutils v0.2.0/go.mod h1:TJJQYtLe/BeEmEjelI3b7xNZjzAukEkeWKmoakvaOoI= +github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e h1:7q6NSFZDeGfvvtIRwBrU/aegEYJYmvev0cHAwo17zZQ= +github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e/go.mod h1:DkpGd78rljTxKAnTDPFqXSGxvETQnJyuSOQwsHycqfs= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624Y= +github.com/sebdah/goldie/v2 v2.5.3/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI= +github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= 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/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 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.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= +github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spdx/gordf v0.0.0-20201111095634-7098f93598fb/go.mod h1:uKWaldnbMnjsSAXRurWqqrdyZen1R7kxl8TkmWk2OyM= +github.com/spdx/tools-golang v0.5.3 h1:ialnHeEYUC4+hkm5vJm4qz2x+oEJbS0mAMFrNXdQraY= +github.com/spdx/tools-golang v0.5.3/go.mod h1:/ETOahiAo96Ob0/RAIBmFZw6XN0yTnyr/uFZm2NTMhI= +github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= +github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= 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/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= +github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI= +github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI= 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= @@ -415,13 +1095,61 @@ 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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/sylabs/sif/v2 v2.11.5 h1:7ssPH3epSonsTrzbS1YxeJ9KuqAN7ISlSM61a7j/mQM= +github.com/sylabs/sif/v2 v2.11.5/go.mod h1:GBoZs9LU3e4yJH1dcZ3Akf/jsqYgy5SeguJQC+zd75Y= +github.com/sylabs/squashfs v0.6.1 h1:4hgvHnD9JGlYWwT0bPYNt9zaz23mAV3Js+VEgQoRGYQ= +github.com/sylabs/squashfs v0.6.1/go.mod h1:ZwpbPCj0ocIvMy2br6KZmix6Gzh6fsGQcCnydMF+Kx8= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/terminalstatic/go-xsd-validate v0.1.5 h1:RqpJnf6HGE2CB/lZB1A8BYguk8uRtcvYAPLCF15qguo= +github.com/terminalstatic/go-xsd-validate v0.1.5/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw= +github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw= +github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY= +github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= +github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= +github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/vbatts/go-mtree v0.5.3 h1:S/jYlfG8rZ+a0bhZd+RANXejy7M4Js8fq9U+XoWTd5w= +github.com/vbatts/go-mtree v0.5.3/go.mod h1:eXsdoPMdL2jcJx6HweWi9lYQxBsTp4lNhqqAjgkZUg8= +github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck= +github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY= +github.com/vifraa/gopom v1.0.0 h1:L9XlKbyvid8PAIK8nr0lihMApJQg/12OBvMA28BcWh0= +github.com/vifraa/gopom v1.0.0/go.mod h1:oPa1dcrGrtlO37WPDBm5SqHAT+wTgF8An1Q71Z6Vv4o= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= +github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651 h1:jIVmlAFIqV3d+DOxazTR9v+zgj8+VYuQBzPgBZvWBHA= +github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651/go.mod h1:b26F2tHLqaoRQf8DywqzVaV1MQ9yvjb0OMcNl7Nxu20= +github.com/wagoodman/go-presenter v0.0.0-20211015174752-f9c01afc824b h1:uWNQ0khA6RdFzODOMwKo9XXu7fuewnnkHykUtuKru8s= +github.com/wagoodman/go-presenter v0.0.0-20211015174752-f9c01afc824b/go.mod h1:ewlIKbKV8l+jCj8rkdXIs361ocR5x3qGyoCSca47Gx8= +github.com/wagoodman/go-progress v0.0.0-20230925121702-07e42b3cdba0 h1:0KGbf+0SMg+UFy4e1A/CPVvXn21f1qtWdeJwxZFoQG8= +github.com/wagoodman/go-progress v0.0.0-20230925121702-07e42b3cdba0/go.mod h1:jLXFoL31zFaHKAAyZUh+sxiTDFe1L1ZHrcK2T1itVKA= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -429,10 +1157,17 @@ 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/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= +github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8= +github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 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.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 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= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= @@ -440,134 +1175,610 @@ 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= +github.com/zclconf/go-cty v1.14.0 h1:/Xrd39K7DXbHzlisFP9c4pHao4yyf+/Ug9LEz+Y/yhc= +github.com/zclconf/go-cty v1.14.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= +go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= +go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 h1:CCriYyAfq1Br1aIYettdHZTy8mBTIPo7We18TuO/bak= +go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= +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.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= 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.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= 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= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/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-20190820162420-60c769a6c586/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= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= 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/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +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/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/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.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181017193950-04a2e542c03f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/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-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +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-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/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-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -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/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-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/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.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= +golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= +golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= 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-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/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-20190222072716-a9d3bda3a223/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-20190606203320-7fc4e5ec1444/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-20190904154756-749cb33beabd/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-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/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-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-20200124204421-9fbb57f87de9/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-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/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-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/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-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/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-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/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-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/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-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 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.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +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.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/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.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -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/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.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= 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-20191108193012-7d206e10da11/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-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +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-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= -golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= 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= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +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/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.152.0 h1:t0r1vPnfMc260S2Ci+en7kfCZaLOPs5KI0sVV/6jZrY= +google.golang.org/api v0.152.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY= 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-20200513103714-09dca8ec2884/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/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/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-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ= +google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= +google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo= +google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:ultW7fxlIvee4HYrtnaRPon9HpEgFk5zYpmfMgtKB5I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= 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.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= -google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +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.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 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= @@ -576,37 +1787,58 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi 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.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +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/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= 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.3/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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls= +gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= helm.sh/helm/v3 v3.13.2 h1:IcO9NgmmpetJODLZhR3f3q+6zzyXVKlRizKFwbi7K8w= helm.sh/helm/v3 v3.13.2/go.mod h1:GIHDwZggaTGbedevTlrQ6DB++LBN6yuQdeGj0HNaDx0= 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.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY= k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0= k8s.io/apiextensions-apiserver v0.28.3 h1:Od7DEnhXHnHPZG+W9I97/fSQkVpVPQx2diy+2EtmY08= @@ -631,8 +1863,19 @@ k8s.io/metrics v0.28.4 h1:u36fom9+6c8jX2sk8z58H0hFaIUfrPWbXIxN7GT2blk= k8s.io/metrics v0.28.4/go.mod h1:bBqAJxH20c7wAsTQxDXOlVqxGMdce49d7WNr1WeaLac= k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +modernc.org/libc v1.29.0 h1:tTFRFq69YKCF2QyGNuRUQxKBm1uZZLubf6Cjh/pVHXs= +modernc.org/libc v1.29.0/go.mod h1:DaG/4Q3LRRdqpiLyP0C2m1B8ZMGkQ+cCgOIjEtQlYhQ= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= +modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= +modernc.org/sqlite v1.27.0 h1:MpKAHoyYB7xqcwnUwkuD+npwEa0fojF0B5QRbN+auJ8= +modernc.org/sqlite v1.27.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0= oras.land/oras-go v1.2.4 h1:djpBY2/2Cs1PV87GSJlxv4voajVOMZxqqtq9AB8YNvY= oras.land/oras-go v1.2.4/go.mod h1:DYcGfb3YF1nKjcezfX2SNlDAeQFKSXmf+qrFmrh4324= +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.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0= @@ -641,5 +1884,6 @@ sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM 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/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/internal/client/metrics.go b/internal/client/metrics.go index 79f34eeb13..8ba7fd3568 100644 --- a/internal/client/metrics.go +++ b/internal/client/metrics.go @@ -228,7 +228,7 @@ func (m *MetricsServer) FetchPodsMetrics(ctx context.Context, ns string) (*mv1be if entry, ok := m.cache.Get(key); ok { mxList, ok := entry.(*mv1beta1.PodMetricsList) if !ok { - return mx, fmt.Errorf("expected podmetricslist but got %T", entry) + return mx, fmt.Errorf("expected PodMetricsList but got %T", entry) } return mxList, nil } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 9e7ea0badd..bef14aeab5 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -284,6 +284,7 @@ var expectedConfig = `k9s: refreshRate: 100 maxConnRetry: 5 enableMouse: false + enableImageScan: false headless: false logoless: false crumbsless: false @@ -365,6 +366,7 @@ var resetConfig = `k9s: refreshRate: 2 maxConnRetry: 5 enableMouse: false + enableImageScan: false headless: false logoless: false crumbsless: false diff --git a/internal/config/k9s.go b/internal/config/k9s.go index 9d090ad6e0..8dbaacb638 100644 --- a/internal/config/k9s.go +++ b/internal/config/k9s.go @@ -18,6 +18,7 @@ type K9s struct { RefreshRate int `yaml:"refreshRate"` MaxConnRetry int `yaml:"maxConnRetry"` EnableMouse bool `yaml:"enableMouse"` + EnableImageScan bool `yaml:"enableImageScan"` Headless bool `yaml:"headless"` Logoless bool `yaml:"logoless"` Crumbsless bool `yaml:"crumbsless"` diff --git a/internal/dao/cronjob.go b/internal/dao/cronjob.go index 2e1d013ed3..290e1bb9ea 100644 --- a/internal/dao/cronjob.go +++ b/internal/dao/cronjob.go @@ -9,6 +9,7 @@ import ( "fmt" "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/render" "github.com/rs/zerolog/log" batchv1 "k8s.io/api/batch/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -24,8 +25,9 @@ const ( ) var ( - _ Accessor = (*CronJob)(nil) - _ Runnable = (*CronJob)(nil) + _ Accessor = (*CronJob)(nil) + _ Runnable = (*CronJob)(nil) + _ ImageLister = (*CronJob)(nil) ) // CronJob represents a cronjob K8s resource. @@ -33,6 +35,16 @@ type CronJob struct { Generic } +// ListImages lists container images. +func (c *CronJob) ListImages(ctx context.Context, fqn string) ([]string, error) { + cj, err := c.GetInstance(fqn) + if err != nil { + return nil, err + } + + return render.ExtractImages(&cj.Spec.JobTemplate.Spec.Template.Spec), nil +} + // Run a CronJob. func (c *CronJob) Run(path string) error { ns, _ := client.Namespaced(path) @@ -113,6 +125,22 @@ func (c *CronJob) ScanSA(ctx context.Context, fqn string, wait bool) (Refs, erro return refs, nil } +// GetInstance fetch a matching cronjob. +func (c *CronJob) GetInstance(fqn string) (*batchv1.CronJob, error) { + o, err := c.GetFactory().Get(c.GVR(), fqn, true, labels.Everything()) + if err != nil { + return nil, err + } + + var cj batchv1.CronJob + err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &cj) + if err != nil { + return nil, errors.New("expecting cronjob resource") + } + + return &cj, nil +} + // ToggleSuspend toggles suspend/resume on a CronJob. func (c *CronJob) ToggleSuspend(ctx context.Context, path string) error { ns, n := client.Namespaced(path) diff --git a/internal/dao/dp.go b/internal/dao/dp.go index 9da3556a65..db1680aa2b 100644 --- a/internal/dao/dp.go +++ b/internal/dao/dp.go @@ -9,6 +9,7 @@ import ( "fmt" "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/render" "github.com/rs/zerolog/log" appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" @@ -30,6 +31,7 @@ var ( _ Scalable = (*Deployment)(nil) _ Controller = (*Deployment)(nil) _ ContainsPodSpec = (*Deployment)(nil) + _ ImageLister = (*Deployment)(nil) ) // Deployment represents a deployment K8s resource. @@ -37,6 +39,16 @@ type Deployment struct { Resource } +// ListImages lists container images. +func (d *Deployment) ListImages(ctx context.Context, fqn string) ([]string, error) { + dp, err := d.GetInstance(fqn) + if err != nil { + return nil, err + } + + return render.ExtractImages(&dp.Spec.Template.Spec), nil +} + // IsHappy check for happy deployments. func (d *Deployment) IsHappy(dp appsv1.Deployment) bool { return dp.Status.Replicas == dp.Status.AvailableReplicas @@ -118,7 +130,7 @@ func (d *Deployment) Restart(ctx context.Context, path string) error { // TailLogs tail logs for all pods represented by this Deployment. func (d *Deployment) TailLogs(ctx context.Context, opts *LogOptions) ([]LogChan, error) { - dp, err := d.GetInstance(d.Factory, opts.Path) + dp, err := d.GetInstance(opts.Path) if err != nil { return nil, err } @@ -131,7 +143,7 @@ func (d *Deployment) TailLogs(ctx context.Context, opts *LogOptions) ([]LogChan, // Pod returns a pod victim by name. func (d *Deployment) Pod(fqn string) (string, error) { - dp, err := d.GetInstance(d.Factory, fqn) + dp, err := d.GetInstance(fqn) if err != nil { return "", err } @@ -140,8 +152,8 @@ func (d *Deployment) Pod(fqn string) (string, error) { } // GetInstance fetch a matching deployment. -func (*Deployment) GetInstance(f Factory, fqn string) (*appsv1.Deployment, error) { - o, err := f.Get("apps/v1/deployments", fqn, true, labels.Everything()) +func (d *Deployment) GetInstance(fqn string) (*appsv1.Deployment, error) { + o, err := d.Factory.Get(d.GVR(), fqn, true, labels.Everything()) if err != nil { return nil, err } @@ -243,7 +255,7 @@ func (d *Deployment) Scan(ctx context.Context, gvr, fqn string, wait bool) (Refs // GetPodSpec returns a pod spec given a resource. func (d *Deployment) GetPodSpec(path string) (*v1.PodSpec, error) { - dp, err := d.GetInstance(d.Factory, path) + dp, err := d.GetInstance(path) if err != nil { return nil, err } diff --git a/internal/dao/ds.go b/internal/dao/ds.go index d970afd274..44c84e3915 100644 --- a/internal/dao/ds.go +++ b/internal/dao/ds.go @@ -11,6 +11,7 @@ import ( "github.com/derailed/k9s/internal" "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/render" "github.com/derailed/k9s/internal/watch" "github.com/rs/zerolog/log" appsv1 "k8s.io/api/apps/v1" @@ -32,6 +33,7 @@ var ( _ Restartable = (*DaemonSet)(nil) _ Controller = (*DaemonSet)(nil) _ ContainsPodSpec = (*DaemonSet)(nil) + _ ImageLister = (*DaemonSet)(nil) ) // DaemonSet represents a K8s daemonset. @@ -39,6 +41,16 @@ type DaemonSet struct { Resource } +// ListImages lists container images. +func (d *DaemonSet) ListImages(ctx context.Context, fqn string) ([]string, error) { + ds, err := d.GetInstance(fqn) + if err != nil { + return nil, err + } + + return render.ExtractImages(&ds.Spec.Template.Spec), nil +} + // IsHappy check for happy deployments. func (d *DaemonSet) IsHappy(ds appsv1.DaemonSet) bool { return ds.Status.DesiredNumberScheduled == ds.Status.CurrentNumberScheduled diff --git a/internal/dao/img_scan.go b/internal/dao/img_scan.go new file mode 100644 index 0000000000..77cdd7b10d --- /dev/null +++ b/internal/dao/img_scan.go @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of K9s + +package dao + +import ( + "context" + "fmt" + + "github.com/derailed/k9s/internal" + "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/render" + "github.com/derailed/k9s/internal/vul" + "k8s.io/apimachinery/pkg/runtime" +) + +var ( + _ Accessor = (*ImageScan)(nil) +) + +// ImageScan represents vulnerability scans. +type ImageScan struct { + NonResource +} + +func (is *ImageScan) listImages(ctx context.Context, gvr client.GVR, path string) ([]string, error) { + res, err := AccessorFor(is.Factory, gvr) + if err != nil { + return nil, err + } + s, ok := res.(ImageLister) + if !ok { + return nil, fmt.Errorf("resource %s is not image lister: %T", gvr, res) + } + + return s.ListImages(ctx, path) +} + +// List returns a collection of scans. +func (is *ImageScan) List(ctx context.Context, _ string) ([]runtime.Object, error) { + fqn, ok := ctx.Value(internal.KeyPath).(string) + if !ok { + return nil, fmt.Errorf("no context path for %q", is.gvr) + } + gvr, ok := ctx.Value(internal.KeyGVR).(client.GVR) + if !ok { + return nil, fmt.Errorf("no context gvr for %q", is.gvr) + } + + ii, err := is.listImages(ctx, gvr, fqn) + if err != nil { + return nil, err + } + + res := make([]runtime.Object, 0, len(ii)) + for _, img := range ii { + s, ok := vul.ImgScanner.GetScan(img) + if !ok { + continue + } + for _, r := range s.Table.Rows { + res = append(res, render.ImageScanRes{Image: img, Row: r}) + } + } + + return res, nil +} diff --git a/internal/dao/job.go b/internal/dao/job.go index 4b9311b3fd..4f70acc700 100644 --- a/internal/dao/job.go +++ b/internal/dao/job.go @@ -10,6 +10,7 @@ import ( "github.com/derailed/k9s/internal" "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/render" "github.com/rs/zerolog/log" batchv1 "k8s.io/api/batch/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -18,9 +19,10 @@ import ( ) var ( - _ Accessor = (*Job)(nil) - _ Nuker = (*Job)(nil) - _ Loggable = (*Job)(nil) + _ Accessor = (*Job)(nil) + _ Nuker = (*Job)(nil) + _ Loggable = (*Job)(nil) + _ ImageLister = (*Deployment)(nil) ) // Job represents a K8s job resource. @@ -28,6 +30,16 @@ type Job struct { Resource } +// ListImages lists container images. +func (j *Job) ListImages(ctx context.Context, fqn string) ([]string, error) { + job, err := j.GetInstance(fqn) + if err != nil { + return nil, err + } + + return render.ExtractImages(&job.Spec.Template.Spec), nil +} + // List returns a collection of resources. func (j *Job) List(ctx context.Context, ns string) ([]runtime.Object, error) { oo, err := j.Resource.List(ctx, ns) @@ -79,6 +91,21 @@ func (j *Job) TailLogs(ctx context.Context, opts *LogOptions) ([]LogChan, error) return podLogs(ctx, job.Spec.Selector.MatchLabels, opts) } +func (j *Job) GetInstance(fqn string) (*batchv1.Job, error) { + o, err := j.GetFactory().Get(j.gvr.String(), fqn, true, labels.Everything()) + if err != nil { + return nil, err + } + + var job batchv1.Job + err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &job) + if err != nil { + return nil, errors.New("expecting a job resource") + } + + return &job, nil +} + // ScanSA scans for serviceaccount refs. func (j *Job) ScanSA(ctx context.Context, fqn string, wait bool) (Refs, error) { ns, n := client.Namespaced(fqn) diff --git a/internal/dao/pod.go b/internal/dao/pod.go index 3e30ebd52e..05ef713e6a 100644 --- a/internal/dao/pod.go +++ b/internal/dao/pod.go @@ -33,6 +33,7 @@ var ( _ Loggable = (*Pod)(nil) _ Controller = (*Pod)(nil) _ ContainsPodSpec = (*Pod)(nil) + _ ImageLister = (*Pod)(nil) ) const ( @@ -76,6 +77,16 @@ func (p *Pod) Get(ctx context.Context, path string) (runtime.Object, error) { return &render.PodWithMetrics{Raw: u, MX: pmx}, nil } +// ListImages lists container images. +func (p *Pod) ListImages(ctx context.Context, path string) ([]string, error) { + pod, err := p.GetInstance(path) + if err != nil { + return nil, err + } + + return render.ExtractImages(&pod.Spec), nil +} + // List returns a collection of nodes. func (p *Pod) List(ctx context.Context, ns string) ([]runtime.Object, error) { oo, err := p.Resource.List(ctx, ns) diff --git a/internal/dao/registry.go b/internal/dao/registry.go index c67a94e5e8..54fdbce53e 100644 --- a/internal/dao/registry.go +++ b/internal/dao/registry.go @@ -85,6 +85,7 @@ func AccessorFor(f Factory, gvr client.GVR) (Accessor, error) { m := Accessors{ client.NewGVR("contexts"): &Context{}, client.NewGVR("containers"): &Container{}, + client.NewGVR("scans"): &ImageScan{}, client.NewGVR("screendumps"): &ScreenDump{}, client.NewGVR("benchmarks"): &Benchmark{}, client.NewGVR("portforwards"): &PortForward{}, @@ -94,6 +95,7 @@ func AccessorFor(f Factory, gvr client.GVR) (Accessor, error) { client.NewGVR("apps/v1/deployments"): &Deployment{}, client.NewGVR("apps/v1/daemonsets"): &DaemonSet{}, client.NewGVR("apps/v1/statefulsets"): &StatefulSet{}, + client.NewGVR("apps/v1/replicasets"): &ReplicaSet{}, client.NewGVR("batch/v1/cronjobs"): &CronJob{}, client.NewGVR("batch/v1beta1/cronjobs"): &CronJob{}, client.NewGVR("batch/v1/jobs"): &Job{}, @@ -290,6 +292,13 @@ func loadK9s(m ResourceMetas) { Verbs: []string{}, Categories: []string{k9sCat}, } + m[client.NewGVR("scans")] = metav1.APIResource{ + Name: "scans", + Kind: "Scans", + SingularName: "scan", + Verbs: []string{}, + Categories: []string{k9sCat}, + } } func loadHelm(m ResourceMetas) { diff --git a/internal/dao/rs.go b/internal/dao/rs.go index 06d91c9158..fea9d3265d 100644 --- a/internal/dao/rs.go +++ b/internal/dao/rs.go @@ -4,12 +4,14 @@ package dao import ( + "context" "errors" "fmt" "strconv" "strings" "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/render" appsv1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/labels" @@ -19,11 +21,25 @@ import ( "k8s.io/kubectl/pkg/polymorphichelpers" ) +var ( + _ ImageLister = (*ReplicaSet)(nil) +) + // ReplicaSet represents a replicaset K8s resource. type ReplicaSet struct { Resource } +// ListImages lists container images. +func (r *ReplicaSet) ListImages(ctx context.Context, fqn string) ([]string, error) { + rs, err := r.Load(r.Factory, fqn) + if err != nil { + return nil, err + } + + return render.ExtractImages(&rs.Spec.Template.Spec), nil +} + // Load returns a given instance. func (r *ReplicaSet) Load(f Factory, path string) (*appsv1.ReplicaSet, error) { o, err := f.Get("apps/v1/replicasets", path, true, labels.Everything()) @@ -98,7 +114,8 @@ func (r *ReplicaSet) Rollback(fqn string) error { } var ddp Deployment - dp, err := ddp.GetInstance(r.Factory, client.FQN(rs.Namespace, name)) + ddp.Init(r.Factory, client.NewGVR("apps/v1/deployments")) + dp, err := ddp.GetInstance(client.FQN(rs.Namespace, name)) if err != nil { return err } diff --git a/internal/dao/sts.go b/internal/dao/sts.go index d9ce1e1e6c..6e4b2fc822 100644 --- a/internal/dao/sts.go +++ b/internal/dao/sts.go @@ -10,6 +10,7 @@ import ( "strings" "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/render" "github.com/rs/zerolog/log" appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" @@ -31,6 +32,7 @@ var ( _ Scalable = (*StatefulSet)(nil) _ Controller = (*StatefulSet)(nil) _ ContainsPodSpec = (*StatefulSet)(nil) + _ ImageLister = (*StatefulSet)(nil) ) // StatefulSet represents a K8s sts. @@ -38,6 +40,16 @@ type StatefulSet struct { Resource } +// ListImages lists container images. +func (s *StatefulSet) ListImages(ctx context.Context, fqn string) ([]string, error) { + sts, err := s.GetInstance(s.Factory, fqn) + if err != nil { + return nil, err + } + + return render.ExtractImages(&sts.Spec.Template.Spec), nil +} + // IsHappy check for happy sts. func (s *StatefulSet) IsHappy(sts appsv1.StatefulSet) bool { return sts.Status.Replicas == sts.Status.ReadyReplicas diff --git a/internal/dao/types.go b/internal/dao/types.go index 9af913985c..e24cb22bf3 100644 --- a/internal/dao/types.go +++ b/internal/dao/types.go @@ -51,6 +51,12 @@ type Factory interface { Forwarders() watch.Forwarders } +// ImageLister tracks resources with container images. +type ImageLister interface { + // ListImages lists container images. + ListImages(ctx context.Context, path string) ([]string, error) +} + // Getter represents a resource getter. type Getter interface { // Get return a given resource. diff --git a/internal/keys.go b/internal/keys.go index db4aeda484..d18bc11d36 100644 --- a/internal/keys.go +++ b/internal/keys.go @@ -8,31 +8,32 @@ type ContextKey string // A collection of context keys. const ( - KeyFactory ContextKey = "factory" - KeyLabels ContextKey = "labels" - KeyFields ContextKey = "fields" - KeyTable ContextKey = "table" - KeyDir ContextKey = "dir" - KeyPath ContextKey = "path" - KeySubject ContextKey = "subject" - KeyGVR ContextKey = "gvr" - KeyFQN ContextKey = "fqn" - KeyForwards ContextKey = "forwards" - KeyContainers ContextKey = "containers" - KeyBenchCfg ContextKey = "benchcfg" - KeyAliases ContextKey = "aliases" - KeyUID ContextKey = "uid" - KeySubjectKind ContextKey = "subjectKind" - KeySubjectName ContextKey = "subjectName" - KeyNamespace ContextKey = "namespace" - KeyCluster ContextKey = "cluster" - KeyApp ContextKey = "app" - KeyStyles ContextKey = "styles" - KeyMetrics ContextKey = "metrics" - KeyHasMetrics ContextKey = "has-metrics" - KeyToast ContextKey = "toast" - KeyWithMetrics ContextKey = "withMetrics" - KeyViewConfig ContextKey = "viewConfig" - KeyWait ContextKey = "wait" - KeyPodCounting ContextKey = "podCounting" + KeyFactory ContextKey = "factory" + KeyLabels ContextKey = "labels" + KeyFields ContextKey = "fields" + KeyTable ContextKey = "table" + KeyDir ContextKey = "dir" + KeyPath ContextKey = "path" + KeySubject ContextKey = "subject" + KeyGVR ContextKey = "gvr" + KeyFQN ContextKey = "fqn" + KeyForwards ContextKey = "forwards" + KeyContainers ContextKey = "containers" + KeyBenchCfg ContextKey = "benchcfg" + KeyAliases ContextKey = "aliases" + KeyUID ContextKey = "uid" + KeySubjectKind ContextKey = "subjectKind" + KeySubjectName ContextKey = "subjectName" + KeyNamespace ContextKey = "namespace" + KeyCluster ContextKey = "cluster" + KeyApp ContextKey = "app" + KeyStyles ContextKey = "styles" + KeyMetrics ContextKey = "metrics" + KeyHasMetrics ContextKey = "has-metrics" + KeyToast ContextKey = "toast" + KeyWithMetrics ContextKey = "withMetrics" + KeyViewConfig ContextKey = "viewConfig" + KeyWait ContextKey = "wait" + KeyPodCounting ContextKey = "podCounting" + KeyEnableImgScan ContextKey = "vulScan" ) diff --git a/internal/model/registry.go b/internal/model/registry.go index e0b0c93938..8b7e238116 100644 --- a/internal/model/registry.go +++ b/internal/model/registry.go @@ -33,12 +33,15 @@ var Registry = map[string]ResourceMeta{ DAO: &dao.HelmHistory{}, Renderer: &helm.History{}, }, - "containers": { DAO: &dao.Container{}, Renderer: &render.Container{}, TreeRenderer: &xray.Container{}, }, + "scans": { + DAO: &dao.ImageScan{}, + Renderer: &render.ImageScan{}, + }, "contexts": { DAO: &dao.Context{}, Renderer: &render.Context{}, diff --git a/internal/render/cronjob.go b/internal/render/cronjob.go index b0947bb888..aaf2e8fa4d 100644 --- a/internal/render/cronjob.go +++ b/internal/render/cronjob.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/vul" batchv1 "k8s.io/api/batch/v1" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -22,9 +23,10 @@ type CronJob struct { // Header returns a header row. func (CronJob) Header(ns string) Header { - return Header{ + h := Header{ HeaderColumn{Name: "NAMESPACE"}, HeaderColumn{Name: "NAME"}, + HeaderColumn{Name: "VS"}, HeaderColumn{Name: "SCHEDULE"}, HeaderColumn{Name: "SUSPEND"}, HeaderColumn{Name: "ACTIVE"}, @@ -36,6 +38,12 @@ func (CronJob) Header(ns string) Header { HeaderColumn{Name: "VALID", Wide: true}, HeaderColumn{Name: "AGE", Time: true}, } + if vul.ImgScanner == nil { + h = append(h[:vulIdx], h[vulIdx+1:]...) + } + + return h + } // Render renders a K8s resource to screen. @@ -59,6 +67,7 @@ func (c CronJob) Render(o interface{}, ns string, r *Row) error { r.Fields = Fields{ cj.Namespace, cj.Name, + computeVulScore(&cj.Spec.JobTemplate.Spec.Template.Spec), cj.Spec.Schedule, boolPtrToStr(cj.Spec.Suspend), strconv.Itoa(len(cj.Status.Active)), @@ -70,6 +79,9 @@ func (c CronJob) Render(o interface{}, ns string, r *Row) error { "", ToAge(cj.GetCreationTimestamp()), } + if vul.ImgScanner == nil { + r.Fields = append(r.Fields[:vulIdx], r.Fields[vulIdx+1:]...) + } return nil } diff --git a/internal/render/dp.go b/internal/render/dp.go index 79a3abb2ef..3d1b2b5534 100644 --- a/internal/render/dp.go +++ b/internal/render/dp.go @@ -8,6 +8,7 @@ import ( "strconv" "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/vul" "github.com/derailed/tview" appsv1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -26,9 +27,10 @@ func (d Deployment) ColorerFunc() ColorerFunc { // Header returns a header row. func (Deployment) Header(ns string) Header { - return Header{ + h := Header{ HeaderColumn{Name: "NAMESPACE"}, HeaderColumn{Name: "NAME"}, + HeaderColumn{Name: "VS"}, HeaderColumn{Name: "READY", Align: tview.AlignRight}, HeaderColumn{Name: "UP-TO-DATE", Align: tview.AlignRight}, HeaderColumn{Name: "AVAILABLE", Align: tview.AlignRight}, @@ -36,6 +38,11 @@ func (Deployment) Header(ns string) Header { HeaderColumn{Name: "VALID", Wide: true}, HeaderColumn{Name: "AGE", Time: true}, } + if vul.ImgScanner == nil { + h = append(h[:vulIdx], h[vulIdx+1:]...) + } + + return h } // Render renders a K8s resource to screen. @@ -55,6 +62,7 @@ func (d Deployment) Render(o interface{}, ns string, r *Row) error { r.Fields = Fields{ dp.Namespace, dp.Name, + computeVulScore(&dp.Spec.Template.Spec), strconv.Itoa(int(dp.Status.AvailableReplicas)) + "/" + strconv.Itoa(int(dp.Status.Replicas)), strconv.Itoa(int(dp.Status.UpdatedReplicas)), strconv.Itoa(int(dp.Status.AvailableReplicas)), @@ -62,6 +70,9 @@ func (d Deployment) Render(o interface{}, ns string, r *Row) error { AsStatus(d.diagnose(dp.Status.Replicas, dp.Status.AvailableReplicas)), ToAge(dp.GetCreationTimestamp()), } + if vul.ImgScanner == nil { + r.Fields = append(r.Fields[:vulIdx], r.Fields[vulIdx+1:]...) + } return nil } diff --git a/internal/render/ds.go b/internal/render/ds.go index 161f68cb5a..87f92494ae 100644 --- a/internal/render/ds.go +++ b/internal/render/ds.go @@ -8,6 +8,7 @@ import ( "strconv" "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/vul" "github.com/derailed/tview" appsv1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -21,9 +22,10 @@ type DaemonSet struct { // Header returns a header row. func (DaemonSet) Header(ns string) Header { - return Header{ + h := Header{ HeaderColumn{Name: "NAMESPACE"}, HeaderColumn{Name: "NAME"}, + HeaderColumn{Name: "VS"}, HeaderColumn{Name: "DESIRED", Align: tview.AlignRight}, HeaderColumn{Name: "CURRENT", Align: tview.AlignRight}, HeaderColumn{Name: "READY", Align: tview.AlignRight}, @@ -33,6 +35,11 @@ func (DaemonSet) Header(ns string) Header { HeaderColumn{Name: "VALID", Wide: true}, HeaderColumn{Name: "AGE", Time: true}, } + if vul.ImgScanner == nil { + h = append(h[:vulIdx], h[vulIdx+1:]...) + } + + return h } // Render renders a K8s resource to screen. @@ -51,6 +58,7 @@ func (d DaemonSet) Render(o interface{}, ns string, r *Row) error { r.Fields = Fields{ ds.Namespace, ds.Name, + computeVulScore(&ds.Spec.Template.Spec), strconv.Itoa(int(ds.Status.DesiredNumberScheduled)), strconv.Itoa(int(ds.Status.CurrentNumberScheduled)), strconv.Itoa(int(ds.Status.NumberReady)), @@ -60,6 +68,9 @@ func (d DaemonSet) Render(o interface{}, ns string, r *Row) error { AsStatus(d.diagnose(ds.Status.DesiredNumberScheduled, ds.Status.NumberReady)), ToAge(ds.GetCreationTimestamp()), } + if vul.ImgScanner == nil { + r.Fields = append(r.Fields[:vulIdx], r.Fields[vulIdx+1:]...) + } return nil } diff --git a/internal/render/helpers.go b/internal/render/helpers.go index 2d2d345d4a..2ccd503173 100644 --- a/internal/render/helpers.go +++ b/internal/render/helpers.go @@ -10,16 +10,28 @@ import ( "time" "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/vul" "github.com/derailed/tview" runewidth "github.com/mattn/go-runewidth" "github.com/rs/zerolog/log" "golang.org/x/text/language" "golang.org/x/text/message" + v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/duration" ) +func computeVulScore(spec *v1.PodSpec) string { + if vul.ImgScanner == nil { + return "0" + } + ii := ExtractImages(spec) + vul.ImgScanner.Enqueue(ii...) + + return vul.ImgScanner.Score(ii...) +} + func runesToNum(rr []rune) int64 { var r int64 var m int64 = 1 diff --git a/internal/render/img_scan.go b/internal/render/img_scan.go new file mode 100644 index 0000000000..03ab3c2eb9 --- /dev/null +++ b/internal/render/img_scan.go @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of K9s + +package render + +import ( + "fmt" + "strings" + + "github.com/derailed/k9s/internal/vul" + "github.com/derailed/tcell/v2" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +const ( + CVEParseIdx = 5 + sevColName = "SEVERITY" +) + +// ImageScan renders scans report table. +type ImageScan struct { + Base +} + +// ColorerFunc colors a resource row. +func (c ImageScan) ColorerFunc() ColorerFunc { + return func(ns string, h Header, re RowEvent) tcell.Color { + c := DefaultColorer(ns, h, re) + + sevCol := h.IndexOf(sevColName, true) + if sevCol == -1 { + return c + } + sev := strings.TrimSpace(re.Row.Fields[sevCol]) + switch sev { + case vul.Sev1: + c = tcell.ColorRed + case vul.Sev2: + c = tcell.ColorDarkOrange + case vul.Sev3: + c = tcell.ColorYellow + case vul.Sev4: + c = tcell.ColorDeepSkyBlue + case vul.Sev5: + c = tcell.ColorCadetBlue + default: + c = tcell.ColorDarkOliveGreen + } + + return c + } + +} + +// Header returns a header row. +func (ImageScan) Header(ns string) Header { + return Header{ + HeaderColumn{Name: "SEVERITY"}, + HeaderColumn{Name: "VULNERABILITY"}, + HeaderColumn{Name: "IMAGE"}, + HeaderColumn{Name: "LIBRARY"}, + HeaderColumn{Name: "VERSION"}, + HeaderColumn{Name: "FIXED-IN"}, + HeaderColumn{Name: "TYPE"}, + } +} + +// Render renders a K8s resource to screen. +func (is ImageScan) Render(o interface{}, name string, r *Row) error { + res, ok := o.(ImageScanRes) + if !ok { + return fmt.Errorf("expected ImageScanRes, but got %T", o) + } + + r.ID = fmt.Sprintf("%s|%s", res.Image, strings.Join(res.Row, "|")) + r.Fields = Fields{ + res.Row.Severity(), + res.Row.Vulnerability(), + res.Image, + res.Row.Name(), + res.Row.Version(), + res.Row.Fix(), + res.Row.Type(), + } + + return nil +} + +// ---------------------------------------------------------------------------- +// Helpers... + +// ImageScanRes represents a container and its metrics. +type ImageScanRes struct { + Image string + Row vul.Row +} + +// GetObjectKind returns a schema object. +func (ImageScanRes) GetObjectKind() schema.ObjectKind { + return nil +} + +// DeepCopyObject returns a container copy. +func (is ImageScanRes) DeepCopyObject() runtime.Object { + return is +} diff --git a/internal/render/job.go b/internal/render/job.go index 5d9c3d0fbb..b6325d8cf9 100644 --- a/internal/render/job.go +++ b/internal/render/job.go @@ -10,6 +10,7 @@ import ( "time" "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/vul" batchv1 "k8s.io/api/batch/v1" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -25,9 +26,10 @@ type Job struct { // Header returns a header row. func (Job) Header(ns string) Header { - return Header{ + h := Header{ HeaderColumn{Name: "NAMESPACE"}, HeaderColumn{Name: "NAME"}, + HeaderColumn{Name: "VS"}, HeaderColumn{Name: "COMPLETIONS"}, HeaderColumn{Name: "DURATION"}, HeaderColumn{Name: "SELECTOR", Wide: true}, @@ -36,6 +38,11 @@ func (Job) Header(ns string) Header { HeaderColumn{Name: "VALID", Wide: true}, HeaderColumn{Name: "AGE", Time: true}, } + if vul.ImgScanner == nil { + h = append(h[:vulIdx], h[vulIdx+1:]...) + } + + return h } // Render renders a K8s resource to screen. @@ -57,6 +64,7 @@ func (j Job) Render(o interface{}, ns string, r *Row) error { r.Fields = Fields{ job.Namespace, job.Name, + computeVulScore(&job.Spec.Template.Spec), ready, toDuration(job.Status), jobSelector(job.Spec), @@ -65,6 +73,9 @@ func (j Job) Render(o interface{}, ns string, r *Row) error { AsStatus(j.diagnose(ready, job.Status.CompletionTime)), ToAge(job.GetCreationTimestamp()), } + if vul.ImgScanner == nil { + r.Fields = append(r.Fields[:vulIdx], r.Fields[vulIdx+1:]...) + } return nil } diff --git a/internal/render/pod.go b/internal/render/pod.go index 0740bc5feb..a79cafe252 100644 --- a/internal/render/pod.go +++ b/internal/render/pod.go @@ -18,12 +18,14 @@ import ( mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1" "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/vul" ) const ( // NodeUnreachablePodReason is reason and message set on a pod when its state // cannot be confirmed as kubelet is unresponsive on the node it is (was) running. NodeUnreachablePodReason = "NodeLost" // k8s.io/kubernetes/pkg/util/node.NodeUnreachablePodReason + vulIdx = 2 ) const ( @@ -83,9 +85,10 @@ func (p Pod) ColorerFunc() ColorerFunc { // Header returns a header row. func (Pod) Header(ns string) Header { - return Header{ + h := Header{ HeaderColumn{Name: "NAMESPACE"}, HeaderColumn{Name: "NAME"}, + HeaderColumn{Name: "VS"}, HeaderColumn{Name: "PF"}, HeaderColumn{Name: "READY"}, HeaderColumn{Name: "STATUS"}, @@ -107,6 +110,22 @@ func (Pod) Header(ns string) Header { HeaderColumn{Name: "VALID", Wide: true}, HeaderColumn{Name: "AGE", Time: true}, } + if vul.ImgScanner == nil { + h = append(h[:vulIdx], h[vulIdx+1:]...) + } + + return h +} + +// ExtractImages returns a collection of container images. +// !!BOZO!! If this has any legs?? enable scans on other container types. +func ExtractImages(spec *v1.PodSpec) []string { + ii := make([]string, 0, len(spec.Containers)) + for _, c := range spec.Containers { + ii = append(ii, c.Image) + } + + return ii } // Render renders a K8s resource to screen. @@ -132,6 +151,7 @@ func (p Pod) Render(o interface{}, ns string, row *Row) error { row.Fields = Fields{ po.Namespace, po.ObjectMeta.Name, + computeVulScore(&po.Spec), "●", strconv.Itoa(cr) + "/" + strconv.Itoa(len(po.Spec.Containers)), phase, @@ -153,6 +173,9 @@ func (p Pod) Render(o interface{}, ns string, row *Row) error { AsStatus(p.diagnose(phase, cr, len(cs))), ToAge(po.GetCreationTimestamp()), } + if vul.ImgScanner == nil { + row.Fields = append(row.Fields[:vulIdx], row.Fields[vulIdx+1:]...) + } return nil } diff --git a/internal/render/row.go b/internal/render/row.go index c562bc23cd..858b11987a 100644 --- a/internal/render/row.go +++ b/internal/render/row.go @@ -193,19 +193,16 @@ func (s RowSorter) Less(i, j int) bool { // ---------------------------------------------------------------------------- // Helpers... -// Less return true if c1 < c2. +// Less return true if c1 <= c2. func Less(isNumber, isDuration, isCapacity bool, id1, id2, v1, v2 string) bool { var less bool switch { case isNumber: - v1, v2 = strings.Replace(v1, ",", "", -1), strings.Replace(v2, ",", "", -1) - less = sortorder.NaturalLess(v1, v2) + less = lessNumber(v1, v2) case isDuration: - d1, d2 := durationToSeconds(v1), durationToSeconds(v2) - less = d1 <= d2 + less = lessDuration(v1, v2) case isCapacity: - c1, c2 := capacityToNumber(v1), capacityToNumber(v2) - less = c1 <= c2 + less = lessCapacity(v1, v2) default: less = sortorder.NaturalLess(v1, v2) } @@ -215,3 +212,20 @@ func Less(isNumber, isDuration, isCapacity bool, id1, id2, v1, v2 string) bool { return less } + +func lessDuration(s1, s2 string) bool { + d1, d2 := durationToSeconds(s1), durationToSeconds(s2) + return d1 <= d2 +} + +func lessCapacity(s1, s2 string) bool { + c1, c2 := capacityToNumber(s1), capacityToNumber(s2) + + return c1 <= c2 +} + +func lessNumber(s1, s2 string) bool { + v1, v2 := strings.Replace(s1, ",", "", -1), strings.Replace(s2, ",", "", -1) + + return sortorder.NaturalLess(v1, v2) +} diff --git a/internal/render/row_event.go b/internal/render/row_event.go index e3f1230d11..7248371db0 100644 --- a/internal/render/row_event.go +++ b/internal/render/row_event.go @@ -244,50 +244,3 @@ func (r RowEventSorter) Less(i, j int) bool { return !less } - -// ---------------------------------------------------------------------------- - -// // IdSorter sorts row events by a given id. -// type IdSorter struct { -// Ids map[string]int -// Events RowEvents -// } - -// func (s IdSorter) Len() int { -// return len(s.Events) -// } - -// func (s IdSorter) Swap(i, j int) { -// s.Events[i], s.Events[j] = s.Events[j], s.Events[i] -// } - -// func (s IdSorter) Less(i, j int) bool { -// return s.Ids[s.Events[i].Row.ID] < s.Ids[s.Events[j].Row.ID] -// } - -// ---------------------------------------------------------------------------- - -// // StringSet represents a collection of unique strings. -// type StringSet []string - -// // Add adds a new item in the set. -// func (ss StringSet) Add(item string) StringSet { -// if ss.In(item) { -// return ss -// } -// return append(ss, item) -// } - -// // In checks if a string is in the set. -// func (ss StringSet) In(item string) bool { -// return ss.indexOf(item) >= 0 -// } - -// func (ss StringSet) indexOf(item string) int { -// for i, s := range ss { -// if s == item { -// return i -// } -// } -// return -1 -// } diff --git a/internal/render/rs.go b/internal/render/rs.go index b7f9d8c240..a8287e4566 100644 --- a/internal/render/rs.go +++ b/internal/render/rs.go @@ -8,6 +8,7 @@ import ( "strconv" "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/vul" "github.com/derailed/tview" appsv1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -26,9 +27,10 @@ func (r ReplicaSet) ColorerFunc() ColorerFunc { // Header returns a header row. func (ReplicaSet) Header(ns string) Header { - return Header{ + h := Header{ HeaderColumn{Name: "NAMESPACE"}, HeaderColumn{Name: "NAME"}, + HeaderColumn{Name: "VS"}, HeaderColumn{Name: "DESIRED", Align: tview.AlignRight}, HeaderColumn{Name: "CURRENT", Align: tview.AlignRight}, HeaderColumn{Name: "READY", Align: tview.AlignRight}, @@ -36,6 +38,11 @@ func (ReplicaSet) Header(ns string) Header { HeaderColumn{Name: "VALID", Wide: true}, HeaderColumn{Name: "AGE", Time: true}, } + if vul.ImgScanner == nil { + h = append(h[:vulIdx], h[vulIdx+1:]...) + } + + return h } // Render renders a K8s resource to screen. @@ -54,6 +61,7 @@ func (r ReplicaSet) Render(o interface{}, ns string, row *Row) error { row.Fields = Fields{ rs.Namespace, rs.Name, + computeVulScore(&rs.Spec.Template.Spec), strconv.Itoa(int(*rs.Spec.Replicas)), strconv.Itoa(int(rs.Status.Replicas)), strconv.Itoa(int(rs.Status.ReadyReplicas)), @@ -61,6 +69,9 @@ func (r ReplicaSet) Render(o interface{}, ns string, row *Row) error { AsStatus(r.diagnose(rs)), ToAge(rs.GetCreationTimestamp()), } + if vul.ImgScanner == nil { + row.Fields = append(row.Fields[:vulIdx], row.Fields[vulIdx+1:]...) + } return nil } diff --git a/internal/render/sts.go b/internal/render/sts.go index dee385cf12..08704bfd9c 100644 --- a/internal/render/sts.go +++ b/internal/render/sts.go @@ -8,6 +8,7 @@ import ( "strconv" "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/vul" appsv1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" @@ -20,9 +21,10 @@ type StatefulSet struct { // Header returns a header row. func (StatefulSet) Header(ns string) Header { - return Header{ + h := Header{ HeaderColumn{Name: "NAMESPACE"}, HeaderColumn{Name: "NAME"}, + HeaderColumn{Name: "VS"}, HeaderColumn{Name: "READY"}, HeaderColumn{Name: "SELECTOR", Wide: true}, HeaderColumn{Name: "SERVICE"}, @@ -32,6 +34,11 @@ func (StatefulSet) Header(ns string) Header { HeaderColumn{Name: "VALID", Wide: true}, HeaderColumn{Name: "AGE", Time: true}, } + if vul.ImgScanner == nil { + h = append(h[:vulIdx], h[vulIdx+1:]...) + } + + return h } // Render renders a K8s resource to screen. @@ -50,6 +57,7 @@ func (s StatefulSet) Render(o interface{}, ns string, r *Row) error { r.Fields = Fields{ sts.Namespace, sts.Name, + computeVulScore(&sts.Spec.Template.Spec), strconv.Itoa(int(sts.Status.ReadyReplicas)) + "/" + strconv.Itoa(int(sts.Status.Replicas)), asSelector(sts.Spec.Selector), na(sts.Spec.ServiceName), @@ -59,6 +67,9 @@ func (s StatefulSet) Render(o interface{}, ns string, r *Row) error { AsStatus(s.diagnose(sts.Status.Replicas, sts.Status.ReadyReplicas)), ToAge(sts.GetCreationTimestamp()), } + if vul.ImgScanner == nil { + r.Fields = append(r.Fields[:vulIdx], r.Fields[vulIdx+1:]...) + } return nil } diff --git a/internal/view/app.go b/internal/view/app.go index f3a5ef0d0c..374f0ba74c 100644 --- a/internal/view/app.go +++ b/internal/view/app.go @@ -23,6 +23,7 @@ import ( "github.com/derailed/k9s/internal/model" "github.com/derailed/k9s/internal/ui" "github.com/derailed/k9s/internal/ui/dialog" + "github.com/derailed/k9s/internal/vul" "github.com/derailed/k9s/internal/watch" "github.com/derailed/tcell/v2" "github.com/derailed/tview" @@ -120,9 +121,28 @@ func (a *App) Init(version string, rate int) error { a.layout(ctx) a.initSignals() + if a.Config.K9s.EnableImageScan { + a.initImgScanner(version) + } + return nil } +func (a *App) stopImgScanner() { + if vul.ImgScanner != nil { + vul.ImgScanner.Stop() + } +} + +func (a *App) initImgScanner(version string) { + defer func(t time.Time) { + log.Debug().Msgf("Scanner init time %s", time.Since(t)) + }(time.Now()) + + vul.ImgScanner = vul.NewImageScanner() + go vul.ImgScanner.Init("k9s", version) +} + func (a *App) layout(ctx context.Context) { flash := ui.NewFlash(a.App) go flash.Watch(ctx, a.Flash().Channel()) @@ -492,6 +512,8 @@ func (a *App) BailOut() { if err := nukeK9sShell(a); err != nil { log.Error().Err(err).Msgf("nuking k9s shell pod") } + + a.stopImgScanner() a.factory.Terminate() a.App.BailOut() } diff --git a/internal/view/benchmark.go b/internal/view/benchmark.go index db9f856c55..daa26be302 100644 --- a/internal/view/benchmark.go +++ b/internal/view/benchmark.go @@ -47,7 +47,7 @@ func (b *Benchmark) viewBench(app *App, model ui.Tabular, gvr, path string) { return } - details := NewDetails(b.App(), "Results", fileToSubject(path), false).Update(data) + details := NewDetails(b.App(), "Results", fileToSubject(path), contentYAML, false).Update(data) if err := app.inject(details, false); err != nil { app.Flash().Err(err) } diff --git a/internal/view/cronjob.go b/internal/view/cronjob.go index a5a5d7de15..940904111a 100644 --- a/internal/view/cronjob.go +++ b/internal/view/cronjob.go @@ -35,7 +35,7 @@ type CronJob struct { // NewCronJob returns a new viewer. func NewCronJob(gvr client.GVR) ResourceViewer { - c := CronJob{ResourceViewer: NewBrowser(gvr)} + c := CronJob{ResourceViewer: NewVulnerabilityExtender(NewBrowser(gvr))} c.AddBindKeysFn(c.bindKeys) c.GetTable().SetEnterFn(c.showJobs) diff --git a/internal/view/details.go b/internal/view/details.go index e3f96f44c7..cc366d33cd 100644 --- a/internal/view/details.go +++ b/internal/view/details.go @@ -17,7 +17,11 @@ import ( "github.com/sahilm/fuzzy" ) -const detailsTitleFmt = "[fg:bg:b] %s([hilite:bg:b]%s[fg:bg:-])[fg:bg:-] " +const ( + detailsTitleFmt = "[fg:bg:b] %s([hilite:bg:b]%s[fg:bg:-])[fg:bg:-] " + contentTXT = "text" + contentYAML = "yaml" +) // Details represents a generic text viewer. type Details struct { @@ -32,20 +36,22 @@ type Details struct { currentRegion, maxRegions int searchable bool fullScreen bool + contentType string } // NewDetails returns a details viewer. -func NewDetails(app *App, title, subject string, searchable bool) *Details { +func NewDetails(app *App, title, subject, contentType string, searchable bool) *Details { d := Details{ - Flex: tview.NewFlex(), - text: tview.NewTextView(), - app: app, - title: title, - subject: subject, - actions: make(ui.KeyActions), - cmdBuff: model.NewFishBuff('/', model.FilterBuffer), - model: model.NewText(), - searchable: searchable, + Flex: tview.NewFlex(), + text: tview.NewTextView(), + app: app, + title: title, + subject: subject, + actions: make(ui.KeyActions), + cmdBuff: model.NewFishBuff('/', model.FilterBuffer), + model: model.NewText(), + searchable: searchable, + contentType: contentType, } d.AddItem(d.text, 0, 1, true) @@ -85,7 +91,12 @@ func (d *Details) InCmdMode() bool { // TextChanged notifies the model changed. func (d *Details) TextChanged(lines []string) { - d.text.SetText(colorizeYAML(d.app.Styles.Views().Yaml, strings.Join(lines, "\n"))) + switch d.contentType { + case contentYAML: + d.text.SetText(colorizeYAML(d.app.Styles.Views().Yaml, strings.Join(lines, "\n"))) + default: + d.text.SetText(strings.Join(lines, "\n")) + } d.text.ScrollToBeginning() } diff --git a/internal/view/dir.go b/internal/view/dir.go index 699ba006e7..5d30276cd1 100644 --- a/internal/view/dir.go +++ b/internal/view/dir.go @@ -96,7 +96,7 @@ func (d *Dir) viewCmd(evt *tcell.EventKey) *tcell.EventKey { return nil } - details := NewDetails(d.App(), yamlAction, sel, true).Update(string(yaml)) + details := NewDetails(d.App(), yamlAction, sel, contentYAML, true).Update(string(yaml)) if err := d.App().inject(details, false); err != nil { d.App().Flash().Err(err) } @@ -216,7 +216,7 @@ func (d *Dir) applyCmd(evt *tcell.EventKey) *tcell.EventKey { res = "message:\n" + fmtResults(res) } - details := NewDetails(d.App(), "Applied Manifest", sel, true).Update(res) + details := NewDetails(d.App(), "Applied Manifest", sel, contentYAML, true).Update(res) if err := d.App().inject(details, false); err != nil { d.App().Flash().Err(err) } @@ -255,7 +255,7 @@ func (d *Dir) delCmd(evt *tcell.EventKey) *tcell.EventKey { } else { res = "message:\n" + fmtResults(res) } - details := NewDetails(d.App(), "Deleted Manifest", sel, true).Update(res) + details := NewDetails(d.App(), "Deleted Manifest", sel, contentYAML, true).Update(res) if err := d.App().inject(details, false); err != nil { d.App().Flash().Err(err) } diff --git a/internal/view/dp.go b/internal/view/dp.go index 8f56948711..9af1bd93bb 100644 --- a/internal/view/dp.go +++ b/internal/view/dp.go @@ -24,10 +24,12 @@ type Deploy struct { func NewDeploy(gvr client.GVR) ResourceViewer { var d Deploy d.ResourceViewer = NewPortForwardExtender( - NewRestartExtender( - NewScaleExtender( - NewImageExtender( - NewLogsExtender(NewBrowser(gvr), d.logOptions), + NewVulnerabilityExtender( + NewRestartExtender( + NewScaleExtender( + NewImageExtender( + NewLogsExtender(NewBrowser(gvr), d.logOptions), + ), ), ), ), @@ -89,20 +91,24 @@ func (d *Deploy) logOptions(prev bool) (*dao.LogOptions, error) { return &opts, nil } -func (d *Deploy) showPods(app *App, model ui.Tabular, gvr, path string) { +func (d *Deploy) showPods(app *App, model ui.Tabular, gvr, fqn string) { var ddp dao.Deployment - dp, err := ddp.GetInstance(app.factory, path) + ddp.Init(d.App().factory, d.GVR()) + + dp, err := ddp.GetInstance(fqn) if err != nil { app.Flash().Err(err) return } - showPodsFromSelector(app, path, dp.Spec.Selector) + showPodsFromSelector(app, fqn, dp.Spec.Selector) } -func (d *Deploy) dp(path string) (*appsv1.Deployment, error) { +func (d *Deploy) dp(fqn string) (*appsv1.Deployment, error) { var dp dao.Deployment - return dp.GetInstance(d.App().factory, path) + dp.Init(d.App().factory, d.GVR()) + + return dp.GetInstance(fqn) } // ---------------------------------------------------------------------------- diff --git a/internal/view/ds.go b/internal/view/ds.go index 7276e74f9e..ab92227364 100644 --- a/internal/view/ds.go +++ b/internal/view/ds.go @@ -18,9 +18,11 @@ type DaemonSet struct { func NewDaemonSet(gvr client.GVR) ResourceViewer { d := DaemonSet{ ResourceViewer: NewPortForwardExtender( - NewRestartExtender( - NewImageExtender( - NewLogsExtender(NewBrowser(gvr), nil), + NewVulnerabilityExtender( + NewRestartExtender( + NewImageExtender( + NewLogsExtender(NewBrowser(gvr), nil), + ), ), ), ), diff --git a/internal/view/img_scan.go b/internal/view/img_scan.go new file mode 100644 index 0000000000..811e1af0e8 --- /dev/null +++ b/internal/view/img_scan.go @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of K9s + +package view + +import ( + "runtime" + "strings" + + "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/render" + "github.com/derailed/k9s/internal/ui" + "github.com/derailed/tcell/v2" +) + +const ( + imgScanTitle = "Scans" + browseOSX = "open" + browseLinux = "sensible-browser" + cveGovURL = "https://nvd.nist.gov/vuln/detail/" + ghsaURL = "https://github.com/advisories/" +) + +// ImageScan represents an image vulnerability scan view. +type ImageScan struct { + ResourceViewer +} + +// NewImageScan returns a new scans view. +func NewImageScan(gvr client.GVR) ResourceViewer { + v := ImageScan{} + v.ResourceViewer = NewBrowser(gvr) + v.AddBindKeysFn(v.bindKeys) + v.GetTable().SetEnterFn(v.viewCVE) + v.GetTable().SetSortCol("SEVERITY", true) + + return &v +} + +// Name returns the component name. +func (s *ImageScan) Name() string { return imgScanTitle } + +func (c *ImageScan) bindKeys(aa ui.KeyActions) { + aa.Delete(ui.KeyShiftA, ui.KeyShiftN, tcell.KeyCtrlZ, tcell.KeyCtrlW) + + aa.Add(ui.KeyActions{ + ui.KeyShiftL: ui.NewKeyAction("Sort Lib", c.GetTable().SortColCmd("LIBRARY", false), true), + ui.KeyShiftS: ui.NewKeyAction("Sort Severity", c.GetTable().SortColCmd("SEVERITY", false), true), + ui.KeyShiftF: ui.NewKeyAction("Sort Fixed-in", c.GetTable().SortColCmd("FIXED-IN", false), true), + ui.KeyShiftV: ui.NewKeyAction("Sort Vulnerability", c.GetTable().SortColCmd("VULNERABILITY", false), true), + }) +} + +func (s *ImageScan) viewCVE(app *App, model ui.Tabular, gvr, path string) { + bin := browseLinux + if runtime.GOOS == "darwin" { + bin = browseOSX + } + + tt := strings.Split(path, "|") + if len(tt) < 7 { + app.Flash().Errf("parse path failed: %s", path) + } + cve := tt[render.CVEParseIdx] + site := cveGovURL + if strings.Index(cve, "GHSA") == 0 { + site = ghsaURL + } + site += cve + + ok, errChan := run(app, shellOpts{ + background: true, + binary: bin, + args: []string{site}, + }) + if !ok { + app.Flash().Errf("unable to run browser command") + return + } + for e := range errChan { + if e != nil { + app.Flash().Err(e) + } + } +} diff --git a/internal/view/job.go b/internal/view/job.go index 60f391b3dc..24df7d38d1 100644 --- a/internal/view/job.go +++ b/internal/view/job.go @@ -19,7 +19,7 @@ type Job struct { // NewJob returns a new viewer. func NewJob(gvr client.GVR) ResourceViewer { - j := Job{ResourceViewer: NewLogsExtender(NewBrowser(gvr), nil)} + j := Job{ResourceViewer: NewVulnerabilityExtender(NewLogsExtender(NewBrowser(gvr), nil))} j.GetTable().SetEnterFn(j.showPods) j.GetTable().SetSortCol("AGE", true) diff --git a/internal/view/live_view_test.go b/internal/view/live_view_test.go index 1df6cd43a0..92509a8912 100644 --- a/internal/view/live_view_test.go +++ b/internal/view/live_view_test.go @@ -25,7 +25,7 @@ apiVersion: v1 ` v := NewLiveView(NewApp(config.NewConfig(nil)), "fred", nil) - v.Init(context.Background()) + assert.NoError(t, v.Init(context.Background())) v.text.SetText(colorizeYAML(config.Yaml{}, s)) assert.Equal(t, s, sanitizeEsc(v.text.GetText(true))) diff --git a/internal/view/node.go b/internal/view/node.go index 0743b88fe3..c1f2274f9c 100644 --- a/internal/view/node.go +++ b/internal/view/node.go @@ -100,7 +100,7 @@ func drainNode(v ResourceViewer, path string, opts dao.DrainOptions) { v.Stop() defer v.Start() { - d := NewDetails(v.App(), "Drain Progress", path, true) + d := NewDetails(v.App(), "Drain Progress", path, contentYAML, true) if err := v.App().inject(d, false); err != nil { v.App().Flash().Err(err) } @@ -194,7 +194,7 @@ func (n *Node) yamlCmd(evt *tcell.EventKey) *tcell.EventKey { return nil } - details := NewDetails(n.App(), yamlAction, sel, true).Update(raw) + details := NewDetails(n.App(), yamlAction, sel, contentYAML, true).Update(raw) if err := n.App().inject(details, false); err != nil { n.App().Flash().Err(err) } diff --git a/internal/view/pod.go b/internal/view/pod.go index d2fd2b43e5..c317304ab9 100644 --- a/internal/view/pod.go +++ b/internal/view/pod.go @@ -45,8 +45,10 @@ type Pod struct { func NewPod(gvr client.GVR) ResourceViewer { var p Pod p.ResourceViewer = NewPortForwardExtender( - NewImageExtender( - NewLogsExtender(NewBrowser(gvr), p.logOptions), + NewVulnerabilityExtender( + NewImageExtender( + NewLogsExtender(NewBrowser(gvr), p.logOptions), + ), ), ) p.AddBindKeysFn(p.bindKeys) diff --git a/internal/view/registrar.go b/internal/view/registrar.go index b0495eca1e..52532c3633 100644 --- a/internal/view/registrar.go +++ b/internal/view/registrar.go @@ -67,6 +67,9 @@ func miscViewers(vv MetaViewers) { vv[client.NewGVR("containers")] = MetaViewer{ viewerFn: NewContainer, } + vv[client.NewGVR("scans")] = MetaViewer{ + viewerFn: NewImageScan, + } vv[client.NewGVR("portforwards")] = MetaViewer{ viewerFn: NewPortForward, } diff --git a/internal/view/rs.go b/internal/view/rs.go index 9a0e64fc9e..739ce6a9d7 100644 --- a/internal/view/rs.go +++ b/internal/view/rs.go @@ -21,7 +21,7 @@ type ReplicaSet struct { // NewReplicaSet returns a new viewer. func NewReplicaSet(gvr client.GVR) ResourceViewer { r := ReplicaSet{ - ResourceViewer: NewBrowser(gvr), + ResourceViewer: NewVulnerabilityExtender(NewBrowser(gvr)), } r.AddBindKeysFn(r.bindKeys) r.GetTable().SetEnterFn(r.showPods) diff --git a/internal/view/secret.go b/internal/view/secret.go index 73a1580513..3cc78234c9 100644 --- a/internal/view/secret.go +++ b/internal/view/secret.go @@ -69,7 +69,7 @@ func (s *Secret) decodeCmd(evt *tcell.EventKey) *tcell.EventKey { return nil } - details := NewDetails(s.App(), "Secret Decoder", path, true).Update(string(raw)) + details := NewDetails(s.App(), "Secret Decoder", path, contentYAML, true).Update(string(raw)) if err := s.App().inject(details, false); err != nil { s.App().Flash().Err(err) } diff --git a/internal/view/sts.go b/internal/view/sts.go index d8b72d7f0a..cbb77a7cd1 100644 --- a/internal/view/sts.go +++ b/internal/view/sts.go @@ -21,10 +21,12 @@ type StatefulSet struct { func NewStatefulSet(gvr client.GVR) ResourceViewer { var s StatefulSet s.ResourceViewer = NewPortForwardExtender( - NewRestartExtender( - NewScaleExtender( - NewImageExtender( - NewLogsExtender(NewBrowser(gvr), s.logOptions), + NewVulnerabilityExtender( + NewRestartExtender( + NewScaleExtender( + NewImageExtender( + NewLogsExtender(NewBrowser(gvr), s.logOptions), + ), ), ), ), diff --git a/internal/view/vul_extender.go b/internal/view/vul_extender.go new file mode 100644 index 0000000000..2bd59b93a3 --- /dev/null +++ b/internal/view/vul_extender.go @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of K9s + +package view + +import ( + "context" + + "github.com/derailed/k9s/internal" + "github.com/derailed/k9s/internal/client" + "github.com/derailed/k9s/internal/ui" + "github.com/derailed/tcell/v2" +) + +// VulnerabilityExtender adds vul image scan extensions. +type VulnerabilityExtender struct { + ResourceViewer +} + +// NewVulnerabilityExtender returns a new extender. +func NewVulnerabilityExtender(r ResourceViewer) ResourceViewer { + v := VulnerabilityExtender{ResourceViewer: r} + v.AddBindKeysFn(v.bindKeys) + + return &v +} + +func (v *VulnerabilityExtender) bindKeys(aa ui.KeyActions) { + if v.App().Config.K9s.EnableImageScan { + aa.Add(ui.KeyActions{ + ui.KeyV: ui.NewKeyAction("Show Vulnerabilities", v.showVulCmd, true), + ui.KeyShiftV: ui.NewKeyAction("Sort Vulnerabilities", v.GetTable().SortColCmd("VS", true), false), + }) + } +} + +func (v *VulnerabilityExtender) showVulCmd(evt *tcell.EventKey) *tcell.EventKey { + isv := NewImageScan(client.NewGVR("scans")) + isv.SetContextFn(v.selContext) + if err := v.App().inject(isv, false); err != nil { + v.App().Flash().Err(err) + } + + return nil +} + +func (v *VulnerabilityExtender) selContext(ctx context.Context) context.Context { + ctx = context.WithValue(ctx, internal.KeyPath, v.GetTable().GetSelectedItem()) + return context.WithValue(ctx, internal.KeyGVR, v.GVR()) +} diff --git a/internal/view/xray.go b/internal/view/xray.go index ea14e576ee..f2dfb0a8b9 100644 --- a/internal/view/xray.go +++ b/internal/view/xray.go @@ -341,7 +341,7 @@ func (x *Xray) viewCmd(evt *tcell.EventKey) *tcell.EventKey { return nil } - details := NewDetails(x.app, yamlAction, spec.Path(), true).Update(raw) + details := NewDetails(x.app, yamlAction, spec.Path(), contentYAML, true).Update(raw) if err := x.app.inject(details, false); err != nil { x.app.Flash().Err(err) } @@ -391,7 +391,7 @@ func (x *Xray) describe(gvr, path string) { return } - details := NewDetails(x.app, "Describe", path, true).Update(yaml) + details := NewDetails(x.app, "Describe", path, contentYAML, true).Update(yaml) if err := x.app.inject(details, false); err != nil { x.app.Flash().Err(err) } diff --git a/internal/vul/scan.go b/internal/vul/scan.go new file mode 100644 index 0000000000..05819c305c --- /dev/null +++ b/internal/vul/scan.go @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of K9s + +package vul + +import ( + "fmt" + "io" + "strings" + + grypeDb "github.com/anchore/grype/grype/db/v5" + "github.com/anchore/grype/grype/match" + "github.com/anchore/grype/grype/vulnerability" +) + +const ( + wontFix = "(won't fix)" + naValue = "" +) + +// Scans tracks scans per image. +type Scans map[string]*Scan + +// Dump dump reports to stdout. +func (s Scans) Dump(w io.Writer) { + for k, v := range s { + fmt.Fprintf(w, "Image: %s -- ", k) + v.Tally.Dump(w) + fmt.Fprintln(w) + v.Dump(w) + } +} + +// Scan tracks image vulnerability scan. +type Scan struct { + ID string + Table *table + Tally tally +} + +func newScan(img string) *Scan { + return &Scan{ID: img, Table: newTable()} +} + +// Dump dump report to stdout. +func (s *Scan) Dump(w io.Writer) { + s.Table.dump(w) +} + +func (s *Scan) run(mm *match.Matches, store vulnerability.MetadataProvider) error { + for m := range mm.Enumerate() { + meta, err := store.GetMetadata(m.Vulnerability.ID, m.Vulnerability.Namespace) + if err != nil { + return err + } + var severity string + if meta != nil { + severity = meta.Severity + } + fixVersion := strings.Join(m.Vulnerability.Fix.Versions, ", ") + switch m.Vulnerability.Fix.State { + case grypeDb.WontFixState: + fixVersion = wontFix + case grypeDb.UnknownFixState: + fixVersion = naValue + } + s.Table.addRow(newRow(m.Package.Name, m.Package.Version, fixVersion, string(m.Package.Type), m.Vulnerability.ID, severity)) + } + s.Table.dedup() + s.Tally = newTally(s.Table) + + return nil +} + +func colorize(rr []string) []string { + crr := make([]string, len(rr)) + copy(crr, rr) + + crr[len(crr)-1] = sevColor(crr[len(crr)-1]) + return crr +} diff --git a/internal/vul/scanner.go b/internal/vul/scanner.go new file mode 100644 index 0000000000..003809dc5b --- /dev/null +++ b/internal/vul/scanner.go @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of K9s + +package vul + +import ( + "errors" + "fmt" + "sync" + "time" + + "github.com/rs/zerolog/log" + + "github.com/anchore/clio" + "github.com/anchore/grype/cmd/grype/cli/options" + "github.com/anchore/grype/grype" + "github.com/anchore/grype/grype/db" + "github.com/anchore/grype/grype/matcher" + "github.com/anchore/grype/grype/matcher/dotnet" + "github.com/anchore/grype/grype/matcher/golang" + "github.com/anchore/grype/grype/matcher/java" + "github.com/anchore/grype/grype/matcher/javascript" + "github.com/anchore/grype/grype/matcher/python" + "github.com/anchore/grype/grype/matcher/ruby" + "github.com/anchore/grype/grype/matcher/stock" + "github.com/anchore/grype/grype/pkg" + "github.com/anchore/grype/grype/store" + "github.com/anchore/grype/grype/vex" +) + +var ImgScanner *imageScanner + +type imageScanner struct { + store *store.Store + dbCloser *db.Closer + dbStatus *db.Status + opts *options.Grype + scans Scans + mx sync.RWMutex + initialized bool +} + +// NewImageScanner returns a new instance. +func NewImageScanner() *imageScanner { + return &imageScanner{ + scans: make(Scans), + } +} + +// GetScan fetch scan for a given image. Returns ok=false when not found. +func (s *imageScanner) GetScan(img string) (*Scan, bool) { + s.mx.RLock() + defer s.mx.RUnlock() + scan, ok := s.scans[img] + + return scan, ok +} + +func (s *imageScanner) SetScan(img string, sc *Scan) { + s.mx.Lock() + defer s.mx.Unlock() + s.scans[img] = sc +} + +// Init initializes image vulnerability database. +func (s *imageScanner) Init(name, version string) { + s.mx.Lock() + defer s.mx.Unlock() + + id := clio.Identification{Name: name, Version: version} + s.opts = options.DefaultGrype(id) + s.opts.GenerateMissingCPEs = true + + var err error + s.store, s.dbStatus, s.dbCloser, err = grype.LoadVulnerabilityDB( + s.opts.DB.ToCuratorConfig(), + s.opts.DB.AutoUpdate, + ) + if err != nil { + log.Error().Err(err).Msgf("VulDb load failed") + return + } + + if err := validateDBLoad(err, s.dbStatus); err != nil { + log.Error().Err(err).Msgf("VulDb validate failed") + return + } + + s.initialized = true +} + +// Stop closes scan database. +func (s *imageScanner) Stop() { + s.mx.RLock() + defer s.mx.RUnlock() + + if s.dbCloser != nil { + s.dbCloser.Close() + } +} + +func (s *imageScanner) Score(ii ...string) string { + var sc scorer + for _, i := range ii { + if scan, ok := s.GetScan(i); ok { + sc = sc.Add(newScorer(scan.Tally)) + } + } + + return sc.String() +} + +func (s *imageScanner) isInitialized() bool { + s.mx.RLock() + defer s.mx.RUnlock() + + return s.initialized +} + +func (s *imageScanner) Enqueue(images ...string) { + if !s.isInitialized() { + return + } + for _, i := range images { + go func(img string) { + if _, ok := s.GetScan(img); ok { + return + } + sc := newScan(img) + s.SetScan(img, sc) + if err := s.scan(img, sc); err != nil { + log.Warn().Err(err).Msgf("Scan failed for img %s --", img) + } + }(i) + } +} + +func (s *imageScanner) scan(img string, sc *Scan) error { + defer func(t time.Time) { + log.Debug().Msgf("Scan %s images: %v", img, time.Since(t)) + }(time.Now()) + + var errs error + packages, pkgContext, _, err := pkg.Provide(img, getProviderConfig(s.opts)) + if err != nil { + errs = errors.Join(errs, fmt.Errorf("failed to catalog %s: %w", img, err)) + } + + v := grype.VulnerabilityMatcher{ + Store: *s.store, + IgnoreRules: s.opts.Ignore, + NormalizeByCVE: s.opts.ByCVE, + FailSeverity: s.opts.FailOnServerity(), + Matchers: getMatchers(s.opts), + VexProcessor: vex.NewProcessor(vex.ProcessorOptions{ + Documents: s.opts.VexDocuments, + IgnoreRules: s.opts.Ignore, + }), + } + + mm, _, err := v.FindMatches(packages, pkgContext) + if err != nil { + errs = errors.Join(errs, err) + } + if err := sc.run(mm, s.store); err != nil { + errs = errors.Join(errs, err) + } + + return errs +} + +func getProviderConfig(opts *options.Grype) pkg.ProviderConfig { + return pkg.ProviderConfig{ + SyftProviderConfig: pkg.SyftProviderConfig{ + RegistryOptions: opts.Registry.ToOptions(), + Exclusions: opts.Exclusions, + CatalogingOptions: opts.Search.ToConfig(), + Platform: opts.Platform, + Name: opts.Name, + DefaultImagePullSource: opts.DefaultImagePullSource, + }, + SynthesisConfig: pkg.SynthesisConfig{ + GenerateMissingCPEs: opts.GenerateMissingCPEs, + }, + } +} + +func getMatchers(opts *options.Grype) []matcher.Matcher { + return matcher.NewDefaultMatchers( + matcher.Config{ + Java: java.MatcherConfig{ + ExternalSearchConfig: opts.ExternalSources.ToJavaMatcherConfig(), + UseCPEs: opts.Match.Java.UseCPEs, + }, + Ruby: ruby.MatcherConfig(opts.Match.Ruby), + Python: python.MatcherConfig(opts.Match.Python), + Dotnet: dotnet.MatcherConfig(opts.Match.Dotnet), + Javascript: javascript.MatcherConfig(opts.Match.Javascript), + Golang: golang.MatcherConfig{ + UseCPEs: opts.Match.Golang.UseCPEs, + AlwaysUseCPEForStdlib: opts.Match.Golang.AlwaysUseCPEForStdlib, + }, + Stock: stock.MatcherConfig(opts.Match.Stock), + }, + ) +} + +func validateDBLoad(loadErr error, status *db.Status) error { + if loadErr != nil { + return fmt.Errorf("failed to load vulnerability db: %w", loadErr) + } + if status == nil { + return fmt.Errorf("unable to determine the status of the vulnerability db") + } + if status.Err != nil { + return fmt.Errorf("db could not be loaded: %w", status.Err) + } + + return nil +} diff --git a/internal/vul/scorer.go b/internal/vul/scorer.go new file mode 100644 index 0000000000..30e949a8d9 --- /dev/null +++ b/internal/vul/scorer.go @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of K9s + +package vul + +import "fmt" + +type scorer uint8 + +func (b scorer) String() string { + return fmt.Sprintf("%08b", b)[:6] +} + +func newScorer(t tally) scorer { + return fromTally(t) +} + +func (b scorer) Add(b1 scorer) scorer { + return b | b1 +} + +func fromTally(t tally) scorer { + var b scorer + for i, v := range t { + if v == 0 { + continue + } + switch i { + case sevCritical: + b |= 0x80 + case sevHigh: + b |= 0x40 + case sevMedium: + b |= 0x20 + case sevLow: + b |= 0x10 + case sevNegligible: + b |= 0x08 + case sevUnknown: + b |= 0x04 + } + } + + return b +} diff --git a/internal/vul/scorer_test.go b/internal/vul/scorer_test.go new file mode 100644 index 0000000000..ac6304cc7c --- /dev/null +++ b/internal/vul/scorer_test.go @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of K9s + +package vul + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_scorerAdd(t *testing.T) { + uu := map[string]struct { + b, b1, e scorer + }{ + "zero": {}, + "same": { + b: scorer(0x80), + b1: scorer(0x80), + e: scorer(0x80), + }, + "c+h": { + b: scorer(0x80), + b1: scorer(0x40), + e: scorer(0xC0), + }, + "ch+hm": { + b: scorer(0xc0), + b1: scorer(0xa0), + e: scorer(0xe0), + }, + } + + for k := range uu { + u := uu[k] + t.Run(k, func(t *testing.T) { + assert.Equal(t, u.e, u.b.Add(u.b1)) + }) + } +} + +func Test_scorerFromTally(t *testing.T) { + uu := map[string]struct { + tt tally + b scorer + }{ + "zero": {}, + "critical": { + tt: tally{29, 0, 0, 0, 0, 0, 0}, + b: scorer(0x80), + }, + "high": { + tt: tally{0, 17, 0, 0, 0, 0, 0}, + b: scorer(0x40), + }, + "medium": { + tt: tally{0, 0, 5, 0, 0, 0, 0}, + b: scorer(0x20), + }, + "low": { + tt: tally{0, 0, 0, 10, 0, 0, 0}, + b: scorer(0x10), + }, + "negligible": { + tt: tally{0, 0, 0, 0, 10, 0, 0}, + b: scorer(0x08), + }, + "unknown": { + tt: tally{0, 0, 0, 0, 0, 10, 0}, + b: scorer(0x04), + }, + "c/h": { + tt: tally{10, 20, 0, 0, 0, 0, 0}, + b: scorer(0xC0), + }, + "c/m": { + tt: tally{10, 0, 20, 0, 0, 0, 0}, + b: scorer(0xA0), + }, + "c/h/l": { + tt: tally{10, 1, 20, 0, 0, 0, 0}, + b: scorer(0xE0), + }, + "n/u": { + tt: tally{0, 0, 0, 0, 10, 20, 0}, + b: scorer(0x0C), + }, + } + + for k := range uu { + u := uu[k] + t.Run(k, func(t *testing.T) { + assert.Equal(t, u.b, newScorer(u.tt)) + }) + } +} diff --git a/internal/vul/table.go b/internal/vul/table.go new file mode 100644 index 0000000000..6b3dbf4e5e --- /dev/null +++ b/internal/vul/table.go @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of K9s + +package vul + +import ( + "fmt" + "io" + "sort" + "strings" + + "github.com/olekukonko/tablewriter" +) + +const ( + nameIdx = iota + verIdx + fixIdx + typeIdx + vulIdx + sevIdx +) + +type Row []string + +func newRow(ss ...string) Row { + r := make(Row, 0, len(ss)) + for i, s := range ss { + if i == sevIdx { + s = toSev(s) + } + r = append(r, s) + } + return r +} + +func toSev(s string) string { + switch s { + case "Critical": + return Sev1 + case "High": + return Sev2 + case "Medium": + return Sev3 + case "Low": + return Sev4 + case "Negligible": + return Sev5 + default: + return SevU + } +} + +func (r Row) Name() string { return r[nameIdx] } +func (r Row) Version() string { return r[verIdx] } +func (r Row) Fix() string { return r[fixIdx] } +func (r Row) Type() string { return r[typeIdx] } +func (r Row) Vulnerability() string { return r[vulIdx] } +func (r Row) Severity() string { return r[sevIdx] } + +func sevColor(s string) string { + switch strings.ToLower(s) { + case "critical": + return fmt.Sprintf("[red::b]%s[-::-]", s) + case "high": + return fmt.Sprintf("[orange::b]%s[-::-]", s) + case "medium": + return fmt.Sprintf("[yellow::b]%s[-::-]", s) + case "low": + return fmt.Sprintf("[blue::b]%s[-::-]", s) + default: + return fmt.Sprintf("[gray::b]%s[-::-]", s) + } +} + +type table struct { + Rows []Row +} + +func newTable() *table { + return &table{} +} + +func (t *table) dedup() { + var ( + seen = make(map[string]struct{}, len(t.Rows)) + rr = make([]Row, 0, len(t.Rows)) + ) + for _, v := range t.Rows { + key := strings.Join(v, "|") + if _, ok := seen[key]; ok { + continue + } + rr, seen[key] = append(rr, v), struct{}{} + } + t.Rows = rr +} + +func (t *table) addRow(r Row) { + t.Rows = append(t.Rows, r) +} + +func (t *table) dump(w io.Writer) { + columns := []string{"Name", "Installed", "Fixed-In", "Type", "Vulnerability", "Severity"} + + table := tablewriter.NewWriter(w) + table.SetHeader(columns) + table.SetAutoWrapText(false) + table.SetHeaderAlignment(tablewriter.ALIGN_LEFT) + table.SetAlignment(tablewriter.ALIGN_LEFT) + + table.SetHeaderLine(false) + table.SetBorder(false) + table.SetAutoFormatHeaders(true) + table.SetCenterSeparator("") + table.SetColumnSeparator("") + table.SetRowSeparator("") + table.SetTablePadding(" ") + table.SetNoWhiteSpace(true) + + for _, row := range t.Rows { + table.Append(colorize(row)) + } + table.Render() +} + +func (t *table) sort() { + t.dedup() + + sort.SliceStable(t.Rows, func(i, j int) bool { + if t.Rows[i][nameIdx] != t.Rows[j][nameIdx] { + return t.Rows[i][nameIdx] < t.Rows[j][nameIdx] + } + if t.Rows[i][verIdx] != t.Rows[j][verIdx] { + return t.Rows[i][verIdx] < t.Rows[j][verIdx] + } + if t.Rows[i][typeIdx] != t.Rows[j][typeIdx] { + return t.Rows[i][typeIdx] < t.Rows[j][typeIdx] + } + + if t.Rows[i][sevIdx] == t.Rows[j][sevIdx] { + return t.Rows[i][vulIdx] < t.Rows[j][vulIdx] + } + return sevToScore(t.Rows[i][sevIdx]) < sevToScore(t.Rows[j][sevIdx]) + }) +} + +func (t *table) sortSev() { + t.dedup() + + sort.SliceStable(t.Rows, func(i, j int) bool { + if s1, s2 := sevToScore(t.Rows[i][sevIdx]), sevToScore(t.Rows[j][sevIdx]); s1 != s2 { + return s1 < s2 + } + if t.Rows[i][nameIdx] != t.Rows[j][nameIdx] { + return t.Rows[i][nameIdx] < t.Rows[j][nameIdx] + } + if t.Rows[i][verIdx] != t.Rows[j][verIdx] { + return t.Rows[i][verIdx] < t.Rows[j][verIdx] + } + if t.Rows[i][typeIdx] != t.Rows[j][typeIdx] { + return t.Rows[i][typeIdx] < t.Rows[j][typeIdx] + } + + return t.Rows[i][vulIdx] < t.Rows[j][vulIdx] + }) +} + +func sevToScore(s string) int { + switch s { + case Sev1: + return 1 + case Sev2: + return 2 + case Sev3: + return 3 + case Sev4: + return 4 + case Sev5: + return 5 + default: + return 6 + } +} diff --git a/internal/vul/table_test.go b/internal/vul/table_test.go new file mode 100644 index 0000000000..b8e5b2f8e6 --- /dev/null +++ b/internal/vul/table_test.go @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of K9s + +package vul + +import ( + "bufio" + "os" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_sort(t *testing.T) { + uu := map[string]struct { + t1, t2 *table + }{ + "simple": { + t1: makeTable(t, "testdata/sort/no_dups/sc1.text"), + t2: makeTable(t, "testdata/sort/no_dups/sc2.text"), + }, + "dups": { + t1: makeTable(t, "testdata/sort/dups/sc1.text"), + t2: makeTable(t, "testdata/sort/dups/sc2.text"), + }, + "full": { + t1: makeTable(t, "testdata/sort/full/sc1.text"), + t2: makeTable(t, "testdata/sort/full/sc2.text"), + }, + } + + for k := range uu { + u := uu[k] + t.Run(k, func(t *testing.T) { + u.t1.sort() + assert.Equal(t, u.t2, u.t1) + }) + } +} + +func Test_sortSev(t *testing.T) { + uu := map[string]struct { + t1, t2 *table + }{ + "simple": { + t1: makeTable(t, "testdata/sort_sev/no_dups/sc1.text"), + t2: makeTable(t, "testdata/sort_sev/no_dups/sc2.text"), + }, + "dups": { + t1: makeTable(t, "testdata/sort_sev/dups/sc1.text"), + t2: makeTable(t, "testdata/sort_sev/dups/sc2.text"), + }, + "full": { + t1: makeTable(t, "testdata/sort_sev/full/sc1.text"), + t2: makeTable(t, "testdata/sort_sev/full/sc2.text"), + }, + } + + for k := range uu { + u := uu[k] + t.Run(k, func(t *testing.T) { + u.t1.sortSev() + assert.Equal(t, u.t2, u.t1) + }) + } +} + +// Helpers... + +func makeTable(t *testing.T, path string) *table { + f, err := os.Open(path) + defer func() { + _ = f.Close() + }() + assert.NoError(t, err) + sc := bufio.NewScanner(f) + var tt table + for sc.Scan() { + ff := strings.Fields(sc.Text()) + tt.addRow(newRow(ff...)) + } + assert.NoError(t, sc.Err()) + + return &tt +} diff --git a/internal/vul/tally.go b/internal/vul/tally.go new file mode 100644 index 0000000000..a7ca25e8ed --- /dev/null +++ b/internal/vul/tally.go @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of K9s + +package vul + +import ( + "fmt" + "io" +) + +const ( + sevCritical = iota + sevHigh + sevMedium + sevLow + sevNegligible + sevUnknown + sevFixed +) + +var vulWeights = []int{10_000, 100, 100, 10, 0, 0, 0, 0} + +type tally [7]int + +func newTally(t *table) tally { + var tt tally + for _, r := range t.Rows { + if r.Fix() != "" { + tt[sevFixed]++ + } + switch r.Severity() { + case Sev1: + tt[sevCritical]++ + case Sev2: + tt[sevHigh]++ + case Sev3: + tt[sevMedium]++ + case Sev4: + tt[sevLow]++ + case Sev5: + tt[sevNegligible]++ + case SevU: + tt[sevUnknown]++ + } + } + + return tt +} + +// Dump dumps tally as text. +func (t tally) Dump(w io.Writer) { + fmt.Fprintf(w, "%d critical, %d high, %d medium, %d low, %d negligible", + t[sevCritical], + t[sevHigh], + t[sevMedium], + t[sevLow], + t[sevNegligible], + ) + if t[sevUnknown] > 0 { + fmt.Fprintf(w, " (%d unknown)", t[sevUnknown]) + } + if t[sevFixed] > 0 { + fmt.Fprintf(w, " -- [Fixed: %d]", t[sevFixed]) + } +} + +func (t *tally) score() int { + var s int + for i, v := range t[:5] { + s += v * vulWeights[i] + } + + return s +} diff --git a/internal/vul/tally_test.go b/internal/vul/tally_test.go new file mode 100644 index 0000000000..3179ca0b51 --- /dev/null +++ b/internal/vul/tally_test.go @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of K9s + +package vul + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_newTally(t *testing.T) { + uu := map[string]struct { + t *table + tt tally + }{ + "full": { + t: makeTable(t, "testdata/sort/full/sc2.text"), + tt: tally{7, 14, 8, 0, 0, 0, 29}, + }, + } + + for k := range uu { + u := uu[k] + t.Run(k, func(t *testing.T) { + assert.Equal(t, u.tt, newTally(u.t)) + }) + } +} + +func Test_score(t *testing.T) { + uu := map[string]struct { + tt tally + sc int + }{ + "zero": {}, + "critical": { + tt: tally{29, 7, 14, 8, 0, 0, 0}, + sc: 292180, + }, + "high": { + tt: tally{0, 17, 14, 8, 0, 0, 0}, + sc: 3180, + }, + "medium": { + tt: tally{0, 0, 14, 0, 0, 0, 0}, + sc: 1400, + }, + } + + for k := range uu { + u := uu[k] + t.Run(k, func(t *testing.T) { + assert.Equal(t, u.sc, u.tt.score()) + }) + } +} diff --git a/internal/vul/testdata/sort/dups/sc1.text b/internal/vul/testdata/sort/dups/sc1.text new file mode 100644 index 0000000000..600a7a17e0 --- /dev/null +++ b/internal/vul/testdata/sort/dups/sc1.text @@ -0,0 +1,9 @@ +busybox 1.34.1 n/a binary CVE-2022-48174 Critical +busybox 1.34.1 n/a binary CVE-2022-28391 High +golang.org/x/net v0.4.0 0.17.0 go-module GHSA-4374-p667-p6c8 High +golang.org/x/net v0.4.0 0.7.0 go-module GHSA-vvpx-j8f3-3w6h High +golang.org/x/net v0.4.0 0.7.0 go-module GHSA-vvpx-j8f3-3w6h High +golang.org/x/net v0.4.0 0.17.0 go-module GHSA-qppj-fm5r-hxr3 Medium +golang.org/x/net v0.4.0 0.13.0 go-module GHSA-2wrh-6pvc-2jm9 Medium +golang.org/x/net v0.4.0 0.13.0 go-module GHSA-2wrh-6pvc-2jm9 Medium +golang.org/x/net v0.4.0 0.17.0 go-module GHSA-qppj-fm5r-hxr3 Medium \ No newline at end of file diff --git a/internal/vul/testdata/sort/dups/sc2.text b/internal/vul/testdata/sort/dups/sc2.text new file mode 100644 index 0000000000..38df5858cf --- /dev/null +++ b/internal/vul/testdata/sort/dups/sc2.text @@ -0,0 +1,6 @@ +busybox 1.34.1 n/a binary CVE-2022-48174 Critical +busybox 1.34.1 n/a binary CVE-2022-28391 High +golang.org/x/net v0.4.0 0.17.0 go-module GHSA-4374-p667-p6c8 High +golang.org/x/net v0.4.0 0.7.0 go-module GHSA-vvpx-j8f3-3w6h High +golang.org/x/net v0.4.0 0.13.0 go-module GHSA-2wrh-6pvc-2jm9 Medium +golang.org/x/net v0.4.0 0.17.0 go-module GHSA-qppj-fm5r-hxr3 Medium \ No newline at end of file diff --git a/internal/vul/testdata/sort/full/sc1.text b/internal/vul/testdata/sort/full/sc1.text new file mode 100644 index 0000000000..75ef53c497 --- /dev/null +++ b/internal/vul/testdata/sort/full/sc1.text @@ -0,0 +1,56 @@ +busybox 1.34.1 n/a binary CVE-2022-48174 Critical +busybox 1.34.1 n/a binary CVE-2022-28391 High +github.com/prometheus/alertmanager v0.25.0 0.25.1 go-module GHSA-v86x-5fm3-5p7j Medium +github.com/prometheus/alertmanager v0.25.0 0.25.1 go-module GHSA-v86x-5fm3-5p7j Medium +golang.org/x/net v0.4.0 0.7.0 go-module GHSA-vvpx-j8f3-3w6h High +golang.org/x/net v0.4.0 0.7.0 go-module GHSA-vvpx-j8f3-3w6h High +golang.org/x/net v0.4.0 0.17.0 go-module GHSA-4374-p667-p6c8 High +golang.org/x/net v0.4.0 0.17.0 go-module GHSA-4374-p667-p6c8 High +golang.org/x/net v0.4.0 0.17.0 go-module GHSA-qppj-fm5r-hxr3 Medium +golang.org/x/net v0.4.0 0.17.0 go-module GHSA-qppj-fm5r-hxr3 Medium +golang.org/x/net v0.4.0 0.13.0 go-module GHSA-2wrh-6pvc-2jm9 Medium +golang.org/x/net v0.4.0 0.13.0 go-module GHSA-2wrh-6pvc-2jm9 Medium +stdlib go1.19.4 n/a go-module CVE-2023-29404 Critical +stdlib go1.19.4 n/a go-module CVE-2023-39323 Critical +stdlib go1.19.4 n/a go-module CVE-2023-24538 Critical +stdlib go1.19.4 n/a go-module CVE-2023-29405 Critical +stdlib go1.19.4 n/a go-module CVE-2023-24540 Critical +stdlib go1.19.4 n/a go-module CVE-2023-29405 Critical +stdlib go1.19.4 n/a go-module CVE-2023-24540 Critical +stdlib go1.19.4 n/a go-module CVE-2023-24538 Critical +stdlib go1.19.4 n/a go-module CVE-2023-29402 Critical +stdlib go1.19.4 n/a go-module CVE-2023-29402 Critical +stdlib go1.19.4 n/a go-module CVE-2023-29404 Critical +stdlib go1.19.4 n/a go-module CVE-2023-39323 Critical +stdlib go1.19.4 n/a go-module CVE-2022-41724 High +stdlib go1.19.4 n/a go-module CVE-2022-41725 High +stdlib go1.19.4 n/a go-module CVE-2023-24534 High +stdlib go1.19.4 n/a go-module CVE-2023-29400 High +stdlib go1.19.4 n/a go-module CVE-2023-24539 High +stdlib go1.19.4 n/a go-module CVE-2023-29403 High +stdlib go1.19.4 n/a go-module CVE-2023-44487 High +stdlib go1.19.4 n/a go-module CVE-2022-41722 High +stdlib go1.19.4 n/a go-module CVE-2022-41724 High +stdlib go1.19.4 n/a go-module CVE-2022-41723 High +stdlib go1.19.4 n/a go-module CVE-2023-24534 High +stdlib go1.19.4 n/a go-module CVE-2022-41725 High +stdlib go1.19.4 n/a go-module CVE-2023-24536 High +stdlib go1.19.4 n/a go-module CVE-2023-24537 High +stdlib go1.19.4 n/a go-module CVE-2023-24537 High +stdlib go1.19.4 n/a go-module CVE-2022-41723 High +stdlib go1.19.4 n/a go-module CVE-2023-24536 High +stdlib go1.19.4 n/a go-module CVE-2023-29403 High +stdlib go1.19.4 n/a go-module CVE-2023-29400 High +stdlib go1.19.4 n/a go-module CVE-2022-41722 High +stdlib go1.19.4 n/a go-module CVE-2023-24539 High +stdlib go1.19.4 n/a go-module CVE-2023-44487 High +stdlib go1.19.4 n/a go-module CVE-2023-29406 Medium +stdlib go1.19.4 n/a go-module CVE-2023-29409 Medium +stdlib go1.19.4 n/a go-module CVE-2023-29409 Medium +stdlib go1.19.4 n/a go-module CVE-2023-24532 Medium +stdlib go1.19.4 n/a go-module CVE-2023-39319 Medium +stdlib go1.19.4 n/a go-module CVE-2023-24532 Medium +stdlib go1.19.4 n/a go-module CVE-2023-29406 Medium +stdlib go1.19.4 n/a go-module CVE-2023-39318 Medium +stdlib go1.19.4 n/a go-module CVE-2023-39319 Medium +stdlib go1.19.4 n/a go-module CVE-2023-39318 Medium \ No newline at end of file diff --git a/internal/vul/testdata/sort/full/sc2.text b/internal/vul/testdata/sort/full/sc2.text new file mode 100644 index 0000000000..74ffd85abd --- /dev/null +++ b/internal/vul/testdata/sort/full/sc2.text @@ -0,0 +1,29 @@ +busybox 1.34.1 n/a binary CVE-2022-48174 Critical +busybox 1.34.1 n/a binary CVE-2022-28391 High +github.com/prometheus/alertmanager v0.25.0 0.25.1 go-module GHSA-v86x-5fm3-5p7j Medium +golang.org/x/net v0.4.0 0.17.0 go-module GHSA-4374-p667-p6c8 High +golang.org/x/net v0.4.0 0.7.0 go-module GHSA-vvpx-j8f3-3w6h High +golang.org/x/net v0.4.0 0.13.0 go-module GHSA-2wrh-6pvc-2jm9 Medium +golang.org/x/net v0.4.0 0.17.0 go-module GHSA-qppj-fm5r-hxr3 Medium +stdlib go1.19.4 n/a go-module CVE-2023-24538 Critical +stdlib go1.19.4 n/a go-module CVE-2023-24540 Critical +stdlib go1.19.4 n/a go-module CVE-2023-29402 Critical +stdlib go1.19.4 n/a go-module CVE-2023-29404 Critical +stdlib go1.19.4 n/a go-module CVE-2023-29405 Critical +stdlib go1.19.4 n/a go-module CVE-2023-39323 Critical +stdlib go1.19.4 n/a go-module CVE-2022-41722 High +stdlib go1.19.4 n/a go-module CVE-2022-41723 High +stdlib go1.19.4 n/a go-module CVE-2022-41724 High +stdlib go1.19.4 n/a go-module CVE-2022-41725 High +stdlib go1.19.4 n/a go-module CVE-2023-24534 High +stdlib go1.19.4 n/a go-module CVE-2023-24536 High +stdlib go1.19.4 n/a go-module CVE-2023-24537 High +stdlib go1.19.4 n/a go-module CVE-2023-24539 High +stdlib go1.19.4 n/a go-module CVE-2023-29400 High +stdlib go1.19.4 n/a go-module CVE-2023-29403 High +stdlib go1.19.4 n/a go-module CVE-2023-44487 High +stdlib go1.19.4 n/a go-module CVE-2023-24532 Medium +stdlib go1.19.4 n/a go-module CVE-2023-29406 Medium +stdlib go1.19.4 n/a go-module CVE-2023-29409 Medium +stdlib go1.19.4 n/a go-module CVE-2023-39318 Medium +stdlib go1.19.4 n/a go-module CVE-2023-39319 Medium \ No newline at end of file diff --git a/internal/vul/testdata/sort/no_dups/sc1.text b/internal/vul/testdata/sort/no_dups/sc1.text new file mode 100644 index 0000000000..6190c71713 --- /dev/null +++ b/internal/vul/testdata/sort/no_dups/sc1.text @@ -0,0 +1,2 @@ +busybox 1.34.1 n/a binary CVE-2022-48174 Critical +busybox 1.34.1 n/a binary CVE-2022-28391 High \ No newline at end of file diff --git a/internal/vul/testdata/sort/no_dups/sc2.text b/internal/vul/testdata/sort/no_dups/sc2.text new file mode 100644 index 0000000000..f9f06da82c --- /dev/null +++ b/internal/vul/testdata/sort/no_dups/sc2.text @@ -0,0 +1,2 @@ +busybox 1.34.1 n/a binary CVE-2022-48174 Critical +busybox 1.34.1 n/a binary CVE-2022-28391 High \ No newline at end of file diff --git a/internal/vul/testdata/sort_sev/dups/sc1.text b/internal/vul/testdata/sort_sev/dups/sc1.text new file mode 100644 index 0000000000..600a7a17e0 --- /dev/null +++ b/internal/vul/testdata/sort_sev/dups/sc1.text @@ -0,0 +1,9 @@ +busybox 1.34.1 n/a binary CVE-2022-48174 Critical +busybox 1.34.1 n/a binary CVE-2022-28391 High +golang.org/x/net v0.4.0 0.17.0 go-module GHSA-4374-p667-p6c8 High +golang.org/x/net v0.4.0 0.7.0 go-module GHSA-vvpx-j8f3-3w6h High +golang.org/x/net v0.4.0 0.7.0 go-module GHSA-vvpx-j8f3-3w6h High +golang.org/x/net v0.4.0 0.17.0 go-module GHSA-qppj-fm5r-hxr3 Medium +golang.org/x/net v0.4.0 0.13.0 go-module GHSA-2wrh-6pvc-2jm9 Medium +golang.org/x/net v0.4.0 0.13.0 go-module GHSA-2wrh-6pvc-2jm9 Medium +golang.org/x/net v0.4.0 0.17.0 go-module GHSA-qppj-fm5r-hxr3 Medium \ No newline at end of file diff --git a/internal/vul/testdata/sort_sev/dups/sc2.text b/internal/vul/testdata/sort_sev/dups/sc2.text new file mode 100644 index 0000000000..38df5858cf --- /dev/null +++ b/internal/vul/testdata/sort_sev/dups/sc2.text @@ -0,0 +1,6 @@ +busybox 1.34.1 n/a binary CVE-2022-48174 Critical +busybox 1.34.1 n/a binary CVE-2022-28391 High +golang.org/x/net v0.4.0 0.17.0 go-module GHSA-4374-p667-p6c8 High +golang.org/x/net v0.4.0 0.7.0 go-module GHSA-vvpx-j8f3-3w6h High +golang.org/x/net v0.4.0 0.13.0 go-module GHSA-2wrh-6pvc-2jm9 Medium +golang.org/x/net v0.4.0 0.17.0 go-module GHSA-qppj-fm5r-hxr3 Medium \ No newline at end of file diff --git a/internal/vul/testdata/sort_sev/full/sc1.text b/internal/vul/testdata/sort_sev/full/sc1.text new file mode 100644 index 0000000000..75ef53c497 --- /dev/null +++ b/internal/vul/testdata/sort_sev/full/sc1.text @@ -0,0 +1,56 @@ +busybox 1.34.1 n/a binary CVE-2022-48174 Critical +busybox 1.34.1 n/a binary CVE-2022-28391 High +github.com/prometheus/alertmanager v0.25.0 0.25.1 go-module GHSA-v86x-5fm3-5p7j Medium +github.com/prometheus/alertmanager v0.25.0 0.25.1 go-module GHSA-v86x-5fm3-5p7j Medium +golang.org/x/net v0.4.0 0.7.0 go-module GHSA-vvpx-j8f3-3w6h High +golang.org/x/net v0.4.0 0.7.0 go-module GHSA-vvpx-j8f3-3w6h High +golang.org/x/net v0.4.0 0.17.0 go-module GHSA-4374-p667-p6c8 High +golang.org/x/net v0.4.0 0.17.0 go-module GHSA-4374-p667-p6c8 High +golang.org/x/net v0.4.0 0.17.0 go-module GHSA-qppj-fm5r-hxr3 Medium +golang.org/x/net v0.4.0 0.17.0 go-module GHSA-qppj-fm5r-hxr3 Medium +golang.org/x/net v0.4.0 0.13.0 go-module GHSA-2wrh-6pvc-2jm9 Medium +golang.org/x/net v0.4.0 0.13.0 go-module GHSA-2wrh-6pvc-2jm9 Medium +stdlib go1.19.4 n/a go-module CVE-2023-29404 Critical +stdlib go1.19.4 n/a go-module CVE-2023-39323 Critical +stdlib go1.19.4 n/a go-module CVE-2023-24538 Critical +stdlib go1.19.4 n/a go-module CVE-2023-29405 Critical +stdlib go1.19.4 n/a go-module CVE-2023-24540 Critical +stdlib go1.19.4 n/a go-module CVE-2023-29405 Critical +stdlib go1.19.4 n/a go-module CVE-2023-24540 Critical +stdlib go1.19.4 n/a go-module CVE-2023-24538 Critical +stdlib go1.19.4 n/a go-module CVE-2023-29402 Critical +stdlib go1.19.4 n/a go-module CVE-2023-29402 Critical +stdlib go1.19.4 n/a go-module CVE-2023-29404 Critical +stdlib go1.19.4 n/a go-module CVE-2023-39323 Critical +stdlib go1.19.4 n/a go-module CVE-2022-41724 High +stdlib go1.19.4 n/a go-module CVE-2022-41725 High +stdlib go1.19.4 n/a go-module CVE-2023-24534 High +stdlib go1.19.4 n/a go-module CVE-2023-29400 High +stdlib go1.19.4 n/a go-module CVE-2023-24539 High +stdlib go1.19.4 n/a go-module CVE-2023-29403 High +stdlib go1.19.4 n/a go-module CVE-2023-44487 High +stdlib go1.19.4 n/a go-module CVE-2022-41722 High +stdlib go1.19.4 n/a go-module CVE-2022-41724 High +stdlib go1.19.4 n/a go-module CVE-2022-41723 High +stdlib go1.19.4 n/a go-module CVE-2023-24534 High +stdlib go1.19.4 n/a go-module CVE-2022-41725 High +stdlib go1.19.4 n/a go-module CVE-2023-24536 High +stdlib go1.19.4 n/a go-module CVE-2023-24537 High +stdlib go1.19.4 n/a go-module CVE-2023-24537 High +stdlib go1.19.4 n/a go-module CVE-2022-41723 High +stdlib go1.19.4 n/a go-module CVE-2023-24536 High +stdlib go1.19.4 n/a go-module CVE-2023-29403 High +stdlib go1.19.4 n/a go-module CVE-2023-29400 High +stdlib go1.19.4 n/a go-module CVE-2022-41722 High +stdlib go1.19.4 n/a go-module CVE-2023-24539 High +stdlib go1.19.4 n/a go-module CVE-2023-44487 High +stdlib go1.19.4 n/a go-module CVE-2023-29406 Medium +stdlib go1.19.4 n/a go-module CVE-2023-29409 Medium +stdlib go1.19.4 n/a go-module CVE-2023-29409 Medium +stdlib go1.19.4 n/a go-module CVE-2023-24532 Medium +stdlib go1.19.4 n/a go-module CVE-2023-39319 Medium +stdlib go1.19.4 n/a go-module CVE-2023-24532 Medium +stdlib go1.19.4 n/a go-module CVE-2023-29406 Medium +stdlib go1.19.4 n/a go-module CVE-2023-39318 Medium +stdlib go1.19.4 n/a go-module CVE-2023-39319 Medium +stdlib go1.19.4 n/a go-module CVE-2023-39318 Medium \ No newline at end of file diff --git a/internal/vul/testdata/sort_sev/full/sc2.text b/internal/vul/testdata/sort_sev/full/sc2.text new file mode 100644 index 0000000000..4e513f4cdc --- /dev/null +++ b/internal/vul/testdata/sort_sev/full/sc2.text @@ -0,0 +1,29 @@ +busybox 1.34.1 n/a binary CVE-2022-48174 Critical +stdlib go1.19.4 n/a go-module CVE-2023-24538 Critical +stdlib go1.19.4 n/a go-module CVE-2023-24540 Critical +stdlib go1.19.4 n/a go-module CVE-2023-29402 Critical +stdlib go1.19.4 n/a go-module CVE-2023-29404 Critical +stdlib go1.19.4 n/a go-module CVE-2023-29405 Critical +stdlib go1.19.4 n/a go-module CVE-2023-39323 Critical +busybox 1.34.1 n/a binary CVE-2022-28391 High +golang.org/x/net v0.4.0 0.17.0 go-module GHSA-4374-p667-p6c8 High +golang.org/x/net v0.4.0 0.7.0 go-module GHSA-vvpx-j8f3-3w6h High +stdlib go1.19.4 n/a go-module CVE-2022-41722 High +stdlib go1.19.4 n/a go-module CVE-2022-41723 High +stdlib go1.19.4 n/a go-module CVE-2022-41724 High +stdlib go1.19.4 n/a go-module CVE-2022-41725 High +stdlib go1.19.4 n/a go-module CVE-2023-24534 High +stdlib go1.19.4 n/a go-module CVE-2023-24536 High +stdlib go1.19.4 n/a go-module CVE-2023-24537 High +stdlib go1.19.4 n/a go-module CVE-2023-24539 High +stdlib go1.19.4 n/a go-module CVE-2023-29400 High +stdlib go1.19.4 n/a go-module CVE-2023-29403 High +stdlib go1.19.4 n/a go-module CVE-2023-44487 High +github.com/prometheus/alertmanager v0.25.0 0.25.1 go-module GHSA-v86x-5fm3-5p7j Medium +golang.org/x/net v0.4.0 0.13.0 go-module GHSA-2wrh-6pvc-2jm9 Medium +golang.org/x/net v0.4.0 0.17.0 go-module GHSA-qppj-fm5r-hxr3 Medium +stdlib go1.19.4 n/a go-module CVE-2023-24532 Medium +stdlib go1.19.4 n/a go-module CVE-2023-29406 Medium +stdlib go1.19.4 n/a go-module CVE-2023-29409 Medium +stdlib go1.19.4 n/a go-module CVE-2023-39318 Medium +stdlib go1.19.4 n/a go-module CVE-2023-39319 Medium \ No newline at end of file diff --git a/internal/vul/testdata/sort_sev/no_dups/sc1.text b/internal/vul/testdata/sort_sev/no_dups/sc1.text new file mode 100644 index 0000000000..6190c71713 --- /dev/null +++ b/internal/vul/testdata/sort_sev/no_dups/sc1.text @@ -0,0 +1,2 @@ +busybox 1.34.1 n/a binary CVE-2022-48174 Critical +busybox 1.34.1 n/a binary CVE-2022-28391 High \ No newline at end of file diff --git a/internal/vul/testdata/sort_sev/no_dups/sc2.text b/internal/vul/testdata/sort_sev/no_dups/sc2.text new file mode 100644 index 0000000000..f9f06da82c --- /dev/null +++ b/internal/vul/testdata/sort_sev/no_dups/sc2.text @@ -0,0 +1,2 @@ +busybox 1.34.1 n/a binary CVE-2022-48174 Critical +busybox 1.34.1 n/a binary CVE-2022-28391 High \ No newline at end of file diff --git a/internal/vul/types.go b/internal/vul/types.go new file mode 100644 index 0000000000..339714d46c --- /dev/null +++ b/internal/vul/types.go @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of K9s + +package vul + +const ( + // Sev1 tracks Critical sev. + Sev1 = "SEV-1" + + // Sev2 tracks High sev. + Sev2 = "SEV-2" + + // Sev3 tracks Medium sev. + Sev3 = "SEV-3" + + // Sev4 tracks Low sev. + Sev4 = "SEV-4" + + // Sev5 tracks Negligible sev. + Sev5 = "SEV-5" + + // SevU tracks Unknown sev. + SevU = "SEV-U" +) From 01fafca86cd60b23eab3ba6f36fa6ca9ee2c7685 Mon Sep 17 00:00:00 2001 From: derailed Date: Sun, 3 Dec 2023 19:19:44 -0700 Subject: [PATCH 21/22] Change skin loading and support - Move skin specification to k9s cluster config section - Load skins for skins dir --- .golangci.yml | 4 +-- internal/client/client.go | 5 +-- internal/config/cluster.go | 1 + internal/config/color.go | 61 +++++++++++++++++++++++++++++++++++ internal/config/config.go | 4 +++ internal/config/helpers.go | 2 +- internal/config/styles.go | 52 ----------------------------- internal/dao/helm_history.go | 5 ++- internal/ui/config.go | 40 ++++++++++++++++------- internal/view/helm_history.go | 3 ++ 10 files changed, 106 insertions(+), 71 deletions(-) create mode 100644 internal/config/color.go diff --git a/.golangci.yml b/.golangci.yml index 78a2a5885f..f880f84a8d 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,10 +1,10 @@ # options for analysis running run: # default concurrency is a available CPU number - concurrency: 4 + concurrency: 8 # timeout for analysis, e.g. 30s, 5m, default is 1m - timeout: 1m + timeout: 5m # exit code when at least one issue was found, default is 1 issues-exit-code: 1 diff --git a/internal/client/client.go b/internal/client/client.go index 6bbdffdd9b..fc5c9f2877 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -22,7 +22,6 @@ import ( "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes" restclient "k8s.io/client-go/rest" - cmdutil "k8s.io/kubectl/pkg/cmd/util" metricsapi "k8s.io/metrics/pkg/apis/metrics" "k8s.io/metrics/pkg/client/clientset/versioned" ) @@ -457,9 +456,7 @@ func (a *APIClient) supportsMetricsResources() error { a.cache.Add(cacheMXAPIKey, supported, cacheExpiry) }() - cfg := cmdutil.NewMatchVersionFlags(a.config.flags) - f := cmdutil.NewFactory(cfg) - dial, err := f.ToDiscoveryClient() + dial, err := a.CachedDiscovery() if err != nil { log.Warn().Err(err).Msgf("Unable to dial discovery API") return err diff --git a/internal/config/cluster.go b/internal/config/cluster.go index 295cd700d2..1fe5dccf9b 100644 --- a/internal/config/cluster.go +++ b/internal/config/cluster.go @@ -12,6 +12,7 @@ const DefaultPFAddress = "localhost" type Cluster struct { Namespace *Namespace `yaml:"namespace"` View *View `yaml:"view"` + Skin string `yaml:"skin,omitempty"` FeatureGates *FeatureGates `yaml:"featureGates"` PortForwardAddress string `yaml:"portForwardAddress"` } diff --git a/internal/config/color.go b/internal/config/color.go new file mode 100644 index 0000000000..59fd4d0a0f --- /dev/null +++ b/internal/config/color.go @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of K9s + +package config + +import ( + "fmt" + + "github.com/derailed/tcell/v2" +) + +const ( + // DefaultColor represents a default color. + DefaultColor Color = "default" + + // TransparentColor represents the terminal bg color. + TransparentColor Color = "-" +) + +// NewColor returns a new color. +func NewColor(c string) Color { + return Color(c) +} + +// String returns color as string. +func (c Color) String() string { + if c.isHex() { + return string(c) + } + if c == DefaultColor { + return "-" + } + col := c.Color().TrueColor().Hex() + if col < 0 { + return "-" + } + + return fmt.Sprintf("#%06x", col) +} + +func (c Color) isHex() bool { + return len(c) == 7 && c[0] == '#' +} + +// Color returns a view color. +func (c Color) Color() tcell.Color { + if c == DefaultColor { + return tcell.ColorDefault + } + + return tcell.GetColor(string(c)).TrueColor() +} + +// Colors converts series string colors to colors. +func (c Colors) Colors() []tcell.Color { + cc := make([]tcell.Color, 0, len(c)) + for _, color := range c { + cc = append(cc, color.Color()) + } + return cc +} diff --git a/internal/config/config.go b/internal/config/config.go index 9ba4a61be7..f7674c7777 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -23,6 +23,10 @@ const K9sConfig = "K9SCONFIG" var ( // K9sConfigFile represents K9s config file location. K9sConfigFile = filepath.Join(K9sHome(), "config.yml") + + // K9sSkinDir represent K9s skin dir + K9sSkinDir = filepath.Join(K9sHome(), "skins") + // K9sDefaultScreenDumpDir represents a default directory where K9s screen dumps will be persisted. K9sDefaultScreenDumpDir = filepath.Join(os.TempDir(), fmt.Sprintf("k9s-screens-%s", MustK9sUser())) ) diff --git a/internal/config/helpers.go b/internal/config/helpers.go index f3668370af..bc14a34898 100644 --- a/internal/config/helpers.go +++ b/internal/config/helpers.go @@ -20,7 +20,7 @@ const ( DefaultFileMod os.FileMode = 0600 ) -var invalidPathCharsRX = regexp.MustCompile(`[:]+`) +var invalidPathCharsRX = regexp.MustCompile(`[:/]+`) // SanitizeFilename sanitizes the dump filename. func SanitizeFilename(name string) string { diff --git a/internal/config/styles.go b/internal/config/styles.go index 62a192a0d3..cefefcf085 100644 --- a/internal/config/styles.go +++ b/internal/config/styles.go @@ -4,7 +4,6 @@ package config import ( - "fmt" "os" "path/filepath" @@ -224,57 +223,6 @@ type ( } ) -const ( - // DefaultColor represents a default color. - DefaultColor Color = "default" - - // TransparentColor represents the terminal bg color. - TransparentColor Color = "-" -) - -// NewColor returns a new color. -func NewColor(c string) Color { - return Color(c) -} - -// String returns color as string. -func (c Color) String() string { - if c.isHex() { - return string(c) - } - if c == DefaultColor { - return "-" - } - col := c.Color().TrueColor().Hex() - if col < 0 { - return "-" - } - - return fmt.Sprintf("#%06x", col) -} - -func (c Color) isHex() bool { - return len(c) == 7 && c[0] == '#' -} - -// Color returns a view color. -func (c Color) Color() tcell.Color { - if c == DefaultColor { - return tcell.ColorDefault - } - - return tcell.GetColor(string(c)).TrueColor() -} - -// Colors converts series string colors to colors. -func (c Colors) Colors() []tcell.Color { - cc := make([]tcell.Color, 0, len(c)) - for _, color := range c { - cc = append(cc, color.Color()) - } - return cc -} - func newStyle() Style { return Style{ Body: newBody(), diff --git a/internal/dao/helm_history.go b/internal/dao/helm_history.go index 3699c4a82e..38fda22ff9 100644 --- a/internal/dao/helm_history.go +++ b/internal/dao/helm_history.go @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of K9s + package dao import ( @@ -25,7 +28,7 @@ type HelmHistory struct { } // List returns a collection of resources. -func (h *HelmHistory) List(ctx context.Context, ns string) ([]runtime.Object, error) { +func (h *HelmHistory) List(ctx context.Context, _ string) ([]runtime.Object, error) { path, ok := ctx.Value(internal.KeyFQN).(string) if !ok { return nil, fmt.Errorf("expecting FQN in context") diff --git a/internal/ui/config.go b/internal/ui/config.go index 6ab5af1f50..3d55da8f4c 100644 --- a/internal/ui/config.go +++ b/internal/ui/config.go @@ -6,7 +6,6 @@ package ui import ( "context" "errors" - "fmt" "os" "path/filepath" @@ -100,6 +99,7 @@ func (c *Configurator) StylesWatcher(ctx context.Context, s synchronizer) error select { case evt := <-w.Events: if evt.Name == c.skinFile && evt.Op != fsnotify.Chmod { + log.Debug().Msgf("Skin changed: %s", c.skinFile) s.QueueUpdateDraw(func() { c.RefreshStyles(c.Config.K9s.CurrentCluster) }) @@ -117,8 +117,12 @@ func (c *Configurator) StylesWatcher(ctx context.Context, s synchronizer) error } }() - log.Debug().Msgf("SkinWatcher watching `%s", c.skinFile) - return w.Add(config.K9sHome()) + log.Debug().Msgf("SkinWatcher watching %q", config.K9sHome()) + if err := w.Add(config.K9sHome()); err != nil { + return err + } + log.Debug().Msgf("SkinWatcher watching %q", config.K9sSkinDir) + return w.Add(config.K9sSkinDir) } // BenchConfig location of the benchmarks configuration file. @@ -130,21 +134,35 @@ func BenchConfig(context string) string { func (c *Configurator) RefreshStyles(context string) { c.BenchFile = BenchConfig(context) - clusterSkins := config.YamlExtension(filepath.Join(config.K9sHome(), fmt.Sprintf("%s_skin.yml", context))) if c.Styles == nil { c.Styles = config.NewStyles() } else { c.Styles.Reset() } - if err := c.Styles.Load(clusterSkins); err != nil { - if errors.Is(err, os.ErrNotExist) { - log.Warn().Msgf("No context specific skin file found -- %s", clusterSkins) + + var skin string + if c.Config != nil { + cl, ok := c.Config.K9s.Clusters[context] + if !ok { + return + } + skin = cl.Skin + } + + var ( + skinFile = filepath.Join(config.K9sSkinDir, skin+".yml") + ) + if skin != "" { + if err := c.Styles.Load(skinFile); err != nil { + if errors.Is(err, os.ErrNotExist) { + log.Warn().Msgf("Skin file %q not found in skins dir: %s", skinFile, config.K9sSkinDir) + } else { + log.Error().Msgf("Failed to parse skin file -- %s: %s.", skinFile, err) + } } else { - log.Error().Msgf("Failed to parse context specific skin file -- %s. %s.", clusterSkins, err) + c.updateStyles(skinFile) + return } - } else { - c.updateStyles(clusterSkins) - return } if err := c.Styles.Load(config.K9sStylesFile); err != nil { diff --git a/internal/view/helm_history.go b/internal/view/helm_history.go index 8074ad0b0d..9a1b7eb86e 100644 --- a/internal/view/helm_history.go +++ b/internal/view/helm_history.go @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Authors of K9s + package view import ( From 3ea92217581e0c43eeac9bbd4f8e30a0c0f605a3 Mon Sep 17 00:00:00 2001 From: derailed Date: Sun, 26 Nov 2023 18:19:20 -0700 Subject: [PATCH 22/22] Release v0.29.0 docs --- Makefile | 2 +- README.md | 29 +++-- change_logs/release_v0.29.0.md | 212 +++++++++++++++++++++++++++++++++ 3 files changed, 235 insertions(+), 8 deletions(-) create mode 100644 change_logs/release_v0.29.0.md diff --git a/Makefile b/Makefile index e59570082b..7409077e08 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ DATE ?= $(shell TZ=UTC date -j -f "%s" ${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H: else DATE ?= $(shell date -u -d @${SOURCE_DATE_EPOCH} +"%Y-%m-%dT%H:%M:%SZ") endif -VERSION ?= v0.28.2 +VERSION ?= v0.29.0 IMG_NAME := derailed/k9s IMAGE := ${IMG_NAME}:${VERSION} diff --git a/README.md b/README.md index 45c5f92136..ae3a89c0ee 100644 --- a/README.md +++ b/README.md @@ -353,7 +353,7 @@ K9s uses aliases to navigate most K8s resources. # Defines the total number of log lines to allow in the view. Default 1000 buffer: 500 # Represents how far to go back in the log timeline in seconds. Setting to -1 will tail logs. Default is -1. - sinceSeconds: 300 # => tail the last 5 mins + sinceSeconds: 300 # => tail the last 5 mins. # Go full screen while displaying logs. Default false fullScreenLogs: false # Toggles log line wrap. Default false @@ -802,21 +802,36 @@ Example: Dracula Skin ;) Dracula Skin -You can style K9s based on your own sense of look and style. Skins are YAML files, that enable a user to change the K9s presentation layer. K9s skins are loaded from `$XDG_CONFIG_HOME/k9s/skin.yml`. If a skin file is detected then the skin would be loaded if not the current stock skin remains in effect. +You can style K9s based on your own sense of look and style. Skins are YAML files, that enable a user to change the K9s presentation layer. K9s default skin is loaded from `$XDG_CONFIG_HOME/k9s/skin.yml`. If a skin file is detected then the skin will be loaded if not the current stock skin remains in effect. -You can also change K9s skins based on the cluster you are connecting too. In this case, you can specify the skin file name as `$XDG_CONFIG_HOME/k9s/mycontext_skin.yml` -Below is a sample skin file, more skins are available in the skins directory in this repo, just simply copy any of these in your user's home dir as `skin.yml`. +You can also change K9s skins based on the cluster you are connecting too. In this case, you can specify a skin field on your cluster config aka `skin: dracula` (just the name of the skin!) and copy this repo skins/dracula.yml to `$XDG_CONFIG_HOME/k9s/skins` directory. +Below is a sample skin file, more skins are available in the skins directory in this repo, just simply copy any of these in your k9s home dir as `skin.yml`. Colors can be defined by name or using a hex representation. Of recent, we've added a color named `default` to indicate a transparent background color to preserve your terminal background color settings if so desired. > NOTE: This is very much an experimental feature at this time, more will be added/modified if this feature has legs so thread accordingly! - - > NOTE: Please see [K9s Skins](https://k9scli.io/topics/skins/) for a list of available colors. +```yaml +# Make cluster fred display in_the_navy skin when loaded... +k9s: + ... + clusters: + fred: + # Override the default skin and use this skin for this cluster. + # NOTE: Just the skin file name to extension! + skin: in_the_navy # -> Look for a skin file in ~/.config/k9s/skins/in_the_navy.yml + namespace: + ... + view: + active: pod + featureGates: + nodeShell: false + portForwardAddress: localhost +``` ```yaml -# Skin InTheNavy... +# in_the_navy.yml: Skin InTheNavy... k9s: # General K9s styles body: diff --git a/change_logs/release_v0.29.0.md b/change_logs/release_v0.29.0.md new file mode 100644 index 0000000000..927d84a794 --- /dev/null +++ b/change_logs/release_v0.29.0.md @@ -0,0 +1,212 @@ + + +# Release v0.29.0 + +## Notes + +Thank you to all that contributed with flushing out issues and enhancements for K9s! +I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev +and see if we're happier with some of the fixes! +If you've filed an issue please help me verify and close. + +Your support, kindness and awesome suggestions to make K9s better are, as ever, very much noted and appreciated! +Also big thanks to all that have allocated their own time to help others on both slack and on this repo!! + +As you may know, K9s is not pimped out by corps with deep pockets, thus if you feel K9s is helping your Kubernetes journey, +please consider joining our [sponsorship program](https://github.com/sponsors/derailed) and/or make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer) + +On Slack? Please join us [K9slackers](https://join.slack.com/t/k9sers/shared_invite/enQtOTA5MDEyNzI5MTU0LWQ1ZGI3MzliYzZhZWEyNzYxYzA3NjE0YTk1YmFmNzViZjIyNzhkZGI0MmJjYzhlNjdlMGJhYzE2ZGU1NjkyNTM) + +--- + +## ♫ Sounds Behind The Release ♭ + +* [Snowbound - Donald Fagen](https://www.youtube.com/watch?v=bj8ZdBdKsfo) +* [Pilgrim - Eric Clapton](https://www.youtube.com/watch?v=8V9tSQuIzbQ) +* [Lucky Number - Lene Lovich](https://www.youtube.com/watch?v=KnIJOO__jVo) + +--- + +## 🦃 Happy (Belated!) ThanksGiving To All! 🦃 + +Hope you and yours had a wonderful holiday!! +Hopefully this drop won't be a cold turkey 😳 + +I'd like to take this opportunity to honor two very special folks: + +* [Alexandru Placinta](https://github.com/placintaalexandru) +* [Jayson Wang](https://github.com/wjiec) + +These guys have been relentless in fishing out bugs, helping out with support and addressing issues, not to mention enduring my code! 🙀 +They dedicate a lot of their time to make `k9s` better for all of us! +So if you happen to run into them live/virtual, please be sure to `Thank` them and give them a huge hug! 🤗 + +I am thankful for all of you for being kind, patient, understanding and one of the coolest OSS community on the web!! + +Feeling blessed and ever so humbled to be part of it. + +Thank you!! + +--- + +## A Word From Our Sponsors... + +To all the good folks below that opted to `pay it forward` and join our sponsorship program, I salute you!! + +* [Marco Stuurman](https://github.com/fe-ax) +* [Paul Sweeney](https://github.com/Kolossi) +* [Cayla Fauver](https://github.com/cayla) +* [alemanek](https://github.com/alemanek) +* [Danske Commodities A/S](https://github.com/DanskeCommodities) + +> Sponsorship cancellations since the last release: **8** ;( + +--- + +## 🎉 Feature Release 🎈👯 + +--- + +### Breaking Bad! + +WARNING! There are breaking change on this drop! + +1. NodeShell configuration has moved up in the k9s config file from the context section to the top level config. +More than likely, one uses the same nodeShell image with all the fixins to introspect nodes no matter the cluster. This update DRY's up k9s config and still allows one to opt in/out of nodeShell via the context specific feature gate. +Please see README for the details. + + > NOTE: If you haven't customize the shellPod images on your contexts, the app will move the nodeShell config section to + > it's new location and update your clusters information accordingly. + > If not, you will need to edit the nodeShell section and manage it from a single location! + +1. Log view used to default to the last 5mins aka `sinceSeconds: 300`. + Changed the default to tail logs instead aka `sinceSeconds: -1` + +1. Skins loading changed! In this release, we do away with the context specific skin files. You can now directly specify the skin to use for a given cluster directly in the k9s config file under the cluster configuration. K9s now expects a skins directory in the k9s config home with your skin files. You can use your custom skins and copy them to the `skins` directory or use the contributes skins found on this repo root. +Specify the name of the skin in the config file and now your cluster will load the specified skin. + +For example: create a `skins` dir your k9s config home and add one_dark.yml skin file from this repo. Then edit your k9s config file as follows: + +```yaml +k9s: + ... + clusters: + fred: + # Override the default skin and use this skin for this cluster. + skin: one_dark # -> Look for a skin file in ~/.config/k9s/skins/one_dark.yml + namespace: + ... + view: + active: pod + featureGates: + nodeShell: false + portForwardAddress: localhost +``` + +The `fred` cluster will now load with the specified skin name. Rinse and repeat for other clusters of your liking. In the case where neither the skin dir or skin file are present, k9s will still honor the global skin aka `skin.yml` in your k9s config home directory to skin all your clusters. + +--- + +### Walk Of SHelm... + +Added a `Releases` view to Helm! + +This provides the ability for Helm users to manage their releases directly from k9s. +You can now press `enter` on a selected Helm install and view all associated releases. +While in the releases view, you can also rollback an install to a previous revision. + +--- + +### Spock! Are You Out Of Your VulScan Mind? + +Tired of having malignent folks shoot holes in your prod clusters or failing compliance testing? + +Added ability to run image vulnerability scans directly from k9s. You can now monitor your security stance in dev/staging/... clusters +prior to proclaiming `It's Open Season...` in prod! + +As it stands Pod, Deployment, StatefulSet, DaemonSet, CronJob, Job views will feature a new column for Vulnerability Scan aka `VS`. + +> NOTE! This feature is gated so you'll need to manually opt in/out by modifying your k9s config file like so: + +```yaml +k9s: + liveViewAutoRefresh: false + enableImageScan: true # <- Yes Please!! + headless: false + ... +``` + +Once enabled, a new column `VS` (aka Vulnerability Score) should be present on the aforementioned views where you will see your vulnerability scores (*Still work in progress!!*). +The `VS` column displays a bit vector aka Sev-1|Sev-2|Sev-3|Sev-4|Sev-5|Sev-Unknown. When the bit is high it indicate the presence of the severity in the scans. Higher order bits = Higher severity +For instance, the following vector `110001` indicates the presence of both critical (Sev-1) and high (Sev-2) and an unclassified severity (aka Sev-Unknown) issues in the scan. Sev-U indicates no classification currently exist in our vulnerability database. + +The image scans are run async, rendering the views eventually consistent, hence you may have to give the scores a few cycles for the dust to settle... +Once the caches are primed, subsequent loads should be faster 🤞 + +You can sort the views by vulnerability score using `ShiftV`. +Additionally, you can view the full scans report by pressing `v` on a selected resource. + +I've synced my entire Thanksgiving holiday break on this ding dang deal, so hopefully it works for most of you?? +Also if you dig this new feature, please make some noise! 😍 + +💘 This is an experimental feature and likely will require additional TLC 💘 + +> NOTE! The lib we use to scan for vulnerabilities only supports macOS and Linux!! +> NOTE: I have yet to test this feature on larger clusters, so likely this may break?? +> Please take these reports with a grain of salt as likely your mileage will vary and help us +> validate the accuracy of the report ie if we cry `Wolf`, is it actually there? + +The paint is still fresh on this deal!! + +### Do You Tube? + +My plan is to begin (again!) putting out short k9s episodes with how-tos, tips, tricks and features previews. + +Please dial [K9s Channel](https://www.youtube.com/channel/UC897uwPygni4QIjkPCpgjmw) for up coming content... + +The first drop should be up by the time you read this! + +* [Vulnerability Scans](https://youtu.be/ULkl0MsaidU) + +--- + +## Resolved Issues + +* [#2308](https://github.com/derailed/k9s/issues/2308) Unable to list CRs for crd with only list and get verb without watch verb +* [#2301](https://github.com/derailed/k9s/issues/2301) Add imagePullPolicy and imagePullSecrets on shell_pod for internal registry uses +* [#2298](https://github.com/derailed/k9s/issues/2298) Weird color after plugin usage +* [#2297](https://github.com/derailed/k9s/issues/2297) Select nodes with space does not work anymore +* [#2290](https://github.com/derailed/k9s/issues/2290) Provide release assets for freebsd amd64/arm64 +* [#2283](https://github.com/derailed/k9s/issues/2283) Adding auto complete in search bar +* [#2219](https://github.com/derailed/k9s/issues/2219) Add tty: true to the node shell pod manifest +* [#2167](https://github.com/derailed/k9s/issues/2167) Show wrong Configmap data +* [#2166](https://github.com/derailed/k9s/issues/2166) Taint count for the nodes view +* [#2165](https://github.com/derailed/k9s/issues/2165) Restart counter for init containers +* [#2162](https://github.com/derailed/k9s/issues/2162) Make edit work when describing a resource +* [#2154](https://github.com/derailed/k9s/issues/2154) Help and h command does not work if typed into cmdbuff +* [#2036](https://github.com/derailed/k9s/issues/2036) Crashed while do filtering +* [#2009](https://github.com/derailed/k9s/issues/2009) Ctrl-s: Name of file (Describe-....) +* [#1513](https://github.com/derailed/k9s/issues/1513) Problem regarding showing the logs - it hangs/slow on pods which are running for long time + NOTE: Better but not cured! Perf improvements while viewing large cm (7k lines) from 26s->9s +* [#568](https://github.com/derailed/k9s/issues/568) Allow both .yaml and .yml yaml config files + +--- + +## Contributed PRs + +Please be sure to give `Big Thanks!` and `ATTA Girls/Boys!` to all the fine contributors for making K9s better for all of us!! + +* [#2322](https://github.com/derailed/k9s/pull/2322) Check if the service provides selectors +* [#2319](https://github.com/derailed/k9s/pull/2319) Proper handling of help commands (fixes #2154) +* [#2315](https://github.com/derailed/k9s/pull/2315) Fix namespace suggestion error on context switch +* [#2313](https://github.com/derailed/k9s/pull/2313) Should not clear screen when executing plugin command +* [#2310](https://github.com/derailed/k9s/pull/2310) chore: Mot recommended to use k8s.io/kubernetes as a dependency +* [#2303](https://github.com/derailed/k9s/pull/2303) Clean up items +* [#2301](https://github.com/derailed/k9s/pull/2301) feat: Add imagePullSecrets and imagePullPolicy configuration for shellpod +* [#2289](https://github.com/derailed/k9s/pull/2289) Clean up issues introduced in #2125 +* [#2288](https://github.com/derailed/k9s/pull/2288) Fix merge issues from PR #2168 +* [#2284](https://github.com/derailed/k9s/issues/2284) Allow both .yaml and .yml yaml config files + +--- + + © 2023 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)