diff --git a/cmd/graphquery.go b/cmd/graphquery.go deleted file mode 100644 index d9072a6..0000000 --- a/cmd/graphquery.go +++ /dev/null @@ -1,166 +0,0 @@ -package main - -import ( - "errors" - "fmt" - - "strings" - - "github.com/anandf/resource-tracker/pkg/argocd" - "github.com/anandf/resource-tracker/pkg/env" - "github.com/anandf/resource-tracker/pkg/graph" - "github.com/anandf/resource-tracker/pkg/version" - "github.com/avitaltamir/cyphernetes/pkg/core" - log "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" -) - -type GraphQueryConfig struct { - applicationName string - applicationNamespace string - globalQuery *bool - logLevel string - kubeConfig string - argocdNamespace string -} - -type GraphQueryCommand struct { - queryServer *graph.QueryServer - argoCDClient argocd.ArgoCD -} - -// newGraphQueryCommand implements "runQuery" command which executes a cyphernetes graph query against a given kubeconfig -func newGraphQueryCommand() *cobra.Command { - cfg := &GraphQueryConfig{} - - var runQueryCmd = &cobra.Command{ - Use: "run-query", - Short: "Runs the resource-tracker which executes a graph based query to fetch the dependencies", - RunE: func(cmd *cobra.Command, args []string) error { - log.Infof("%s %s starting [loglevel:%s]", - version.BinaryName(), - version.Version(), - strings.ToUpper(cfg.logLevel), - ) - var err error - level, err := log.ParseLevel(cfg.logLevel) - if err != nil { - return fmt.Errorf("failed to parse log level: %w", err) - } - log.SetLevel(level) - core.LogLevel = cfg.logLevel - r, err := newGraphQueryCommandController(cfg) - if err != nil { - return err - } - if err != nil { - return err - } - return r.execute(cfg) - }, - } - runQueryCmd.Flags().StringVar(&cfg.logLevel, "loglevel", env.GetStringVal("RESOURCE_TRACKER_LOGLEVEL", "info"), "set the loglevel to one of trace|debug|info|warn|error") - runQueryCmd.Flags().StringVar(&cfg.kubeConfig, "kubeconfig", "", "full path to kube client configuration, i.e. ~/.kube/config") - runQueryCmd.Flags().StringVar(&cfg.applicationName, "app-name", "", "if only specific application resources needs to be tracked, by default all applications ") - runQueryCmd.Flags().StringVar(&cfg.applicationNamespace, "app-namespace", "", "namespace for the given application. Default value is empty string indicating cluster scope") - runQueryCmd.Flags().StringVar(&cfg.argocdNamespace, "argocd-namespace", "argocd", "namespace where argocd control plane components are running") - cfg.globalQuery = runQueryCmd.Flags().Bool("global", true, "perform graph query without listing applications and finding children for each application") - return runQueryCmd -} - -// newGraphQueryCommandController initializes the required kubernetes clients and the cyphernetes graph query executor. -// this is an expensive operation and done only once, and the same executor is used for further graph query executions -func newGraphQueryCommandController(cfg *GraphQueryConfig) (*GraphQueryCommand, error) { - // First try in-cluster config - restConfig, err := rest.InClusterConfig() - if err != nil && !errors.Is(err, rest.ErrNotInCluster) { - return nil, fmt.Errorf("failed to create config: %v", err) - } - - // If not running in-cluster, try loading from KUBECONFIG env or $HOME/.kube/config file - if restConfig == nil { - // Fall back to kubeconfig - loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() - loadingRules.ExplicitPath = cfg.kubeConfig - configOverrides := &clientcmd.ConfigOverrides{} - kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides) - restConfig, err = kubeConfig.ClientConfig() - if err != nil { - return nil, fmt.Errorf("failed to create config: %v", err) - } - } - - argoCD, err := argocd.NewArgoCD(restConfig, cfg.argocdNamespace) - if err != nil { - return nil, err - } - trackingMethod, err := argoCD.GetTrackingMethod() - if err != nil { - return nil, err - } - qs, err := graph.NewQueryServer(restConfig, trackingMethod, true) - if err != nil { - return nil, err - } - return &GraphQueryCommand{ - queryServer: qs, - argoCDClient: argoCD, - }, nil -} - -// execute runs the graph query, computes the resources managed via Argo CD and prints it on the terminal -func (r *GraphQueryCommand) execute(cfg *GraphQueryConfig) error { - log.Info("Starting query executor...") - var allAppChildren []graph.ResourceInfo - if *cfg.globalQuery { - log.Infof("Querying Argo CD application globally for application '%s'...", cfg.applicationName) - appChildren, err := r.queryServer.GetApplicationChildResources(cfg.applicationName, "") - if err != nil { - return err - } - log.Infof("Children of Argo CD application globally for application '%s': %s", cfg.applicationName, appChildren.String()) - for appChild := range appChildren { - allAppChildren = append(allAppChildren, appChild) - } - } else { - argoAppResources, err := r.argoCDClient.ListApplications() - if err != nil { - return err - } - for _, argoAppResource := range argoAppResources { - log.Infof("Querying Argo CD application '%v'", argoAppResource) - appChildren, err := r.queryServer.GetApplicationChildResources(argoAppResource.Name, "") - if err != nil { - return err - } - log.Infof("Children of Argo CD application '%s': %v", argoAppResource.Name, appChildren) - for appChild := range appChildren { - allAppChildren = append(allAppChildren, appChild) - } - } - } - groupedKinds := make(graph.GroupedResourceKinds) - groupedKinds.MergeResourceInfos(allAppChildren) - missingResources, err := r.argoCDClient.GetAllMissingResources() - if err != nil { - return err - } - // Check if additional resources are missing, if so add it. - for _, resource := range missingResources { - log.Infof("adding missing resource '%v'", resource) - if kindMap, ok := groupedKinds[resource.APIVersion]; !ok && kindMap == nil { - groupedKinds[resource.APIVersion] = graph.Kinds{resource.Kind: graph.Void{}} - } else { - groupedKinds[resource.APIVersion][resource.Kind] = graph.Void{} - } - } - - resourceInclusionString := groupedKinds.String() - if strings.HasPrefix(resourceInclusionString, "error:") { - return fmt.Errorf("error in yaml string of resource.inclusions: %s", resourceInclusionString) - } - fmt.Printf("resource.inclusions: |\n%sresource.exclusions: ''\n", resourceInclusionString) - return nil -} diff --git a/cmd/main.go b/cmd/main.go index 465dd4b..a41fae5 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -10,10 +10,10 @@ import ( func newRootCommand() error { var rootCmd = &cobra.Command{ Use: "argocd-resource-tracker", - Short: "Dynamically update resource.inclusions based on the resources managed by Argo Applications", + Short: "Argo CD Resource Tracker", + Long: "Argo CD Resource Tracker is a tool which analyzes the resource inclusions settings based on the resources managed by Argo Applications", } - rootCmd.AddCommand(newRepoServerCommand()) - rootCmd.AddCommand(newGraphQueryCommand()) + rootCmd.AddCommand(NewAnalyzeCommand()) rootCmd.AddCommand(newVersionCommand()) err := rootCmd.Execute() return err diff --git a/cmd/reposerver.go b/cmd/reposerver.go deleted file mode 100644 index 7b31f8c..0000000 --- a/cmd/reposerver.go +++ /dev/null @@ -1,196 +0,0 @@ -package main - -import ( - "context" - "fmt" - "os" - "strings" - "sync" - - "github.com/anandf/resource-tracker/pkg/argocd" - "github.com/anandf/resource-tracker/pkg/graph" - "github.com/anandf/resource-tracker/pkg/kube" - "github.com/argoproj/argo-cd/v2/common" - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" - log "github.com/sirupsen/logrus" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/client-go/rest" - - "github.com/anandf/resource-tracker/pkg/env" - "github.com/anandf/resource-tracker/pkg/version" - "github.com/spf13/cobra" -) - -// RepoServerCommandConfig contains global configuration and required runtime data -type RepoServerCommandConfig struct { - argocdNamespace string - logLevel string - repoServerAddress string - repoServerPlaintext bool - repoServerStrictTLS bool - repoServerTimeoutSeconds int - kubeConfig string -} - -type RepoServerCommand struct { - argoCDClient argocd.ArgoCD - repoClient *argocd.RepoServerManager -} - -type manifestResponse struct { - children []*unstructured.Unstructured - destinationConfig *rest.Config - appName string -} - -func newRepoServerCommandController(cfg *RepoServerCommandConfig) (*RepoServerCommand, error) { - // Prepare the KUBECONFIG to connect to the Kubernetes cluster. - config, err := kube.GetKubeConfig(cfg.kubeConfig) - if err != nil { - return nil, fmt.Errorf("failed to get kube config: %w", err) - } - // Set this environment variable when running as CLI connecting to the Argo CD components running - // inside a cluster. - err = os.Setenv("ARGOCD_FAKE_IN_CLUSTER", "true") - if err != nil { - return nil, fmt.Errorf("failed to set env variable ARGOCD_FAKE_IN_CLUSTER: %w", err) - } - argoCD, err := argocd.NewArgoCD(config, cfg.argocdNamespace) - if err != nil { - return nil, err - } - repo, err := argocd.NewRepoServerManager(config, cfg.argocdNamespace, cfg.repoServerAddress, cfg.repoServerTimeoutSeconds, - cfg.repoServerPlaintext, cfg.repoServerStrictTLS) - if err != nil { - return nil, err - } - return &RepoServerCommand{ - argoCDClient: argoCD, - repoClient: repo, - }, nil -} - -// newRepoServerCommand implements "run" command -func newRepoServerCommand() *cobra.Command { - cfg := &RepoServerCommandConfig{} - var runCmd = &cobra.Command{ - Use: "run", - Short: "Runs the resource-tracker with a set of options", - RunE: func(cmd *cobra.Command, args []string) error { - - log.Infof("%s %s starting [loglevel:%s]", - version.BinaryName(), - version.Version(), - strings.ToUpper(cfg.logLevel), - ) - var err error - level, err := log.ParseLevel(cfg.logLevel) - if err != nil { - return fmt.Errorf("failed to parse log level: %w", err) - } - log.SetLevel(level) - r, err := newRepoServerCommandController(cfg) - if err != nil { - return err - } - return r.execute() - }, - } - runCmd.Flags().StringVar(&cfg.repoServerAddress, "repo-server", env.GetStringVal("ARGOCD_REPO_SERVER", common.DefaultRepoServerAddr), "Repo server address.") - runCmd.Flags().StringVar(&cfg.logLevel, "loglevel", env.GetStringVal("RESOURCE_TRACKER_LOGLEVEL", "info"), "set the loglevel to one of trace|debug|info|warn|error") - runCmd.Flags().IntVar(&cfg.repoServerTimeoutSeconds, "repo-server-timeout-seconds", 60, "Repo server RPC call timeout seconds.") - runCmd.Flags().BoolVar(&cfg.repoServerPlaintext, "repo-server-plaintext", false, "Disable TLS on connections to repo server, Default: false") - runCmd.Flags().BoolVar(&cfg.repoServerStrictTLS, "repo-server-strict-tls", false, "Whether to use strict validation of the TLS cert presented by the repo server, Default: false") - runCmd.Flags().StringVar(&cfg.kubeConfig, "kubeconfig", "", "full path to kube client configuration, i.e. ~/.kube/config") - runCmd.Flags().StringVar(&cfg.argocdNamespace, "argocd-namespace", "", "namespace where ArgoCD runs in (current namespace by default)") - return runCmd -} - -func (r *RepoServerCommand) execute() error { - log.Info("Starting resource tracking process...") - apps, err := r.argoCDClient.ListApplications() - if err != nil { - log.Fatalf("Error while listing applications: %v", err) - } - log.Infof("Fetched %d applications", len(apps)) - resourceChan := make(chan manifestResponse) - errChan := make(chan error) - allAppChildren := make([]manifestResponse, 0) - // Launch consumer (Tracker) - go startResourceTrackerConsumer(resourceChan, &allAppChildren) - var wg sync.WaitGroup - for _, app := range apps { - wg.Add(1) - go func(app v1alpha1.Application) { - log.Infof("processing application: %s", app.Name) - defer wg.Done() - appProject, err := r.argoCDClient.GetAppProject(app) - if err != nil { - errChan <- err - return - } - // Get target object from repo-server - targetObjs, destinationConfig, err := r.repoClient.GetApplicationChildManifests(context.Background(), &app, appProject) - if err != nil { - errChan <- err - return - } - resourceChan <- manifestResponse{ - children: targetObjs, - destinationConfig: destinationConfig, - appName: app.Name, - } - log.Infof("Fetched target manifests from repo-server for application: %s", app.Name) - }(app) - } - // Handle processing errors - go func() { - for err := range errChan { - log.Errorf("Error processing application: %v", err) - } - }() - log.Info("Resource tracking initiated for all applications.") - wg.Wait() - close(resourceChan) - log.Info("Resource channel has been closed. Resource Tracker process has completed successfully.") - var nestedResources = make([]graph.ResourceInfo, 0) - for _, appChild := range allAppChildren { - appGroupedResources, err := r.argoCDClient.ProcessApplication(appChild.children, appChild.appName, appChild.destinationConfig) - if err != nil { - return fmt.Errorf("error processing application: %w", err) - } - nestedResources = append(nestedResources, appGroupedResources...) - } - groupedKinds := make(graph.GroupedResourceKinds) - groupedKinds.MergeResourceInfos(nestedResources) - missingResources, err := r.argoCDClient.GetAllMissingResources() - if err != nil { - return fmt.Errorf("error while fetching missing resources: %v", err) - } - // Check if additional resources are missing, if so add it. - for _, resource := range missingResources { - log.Infof("adding missing resource '%v'", resource) - if kindMap, ok := groupedKinds[resource.APIVersion]; !ok && kindMap == nil { - groupedKinds[resource.APIVersion] = graph.Kinds{resource.Kind: graph.Void{}} - } else { - groupedKinds[resource.APIVersion][resource.Kind] = graph.Void{} - } - } - - resourceInclusionString := groupedKinds.String() - if strings.HasPrefix(resourceInclusionString, "error:") { - return fmt.Errorf("error in yaml string of resource.inclusions: %s", resourceInclusionString) - } - fmt.Printf("resource.inclusions: |\n%sresource.exclusions: ''\n", resourceInclusionString) - return nil -} - -func startResourceTrackerConsumer(resourceChan <-chan manifestResponse, allAppChildren *[]manifestResponse) { - // Process resources from the channel - // and update the tracked resources in the config - // This is a blocking call, so it will keep running until the channel is closed - for groupedResources := range resourceChan { - *allAppChildren = append(*allAppChildren, groupedResources) - } - -} diff --git a/cmd/reposerver_test.go b/cmd/reposerver_test.go deleted file mode 100644 index 18eddca..0000000 --- a/cmd/reposerver_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package main - -import ( - "os" - "testing" - - "github.com/anandf/resource-tracker/pkg/env" - "github.com/stretchr/testify/assert" -) - -// TestNewRunCommand tests various flags and their default values. -func TestNewRunCommand(t *testing.T) { - asser := assert.New(t) - runCmd := newRepoServerCommand() - asser.Contains(runCmd.Use, "run") - asser.Greater(len(runCmd.Short), 25) - asser.NotNil(runCmd.RunE) - asser.Equal("2m0s", runCmd.Flag("interval").Value.String()) - asser.Equal(env.GetStringVal("RESOURCE_TRACKER_LOGLEVEL", "info"), runCmd.Flag("loglevel").Value.String()) - asser.Equal("", runCmd.Flag("kubeconfig").Value.String()) - asser.Equal("", runCmd.Flag("argocd-namespace").Value.String()) - asser.Nil(runCmd.Help()) -} - -// TestRootCmd tests main.go#newRootCommand. -func TestRootCmd(t *testing.T) { - //remove the last element from os.Args so that it will not be taken as the arg to the image-updater command - os.Args = os.Args[:len(os.Args)-1] - err := newRootCommand() - assert.Nil(t, err) -} diff --git a/cmd/tracker_cmd.go b/cmd/tracker_cmd.go new file mode 100644 index 0000000..d7954c4 --- /dev/null +++ b/cmd/tracker_cmd.go @@ -0,0 +1,179 @@ +package main + +import ( + "context" + "fmt" + "strings" + + "github.com/anandf/resource-tracker/pkg/analyzer" + dynamicbackend "github.com/anandf/resource-tracker/pkg/analyzer/dynamic" + graphbackend "github.com/anandf/resource-tracker/pkg/analyzer/graph" + "github.com/anandf/resource-tracker/pkg/common" + "github.com/anandf/resource-tracker/pkg/env" + "github.com/anandf/resource-tracker/pkg/kube" + "github.com/anandf/resource-tracker/pkg/version" + argocdcommon "github.com/argoproj/argo-cd/v3/common" + kubeutil "github.com/argoproj/argo-cd/v3/util/kube" + "github.com/avitaltamir/cyphernetes/pkg/core" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" +) + +type queryCLIConfig struct { + applicationName string + applicationNamespace string + logLevel string + kubeConfig string + repoServerAddress string + repoServerPlaintext bool + repoServerStrictTLS bool + repoServerTimeoutSeconds int + argocdNamespace string + strategy string // 'dynamic' or 'graph' + allApps bool +} + +// NewAnalyzeCommand creates the 'analyze' command, which is the primary entrypoint. +func NewAnalyzeCommand() *cobra.Command { + cfg := &queryCLIConfig{} + + cmd := &cobra.Command{ + Use: "analyze", + Short: "Analyze resource relationships and dependencies for ArgoCD applications", + Long: "Analyze resource relationships and dependencies for ArgoCD applications. Can process a single app or all apps.", + RunE: func(cmd *cobra.Command, args []string) error { + log.Infof("%s %s starting [loglevel:%s]", + version.BinaryName(), + version.Version(), + strings.ToUpper(cfg.logLevel), + ) + level, err := log.ParseLevel(cfg.logLevel) + if err != nil { + return fmt.Errorf("failed to parse log level: %w", err) + } + log.SetLevel(level) + core.LogLevel = cfg.logLevel + + // Require --app when --all-apps is false, to avoid silently analyzing all apps. + if !cfg.allApps && cfg.applicationName == "" { + return fmt.Errorf("application name is required to analyze a single application") + } + + // Support app specified as "namespace/name" similar to `argocd app get ns/name`. + // If provided, override the separate applicationNamespace flag. + if cfg.applicationName != "" && !cfg.allApps { + if parts := strings.SplitN(cfg.applicationName, "/", 2); len(parts) == 2 { + cfg.applicationNamespace = parts[0] + cfg.applicationName = parts[1] + log.WithFields(log.Fields{ + "applicationName": cfg.applicationName, + "applicationNamespace": cfg.applicationNamespace, + }).Debug("Parsed application from namespace/name syntax") + } + } + + // Load the Kubernetes REST config (in-cluster or from kubeconfig path). + restCfg, err := kube.GetKubeConfig(cfg.kubeConfig) + if err != nil { + return fmt.Errorf("failed to load kubeconfig: %w", err) + } + repoAddr, err := ensureRepoServerAddress(restCfg, cfg.argocdNamespace, cfg.repoServerAddress) + if err != nil { + return err + } + + opts := analyzer.Options{ + KubeConfig: restCfg, + KubeConfigPath: cfg.kubeConfig, + ArgoCDNamespace: cfg.argocdNamespace, + TargetApp: cfg.applicationName, + TargetAppNamespace: cfg.applicationNamespace, + RepoServerAddress: repoAddr, + RepoServerPlaintext: cfg.repoServerPlaintext, + RepoServerStrictTLS: cfg.repoServerStrictTLS, + RepoServerTimeoutSeconds: cfg.repoServerTimeoutSeconds, + } + // Select backend. + var backend analyzer.Backend + switch cfg.strategy { + case "graph": + backend = graphbackend.NewBackend() + case "dynamic": + backend = dynamicbackend.NewBackend() + default: + return fmt.Errorf("invalid strategy: %s (must be 'graph' or 'dynamic')", cfg.strategy) + } + + // Execute analysis. + groupedKinds, err := backend.Execute(context.Background(), opts) + if err != nil { + return err + } + printInclusions(groupedKinds) + return nil + }, + } + cmd.Flags().StringVar(&cfg.logLevel, "loglevel", env.GetStringVal("RESOURCE_TRACKER_LOGLEVEL", "info"), "set the loglevel to one of trace|debug|info|warn|error") + cmd.Flags().StringVarP(&cfg.applicationName, "app", "", "", "Application name (required for single app analysis). Supports 'namespace/name' syntax.") + cmd.Flags().StringVarP(&cfg.applicationNamespace, "app-namespace", "N", "", "Application namespace") + cmd.Flags().StringVar(&cfg.repoServerAddress, "repo-server", env.GetStringVal("ARGOCD_REPO_SERVER", ""), "Repo server address. If empty, the CLI will port-forward to the repo-server service.") + cmd.Flags().BoolVar(&cfg.repoServerPlaintext, "repo-server-plaintext", false, "Use an unencrypted HTTP connection to the ArgoCD API instead of TLS.") + cmd.Flags().BoolVar(&cfg.repoServerStrictTLS, "repo-server-strict-tls", false, "Enable strict TLS validation for the repo server connection.") + cmd.Flags().IntVar(&cfg.repoServerTimeoutSeconds, "repo-server-timeout-seconds", 60, "Timeout in seconds for repo server RPC calls.") + cmd.Flags().StringVarP(&cfg.argocdNamespace, "namespace", "n", "argocd", "ArgoCD namespace") + cmd.Flags().StringVar(&cfg.kubeConfig, "kubeconfig", "", "Path to kubeconfig file for cluster access") + cmd.Flags().BoolVar(&cfg.allApps, "all-apps", false, "Analyze all applications in the namespace") + cmd.Flags().StringVar(&cfg.strategy, "strategy", "graph", "Analysis strategy: 'dynamic' (OwnerRef walking) or 'graph' (Cyphernetes)") + return cmd +} + +func printInclusions(groupedKinds *common.GroupedResourceKinds) { + resourceInclusionString := groupedKinds.String() + if strings.HasPrefix(resourceInclusionString, "error:") { + log.Errorf("error generating resource.inclusions: %s", resourceInclusionString) + return + } + log.Infof("resource.inclusions: |\n%s", resourceInclusionString) +} + +func ensureRepoServerAddress(restCfg *rest.Config, namespace, current string) (string, error) { + if current != "" { + return current, nil + } + log.Infof("Repo server address not provided, attempting to port-forward to argocd-repo-server in namespace %q", namespace) + + clientset, err := kubernetes.NewForConfig(restCfg) + if err != nil { + return "", fmt.Errorf("failed to create kube client for port-forward: %w", err) + } + // Discover the repo-server service to determine the app name label. + svcSelector := fmt.Sprintf("%s=%s", argocdcommon.LabelKeyComponentRepoServer, argocdcommon.LabelValueComponentRepoServer) + services, err := clientset.CoreV1().Services(namespace).List(context.Background(), metav1.ListOptions{ + LabelSelector: svcSelector, + }) + if err != nil { + return "", fmt.Errorf("failed to list repo-server services: %w", err) + } + repoServerName := "argocd-repo-server" + if len(services.Items) > 0 { + if v, ok := services.Items[0].Labels[argocdcommon.LabelKeyAppName]; ok && v != "" { + repoServerName = v + } + } + // Use the same label selector Argo CD uses for the repo-server pods. + podSelector := fmt.Sprintf("%s=%s", argocdcommon.LabelKeyAppName, repoServerName) + overrides := clientcmd.ConfigOverrides{} + + localPort, err := kubeutil.PortForward(8081, namespace, &overrides, podSelector) + if err != nil { + return "", fmt.Errorf("failed to port-forward to repo-server: %w", err) + } + + addr := fmt.Sprintf("localhost:%d", localPort) + log.WithField("repoServerAddress", addr).Info("Using port-forwarded repo-server address") + return addr, nil +} diff --git a/go.mod b/go.mod index 8122701..083e645 100644 --- a/go.mod +++ b/go.mod @@ -1,57 +1,59 @@ module github.com/anandf/resource-tracker -go 1.23.0 - -toolchain go1.23.4 +go 1.24.6 require ( - github.com/argoproj/argo-cd/v2 v2.13.5 - github.com/argoproj/gitops-engine v0.7.1-0.20250129155113-4c6e03c46314 + github.com/argoproj/argo-cd/v3 v3.0.0 github.com/avitaltamir/cyphernetes v0.17.3-0.20250528180625-d07fbac2979a github.com/emirpasic/gods v1.18.1 github.com/sirupsen/logrus v1.9.3 - github.com/spf13/cobra v1.8.1 + github.com/spf13/cobra v1.9.1 github.com/stretchr/testify v1.10.0 gopkg.in/yaml.v2 v2.4.0 - gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.31.2 - k8s.io/apiextensions-apiserver v0.31.2 - k8s.io/apimachinery v0.32.0 - k8s.io/client-go v1.5.2 + k8s.io/apiextensions-apiserver v0.32.2 + k8s.io/apimachinery v0.32.2 + k8s.io/client-go v0.32.2 ) require ( - cloud.google.com/go/compute/metadata v0.5.2 // indirect + cloud.google.com/go/compute/metadata v0.6.0 // indirect dario.cat/mergo v1.0.1 // indirect github.com/AvitalTamir/jsonpath v0.0.0 // indirect - github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect + github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/Masterminds/semver/v3 v3.3.1 // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/ProtonMail/go-crypto v1.1.5 // indirect - github.com/argoproj/pkg v0.13.7-0.20230627120311-a4dd357b057e // indirect + github.com/argoproj/gitops-engine v0.7.1-0.20250521000818-c08b0a72c1f1 // indirect + github.com/argoproj/pkg v0.13.7-0.20250305113207-cbc37dc61de5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect - github.com/bmatcuk/doublestar/v4 v4.7.1 // indirect - github.com/bombsimon/logrusr/v2 v2.0.1 // indirect - github.com/bradleyfalzon/ghinstallation/v2 v2.12.0 // indirect + github.com/bmatcuk/doublestar/v4 v4.8.1 // indirect + github.com/bombsimon/logrusr/v4 v4.1.0 // indirect + github.com/bradleyfalzon/ghinstallation/v2 v2.14.0 // indirect + github.com/casbin/casbin/v2 v2.103.0 // indirect + github.com/casbin/govaluate v1.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect - github.com/cloudflare/circl v1.3.7 // indirect - github.com/cyphar/filepath-securejoin v0.3.6 // indirect + github.com/cloudflare/circl v1.6.0 // indirect + github.com/cyphar/filepath-securejoin v0.4.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/distribution/reference v0.5.0 // indirect - github.com/dlclark/regexp2 v1.11.4 // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/dlclark/regexp2 v1.11.5 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/evanphx/json-patch v5.9.0+incompatible // indirect - github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect + github.com/evanphx/json-patch v5.9.11+incompatible // indirect + github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect github.com/fatih/camelcase v1.0.0 // indirect github.com/fxamacker/cbor/v2 v2.7.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.6.2 // indirect - github.com/go-git/go-git/v5 v5.13.2 // indirect + github.com/go-git/go-git/v5 v5.14.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect @@ -60,14 +62,16 @@ require ( github.com/go-redis/cache/v9 v9.0.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang-jwt/jwt/v4 v4.5.1 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang-jwt/jwt/v4 v4.5.2 // indirect + github.com/golang-jwt/jwt/v5 v5.2.2 // indirect + github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.1.3 // indirect github.com/google/gnostic v0.7.0 // indirect - github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect - github.com/google/go-cmp v0.6.0 // indirect + github.com/google/gnostic-models v0.6.9 // indirect + github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-github/v66 v66.0.0 // indirect + github.com/google/go-github/v69 v69.2.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect @@ -75,16 +79,17 @@ require ( github.com/gorilla/websocket v1.5.3 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect - github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect - github.com/jonboulle/clockwork v0.2.2 // indirect + github.com/jonboulle/clockwork v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect - github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/compress v1.17.11 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect @@ -100,64 +105,66 @@ require ( github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pjbgf/sha1cd v0.3.2 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.20.5 // indirect + github.com/prometheus/client_golang v1.21.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/r3labs/diff v1.1.0 // indirect - github.com/redis/go-redis/v9 v9.6.1 // indirect + github.com/r3labs/diff/v3 v3.0.1 // indirect + github.com/redis/go-redis/v9 v9.7.3 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect - github.com/skeema/knownhosts v1.3.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/objx v0.5.2 // indirect + github.com/skeema/knownhosts v1.3.1 // indirect + github.com/spf13/pflag v1.0.6 // indirect github.com/vmihailenco/go-tinylfu v0.2.2 // indirect - github.com/vmihailenco/msgpack/v5 v5.3.4 // indirect + github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xlab/treeprint v1.2.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 // indirect - go.opentelemetry.io/otel v1.32.0 // indirect - go.opentelemetry.io/otel/metric v1.32.0 // indirect - go.opentelemetry.io/otel/trace v1.32.0 // indirect - go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect - golang.org/x/crypto v0.36.0 // indirect - golang.org/x/mod v0.22.0 // indirect - golang.org/x/net v0.38.0 // indirect - golang.org/x/oauth2 v0.25.0 // indirect - golang.org/x/sync v0.12.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/term v0.30.0 // indirect - golang.org/x/text v0.23.0 // indirect - golang.org/x/time v0.7.0 // indirect - golang.org/x/tools v0.28.0 // indirect - google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect - google.golang.org/grpc v1.70.0 // indirect - google.golang.org/protobuf v1.36.1 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect + go.opentelemetry.io/otel v1.35.0 // indirect + go.opentelemetry.io/otel/metric v1.35.0 // indirect + go.opentelemetry.io/otel/trace v1.35.0 // indirect + golang.org/x/crypto v0.37.0 // indirect + golang.org/x/net v0.39.0 // indirect + golang.org/x/oauth2 v0.28.0 // indirect + golang.org/x/sync v0.13.0 // indirect + golang.org/x/sys v0.32.0 // indirect + golang.org/x/term v0.31.0 // indirect + golang.org/x/text v0.24.0 // indirect + golang.org/x/time v0.11.0 // indirect + google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250219182151-9fdb1cabc7b2 // indirect + google.golang.org/grpc v1.71.0 // indirect + google.golang.org/protobuf v1.36.5 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect - k8s.io/apiserver v0.31.2 // indirect - k8s.io/cli-runtime v0.31.2 // indirect - k8s.io/component-base v0.31.2 // indirect - k8s.io/component-helpers v0.31.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.32.2 // indirect + k8s.io/apiserver v0.32.2 // indirect + k8s.io/cli-runtime v0.32.2 // indirect + k8s.io/component-base v0.32.2 // indirect + k8s.io/component-helpers v0.32.2 // indirect + k8s.io/controller-manager v0.0.0 // indirect k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/kube-aggregator v0.31.2 // indirect - k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect - k8s.io/kubectl v0.31.2 // indirect - k8s.io/kubernetes v1.31.0 // indirect - k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect + k8s.io/kube-aggregator v0.32.2 // indirect + k8s.io/kube-openapi v0.0.0-20250304201544-e5f78fe3ede9 // indirect + k8s.io/kubectl v0.32.2 // indirect + k8s.io/kubernetes v1.32.2 // indirect + k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect oras.land/oras-go/v2 v2.5.0 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect - sigs.k8s.io/kustomize/api v0.17.2 // indirect - sigs.k8s.io/kustomize/kyaml v0.17.1 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.3 // indirect + sigs.k8s.io/kustomize/api v0.18.0 // indirect + sigs.k8s.io/kustomize/kyaml v0.18.1 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) @@ -166,35 +173,35 @@ replace ( github.com/avitaltamir/cyphernetes => github.com/anandf/cyphernetes v0.0.0-20250710140438-434b34c289ab github.com/golang/protobuf => github.com/golang/protobuf v1.5.4 - k8s.io/api => k8s.io/api v0.31.0 - k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.31.0 - k8s.io/apimachinery => k8s.io/apimachinery v0.31.2 - k8s.io/apiserver => k8s.io/apiserver v0.31.0 - k8s.io/cli-runtime => k8s.io/cli-runtime v0.31.0 - k8s.io/client-go => k8s.io/client-go v0.31.0 - k8s.io/cloud-provider => k8s.io/cloud-provider v0.31.0 - k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.31.0 - k8s.io/code-generator => k8s.io/code-generator v0.31.0 - k8s.io/component-base => k8s.io/component-base v0.31.0 - k8s.io/component-helpers => k8s.io/component-helpers v0.31.0 - k8s.io/controller-manager => k8s.io/controller-manager v0.31.0 - k8s.io/cri-api => k8s.io/cri-api v0.31.0 - k8s.io/cri-client => k8s.io/cri-client v0.31.0 - k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.31.0 - k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.31.0 - k8s.io/endpointslice => k8s.io/endpointslice v0.31.0 - k8s.io/kms => k8s.io/kms v0.31.0 - k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.31.0 - k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.31.0 - k8s.io/kube-proxy => k8s.io/kube-proxy v0.31.0 - k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.31.0 - k8s.io/kubectl => k8s.io/kubectl v0.31.0 - k8s.io/kubelet => k8s.io/kubelet v0.31.0 - k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.31.0 - k8s.io/metrics => k8s.io/metrics v0.31.0 - k8s.io/mount-utils => k8s.io/mount-utils v0.31.0 - k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.31.0 - k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.31.0 - k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.31.0 - k8s.io/sample-controller => k8s.io/sample-controller v0.31.0 + k8s.io/api => k8s.io/api v0.32.0 + k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.32.0 + k8s.io/apimachinery => k8s.io/apimachinery v0.32.0 + k8s.io/apiserver => k8s.io/apiserver v0.32.0 + k8s.io/cli-runtime => k8s.io/cli-runtime v0.32.0 + k8s.io/client-go => k8s.io/client-go v0.32.0 + k8s.io/cloud-provider => k8s.io/cloud-provider v0.32.0 + k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.32.0 + k8s.io/code-generator => k8s.io/code-generator v0.32.0 + k8s.io/component-base => k8s.io/component-base v0.32.0 + k8s.io/component-helpers => k8s.io/component-helpers v0.32.0 + k8s.io/controller-manager => k8s.io/controller-manager v0.32.0 + k8s.io/cri-api => k8s.io/cri-api v0.32.0 + k8s.io/cri-client => k8s.io/cri-client v0.32.0 + k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.32.0 + k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.32.0 + k8s.io/endpointslice => k8s.io/endpointslice v0.32.0 + k8s.io/kms => k8s.io/kms v0.32.0 + k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.32.0 + k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.32.0 + k8s.io/kube-proxy => k8s.io/kube-proxy v0.32.0 + k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.32.0 + k8s.io/kubectl => k8s.io/kubectl v0.32.0 + k8s.io/kubelet => k8s.io/kubelet v0.32.0 + k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.32.0 + k8s.io/metrics => k8s.io/metrics v0.32.0 + k8s.io/mount-utils => k8s.io/mount-utils v0.32.0 + k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.32.0 + k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.32.0 + k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.32.0 + k8s.io/sample-controller => k8s.io/sample-controller v0.32.0 ) diff --git a/go.sum b/go.sum index dacffbe..d615dcb 100644 --- a/go.sum +++ b/go.sum @@ -175,9 +175,8 @@ cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZ cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= -cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= +cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= +cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= @@ -601,8 +600,20 @@ gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zum git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= github.com/AvitalTamir/jsonpath v0.0.0 h1:FVEm2hRqG0MYT0IAUEhpk1Y1TPvu9CqBjmg/TGczIgY= github.com/AvitalTamir/jsonpath v0.0.0/go.mod h1:necBB/ZJpGCK75uT4dBEy6+AKekEWeK/fBbT11OgKEg= -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/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 h1:F0gBpfdPLGsw+nsgk6aqqkZS1jiixa5WwFe3fk/T3Ys= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= +github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 h1:H5xDQaE3XowWfhZRUpnfC+rGZMEVoSiji+b+/HFAPU4= +github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= @@ -611,9 +622,8 @@ github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6 github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= 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/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE1FQO4= github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= @@ -621,10 +631,10 @@ github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= -github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= -github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= -github.com/alicebob/miniredis/v2 v2.33.0 h1:uvTF0EDeu9RLnUEG27Db5I68ESoIxTiXbNUiji6lZrA= -github.com/alicebob/miniredis/v2 v2.33.0/go.mod h1:MhP4a3EU7aENRi9aO+tHfTBZicLqQevyi/DJpoj6mi0= +github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE= +github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= +github.com/alicebob/miniredis/v2 v2.34.0 h1:mBFWMaJSNL9RwdGRyEDoAAv8OQc5UlEhLDQggTglU/0= +github.com/alicebob/miniredis/v2 v2.34.0/go.mod h1:kWShP4b58T1CW0Y5dViCd5ztzrDqRWqM3nksiyXk5s8= github.com/anandf/cyphernetes v0.0.0-20250710140438-434b34c289ab h1:+tphEyo7bMY3EFmh3L6X8Ykjy6JHu/VqS6nVvuOABfo= github.com/anandf/cyphernetes v0.0.0-20250710140438-434b34c289ab/go.mod h1:SEfVQWGnKrlk9CVEVyR/0n5OJF9Pl20tsRVD4r0ttD0= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= @@ -634,34 +644,37 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI= github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= -github.com/argoproj/argo-cd/v2 v2.13.5 h1:rnX3gDhSw587P1H8uiNNHqaCCOyG9ue6jihPxbgmRLw= -github.com/argoproj/argo-cd/v2 v2.13.5/go.mod h1:1xggXUniuSkUtcBu0EWl45k1BTuYSASd0bn6WOma4vA= -github.com/argoproj/gitops-engine v0.7.1-0.20250129155113-4c6e03c46314 h1:UIM6b4b/eNmWLwnsaJNmLzcm0qjHCuyHTuJKeIq2WeE= -github.com/argoproj/gitops-engine v0.7.1-0.20250129155113-4c6e03c46314/go.mod h1:b1vuwkyMUszyUK+USUJqC8vJijnQsEPNDpC+sDdDLtM= -github.com/argoproj/pkg v0.13.7-0.20230627120311-a4dd357b057e h1:kuLQvJqwwRMQTheT4MFyKVM8Txncu21CHT4yBWUl1Mk= -github.com/argoproj/pkg v0.13.7-0.20230627120311-a4dd357b057e/go.mod h1:xBN5PLx2MoK63dmPfMo/PGBvd77K1Y0m/rzZOe4cs1s= +github.com/argoproj/argo-cd/v3 v3.0.0 h1:VG3KgvjQqD7nQ/xdPnNrvSz5yLraJxVCMljdkLET46I= +github.com/argoproj/argo-cd/v3 v3.0.0/go.mod h1:JOi2rhOE1zxjhnke8Opotx0fAFkp7Iw2BkLPIXJPWC8= +github.com/argoproj/gitops-engine v0.7.1-0.20250521000818-c08b0a72c1f1 h1:Ze4U6kV49vSzlUBhH10HkO52bYKAIXS4tHr/MlNDfdU= +github.com/argoproj/gitops-engine v0.7.1-0.20250521000818-c08b0a72c1f1/go.mod h1:WsnykM8idYRUnneeT31cM/Fq/ZsjkefCbjiD8ioCJkU= +github.com/argoproj/pkg v0.13.7-0.20250305113207-cbc37dc61de5 h1:YBoLSjpoaJXaXAldVvBRKJuOPvIXz9UOv6S96gMJM/Q= +github.com/argoproj/pkg v0.13.7-0.20250305113207-cbc37dc61de5/go.mod h1:ebVOzFJphdN1p6EG2mIMECv/3Rk/almSaxIYuFAmsSw= 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-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/aws/aws-sdk-go v1.44.290/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 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/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/bmatcuk/doublestar/v4 v4.7.1 h1:fdDeAqgT47acgwd9bd9HxJRDmc9UAmPpc+2m0CXv75Q= -github.com/bmatcuk/doublestar/v4 v4.7.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= -github.com/bombsimon/logrusr/v2 v2.0.1 h1:1VgxVNQMCvjirZIYaT9JYn6sAVGVEcNtRE0y4mvaOAM= -github.com/bombsimon/logrusr/v2 v2.0.1/go.mod h1:ByVAX+vHdLGAfdroiMg6q0zgq2FODY2lc5YJvzmOJio= +github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= +github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38= +github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= +github.com/bombsimon/logrusr/v4 v4.1.0 h1:uZNPbwusB0eUXlO8hIUwStE6Lr5bLN6IgYgG+75kuh4= +github.com/bombsimon/logrusr/v4 v4.1.0/go.mod h1:pjfHC5e59CvjTBIU3V3sGhFWFAnsnhOR03TRc6im0l8= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/bradleyfalzon/ghinstallation/v2 v2.12.0 h1:k8oVjGhZel2qmCUsYwSE34jPNT9DL2wCBOtugsHv26g= -github.com/bradleyfalzon/ghinstallation/v2 v2.12.0/go.mod h1:V4gJcNyAftH0rXpRp1SUVUuh+ACxOH1xOk/ZzkRHltg= +github.com/bradleyfalzon/ghinstallation/v2 v2.14.0 h1:0D4vKCHOvYrDU8u61TnE2JfNT4VRrBLphmxtqazTO+M= +github.com/bradleyfalzon/ghinstallation/v2 v2.14.0/go.mod h1:LOVmdZYVZ8jqdr4n9wWm1ocDiMz9IfMGfRkaYC1a52A= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/casbin/casbin/v2 v2.103.0 h1:dHElatNXNrr8XcseUov0ZSiWjauwmZZE6YMV3eU1yic= +github.com/casbin/casbin/v2 v2.103.0/go.mod h1:Ee33aqGrmES+GNL17L0h9X28wXuo829wnNUnS0edAco= +github.com/casbin/govaluate v1.3.0 h1:VA0eSY0M2lA86dYd5kPPuNZMUD9QkWnOCnavGrw9myc= +github.com/casbin/govaluate v1.3.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A= 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/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= @@ -672,18 +685,12 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.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/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= -github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs= -github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= -github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk= +github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= 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= @@ -696,29 +703,26 @@ github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= 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.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM= -github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= +github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= +github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -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/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= -github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= +github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/elazarl/goproxy v1.4.0 h1:4GyuSbFa+s26+3rmYNSuUVsx+HgPrV1bk1jXI0l9wjM= -github.com/elazarl/goproxy v1.4.0/go.mod h1:X/5W/t+gzDyLfHW4DrMdpjqYjpXsURlBt9lpBDxZZZQ= -github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o= +github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= @@ -736,20 +740,19 @@ github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= -github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls= -github.com/evanphx/json-patch v5.9.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/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8= +github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4= +github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc= 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/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -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/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -768,38 +771,27 @@ github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UN github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= 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.13.2 h1:7O7xvsK7K+rZPKW6AQR1YyNhfywkv7B8/FsP3ki6Zv0= -github.com/go-git/go-git/v5 v5.13.2/go.mod h1:hWdW5P4YZRjmpGHwRH2v3zkWcNl6HeXaXQEMGb3NJ9A= +github.com/go-git/go-git/v5 v5.14.0 h1:/MD3lCrGjCen5WfEAzKg00MJJffKhC8gzS80ycmCi60= +github.com/go-git/go-git/v5 v5.14.0/go.mod h1:Z5Xhoia5PcWA3NF8vRLURn9E5FRhSl7dGj9ItW3Wk5k= 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-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= -github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= +github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= +github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v1.0.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= @@ -809,32 +801,29 @@ github.com/go-playground/webhooks/v6 v6.4.0/go.mod h1:5lBxopx+cAJiBI4+kyRbuHrEi+ github.com/go-redis/cache/v9 v9.0.0 h1:0thdtFo0xJi0/WXbRVu8B066z8OvVymXTJGaXrVWnN0= github.com/go-redis/cache/v9 v9.0.0/go.mod h1:cMwi1N8ASBOufbIvk7cdXe2PbPjK/WMRL95FFHWsSgI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-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-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= 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/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= -github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/gogits/go-gogs-client v0.0.0-20200905025246-8bb8a50cb355 h1:HTVNOdTWO/gHYeFnr/HwpYwY6tgMcYd+Rgf1XrHnORY= -github.com/gogits/go-gogs-client v0.0.0-20200905025246-8bb8a50cb355/go.mod h1:cY2AIrMgHm6oOHmR7jY+9TtjzSjQ3iG7tURJG3Y6XH0= +github.com/gogits/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 h1:04sojTxgYxu1L4Hn7Tgf7UVtIosVa6CuHtvNY+7T1K4= +github.com/gogits/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85/go.mod h1:cY2AIrMgHm6oOHmR7jY+9TtjzSjQ3iG7tURJG3Y6XH0= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= -github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 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/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= 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= @@ -851,15 +840,14 @@ github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 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/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/gnostic v0.7.0 h1:d7EpuFp8vVdML+y0JJJYiKeOLjKTdH/GvVkLOBWqJpw= github.com/google/gnostic v0.7.0/go.mod h1:IAcUyMl6vtC95f60EZ8oXyqTsOersP6HbwjeG7EyDPM= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= -github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 h1:0VpGH+cDhbDtdcweoyCVsF3fhN8kejK6rFe/2FFX2nU= github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49/go.mod h1:BkkQ4L1KS1xMt2aWSPStnn55ChGC0DPOn2FQYj+f25M= +github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= +github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -875,14 +863,15 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ 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-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-github/v66 v66.0.0 h1:ADJsaXj9UotwdgK8/iFZtv7MLc8E8WBl62WLd/D/9+M= github.com/google/go-github/v66 v66.0.0/go.mod h1:+4SO9Zkuyf8ytMj0csN1NR/5OTR+MfqPp8P8dVlcvY4= +github.com/google/go-github/v69 v69.2.0 h1:wR+Wi/fN2zdUx9YxSmYE0ktiX9IAR/BeePzeaUUbEHE= +github.com/google/go-github/v69 v69.2.0/go.mod h1:xne4jymxLR6Uj9b7J7PyTpkMYstEMMwGZa0Aehh1azM= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -906,8 +895,6 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe 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-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= -github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= @@ -935,14 +922,14 @@ github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57Q github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= @@ -953,18 +940,12 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/iancoleman/strcase v0.2.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-20240312041847-bd984b5ce465/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= -github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= -github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= 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/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= -github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= +github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -977,20 +958,17 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNU github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= 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/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= +github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= 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/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -1003,7 +981,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= 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/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY= @@ -1017,12 +994,8 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= -github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= -github.com/minio/minio-go/v7 v7.0.58/go.mod h1:NUDy4A4oXPq1l2yK6LTSvCEzAMeIcoz9lcj5dbzSrRE= -github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= 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/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= @@ -1034,7 +1007,6 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= -github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 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/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= @@ -1042,7 +1014,6 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+ github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852/go.mod h1:eqOVx5Vwu4gd2mmMZvVZsgIqNSaW3xxRThUJ0k/TPk4= 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/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= @@ -1055,17 +1026,6 @@ github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8Ay github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo= github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw= github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo= -github.com/onsi/ginkgo/v2 v2.8.1/go.mod h1:N1/NbDngAFcSLdyZ+/aYTYGSlq9qMCS/cNKGJjy+csc= -github.com/onsi/ginkgo/v2 v2.9.0/go.mod h1:4xkjoL/tZv4SMWeww56BU5kAt19mVB47gTWxmrTcxyk= -github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo= -github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= -github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= -github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= -github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= -github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= -github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= -github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= -github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= @@ -1078,17 +1038,6 @@ github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM= github.com/onsi/gomega v1.25.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= -github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= -github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw= -github.com/onsi/gomega v1.27.3/go.mod h1:5vG284IBtfDAmDyrK+eGyZmUgUlmi+Wngqo557cZ6Gw= -github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= -github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= -github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ= -github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= -github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= -github.com/onsi/gomega v1.33.0/go.mod h1:+925n5YtiFsLzzafLUHzVMBpvvRAzrydIBiSIxjX3wY= -github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= @@ -1096,7 +1045,6 @@ github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3I github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= @@ -1107,6 +1055,8 @@ github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -1116,21 +1066,21 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR 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/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= -github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= +github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= 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.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/r3labs/diff v1.1.0 h1:V53xhrbTHrWFWq3gI4b94AjgEJOerO1+1l0xyHOBi8M= -github.com/r3labs/diff v1.1.0/go.mod h1:7WjXasNzi0vJetRcB/RqNl5dlIsmXcTTLmF5IoH6Xig= +github.com/r3labs/diff/v3 v3.0.1 h1:CBKqf3XmNRHXKmdU7mZP1w7TV0pDyVCis1AUHtA4Xtg= +github.com/r3labs/diff/v3 v3.0.1/go.mod h1:f1S9bourRbiM66NskseyUdo0fTmEE0qKrikYJX63dgo= github.com/redis/go-redis/v9 v9.0.0-rc.4/go.mod h1:Vo3EsyWnicKnSKCA7HhgnvnyA74wOA69Cd2Meli5mmA= -github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4= -github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA= +github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM= +github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= @@ -1138,9 +1088,8 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= 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/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= @@ -1149,21 +1098,18 @@ github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= 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.2/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.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY= -github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M= +github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= +github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 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.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -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/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -1180,14 +1126,13 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ 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/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/vmihailenco/go-tinylfu v0.2.2 h1:H1eiG6HM36iniK6+21n9LLpzx1G9R3DJa2UjUjbynsI= github.com/vmihailenco/go-tinylfu v0.2.2/go.mod h1:CutYi2Q9puTxfcolkliPq4npPuofg9N9t8JVrjzwa3Q= -github.com/vmihailenco/msgpack/v5 v5.3.4 h1:qMKAwOV+meBw2Y8k9cVwAy7qErtYCwBzZ2ellBfvnqc= github.com/vmihailenco/msgpack/v5 v5.3.4/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= +github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= @@ -1218,22 +1163,22 @@ 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/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 h1:hCq2hNMwsegUvPzI7sPOvtO9cqyy5GbWt/Ybp2xrx8Q= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0/go.mod h1:LqaApwGx/oUmzsbqxkzuBvyoPpkxk3JQWnqfVrJ3wCA= -go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= -go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= -go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= -go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= -go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= -go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= -go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU= -go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= -go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= -go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4= +go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= +go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= +go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= +go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= +go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -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.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -1251,21 +1196,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/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.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= -golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= +golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1324,14 +1256,6 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= -golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 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= @@ -1394,21 +1318,8 @@ golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.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.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= +golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1437,9 +1348,8 @@ golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= -golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70= -golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= +golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= 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= @@ -1456,13 +1366,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= +golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1515,7 +1420,6 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w 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-20210608053332-aa57babbf139/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= @@ -1532,7 +1436,6 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc 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-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/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= @@ -1543,7 +1446,6 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc 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-20220704084225-05e143d24a9e/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= @@ -1555,47 +1457,18 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.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.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/telemetry v0.0.0-20240208230135-b75ee8823808/go.mod h1:KG1lNk5ZFNssSZLrpVb4sMXKMpGwGXOxSG3rnu2gZQQ= -golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= +golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 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.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= 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.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= -golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= -golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= -golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= -golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= -golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= -golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= +golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= +golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= 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= @@ -1611,24 +1484,16 @@ golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.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.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= -golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= +golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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= @@ -1696,17 +1561,6 @@ golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= -golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= -golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= -golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= -golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= -golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= -golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= -golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= -golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1923,16 +1777,16 @@ google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOl google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL5hZrHzQceCwuSYwZZ5QZBazOcprJ5rgs3lY= google.golang.org/genproto v0.0.0-20230526161137-0005af68ea54/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk= -google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY= -google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a h1:OAiGFfOiA0v9MRYsSidp3ubZaBnteRUyn3xB2ZQ5G/E= -google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a/go.mod h1:jehYqy3+AhJU9ve55aNOaSml7wUXjF9x6z2LcCfpAhY= +google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 h1:GVIKPyP/kLIyVOgOnTwFOrvQaQUzOzGMCxgFUOEmm24= +google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422/go.mod h1:b6h1vNKhxaSoEI+5jc3PJUCustfli/mRab7295pY7rw= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a h1:hgh8P4EuoxpsuKMXX/To36nOFD7vixReXgn8lPGnt+o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250219182151-9fdb1cabc7b2 h1:DMTIbak9GhdaSxEjvVzAeNZvyc03I61duqNbnm3SU0M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250219182151-9fdb1cabc7b2/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= 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= @@ -1972,8 +1826,8 @@ google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCD google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= -google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= -google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= +google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg= +google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 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= @@ -1987,9 +1841,8 @@ google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= +google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 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= @@ -2001,7 +1854,6 @@ gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWM gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 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.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= @@ -2025,42 +1877,36 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt 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= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= -k8s.io/api v0.31.0 h1:b9LiSjR2ym/SzTOlfMHm1tr7/21aD7fSkqgD/CVJBCo= -k8s.io/api v0.31.0/go.mod h1:0YiFF+JfFxMM6+1hQei8FY8M7s1Mth+z/q7eF1aJkTE= -k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk= -k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk= -k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= -k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -k8s.io/apiserver v0.31.0 h1:p+2dgJjy+bk+B1Csz+mc2wl5gHwvNkC9QJV+w55LVrY= -k8s.io/apiserver v0.31.0/go.mod h1:KI9ox5Yu902iBnnyMmy7ajonhKnkeZYJhTZ/YI+WEMk= -k8s.io/cli-runtime v0.31.0 h1:V2Q1gj1u3/WfhD475HBQrIYsoryg/LrhhK4RwpN+DhA= -k8s.io/cli-runtime v0.31.0/go.mod h1:vg3H94wsubuvWfSmStDbekvbla5vFGC+zLWqcf+bGDw= -k8s.io/client-go v0.31.0 h1:QqEJzNjbN2Yv1H79SsS+SWnXkBgVu4Pj3CJQgbx0gI8= -k8s.io/client-go v0.31.0/go.mod h1:Y9wvC76g4fLjmU0BA+rV+h2cncoadjvjjkkIGoTLcGU= -k8s.io/component-base v0.31.0 h1:/KIzGM5EvPNQcYgwq5NwoQBaOlVFrghoVGr8lG6vNRs= -k8s.io/component-base v0.31.0/go.mod h1:TYVuzI1QmN4L5ItVdMSXKvH7/DtvIuas5/mm8YT3rTo= -k8s.io/component-helpers v0.31.0 h1:jyRUKA+GX+q19o81k4x94imjNICn+e6Gzi6T89va1/A= -k8s.io/component-helpers v0.31.0/go.mod h1:MrNIvT4iB7wXIseYSWfHUJB/aNUiFvbilp4qDfBQi6s= -k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70/go.mod h1:VH3AT8AaQOqiGjMF9p0/IM1Dj+82ZwjfxUP1IxaHE+8= -k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.5.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/api v0.32.0 h1:OL9JpbvAU5ny9ga2fb24X8H6xQlVp+aJMFlgtQjR9CE= +k8s.io/api v0.32.0/go.mod h1:4LEwHZEf6Q/cG96F3dqR965sYOfmPM7rq81BLgsE0p0= +k8s.io/apiextensions-apiserver v0.32.0 h1:S0Xlqt51qzzqjKPxfgX1xh4HBZE+p8KKBq+k2SWNOE0= +k8s.io/apiextensions-apiserver v0.32.0/go.mod h1:86hblMvN5yxMvZrZFX2OhIHAuFIMJIZ19bTvzkP+Fmw= +k8s.io/apimachinery v0.32.0 h1:cFSE7N3rmEEtv4ei5X6DaJPHHX0C+upp+v5lVPiEwpg= +k8s.io/apimachinery v0.32.0/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= +k8s.io/apiserver v0.32.0 h1:VJ89ZvQZ8p1sLeiWdRJpRD6oLozNZD2+qVSLi+ft5Qs= +k8s.io/apiserver v0.32.0/go.mod h1:HFh+dM1/BE/Hm4bS4nTXHVfN6Z6tFIZPi649n83b4Ag= +k8s.io/cli-runtime v0.32.0 h1:dP+OZqs7zHPpGQMCGAhectbHU2SNCuZtIimRKTv2T1c= +k8s.io/cli-runtime v0.32.0/go.mod h1:Mai8ht2+esoDRK5hr861KRy6z0zHsSTYttNVJXgP3YQ= +k8s.io/client-go v0.32.0 h1:DimtMcnN/JIKZcrSrstiwvvZvLjG0aSxy8PxN8IChp8= +k8s.io/client-go v0.32.0/go.mod h1:boDWvdM1Drk4NJj/VddSLnx59X3OPgwrOo0vGbtq9+8= +k8s.io/component-base v0.32.0 h1:d6cWHZkCiiep41ObYQS6IcgzOUQUNpywm39KVYaUqzU= +k8s.io/component-base v0.32.0/go.mod h1:JLG2W5TUxUu5uDyKiH2R/7NnxJo1HlPoRIIbVLkK5eM= +k8s.io/component-helpers v0.32.0 h1:pQEEBmRt3pDJJX98cQvZshDgJFeKRM4YtYkMmfOlczw= +k8s.io/component-helpers v0.32.0/go.mod h1:9RuClQatbClcokXOcDWSzFKQm1huIf0FzQlPRpizlMc= +k8s.io/controller-manager v0.32.0 h1:tpQl1rvH4huFB6Avl1nhowZHtZoCNWqn6OYdZPl7Ybc= +k8s.io/controller-manager v0.32.0/go.mod h1:JRuYnYCkKj3NgBTy+KNQKIUm/lJRoDAvGbfdEmk9LhY= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-aggregator v0.31.0 h1:3DqSpmqHF8rey7fY+qYXLJms0tYPhxrgWvjpnKVnS0Y= -k8s.io/kube-aggregator v0.31.0/go.mod h1:Fa+OVSpMQC7zbTTz7/QG7FXe9jZ8usuJQej5sMdCrkM= -k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= -k8s.io/kubectl v0.31.0 h1:kANwAAPVY02r4U4jARP/C+Q1sssCcN/1p9Nk+7BQKVg= -k8s.io/kubectl v0.31.0/go.mod h1:pB47hhFypGsaHAPjlwrNbvhXgmuAr01ZBvAIIUaI8d4= -k8s.io/kubernetes v1.31.0 h1:sYAB12TTWexXKp4RxqJMm/7EC+P0mNOgn4Xdj5eu7HM= -k8s.io/kubernetes v1.31.0/go.mod h1:UTpGn7nxrUrPWw5hNIYTAjodcWIvLakgHpLtfrr6GC8= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= -k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/kube-aggregator v0.32.0 h1:5ZyMW3QwAbmkasQrROcpa5we3et938DQuyUYHeXSPao= +k8s.io/kube-aggregator v0.32.0/go.mod h1:6OKivf6Ypx44qu2v1ZUMrxH8kRp/8LKFKeJU72J18lU= +k8s.io/kube-openapi v0.0.0-20250304201544-e5f78fe3ede9 h1:t0huyHnz6HsokckRxAF1bY0cqPFwzINKCL7yltEjZQc= +k8s.io/kube-openapi v0.0.0-20250304201544-e5f78fe3ede9/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= +k8s.io/kubectl v0.32.0 h1:rpxl+ng9qeG79YA4Em9tLSfX0G8W0vfaiPVrc/WR7Xw= +k8s.io/kubectl v0.32.0/go.mod h1:qIjSX+QgPQUgdy8ps6eKsYNF+YmFOAO3WygfucIqFiE= +k8s.io/kubernetes v1.32.2 h1:mShetlA102UpjRVSGzB+5vjJwy8oPy8FMWrkTH5f37o= +k8s.io/kubernetes v1.32.2/go.mod h1:tiIKO63GcdPRBHW2WiUFm3C0eoLczl3f7qi56Dm1W8I= +k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0= +k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= @@ -2101,17 +1947,16 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 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/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= -sigs.k8s.io/kustomize/api v0.17.2 h1:E7/Fjk7V5fboiuijoZHgs4aHuexi5Y2loXlVOAVAG5g= -sigs.k8s.io/kustomize/api v0.17.2/go.mod h1:UWTz9Ct+MvoeQsHcJ5e+vziRRkwimm3HytpZgIYqye0= -sigs.k8s.io/kustomize/kyaml v0.17.1 h1:TnxYQxFXzbmNG6gOINgGWQt09GghzgTP6mIurOgrLCQ= -sigs.k8s.io/kustomize/kyaml v0.17.1/go.mod h1:9V0mCjIEYjlXuCdYsSXvyoy2BTsLESH7TlGV81S282U= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/structured-merge-diff/v4 v4.4.3 h1:sCP7Vv3xx/CWIuTPVN38lUPx0uw0lcLfzaiDa8Ja01A= -sigs.k8s.io/structured-merge-diff/v4 v4.4.3/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sigs.k8s.io/kustomize/api v0.18.0 h1:hTzp67k+3NEVInwz5BHyzc9rGxIauoXferXyjv5lWPo= +sigs.k8s.io/kustomize/api v0.18.0/go.mod h1:f8isXnX+8b+SGLHQ6yO4JG1rdkZlvhaCf/uZbLVMb0U= +sigs.k8s.io/kustomize/kyaml v0.18.1 h1:WvBo56Wzw3fjS+7vBjN6TeivvpbW9GmRaWZ9CIVmt4E= +sigs.k8s.io/kustomize/kyaml v0.18.1/go.mod h1:C3L2BFVU1jgcddNBE1TxuVLgS46TjObMwW5FT9FcjYo= +sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= +sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= 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/operator/common.go b/operator/common.go index df1a502..b66a654 100644 --- a/operator/common.go +++ b/operator/common.go @@ -11,8 +11,10 @@ import ( "time" "github.com/anandf/resource-tracker/pkg/argocd" + "github.com/anandf/resource-tracker/pkg/common" "github.com/anandf/resource-tracker/pkg/graph" "github.com/anandf/resource-tracker/pkg/kube" + argocdcommon "github.com/argoproj/argo-cd/v3/common" log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -45,7 +47,7 @@ type BaseControllerConfig struct { type BaseController struct { dynamicClient dynamic.Interface restConfig *rest.Config - previousGroupedKinds graph.GroupedResourceKinds + previousGroupedKinds common.GroupedResourceKinds queryServers map[string]*graph.QueryServer argoCDClient argocd.ArgoCD lastRunTime time.Time @@ -70,7 +72,15 @@ func newBaseController(cfg *BaseControllerConfig) (*BaseController, error) { return nil, err } clusterConfigs = append(clusterConfigs, restConfig) - argoClient, err := argocd.NewArgoCD(restConfig, cfg.argocdNamespace) + argoClient, err := argocd.NewArgoCD( + restConfig, + cfg.argocdNamespace, + "", + argocdcommon.DefaultRepoServerAddr, + 10, + false, + false, + ) if err != nil { return nil, err } @@ -201,12 +211,12 @@ func listClusterConfigs(dynamicClient dynamic.Interface, argocdNS string) ([]*re } // handleUpdateInArgoCDCR handles the update of resource.inclusions settings in ArgoCD CustomResource -func handleUpdateInArgoCDCR(argoCDClient argocd.ArgoCD, resourceName, resourceNamespace string, groupedKinds graph.GroupedResourceKinds) error { +func handleUpdateInArgoCDCR(argoCDClient argocd.ArgoCD, resourceName, resourceNamespace string, groupedKinds common.GroupedResourceKinds) error { currentResourceInclusions, err := argoCDClient.GetCurrentResourceInclusions(&graph.ArgoCDGVR, resourceName, resourceNamespace) if err != nil { return err } - existingGroupKinds := make(graph.GroupedResourceKinds) + existingGroupKinds := make(common.GroupedResourceKinds) err = existingGroupKinds.FromYaml(currentResourceInclusions) if err != nil { return err @@ -224,12 +234,12 @@ func handleUpdateInArgoCDCR(argoCDClient argocd.ArgoCD, resourceName, resourceNa } // handleUpdateInCM handles the update of resource.inclusions settings in argocd-cm ConfigMap -func handleUpdateInCM(argoCDClient argocd.ArgoCD, resourceNamespace string, groupedKinds graph.GroupedResourceKinds) error { +func handleUpdateInCM(argoCDClient argocd.ArgoCD, resourceNamespace string, groupedKinds common.GroupedResourceKinds) error { currentResourceInclusions, err := argoCDClient.GetCurrentResourceInclusions(&graph.ConfigMapGVR, "argocd-cm", resourceNamespace) if err != nil { return err } - existingGroupKinds := make(graph.GroupedResourceKinds) + existingGroupKinds := make(common.GroupedResourceKinds) err = existingGroupKinds.FromYaml(currentResourceInclusions) if err != nil { return err diff --git a/operator/graphquery.go b/operator/graphquery.go index 132d863..e9959cf 100644 --- a/operator/graphquery.go +++ b/operator/graphquery.go @@ -5,8 +5,8 @@ import ( "strings" "time" + "github.com/anandf/resource-tracker/pkg/common" "github.com/anandf/resource-tracker/pkg/env" - "github.com/anandf/resource-tracker/pkg/graph" "github.com/anandf/resource-tracker/pkg/version" "github.com/avitaltamir/cyphernetes/pkg/core" log "github.com/sirupsen/logrus" @@ -81,22 +81,22 @@ func (g *GraphQueryController) execute() error { log.Info("skipping query executor due to last run not lapsed the check interval") return nil } - var allAppChildren []graph.ResourceInfo + var allAppChildren []*common.ResourceInfo g.lastRunTime = time.Now() for host, qs := range g.queryServers { log.Infof("Querying Argo CD application globally for application in host %s", host) - qs.VisitedKinds = make(map[graph.ResourceInfo]bool) + qs.VisitedKinds = make(map[common.ResourceInfo]bool) appChildren, err := qs.GetApplicationChildResources("", "") if err != nil { return err } log.Infof("Children of Argo CD application globally for application: %v", appChildren) for appChild := range appChildren { - allAppChildren = append(allAppChildren, appChild) + allAppChildren = append(allAppChildren, &appChild) } } - groupedKinds := make(graph.GroupedResourceKinds) + groupedKinds := make(common.GroupedResourceKinds) groupedKinds.MergeResourceInfos(allAppChildren) missingResources, err := g.argoCDClient.GetAllMissingResources() if err != nil { @@ -105,10 +105,10 @@ func (g *GraphQueryController) execute() error { // Check if additional resources are missing, if so add it. for _, resource := range missingResources { log.Infof("adding missing resource '%v'", resource) - if kindMap, ok := groupedKinds[resource.APIVersion]; !ok && kindMap == nil { - groupedKinds[resource.APIVersion] = graph.Kinds{resource.Kind: graph.Void{}} + if kindMap, ok := groupedKinds[resource.Group]; !ok && kindMap == nil { + groupedKinds[resource.Group] = common.Kinds{resource.Kind: common.Void{}} } else { - groupedKinds[resource.APIVersion][resource.Kind] = graph.Void{} + groupedKinds[resource.Group][resource.Kind] = common.Void{} } } if !*g.cfg.updateEnabled { diff --git a/operator/main.go b/operator/main.go index 0681679..85b6501 100644 --- a/operator/main.go +++ b/operator/main.go @@ -14,7 +14,6 @@ func newRootCommand() error { } rootCmd.AddCommand(newGraphQueryCommand()) - rootCmd.AddCommand(newRunCommand()) err := rootCmd.Execute() return err } diff --git a/operator/reposerver.go b/operator/reposerver.go deleted file mode 100644 index 0d1d1aa..0000000 --- a/operator/reposerver.go +++ /dev/null @@ -1,220 +0,0 @@ -package main - -import ( - "context" - "fmt" - "strings" - "sync" - "time" - - "github.com/anandf/resource-tracker/pkg/argocd" - "github.com/anandf/resource-tracker/pkg/env" - "github.com/anandf/resource-tracker/pkg/graph" - "github.com/anandf/resource-tracker/pkg/version" - "github.com/argoproj/argo-cd/v2/common" - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" - "github.com/avitaltamir/cyphernetes/pkg/core" - log "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/client-go/rest" -) - -type RepoServerQueryController struct { - *BaseController - cfg *RepoServerQueryControllerConfig - repoClient *argocd.RepoServerManager -} - -type RepoServerQueryControllerConfig struct { - BaseControllerConfig - repoServerAddress string - repoServerPlaintext bool - repoServerStrictTLS bool - repoServerTimeoutSeconds int -} - -type manifestResponse struct { - children []*unstructured.Unstructured - destinationConfig *rest.Config - appName string -} - -// newRunCommand implements "runQuery" command which executes a cyphernetes graph query against a given kubeconfig -func newRunCommand() *cobra.Command { - cfg := &RepoServerQueryControllerConfig{} - var runCmd = &cobra.Command{ - Use: "run", - Short: "Runs the resource-tracker which executes a graph based query to fetch the dependencies", - RunE: func(cmd *cobra.Command, args []string) error { - log.Infof("%s %s starting [loglevel:%s, interval:%s]", - fmt.Sprintf("%s-%s", version.BinaryName(), "operator"), - version.Version(), - strings.ToUpper(cfg.logLevel), - cfg.checkInterval, - ) - var err error - level, err := log.ParseLevel(cfg.logLevel) - if err != nil { - return fmt.Errorf("failed to parse log level: %w", err) - } - log.SetLevel(level) - core.LogLevel = cfg.logLevel - controller, err := newRepoServerQueryController(cfg) - if err != nil { - return err - } - return initApplicationInformer(controller.dynamicClient, controller) - }, - } - runCmd.Flags().StringVar(&cfg.logLevel, "loglevel", env.GetStringVal("RESOURCE_TRACKER_LOGLEVEL", "info"), "set the loglevel to one of trace|debug|info|warn|error") - runCmd.Flags().StringVar(&cfg.kubeConfig, "kubeconfig", "", "full path to kube client configuration, i.e. ~/.kube/config") - runCmd.Flags().StringVar(&cfg.argocdNamespace, "argocd-namespace", "argocd", "namespace where argocd control plane components are running") - cfg.updateEnabled = runCmd.Flags().Bool("update-enabled", false, "if enabled updates the argocd-cm directly, else prints the output on screen") - runCmd.Flags().StringVar(&cfg.updateResourceName, "update-resource-name", "argocd-cm", "name of the resource that needs to be updated. Default: argocd-cm") - runCmd.Flags().StringVar(&cfg.updateResourceKind, "update-resource-kind", "ConfigMap", "kind of resource that needs to be updated, "+ - "users can choose to update either spec.data in argocd-cm or spec.extraConfigs in ArgoCD resource, Default: ConfigMap") - runCmd.Flags().DurationVar(&cfg.checkInterval, "interval", DefaultCheckInterval, "interval for how often to check for updates, "+ - "to avoid frequent execution of compute and memory intensive graph queries") - runCmd.Flags().StringVar(&cfg.repoServerAddress, "repo-server", env.GetStringVal("ARGOCD_REPO_SERVER", common.DefaultRepoServerAddr), "Repo server address.") - runCmd.Flags().IntVar(&cfg.repoServerTimeoutSeconds, "repo-server-timeout-seconds", 60, "Repo server RPC call timeout seconds.") - runCmd.Flags().BoolVar(&cfg.repoServerPlaintext, "repo-server-plaintext", false, "Disable TLS on connections to repo server, Default: false") - runCmd.Flags().BoolVar(&cfg.repoServerStrictTLS, "repo-server-strict-tls", false, "Whether to use strict validation of the TLS cert presented by the repo server, Default: false") - - return runCmd -} - -func newRepoServerQueryController(cfg *RepoServerQueryControllerConfig) (*RepoServerQueryController, error) { - base, err := newBaseController(&cfg.BaseControllerConfig) - if err != nil { - return nil, err - } - repoClient, err := argocd.NewRepoServerManager(base.restConfig, cfg.argocdNamespace, cfg.repoServerAddress, cfg.repoServerTimeoutSeconds, - cfg.repoServerPlaintext, cfg.repoServerStrictTLS) - if err != nil { - return nil, err - } - return &RepoServerQueryController{ - BaseController: base, - cfg: cfg, - repoClient: repoClient, - }, nil -} - -// execute runs the graph query, computes the resources managed via Argo CD and update the resource.inclusions -// settings in the argocd-cm config map if it detects any new changes compared to the previous computed value or if its -// value is different from what is present in the argocd-cm config map. -// if the check interval time has not passed since the previous run, then the method returns without executing any queries. -func (r *RepoServerQueryController) execute() error { - if !r.lastRunTime.IsZero() && time.Since(r.lastRunTime) < r.cfg.checkInterval { - log.Info("skipping query executor due to last run not lapsed the check interval") - return nil - } - r.lastRunTime = time.Now() - log.Info("Starting resource tracking process...") - apps, err := r.argoCDClient.ListApplications() - if err != nil { - log.Fatalf("Error while listing applications: %v", err) - } - log.Infof("Fetched %d applications", len(apps)) - resourceChan := make(chan manifestResponse) - errChan := make(chan error) - allAppChildren := make([]manifestResponse, 0) - // Launch consumer (Tracker) - go startResourceTrackerConsumer(resourceChan, &allAppChildren) - var wg sync.WaitGroup - for _, app := range apps { - wg.Add(1) - go func(app v1alpha1.Application) { - log.Infof("processing application: %s", app.Name) - defer wg.Done() - appProject, err := r.argoCDClient.GetAppProject(app) - if err != nil { - errChan <- err - return - } - // Get target object from repo-server - targetObjs, destinationConfig, err := r.repoClient.GetApplicationChildManifests(context.Background(), &app, appProject) - if err != nil { - errChan <- err - return - } - resourceChan <- manifestResponse{ - children: targetObjs, - destinationConfig: destinationConfig, - appName: app.Name, - } - log.Infof("Fetched target manifests from repo-server for application: %s", app.Name) - }(app) - } - // Handle processing errors - go func() { - for err := range errChan { - log.Errorf("Error processing application: %v", err) - } - }() - log.Info("Resource tracking initiated for all applications.") - wg.Wait() - close(resourceChan) - log.Info("Resource channel has been closed. Resource Tracker process has completed successfully.") - var nestedResources = make([]graph.ResourceInfo, 0) - for _, appChild := range allAppChildren { - appGroupedResources, err := r.argoCDClient.ProcessApplication(appChild.children, appChild.appName, appChild.destinationConfig) - if err != nil { - return fmt.Errorf("error processing application: %w", err) - } - nestedResources = append(nestedResources, appGroupedResources...) - } - groupedKinds := make(graph.GroupedResourceKinds) - groupedKinds.MergeResourceInfos(nestedResources) - missingResources, err := r.argoCDClient.GetAllMissingResources() - if err != nil { - return fmt.Errorf("error while fetching missing resources: %v", err) - } - // Check if additional resources are missing, if so add it. - for _, resource := range missingResources { - log.Infof("adding missing resource '%v'", resource) - if kindMap, ok := groupedKinds[resource.APIVersion]; !ok && kindMap == nil { - groupedKinds[resource.APIVersion] = graph.Kinds{resource.Kind: graph.Void{}} - } else { - groupedKinds[resource.APIVersion][resource.Kind] = graph.Void{} - } - } - - if !*r.cfg.updateEnabled { - if !r.previousGroupedKinds.Equal(&groupedKinds) { - log.Info("direct update or argocd-cm is disabled, printing the output on terminal") - resourceInclusionString := groupedKinds.String() - if strings.HasPrefix(resourceInclusionString, "error:") { - return fmt.Errorf("error in yaml string of resource.inclusions: %s", resourceInclusionString) - } - fmt.Printf("resource.inclusions: |\n%sresource.exclusions: ''\n", resourceInclusionString) - } else { - log.Infof("no changes detected in previously computed resource inclusions and current computed resource inclusions") - } - } else { - if r.cfg.updateResourceKind == ArgoCDResourceKind { - err = handleUpdateInArgoCDCR(r.argoCDClient, r.cfg.updateResourceName, r.cfg.argocdNamespace, groupedKinds) - if err != nil { - return err - } - } else { - err = handleUpdateInCM(r.argoCDClient, r.cfg.argocdNamespace, groupedKinds) - if err != nil { - return err - } - } - } - r.previousGroupedKinds = groupedKinds - return nil -} - -func startResourceTrackerConsumer(resourceChan <-chan manifestResponse, allAppChildren *[]manifestResponse) { - // Process resources from the channel - // and update the tracked resources in the config - // This is a blocking call, so it will keep running until the channel is closed - for groupedResources := range resourceChan { - *allAppChildren = append(*allAppChildren, groupedResources) - } - -} diff --git a/pkg/analyzer/dynamic/backend.go b/pkg/analyzer/dynamic/backend.go new file mode 100644 index 0000000..b67c94c --- /dev/null +++ b/pkg/analyzer/dynamic/backend.go @@ -0,0 +1,222 @@ +package dynamicbackend + +import ( + "context" + "fmt" + "sync" + + "github.com/anandf/resource-tracker/pkg/analyzer" + "github.com/anandf/resource-tracker/pkg/argocd" + "github.com/anandf/resource-tracker/pkg/common" + "github.com/anandf/resource-tracker/pkg/dynamic" + "github.com/anandf/resource-tracker/pkg/kube" + "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" + "github.com/emirpasic/gods/sets/hashset" + log "github.com/sirupsen/logrus" + "golang.org/x/sync/errgroup" +) + +// Backend implements the analysis using OwnerRefs and the dynamic resource graph logic. +type Backend struct{} + +func NewBackend() *Backend { + return &Backend{} +} + +// Execute runs the dynamic analysis and returns grouped resource kinds. +func (b *Backend) Execute(ctx context.Context, opts analyzer.Options) (*common.GroupedResourceKinds, error) { + logger := log.WithFields(log.Fields{ + "controllerNamespace": opts.ArgoCDNamespace, + "strategy": "dynamic", + "allApps": opts.TargetApp == "", + }) + logger.Info("Starting dynamic analysis backend...") + + if opts.KubeConfig == nil { + return nil, fmt.Errorf("dynamic backend: KubeConfig is nil in Options") + } + + // Initialize ArgoCD high-level client against the control-plane cluster. + ac, err := argocd.NewArgoCD( + opts.KubeConfig, + opts.ArgoCDNamespace, + opts.TargetAppNamespace, + opts.RepoServerAddress, + opts.RepoServerTimeoutSeconds, + opts.RepoServerPlaintext, + opts.RepoServerStrictTLS, + ) + if err != nil { + return nil, err + } + // Initialize the shared DynamicTracker used to discover relations across clusters. + rt := dynamic.NewDynamicTracker(logger) + var apps []*v1alpha1.Application + groupedKinds := make(common.GroupedResourceKinds) + if opts.TargetApp == "" { + // Analyze all apps + logger.Info("Listing all applications...") + appsList, err := ac.ListApplications() + if err != nil { + return nil, err + } + logger.Infof("Found %d applications", len(appsList)) + apps = make([]*v1alpha1.Application, 0, len(appsList)) + for i := range appsList { + app := appsList[i] + apps = append(apps, &app) + missingResources, err := ac.GetResourcesFromApplicationStatus(ctx, &app) + if err != nil { + logger.WithError(err).Error("Error getting missing resources from application conditions") + continue + } + logger.Debugf("Found %d missing resources from application conditions", len(missingResources)) + groupedKinds.MergeResourceInfos(missingResources) + } + + } else { + // Analyze a single app + logger.Infof("Getting application %q", opts.TargetApp) + app, err := ac.GetApplication(opts.TargetApp) + if err != nil { + return nil, err + } + apps = []*v1alpha1.Application{app} + missingResources, err := ac.GetResourcesFromApplicationStatus(ctx, app) + if err != nil { + return nil, err + } + logger.Debugf("Found %d missing resources from application conditions", len(missingResources)) + groupedKinds.MergeResourceInfos(missingResources) + } + + // Use the v2 implementation based on errgroup for concurrency and cancellation. + appChildren := analyzeWithDynamicTracker(opts.KubeConfigPath, ctx, apps, ac, rt, logger) + groupedKinds.MergeResourceInfos(appChildren) + return &groupedKinds, nil +} + +// analyzeWithDynamicTracker analyzes the applications concurrently using errgroup +// and returns the computed list of resources. +func analyzeWithDynamicTracker( + kubeconfigPath string, + ctx context.Context, + apps []*v1alpha1.Application, + ac argocd.ArgoCD, // Passed in dependency + rt *dynamic.DynamicTracker, // Passed in dependency + logger *log.Entry, +) []*common.ResourceInfo { + var ( + mu sync.Mutex + appChildren []*common.ResourceInfo + ) + + // errgroup handles concurrency, error propagation, and context cancellation. + g, ctx := errgroup.WithContext(ctx) + g.SetLimit(4) + + for _, app := range apps { + // Lets not terminate if we encounter an error while processing an application, we are logging the error and returning nil to continue the loop. + // returing an error will terminate the errgroup and return the error to the caller. + g.Go(func() error { + appLogger := logger.WithFields(log.Fields{ + "applicationName": app.GetName(), + "applicationNamespace": app.GetNamespace(), + }) + appLogger.Info("Processing application") + server := app.Spec.Destination.Server + if server == "" { + var err error + if app.Spec.Destination.Name == "" { + err := fmt.Errorf("both destination server and name are empty") + appLogger.WithError(err).Error("Destination missing") + return nil + } + server, err = ac.GetApplicationClusterServerByName(ctx, app.Spec.Destination.Name) + if err != nil { + logger.WithError(err).Error("Error getting cluster by name") + return nil + } + } + appCluster, err := ac.GetAppCluster(ctx, server) + if err != nil { + appLogger.WithError(err).Error("Error getting cluster") + return nil + } + restCfg, err := kube.RestConfigFromCluster(appCluster, kubeconfigPath) + if err != nil { + appLogger.WithError(err).Error("Error creating rest config") + return nil + } + err = rt.SyncResourceMapper(server, restCfg) + if err != nil { + appLogger.WithError(err).Error("Error syncing resource mapper") + return nil + } + if len(rt.ResourceMapperStore) == 0 { + appLogger.Error("No destination clusters synced; ensure Applications have valid .spec.destination and Argo CD has access") + return nil + } + childManifests, err := ac.GetApplicationChildManifests(ctx, app, kubeconfigPath, server) + if err != nil { + appLogger.WithError(err).Error("Error getting child manifests") + return nil + } + appLogger.Debugf("Children of Argo CD application %q: %v", app.GetName(), childManifests) + // Check if any direct resource is missing in cache + rt.CacheMu.RLock() + syncRequired := false + for _, resource := range childManifests { + k := dynamic.GetResourceKey(resource.Group, resource.Kind) + if _, exists := rt.SharedRelationsCache[k]; !exists { + syncRequired = true + break + } + } + rt.CacheMu.RUnlock() + if syncRequired { + // Ensure only one worker per cluster performs the sync; others wait. + clusterLock := rt.GetClusterSyncLock(server) + clusterLock.Lock() + // Re-check under the cluster lock in case another worker already synced. + rt.CacheMu.RLock() + stillMissing := false + missingResource := "" + for _, resource := range childManifests { + k := dynamic.GetResourceKey(resource.Group, resource.Kind) + if _, exists := rt.SharedRelationsCache[k]; !exists { + stillMissing = true + missingResource = resource.String() + break + } + } + rt.CacheMu.RUnlock() + if stillMissing { + appLogger.WithFields(log.Fields{ + "cluster": server, + "missingResource": missingResource, + }).Info("Syncing cache for missing resource") + rt.EnsureSyncedSharedCacheOnHost(ctx, server) + // if the direct resources are not in the cache, add them to the cache as left nodes + rt.CacheMu.Lock() + for _, resource := range childManifests { + k := dynamic.GetResourceKey(resource.Group, resource.Kind) + if _, exists := rt.SharedRelationsCache[k]; !exists { + rt.SharedRelationsCache[k] = hashset.New() + } + } + rt.CacheMu.Unlock() + } + clusterLock.Unlock() + } + relations := dynamic.GetResourceRelation(rt.SharedRelationsCache, childManifests) + mu.Lock() + appChildren = append(appChildren, relations...) + mu.Unlock() + return nil + }) + } + // Wait for all workers to complete. + g.Wait() + return appChildren +} diff --git a/pkg/analyzer/graph/backend.go b/pkg/analyzer/graph/backend.go new file mode 100644 index 0000000..251c345 --- /dev/null +++ b/pkg/analyzer/graph/backend.go @@ -0,0 +1,202 @@ +package graphbackend + +import ( + "context" + "fmt" + "sync" + + "github.com/anandf/resource-tracker/pkg/analyzer" + "github.com/anandf/resource-tracker/pkg/argocd" + "github.com/anandf/resource-tracker/pkg/common" + "github.com/anandf/resource-tracker/pkg/graph" + "github.com/anandf/resource-tracker/pkg/kube" + "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" + log "github.com/sirupsen/logrus" +) + +// It caches one QueryServer per destination cluster. +type Backend struct { + mu sync.Mutex + queryServers map[string]*graph.QueryServer +} + +func NewBackend() *Backend { + return &Backend{ + mu: sync.Mutex{}, + queryServers: make(map[string]*graph.QueryServer), + } +} + +// Execute performs a graph-based analysis and returns grouped resource kinds. +func (b *Backend) Execute(ctx context.Context, opts analyzer.Options) (*common.GroupedResourceKinds, error) { + logger := log.WithFields(log.Fields{ + "controllerNamespace": opts.ArgoCDNamespace, + "strategy": "graph", + "applicationNamespace": opts.TargetAppNamespace, + }) + logger.Info("Starting graph (Cyphernetes) analysis backend...") + + if opts.KubeConfig == nil { + return nil, fmt.Errorf("graph backend: KubeConfig is nil in Options") + } + + // Initialize ArgoCD client against the control-plane cluster. + argoCDClient, err := argocd.NewArgoCD( + opts.KubeConfig, + opts.ArgoCDNamespace, + opts.TargetAppNamespace, + opts.RepoServerAddress, + opts.RepoServerTimeoutSeconds, + opts.RepoServerPlaintext, + opts.RepoServerStrictTLS, + ) + if err != nil { + return nil, err + } + trackingMethod, err := argoCDClient.GetTrackingMethod() + if err != nil { + return nil, err + } + + var allAppChildren []*common.ResourceInfo + if opts.TargetApp != "" { + appLogger := logger.WithField("applicationName", opts.TargetApp) + appLogger.Infof("Processing application") + argoApp, err := argoCDClient.GetApplication(opts.TargetApp) + if err != nil { + // If the application itself cannot be fetched, fail fast. + return nil, err + } + + // Try to resolve and traverse the destination cluster; on failure just log + // and fall back to status-based resources. + if qs, err := b.getQueryServerForApp(ctx, argoCDClient, argoApp, opts.KubeConfigPath, trackingMethod, appLogger); err != nil { + appLogger.WithError(err).Error("Error getting query server for destination cluster") + } else { + appChildren, err := argoCDClient.GetApplicationChildManifests(ctx, argoApp, opts.KubeConfigPath, "") + if err != nil { + appLogger.WithError(err).Error("Error getting application children") + } else { + appLogger.Debugf("Children of Argo CD application %q: %v", argoApp.Name, appChildren) + for _, appChild := range appChildren { + childResources, err := qs.GetNestedChildResources(appChild) + if err != nil { + appLogger.WithError(err).Error("Error getting nested child resources") + continue + } + for childResource := range childResources { + allAppChildren = append(allAppChildren, &childResource) + } + } + } + } + + // Always try to augment with resources inferred from Application.status, + // even if graph traversal failed. + resources, err := argoCDClient.GetResourcesFromApplicationStatus(ctx, argoApp) + if err != nil { + appLogger.WithError(err).Error("Error getting resources from application status") + } else { + allAppChildren = append(allAppChildren, resources...) + } + } else { + argoApps, err := argoCDClient.ListApplications() + if err != nil { + return nil, err + } + logger.Infof("Found %d applications", len(argoApps)) + for _, argoApp := range argoApps { + appLogger := logger.WithField("applicationName", argoApp.Name) + appLogger.Info("Processing application") + appLogger.Debugf("Querying Argo CD application %q", argoApp.Name) + appChildren, err := argoCDClient.GetApplicationChildManifests(ctx, &argoApp, opts.KubeConfigPath, "") + if err != nil { + appLogger.WithError(err).Error("Error getting application children") + } + // Try to resolve and traverse the destination cluster; on failure just + // log and fall back to status-based resources. + if qs, err := b.getQueryServerForApp(ctx, argoCDClient, &argoApp, opts.KubeConfigPath, trackingMethod, logger); err != nil { + appLogger.WithError(err).Error("Error getting query server for application") + } else { + for _, appChild := range appChildren { + childResources, err := qs.GetNestedChildResources(appChild) + if err != nil { + appLogger.WithError(err).Error("Error getting nested child resources") + continue + } + for childResource := range childResources { + allAppChildren = append(allAppChildren, &childResource) + } + appLogger.Debugf("Children of Argo CD application %q: %v", argoApp.Name, childResources) + } + } + // Always try to augment with resources inferred from Application.status, + // even if graph traversal failed. + resources, err := argoCDClient.GetResourcesFromApplicationStatus(ctx, &argoApp) + if err != nil { + appLogger.WithError(err).Error("Error getting resources from application status") + continue + } + allAppChildren = append(allAppChildren, resources...) + } + } + groupedKinds := make(common.GroupedResourceKinds) + groupedKinds.MergeResourceInfos(allAppChildren) + return &groupedKinds, nil +} + +// getQueryServerForApp resolves the destination cluster for the given Argo CD +// Application and returns a cached QueryServer for that cluster, creating it +// if necessary. +func (b *Backend) getQueryServerForApp( + ctx context.Context, + argoCDClient argocd.ArgoCD, + app *v1alpha1.Application, + kubeConfigPath string, + trackingMethod string, + logger *log.Entry, +) (*graph.QueryServer, error) { + // Determine the destination server for this application. + server := app.Spec.Destination.Server + if server == "" { + if app.Spec.Destination.Name == "" { + return nil, fmt.Errorf("both destination server and name are empty for application %q", app.Name) + } + var err error + server, err = argoCDClient.GetApplicationClusterServerByName(ctx, app.Spec.Destination.Name) + if err != nil { + return nil, fmt.Errorf("error getting application cluster server by name %q: %w", app.Spec.Destination.Name, err) + } + } + + // Check cache first. + b.mu.Lock() + if qs, ok := b.queryServers[server]; ok { + b.mu.Unlock() + return qs, nil + } + b.mu.Unlock() + + // Fetch the Argo CD Cluster object and build a rest.Config for the + // destination cluster. + cluster, err := argoCDClient.GetAppCluster(ctx, server) + if err != nil { + return nil, fmt.Errorf("failed to get destination cluster %q: %w", server, err) + } + restCfg, err := kube.RestConfigFromCluster(cluster, kubeConfigPath) + if err != nil { + return nil, fmt.Errorf("failed to build rest.Config for cluster %q: %w", server, err) + } + + qs, err := graph.NewQueryServer(restCfg, trackingMethod, true) + if err != nil { + return nil, fmt.Errorf("failed to create query server for cluster %q: %w", server, err) + } + + b.mu.Lock() + b.queryServers[server] = qs + b.mu.Unlock() + + logger.WithField("cluster", server).Debug("Created new QueryServer for destination cluster") + return qs, nil +} diff --git a/pkg/analyzer/interface.go b/pkg/analyzer/interface.go new file mode 100644 index 0000000..26d5d86 --- /dev/null +++ b/pkg/analyzer/interface.go @@ -0,0 +1,47 @@ +package analyzer + +import ( + "context" + + "github.com/anandf/resource-tracker/pkg/common" + "k8s.io/client-go/rest" +) + +// Options holds the configuration required to run an analysis. +type Options struct { + // KubeConfig is the Kubernetes REST config for talking to the Argo CD control plane. + // In the CLI this is typically loaded from a kubeconfig file; in an Operator it + // would usually come from rest.InClusterConfig(). + KubeConfig *rest.Config + + // KubeConfigPath is the original kubeconfig path used by the CLI to load the KubeConfig. + KubeConfigPath string + + // ArgoCDNamespace is where Argo CD is running. + ArgoCDNamespace string + + // TargetApp is the specific app to analyze. If empty, analyze all applications. + TargetApp string + + // TargetAppNamespace is the namespace of the target application. + TargetAppNamespace string + + // RepoServerAddress is the address of the Argo CD repo-server (host:port). + RepoServerAddress string + + // RepoServerPlaintext controls whether the repo-server connection uses + // plain HTTP instead of TLS. + RepoServerPlaintext bool + + // RepoServerStrictTLS controls whether strict TLS verification is enabled + // for the repo-server connection. + RepoServerStrictTLS bool + + // RepoServerTimeoutSeconds is the timeout for repo-server RPC calls. + RepoServerTimeoutSeconds int +} + +// Backend is the common interface that both CLI and Operator code can use. +type Backend interface { + Execute(ctx context.Context, opts Options) (*common.GroupedResourceKinds, error) +} diff --git a/pkg/argocd/application.go b/pkg/argocd/application.go index d4235ce..a09abbc 100644 --- a/pkg/argocd/application.go +++ b/pkg/argocd/application.go @@ -6,15 +6,17 @@ import ( "fmt" "regexp" + "github.com/anandf/resource-tracker/pkg/common" "github.com/anandf/resource-tracker/pkg/graph" "github.com/anandf/resource-tracker/pkg/kube" - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" - "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned" - "github.com/argoproj/argo-cd/v2/util/argo" - "github.com/argoproj/argo-cd/v2/util/settings" + "github.com/anandf/resource-tracker/pkg/repo" + "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" + "github.com/argoproj/argo-cd/v3/pkg/client/clientset/versioned" + "github.com/argoproj/argo-cd/v3/util/argo" + "github.com/argoproj/argo-cd/v3/util/db" + "github.com/argoproj/argo-cd/v3/util/settings" log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic" @@ -23,34 +25,41 @@ import ( ) const ( - ConditionTypeExcludedResourceWarning = "ConditionTypeExcludedResourceWarning" - ExcludedResourceWarningMsgPattern = "([a-zA-Z]*)/([a-zA-Z0-9.]+) ([a-zA-Z0-9-_.]+)" + ConditionTypeExcludedResourceWarning = "ExcludedResourceWarning" + ExcludedResourceWarningMsgPattern = "([A-Za-z0-9.-]*)/([A-Za-z0-9.]+) ([A-Za-z0-9-_.]+)" ) // ArgoCD is the interface for accessing Argo CD functions we need type ArgoCD interface { ListApplications() ([]v1alpha1.Application, error) GetApplication(name string) (*v1alpha1.Application, error) - GetAppProject(app v1alpha1.Application) (*v1alpha1.AppProject, error) - ProcessApplication(targetObjs []*unstructured.Unstructured, destinationNS string, destinationConfig *rest.Config) ([]graph.ResourceInfo, error) - GetAllMissingResources() ([]graph.ResourceInfo, error) + GetAppProject(app *v1alpha1.Application) (*v1alpha1.AppProject, error) + GetApplicationClusterServerByName(ctx context.Context, clusterName string) (string, error) + GetResourcesFromApplicationStatus(ctx context.Context, application *v1alpha1.Application) ([]*common.ResourceInfo, error) + GetAllMissingResources() ([]*common.ResourceInfo, error) + GetApplicationChildManifests(ctx context.Context, application *v1alpha1.Application, kubeconfig string, server string) ([]*common.ResourceInfo, error) GetTrackingMethod() (string, error) + GetAppCluster(ctx context.Context, server string) (*v1alpha1.Cluster, error) GetCurrentResourceInclusions(gvr *schema.GroupVersionResource, resourceName, resourceNamespace string) (string, error) UpdateResourceInclusions(gvr *schema.GroupVersionResource, resourceName, resourceNamespace, resourceInclusionYaml string) error } // Kubernetes based client type argocd struct { + db db.ArgoDB kubeClient *kube.KubeClient dynamicClient dynamic.Interface applicationClientSet versioned.Interface queryServers map[string]*graph.QueryServer trackingMethod v1alpha1.TrackingMethod + repoServerManager *repo.RepoServerManager settingsManager *settings.SettingsManager + applicationNamespace string } -// NewArgoCD creates a new kube client to interact with kube api-server. -func NewArgoCD(config *rest.Config, argocdNS string) (ArgoCD, error) { +// NewArgoCD creates a new kube client to interact with kube api-server and +// configures access to the Argo CD repo-server. +func NewArgoCD(config *rest.Config, argocdNS string, applicationNS string, repoServerAddress string, repoServerTimeoutSeconds int, repoServerPlaintext, repoServerStrictTLS bool) (ArgoCD, error) { resourceTrackerConfig, err := kube.NewKubernetesClientFromConfig(context.Background(), argocdNS, config) if err != nil { return nil, fmt.Errorf("could not create K8s client: %w", err) @@ -66,6 +75,11 @@ func NewArgoCD(config *rest.Config, argocdNS string) (ArgoCD, error) { if err != nil { return nil, fmt.Errorf("could not create dynamic client: %w", err) } + dbInstance := db.NewDB(argocdNS, settingsMgr, resourceTrackerConfig.KubeClient.Clientset) + repoServerManager, err := repo.NewRepoServerManager(config, argocdNS, repoServerAddress, repoServerTimeoutSeconds, repoServerPlaintext, repoServerStrictTLS) + if err != nil { + return nil, fmt.Errorf("could not create repo server manager: %w", err) + } return &argocd{ kubeClient: resourceTrackerConfig.KubeClient, dynamicClient: dynamicClient, @@ -73,12 +87,16 @@ func NewArgoCD(config *rest.Config, argocdNS string) (ArgoCD, error) { queryServers: qsMap, trackingMethod: argo.GetTrackingMethod(settingsMgr), settingsManager: settingsMgr, + repoServerManager: repoServerManager, + applicationNamespace: applicationNS, + db: dbInstance, }, nil } // ListApplications lists all applications across all namespaces. func (a *argocd) ListApplications() ([]v1alpha1.Application, error) { - list, err := a.applicationClientSet.ArgoprojV1alpha1().Applications(a.kubeClient.Namespace).List(context.TODO(), v1.ListOptions{}) + ns := a.applicationNamespace + list, err := a.applicationClientSet.ArgoprojV1alpha1().Applications(ns).List(context.TODO(), metav1.ListOptions{}) if err != nil { return nil, fmt.Errorf("error listing applications: %w", err) } @@ -87,7 +105,8 @@ func (a *argocd) ListApplications() ([]v1alpha1.Application, error) { // GetApplication lists all applications across all namespaces. func (a *argocd) GetApplication(name string) (*v1alpha1.Application, error) { - application, err := a.applicationClientSet.ArgoprojV1alpha1().Applications(a.kubeClient.Namespace).Get(context.TODO(), name, v1.GetOptions{}) + ns := a.applicationNamespace + application, err := a.applicationClientSet.ArgoprojV1alpha1().Applications(ns).Get(context.TODO(), name, metav1.GetOptions{}) if err != nil { return nil, fmt.Errorf("error getting application %s: %w", name, err) } @@ -95,9 +114,9 @@ func (a *argocd) GetApplication(name string) (*v1alpha1.Application, error) { } // GetAppProject get the associated AppProject for a given Argo CD Application. -func (a *argocd) GetAppProject(app v1alpha1.Application) (*v1alpha1.AppProject, error) { +func (a *argocd) GetAppProject(app *v1alpha1.Application) (*v1alpha1.AppProject, error) { // Fetch AppProject - appProject, err := a.applicationClientSet.ArgoprojV1alpha1().AppProjects(a.kubeClient.Namespace).Get(context.Background(), app.Spec.Project, v1.GetOptions{}) + appProject, err := a.applicationClientSet.ArgoprojV1alpha1().AppProjects(a.kubeClient.Namespace).Get(context.Background(), app.Spec.Project, metav1.GetOptions{}) if err != nil { return nil, fmt.Errorf("failed to fetch AppProject %s for application %s: %w", app.Spec.Project, app.Name, err) } @@ -105,39 +124,9 @@ func (a *argocd) GetAppProject(app v1alpha1.Application) (*v1alpha1.AppProject, return appProject, err } -// ProcessApplication processes a list of application managed objects and returns a list of child resources. -func (a *argocd) ProcessApplication(targetObjs []*unstructured.Unstructured, destinationNS string, destinationConfig *rest.Config) ([]graph.ResourceInfo, error) { - var allAppChildren []graph.ResourceInfo - for _, targetObj := range targetObjs { - namespace := targetObj.GetNamespace() - if len(namespace) == 0 { - namespace = destinationNS - } - log.Infof("Processing target object: %s/%s of kind %s", namespace, targetObj.GetName(), targetObj.GetKind()) - qs, err := a.lookupQueryServer(destinationConfig) - if err != nil { - return nil, err - } - qs.VisitedKinds = make(map[graph.ResourceInfo]bool) - appChildren, err := qs.GetNestedChildResources(&graph.ResourceInfo{ - Name: targetObj.GetName(), - Namespace: namespace, - Kind: targetObj.GetKind(), - APIVersion: targetObj.GetAPIVersion(), - }) - if err != nil { - return nil, err - } - for childRes := range appChildren { - allAppChildren = append(allAppChildren, childRes) - } - } - return allAppChildren, nil -} - // GetAllMissingResources returns the missing resources across all applications -func (a *argocd) GetAllMissingResources() ([]graph.ResourceInfo, error) { - allMissingResources := make([]graph.ResourceInfo, 0) +func (a *argocd) GetAllMissingResources() ([]*common.ResourceInfo, error) { + allMissingResources := make([]*common.ResourceInfo, 0) appList, err := a.ListApplications() if err != nil { return nil, err @@ -162,7 +151,7 @@ func (a *argocd) GetTrackingMethod() (string, error) { func (a *argocd) UpdateResourceInclusions(gvr *schema.GroupVersionResource, resourceName, resourceNamespace, resourceInclusionYaml string) error { ctx := context.Background() return retry.RetryOnConflict(retry.DefaultRetry, func() error { - resource, err := a.dynamicClient.Resource(*gvr).Namespace(resourceNamespace).Get(ctx, resourceName, v1.GetOptions{}) + resource, err := a.dynamicClient.Resource(*gvr).Namespace(resourceNamespace).Get(ctx, resourceName, metav1.GetOptions{}) if err != nil { return fmt.Errorf("error fetching ConfigMap: %v", err) } @@ -177,7 +166,7 @@ func (a *argocd) UpdateResourceInclusions(gvr *schema.GroupVersionResource, reso unstructured.RemoveNestedField(resource.Object, "data", "resource.exclusions") // perform the actual update of the configmap - _, err = a.dynamicClient.Resource(*gvr).Namespace(resourceNamespace).Update(ctx, resource, v1.UpdateOptions{}) + _, err = a.dynamicClient.Resource(*gvr).Namespace(resourceNamespace).Update(ctx, resource, metav1.UpdateOptions{}) if err != nil { log.Warningf("Retrying due to conflict: %v", err) return err @@ -189,7 +178,7 @@ func (a *argocd) UpdateResourceInclusions(gvr *schema.GroupVersionResource, reso // GetCurrentResourceInclusions returns the resource.inclusions from argocd-cm configmap or ArgoCD Custom Resource. func (a *argocd) GetCurrentResourceInclusions(gvr *schema.GroupVersionResource, resourceName, resourceNamespace string) (string, error) { - argocdCM, err := a.dynamicClient.Resource(*gvr).Namespace(resourceNamespace).Get(context.Background(), resourceName, v1.GetOptions{}) + argocdCM, err := a.dynamicClient.Resource(*gvr).Namespace(resourceNamespace).Get(context.Background(), resourceName, metav1.GetOptions{}) if err != nil { return "", fmt.Errorf("error fetching ConfigMap: %v", err) } @@ -204,34 +193,12 @@ func (a *argocd) GetCurrentResourceInclusions(gvr *schema.GroupVersionResource, return resourceInclusionsYaml, nil } -// lookupQueryServer looks up query server for a given kubeconfig -func (a *argocd) lookupQueryServer(kubeConfig *rest.Config) (*graph.QueryServer, error) { - if kubeConfig == nil { - return nil, fmt.Errorf("invalid kubeConfig is nil") - } - if qs, ok := a.queryServers[kubeConfig.Host]; !ok { - trackingMethod, err := a.GetTrackingMethod() - if err != nil { - return nil, err - } - newQueryServer, err := graph.NewQueryServer(kubeConfig, trackingMethod, false) - if err != nil { - return nil, fmt.Errorf("could not create query server: %w", err) - } - a.queryServers[kubeConfig.Host] = newQueryServer - return newQueryServer, nil - } else { - return qs, nil - } -} - // getMissingResources returns the resources that are missing to be managed via an Argo Application -func getMissingResources(obj *v1alpha1.Application) ([]graph.ResourceInfo, error) { +func getMissingResources(obj *v1alpha1.Application) ([]*common.ResourceInfo, error) { conditions, err := getExcludedResourceConditions(obj.Status.Conditions) if err != nil { return nil, err } - missingResources, err := getResourcesFromConditions(conditions) if err != nil { return nil, err @@ -253,7 +220,7 @@ func getExcludedResourceConditions(statusConditions []v1alpha1.ApplicationCondit if err := json.Unmarshal(jsonBytes, &condition); err != nil { return nil, fmt.Errorf("error unmarshaling condition: %w", err) } - if condition.Type == "ConditionTypeExcludedResourceWarning" { + if condition.Type == "ExcludedResourceWarning" { resultConditions = append(resultConditions, condition) } } @@ -262,9 +229,9 @@ func getExcludedResourceConditions(statusConditions []v1alpha1.ApplicationCondit // getResourcesFromConditions returns the resources that are missing to be managed reported in status.conditions // of an Argo CD Application -func getResourcesFromConditions(conditions []metav1.Condition) ([]graph.ResourceInfo, error) { +func getResourcesFromConditions(conditions []metav1.Condition) ([]*common.ResourceInfo, error) { regex := regexp.MustCompile(ExcludedResourceWarningMsgPattern) - results := make([]graph.ResourceInfo, 0, len(conditions)) + results := make([]*common.ResourceInfo, 0, len(conditions)) for _, condition := range conditions { if condition.Type == ConditionTypeExcludedResourceWarning { matches := regex.FindStringSubmatch(condition.Message) @@ -272,10 +239,13 @@ func getResourcesFromConditions(conditions []metav1.Condition) ([]graph.Resource group := matches[1] kind := matches[2] resourceName := matches[3] - results = append(results, graph.ResourceInfo{ - APIVersion: group, - Kind: kind, - Name: resourceName, + if group == "" { + group = "core" + } + results = append(results, &common.ResourceInfo{ + Group: group, + Kind: kind, + Name: resourceName, }) } } @@ -283,6 +253,33 @@ func getResourcesFromConditions(conditions []metav1.Condition) ([]graph.Resource return results, nil } +func (a *argocd) GetResourcesFromApplicationStatus(ctx context.Context, application *v1alpha1.Application) ([]*common.ResourceInfo, error) { + missingResources, err := getMissingResources(application) + if err != nil { + return nil, fmt.Errorf("error getting missing resources: %w", err) + } + results := make([]*common.ResourceInfo, 0, len(application.Status.Resources)+len(missingResources)) + for _, mr := range missingResources { + // Convert value type to pointer type expected by the result slice. + mrCopy := mr + results = append(results, &common.ResourceInfo{ + Group: mrCopy.Group, + Kind: mrCopy.Kind, + Name: mrCopy.Name, + Namespace: mrCopy.Namespace, + }) + } + for _, resource := range application.Status.Resources { + results = append(results, &common.ResourceInfo{ + Group: resource.Group, + Kind: resource.Kind, + Name: resource.Name, + Namespace: resource.Namespace, + }) + } + return results, nil +} + // getResourceInclusionsHierarchy returns the hierarchy path for getting or updating resource.inclusions for a given GVR func getResourceInclusionsHierarchy(gvr *schema.GroupVersionResource) []string { if gvr.Resource == graph.ArgoCDGVR.Resource { @@ -298,3 +295,42 @@ func getResourceExclusionsHierarchy(gvr *schema.GroupVersionResource) []string { } return []string{"data", "resource.exclusions"} } + +func (a *argocd) GetApplicationClusterServerByName(ctx context.Context, clusterName string) (string, error) { + servers, err := a.db.GetClusterServersByName(ctx, clusterName) + if err != nil { + return "", fmt.Errorf("error getting cluster server by name %q: %w", clusterName, err) + } + if len(servers) > 1 { + return "", fmt.Errorf("there are %d clusters with the same name: %v", len(servers), servers) + } + return servers[0], nil +} + +func (a *argocd) GetAppCluster(ctx context.Context, server string) (*v1alpha1.Cluster, error) { + cluster, err := a.db.GetCluster(ctx, server) + if err != nil { + return nil, fmt.Errorf("failed to get cluster: %w", err) + } + return cluster, nil +} + +func (a *argocd) GetApplicationChildManifests(ctx context.Context, application *v1alpha1.Application, kubeconfig string, server string) ([]*common.ResourceInfo, error) { + appProject, err := a.GetAppProject(application) + if err != nil { + return nil, fmt.Errorf("error getting app project: %w", err) + } + childManifests, err := a.repoServerManager.GetApplicationChildManifests(ctx, application, appProject, kubeconfig) + if err != nil { + return nil, fmt.Errorf("error getting child manifests: %w", err) + } + results := make([]*common.ResourceInfo, 0, len(childManifests)) + for _, manifest := range childManifests { + results = append(results, &common.ResourceInfo{ + Group: manifest.GroupVersionKind().Group, + Kind: manifest.GroupVersionKind().Kind, + Name: manifest.GetName(), + }) + } + return results, nil +} diff --git a/pkg/argocd/repo_test.go b/pkg/argocd/repo_test.go deleted file mode 100644 index e12560f..0000000 --- a/pkg/argocd/repo_test.go +++ /dev/null @@ -1,202 +0,0 @@ -package argocd - -import ( - "context" - "errors" - "fmt" - "testing" - - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" - "github.com/argoproj/argo-cd/v2/reposerver/apiclient" - mockrepoclient "github.com/argoproj/argo-cd/v2/reposerver/apiclient/mocks" - dbmocks "github.com/argoproj/argo-cd/v2/util/db/mocks" - "github.com/argoproj/argo-cd/v2/util/settings" - "github.com/argoproj/gitops-engine/pkg/utils/kube" - "github.com/argoproj/gitops-engine/pkg/utils/kube/kubetest" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/kubernetes/fake" - "k8s.io/client-go/rest" -) - -type MockKubectl struct { - mock.Mock - kube.Kubectl -} - -func (m *MockKubectl) GetServerVersion(config *rest.Config) (string, error) { - args := m.Called(config) - return args.String(0), args.Error(1) -} - -func (m *MockKubectl) GetAPIResources(config *rest.Config, all bool, filter kube.ResourceFilter) ([]kube.APIResourceInfo, error) { - args := m.Called(config, all, filter) - return args.Get(0).([]kube.APIResourceInfo), args.Error(1) -} - -func TestGetApplicationChildManifests(t *testing.T) { - ctx := context.Background() - configMap := corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "argocd-cm", - Namespace: "test-argocd", - Labels: map[string]string{ - "app.kubernetes.io/part-of": "argocd", - }, - }, - Data: make(map[string]string), - } - setupMocks := func() (*MockKubectl, *dbmocks.ArgoDB, *settings.SettingsManager, *mockrepoclient.Clientset) { - mockKubectl := &MockKubectl{Kubectl: &kubetest.MockKubectlCmd{}} - mockKubectl.On("GetServerVersion", mock.Anything).Return("v1.25.0", nil) - mockKubectl.On("GetAPIResources", mock.Anything, false, &settings.ResourcesFilter{}).Return( - []kube.APIResourceInfo{ - {GroupKind: schema.GroupKind{Group: "", Kind: "Pod"}}, - }, nil) - - kubeClient := fake.NewSimpleClientset(&configMap) - db := &dbmocks.ArgoDB{} - settingsManager := settings.NewSettingsManager(ctx, kubeClient, "test-argocd") - mockRepoClient := mockrepoclient.RepoServerServiceClient{} - mockRepoClientset := mockrepoclient.Clientset{RepoServerServiceClient: &mockRepoClient} - db.On("ListHelmRepositories", ctx).Return([]*v1alpha1.Repository{}, nil) - db.On("GetAllHelmRepositoryCredentials", ctx).Return([]*v1alpha1.RepoCreds{}, nil) - db.On("GetCluster", ctx, mock.Anything).Return(&v1alpha1.Cluster{}, nil) - db.On("GetRepository", ctx, mock.Anything, mock.Anything).Return(&v1alpha1.Repository{}, nil) - - return mockKubectl, db, settingsManager, &mockRepoClientset - } - t.Run("success on GenerateManifest", func(t *testing.T) { - mockKubectl, db, settingsManager, mockRepoClientset := setupMocks() - mockRepoClientset.RepoServerServiceClient.(*mockrepoclient.RepoServerServiceClient).On("GenerateManifest", mock.Anything, mock.Anything).Return(&apiclient.ManifestResponse{}, nil) - repoServerManager := &repoServerManager{ - db: db, - settingsMgr: settingsManager, - repoClientset: mockRepoClientset, - kubectl: mockKubectl, - } - _, _, err := getApplicationChildManifests(ctx, &v1alpha1.Application{ - Spec: v1alpha1.ApplicationSpec{ - Destination: v1alpha1.ApplicationDestination{ - Server: "test", - }, - }, - }, &v1alpha1.AppProject{}, "test-argocd", repoServerManager) - assert.NoError(t, err) - }) - t.Run("failure on GenerateManifest", func(t *testing.T) { - mockKubectl, db, settingsManager, mockRepoClientset := setupMocks() - mockRepoClientset.RepoServerServiceClient.(*mockrepoclient.RepoServerServiceClient).On("GenerateManifest", mock.Anything, mock.Anything).Return(&apiclient.ManifestResponse{}, fmt.Errorf("error")) - repoServerManager := &repoServerManager{ - db: db, - settingsMgr: settingsManager, - repoClientset: mockRepoClientset, - kubectl: mockKubectl, - } - _, _, err := getApplicationChildManifests(ctx, &v1alpha1.Application{ - Spec: v1alpha1.ApplicationSpec{ - Destination: v1alpha1.ApplicationDestination{ - Server: "test", - }, - }, - }, &v1alpha1.AppProject{}, "test-argocd", repoServerManager) - assert.Error(t, err) - assert.Contains(t, err.Error(), "error") - }) -} - -func TestUnmarshalManifests(t *testing.T) { - validManifest := `{"apiVersion":"apps/v1","kind":"StatefulSet","metadata":{"labels":{"app":"example"},"name":"example-sts"},"spec":{"replicas":2,"selector":{"matchLabels":{"app":"example"}},"serviceName":"example-service","template":{"metadata":{"labels":{"app":"example"}},"spec":{"containers":[{"image":"nginx:latest","name":"nginx","ports":[{"containerPort":80}],"volumeMounts":[{"mountPath":"/usr/share/nginx/html","name":"example-pvc"}]}]}},"volumeClaimTemplates":[{"metadata":{"name":"example-pvc"},"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"1Gi"}},"storageClassName":"standard"}}]}}` - invalidManifest := `{"apiVersion":"apps/v1","kind":"InvalidKind","metadata":{"name":}` - t.Run("valid manifest", func(t *testing.T) { - manifests := []string{validManifest} - objs, err := unmarshalManifests(manifests) - assert.NoError(t, err) - assert.Len(t, objs, 1) - assert.Equal(t, "StatefulSet", objs[0].GetKind()) - assert.Equal(t, "example-sts", objs[0].GetName()) - }) - t.Run("invalid manifest", func(t *testing.T) { - manifests := []string{invalidManifest} - objs, err := unmarshalManifests(manifests) - assert.Error(t, err) - assert.Nil(t, objs) - }) -} - -func TestGetDestinationServer(t *testing.T) { - ctx := context.Background() - t.Run("single cluster found", func(t *testing.T) { - mockDB := &dbmocks.ArgoDB{} - mockDB.On("GetClusterServersByName", ctx, "test-cluster").Return([]string{"https://test-cluster-server"}, nil) - server, err := getDestinationServer(ctx, mockDB, "test-cluster") - assert.NoError(t, err) - assert.Equal(t, "https://test-cluster-server", server) - }) - t.Run("multiple clusters found", func(t *testing.T) { - mockDB := &dbmocks.ArgoDB{} - mockDB.On("GetClusterServersByName", ctx, "test-cluster").Return([]string{"https://test-cluster-server1", "https://test-cluster-server2"}, nil) - server, err := getDestinationServer(ctx, mockDB, "test-cluster") - assert.Error(t, err) - assert.EqualError(t, err, "there are 2 clusters with the same name: [https://test-cluster-server1 https://test-cluster-server2]") - assert.Empty(t, server) - }) - t.Run("no clusters found", func(t *testing.T) { - mockDB := &dbmocks.ArgoDB{} - mockDB.On("GetClusterServersByName", ctx, "test-cluster").Return([]string{}, nil) - server, err := getDestinationServer(ctx, mockDB, "test-cluster") - assert.Error(t, err) - assert.EqualError(t, err, "there are no clusters with this name: test-cluster") - assert.Empty(t, server) - }) - t.Run("error fetching clusters", func(t *testing.T) { - mockDB := &dbmocks.ArgoDB{} - mockDB.On("GetClusterServersByName", ctx, "test-cluster").Return(nil, fmt.Errorf("database error")) - server, err := getDestinationServer(ctx, mockDB, "test-cluster") - assert.Error(t, err) - assert.EqualError(t, err, "error getting cluster server by name \"test-cluster\": database error") - assert.Empty(t, server) - }) -} - -func TestGetClusterAPIDetails(t *testing.T) { - t.Run("Success Case", func(t *testing.T) { - mockKubectl := &MockKubectl{Kubectl: &kubetest.MockKubectlCmd{}} - config := &rest.Config{} - mockKubectl.On("GetServerVersion", config).Return("v1.25.0", nil) - mockKubectl.On("GetAPIResources", config, false, &settings.ResourcesFilter{}).Return( - []kube.APIResourceInfo{ - {GroupKind: schema.GroupKind{Group: "", Kind: "Pod"}}, - }, nil) - - details, err := getClusterAPIDetails(config, mockKubectl) - assert.NoError(t, err) - assert.NotNil(t, details) - assert.Equal(t, "v1.25.0", details.APIVersions) - assert.Equal(t, []kube.APIResourceInfo{ - {GroupKind: schema.GroupKind{Group: "", Kind: "Pod"}}, - }, details.APIResources) - }) - t.Run("Failure in GetServerVersion", func(t *testing.T) { - mockKubectl := &MockKubectl{Kubectl: &kubetest.MockKubectlCmd{}} - config := &rest.Config{} - mockKubectl.On("GetServerVersion", config).Return("", errors.New("server error")) - details, err := getClusterAPIDetails(config, mockKubectl) - assert.Error(t, err) - assert.Nil(t, details) - assert.Contains(t, err.Error(), "failed to get server version") - }) - t.Run("Failure in GetAPIResources", func(t *testing.T) { - mockKubectl := &MockKubectl{Kubectl: &kubetest.MockKubectlCmd{}} - config := &rest.Config{} - mockKubectl.On("GetServerVersion", config).Return("v1.25.0", nil) - mockKubectl.On("GetAPIResources", config, false, &settings.ResourcesFilter{}).Return([]kube.APIResourceInfo{}, errors.New("resource error")) - details, err := getClusterAPIDetails(config, mockKubectl) - assert.Error(t, err) - assert.Nil(t, details) - assert.Contains(t, err.Error(), "failed to get API resources") - }) -} diff --git a/pkg/graph/types.go b/pkg/common/common.go similarity index 81% rename from pkg/graph/types.go rename to pkg/common/common.go index b190bc7..4475e16 100644 --- a/pkg/graph/types.go +++ b/pkg/common/common.go @@ -1,20 +1,20 @@ -package graph +package common import ( "fmt" "reflect" "strings" - "gopkg.in/yaml.v3" + "gopkg.in/yaml.v2" ) type Void struct{} type ResourceInfoSet map[ResourceInfo]Void type ResourceInfo struct { - Kind string - APIVersion string - Name string - Namespace string + Kind string + Group string + Name string + Namespace string } type Kinds map[string]Void @@ -27,7 +27,7 @@ type ResourceInclusionEntry struct { } func (r *ResourceInfo) String() string { - return fmt.Sprintf("[apiVersion:%s, kind: %s, name: %s, namespace:%s]", r.APIVersion, r.Kind, r.Name, r.Namespace) + return fmt.Sprintf("[group:%s, kind: %s, name: %s, namespace:%s]", r.Group, r.Kind, r.Name, r.Namespace) } func (k *Kinds) Equal(other *Kinds) bool { @@ -55,11 +55,18 @@ func (r *ResourceInclusionEntry) Equal(other *ResourceInclusionEntry) bool { return true } +// String is the single, centralized function to print the YAML output. func (g *GroupedResourceKinds) String() string { includedResources := make([]ResourceInclusionEntry, 0, len(*g)) for group, kinds := range *g { + // Handle core group + apiGroup := group + if group == "core" || group == "" { + apiGroup = "" + } + includedResources = append(includedResources, ResourceInclusionEntry{ - APIGroups: []string{group}, + APIGroups: []string{apiGroup}, Kinds: getUniqueKinds(kinds), Clusters: []string{"*"}, }) @@ -104,11 +111,15 @@ func (g *GroupedResourceKinds) FromYaml(resourceInclusionsYaml string) error { } for _, resourceInclusion := range existingResourceInclusionsInCM { for _, apiGroup := range resourceInclusion.APIGroups { + group := apiGroup + if group == "" { + group = "core" + } for _, kind := range resourceInclusion.Kinds { - if (*g)[apiGroup] == nil { - (*g)[apiGroup] = make(map[string]Void) + if (*g)[group] == nil { + (*g)[group] = make(map[string]Void) } - (*g)[apiGroup][kind] = Void{} + (*g)[group][kind] = Void{} } // break after the first item in apiGroup list break @@ -118,12 +129,13 @@ func (g *GroupedResourceKinds) FromYaml(resourceInclusionsYaml string) error { } // MergeResourceInfos groups given set of ResourceInfo objects according to their api groups and merges it into this GroupResourceKinds object -func (g *GroupedResourceKinds) MergeResourceInfos(input []ResourceInfo) { +func (g *GroupedResourceKinds) MergeResourceInfos(input []*ResourceInfo) { for _, resourceInfo := range input { - if len(resourceInfo.APIVersion) <= 0 { - continue + apiGroup := resourceInfo.Group + if apiGroup == "" { + apiGroup = "core" } - apiGroup := getAPIGroup(resourceInfo.APIVersion) + if _, found := (*g)[apiGroup]; !found { (*g)[apiGroup] = map[string]Void{ resourceInfo.Kind: {}, @@ -134,14 +146,6 @@ func (g *GroupedResourceKinds) MergeResourceInfos(input []ResourceInfo) { } } -// getAPIGroup returns the API group for a given API version. -func getAPIGroup(apiVersion string) string { - if strings.Contains(apiVersion, "/") { - return strings.Split(apiVersion, "/")[0] - } - return "" -} - // getUniqueKinds given a set of kinds, it returns unique set of kinds func getUniqueKinds(kinds Kinds) []string { uniqueKinds := make([]string, 0) diff --git a/pkg/dynamic/dynamic.go b/pkg/dynamic/dynamic.go new file mode 100644 index 0000000..5f511d6 --- /dev/null +++ b/pkg/dynamic/dynamic.go @@ -0,0 +1,97 @@ +package dynamic + +import ( + "context" + "fmt" + "sync" + + "github.com/emirpasic/gods/sets/hashset" + log "github.com/sirupsen/logrus" + "k8s.io/client-go/rest" +) + +// DynamicTracker handles the analysis of ArgoCD application resources +type DynamicTracker struct { + ResourceMapperStore map[string]*ResourceMapper + // shared cache across ALL clusters: parentKey -> set(childKey) + SharedRelationsCache map[string]*hashset.Set + CacheMu sync.RWMutex + // per-cluster sync locks to avoid concurrent resyncs for the same cluster + syncLocks map[string]*sync.Mutex + // logger for the tracker + logger *log.Entry +} + +// NewDynamicTracker creates a new resource tracker instance +func NewDynamicTracker(logger *log.Entry) *DynamicTracker { + return &DynamicTracker{ + ResourceMapperStore: make(map[string]*ResourceMapper), + SharedRelationsCache: make(map[string]*hashset.Set), + syncLocks: make(map[string]*sync.Mutex), + logger: logger, + } +} + +// GetClusterSyncLock returns a per-cluster mutex, creating it if needed. +// It is safe to call concurrently. +func (rt *DynamicTracker) GetClusterSyncLock(server string) *sync.Mutex { + rt.CacheMu.Lock() + defer rt.CacheMu.Unlock() + + if rt.syncLocks == nil { + rt.syncLocks = make(map[string]*sync.Mutex) + } + if l, ok := rt.syncLocks[server]; ok { + return l + } + mu := &sync.Mutex{} + rt.syncLocks[server] = mu + return mu +} + +// EnsureSyncedSharedCacheOnHost ensures the shared cache is synced on the given server. +func (rt *DynamicTracker) EnsureSyncedSharedCacheOnHost(ctx context.Context, server string) { + + mapper, ok := rt.ResourceMapperStore[server] + if !ok || mapper == nil { + rt.logger.Warningf("No mapper for host %s", server) + return + } + rt.logger.Infof("Querying relations host=%s", server) + rel, err := mapper.GetClusterResourcesRelation(ctx) + if err != nil { + rt.logger.Warningf("Dynamic scan on %s failed: %v", server, err) + return + } + rt.CacheMu.Lock() + mergeInto(rt.SharedRelationsCache, rel) + rt.CacheMu.Unlock() +} + +// SyncResourceMapper syncs the resource mapper for the given server. +func (rt *DynamicTracker) SyncResourceMapper(server string, restCfg *rest.Config) error { + if _, exists := rt.ResourceMapperStore[server]; !exists { + mapper, err := NewResourceMapper(restCfg) + if err != nil { + return fmt.Errorf("failed to create ResourceMapper: %w", err) + } + // Start CRD informer so add/update events invoke addToResourceList + go mapper.StartInformer() + rt.ResourceMapperStore[server] = mapper + } + return nil +} + +// mergeInto adds rel (parent -> children) into dst +func mergeInto(dst, rel map[string]*hashset.Set) { + for p, set := range rel { + if _, ok := dst[p]; !ok { + dst[p] = hashset.New() + } + for _, v := range set.Values() { + if s, ok := v.(string); ok { + dst[p].Add(s) + } + } + } +} diff --git a/pkg/dynamic/resourcegraph.go b/pkg/dynamic/resourcegraph.go new file mode 100644 index 0000000..4484b52 --- /dev/null +++ b/pkg/dynamic/resourcegraph.go @@ -0,0 +1,380 @@ +package dynamic + +import ( + "context" + "fmt" + "reflect" + "strings" + + "github.com/anandf/resource-tracker/pkg/common" + "github.com/emirpasic/gods/sets/hashset" + log "github.com/sirupsen/logrus" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" + apiextensionsinformer "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions" + k8sErrors "k8s.io/apimachinery/pkg/api/errors" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/discovery" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/cache" +) + +//TODO: Rename this pkg + +type ResourceMapper struct { + DiscoveryClient discovery.DiscoveryInterface + InformerFactory apiextensionsinformer.SharedInformerFactory + ResourceList hashset.Set + CRDInformer cache.SharedInformer + DynamicClient dynamic.Interface + ClusterScopedResources hashset.Set + ClusterHostname string +} + +// excludedGroupsKinds mirrors Argo CD's default resource.exclusions for +// internal / noisy resources. We skip these when building the relation cache +// to reduce API traffic and cache size. +var excludedGroupsKinds = map[string]map[string]bool{ + "": { // core + "Endpoints": true, + }, + "discovery.k8s.io": { + "EndpointSlice": true, + }, + "coordination.k8s.io": { + "Lease": true, + }, + "authentication.k8s.io": { + "SelfSubjectReview": true, + "TokenReview": true, + }, + "authorization.k8s.io": { + "LocalSubjectAccessReview": true, + "SelfSubjectAccessReview": true, + "SelfSubjectRulesReview": true, + "SubjectAccessReview": true, + }, + "certificates.k8s.io": { + "CertificateSigningRequest": true, + }, + "cert-manager.io": { + "CertificateRequest": true, + }, + "cilium.io": { + "CiliumIdentity": true, + "CiliumEndpoint": true, + "CiliumEndpointSlice": true, + }, + "kyverno.io": { + "EphemeralReport": true, + "ClusterEphemeralReport": true, + "AdmissionReport": true, + "ClusterAdmissionReport": true, + "BackgroundScanReport": true, + "ClusterBackgroundScanReport": true, + "UpdateRequest": true, + }, + "reports.kyverno.io": { + "PolicyReport": true, + "ClusterPolicyReport": true, + }, + "wgpolicyk8s.io": { + "PolicyReport": true, + "ClusterPolicyReport": true, + }, +} + +func isExcludedKind(group, kind string) bool { + if m, ok := excludedGroupsKinds[group]; ok { + return m[kind] + } + return false +} + +func NewResourceMapper(destinationConfig *rest.Config) (*ResourceMapper, error) { + destinationConfig.QPS = 50 + destinationConfig.Burst = 100 + apiextensionsClient, err := apiextensionsclient.NewForConfig(destinationConfig) + if err != nil { + return nil, fmt.Errorf("failed to create apiextensions client: %w", err) + } + + // Create informer factory + informerFactory := apiextensionsinformer.NewSharedInformerFactory(apiextensionsClient, 0) + + // Get CRD informer + crdInformer := informerFactory.Apiextensions().V1().CustomResourceDefinitions().Informer() + + discoveryClient, err := discovery.NewDiscoveryClientForConfig(destinationConfig) + if err != nil { + return nil, fmt.Errorf("failed to create discovery client: %w", err) + } + // Create dynamic client + dynamicClient, err := dynamic.NewForConfig(destinationConfig) + if err != nil { + return nil, fmt.Errorf("failed to create dynamic client: %w", err) + } + + rm := &ResourceMapper{ + DiscoveryClient: discoveryClient, + DynamicClient: dynamicClient, + InformerFactory: informerFactory, + CRDInformer: crdInformer, + ResourceList: *hashset.New(), + ClusterScopedResources: *hashset.New(), + ClusterHostname: destinationConfig.Host, + } + + if err := rm.Init(); err != nil { + return nil, fmt.Errorf("failed to contact cluster: %w", err) + } + + // Set up event handlers + crdInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: rm.addToResourceList, + UpdateFunc: func(oldObj, newObj interface{}) { + oldCRD, ok1 := oldObj.(*apiextensionsv1.CustomResourceDefinition) + newCRD, ok2 := newObj.(*apiextensionsv1.CustomResourceDefinition) + if !ok1 || !ok2 { + log.Errorf("Failed to convert objects to CRD") + return + } + // Compare the spec fields before reprocessing + if reflect.DeepEqual(oldCRD.Spec, newCRD.Spec) { + log.Debugf("CRD %s update ignored as there is no spec change", newCRD.Name) + return + } + rm.addToResourceList(newObj) + }, + }) + return rm, nil +} + +func (r *ResourceMapper) addToResourceList(obj interface{}) { + crd, ok := obj.(*apiextensionsv1.CustomResourceDefinition) + if !ok { + log.Errorf("Failed to convert object to CRD") + return + } + + for _, version := range crd.Spec.Versions { + if !version.Served { + continue // Skip versions that are not served + } + + // Check if the CRD is namespaced + if !(crd.Spec.Scope == apiextensionsv1.NamespaceScoped) { + gv := fmt.Sprintf("%s/%s", crd.Spec.Group, version.Name) + key := GetResourceKey(gv, crd.Spec.Names.Kind) + //log.Infof("Adding cluster scoped resource: %s", key) + r.ClusterScopedResources.Add(key) + continue + } + + gvr := schema.GroupVersionResource{ + Group: crd.Spec.Group, + Version: version.Name, + Resource: crd.Spec.Names.Plural, // CRD resources are named using the `plural` field + } + + // Log whether we're updating or adding a new CRD version + if r.ResourceList.Contains(gvr) { + // log.Debugf("Updating existing CRD version: %s/%s (%s)", gvr.Group, gvr.Version, gvr.Resource) + } else { + //log.Infof("Adding new CRD version: %s/%s (%s)", gvr.Group, gvr.Version, gvr.Resource) + } + + r.ResourceList.Add(gvr) + // Add the served version of CRD to ResourceList + } +} + +func (r *ResourceMapper) Init() error { + // Get API resource list + resourceList, err := r.DiscoveryClient.ServerPreferredResources() + if err != nil { + if len(resourceList) == 0 { + return err + } + log.Errorf("Partial success when performing preferred resource discovery: %v", err) + } + for _, resourceGroup := range resourceList { + for _, resource := range resourceGroup.APIResources { + gv, err := schema.ParseGroupVersion(resourceGroup.GroupVersion) + if err != nil { + continue + } + // Record cluster-scoped kinds for quick detection + if !resource.Namespaced { + groupVersion := gv.Version + if gv.Group != "" { + groupVersion = fmt.Sprintf("%s/%s", gv.Group, gv.Version) + } + key := GetResourceKey(groupVersion, resource.Kind) + r.ClusterScopedResources.Add(key) + // Skip adding to ResourceList, since we only scan namespaced kinds + continue + } + // Skip noisy / internal resources based on Argo CD's resource.exclusions + if isExcludedKind(gv.Group, resource.Kind) { + continue + } + + gvr := schema.GroupVersionResource{ + Group: gv.Group, + Version: gv.Version, + Resource: resource.Name, + } + r.ResourceList.Add(gvr) + } + } + return nil +} + +// GetResourceKey returns the key for a given resource. +func GetResourceKey(groupVersion, kind string) string { + group := "" + splitGroupVersion := strings.Split(groupVersion, "/") + if len(splitGroupVersion) > 1 { + group = splitGroupVersion[0] + } else { + group = "core" + } + return fmt.Sprintf("%s_%s", group, kind) +} +func (r *ResourceMapper) StartInformer() { + log.Info("Starting informer for cluster ", r.ClusterHostname) + r.InformerFactory.Start(context.Background().Done()) +} + +// GetResourcesRelation retrieves a mapping of parent resource kinds to their child resource kinds. +func (r *ResourceMapper) GetClusterResourcesRelation(ctx context.Context) (map[string]*hashset.Set, error) { + resourceRelation := make(map[string]*hashset.Set) + // Iterate over all API resources + for _, value := range r.ResourceList.Values() { + gvr, ok := value.(schema.GroupVersionResource) + if !ok { + log.Errorf("Failed to assert type for gvr: %v", value) + continue + } + var continueToken string + for { + resourceList, err := r.DynamicClient.Resource(gvr).Namespace(v1.NamespaceAll).List(ctx, v1.ListOptions{ + Limit: 250, + Continue: continueToken, + }) + if err != nil { + if !k8sErrors.IsNotFound(err) { + log.Errorf("Failed to list resource %s: %v", gvr, err) + } + break + } + // Process each resource + for _, item := range resourceList.Items { + // Skip excluded resources entirely + gvk := item.GroupVersionKind() + if isExcludedKind(gvk.Group, gvk.Kind) { + continue + } + for _, ownerRef := range item.GetOwnerReferences() { + parent := GetResourceKey(ownerRef.APIVersion, ownerRef.Kind) + child := GetResourceKey(item.GetAPIVersion(), item.GetKind()) + // Initialize resourceRelation[parent] if not present + if _, exists := resourceRelation[parent]; !exists { + resourceRelation[parent] = hashset.New() + } + resourceRelation[parent].Add(child) + } + // Special case + if item.GetKind() == "ClusterServiceVersion" { + parent := GetResourceKey("operators.coreos.com/v1", "OperatorGroup") + child := GetResourceKey(item.GetAPIVersion(), item.GetKind()) + if _, exists := resourceRelation[parent]; !exists { + resourceRelation[parent] = hashset.New() + } + resourceRelation[parent].Add(child) + } + if item.GetKind() == "Secret" { + parent := GetResourceKey("v1", "ServiceAccount") + child := GetResourceKey(item.GetAPIVersion(), item.GetKind()) + if _, exists := resourceRelation[parent]; !exists { + resourceRelation[parent] = hashset.New() + } + resourceRelation[parent].Add(child) + } + if item.GetKind() == "volumeClaimTemplates" { + // add sts as parent + parent := GetResourceKey("apps/v1", "StatefulSet") + child := GetResourceKey(item.GetAPIVersion(), item.GetKind()) + if _, exists := resourceRelation[parent]; !exists { + resourceRelation[parent] = hashset.New() + } + resourceRelation[parent].Add(child) + } + } + // Check if there are more results to fetch + continueToken = resourceList.GetContinue() + if continueToken == "" { + break + } + } + } + + return resourceRelation, nil +} + +// GetResourceRelation builds a parent->children map of resource keys reachable +// from the provided resources, using the relation cache. +func GetResourceRelation( + resourceRelation map[string]*hashset.Set, + directChildren []*common.ResourceInfo, +) []*common.ResourceInfo { + visitedKeys := make(map[string]struct{}) + for _, direct := range directChildren { + group := direct.Group + if group == "" { + group = "core" + } + rootKey := fmt.Sprintf("%s_%s", group, direct.Kind) + dfs(resourceRelation, rootKey, visitedKeys) + } + // Convert visitedKeys -> []common.ResourceInfo + out := make([]*common.ResourceInfo, 0, len(visitedKeys)) + for key := range visitedKeys { + parts := strings.SplitN(key, "_", 2) + if len(parts) != 2 { + continue + } + groupSeg, kind := parts[0], parts[1] + group := groupSeg + if groupSeg == "core" { + group = "" + } + out = append(out, &common.ResourceInfo{ + Group: group, + Kind: kind, + // Name/Namespace can stay empty; grouping ignores them + }) + } + return out +} + +func dfs(rel map[string]*hashset.Set, key string, visited map[string]struct{}) { + if _, ok := visited[key]; ok { + return + } + visited[key] = struct{}{} + childrenSet, ok := rel[key] + if !ok { + return + } + for _, v := range childrenSet.Values() { + childKey, ok := v.(string) + if !ok { + continue + } + dfs(rel, childKey, visited) + } +} diff --git a/pkg/graph/query.go b/pkg/graph/query.go index f11029b..a90294e 100644 --- a/pkg/graph/query.go +++ b/pkg/graph/query.go @@ -5,6 +5,7 @@ import ( "os" "strings" + "github.com/anandf/resource-tracker/pkg/common" "github.com/avitaltamir/cyphernetes/pkg/core" "github.com/avitaltamir/cyphernetes/pkg/provider" "github.com/avitaltamir/cyphernetes/pkg/provider/apiserver" @@ -70,27 +71,27 @@ var ( "Namespace": true, } - defaultIncludedResources = ResourceInfoSet{ - ResourceInfo{ - Kind: "ConfigMap", - APIVersion: "v1", - }: Void{}, - ResourceInfo{ - Kind: "Secret", - APIVersion: "v1", - }: Void{}, - ResourceInfo{ - Kind: "ServiceAccount", - APIVersion: "v1", - }: Void{}, - ResourceInfo{ - Kind: "Pod", - APIVersion: "v1", - }: Void{}, - ResourceInfo{ - Kind: "Namespace", - APIVersion: "v1", - }: Void{}, + defaultIncludedResources = common.ResourceInfoSet{ + common.ResourceInfo{ + Kind: "ConfigMap", + Group: "", + }: common.Void{}, + common.ResourceInfo{ + Kind: "Secret", + Group: "", + }: common.Void{}, + common.ResourceInfo{ + Kind: "ServiceAccount", + Group: "", + }: common.Void{}, + common.ResourceInfo{ + Kind: "Pod", + Group: "", + }: common.Void{}, + common.ResourceInfo{ + Kind: "Namespace", + Group: "", + }: common.Void{}, } ) @@ -100,7 +101,7 @@ type QueryServer struct { FieldAMatchCriteria string Tracker string Comparison core.ComparisonType - VisitedKinds map[ResourceInfo]bool + VisitedKinds map[common.ResourceInfo]bool } func NewQueryServer(restConfig *rest.Config, trackingMethod string, loadCustomRules bool) (*QueryServer, error) { @@ -158,19 +159,24 @@ func NewQueryServer(restConfig *rest.Config, trackingMethod string, loadCustomRu Tracker: tracker, FieldAMatchCriteria: fieldAMatchCriteria, Comparison: comparison, - VisitedKinds: make(map[ResourceInfo]bool), + VisitedKinds: make(map[common.ResourceInfo]bool), }, nil } -func (q *QueryServer) GetApplicationChildResources(name, namespace string) (ResourceInfoSet, error) { - return q.GetNestedChildResources(&ResourceInfo{Kind: "applications.argoproj.io", Name: name, Namespace: namespace}) +func (q *QueryServer) GetApplicationChildResources(name, namespace string) (common.ResourceInfoSet, error) { + return q.GetNestedChildResources(&common.ResourceInfo{ + Kind: "applications.argoproj.io", + Group: "argoproj.io", + Name: name, + Namespace: namespace, + }) } -func (q *QueryServer) GetNestedChildResources(resource *ResourceInfo) (ResourceInfoSet, error) { - allLevelChildren := make(ResourceInfoSet) +func (q *QueryServer) GetNestedChildResources(resource *common.ResourceInfo) (common.ResourceInfoSet, error) { + allLevelChildren := make(common.ResourceInfoSet) for resInfo := range defaultIncludedResources { - allLevelChildren[resInfo] = Void{} + allLevelChildren[resInfo] = common.Void{} q.VisitedKinds[resInfo] = true } allLevelChildren, err := q.depthFirstTraversal(resource, allLevelChildren) @@ -181,18 +187,18 @@ func (q *QueryServer) GetNestedChildResources(resource *ResourceInfo) (ResourceI } // getChildren returns the immediate direct child of a given node by doing a graph query. -func (q *QueryServer) getChildren(parentResourceInfo *ResourceInfo) ([]*ResourceInfo, error) { +func (q *QueryServer) getChildren(parentResourceInfo *common.ResourceInfo) ([]*common.ResourceInfo, error) { if leafKinds[parentResourceInfo.Kind] || blackListedKinds[parentResourceInfo.Kind] { log.Infof("skipping leaf or blacklisted resource: %v", parentResourceInfo) return nil, nil } - visitedKindKey := ResourceInfo{Kind: parentResourceInfo.Kind, APIVersion: parentResourceInfo.APIVersion} + visitedKindKey := common.ResourceInfo{Kind: parentResourceInfo.Kind, Group: parentResourceInfo.Group} if _, ok := q.VisitedKinds[visitedKindKey]; ok { log.Infof("skipping resource %v as kind already visited", parentResourceInfo) return nil, nil } unambiguousKind := parentResourceInfo.Kind - if parentResourceInfo.APIVersion == "v1" { + if parentResourceInfo.Group == "" { unambiguousKind = fmt.Sprintf("%s.%s", "core", parentResourceInfo.Kind) } // Get the query string @@ -229,7 +235,7 @@ func (q *QueryServer) executeQuery(queryStr, namespace string) (*core.QueryResul } // depthFirstTraversal recursively traverses the resource tree using a DFS approach. -func (q *QueryServer) depthFirstTraversal(info *ResourceInfo, visitedNodes ResourceInfoSet) (ResourceInfoSet, error) { +func (q *QueryServer) depthFirstTraversal(info *common.ResourceInfo, visitedNodes common.ResourceInfoSet) (common.ResourceInfoSet, error) { if info == nil { return visitedNodes, nil } @@ -238,7 +244,7 @@ func (q *QueryServer) depthFirstTraversal(info *ResourceInfo, visitedNodes Resou log.Debugf("Resource visited already: %v", info) return visitedNodes, nil } - visitedNodes[*info] = Void{} + visitedNodes[*info] = common.Void{} // 2. Get children of the current node children, err := q.getChildren(info) if err != nil { @@ -273,12 +279,12 @@ func (q *QueryServer) AddRuleForResourceKind(resourceKind string) { } // extractResourceInfo extracts the ResourceInfo from a given query result and variable name. -func extractResourceInfo(queryResult *core.QueryResult, variable string) ([]*ResourceInfo, error) { +func extractResourceInfo(queryResult *core.QueryResult, variable string) ([]*common.ResourceInfo, error) { child := queryResult.Data[variable] if child == nil { return nil, nil } - resourceInfoList := make([]*ResourceInfo, 0, len(child.([]interface{}))) + resourceInfoList := make([]*common.ResourceInfo, 0, len(child.([]interface{}))) for _, meta := range child.([]interface{}) { info, ok := meta.(map[string]interface{}) if !ok { @@ -289,10 +295,18 @@ func extractResourceInfo(queryResult *core.QueryResult, variable string) ([]*Res log.Infof("ignoring resource of kind: %v", info["kind"]) continue } - resourceInfo := ResourceInfo{ - Kind: info["kind"].(string), - APIVersion: info["apiVersion"].(string), - Name: info["name"].(string), + apiVersion, _ := info["apiVersion"].(string) + group := "" + if apiVersion != "" { + parts := strings.Split(apiVersion, "/") + if len(parts) == 2 { + group = parts[0] + } + } + resourceInfo := common.ResourceInfo{ + Kind: info["kind"].(string), + Group: group, + Name: info["name"].(string), } metadata, ok := info["metadata"].(map[string]interface{}) if !ok { diff --git a/pkg/kube/kubernetes.go b/pkg/kube/kubernetes.go index 81746e0..6dbc3a0 100644 --- a/pkg/kube/kubernetes.go +++ b/pkg/kube/kubernetes.go @@ -4,11 +4,15 @@ import ( "context" "errors" "fmt" + "net/http" + "strings" - "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned" + "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" + "github.com/argoproj/argo-cd/v3/pkg/client/clientset/versioned" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" + clientauthapi "k8s.io/client-go/tools/clientcmd/api" ) type ResourceTrackerKubeClient struct { @@ -73,3 +77,106 @@ func GetKubeConfig(kubeconfigPath string) (*rest.Config, error) { } return restConfig, nil } + +// RestConfigFromCluster creates a rest.Config from a cluster +func RestConfigFromCluster(c *v1alpha1.Cluster, kubeconfigPath string) (*rest.Config, error) { + tls := rest.TLSClientConfig{ + Insecure: c.Config.Insecure, + ServerName: c.Config.ServerName, + CertData: c.Config.CertData, + KeyData: c.Config.KeyData, + CAData: c.Config.CAData, + } + + var cfg *rest.Config + + // if the server is in-cluster, load the kubeconfig from the kubeconfig file or the default kubeconfig file + if strings.Contains(c.Server, "kubernetes.default.svc") { + localCfg, err := rest.InClusterConfig() + if err != nil && !errors.Is(err, rest.ErrNotInCluster) { + return nil, fmt.Errorf("failed to create config: %v", err) + } + if localCfg == nil { + if kubeconfigPath != "" { + localCfg, err = clientcmd.BuildConfigFromFlags("", kubeconfigPath) + } else { + loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() + configOverrides := &clientcmd.ConfigOverrides{} + kubeCfg := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides) + localCfg, err = kubeCfg.ClientConfig() + } + if err != nil { + return nil, fmt.Errorf("failed to load kubeconfig: %w", err) + } + } + cfg = localCfg + } else { + + switch { + case c.Config.AWSAuthConfig != nil: + // EKS via argocd-k8s-auth (same contract as Argo CD) + args := []string{"aws", "--cluster-name", c.Config.AWSAuthConfig.ClusterName} + if c.Config.AWSAuthConfig.RoleARN != "" { + args = append(args, "--role-arn", c.Config.AWSAuthConfig.RoleARN) + } + if c.Config.AWSAuthConfig.Profile != "" { + args = append(args, "--profile", c.Config.AWSAuthConfig.Profile) + } + cfg = &rest.Config{ + Host: c.Server, + TLSClientConfig: tls, + ExecProvider: &clientauthapi.ExecConfig{ + APIVersion: "client.authentication.k8s.io/v1beta1", + Command: "argocd-k8s-auth", + Args: args, + InteractiveMode: clientauthapi.NeverExecInteractiveMode, + }, + } + + case c.Config.ExecProviderConfig != nil: + // Generic exec provider (OIDC, SSO, etc.) + var env []clientauthapi.ExecEnvVar + for k, v := range c.Config.ExecProviderConfig.Env { + env = append(env, clientauthapi.ExecEnvVar{Name: k, Value: v}) + } + cfg = &rest.Config{ + Host: c.Server, + TLSClientConfig: tls, + ExecProvider: &clientauthapi.ExecConfig{ + APIVersion: c.Config.ExecProviderConfig.APIVersion, + Command: c.Config.ExecProviderConfig.Command, + Args: c.Config.ExecProviderConfig.Args, + Env: env, + InstallHint: c.Config.ExecProviderConfig.InstallHint, + InteractiveMode: clientauthapi.NeverExecInteractiveMode, + }, + } + + default: + // Static auth (token or basic) and TLS + cfg = &rest.Config{ + Host: c.Server, + Username: c.Config.Username, + Password: c.Config.Password, + BearerToken: c.Config.BearerToken, + TLSClientConfig: tls, + } + } + } + + if c.Config.ProxyUrl != "" { + u, err := v1alpha1.ParseProxyUrl(c.Config.ProxyUrl) + if err != nil { + return nil, fmt.Errorf("failed to parse proxy url: %w", err) + } + cfg.Proxy = http.ProxyURL(u) + } + // Apply Argo CD defaults + cfg.DisableCompression = c.Config.DisableCompression + cfg.Timeout = v1alpha1.K8sServerSideTimeout + cfg.QPS = v1alpha1.K8sClientConfigQPS + cfg.Burst = v1alpha1.K8sClientConfigBurst + v1alpha1.SetK8SConfigDefaults(cfg) + + return cfg, nil +} diff --git a/pkg/kube/kubernetes_test.go b/pkg/kube/kubernetes_test.go index 6a5a7df..2027779 100644 --- a/pkg/kube/kubernetes_test.go +++ b/pkg/kube/kubernetes_test.go @@ -11,14 +11,18 @@ import ( func Test_NewKubernetesClientFromConfig(t *testing.T) { t.Run("Get new K8s client for remote cluster instance", func(t *testing.T) { - client, err := NewKubernetesClientFromConfig(context.TODO(), "", "../../test/testdata/kubernetes/config") + config, err := GetKubeConfig("../../test/testdata/kubernetes/config") + require.NoError(t, err) + client, err := NewKubernetesClientFromConfig(context.TODO(), "", config) require.NoError(t, err) assert.NotNil(t, client) assert.Equal(t, "default", client.KubeClient.Namespace) }) t.Run("Get new K8s client for remote cluster instance specified namespace", func(t *testing.T) { - client, err := NewKubernetesClientFromConfig(context.TODO(), "argocd", "../../test/testdata/kubernetes/config") + config, err := GetKubeConfig("../../test/testdata/kubernetes/config") + require.NoError(t, err) + client, err := NewKubernetesClientFromConfig(context.TODO(), "argocd", config) require.NoError(t, err) assert.NotNil(t, client) assert.Equal(t, "argocd", client.KubeClient.Namespace) diff --git a/pkg/argocd/repo.go b/pkg/repo/repo.go similarity index 54% rename from pkg/argocd/repo.go rename to pkg/repo/repo.go index f991bd5..d08c87e 100644 --- a/pkg/argocd/repo.go +++ b/pkg/repo/repo.go @@ -1,19 +1,19 @@ -package argocd +package repo import ( "context" "fmt" - "github.com/argoproj/argo-cd/v2/common" - appsv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" - "github.com/argoproj/argo-cd/v2/reposerver/apiclient" - "github.com/argoproj/argo-cd/v2/util/argo" - "github.com/argoproj/argo-cd/v2/util/db" - "github.com/argoproj/argo-cd/v2/util/env" - "github.com/argoproj/argo-cd/v2/util/io" - kubeutil "github.com/argoproj/argo-cd/v2/util/kube" - "github.com/argoproj/argo-cd/v2/util/settings" - "github.com/argoproj/argo-cd/v2/util/tls" + "github.com/argoproj/argo-cd/v3/common" + appsv1alpha1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" + "github.com/argoproj/argo-cd/v3/reposerver/apiclient" + "github.com/argoproj/argo-cd/v3/util/argo" + "github.com/argoproj/argo-cd/v3/util/db" + "github.com/argoproj/argo-cd/v3/util/env" + "github.com/argoproj/argo-cd/v3/util/io" + kubeutil "github.com/argoproj/argo-cd/v3/util/kube" + "github.com/argoproj/argo-cd/v3/util/settings" + "github.com/argoproj/argo-cd/v3/util/tls" "github.com/argoproj/gitops-engine/pkg/utils/kube" log "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -61,7 +61,6 @@ func NewRepoServerManager(kubeConfig *rest.Config, } repoClientset := apiclient.NewRepoServerClientset(repoServerAddress, repoServerTimeoutSeconds, tlsConfig) kubectl := kubeutil.NewKubectl() - return &RepoServerManager{ db: dbInstance, settingsMgr: settingsMgr, @@ -72,68 +71,40 @@ func NewRepoServerManager(kubeConfig *rest.Config, } // GetApplicationChildManifests fetches manifests and filters direct child resources -func (r *RepoServerManager) GetApplicationChildManifests(ctx context.Context, application *appsv1alpha1.Application, proj *appsv1alpha1.AppProject) ([]*unstructured.Unstructured, *rest.Config, error) { +func (r *RepoServerManager) GetApplicationChildManifests(ctx context.Context, application *appsv1alpha1.Application, proj *appsv1alpha1.AppProject, kubeconfig string) ([]*unstructured.Unstructured, error) { // Fetch Helm repositories helmRepos, err := r.db.ListHelmRepositories(ctx) if err != nil { - return nil, nil, fmt.Errorf("error fetching Helm repositories: %w", err) + return nil, fmt.Errorf("error fetching Helm repositories: %w", err) } // Filter permitted Helm repositories permittedHelmRepos, err := argo.GetPermittedRepos(proj, helmRepos) if err != nil { - return nil, nil, fmt.Errorf("error filtering permitted Helm repositories: %w", err) + return nil, fmt.Errorf("error filtering permitted Helm repositories: %w", err) } // Fetch Helm repository credentials helmRepositoryCredentials, err := r.db.GetAllHelmRepositoryCredentials(ctx) if err != nil { - return nil, nil, fmt.Errorf("error fetching Helm repository credentials: %w", err) + return nil, fmt.Errorf("error fetching Helm repository credentials: %w", err) } // Filter permitted Helm credentials permittedHelmCredentials, err := argo.GetPermittedReposCredentials(proj, helmRepositoryCredentials) if err != nil { - return nil, nil, fmt.Errorf("error filtering permitted Helm credentials: %w", err) + return nil, fmt.Errorf("error filtering permitted Helm credentials: %w", err) } // Get enabled source types enabledSourceTypes, err := r.settingsMgr.GetEnabledSourceTypes() if err != nil { - return nil, nil, fmt.Errorf("error getting enabled source types: %w", err) - } - // Fetch Helm settings - helmOptions, err := r.settingsMgr.GetHelmSettings() - if err != nil { - return nil, nil, fmt.Errorf("error fetching Helm settings: %w", err) - } - // Get installation ID - installationID, err := r.settingsMgr.GetInstallationID() - if err != nil { - return nil, nil, fmt.Errorf("error getting installation ID: %w", err) + return nil, fmt.Errorf("error getting enabled source types: %w", err) } kustomizeSettings, err := r.settingsMgr.GetKustomizeSettings() if err != nil { - return nil, nil, fmt.Errorf("error fetching Kustomize settings: %w", err) - } - server := application.Spec.Destination.Server - if server == "" { - if application.Spec.Destination.Name == "" { - return nil, nil, fmt.Errorf("both destination server and name are empty") - } - server, err = getDestinationServer(ctx, r.db, application.Spec.Destination.Name) - if err != nil { - return nil, nil, fmt.Errorf("error getting cluster: %w", err) - } - } - cluster, err := r.db.GetCluster(ctx, server) - if err != nil { - return nil, nil, fmt.Errorf("error getting cluster: %w", err) - } - clusterAPIDetails, err := getClusterAPIDetails(cluster.RESTConfig(), r.kubectl) - if err != nil { - return nil, nil, fmt.Errorf("error fetching cluster API details: %w", err) + return nil, fmt.Errorf("error fetching Kustomize settings: %w", err) } // Establish a connection with the repo-server conn, repoClient, err := r.repoClientset.NewRepoServerClient() if err != nil { - return nil, nil, fmt.Errorf("error connecting to repo-server: %w", err) + return nil, fmt.Errorf("error connecting to repo-server: %w", err) } defer io.Close(conn) sources := make([]appsv1alpha1.ApplicationSource, 0) @@ -150,50 +121,41 @@ func (r *RepoServerManager) GetApplicationChildManifests(ctx context.Context, ap } refSources, err := argo.GetRefSources(ctx, sources, application.Spec.Project, r.db.GetRepository, revisions, false) if err != nil { - return nil, nil, fmt.Errorf("error getting ref sources: %w", err) + return nil, fmt.Errorf("error getting ref sources: %w", err) } targetObjs := make([]*unstructured.Unstructured, 0) for i, source := range sources { repo, err := r.db.GetRepository(ctx, source.RepoURL, proj.Name) if err != nil { - return nil, nil, fmt.Errorf("error fetching repository: %w", err) + return nil, fmt.Errorf("error fetching repository: %w", err) } kustomizeOptions, err := kustomizeSettings.GetOptions(source) if err != nil { - return nil, nil, fmt.Errorf("error getting ref sources: %w", err) + return nil, fmt.Errorf("error getting ref sources: %w", err) } // Generate manifest using the RepoServer client manifestInfo, err := repoClient.GenerateManifest(ctx, &apiclient.ManifestRequest{ Repo: repo, Repos: permittedHelmRepos, Revision: revisions[i], - AppName: application.InstanceName(r.controllerNS), - Namespace: application.Spec.Destination.Namespace, ApplicationSource: &source, + EnabledSourceTypes: enabledSourceTypes, KustomizeOptions: kustomizeOptions, - KubeVersion: clusterAPIDetails.APIVersions, - ApiVersions: argo.APIResourcesToStrings(clusterAPIDetails.APIResources, true), HelmRepoCreds: permittedHelmCredentials, - TrackingMethod: string(argo.GetTrackingMethod(r.settingsMgr)), - EnabledSourceTypes: enabledSourceTypes, - HelmOptions: helmOptions, HasMultipleSources: application.Spec.HasMultipleSources(), RefSources: refSources, - ProjectName: proj.Name, - ProjectSourceRepos: proj.Spec.SourceRepos, - InstallationID: installationID, }) if err != nil { - return nil, nil, fmt.Errorf("error generating manifest: %w", err) + return nil, fmt.Errorf("error generating manifest: %w", err) } targetObj, err := unmarshalManifests(manifestInfo.Manifests) if err != nil { - return nil, nil, fmt.Errorf("error unmarshalling manifests: %w", err) + return nil, fmt.Errorf("error unmarshalling manifests: %w", err) } targetObjs = append(targetObjs, targetObj...) log.Debugf("Successfully fetched %v target manifest(s) from repo-server for application: %s. Manifests: %v", len(manifestInfo.Manifests), application.Name, manifestInfo.Manifests) } - return targetObjs, cluster.RESTConfig(), nil + return targetObjs, nil } func unmarshalManifests(manifests []string) ([]*unstructured.Unstructured, error) { @@ -207,36 +169,3 @@ func unmarshalManifests(manifests []string) ([]*unstructured.Unstructured, error } return targetObjs, nil } - -// getClusterAPIDetails retrieves the server version and API resources from the Kubernetes cluster -func getClusterAPIDetails(config *rest.Config, kubectl kube.Kubectl) (*clusterAPIDetails, error) { - // Retrieve the server version - serverVersion, err := kubectl.GetServerVersion(config) - if err != nil { - return nil, fmt.Errorf("failed to get server version: %w", err) - } - // Retrieve the API resources - apiResources, err := kubectl.GetAPIResources(config, false, &settings.ResourcesFilter{}) - if err != nil { - return nil, fmt.Errorf("failed to get API resources: %w", err) - } - // Return the combined details - return &clusterAPIDetails{ - APIVersions: serverVersion, - APIResources: apiResources, - }, nil -} - -// getDestinationServer retrieves the server version and API resources from the Kubernetes cluster -func getDestinationServer(ctx context.Context, db db.ArgoDB, clusterName string) (string, error) { - servers, err := db.GetClusterServersByName(ctx, clusterName) - if err != nil { - return "", fmt.Errorf("error getting cluster server by name %q: %w", clusterName, err) - } - if len(servers) > 1 { - return "", fmt.Errorf("there are %d clusters with the same name: %v", len(servers), servers) - } else if len(servers) == 0 { - return "", fmt.Errorf("there are no clusters with this name: %s", clusterName) - } - return servers[0], nil -}