From 10809762cf810249a6380e3523e1febe7b8aef95 Mon Sep 17 00:00:00 2001 From: Simon Herrmann Date: Wed, 28 Jan 2026 15:53:55 +0100 Subject: [PATCH 01/12] refac(bootstrap): big refactor of the gcp bootstrapper, add tests --- .mockery.yml | 8 + cli/cmd/bootstrap_gcp.go | 49 +- internal/bootstrap/bootstrap_stepper.go | 84 + internal/bootstrap/gcp.go | 1429 --------- .../bootstrap/gcp/bootstrap_suite_test.go | 16 + internal/bootstrap/gcp/gcp.go | 1349 +++++++++ internal/bootstrap/gcp/gcp_client.go | 647 +++++ internal/bootstrap/gcp/gcp_test.go | 2559 +++++++++++++++++ internal/bootstrap/gcp/mocks.go | 1316 +++++++++ internal/bootstrap/gcp_client.go | 440 --- internal/bootstrap/ovh/ovh.go | 12 + internal/installer/config_manager_profile.go | 4 - internal/installer/node/mocks.go | 955 ++++++ internal/installer/node/node.go | 656 +++-- internal/util/path.go | 17 + internal/util/string.go | 9 + 16 files changed, 7372 insertions(+), 2178 deletions(-) create mode 100644 internal/bootstrap/bootstrap_stepper.go delete mode 100644 internal/bootstrap/gcp.go create mode 100644 internal/bootstrap/gcp/bootstrap_suite_test.go create mode 100644 internal/bootstrap/gcp/gcp.go create mode 100644 internal/bootstrap/gcp/gcp_client.go create mode 100644 internal/bootstrap/gcp/gcp_test.go create mode 100644 internal/bootstrap/gcp/mocks.go delete mode 100644 internal/bootstrap/gcp_client.go create mode 100644 internal/bootstrap/ovh/ovh.go create mode 100644 internal/installer/node/mocks.go create mode 100644 internal/util/path.go create mode 100644 internal/util/string.go diff --git a/.mockery.yml b/.mockery.yml index fba11d22..8e543a70 100644 --- a/.mockery.yml +++ b/.mockery.yml @@ -14,6 +14,10 @@ require-template-schema-exists: true template: testify template-schema: "{{.Template}}.schema.json" packages: + github.com/codesphere-cloud/oms/internal/bootstrap/gcp: + config: + all: true + interfaces: github.com/codesphere-cloud/oms/internal/env: config: all: true @@ -22,6 +26,10 @@ packages: config: all: true interfaces: + github.com/codesphere-cloud/oms/internal/installer/node: + config: + all: true + interfaces: github.com/codesphere-cloud/oms/internal/portal: config: all: true diff --git a/cli/cmd/bootstrap_gcp.go b/cli/cmd/bootstrap_gcp.go index 9dd476b6..ed5b50aa 100644 --- a/cli/cmd/bootstrap_gcp.go +++ b/cli/cmd/bootstrap_gcp.go @@ -13,21 +13,22 @@ import ( "github.com/codesphere-cloud/cs-go/pkg/io" "github.com/codesphere-cloud/oms/internal/bootstrap" + "github.com/codesphere-cloud/oms/internal/bootstrap/gcp" "github.com/codesphere-cloud/oms/internal/env" + "github.com/codesphere-cloud/oms/internal/installer" + "github.com/codesphere-cloud/oms/internal/installer/node" "github.com/codesphere-cloud/oms/internal/util" ) type BootstrapGcpCmd struct { - cmd *cobra.Command - Opts *GlobalOptions - Env env.Env - CodesphereEnv *bootstrap.CodesphereEnvironment - + cmd *cobra.Command + Opts *GlobalOptions + Env env.Env + CodesphereEnv *gcp.CodesphereEnvironment InputRegistryType string } func (c *BootstrapGcpCmd) RunE(_ *cobra.Command, args []string) error { - err := c.BootstrapGcp() if err != nil { return fmt.Errorf("failed to bootstrap: %w", err) @@ -49,7 +50,7 @@ func AddBootstrapGcpCmd(root *cobra.Command, opts *GlobalOptions) { }, Opts: opts, Env: env.NewEnv(), - CodesphereEnv: &bootstrap.CodesphereEnvironment{}, + CodesphereEnv: &gcp.CodesphereEnvironment{}, } flags := bootstrapGcpCmd.cmd.Flags() @@ -65,8 +66,8 @@ func AddBootstrapGcpCmd(root *cobra.Command, opts *GlobalOptions) { flags.BoolVar(&bootstrapGcpCmd.CodesphereEnv.Preemptible, "preemptible", false, "Use preemptible VMs for Codesphere infrastructure (default: false)") flags.IntVar(&bootstrapGcpCmd.CodesphereEnv.DatacenterID, "datacenter-id", 1, "Datacenter ID (default: 1)") flags.StringVar(&bootstrapGcpCmd.CodesphereEnv.CustomPgIP, "custom-pg-ip", "", "Custom PostgreSQL IP (optional)") - flags.StringVar(&bootstrapGcpCmd.CodesphereEnv.InstallConfig, "install-config", "config.yaml", "Path to install config file (optional)") - flags.StringVar(&bootstrapGcpCmd.CodesphereEnv.SecretsFile, "secrets-file", "prod.vault.yaml", "Path to secrets files (optional)") + flags.StringVar(&bootstrapGcpCmd.CodesphereEnv.InstallConfigPath, "install-config", "config.yaml", "Path to install config file (optional)") + flags.StringVar(&bootstrapGcpCmd.CodesphereEnv.SecretsFilePath, "secrets-file", "prod.vault.yaml", "Path to secrets files (optional)") flags.StringVar(&bootstrapGcpCmd.CodesphereEnv.Region, "region", "europe-west4", "GCP Region (default: europe-west4)") flags.StringVar(&bootstrapGcpCmd.CodesphereEnv.Zone, "zone", "europe-west4-a", "GCP Zone (default: europe-west4-a)") flags.StringVar(&bootstrapGcpCmd.CodesphereEnv.DNSProjectID, "dns-project-id", "", "GCP Project ID for Cloud DNS (optional)") @@ -84,33 +85,37 @@ func AddBootstrapGcpCmd(root *cobra.Command, opts *GlobalOptions) { } func (c *BootstrapGcpCmd) BootstrapGcp() error { - c.CodesphereEnv.RegistryType = bootstrap.RegistryType(c.InputRegistryType) - - gcpClient := bootstrap.NewGCPClient(os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")) - bootstrapper, err := bootstrap.NewGCPBootstrapper(c.Env, c.CodesphereEnv, gcpClient) + ctx := c.cmd.Context() + stlog := bootstrap.NewStepLogger(false) + icg := installer.NewInstallConfigManager() + gcpClient := gcp.NewGCPClient(ctx, stlog, os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")) + fw := util.NewFilesystemWriter() + nm := node.NewNode(fw, c.CodesphereEnv.SSHPrivateKeyPath) + + bs, err := gcp.NewGCPBootstrapper(ctx, c.Env, stlog, c.CodesphereEnv, icg, gcpClient, nm, fw) if err != nil { return err } - env, err := bootstrapper.Bootstrap() - envBytes, err2 := json.MarshalIndent(env, "", " ") + c.CodesphereEnv.RegistryType = gcp.RegistryType(c.InputRegistryType) + + err = bs.Bootstrap() + envBytes, err2 := json.MarshalIndent(bs.Env, "", " ") envString := string(envBytes) if err2 != nil { envString = "" } if err != nil { - if env.Jumpbox.ExternalIP != "" { - log.Printf("To debug on the jumpbox host:\nssh-add $SSH_KEY_PATH; ssh -o StrictHostKeyChecking=no -o ForwardAgent=yes -o SendEnv=OMS_PORTAL_API_KEY root@%s", env.Jumpbox.ExternalIP) + if bs.Env.Jumpbox != nil && bs.Env.Jumpbox.GetExternalIP() != "" { + log.Printf("To debug on the jumpbox host:\nssh-add $SSH_KEY_PATH; ssh -o StrictHostKeyChecking=no -o ForwardAgent=yes -o SendEnv=OMS_PORTAL_API_KEY root@%s", bs.Env.Jumpbox.GetExternalIP()) } return fmt.Errorf("failed to bootstrap GCP: %w, env: %s", err, envString) } - log.Println("GCP infrastructure bootstrapped:") + log.Println("\nGCP infrastructure bootstrapped:") log.Println(envString) - - log.Printf("Start the Codesphere installation using OMS from the jumpbox host:\nssh-add $SSH_KEY_PATH; ssh -o StrictHostKeyChecking=no -o ForwardAgent=yes -o SendEnv=OMS_PORTAL_API_KEY root@%s", env.Jumpbox.ExternalIP) - - log.Printf("When the installation is done, run the k0s configuration script generated at the k0s-1 host %s /root/configure-k0s.sh.", env.ControlPlaneNodes[0].InternalIP) + log.Printf("Start the Codesphere installation using OMS from the jumpbox host:\nssh-add $SSH_KEY_PATH; ssh -o StrictHostKeyChecking=no -o ForwardAgent=yes -o SendEnv=OMS_PORTAL_API_KEY root@%s", bs.Env.Jumpbox.GetExternalIP()) + log.Printf("When the installation is done, run the k0s configuration script generated at the k0s-1 host %s /root/configure-k0s.sh.", bs.Env.ControlPlaneNodes[0].GetInternalIP()) return err } diff --git a/internal/bootstrap/bootstrap_stepper.go b/internal/bootstrap/bootstrap_stepper.go new file mode 100644 index 00000000..37800fd6 --- /dev/null +++ b/internal/bootstrap/bootstrap_stepper.go @@ -0,0 +1,84 @@ +package bootstrap + +import ( + "fmt" +) + +const ( + LINE_RESET = "\r\033[2K" + MOVE_UP = "\033[1A" + MOVE_UP_CLEAR_LINE = "\033[1A\033[K" + RESET_TEXT = "\033[0m" + RED_TEXT = "\033[31m" + GREEN_TEXT = "\033[32m" +) + +type StepLogger struct { + silent bool + subSteps int + currentStep string +} + +func NewStepLogger(silent bool) *StepLogger { + return &StepLogger{ + silent: silent, + } +} + +func (b *StepLogger) Step(name string, fn func() error) error { + if b.silent { + return fn() + } + + b.subSteps = 0 + b.currentStep = name + + fmt.Printf("%s%s%s...", LINE_RESET, RESET_TEXT, name) + err := fn() + if err != nil { + fmt.Printf("%s%s%s failed: %v%s\n", LINE_RESET, RED_TEXT, name, err, RESET_TEXT) + } else { + for i := 0; i < b.subSteps; i++ { + fmt.Printf("%s", MOVE_UP_CLEAR_LINE) + } + fmt.Printf("%s%s%s %s✓%s\n", LINE_RESET, RESET_TEXT, name, GREEN_TEXT, RESET_TEXT) + } + return err +} + +func (b *StepLogger) Substep(name string, fn func() error) error { + if b.silent { + return fn() + } + + b.subSteps += 1 + b.currentStep = name + + fmt.Printf("%s%s %s...", LINE_RESET, RESET_TEXT, name) + err := fn() + if err != nil { + fmt.Printf("%s%s %s failed: %v%s\n", LINE_RESET, RED_TEXT, name, err, RESET_TEXT) + } else { + fmt.Printf("%s%s %s %s✓%s\n", LINE_RESET, RESET_TEXT, name, GREEN_TEXT, RESET_TEXT) + } + return err +} + +// LogRetry prints a retry message for the current step. +func (b *StepLogger) LogRetry() { + if b.subSteps > 0 { + fmt.Printf("%s%s Retrying: %s...%s", LINE_RESET, RESET_TEXT, b.currentStep, RESET_TEXT) + } else { + fmt.Printf("%s%sRetrying: %s...%s", LINE_RESET, RESET_TEXT, b.currentStep, RESET_TEXT) + } +} + +// Logf prints a log message for the current step. +func (b *StepLogger) Logf(message string, args ...interface{}) { + if b.silent { + return + } + + b.subSteps += 1 + fmt.Printf("%s%s %s%s\n", LINE_RESET, RESET_TEXT, fmt.Sprintf(message, args...), RESET_TEXT) +} diff --git a/internal/bootstrap/gcp.go b/internal/bootstrap/gcp.go deleted file mode 100644 index 802a60e9..00000000 --- a/internal/bootstrap/gcp.go +++ /dev/null @@ -1,1429 +0,0 @@ -// Copyright (c) Codesphere Inc. -// SPDX-License-Identifier: Apache-2.0 - -package bootstrap - -import ( - "context" - "fmt" - "log" - "os" - "path/filepath" - "sort" - "strings" - "sync" - "time" - - compute "cloud.google.com/go/compute/apiv1" - "cloud.google.com/go/compute/apiv1/computepb" - "github.com/codesphere-cloud/oms/internal/env" - "github.com/codesphere-cloud/oms/internal/installer" - "github.com/codesphere-cloud/oms/internal/installer/files" - "github.com/codesphere-cloud/oms/internal/installer/node" - "github.com/codesphere-cloud/oms/internal/util" - "github.com/lithammer/shortuuid" - "google.golang.org/api/dns/v1" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -type RegistryType string - -const ( - RegistryTypeLocalContainer RegistryType = "local-container" - RegistryTypeArtifactRegistry RegistryType = "artifact-registry" -) - -type GCPBootstrapper struct { - ctx context.Context - env *CodesphereEnvironment - InstallConfig *files.RootConfig - Secrets *files.InstallVault - icg installer.InstallConfigManager - NodeManager *node.NodeManager - GCPClient GCPClient -} - -type CodesphereEnvironment struct { - ProjectID string `json:"project_id"` - ProjectName string `json:"project_name"` - DNSProjectID string `json:"dns_project_id"` - PostgreSQLNode node.Node `json:"postgresql_node"` - ControlPlaneNodes []node.Node `json:"control_plane_nodes"` - CephNodes []node.Node `json:"ceph_nodes"` - Jumpbox node.Node `json:"jumpbox"` - ContainerRegistryURL string `json:"container_registry_url"` - ExistingConfigUsed bool `json:"existing_config_used"` - InstallCodesphereVersion string `json:"install_codesphere_version"` - Preemptible bool `json:"preemptible"` - WriteConfig bool `json:"write_config"` - GatewayIP string `json:"gateway_ip"` - PublicGatewayIP string `json:"public_gateway_ip"` - RegistryType RegistryType `json:"registry_type"` - - ProjectDisplayName string - BillingAccount string - BaseDomain string - GithubAppClientID string - GithubAppClientSecret string - SecretsDir string - FolderID string - SSHPublicKeyPath string - SSHPrivateKeyPath string - DatacenterID int - CustomPgIP string - InstallConfig string - SecretsFile string - Region string - Zone string - DNSZoneName string -} - -func NewGCPBootstrapper(env env.Env, CodesphereEnv *CodesphereEnvironment, gcpClient GCPClient) (*GCPBootstrapper, error) { - ctx := context.Background() - fw := util.NewFilesystemWriter() - icg := installer.NewInstallConfigManager() - nm := &node.NodeManager{ - FileIO: fw, - KeyPath: expandPath(CodesphereEnv.SSHPrivateKeyPath), - } - - if fw.Exists(CodesphereEnv.InstallConfig) { - log.Printf("Reading install config file: %s", CodesphereEnv.InstallConfig) - err := icg.LoadInstallConfigFromFile(CodesphereEnv.InstallConfig) - if err != nil { - return nil, fmt.Errorf("failed to load config file: %w", err) - } - - CodesphereEnv.ExistingConfigUsed = true - } else { - err := icg.ApplyProfile("dev") - if err != nil { - return nil, fmt.Errorf("failed to apply profile: %w", err) - } - } - - if fw.Exists(CodesphereEnv.SecretsFile) { - log.Printf("Reading vault file: %s", CodesphereEnv.SecretsFile) - err := icg.LoadVaultFromFile(CodesphereEnv.SecretsFile) - if err != nil { - return nil, fmt.Errorf("failed to load vault file: %w", err) - } - - log.Println("Merging vault secrets into configuration...") - err = icg.MergeVaultIntoConfig() - if err != nil { - return nil, fmt.Errorf("failed to merge vault into config: %w", err) - } - } - - return &GCPBootstrapper{ - env: CodesphereEnv, - InstallConfig: icg.GetInstallConfig(), - NodeManager: nm, - Secrets: icg.GetVault(), - ctx: ctx, - icg: icg, - GCPClient: gcpClient, - }, nil -} - -func (b *GCPBootstrapper) Bootstrap() (*CodesphereEnvironment, error) { - err := b.EnsureProject() - if err != nil { - return b.env, fmt.Errorf("failed to ensure GCP project: %w", err) - } - - err = b.EnsureBilling() - if err != nil { - return b.env, fmt.Errorf("failed to ensure billing is enabled: %w", err) - } - - err = b.EnsureAPIsEnabled() - if err != nil { - return b.env, fmt.Errorf("failed to enable required APIs: %w", err) - } - - if b.env.RegistryType == RegistryTypeArtifactRegistry { - err = b.EnsureArtifactRegistry() - if err != nil { - return b.env, fmt.Errorf("failed to ensure artifact registry: %w", err) - } - } - - err = b.EnsureServiceAccounts() - if err != nil { - return b.env, fmt.Errorf("failed to ensure service accounts: %w", err) - } - - err = b.EnsureIAMRoles() - if err != nil { - return b.env, fmt.Errorf("failed to ensure IAM roles: %w", err) - } - - err = b.EnsureVPC() - if err != nil { - return b.env, fmt.Errorf("failed to ensure VPC: %w", err) - } - - err = b.EnsureFirewallRules() - if err != nil { - return b.env, fmt.Errorf("failed to ensure firewall rules: %w", err) - } - - err = b.EnsureComputeInstances() - if err != nil { - return b.env, fmt.Errorf("failed to ensure compute instances: %w", err) - } - - err = b.EnsureGatewayIPAddresses() - if err != nil { - return b.env, fmt.Errorf("failed to ensure external IP addresses: %w", err) - } - - err = b.EnsureRootLoginEnabled() - if err != nil { - return b.env, fmt.Errorf("failed to ensure root login is enabled: %w", err) - } - - err = b.EnsureJumpboxConfigured() - if err != nil { - return b.env, fmt.Errorf("failed to ensure jumpbox is configured: %w", err) - } - - err = b.EnsureHostsConfigured() - if err != nil { - return b.env, fmt.Errorf("failed to ensure hosts are configured: %w", err) - } - - if b.env.RegistryType == RegistryTypeLocalContainer { - err = b.EnsureLocalContainerRegistry() - if err != nil { - return b.env, fmt.Errorf("failed to ensure local container registry: %w", err) - } - } - - if b.env.WriteConfig { - err = b.UpdateInstallConfig() - if err != nil { - return b.env, fmt.Errorf("failed to update install config: %w", err) - } - - err = b.EnsureAgeKey() - if err != nil { - return b.env, fmt.Errorf("failed to ensure age key: %w", err) - } - - err = b.EncryptVault() - if err != nil { - return b.env, fmt.Errorf("failed to encrypt vault: %w", err) - } - } - - err = b.EnsureDNSRecords() - if err != nil { - return b.env, fmt.Errorf("failed to ensure DNS records: %w", err) - } - - if b.env.InstallCodesphereVersion != "" { - err = b.InstallCodesphere() - if err != nil { - return b.env, fmt.Errorf("failed to install Codesphere: %w", err) - } - } - - err = b.GenerateK0sConfigScript() - if err != nil { - return b.env, fmt.Errorf("failed to generate k0s config script: %w", err) - } - - return b.env, nil -} - -func (b *GCPBootstrapper) EnsureProject() error { - parent := "" - if b.env.FolderID != "" { - parent = fmt.Sprintf("folders/%s", b.env.FolderID) - } - - // Generate a unique project ID - projectGuid := strings.ToLower(shortuuid.New()[:8]) - projectId := b.env.ProjectName + "-" + projectGuid - - existingProject, err := b.GCPClient.GetProjectByName(b.ctx, b.env.FolderID, b.env.ProjectName) - if err == nil { - b.env.ProjectID = existingProject.ProjectId - b.env.ProjectName = existingProject.Name - return nil - } - if err.Error() == fmt.Sprintf("project not found: %s", b.env.ProjectName) { - _, err := b.GCPClient.CreateProject(b.ctx, parent, projectId, b.env.ProjectName) - if err != nil { - return fmt.Errorf("failed to create project: %w", err) - } - b.env.ProjectID = projectId - return nil - } - return fmt.Errorf("failed to get project: %w", err) -} - -func (b *GCPBootstrapper) EnsureBilling() error { - bi, err := b.GCPClient.GetBillingInfo(b.env.ProjectID) - if err != nil { - return fmt.Errorf("failed to get billing info: %w", err) - } - if bi.BillingEnabled && bi.BillingAccountName == b.env.BillingAccount { - return nil - } - - err = b.GCPClient.EnableBilling(b.ctx, b.env.ProjectID, b.env.BillingAccount) - if err != nil { - return fmt.Errorf("failed to enable billing: %w", err) - } - log.Printf("Billing enabled for project %s with account %s", b.env.ProjectID, b.env.BillingAccount) - - return nil -} - -func (b *GCPBootstrapper) EnsureAPIsEnabled() error { - apis := []string{ - "compute.googleapis.com", - "serviceusage.googleapis.com", - "artifactregistry.googleapis.com", - "dns.googleapis.com", - } - - err := b.GCPClient.EnableAPIs(b.ctx, b.env.ProjectID, apis) - if err != nil { - return fmt.Errorf("failed to enable APIs: %w", err) - } - - log.Printf("Required APIs enabled for project %s", b.env.ProjectID) - - return nil -} - -func (b *GCPBootstrapper) EnsureArtifactRegistry() error { - repoName := "codesphere-registry" - - repo, err := b.GCPClient.GetArtifactRegistry(b.ctx, b.env.ProjectID, b.env.Region, repoName) - if err != nil && status.Code(err) != codes.NotFound { - return fmt.Errorf("failed to get artifact registry: %w", err) - } - - // Create the repository if it doesn't exist - if repo == nil { - repo, err = b.GCPClient.CreateArtifactRegistry(b.ctx, b.env.ProjectID, b.env.Region, repoName) - if err != nil || repo == nil { - return fmt.Errorf("failed to create artifact registry: %w, repo: %v", err, repo) - } - } - - b.InstallConfig.Registry.Server = repo.GetRegistryUri() - - log.Printf("Artifact Registry repository %s ensured", b.InstallConfig.Registry.Server) - - return nil -} - -// Installs a docker registry on the postgres node to speed up image loading time -func (b *GCPBootstrapper) EnsureLocalContainerRegistry() error { - localRegistryServer := b.env.PostgreSQLNode.InternalIP + ":5000" - - // Figure out if registry is already running - checkCommand := `test "$(podman ps --filter 'name=registry' --format '{{.Names}}' | wc -l)" -eq "1"` - err := b.env.PostgreSQLNode.RunSSHCommand(&b.env.Jumpbox, b.NodeManager, "root", checkCommand) - if err == nil && b.InstallConfig.Registry != nil && b.InstallConfig.Registry.Server == localRegistryServer && - b.InstallConfig.Registry.Username != "" && b.InstallConfig.Registry.Password != "" { - log.Println("Local container registry already running on postgres node") - return nil - } - - log.Println("Installing registry") - - b.InstallConfig.Registry.Server = localRegistryServer - b.InstallConfig.Registry.Username = "custom-registry" - b.InstallConfig.Registry.Password = shortuuid.New() - - commands := []string{ - "apt-get update", - "apt-get install -y podman apache2-utils", - "htpasswd -bBc /root/registry.password " + b.InstallConfig.Registry.Username + " " + b.InstallConfig.Registry.Password, - "openssl req -newkey rsa:4096 -nodes -sha256 -keyout /root/registry.key -x509 -days 365 -out /root/registry.crt -subj \"/C=DE/ST=BW/L=Karlsruhe/O=Codesphere/CN=" + b.env.PostgreSQLNode.InternalIP + "\" -addext \"subjectAltName = DNS:postgres,IP:" + b.env.PostgreSQLNode.InternalIP + "\"", - "podman rm -f registry || true", - `podman run -d \ - --restart=always --name registry --net=host\ - --env REGISTRY_HTTP_ADDR=0.0.0.0:5000 \ - --env REGISTRY_AUTH=htpasswd \ - --env REGISTRY_AUTH_HTPASSWD_REALM='Registry Realm' \ - --env REGISTRY_AUTH_HTPASSWD_PATH=/auth/registry.password \ - -v /root/registry.password:/auth/registry.password \ - --env REGISTRY_HTTP_TLS_CERTIFICATE=/certs/registry.crt \ - --env REGISTRY_HTTP_TLS_KEY=/certs/registry.key \ - -v /root/registry.crt:/certs/registry.crt \ - -v /root/registry.key:/certs/registry.key \ - registry:2`, - `mkdir -p /etc/docker/certs.d/` + b.InstallConfig.Registry.Server, - `cp /root/registry.crt /etc/docker/certs.d/` + b.InstallConfig.Registry.Server + `/ca.crt`, - } - for _, cmd := range commands { - err := b.env.PostgreSQLNode.RunSSHCommand(&b.env.Jumpbox, b.NodeManager, "root", cmd) - if err != nil { - return fmt.Errorf("failed to run command on postgres node: %w", err) - } - } - - allNodes := append(b.env.ControlPlaneNodes, b.env.CephNodes...) - for _, node := range allNodes { - err := b.env.PostgreSQLNode.RunSSHCommand(&b.env.Jumpbox, b.NodeManager, "root", "scp -o StrictHostKeyChecking=no /root/registry.crt root@"+node.InternalIP+":/usr/local/share/ca-certificates/registry.crt") - if err != nil { - return fmt.Errorf("failed to copy registry certificate to node %s: %w", node.InternalIP, err) - } - err = node.RunSSHCommand(&b.env.Jumpbox, b.NodeManager, "root", "update-ca-certificates") - if err != nil { - return fmt.Errorf("failed to update CA certificates on node %s: %w", node.InternalIP, err) - } - err = node.RunSSHCommand(&b.env.Jumpbox, b.NodeManager, "root", "systemctl restart docker.service || true") // docker is probably not yet installed - if err != nil { - return fmt.Errorf("failed to restart docker service on node %s: %w", node.InternalIP, err) - } - } - - return nil -} - -func (b *GCPBootstrapper) EnsureServiceAccounts() error { - _, _, err := b.EnsureServiceAccount("cloud-controller") - if err != nil { - return err - } - - if b.env.RegistryType == RegistryTypeArtifactRegistry { - sa, newSa, err := b.EnsureServiceAccount("artifact-registry-writer") - if err != nil { - return err - } - - if !newSa && b.InstallConfig.Registry.Password != "" { - return nil - } - - for retries := range 5 { - privateKey, err := b.GCPClient.CreateServiceAccountKey(b.ctx, b.env.ProjectID, sa) - - if err != nil && status.Code(err) != codes.AlreadyExists { - if retries > 3 { - return fmt.Errorf("failed to create service account key: %w", err) - } - log.Printf("got response %d trying to create service account key for %s, retrying...", status.Code(err), sa) - time.Sleep(5 * time.Second) - continue - } - log.Printf("Service account key for %s ensured", sa) - b.InstallConfig.Registry.Password = string(privateKey) - b.InstallConfig.Registry.Username = "_json_key_base64" - break - } - } - - return nil -} - -func (b *GCPBootstrapper) EnsureServiceAccount(name string) (string, bool, error) { - return b.GCPClient.CreateServiceAccount(b.ctx, b.env.ProjectID, name, name) -} - -func (b *GCPBootstrapper) EnsureIAMRoles() error { - err := b.GCPClient.AssignIAMRole(b.ctx, b.env.ProjectID, "cloud-controller", "roles/compute.admin") - if err != nil { - return err - } - - if b.env.RegistryType != RegistryTypeArtifactRegistry { - return nil - } - - err = b.GCPClient.AssignIAMRole(b.ctx, b.env.ProjectID, "artifact-registry-writer", "roles/artifactregistry.writer") - return err -} - -func (b *GCPBootstrapper) EnsureVPC() error { - networkName := fmt.Sprintf("%s-vpc", b.env.ProjectID) - subnetName := fmt.Sprintf("%s-%s-subnet", b.env.ProjectID, b.env.Region) - routerName := fmt.Sprintf("%s-router", b.env.ProjectID) - natName := fmt.Sprintf("%s-nat-gateway", b.env.ProjectID) - - // Create VPC - err := b.GCPClient.CreateVPC(b.ctx, b.env.ProjectID, b.env.Region, networkName, subnetName, routerName, natName) - if err != nil { - return fmt.Errorf("failed to ensure VPC: %w", err) - } - - log.Printf("VPC %s ensured", networkName) - - return nil -} - -func (b *GCPBootstrapper) EnsureFirewallRules() error { - networkName := fmt.Sprintf("%s-vpc", b.env.ProjectID) - - // Allow external SSH to Jumpbox - sshRule := &computepb.Firewall{ - Name: protoString("allow-ssh-ext"), - Network: protoString(fmt.Sprintf("projects/%s/global/networks/%s", b.env.ProjectID, networkName)), - Direction: protoString("INGRESS"), - Priority: protoInt32(1000), - Allowed: []*computepb.Allowed{ - { - IPProtocol: protoString("tcp"), - Ports: []string{"22"}, - }, - }, - SourceRanges: []string{"0.0.0.0/0"}, - TargetTags: []string{"ssh"}, - Description: protoString("Allow external SSH to Jumpbox"), - } - err := b.GCPClient.CreateFirewallRule(b.ctx, b.env.ProjectID, sshRule) - if err != nil { - return fmt.Errorf("failed to create jumpbox ssh firewall rule: %w", err) - } - - // Allow all internal traffic - internalRule := &computepb.Firewall{ - Name: protoString("allow-internal"), - Network: protoString(fmt.Sprintf("projects/%s/global/networks/%s", b.env.ProjectID, networkName)), - Direction: protoString("INGRESS"), - Priority: protoInt32(1000), - Allowed: []*computepb.Allowed{ - {IPProtocol: protoString("all")}, - }, - SourceRanges: []string{"10.10.0.0/20"}, - Description: protoString("Allow all internal traffic"), - } - err = b.GCPClient.CreateFirewallRule(b.ctx, b.env.ProjectID, internalRule) - if err != nil { - return fmt.Errorf("failed to create internal firewall rule: %w", err) - } - - // Allow all egress - egressRule := &computepb.Firewall{ - Name: protoString("allow-all-egress"), - Network: protoString(fmt.Sprintf("projects/%s/global/networks/%s", b.env.ProjectID, networkName)), - Direction: protoString("EGRESS"), - Priority: protoInt32(1000), - Allowed: []*computepb.Allowed{ - {IPProtocol: protoString("all")}, - }, - DestinationRanges: []string{"0.0.0.0/0"}, - Description: protoString("Allow all egress"), - } - err = b.GCPClient.CreateFirewallRule(b.ctx, b.env.ProjectID, egressRule) - if err != nil { - return fmt.Errorf("failed to create egress firewall rule: %w", err) - } - - // Allow ingress for web (HTTP/HTTPS) - webRule := &computepb.Firewall{ - Name: protoString("allow-ingress-web"), - Network: protoString(fmt.Sprintf("projects/%s/global/networks/%s", b.env.ProjectID, networkName)), - Direction: protoString("INGRESS"), - Priority: protoInt32(1000), - Allowed: []*computepb.Allowed{ - {IPProtocol: protoString("tcp"), Ports: []string{"80", "443"}}, - }, - SourceRanges: []string{"0.0.0.0/0"}, - Description: protoString("Allow HTTP/HTTPS ingress"), - } - err = b.GCPClient.CreateFirewallRule(b.ctx, b.env.ProjectID, webRule) - if err != nil { - return fmt.Errorf("failed to create web firewall rule: %w", err) - } - - // Allow ingress for PostgreSQL - postgresRule := &computepb.Firewall{ - Name: protoString("allow-ingress-postgres"), - Network: protoString(fmt.Sprintf("projects/%s/global/networks/%s", b.env.ProjectID, networkName)), - Direction: protoString("INGRESS"), - Priority: protoInt32(1000), - Allowed: []*computepb.Allowed{ - {IPProtocol: protoString("tcp"), Ports: []string{"5432"}}, - }, - SourceRanges: []string{"0.0.0.0/0"}, - TargetTags: []string{"postgres"}, - Description: protoString("Allow external access to PostgreSQL"), - } - err = b.GCPClient.CreateFirewallRule(b.ctx, b.env.ProjectID, postgresRule) - if err != nil { - return fmt.Errorf("failed to create postgres firewall rule: %w", err) - } - - log.Println("Firewall rules ensured") - return nil -} - -type VMDef struct { - Name string - MachineType string - Tags []string - AdditionalDisks []int64 - ExternalIP bool -} - -func (b *GCPBootstrapper) EnsureComputeInstances() error { - projectID := b.env.ProjectID - region := b.env.Region - zone := b.env.Zone - ctx := b.ctx - - instancesClient, err := compute.NewInstancesRESTClient(ctx) - if err != nil { - return fmt.Errorf("failed to create instances client: %w", err) - } - defer util.IgnoreError(instancesClient.Close) - - // Example VM definitions (expand as needed) - - vmDefs := []VMDef{ - {"jumpbox", "e2-medium", []string{"jumpbox", "ssh"}, []int64{}, true}, - {"postgres", "e2-standard-8", []string{"postgres"}, []int64{}, true}, - {"ceph-1", "e2-standard-8", []string{"ceph"}, []int64{20, 200}, false}, - {"ceph-2", "e2-standard-8", []string{"ceph"}, []int64{20, 200}, false}, - {"ceph-3", "e2-standard-8", []string{"ceph"}, []int64{20, 200}, false}, - {"ceph-4", "e2-standard-8", []string{"ceph"}, []int64{20, 200}, false}, - {"k0s-1", "e2-standard-16", []string{"k0s"}, []int64{}, false}, - {"k0s-2", "e2-standard-16", []string{"k0s"}, []int64{}, false}, - {"k0s-3", "e2-standard-16", []string{"k0s"}, []int64{}, false}, - } - - network := fmt.Sprintf("projects/%s/global/networks/%s-vpc", projectID, projectID) - subnetwork := fmt.Sprintf("projects/%s/regions/%s/subnetworks/%s-%s-subnet", projectID, region, projectID, region) - diskType := fmt.Sprintf("projects/%s/zones/%s/diskTypes/pd-ssd", projectID, zone) - - // Create VMs in parallel - wg := sync.WaitGroup{} - errCh := make(chan error, len(vmDefs)) - mu := sync.Mutex{} - for _, vm := range vmDefs { - wg.Add(1) - go func(vm VMDef) { - defer wg.Done() - disks := []*computepb.AttachedDisk{ - { - Boot: protoBool(true), - AutoDelete: protoBool(true), - Type: protoString("PERSISTENT"), - InitializeParams: &computepb.AttachedDiskInitializeParams{ - DiskType: &diskType, - DiskSizeGb: protoInt64(200), - SourceImage: protoString("projects/ubuntu-os-cloud/global/images/family/ubuntu-2204-lts"), - }, - }, - } - for _, diskSize := range vm.AdditionalDisks { - disks = append(disks, &computepb.AttachedDisk{ - Boot: protoBool(false), - AutoDelete: protoBool(true), - Type: protoString("PERSISTENT"), - InitializeParams: &computepb.AttachedDiskInitializeParams{ - DiskSizeGb: protoInt64(diskSize), - DiskType: &diskType, - }, - }) - } - - serviceAccount := fmt.Sprintf("cloud-controller@%s.iam.gserviceaccount.com", projectID) - - pubKey, err := readSSHKey(b.env.SSHPublicKeyPath) - if err != nil { - errCh <- fmt.Errorf("failed to read SSH public key: %w", err) - return - } - - instance := &computepb.Instance{ - Name: protoString(vm.Name), - ServiceAccounts: []*computepb.ServiceAccount{ - { - Email: protoString(serviceAccount), - Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"}, - }, - }, - MachineType: protoString(fmt.Sprintf("zones/%s/machineTypes/%s", zone, vm.MachineType)), - Tags: &computepb.Tags{ - Items: vm.Tags, - }, - Scheduling: &computepb.Scheduling{ - Preemptible: &b.env.Preemptible, - }, - NetworkInterfaces: []*computepb.NetworkInterface{ - { - Network: protoString(network), - Subnetwork: protoString(subnetwork), - }, - }, - Disks: disks, - Metadata: &computepb.Metadata{ - Items: []*computepb.Items{ - { - Key: protoString("ssh-keys"), - Value: protoString(fmt.Sprintf("root:%s\nubuntu:%s", pubKey+"root", pubKey+"ubuntu")), - }, - }, - }, - } - - // Configure external IP if needed - if vm.ExternalIP { - instance.NetworkInterfaces[0].AccessConfigs = []*computepb.AccessConfig{ - { - Name: protoString("External NAT"), - Type: protoString("ONE_TO_ONE_NAT"), - }, - } - } - - op, err := instancesClient.Insert(ctx, &computepb.InsertInstanceRequest{ - Project: projectID, - Zone: zone, - InstanceResource: instance, - }) - if err != nil && !isAlreadyExistsError(err) { - errCh <- fmt.Errorf("failed to create instance %s: %w", vm.Name, err) - } - if err == nil { - if err := op.Wait(ctx); err != nil { - errCh <- fmt.Errorf("failed to wait for instance %s creation: %w", vm.Name, err) - } - } - log.Printf("Instance %s ensured", vm.Name) - - //find out the IP addresses of the created instance - resp, err := instancesClient.Get(ctx, &computepb.GetInstanceRequest{ - Project: projectID, - Zone: zone, - Instance: vm.Name, - }) - if err != nil { - errCh <- fmt.Errorf("failed to get instance %s: %w", vm.Name, err) - } - - externalIP := "" - internalIP := "" - if len(resp.GetNetworkInterfaces()) > 0 { - internalIP = resp.GetNetworkInterfaces()[0].GetNetworkIP() - if len(resp.GetNetworkInterfaces()[0].GetAccessConfigs()) > 0 { - externalIP = resp.GetNetworkInterfaces()[0].GetAccessConfigs()[0].GetNatIP() - } - } - - node := node.Node{ - ExternalIP: externalIP, - InternalIP: internalIP, - Name: vm.Name, - } - - mu.Lock() - switch vm.Tags[0] { - case "jumpbox": - b.env.Jumpbox = node - case "postgres": - b.env.PostgreSQLNode = node - case "ceph": - b.env.CephNodes = append(b.env.CephNodes, node) - case "k0s": - b.env.ControlPlaneNodes = append(b.env.ControlPlaneNodes, node) - } - mu.Unlock() - }(vm) - } - wg.Wait() - - close(errCh) - errStr := "" - for err := range errCh { - errStr += err.Error() + "; " - } - if errStr != "" { - return fmt.Errorf("error ensuring compute instances: %s", errStr) - } - - //sort ceph nodes by name to ensure consistent ordering - sort.Slice(b.env.CephNodes, func(i, j int) bool { - return b.env.CephNodes[i].Name < b.env.CephNodes[j].Name - }) - - //sort control plane nodes by name to ensure consistent ordering - sort.Slice(b.env.ControlPlaneNodes, func(i, j int) bool { - return b.env.ControlPlaneNodes[i].Name < b.env.ControlPlaneNodes[j].Name - }) - return nil -} - -// EnsureGatewayIPAddresses reserves 2 static external IP addresses for the ingress -// controllers of the cluster. -func (b *GCPBootstrapper) EnsureGatewayIPAddresses() error { - var err error - b.env.GatewayIP, err = b.EnsureExternalIP("gateway") - if err != nil { - return fmt.Errorf("failed to ensure gateway IP: %w", err) - } - b.env.PublicGatewayIP, err = b.EnsureExternalIP("public-gateway") - if err != nil { - return fmt.Errorf("failed to ensure public gateway IP: %w", err) - } - return nil -} - -func (b *GCPBootstrapper) EnsureExternalIP(name string) (string, error) { - addressesClient, err := compute.NewAddressesRESTClient(b.ctx) - if err != nil { - return "", fmt.Errorf("failed to create addresses client: %w", err) - } - defer util.IgnoreError(addressesClient.Close) - - desiredAddress := &computepb.Address{ - Name: &name, - AddressType: protoString("EXTERNAL"), - Region: &b.env.Region, - } - - // Figure out if address already exists and get IP - req := &computepb.GetAddressRequest{ - Project: b.env.ProjectID, - Region: b.env.Region, - Address: *desiredAddress.Name, - } - - address, err := addressesClient.Get(b.ctx, req) - - if err == nil && address != nil { - log.Printf("Address %s already exists", name) - - return address.GetAddress(), nil - } - - op, err := addressesClient.Insert(b.ctx, &computepb.InsertAddressRequest{ - Project: b.env.ProjectID, - Region: b.env.Region, - AddressResource: desiredAddress, - }) - if err != nil { - return "", fmt.Errorf("failed to create address %s: %w", name, err) - } - if err := op.Wait(b.ctx); err != nil { - return "", fmt.Errorf("failed to wait for address %s creation: %w", name, err) - } - log.Printf("Address %s ensured", name) - - address, err = addressesClient.Get(b.ctx, req) - - if err == nil && address != nil { - return address.GetAddress(), nil - } - return "", fmt.Errorf("failed to get address %s after creation", name) -} - -func (b *GCPBootstrapper) EnsureRootLoginEnabled() error { - // wait for SSH service to be available on jumpbox - err := b.env.Jumpbox.WaitForSSH(nil, b.NodeManager, 30*time.Second) - if err != nil { - return fmt.Errorf("timed out waiting for SSH service to start on jumpbox: %w", err) - } - log.Printf("SSH service available on jumpbox '%s'", b.env.Jumpbox.Name) - - hasRootLogin := b.env.Jumpbox.HasRootLoginEnabled(nil, b.NodeManager) - if !hasRootLogin { - err := b.env.Jumpbox.EnableRootLogin(nil, b.NodeManager) - if err != nil { - return fmt.Errorf("failed to enable root login on %s: %w", b.env.Jumpbox.Name, err) - } - log.Printf("Root login enabled on %s", b.env.Jumpbox.Name) - } - - allNodes := append(b.env.ControlPlaneNodes, b.env.PostgreSQLNode) - allNodes = append(allNodes, b.env.CephNodes...) - - for _, node := range allNodes { - err = node.WaitForSSH(&b.env.Jumpbox, b.NodeManager, 30*time.Second) - if err != nil { - return fmt.Errorf("timed out waiting for SSH service to start on %s: %w", node.Name, err) - } - hasRootLogin := node.HasRootLoginEnabled(&b.env.Jumpbox, b.NodeManager) - if hasRootLogin { - log.Printf("Root login already enabled on %s", node.Name) - - continue - } - for i := range 3 { - err := node.EnableRootLogin(&b.env.Jumpbox, b.NodeManager) - if err == nil { - break - } - if i == 2 { - return fmt.Errorf("failed to enable root login on %s: %w", node.Name, err) - } - log.Printf("cannot enable root login on %s yet, retrying in 10 seconds: %v", node.Name, err) - time.Sleep(10 * time.Second) - } - - log.Printf("Root login enabled on %s", node.Name) - } - return nil -} - -func (b *GCPBootstrapper) EnsureJumpboxConfigured() error { - if !b.env.Jumpbox.HasAcceptEnvConfigured(nil, b.NodeManager) { - err := b.env.Jumpbox.ConfigureAcceptEnv(nil, b.NodeManager) - if err != nil { - return fmt.Errorf("failed to configure AcceptEnv on jumpbox: %w", err) - } - } - hasOms := b.env.Jumpbox.HasCommand(b.NodeManager, "oms-cli") - if hasOms { - log.Println("OMS already installed on jumpbox") - return nil - } - err := b.env.Jumpbox.InstallOms(b.NodeManager) - if err != nil { - return fmt.Errorf("failed to install OMS on jumpbox: %w", err) - } - - log.Println("OMS installed on jumpbox") - return nil -} - -func (b *GCPBootstrapper) EnsureHostsConfigured() error { - allNodes := append(b.env.ControlPlaneNodes, b.env.PostgreSQLNode) - allNodes = append(allNodes, b.env.CephNodes...) - - for _, node := range allNodes { - if !node.HasInotifyWatchesConfigured(&b.env.Jumpbox, b.NodeManager) { - err := node.ConfigureInotifyWatches(&b.env.Jumpbox, b.NodeManager) - if err != nil { - return fmt.Errorf("failed to configure inotify watches on %s: %w", node.Name, err) - } - } - - if !node.HasMemoryMapConfigured(&b.env.Jumpbox, b.NodeManager) { - err := node.ConfigureMemoryMap(&b.env.Jumpbox, b.NodeManager) - if err != nil { - return fmt.Errorf("failed to configure memory map on %s: %w", node.Name, err) - } - } - log.Printf("Host %s configured", node.Name) - } - return nil -} - -func (b *GCPBootstrapper) UpdateInstallConfig() error { - - // Update install config with necessary values - b.InstallConfig.Datacenter.ID = b.env.DatacenterID - b.InstallConfig.Datacenter.City = "Karlsruhe" - b.InstallConfig.Datacenter.CountryCode = "DE" - b.InstallConfig.Secrets.BaseDir = b.env.SecretsDir - b.InstallConfig.Registry.ReplaceImagesInBom = true - b.InstallConfig.Registry.LoadContainerImages = true - - if b.InstallConfig.Postgres.Primary == nil { - b.InstallConfig.Postgres.Primary = &files.PostgresPrimaryConfig{ - Hostname: b.env.PostgreSQLNode.Name, - } - } - b.InstallConfig.Postgres.Primary.IP = b.env.PostgreSQLNode.InternalIP - - b.InstallConfig.Ceph.CsiKubeletDir = "/var/lib/k0s/kubelet" - b.InstallConfig.Ceph.NodesSubnet = "10.10.0.0/20" - b.InstallConfig.Ceph.Hosts = []files.CephHost{ - { - Hostname: b.env.CephNodes[0].Name, - IsMaster: true, - IPAddress: b.env.CephNodes[0].InternalIP, - }, - { - Hostname: b.env.CephNodes[1].Name, - IPAddress: b.env.CephNodes[1].InternalIP, - }, - { - Hostname: b.env.CephNodes[2].Name, - IPAddress: b.env.CephNodes[2].InternalIP, - }, - { - Hostname: b.env.CephNodes[3].Name, - IPAddress: b.env.CephNodes[3].InternalIP, - }, - } - b.InstallConfig.Ceph.OSDs = []files.CephOSD{ - { - SpecID: "default", - Placement: files.CephPlacement{ - HostPattern: "*", - }, - DataDevices: files.CephDataDevices{ - Size: "100G:", - Limit: 1, - }, - DBDevices: files.CephDBDevices{ - Size: "10G:500G", - Limit: 1, - }, - }, - } - - b.InstallConfig.Kubernetes = files.KubernetesConfig{ - ManagedByCodesphere: true, - APIServerHost: b.env.ControlPlaneNodes[0].InternalIP, - ControlPlanes: []files.K8sNode{ - { - IPAddress: b.env.ControlPlaneNodes[0].InternalIP, - }, - }, - Workers: []files.K8sNode{ - { - IPAddress: b.env.ControlPlaneNodes[0].InternalIP, - }, - - { - IPAddress: b.env.ControlPlaneNodes[1].InternalIP, - }, - { - IPAddress: b.env.ControlPlaneNodes[2].InternalIP, - }, - }, - } - b.InstallConfig.Cluster.Monitoring = &files.MonitoringConfig{ - Prometheus: &files.PrometheusConfig{ - RemoteWrite: &files.RemoteWriteConfig{ - Enabled: false, - ClusterName: "GCP-test", - }, - }, - } - b.InstallConfig.Cluster.Gateway = files.GatewayConfig{ - ServiceType: "LoadBalancer", - //IPAddresses: []string{b.env.ControlPlaneNodes[0].ExternalIP}, - Annotations: map[string]string{ - "cloud.google.com/load-balancer-ipv4": b.env.GatewayIP, - }, - } - b.InstallConfig.Cluster.PublicGateway = files.GatewayConfig{ - ServiceType: "LoadBalancer", - Annotations: map[string]string{ - "cloud.google.com/load-balancer-ipv4": b.env.PublicGatewayIP, - }, - //IPAddresses: []string{b.env.ControlPlaneNodes[1].ExternalIP}, - } - - b.InstallConfig.Codesphere.Domain = "cs." + b.env.BaseDomain - b.InstallConfig.Codesphere.WorkspaceHostingBaseDomain = "ws." + b.env.BaseDomain - b.InstallConfig.Codesphere.PublicIP = b.env.ControlPlaneNodes[1].ExternalIP - b.InstallConfig.Codesphere.CustomDomains = files.CustomDomainsConfig{ - CNameBaseDomain: "ws." + b.env.BaseDomain, - } - b.InstallConfig.Codesphere.DNSServers = []string{"8.8.8.8"} - b.InstallConfig.Codesphere.Experiments = []string{} - b.InstallConfig.Codesphere.DeployConfig = files.DeployConfig{ - Images: map[string]files.ImageConfig{ - "ubuntu-24.04": { - Name: "Ubuntu 24.04", - SupportedUntil: "2028-05-31", - Flavors: map[string]files.FlavorConfig{ - "default": { - Image: files.ImageRef{ - BomRef: "workspace-agent-24.04", - }, - Pool: map[int]int{ - 1: 1, - 2: 1, - 3: 0, - 4: 0, - }, - }, - }, - }, - }, - } - b.InstallConfig.Codesphere.Plans = files.PlansConfig{ - HostingPlans: map[int]files.HostingPlan{ - 1: { - CPUTenth: 10, - GPUParts: 0, - MemoryMb: 2048, - StorageMb: 20480, - TempStorageMb: 1024, - }, - 2: { - CPUTenth: 20, - GPUParts: 0, - MemoryMb: 4096, - StorageMb: 20480, - TempStorageMb: 1024, - }, - 3: { - CPUTenth: 40, - GPUParts: 0, - MemoryMb: 8192, - StorageMb: 40960, - TempStorageMb: 1024, - }, - 4: { - CPUTenth: 80, - GPUParts: 0, - MemoryMb: 16384, - StorageMb: 40960, - TempStorageMb: 1024, - }, - }, - WorkspacePlans: map[int]files.WorkspacePlan{ - 1: { - Name: "Micro", - HostingPlanID: 1, - MaxReplicas: 3, - OnDemand: true, - }, - 2: { - Name: "Standard", - HostingPlanID: 2, - MaxReplicas: 3, - OnDemand: true, - }, - 3: { - Name: "Big", - HostingPlanID: 3, - MaxReplicas: 3, - OnDemand: true, - }, - 4: { - Name: "Pro", - HostingPlanID: 4, - MaxReplicas: 3, - OnDemand: true, - }, - }, - } - b.InstallConfig.Codesphere.GitProviders = &files.GitProvidersConfig{ - GitHub: &files.GitProviderConfig{ - Enabled: true, - URL: "https://github.com", - API: files.APIConfig{ - BaseURL: "https://api.github.com", - }, - OAuth: files.OAuthConfig{ - Issuer: "https://github.com", - AuthorizationEndpoint: "https://github.com/login/oauth/authorize", - TokenEndpoint: "https://github.com/login/oauth/access_token", - - ClientID: b.env.GithubAppClientID, - ClientSecret: b.env.GithubAppClientSecret, - }, - }, - } - b.InstallConfig.Codesphere.ManagedServices = []files.ManagedServiceConfig{} - - if !b.env.ExistingConfigUsed { - err := b.icg.GenerateSecrets() - if err != nil { - return fmt.Errorf("failed to generate secrets: %w", err) - } - } else { - var err error - b.InstallConfig.Postgres.Primary.PrivateKey, b.InstallConfig.Postgres.Primary.SSLConfig.ServerCertPem, err = installer.GenerateServerCertificate( - b.InstallConfig.Postgres.CaCertPrivateKey, - b.InstallConfig.Postgres.CACertPem, - b.InstallConfig.Postgres.Primary.Hostname, - []string{b.InstallConfig.Postgres.Primary.IP}) - if err != nil { - return fmt.Errorf("failed to generate primary server certificate: %w", err) - } - if b.InstallConfig.Postgres.Replica != nil { - b.InstallConfig.Postgres.ReplicaPrivateKey, b.InstallConfig.Postgres.Replica.SSLConfig.ServerCertPem, err = installer.GenerateServerCertificate( - b.InstallConfig.Postgres.CaCertPrivateKey, - b.InstallConfig.Postgres.CACertPem, - b.InstallConfig.Postgres.Replica.Name, - []string{b.InstallConfig.Postgres.Replica.IP}) - if err != nil { - return fmt.Errorf("failed to generate replica server certificate: %w", err) - } - } - } - - if err := b.icg.WriteInstallConfig(b.env.InstallConfig, true); err != nil { - return fmt.Errorf("failed to write config file: %w", err) - } - - if err := b.icg.WriteVault(b.env.SecretsFile, true); err != nil { - return fmt.Errorf("failed to write vault file: %w", err) - } - - err := b.env.Jumpbox.CopyFile(nil, b.NodeManager, b.env.InstallConfig, "/etc/codesphere/config.yaml") - if err != nil { - return fmt.Errorf("failed to copy install config to jumpbox: %w", err) - } - - err = b.env.Jumpbox.CopyFile(nil, b.NodeManager, b.env.SecretsFile, b.env.SecretsDir+"/prod.vault.yaml") - if err != nil { - return fmt.Errorf("failed to copy secrets file to jumpbox: %w", err) - } - return nil -} - -func (b *GCPBootstrapper) EnsureAgeKey() error { - hasKey := b.env.Jumpbox.HasFile(nil, b.NodeManager, b.env.SecretsDir+"/age_key.txt") - if hasKey { - log.Println("Age key already present on jumpbox") - return nil - } - - err := b.env.Jumpbox.RunSSHCommand(nil, b.NodeManager, "root", fmt.Sprintf("mkdir -p %s; age-keygen -o %s/age_key.txt", b.env.SecretsDir, b.env.SecretsDir)) - if err != nil { - return fmt.Errorf("failed to generate age key on jumpbox: %w", err) - } - - log.Println("Age key generated on jumpbox") - return nil -} - -func (b *GCPBootstrapper) EncryptVault() error { - err := b.env.Jumpbox.RunSSHCommand(nil, b.NodeManager, "root", "cp "+b.env.SecretsDir+"/prod.vault.yaml{,.bak}") - if err != nil { - return fmt.Errorf("failed backup vault on jumpbox: %w", err) - } - - err = b.env.Jumpbox.RunSSHCommand(nil, b.NodeManager, "root", "sops --encrypt --in-place --age $(age-keygen -y "+b.env.SecretsDir+"/age_key.txt) "+b.env.SecretsDir+"/prod.vault.yaml") - if err != nil { - return fmt.Errorf("failed to encrypt vault on jumpbox: %w", err) - } - - log.Println("Vault encrypted on jumpbox") - return nil -} - -func (b *GCPBootstrapper) EnsureDNSRecords() error { - ctx := context.Background() - gcpProject := b.env.DNSProjectID - if b.env.DNSProjectID == "" { - gcpProject = b.env.ProjectID - } - - dnsService, err := dns.NewService(ctx) - if err != nil { - return fmt.Errorf("failed to create DNS service: %w", err) - } - - zoneName := b.env.DNSZoneName - // Check if zone exists, otherwise create - _, err = dnsService.ManagedZones.Get(gcpProject, zoneName).Context(ctx).Do() - if err != nil { - zone := &dns.ManagedZone{ - Name: zoneName, - DnsName: b.env.BaseDomain + ".", - Description: "Codesphere DNS zone", - } - _, err = dnsService.ManagedZones.Create(gcpProject, zone).Context(ctx).Do() - if err != nil { - return fmt.Errorf("failed to create DNS zone: %w", err) - } - } - - records := []*dns.ResourceRecordSet{ - { - Name: fmt.Sprintf("cs.%s.", b.env.BaseDomain), - Type: "A", - Ttl: 300, - Rrdatas: []string{b.env.GatewayIP}, - }, - { - Name: fmt.Sprintf("*.cs.%s.", b.env.BaseDomain), - Type: "A", - Ttl: 300, - Rrdatas: []string{b.env.GatewayIP}, - }, - { - Name: fmt.Sprintf("*.ws.%s.", b.env.BaseDomain), - Type: "A", - Ttl: 300, - Rrdatas: []string{b.env.PublicGatewayIP}, - }, - { - Name: fmt.Sprintf("ws.%s.", b.env.BaseDomain), - Type: "A", - Ttl: 300, - Rrdatas: []string{b.env.PublicGatewayIP}, - }, - } - - deletions := []*dns.ResourceRecordSet{} - // Clean up existing records - for _, record := range records { - existingRecord, err := dnsService.ResourceRecordSets.Get(gcpProject, zoneName, record.Name, record.Type).Context(ctx).Do() - if err == nil && existingRecord != nil { - deletions = append(deletions, existingRecord) - } - } - - if len(deletions) > 0 { - delChange := &dns.Change{ - Deletions: deletions, - } - _, err = dnsService.Changes.Create(gcpProject, zoneName, delChange).Context(ctx).Do() - if err != nil { - return fmt.Errorf("failed to delete DNS records: %w", err) - } - } - - change := &dns.Change{ - Additions: records, - } - - _, err = dnsService.Changes.Create(gcpProject, zoneName, change).Context(ctx).Do() - if err != nil { - return fmt.Errorf("failed to create DNS records: %w", err) - } - - log.Printf("DNS records created in project %s zone %s", gcpProject, zoneName) - return nil -} - -func (b *GCPBootstrapper) InstallCodesphere() error { - err := b.env.Jumpbox.RunSSHCommand(nil, b.NodeManager, "root", "oms-cli download package "+b.env.InstallCodesphereVersion) - if err != nil { - return fmt.Errorf("failed to download Codesphere package from jumpbox: %w", err) - } - - err = b.env.Jumpbox.RunSSHCommand(nil, b.NodeManager, "root", "oms-cli install codesphere -c /etc/codesphere/config.yaml -k "+b.env.SecretsDir+"/age_key.txt -p "+b.env.InstallCodesphereVersion+".tar.gz") - if err != nil { - return fmt.Errorf("failed to install Codesphere from jumpbox: %w", err) - } - - log.Println("Codesphere installed from jumpbox") - return nil -} - -func (b *GCPBootstrapper) GenerateK0sConfigScript() error { - script := `#!/bin/bash - -cat < cloud.conf -[Global] -project-id = "$PROJECT_ID" -EOF - -cat <> cc-deployment.yaml -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: cloud-controller-manager - namespace: kube-system - labels: - component: cloud-controller-manager -spec: - selector: - matchLabels: - component: cloud-controller-manager - template: - metadata: - labels: - component: cloud-controller-manager - spec: - serviceAccountName: cloud-controller-manager - containers: - - name: cloud-controller-manager - image: k8scloudprovidergcp/cloud-controller-manager:latest - command: - - /usr/local/bin/cloud-controller-manager - args: - - --v=5 - - --cloud-provider=gce - - --cloud-config=/etc/gce/cloud.conf - - --leader-elect-resource-name=k0s-gcp-ccm - - --use-service-account-credentials=true - - --controllers=cloud-node,cloud-node-lifecycle,service - - --allocate-node-cidrs=false - - --configure-cloud-routes=false - volumeMounts: - - name: cloud-config-volume - mountPath: /etc/gce - readOnly: true - volumes: - - name: cloud-config-volume - configMap: - name: cloud-config - tolerations: - - key: node.cloudprovider.kubernetes.io/uninitialized - value: "true" - effect: NoSchedule - - key: node-role.kubernetes.io/master - effect: NoSchedule - - key: node-role.kubernetes.io/control-plane - effect: NoSchedule -EOF - -KUBECTL="/etc/codesphere/deps/kubernetes/files/k0s kubectl" -$KUBECTL create configmap cloud-config --from-file=cloud.conf -n kube-system -echo alias kubectl=\"$KUBECTL\" >> /root/.bashrc -echo alias k=\"$KUBECTL\" >> /root/.bashrc - -$KUBECTL apply -f https://raw.githubusercontent.com/kubernetes/cloud-provider-gcp/refs/tags/providers/v0.28.2/deploy/packages/default/manifest.yaml - -$KUBECTL apply -f cc-deployment.yaml - -# set loadBalancerIP for public-gateway-controller and gateway-controller -$KUBECTL patch svc public-gateway-controller -n codesphere -p '{"spec": {"loadBalancerIP": "'` + b.env.PublicGatewayIP + `'"}}' -$KUBECTL patch svc gateway-controller -n codesphere -p '{"spec": {"loadBalancerIP": "'` + b.env.GatewayIP + `'"}}' - -sed -i 's/k0scontroller/k0scontroller --enable-cloud-provider/g' /etc/systemd/system/k0scontroller.service - -ssh root@` + b.env.ControlPlaneNodes[1].InternalIP + ` "sed -i 's/k0sworker/k0sworker --enable-cloud-provider/g' /etc/systemd/system/k0sworker.service; systemctl daemon-reload; systemctl restart k0sworker" - -ssh root@` + b.env.ControlPlaneNodes[2].InternalIP + ` "sed -i 's/k0sworker/k0sworker --enable-cloud-provider/g' /etc/systemd/system/k0sworker.service; systemctl daemon-reload; systemctl restart k0sworker" - -systemctl daemon-reload -systemctl restart k0scontroller -` - // Probably we need to enable the cloud provider plugin in k0s configuration. - // --enable-cloud-provider on worker nodes systemd file /etc/systemd/system/k0sworker.service - // in addition on the first node: /etc/systemd/system/k0scontroller.service the flag --enable-cloud-provider - - err := os.WriteFile("configure-k0s.sh", []byte(script), 0755) - if err != nil { - return fmt.Errorf("failed to write configure-k0s.sh: %w", err) - } - err = b.env.ControlPlaneNodes[0].CopyFile(&b.env.Jumpbox, b.NodeManager, "configure-k0s.sh", "/root/configure-k0s.sh") - if err != nil { - return fmt.Errorf("failed to copy configure-k0s.sh to control plane node: %w", err) - } - err = b.env.ControlPlaneNodes[0].RunSSHCommand(&b.env.Jumpbox, b.NodeManager, "root", "chmod +x /root/configure-k0s.sh") - if err != nil { - return fmt.Errorf("failed to make configure-k0s.sh executable on control plane node: %w", err) - } - return nil -} - -// Helper functions -func protoInt32(i int32) *int32 { return &i } -func protoInt64(i int64) *int64 { return &i } -func isAlreadyExistsError(err error) bool { - return status.Code(err) == codes.AlreadyExists || strings.Contains(err.Error(), "already exists") -} - -// expandPath expands ~ to the user's home directory -func expandPath(path string) string { - if strings.HasPrefix(path, "~/") { - if home, err := os.UserHomeDir(); err == nil { - return filepath.Join(home, path[2:]) - } - } - return path -} - -// readSSHKey reads an SSH key file, expanding ~ in the path -func readSSHKey(path string) (string, error) { - realPath := expandPath(path) - data, err := os.ReadFile(realPath) - if err != nil { - return "", fmt.Errorf("error reading SSH key from %s: %w", realPath, err) - } - key := strings.TrimSpace(string(data)) - if key == "" { - return "", fmt.Errorf("SSH key at %s is empty", realPath) - } - return key, nil -} diff --git a/internal/bootstrap/gcp/bootstrap_suite_test.go b/internal/bootstrap/gcp/bootstrap_suite_test.go new file mode 100644 index 00000000..bc03cf06 --- /dev/null +++ b/internal/bootstrap/gcp/bootstrap_suite_test.go @@ -0,0 +1,16 @@ +// Copyright (c) Codesphere Inc. +// SPDX-License-Identifier: Apache-2.0 + +package gcp_test + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestBootstrap(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Bootstrap Suite") +} diff --git a/internal/bootstrap/gcp/gcp.go b/internal/bootstrap/gcp/gcp.go new file mode 100644 index 00000000..bfe55f8e --- /dev/null +++ b/internal/bootstrap/gcp/gcp.go @@ -0,0 +1,1349 @@ +// Copyright (c) Codesphere Inc. +// SPDX-License-Identifier: Apache-2.0 + +package gcp + +import ( + "context" + "fmt" + "sort" + "strings" + "sync" + "time" + + "cloud.google.com/go/compute/apiv1/computepb" + "github.com/codesphere-cloud/oms/internal/bootstrap" + "github.com/codesphere-cloud/oms/internal/env" + "github.com/codesphere-cloud/oms/internal/installer" + "github.com/codesphere-cloud/oms/internal/installer/files" + "github.com/codesphere-cloud/oms/internal/installer/node" + "github.com/codesphere-cloud/oms/internal/util" + "github.com/lithammer/shortuuid" + "google.golang.org/api/dns/v1" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type RegistryType string + +const ( + RegistryTypeLocalContainer RegistryType = "local-container" + RegistryTypeArtifactRegistry RegistryType = "artifact-registry" +) + +type VMDef struct { + Name string + MachineType string + Tags []string + AdditionalDisks []int64 + ExternalIP bool +} + +// Example VM definitions (expand as needed) +var vmDefs = []VMDef{ + {"jumpbox", "e2-medium", []string{"jumpbox", "ssh"}, []int64{}, true}, + {"postgres", "e2-standard-8", []string{"postgres"}, []int64{}, true}, + {"ceph-1", "e2-standard-8", []string{"ceph"}, []int64{20, 200}, false}, + {"ceph-2", "e2-standard-8", []string{"ceph"}, []int64{20, 200}, false}, + {"ceph-3", "e2-standard-8", []string{"ceph"}, []int64{20, 200}, false}, + {"ceph-4", "e2-standard-8", []string{"ceph"}, []int64{20, 200}, false}, + {"k0s-1", "e2-standard-16", []string{"k0s"}, []int64{}, false}, + {"k0s-2", "e2-standard-16", []string{"k0s"}, []int64{}, false}, + {"k0s-3", "e2-standard-16", []string{"k0s"}, []int64{}, false}, +} + +type GCPBootstrapper struct { + ctx context.Context + stlog *bootstrap.StepLogger + fw util.FileIO + icg installer.InstallConfigManager + NodeManager node.NodeManager + GCPClient GCPClientManager + // Environment + Env *CodesphereEnvironment + // SSH options + sshQuiet bool +} + +type CodesphereEnvironment struct { + ProjectID string `json:"project_id"` + ProjectName string `json:"project_name"` + DNSProjectID string `json:"dns_project_id"` + Jumpbox node.NodeManager `json:"jumpbox"` + PostgreSQLNode node.NodeManager `json:"postgresql_node"` + ControlPlaneNodes []node.NodeManager `json:"control_plane_nodes"` + CephNodes []node.NodeManager `json:"ceph_nodes"` + ContainerRegistryURL string `json:"container_registry_url"` + ExistingConfigUsed bool `json:"existing_config_used"` + InstallCodesphereVersion string `json:"install_codesphere_version"` + Preemptible bool `json:"preemptible"` + WriteConfig bool `json:"write_config"` + GatewayIP string `json:"gateway_ip"` + PublicGatewayIP string `json:"public_gateway_ip"` + RegistryType RegistryType `json:"registry_type"` + + // Config + InstallConfigPath string + SecretsFilePath string + InstallConfig *files.RootConfig + Secrets *files.InstallVault + + // GCP Specific + ProjectDisplayName string + BillingAccount string + BaseDomain string + GithubAppClientID string + GithubAppClientSecret string + SecretsDir string + FolderID string + SSHPublicKeyPath string + SSHPrivateKeyPath string + DatacenterID int + CustomPgIP string + Region string + Zone string + DNSZoneName string +} + +func NewGCPBootstrapper(ctx context.Context, env env.Env, stlog *bootstrap.StepLogger, CodesphereEnv *CodesphereEnvironment, icg installer.InstallConfigManager, gcpClient GCPClientManager, nm node.NodeManager, fw util.FileIO) (*GCPBootstrapper, error) { + return &GCPBootstrapper{ + ctx: ctx, + stlog: stlog, + fw: fw, + icg: icg, + GCPClient: gcpClient, + NodeManager: nm, + Env: CodesphereEnv, + sshQuiet: true, + }, nil +} + +func (b *GCPBootstrapper) Bootstrap() error { + err := b.stlog.Step("Ensure install config", b.EnsureInstallConfig) + if err != nil { + return fmt.Errorf("failed to ensure install config: %w", err) + } + + err = b.stlog.Step("Ensure secrets", b.EnsureSecrets) + if err != nil { + return fmt.Errorf("failed to ensure secrets: %w", err) + } + + err = b.stlog.Step("Ensure project", b.EnsureProject) + if err != nil { + return fmt.Errorf("failed to ensure GCP project: %w", err) + } + + err = b.stlog.Step("Ensure billing", b.EnsureBilling) + if err != nil { + return fmt.Errorf("failed to ensure billing is enabled: %w", err) + } + + err = b.stlog.Step("Ensure APIs enabled", b.EnsureAPIsEnabled) + if err != nil { + return fmt.Errorf("failed to enable required APIs: %w", err) + } + + if b.Env.RegistryType == RegistryTypeArtifactRegistry { + err = b.stlog.Step("Ensure artifact registry", b.EnsureArtifactRegistry) + if err != nil { + return fmt.Errorf("failed to ensure artifact registry: %w", err) + } + } + + err = b.stlog.Step("Ensure service accounts", b.EnsureServiceAccounts) + if err != nil { + return fmt.Errorf("failed to ensure service accounts: %w", err) + } + + err = b.stlog.Step("Ensure IAM roles", b.EnsureIAMRoles) + if err != nil { + return fmt.Errorf("failed to ensure IAM roles: %w", err) + } + + err = b.stlog.Step("Ensure VPC", b.EnsureVPC) + if err != nil { + return fmt.Errorf("failed to ensure VPC: %w", err) + } + + err = b.stlog.Step("Ensure firewall rules", b.EnsureFirewallRules) + if err != nil { + return fmt.Errorf("failed to ensure firewall rules: %w", err) + } + + err = b.stlog.Step("Ensure compute instances", b.EnsureComputeInstances) + if err != nil { + return fmt.Errorf("failed to ensure compute instances: %w", err) + } + + err = b.stlog.Step("Ensure gateway IP addresses", b.EnsureGatewayIPAddresses) + if err != nil { + return fmt.Errorf("failed to ensure external IP addresses: %w", err) + } + + err = b.stlog.Step("Ensure root login enabled", b.EnsureRootLoginEnabled) + if err != nil { + return fmt.Errorf("failed to ensure root login is enabled: %w", err) + } + + err = b.stlog.Step("Ensure jumpbox configured", b.EnsureJumpboxConfigured) + if err != nil { + return fmt.Errorf("failed to ensure jumpbox is configured: %w", err) + } + + err = b.stlog.Step("Ensure hosts are configured", b.EnsureHostsConfigured) + if err != nil { + return fmt.Errorf("failed to ensure hosts are configured: %w", err) + } + + if b.Env.RegistryType == RegistryTypeLocalContainer { + err = b.stlog.Step("Ensure local container registry", b.EnsureLocalContainerRegistry) + if err != nil { + return fmt.Errorf("failed to ensure local container registry: %w", err) + } + } + + if b.Env.WriteConfig { + err = b.stlog.Step("Update install config", b.UpdateInstallConfig) + if err != nil { + return fmt.Errorf("failed to update install config: %w", err) + } + + err = b.stlog.Step("Ensure age key", b.EnsureAgeKey) + if err != nil { + return fmt.Errorf("failed to ensure age key: %w", err) + } + + err = b.stlog.Step("Encrypt vault", b.EncryptVault) + if err != nil { + return fmt.Errorf("failed to encrypt vault: %w", err) + } + } + + err = b.stlog.Step("Ensure DNS records", b.EnsureDNSRecords) + if err != nil { + return fmt.Errorf("failed to ensure DNS records: %w", err) + } + + if b.Env.InstallCodesphereVersion != "" { + err = b.stlog.Step("Install Codesphere", b.InstallCodesphere) + if err != nil { + return fmt.Errorf("failed to install Codesphere: %w", err) + } + } + + err = b.stlog.Step("Generate k0s config script", b.GenerateK0sConfigScript) + if err != nil { + return fmt.Errorf("failed to generate k0s config script: %w", err) + } + + return nil +} + +func (b *GCPBootstrapper) EnsureInstallConfig() error { + if b.fw.Exists(b.Env.InstallConfigPath) { + err := b.icg.LoadInstallConfigFromFile(b.Env.InstallConfigPath) + if err != nil { + return fmt.Errorf("failed to load config file: %w", err) + } + + b.Env.ExistingConfigUsed = true + } else { + err := b.icg.ApplyProfile("dev") + if err != nil { + return fmt.Errorf("failed to apply profile: %w", err) + } + } + + b.Env.InstallConfig = b.icg.GetInstallConfig() + + return nil +} + +func (b *GCPBootstrapper) EnsureSecrets() error { + if b.fw.Exists(b.Env.SecretsFilePath) { + err := b.icg.LoadVaultFromFile(b.Env.SecretsFilePath) + if err != nil { + return fmt.Errorf("failed to load vault file: %w", err) + } + err = b.icg.MergeVaultIntoConfig() + if err != nil { + return fmt.Errorf("failed to merge vault into config: %w", err) + } + } + + b.Env.Secrets = b.icg.GetVault() + + return nil +} + +func (b *GCPBootstrapper) EnsureProject() error { + parent := "" + if b.Env.FolderID != "" { + parent = fmt.Sprintf("folders/%s", b.Env.FolderID) + } + + existingProject, err := b.GCPClient.GetProjectByName(b.Env.FolderID, b.Env.ProjectName) + if err == nil { + b.Env.ProjectID = existingProject.ProjectId + b.Env.ProjectName = existingProject.Name + return nil + } + if err.Error() == fmt.Sprintf("project not found: %s", b.Env.ProjectName) { + projectId := b.GCPClient.CreateProjectID(b.Env.ProjectName) + _, err = b.GCPClient.CreateProject(parent, projectId, b.Env.ProjectName) + if err != nil { + return fmt.Errorf("failed to create project: %w", err) + } + + b.Env.ProjectID = projectId + return nil + } + + return fmt.Errorf("failed to get project: %w", err) +} + +func (b *GCPBootstrapper) EnsureBilling() error { + bi, err := b.GCPClient.GetBillingInfo(b.Env.ProjectID) + if err != nil { + return fmt.Errorf("failed to get billing info: %w", err) + } + if bi.BillingEnabled && bi.BillingAccountName == b.Env.BillingAccount { + return nil + } + + err = b.GCPClient.EnableBilling(b.Env.ProjectID, b.Env.BillingAccount) + if err != nil { + return fmt.Errorf("failed to enable billing: %w", err) + } + + return nil +} + +func (b *GCPBootstrapper) EnsureAPIsEnabled() error { + apis := []string{ + "compute.googleapis.com", + "serviceusage.googleapis.com", + "artifactregistry.googleapis.com", + "dns.googleapis.com", + } + + err := b.GCPClient.EnableAPIs(b.Env.ProjectID, apis) + if err != nil { + return fmt.Errorf("failed to enable APIs: %w", err) + } + + return nil +} + +func (b *GCPBootstrapper) EnsureArtifactRegistry() error { + repoName := "codesphere-registry" + + repo, err := b.GCPClient.GetArtifactRegistry(b.Env.ProjectID, b.Env.Region, repoName) + if err == nil && repo != nil { + b.Env.InstallConfig.Registry.Server = repo.GetRegistryUri() + return nil + } + + repo, err = b.GCPClient.CreateArtifactRegistry(b.Env.ProjectID, b.Env.Region, repoName) + if err != nil || repo == nil { + return fmt.Errorf("failed to create artifact registry: %w, repo: %v", err, repo) + } + + return nil +} + +func (b *GCPBootstrapper) EnsureServiceAccounts() error { + _, _, err := b.GCPClient.CreateServiceAccount(b.Env.ProjectID, "cloud-controller", "cloud-controller") + if err != nil { + return err + } + + if b.Env.RegistryType == RegistryTypeArtifactRegistry { + sa, newSa, err := b.GCPClient.CreateServiceAccount(b.Env.ProjectID, "artifact-registry-writer", "artifact-registry-writer") + if err != nil { + return err + } + + if !newSa && b.Env.InstallConfig.Registry.Password != "" { + return nil + } + + for retries := range 5 { + privateKey, err := b.GCPClient.CreateServiceAccountKey(b.Env.ProjectID, sa) + + if err != nil && status.Code(err) != codes.AlreadyExists { + if retries > 3 { + return fmt.Errorf("failed to create service account key: %w", err) + } + b.stlog.LogRetry() + time.Sleep(5 * time.Second) + continue + } + + b.Env.InstallConfig.Registry.Password = string(privateKey) + b.Env.InstallConfig.Registry.Username = "_json_key_base64" + + break + } + } + + return nil +} + +func (b *GCPBootstrapper) EnsureIAMRoles() error { + err := b.GCPClient.AssignIAMRole(b.Env.ProjectID, "cloud-controller", "roles/compute.admin") + if err != nil { + return err + } + + if b.Env.RegistryType != RegistryTypeArtifactRegistry { + return nil + } + + err = b.GCPClient.AssignIAMRole(b.Env.ProjectID, "artifact-registry-writer", "roles/artifactregistry.writer") + return err +} + +func (b *GCPBootstrapper) EnsureVPC() error { + networkName := fmt.Sprintf("%s-vpc", b.Env.ProjectID) + subnetName := fmt.Sprintf("%s-%s-subnet", b.Env.ProjectID, b.Env.Region) + routerName := fmt.Sprintf("%s-router", b.Env.ProjectID) + natName := fmt.Sprintf("%s-nat-gateway", b.Env.ProjectID) + + // Create VPC + err := b.GCPClient.CreateVPC(b.Env.ProjectID, b.Env.Region, networkName, subnetName, routerName, natName) + if err != nil { + return fmt.Errorf("failed to ensure VPC: %w", err) + } + + return nil +} + +func (b *GCPBootstrapper) EnsureFirewallRules() error { + networkName := fmt.Sprintf("%s-vpc", b.Env.ProjectID) + + // Allow external SSH to Jumpbox + sshRule := &computepb.Firewall{ + Name: protoString("allow-ssh-ext"), + Network: protoString(fmt.Sprintf("projects/%s/global/networks/%s", b.Env.ProjectID, networkName)), + Direction: protoString("INGRESS"), + Priority: protoInt32(1000), + Allowed: []*computepb.Allowed{ + { + IPProtocol: protoString("tcp"), + Ports: []string{"22"}, + }, + }, + SourceRanges: []string{"0.0.0.0/0"}, + TargetTags: []string{"ssh"}, + Description: protoString("Allow external SSH to Jumpbox"), + } + err := b.GCPClient.CreateFirewallRule(b.Env.ProjectID, sshRule) + if err != nil { + return fmt.Errorf("failed to create jumpbox ssh firewall rule: %w", err) + } + + // Allow all internal traffic + internalRule := &computepb.Firewall{ + Name: protoString("allow-internal"), + Network: protoString(fmt.Sprintf("projects/%s/global/networks/%s", b.Env.ProjectID, networkName)), + Direction: protoString("INGRESS"), + Priority: protoInt32(1000), + Allowed: []*computepb.Allowed{ + {IPProtocol: protoString("all")}, + }, + SourceRanges: []string{"10.10.0.0/20"}, + Description: protoString("Allow all internal traffic"), + } + err = b.GCPClient.CreateFirewallRule(b.Env.ProjectID, internalRule) + if err != nil { + return fmt.Errorf("failed to create internal firewall rule: %w", err) + } + + // Allow all egress + egressRule := &computepb.Firewall{ + Name: protoString("allow-all-egress"), + Network: protoString(fmt.Sprintf("projects/%s/global/networks/%s", b.Env.ProjectID, networkName)), + Direction: protoString("EGRESS"), + Priority: protoInt32(1000), + Allowed: []*computepb.Allowed{ + {IPProtocol: protoString("all")}, + }, + DestinationRanges: []string{"0.0.0.0/0"}, + Description: protoString("Allow all egress"), + } + err = b.GCPClient.CreateFirewallRule(b.Env.ProjectID, egressRule) + if err != nil { + return fmt.Errorf("failed to create egress firewall rule: %w", err) + } + + // Allow ingress for web (HTTP/HTTPS) + webRule := &computepb.Firewall{ + Name: protoString("allow-ingress-web"), + Network: protoString(fmt.Sprintf("projects/%s/global/networks/%s", b.Env.ProjectID, networkName)), + Direction: protoString("INGRESS"), + Priority: protoInt32(1000), + Allowed: []*computepb.Allowed{ + {IPProtocol: protoString("tcp"), Ports: []string{"80", "443"}}, + }, + SourceRanges: []string{"0.0.0.0/0"}, + Description: protoString("Allow HTTP/HTTPS ingress"), + } + err = b.GCPClient.CreateFirewallRule(b.Env.ProjectID, webRule) + if err != nil { + return fmt.Errorf("failed to create web firewall rule: %w", err) + } + + // Allow ingress for PostgreSQL + postgresRule := &computepb.Firewall{ + Name: protoString("allow-ingress-postgres"), + Network: protoString(fmt.Sprintf("projects/%s/global/networks/%s", b.Env.ProjectID, networkName)), + Direction: protoString("INGRESS"), + Priority: protoInt32(1000), + Allowed: []*computepb.Allowed{ + {IPProtocol: protoString("tcp"), Ports: []string{"5432"}}, + }, + SourceRanges: []string{"0.0.0.0/0"}, + TargetTags: []string{"postgres"}, + Description: protoString("Allow external access to PostgreSQL"), + } + err = b.GCPClient.CreateFirewallRule(b.Env.ProjectID, postgresRule) + if err != nil { + return fmt.Errorf("failed to create postgres firewall rule: %w", err) + } + + return nil +} + +type vmResult struct { + vmType string // jumpbox, postgres, ceph, k0s + name string + externalIP string + internalIP string +} + +func (b *GCPBootstrapper) EnsureComputeInstances() error { + projectID := b.Env.ProjectID + region := b.Env.Region + zone := b.Env.Zone + + network := fmt.Sprintf("projects/%s/global/networks/%s-vpc", projectID, projectID) + subnetwork := fmt.Sprintf("projects/%s/regions/%s/subnetworks/%s-%s-subnet", projectID, region, projectID, region) + diskType := fmt.Sprintf("projects/%s/zones/%s/diskTypes/pd-ssd", projectID, zone) + + // Create VMs in parallel + wg := sync.WaitGroup{} + errCh := make(chan error, len(vmDefs)) + resultCh := make(chan vmResult, len(vmDefs)) + for _, vm := range vmDefs { + wg.Add(1) + go func(vm VMDef) { + defer wg.Done() + disks := []*computepb.AttachedDisk{ + { + Boot: protoBool(true), + AutoDelete: protoBool(true), + Type: protoString("PERSISTENT"), + InitializeParams: &computepb.AttachedDiskInitializeParams{ + DiskType: &diskType, + DiskSizeGb: protoInt64(200), + SourceImage: protoString("projects/ubuntu-os-cloud/global/images/family/ubuntu-2204-lts"), + }, + }, + } + for _, diskSize := range vm.AdditionalDisks { + disks = append(disks, &computepb.AttachedDisk{ + Boot: protoBool(false), + AutoDelete: protoBool(true), + Type: protoString("PERSISTENT"), + InitializeParams: &computepb.AttachedDiskInitializeParams{ + DiskSizeGb: protoInt64(diskSize), + DiskType: &diskType, + }, + }) + } + + pubKey, err := b.readSSHKey(b.Env.SSHPublicKeyPath) + if err != nil { + errCh <- fmt.Errorf("failed to read SSH public key: %w", err) + return + } + + serviceAccount := fmt.Sprintf("cloud-controller@%s.iam.gserviceaccount.com", projectID) + instance := &computepb.Instance{ + Name: protoString(vm.Name), + ServiceAccounts: []*computepb.ServiceAccount{ + { + Email: protoString(serviceAccount), + Scopes: []string{"https://www.googleapis.com/auth/cloud-platform"}, + }, + }, + MachineType: protoString(fmt.Sprintf("zones/%s/machineTypes/%s", zone, vm.MachineType)), + Tags: &computepb.Tags{ + Items: vm.Tags, + }, + Scheduling: &computepb.Scheduling{ + Preemptible: &b.Env.Preemptible, + }, + NetworkInterfaces: []*computepb.NetworkInterface{ + { + Network: protoString(network), + Subnetwork: protoString(subnetwork), + }, + }, + Disks: disks, + Metadata: &computepb.Metadata{ + Items: []*computepb.Items{ + { + Key: protoString("ssh-keys"), + Value: protoString(fmt.Sprintf("root:%s\nubuntu:%s", pubKey+"root", pubKey+"ubuntu")), + }, + }, + }, + } + + // Configure external IP if needed + if vm.ExternalIP { + instance.NetworkInterfaces[0].AccessConfigs = []*computepb.AccessConfig{ + { + Name: protoString("External NAT"), + Type: protoString("ONE_TO_ONE_NAT"), + }, + } + } + + err = b.GCPClient.CreateInstance(projectID, zone, instance) + if err != nil && !isAlreadyExistsError(err) { + errCh <- fmt.Errorf("failed to create instance %s: %w", vm.Name, err) + return + } + + // Find out the IP addresses of the created instance + resp, err := b.GCPClient.GetInstance(projectID, zone, vm.Name) + if err != nil { + errCh <- fmt.Errorf("failed to get instance %s: %w", vm.Name, err) + return + } + + externalIP := "" + internalIP := "" + if len(resp.GetNetworkInterfaces()) > 0 { + internalIP = resp.GetNetworkInterfaces()[0].GetNetworkIP() + if len(resp.GetNetworkInterfaces()[0].GetAccessConfigs()) > 0 { + externalIP = resp.GetNetworkInterfaces()[0].GetAccessConfigs()[0].GetNatIP() + } + } + + // Send result through channel instead of creating nodes in goroutine + resultCh <- vmResult{ + vmType: vm.Tags[0], + name: vm.Name, + externalIP: externalIP, + internalIP: internalIP, + } + }(vm) + } + wg.Wait() + + close(errCh) + close(resultCh) + + errStr := "" + for err := range errCh { + errStr += err.Error() + "; " + } + if errStr != "" { + return fmt.Errorf("error ensuring compute instances: %s", errStr) + } + + // Create nodes from results (in main goroutine, not in spawned goroutines) + for result := range resultCh { + switch result.vmType { + case "jumpbox": + b.NodeManager.UpdateNode(result.name, result.externalIP, result.internalIP) + b.Env.Jumpbox = b.NodeManager + case "postgres": + b.Env.PostgreSQLNode = b.NodeManager.CreateSubNode(result.name, result.externalIP, result.internalIP) + case "ceph": + node := b.NodeManager.CreateSubNode(result.name, result.externalIP, result.internalIP) + b.Env.CephNodes = append(b.Env.CephNodes, node) + case "k0s": + node := b.NodeManager.CreateSubNode(result.name, result.externalIP, result.internalIP) + b.Env.ControlPlaneNodes = append(b.Env.ControlPlaneNodes, node) + } + } + + //sort ceph nodes by name to ensure consistent ordering + sort.Slice(b.Env.CephNodes, func(i, j int) bool { + return b.Env.CephNodes[i].GetName() < b.Env.CephNodes[j].GetName() + }) + //sort control plane nodes by name to ensure consistent ordering + sort.Slice(b.Env.ControlPlaneNodes, func(i, j int) bool { + return b.Env.ControlPlaneNodes[i].GetName() < b.Env.ControlPlaneNodes[j].GetName() + }) + + return nil +} + +// EnsureGatewayIPAddresses reserves 2 static external IP addresses for the ingress +// controllers of the cluster. +func (b *GCPBootstrapper) EnsureGatewayIPAddresses() error { + var err error + b.Env.GatewayIP, err = b.EnsureExternalIP("gateway") + if err != nil { + return fmt.Errorf("failed to ensure gateway IP: %w", err) + } + b.Env.PublicGatewayIP, err = b.EnsureExternalIP("public-gateway") + if err != nil { + return fmt.Errorf("failed to ensure public gateway IP: %w", err) + } + return nil +} + +// EnsureExternalIP ensures that a static external IP address with the given name exists. +func (b *GCPBootstrapper) EnsureExternalIP(name string) (string, error) { + desiredAddress := &computepb.Address{ + Name: &name, + AddressType: protoString("EXTERNAL"), + Region: &b.Env.Region, + } + + // Figure out if address already exists and get IP + address, err := b.GCPClient.GetAddress(b.Env.ProjectID, b.Env.Region, name) + if err == nil && address != nil { + return address.GetAddress(), nil + } + + createdIP, err := b.GCPClient.CreateAddress(b.Env.ProjectID, b.Env.Region, desiredAddress) + if err != nil && !isAlreadyExistsError(err) { + return "", fmt.Errorf("failed to create address %s: %w", name, err) + } + + if createdIP != "" { + return createdIP, nil + } + + address, err = b.GCPClient.GetAddress(b.Env.ProjectID, b.Env.Region, name) + + if err == nil && address != nil { + return address.GetAddress(), nil + } + return "", fmt.Errorf("failed to get address %s after creation", name) +} + +func (b *GCPBootstrapper) EnsureRootLoginEnabled() error { + allNodes := []node.NodeManager{ + b.Env.Jumpbox, + } + allNodes = append(allNodes, b.Env.ControlPlaneNodes...) + allNodes = append(allNodes, b.Env.PostgreSQLNode) + allNodes = append(allNodes, b.Env.CephNodes...) + + for _, node := range allNodes { + err := b.stlog.Substep(fmt.Sprintf("Ensuring root login enabled on %s", node.GetName()), func() error { + return b.ensureRootLoginEnabledInNode(node) + }) + if err != nil { + return err + } + } + + return nil +} + +func (b *GCPBootstrapper) ensureRootLoginEnabledInNode(node node.NodeManager) error { + err := node.WaitForSSH(30 * time.Second) + if err != nil { + return fmt.Errorf("timed out waiting for SSH service to start on %s: %w", node.GetName(), err) + } + + hasRootLogin := node.HasRootLoginEnabled() + if hasRootLogin { + return nil + } + + for i := range 3 { + err := node.EnableRootLogin() + if err == nil { + break + } + if i == 2 { + return fmt.Errorf("failed to enable root login on %s: %w", node.GetName(), err) + } + b.stlog.LogRetry() + time.Sleep(10 * time.Second) + } + + return nil +} + +func (b *GCPBootstrapper) EnsureJumpboxConfigured() error { + if !b.Env.Jumpbox.HasAcceptEnvConfigured() { + err := b.Env.Jumpbox.ConfigureAcceptEnv() + if err != nil { + return fmt.Errorf("failed to configure AcceptEnv on jumpbox: %w", err) + } + } + + hasOms := b.Env.Jumpbox.HasCommand("oms-cli") + if hasOms { + return nil + } + + err := b.Env.Jumpbox.InstallOms() + if err != nil { + return fmt.Errorf("failed to install OMS on jumpbox: %w", err) + } + + return nil +} + +func (b *GCPBootstrapper) EnsureHostsConfigured() error { + allNodes := append(b.Env.ControlPlaneNodes, b.Env.PostgreSQLNode) + allNodes = append(allNodes, b.Env.CephNodes...) + + for _, node := range allNodes { + if !node.HasInotifyWatchesConfigured() { + err := node.ConfigureInotifyWatches() + if err != nil { + return fmt.Errorf("failed to configure inotify watches on %s: %w", node.GetName(), err) + } + } + if !node.HasMemoryMapConfigured() { + err := node.ConfigureMemoryMap() + if err != nil { + return fmt.Errorf("failed to configure memory map on %s: %w", node.GetName(), err) + } + } + } + + return nil +} + +// EnsureLocalContainerRegistry installs a docker registry on the postgres node to speed up image loading time +func (b *GCPBootstrapper) EnsureLocalContainerRegistry() error { + localRegistryServer := b.Env.PostgreSQLNode.GetInternalIP() + ":5000" + + // Figure out if registry is already running + b.stlog.Logf("Checking if local container registry is already running on postgres node") + checkCommand := `test "$(podman ps --filter 'name=registry' --format '{{.Names}}' | wc -l)" -eq "1"` + err := b.Env.PostgreSQLNode.RunSSHCommand("root", checkCommand, b.sshQuiet) + if err == nil && b.Env.InstallConfig.Registry != nil && b.Env.InstallConfig.Registry.Server == localRegistryServer && + b.Env.InstallConfig.Registry.Username != "" && b.Env.InstallConfig.Registry.Password != "" { + b.stlog.Logf("Local container registry already running on postgres node") + return nil + } + + b.Env.InstallConfig.Registry.Server = localRegistryServer + b.Env.InstallConfig.Registry.Username = "custom-registry" + b.Env.InstallConfig.Registry.Password = shortuuid.New() + + commands := []string{ + "apt-get update", + "apt-get install -y podman apache2-utils", + "htpasswd -bBc /root/registry.password " + b.Env.InstallConfig.Registry.Username + " " + b.Env.InstallConfig.Registry.Password, + "openssl req -newkey rsa:4096 -nodes -sha256 -keyout /root/registry.key -x509 -days 365 -out /root/registry.crt -subj \"/C=DE/ST=BW/L=Karlsruhe/O=Codesphere/CN=" + b.Env.PostgreSQLNode.GetInternalIP() + "\" -addext \"subjectAltName = DNS:postgres,IP:" + b.Env.PostgreSQLNode.GetInternalIP() + "\"", + "podman rm -f registry || true", + `podman run -d \ + --restart=always --name registry --net=host\ + --env REGISTRY_HTTP_ADDR=0.0.0.0:5000 \ + --env REGISTRY_AUTH=htpasswd \ + --env REGISTRY_AUTH_HTPASSWD_REALM='Registry Realm' \ + --env REGISTRY_AUTH_HTPASSWD_PATH=/auth/registry.password \ + -v /root/registry.password:/auth/registry.password \ + --env REGISTRY_HTTP_TLS_CERTIFICATE=/certs/registry.crt \ + --env REGISTRY_HTTP_TLS_KEY=/certs/registry.key \ + -v /root/registry.crt:/certs/registry.crt \ + -v /root/registry.key:/certs/registry.key \ + registry:2`, + `mkdir -p /etc/docker/certs.d/` + b.Env.InstallConfig.Registry.Server, + `cp /root/registry.crt /etc/docker/certs.d/` + b.Env.InstallConfig.Registry.Server + `/ca.crt`, + } + for _, cmd := range commands { + b.stlog.Logf("Running command on postgres node: %s", util.Truncate(cmd, 12)) + err := b.Env.PostgreSQLNode.RunSSHCommand("root", cmd, b.sshQuiet) + if err != nil { + return fmt.Errorf("failed to run command on postgres node: %w", err) + } + } + + allNodes := append(b.Env.ControlPlaneNodes, b.Env.CephNodes...) + for _, node := range allNodes { + b.stlog.Logf("Configuring node '%s' to trust local registry certificate", node.GetName()) + err := b.Env.PostgreSQLNode.RunSSHCommand("root", "scp -o StrictHostKeyChecking=no /root/registry.crt root@"+node.GetInternalIP()+":/usr/local/share/ca-certificates/registry.crt", b.sshQuiet) + if err != nil { + return fmt.Errorf("failed to copy registry certificate to node %s: %w", node.GetInternalIP(), err) + } + err = node.RunSSHCommand("root", "update-ca-certificates", b.sshQuiet) + if err != nil { + return fmt.Errorf("failed to update CA certificates on node %s: %w", node.GetInternalIP(), err) + } + err = node.RunSSHCommand("root", "systemctl restart docker.service || true", true) // docker is probably not yet instb.sshQuietd + if err != nil { + return fmt.Errorf("failed to restart docker service on node %s: %w", node.GetInternalIP(), err) + } + } + + return nil +} + +func (b *GCPBootstrapper) UpdateInstallConfig() error { + // Update install config with necessary values + b.Env.InstallConfig.Datacenter.ID = b.Env.DatacenterID + b.Env.InstallConfig.Datacenter.City = "Karlsruhe" + b.Env.InstallConfig.Datacenter.CountryCode = "DE" + b.Env.InstallConfig.Secrets.BaseDir = b.Env.SecretsDir + b.Env.InstallConfig.Registry.ReplaceImagesInBom = true + b.Env.InstallConfig.Registry.LoadContainerImages = true + + if b.Env.InstallConfig.Postgres.Primary == nil { + b.Env.InstallConfig.Postgres.Primary = &files.PostgresPrimaryConfig{ + Hostname: b.Env.PostgreSQLNode.GetName(), + } + } + b.Env.InstallConfig.Postgres.Primary.IP = b.Env.PostgreSQLNode.GetInternalIP() + + b.Env.InstallConfig.Ceph.CsiKubeletDir = "/var/lib/k0s/kubelet" + b.Env.InstallConfig.Ceph.NodesSubnet = "10.10.0.0/20" + b.Env.InstallConfig.Ceph.Hosts = []files.CephHost{ + { + Hostname: b.Env.CephNodes[0].GetName(), + IsMaster: true, + IPAddress: b.Env.CephNodes[0].GetInternalIP(), + }, + { + Hostname: b.Env.CephNodes[1].GetName(), + IPAddress: b.Env.CephNodes[1].GetInternalIP(), + }, + { + Hostname: b.Env.CephNodes[2].GetName(), + IPAddress: b.Env.CephNodes[2].GetInternalIP(), + }, + { + Hostname: b.Env.CephNodes[3].GetName(), + IPAddress: b.Env.CephNodes[3].GetInternalIP(), + }, + } + b.Env.InstallConfig.Ceph.OSDs = []files.CephOSD{ + { + SpecID: "default", + Placement: files.CephPlacement{ + HostPattern: "*", + }, + DataDevices: files.CephDataDevices{ + Size: "100G:", + Limit: 1, + }, + DBDevices: files.CephDBDevices{ + Size: "10G:500G", + Limit: 1, + }, + }, + } + + b.Env.InstallConfig.Kubernetes = files.KubernetesConfig{ + ManagedByCodesphere: true, + APIServerHost: b.Env.ControlPlaneNodes[0].GetInternalIP(), + ControlPlanes: []files.K8sNode{ + { + IPAddress: b.Env.ControlPlaneNodes[0].GetInternalIP(), + }, + }, + Workers: []files.K8sNode{ + { + IPAddress: b.Env.ControlPlaneNodes[0].GetInternalIP(), + }, + + { + IPAddress: b.Env.ControlPlaneNodes[1].GetInternalIP(), + }, + { + IPAddress: b.Env.ControlPlaneNodes[2].GetInternalIP(), + }, + }, + } + b.Env.InstallConfig.Cluster.Monitoring = &files.MonitoringConfig{ + Prometheus: &files.PrometheusConfig{ + RemoteWrite: &files.RemoteWriteConfig{ + Enabled: false, + ClusterName: "GCP-test", + }, + }, + } + b.Env.InstallConfig.Cluster.Gateway = files.GatewayConfig{ + ServiceType: "LoadBalancer", + //IPAddresses: []string{b.Env.ControlPlaneNodes[0].ExternalIP}, + Annotations: map[string]string{ + "cloud.google.com/load-balancer-ipv4": b.Env.GatewayIP, + }, + } + b.Env.InstallConfig.Cluster.PublicGateway = files.GatewayConfig{ + ServiceType: "LoadBalancer", + Annotations: map[string]string{ + "cloud.google.com/load-balancer-ipv4": b.Env.PublicGatewayIP, + }, + //IPAddresses: []string{b.Env.ControlPlaneNodes[1].ExternalIP}, + } + + b.Env.InstallConfig.Codesphere.Domain = "cs." + b.Env.BaseDomain + b.Env.InstallConfig.Codesphere.WorkspaceHostingBaseDomain = "ws." + b.Env.BaseDomain + b.Env.InstallConfig.Codesphere.PublicIP = b.Env.ControlPlaneNodes[1].GetExternalIP() + b.Env.InstallConfig.Codesphere.CustomDomains = files.CustomDomainsConfig{ + CNameBaseDomain: "ws." + b.Env.BaseDomain, + } + b.Env.InstallConfig.Codesphere.DNSServers = []string{"8.8.8.8"} + b.Env.InstallConfig.Codesphere.Experiments = []string{} + b.Env.InstallConfig.Codesphere.DeployConfig = files.DeployConfig{ + Images: map[string]files.ImageConfig{ + "ubuntu-24.04": { + Name: "Ubuntu 24.04", + SupportedUntil: "2028-05-31", + Flavors: map[string]files.FlavorConfig{ + "default": { + Image: files.ImageRef{ + BomRef: "workspace-agent-24.04", + }, + Pool: map[int]int{ + 1: 1, + 2: 1, + 3: 0, + 4: 0, + }, + }, + }, + }, + }, + } + b.Env.InstallConfig.Codesphere.Plans = files.PlansConfig{ + HostingPlans: map[int]files.HostingPlan{ + 1: { + CPUTenth: 10, + GPUParts: 0, + MemoryMb: 2048, + StorageMb: 20480, + TempStorageMb: 1024, + }, + 2: { + CPUTenth: 20, + GPUParts: 0, + MemoryMb: 4096, + StorageMb: 20480, + TempStorageMb: 1024, + }, + 3: { + CPUTenth: 40, + GPUParts: 0, + MemoryMb: 8192, + StorageMb: 40960, + TempStorageMb: 1024, + }, + 4: { + CPUTenth: 80, + GPUParts: 0, + MemoryMb: 16384, + StorageMb: 40960, + TempStorageMb: 1024, + }, + }, + WorkspacePlans: map[int]files.WorkspacePlan{ + 1: { + Name: "Micro", + HostingPlanID: 1, + MaxReplicas: 3, + OnDemand: true, + }, + 2: { + Name: "Standard", + HostingPlanID: 2, + MaxReplicas: 3, + OnDemand: true, + }, + 3: { + Name: "Big", + HostingPlanID: 3, + MaxReplicas: 3, + OnDemand: true, + }, + 4: { + Name: "Pro", + HostingPlanID: 4, + MaxReplicas: 3, + OnDemand: true, + }, + }, + } + b.Env.InstallConfig.Codesphere.GitProviders = &files.GitProvidersConfig{ + GitHub: &files.GitProviderConfig{ + Enabled: true, + URL: "https://github.com", + API: files.APIConfig{ + BaseURL: "https://api.github.com", + }, + OAuth: files.OAuthConfig{ + Issuer: "https://github.com", + AuthorizationEndpoint: "https://github.com/login/oauth/authorize", + TokenEndpoint: "https://github.com/login/oauth/access_token", + + ClientID: b.Env.GithubAppClientID, + ClientSecret: b.Env.GithubAppClientSecret, + }, + }, + } + b.Env.InstallConfig.Codesphere.ManagedServices = []files.ManagedServiceConfig{} + + if !b.Env.ExistingConfigUsed { + err := b.icg.GenerateSecrets() + if err != nil { + return fmt.Errorf("failed to generate secrets: %w", err) + } + } else { + var err error + b.Env.InstallConfig.Postgres.Primary.PrivateKey, b.Env.InstallConfig.Postgres.Primary.SSLConfig.ServerCertPem, err = installer.GenerateServerCertificate( + b.Env.InstallConfig.Postgres.CaCertPrivateKey, + b.Env.InstallConfig.Postgres.CACertPem, + b.Env.InstallConfig.Postgres.Primary.Hostname, + []string{b.Env.InstallConfig.Postgres.Primary.IP}) + if err != nil { + return fmt.Errorf("failed to generate primary server certificate: %w", err) + } + if b.Env.InstallConfig.Postgres.Replica != nil { + b.Env.InstallConfig.Postgres.ReplicaPrivateKey, b.Env.InstallConfig.Postgres.Replica.SSLConfig.ServerCertPem, err = installer.GenerateServerCertificate( + b.Env.InstallConfig.Postgres.CaCertPrivateKey, + b.Env.InstallConfig.Postgres.CACertPem, + b.Env.InstallConfig.Postgres.Replica.Name, + []string{b.Env.InstallConfig.Postgres.Replica.IP}) + if err != nil { + return fmt.Errorf("failed to generate replica server certificate: %w", err) + } + } + } + + if err := b.icg.WriteInstallConfig(b.Env.InstallConfigPath, true); err != nil { + return fmt.Errorf("failed to write config file: %w", err) + } + + if err := b.icg.WriteVault(b.Env.SecretsFilePath, true); err != nil { + return fmt.Errorf("failed to write vault file: %w", err) + } + + err := b.Env.Jumpbox.CopyFile(b.Env.InstallConfigPath, "/etc/codesphere/config.yaml") + if err != nil { + return fmt.Errorf("failed to copy install config to jumpbox: %w", err) + } + + err = b.Env.Jumpbox.CopyFile(b.Env.SecretsFilePath, b.Env.SecretsDir+"/prod.vault.yaml") + if err != nil { + return fmt.Errorf("failed to copy secrets file to jumpbox: %w", err) + } + return nil +} + +func (b *GCPBootstrapper) EnsureAgeKey() error { + hasKey := b.Env.Jumpbox.HasFile(b.Env.SecretsDir + "/age_key.txt") + if hasKey { + return nil + } + + err := b.Env.Jumpbox.RunSSHCommand("root", fmt.Sprintf("mkdir -p %s; age-keygen -o %s/age_key.txt", b.Env.SecretsDir, b.Env.SecretsDir), b.sshQuiet) + if err != nil { + return fmt.Errorf("failed to generate age key on jumpbox: %w", err) + } + + return nil +} + +func (b *GCPBootstrapper) EncryptVault() error { + err := b.Env.Jumpbox.RunSSHCommand("root", "cp "+b.Env.SecretsDir+"/prod.vault.yaml{,.bak}", b.sshQuiet) + if err != nil { + return fmt.Errorf("failed backup vault on jumpbox: %w", err) + } + + err = b.Env.Jumpbox.RunSSHCommand("root", "sops --encrypt --in-place --age $(age-keygen -y "+b.Env.SecretsDir+"/age_key.txt) "+b.Env.SecretsDir+"/prod.vault.yaml", b.sshQuiet) + if err != nil { + return fmt.Errorf("failed to encrypt vault on jumpbox: %w", err) + } + + return nil +} + +func (b *GCPBootstrapper) EnsureDNSRecords() error { + gcpProject := b.Env.DNSProjectID + if b.Env.DNSProjectID == "" { + gcpProject = b.Env.ProjectID + } + + zoneName := b.Env.DNSZoneName + err := b.GCPClient.EnsureDNSManagedZone(gcpProject, zoneName, b.Env.BaseDomain+".", "Codesphere DNS zone") + if err != nil { + return fmt.Errorf("failed to ensure DNS managed zone: %w", err) + } + + records := []*dns.ResourceRecordSet{ + { + Name: fmt.Sprintf("cs.%s.", b.Env.BaseDomain), + Type: "A", + Ttl: 300, + Rrdatas: []string{b.Env.GatewayIP}, + }, + { + Name: fmt.Sprintf("*.cs.%s.", b.Env.BaseDomain), + Type: "A", + Ttl: 300, + Rrdatas: []string{b.Env.GatewayIP}, + }, + { + Name: fmt.Sprintf("*.ws.%s.", b.Env.BaseDomain), + Type: "A", + Ttl: 300, + Rrdatas: []string{b.Env.PublicGatewayIP}, + }, + { + Name: fmt.Sprintf("ws.%s.", b.Env.BaseDomain), + Type: "A", + Ttl: 300, + Rrdatas: []string{b.Env.PublicGatewayIP}, + }, + } + + err = b.GCPClient.EnsureDNSRecordSets(gcpProject, zoneName, records) + if err != nil { + return fmt.Errorf("failed to ensure DNS record sets: %w", err) + } + + return nil +} + +func (b *GCPBootstrapper) InstallCodesphere() error { + err := b.Env.Jumpbox.RunSSHCommand("root", "oms-cli download package "+b.Env.InstallCodesphereVersion, b.sshQuiet) + if err != nil { + return fmt.Errorf("failed to download Codesphere package from jumpbox: %w", err) + } + + err = b.Env.Jumpbox.RunSSHCommand("root", "oms-cli install codesphere -c /etc/codesphere/config.yaml -k "+b.Env.SecretsDir+"/age_key.txt -p "+b.Env.InstallCodesphereVersion+".tar.gz", b.sshQuiet) + if err != nil { + return fmt.Errorf("failed to install Codesphere from jumpbox: %w", err) + } + + return nil +} + +func (b *GCPBootstrapper) GenerateK0sConfigScript() error { + script := `#!/bin/bash + +cat < cloud.conf +[Global] +project-id = "$PROJECT_ID" +EOF + +cat <> cc-deployment.yaml +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: cloud-controller-manager + namespace: kube-system + labels: + component: cloud-controller-manager +spec: + selector: + matchLabels: + component: cloud-controller-manager + template: + metadata: + labels: + component: cloud-controller-manager + spec: + serviceAccountName: cloud-controller-manager + containers: + - name: cloud-controller-manager + image: k8scloudprovidergcp/cloud-controller-manager:latest + command: + - /usr/local/bin/cloud-controller-manager + args: + - --v=5 + - --cloud-provider=gce + - --cloud-config=/etc/gce/cloud.conf + - --leader-elect-resource-name=k0s-gcp-ccm + - --use-service-account-credentials=true + - --controllers=cloud-node,cloud-node-lifecycle,service + - --allocate-node-cidrs=false + - --configure-cloud-routes=false + volumeMounts: + - name: cloud-config-volume + mountPath: /etc/gce + readOnly: true + volumes: + - name: cloud-config-volume + configMap: + name: cloud-config + tolerations: + - key: node.cloudprovider.kubernetes.io/uninitialized + value: "true" + effect: NoSchedule + - key: node-role.kubernetes.io/master + effect: NoSchedule + - key: node-role.kubernetes.io/control-plane + effect: NoSchedule +EOF + +KUBECTL="/etc/codesphere/deps/kubernetes/files/k0s kubectl" +$KUBECTL create configmap cloud-config --from-file=cloud.conf -n kube-system +echo alias kubectl=\"$KUBECTL\" >> /root/.bashrc +echo alias k=\"$KUBECTL\" >> /root/.bashrc + +$KUBECTL apply -f https://raw.githubusercontent.com/kubernetes/cloud-provider-gcp/refs/tags/providers/v0.28.2/deploy/packages/default/manifest.yaml + +$KUBECTL apply -f cc-deployment.yaml + +# set loadBalancerIP for public-gateway-controller and gateway-controller +$KUBECTL patch svc public-gateway-controller -n codesphere -p '{"spec": {"loadBalancerIP": "'` + b.Env.PublicGatewayIP + `'"}}' +$KUBECTL patch svc gateway-controller -n codesphere -p '{"spec": {"loadBalancerIP": "'` + b.Env.GatewayIP + `'"}}' + +sed -i 's/k0scontroller/k0scontroller --enable-cloud-provider/g' /etc/systemd/system/k0scontroller.service + +ssh root@` + b.Env.ControlPlaneNodes[1].GetInternalIP() + ` "sed -i 's/k0sworker/k0sworker --enable-cloud-provider/g' /etc/systemd/system/k0sworker.service; systemctl daemon-reload; systemctl restart k0sworker" + +ssh root@` + b.Env.ControlPlaneNodes[2].GetInternalIP() + ` "sed -i 's/k0sworker/k0sworker --enable-cloud-provider/g' /etc/systemd/system/k0sworker.service; systemctl daemon-reload; systemctl restart k0sworker" + +systemctl daemon-reload +systemctl restart k0scontroller +` + // Probably we need to enable the cloud provider plugin in k0s configuration. + // --enable-cloud-provider on worker nodes systemd file /etc/systemd/system/k0sworker.service + // in addition on the first node: /etc/systemd/system/k0scontroller.service the flag --enable-cloud-provider + + err := b.fw.WriteFile("configure-k0s.sh", []byte(script), 0755) + if err != nil { + return fmt.Errorf("failed to write configure-k0s.sh: %w", err) + } + err = b.Env.ControlPlaneNodes[0].CopyFile("configure-k0s.sh", "/root/configure-k0s.sh") + if err != nil { + return fmt.Errorf("failed to copy configure-k0s.sh to control plane node: %w", err) + } + err = b.Env.ControlPlaneNodes[0].RunSSHCommand("root", "chmod +x /root/configure-k0s.sh", b.sshQuiet) + if err != nil { + return fmt.Errorf("failed to make configure-k0s.sh executable on control plane node: %w", err) + } + return nil +} + +// Helper functions +func protoInt32(i int32) *int32 { return &i } +func protoInt64(i int64) *int64 { return &i } +func isAlreadyExistsError(err error) bool { + return status.Code(err) == codes.AlreadyExists || strings.Contains(err.Error(), "already exists") +} + +// readSSHKey reads an SSH key file, expanding ~ in the path +func (b *GCPBootstrapper) readSSHKey(path string) (string, error) { + realPath := util.ExpandPath(path) + data, err := b.fw.ReadFile(realPath) + if err != nil { + return "", fmt.Errorf("error reading SSH key from %s: %w", realPath, err) + } + key := strings.TrimSpace(string(data)) + if key == "" { + return "", fmt.Errorf("SSH key at %s is empty", realPath) + } + return key, nil +} diff --git a/internal/bootstrap/gcp/gcp_client.go b/internal/bootstrap/gcp/gcp_client.go new file mode 100644 index 00000000..21ee7024 --- /dev/null +++ b/internal/bootstrap/gcp/gcp_client.go @@ -0,0 +1,647 @@ +// Copyright (c) Codesphere Inc. +// SPDX-License-Identifier: Apache-2.0 + +package gcp + +import ( + "context" + "fmt" + "strings" + "sync" + + "slices" + + artifact "cloud.google.com/go/artifactregistry/apiv1" + artifactpb "cloud.google.com/go/artifactregistry/apiv1/artifactregistrypb" + compute "cloud.google.com/go/compute/apiv1" + "cloud.google.com/go/compute/apiv1/computepb" + "cloud.google.com/go/iam/apiv1/iampb" + resourcemanager "cloud.google.com/go/resourcemanager/apiv3" + "cloud.google.com/go/resourcemanager/apiv3/resourcemanagerpb" + serviceusage "cloud.google.com/go/serviceusage/apiv1" + "cloud.google.com/go/serviceusage/apiv1/serviceusagepb" + "github.com/codesphere-cloud/oms/internal/bootstrap" + "github.com/codesphere-cloud/oms/internal/util" + "github.com/lithammer/shortuuid" + "google.golang.org/api/cloudbilling/v1" + "google.golang.org/api/dns/v1" + "google.golang.org/api/iam/v1" + "google.golang.org/api/iterator" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// Interface for high-level GCP operations +type GCPClientManager interface { + GetProjectByName(folderID string, displayName string) (*resourcemanagerpb.Project, error) + CreateProjectID(projectName string) string + CreateProject(parent, projectName, displayName string) (string, error) + GetBillingInfo(projectID string) (*cloudbilling.ProjectBillingInfo, error) + EnableBilling(projectID, billingAccount string) error + EnableAPIs(projectID string, apis []string) error + GetArtifactRegistry(projectID, region, repoName string) (*artifactpb.Repository, error) + CreateArtifactRegistry(projectID, region, repoName string) (*artifactpb.Repository, error) + CreateServiceAccount(projectID, name, displayName string) (string, bool, error) + CreateServiceAccountKey(projectID, saEmail string) (string, error) + AssignIAMRole(projectID, saEmail, role string) error + CreateVPC(projectID, region, networkName, subnetName, routerName, natName string) error + CreateFirewallRule(projectID string, rule *computepb.Firewall) error + CreateInstance(projectID, zone string, instance *computepb.Instance) error + GetInstance(projectID, zone, instanceName string) (*computepb.Instance, error) + CreateAddress(projectID, region string, address *computepb.Address) (string, error) + GetAddress(projectID, region, addressName string) (*computepb.Address, error) + EnsureDNSManagedZone(projectID, zoneName, dnsName, description string) error + EnsureDNSRecordSets(projectID, zoneName string, records []*dns.ResourceRecordSet) error +} + +// Concrete implementation +type GCPClient struct { + ctx context.Context + st *bootstrap.StepLogger + CredentialsFile string +} + +func NewGCPClient(ctx context.Context, st *bootstrap.StepLogger, credentialsFile string) *GCPClient { + return &GCPClient{ + ctx: ctx, + st: st, + CredentialsFile: credentialsFile, + } +} + +// GetProjectByName retrieves a GCP project by its display name within the specified folder. +func (c *GCPClient) GetProjectByName(folderID string, displayName string) (*resourcemanagerpb.Project, error) { + client, err := resourcemanager.NewProjectsClient(c.ctx) + if err != nil { + return nil, err + } + defer util.IgnoreError(client.Close) + + req := &resourcemanagerpb.ListProjectsRequest{ + Parent: fmt.Sprintf("folders/%s", folderID), + ShowDeleted: false, + } + + it := client.ListProjects(c.ctx, req) + + for { + project, err := it.Next() + if err == iterator.Done { + // No more results found + return nil, fmt.Errorf("project not found: %s", displayName) + } + if err != nil { + return nil, fmt.Errorf("error iterating projects: %w", err) + } + + // Because the filter is a prefix search on the display name, + // we should perform an exact match check here to be sure. + if project.GetDisplayName() == displayName { + return project, nil + } + } +} + +// CreateProjectID generates a unique project ID based on the given project name. +func (c *GCPClient) CreateProjectID(projectName string) string { + projectGuid := strings.ToLower(shortuuid.New()[:8]) + return projectName + "-" + projectGuid +} + +// CreateProject creates a new GCP project under the specified parent (folder or organization). +// It returns the project ID of the newly created project. +func (c *GCPClient) CreateProject(parent, projectID, displayName string) (string, error) { + client, err := resourcemanager.NewProjectsClient(c.ctx) + if err != nil { + return "", err + } + defer util.IgnoreError(client.Close) + + project := &resourcemanagerpb.Project{ + ProjectId: projectID, + DisplayName: displayName, + Parent: parent, + } + op, err := client.CreateProject(c.ctx, &resourcemanagerpb.CreateProjectRequest{Project: project}) + if err != nil { + return "", err + } + resp, err := op.Wait(c.ctx) + if err != nil { + return "", err + } + + return resp.ProjectId, nil +} + +func getProjectResourceName(projectID string) string { + return fmt.Sprintf("projects/%s", projectID) +} + +// GetBillingInfo retrieves the billing information for the given project. +func (c *GCPClient) GetBillingInfo(projectID string) (*cloudbilling.ProjectBillingInfo, error) { + billingService, err := cloudbilling.NewService(context.Background()) + if err != nil { + return nil, err + } + + projectName := getProjectResourceName(projectID) + billingInfo, err := billingService.Projects.GetBillingInfo(projectName).Do() + if err != nil { + return nil, err + } + return billingInfo, nil +} + +// EnableBilling enables billing for the given project using the specified billing account. +func (c *GCPClient) EnableBilling(projectID, billingAccount string) error { + billingService, err := cloudbilling.NewService(c.ctx) + if err != nil { + return err + } + + projectName := getProjectResourceName(projectID) + billingInfo := &cloudbilling.ProjectBillingInfo{ + BillingAccountName: fmt.Sprintf("billingAccounts/%s", billingAccount), + } + _, err = billingService.Projects.UpdateBillingInfo(projectName, billingInfo).Context(c.ctx).Do() + return err +} + +// EnableAPIs enables the specified APIs for the given project. +func (c *GCPClient) EnableAPIs(projectID string, apis []string) error { + client, err := serviceusage.NewClient(c.ctx) + if err != nil { + return err + } + defer util.IgnoreError(client.Close) + // enable APIs in parallel + wg := sync.WaitGroup{} + errCh := make(chan error, len(apis)) + for _, api := range apis { + serviceName := fmt.Sprintf("projects/%s/services/%s", projectID, api) + wg.Add(1) + + go func(serviceName, api string) { + defer wg.Done() + c.st.Logf("Enabling API %s", api) + + op, err := client.EnableService(c.ctx, &serviceusagepb.EnableServiceRequest{Name: serviceName}) + if status.Code(err) == codes.AlreadyExists { + c.st.Logf("API %s already enabled", api) + return + } + if err != nil { + errCh <- fmt.Errorf("failed to enable API %s: %w", api, err) + } + if _, err := op.Wait(c.ctx); err != nil { + errCh <- fmt.Errorf("failed to enable API %s: %w", api, err) + } + + c.st.Logf("API %s enabled", api) + }(serviceName, api) + } + + wg.Wait() + close(errCh) + errStr := "" + for err := range errCh { + errStr += err.Error() + "; " + } + if len(errStr) > 0 { + return fmt.Errorf("errors occurred while enabling APIs: %s", errStr) + } + return nil +} + +// GetArtifactRegistry retrieves an Artifact Registry repository by its name. +func (c *GCPClient) CreateArtifactRegistry(projectID, region, repoName string) (*artifactpb.Repository, error) { + client, err := artifact.NewClient(c.ctx) + if err != nil { + return nil, err + } + defer util.IgnoreError(client.Close) + + parent := fmt.Sprintf("projects/%s/locations/%s", projectID, region) + repoReq := &artifactpb.CreateRepositoryRequest{ + Parent: parent, + RepositoryId: repoName, + Repository: &artifactpb.Repository{ + Format: artifactpb.Repository_DOCKER, + Description: "Codesphere managed registry", + }, + } + op, err := client.CreateRepository(c.ctx, repoReq) + if err != nil && !strings.Contains(err.Error(), "already exists") { + return nil, err + } + var repo *artifactpb.Repository + if err == nil { + repo, err = op.Wait(c.ctx) + if err != nil { + return nil, err + } + } + + // get repo again to ensure all infos are stored, else e.g. uri would be missing + repo, err = c.GetArtifactRegistry(projectID, region, repoName) + if err != nil { + return nil, fmt.Errorf("failed to get newly created artifact registry: %w", err) + } + + return repo, nil +} + +// GetArtifactRegistry retrieves an existing Artifact Registry repository by its name. +func (c *GCPClient) GetArtifactRegistry(projectID, region, repoName string) (*artifactpb.Repository, error) { + client, err := artifact.NewClient(c.ctx) + if err != nil { + return nil, err + } + defer util.IgnoreError(client.Close) + + fullRepoName := fmt.Sprintf("projects/%s/locations/%s/repositories/%s", projectID, region, repoName) + repo, err := client.GetRepository(c.ctx, &artifactpb.GetRepositoryRequest{ + Name: fullRepoName, + }) + if err != nil { + return nil, fmt.Errorf("failed to get artifact registry repository: %w", err) + } + + return repo, nil +} + +// CreateServiceAccount creates a new service account with the given name and display name. +// It returns the email of the created service account, a boolean indicating whether the account was newly created, +// and an error if any occurred during the process. +func (c *GCPClient) CreateServiceAccount(projectID, name, displayName string) (string, bool, error) { + saMail := fmt.Sprintf("%s@%s.iam.gserviceaccount.com", name, projectID) + iamService, err := iam.NewService(c.ctx) + if err != nil { + return saMail, false, err + } + + saReq := &iam.CreateServiceAccountRequest{ + AccountId: name, + ServiceAccount: &iam.ServiceAccount{ + DisplayName: displayName, + }, + } + _, err = iamService.Projects.ServiceAccounts.Create(fmt.Sprintf("projects/%s", projectID), saReq).Context(c.ctx).Do() + if err != nil && !strings.Contains(err.Error(), "already exists") { + return saMail, false, err + } + if err != nil && strings.Contains(err.Error(), "already exists") { + return saMail, false, nil + } + + return saMail, true, nil +} + +// CreateServiceAccountKey creates a new key for the specified service account. +// It returns the private key data in PEM format and an error if any occurred during the process. +func (c *GCPClient) CreateServiceAccountKey(projectID, saEmail string) (string, error) { + iamService, err := iam.NewService(c.ctx) + if err != nil { + return "", err + } + + keyReq := &iam.CreateServiceAccountKeyRequest{} + saName := fmt.Sprintf("projects/%s/serviceAccounts/%s", projectID, saEmail) + key, err := iamService.Projects.ServiceAccounts.Keys.Create(saName, keyReq).Context(c.ctx).Do() + if err != nil { + return "", err + } + + return string(key.PrivateKeyData), nil +} + +// AssignIAMRole assigns the specified IAM role to the given service account in the project. +func (c *GCPClient) AssignIAMRole(projectID, saName, role string) error { + saEmail := fmt.Sprintf("%s@%s.iam.gserviceaccount.com", saName, projectID) + client, err := resourcemanager.NewProjectsClient(c.ctx) + if err != nil { + return err + } + defer util.IgnoreError(client.Close) + getReq := &iampb.GetIamPolicyRequest{ + Resource: fmt.Sprintf("projects/%s", projectID), + } + + policy, err := client.GetIamPolicy(c.ctx, getReq) + if err != nil { + return err + } + + // Check if already assigned + member := fmt.Sprintf("serviceAccount:%s", saEmail) + for _, binding := range policy.Bindings { + if binding.Role == role { + if slices.Contains(binding.Members, member) { + return nil + } + } + } + + policy.Bindings = append(policy.Bindings, &iampb.Binding{ + Role: role, + Members: []string{member}, + }) + setReq := &iampb.SetIamPolicyRequest{ + Resource: fmt.Sprintf("projects/%s", projectID), + Policy: policy, + } + _, err = client.SetIamPolicy(c.ctx, setReq) + return err +} + +// CreateVPC creates a VPC network with the specified subnet, router, and NAT gateway. +func (c *GCPClient) CreateVPC(projectID, region, networkName, subnetName, routerName, natName string) error { + // Create Network + networksClient, err := compute.NewNetworksRESTClient(c.ctx) + if err != nil { + return err + } + defer util.IgnoreError(networksClient.Close) + + network := &computepb.Network{ + Name: &networkName, + AutoCreateSubnetworks: protoBool(false), + } + op, err := networksClient.Insert(c.ctx, &computepb.InsertNetworkRequest{ + Project: projectID, + NetworkResource: network, + }) + if err != nil && !strings.Contains(err.Error(), "already exists") { + return err + } + if err == nil { + if err := op.Wait(c.ctx); err != nil { + return err + } + } + + c.st.Logf("Network %s ensured", networkName) + + // Create Subnet + subnetsClient, err := compute.NewSubnetworksRESTClient(c.ctx) + if err != nil { + return err + } + defer util.IgnoreError(subnetsClient.Close) + + subnet := &computepb.Subnetwork{ + Name: &subnetName, + IpCidrRange: protoString("10.10.0.0/20"), + Region: ®ion, + Network: protoString(fmt.Sprintf("projects/%s/global/networks/%s", projectID, networkName)), + } + op, err = subnetsClient.Insert(c.ctx, &computepb.InsertSubnetworkRequest{ + Project: projectID, + Region: region, + SubnetworkResource: subnet, + }) + if err != nil && !strings.Contains(err.Error(), "already exists") { + return err + } + if err == nil { + if err := op.Wait(c.ctx); err != nil { + return err + } + } + + c.st.Logf("Subnetwork %s ensured", subnetName) + + // Create Router + routersClient, err := compute.NewRoutersRESTClient(c.ctx) + if err != nil { + return fmt.Errorf("failed to create routers client: %w", err) + } + defer util.IgnoreError(routersClient.Close) + + router := &computepb.Router{ + Name: &routerName, + Region: ®ion, + Network: protoString(fmt.Sprintf("projects/%s/global/networks/%s", projectID, networkName)), + } + op, err = routersClient.Insert(c.ctx, &computepb.InsertRouterRequest{ + Project: projectID, + Region: region, + RouterResource: router, + }) + if err != nil && !isAlreadyExistsError(err) { + return fmt.Errorf("failed to create router: %w", err) + } + if err == nil { + if err := op.Wait(c.ctx); err != nil { + return fmt.Errorf("failed to wait for router creation: %w", err) + } + } + + c.st.Logf("Router %s ensured", routerName) + + // Create NAT Gateway + natsClient, err := compute.NewRoutersRESTClient(c.ctx) + if err != nil { + return fmt.Errorf("failed to create routers client for NAT: %w", err) + } + defer util.IgnoreError(natsClient.Close) + + nat := &computepb.RouterNat{ + Name: &natName, + SourceSubnetworkIpRangesToNat: protoString("ALL_SUBNETWORKS_ALL_IP_RANGES"), + NatIpAllocateOption: protoString("AUTO_ONLY"), + LogConfig: &computepb.RouterNatLogConfig{ + Enable: protoBool(false), + Filter: protoString("ERRORS_ONLY"), + }, + } + // Patch NAT config to router + _, err = routersClient.Patch(c.ctx, &computepb.PatchRouterRequest{ + Project: projectID, + Region: region, + Router: routerName, + RouterResource: &computepb.Router{ + Name: &routerName, + Nats: []*computepb.RouterNat{nat}, + }, + }) + if err != nil && !isAlreadyExistsError(err) { + return fmt.Errorf("failed to create NAT gateway: %w", err) + } + + c.st.Logf("NAT gateway %s ensured", natName) + + return nil +} + +// CreateFirewallRule creates a firewall rule in the specified project. +func (c *GCPClient) CreateFirewallRule(projectID string, rule *computepb.Firewall) error { + firewallsClient, err := compute.NewFirewallsRESTClient(c.ctx) + if err != nil { + return err + } + defer util.IgnoreError(firewallsClient.Close) + + _, err = firewallsClient.Insert(c.ctx, &computepb.InsertFirewallRequest{ + Project: projectID, + FirewallResource: rule, + }) + if err != nil && !strings.Contains(err.Error(), "already exists") { + return err + } + + return nil +} + +// CreateInstance creates a new Compute Engine instance in the specified project and zone. +func (c *GCPClient) CreateInstance(projectID, zone string, instance *computepb.Instance) error { + client, err := compute.NewInstancesRESTClient(c.ctx) + if err != nil { + return err + } + defer util.IgnoreError(client.Close) + + op, err := client.Insert(c.ctx, &computepb.InsertInstanceRequest{ + Project: projectID, + Zone: zone, + InstanceResource: instance, + }) + if err != nil { + return err + } + + return op.Wait(c.ctx) +} + +// GetInstance retrieves a Compute Engine instance by its name in the specified project and zone. +func (c *GCPClient) GetInstance(projectID, zone, instanceName string) (*computepb.Instance, error) { + client, err := compute.NewInstancesRESTClient(c.ctx) + if err != nil { + return nil, err + } + defer util.IgnoreError(client.Close) + + return client.Get(c.ctx, &computepb.GetInstanceRequest{ + Project: projectID, + Zone: zone, + Instance: instanceName, + }) +} + +// CreateAddress creates a new static IP address in the specified project and region. +func (c *GCPClient) CreateAddress(projectID, region string, address *computepb.Address) (string, error) { + client, err := compute.NewAddressesRESTClient(c.ctx) + if err != nil { + return "", err + } + defer util.IgnoreError(client.Close) + + op, err := client.Insert(c.ctx, &computepb.InsertAddressRequest{ + Project: projectID, + Region: region, + AddressResource: address, + }) + if err != nil { + return "", err + } + if err = op.Wait(c.ctx); err != nil { + return "", err + } + + // Fetch the created address to get the IP + createdAddress, err := client.Get(c.ctx, &computepb.GetAddressRequest{ + Project: projectID, + Region: region, + Address: *address.Name, + }) + if err != nil { + return "", err + } + + return *createdAddress.Address, nil +} + +// GetAddress retrieves a static IP address by its name in the specified project and region. +func (c *GCPClient) GetAddress(projectID, region, addressName string) (*computepb.Address, error) { + client, err := compute.NewAddressesRESTClient(c.ctx) + if err != nil { + return nil, err + } + defer util.IgnoreError(client.Close) + + return client.Get(c.ctx, &computepb.GetAddressRequest{ + Project: projectID, + Region: region, + Address: addressName, + }) +} + +// EnsureDNSManagedZone ensures that a DNS managed zone exists in the specified project. +func (c *GCPClient) EnsureDNSManagedZone(projectID, zoneName, dnsName, description string) error { + service, err := dns.NewService(c.ctx) + if err != nil { + return fmt.Errorf("failed to create DNS service: %w", err) + } + + // Check if zone exists + _, err = service.ManagedZones.Get(projectID, zoneName).Context(c.ctx).Do() + if err == nil { + // Zone exists + return nil + } + + // Create zone + zone := &dns.ManagedZone{ + Name: zoneName, + DnsName: dnsName, + Description: description, + } + _, err = service.ManagedZones.Create(projectID, zone).Context(c.ctx).Do() + if err != nil { + return fmt.Errorf("failed to create DNS zone: %w", err) + } + + return nil +} + +// EnsureDNSRecordSets ensures that the specified DNS record sets exist in the given managed zone. +func (c *GCPClient) EnsureDNSRecordSets(projectID, zoneName string, records []*dns.ResourceRecordSet) error { + service, err := dns.NewService(c.ctx) + if err != nil { + return fmt.Errorf("failed to create DNS service: %w", err) + } + + deletions := []*dns.ResourceRecordSet{} + // Clean up existing records + for _, record := range records { + existingRecord, err := service.ResourceRecordSets.Get(projectID, zoneName, record.Name, record.Type).Context(c.ctx).Do() + if err == nil && existingRecord != nil { + deletions = append(deletions, existingRecord) + } + } + + if len(deletions) > 0 { + delChange := &dns.Change{ + Deletions: deletions, + } + _, err = service.Changes.Create(projectID, zoneName, delChange).Context(c.ctx).Do() + if err != nil { + return fmt.Errorf("failed to delete existing DNS records: %w", err) + } + } + + change := &dns.Change{ + Additions: records, + } + _, err = service.Changes.Create(projectID, zoneName, change).Context(c.ctx).Do() + if err != nil { + return fmt.Errorf("failed to create DNS records: %w", err) + } + + return nil +} + +// Helper functions +func protoString(s string) *string { return &s } +func protoBool(b bool) *bool { return &b } diff --git a/internal/bootstrap/gcp/gcp_test.go b/internal/bootstrap/gcp/gcp_test.go new file mode 100644 index 00000000..64a8bedb --- /dev/null +++ b/internal/bootstrap/gcp/gcp_test.go @@ -0,0 +1,2559 @@ +// Copyright (c) Codesphere Inc. +// SPDX-License-Identifier: Apache-2.0 + +package gcp_test + +import ( + "context" + "fmt" + "strings" + "time" + + "os" + + "cloud.google.com/go/artifactregistry/apiv1/artifactregistrypb" + "cloud.google.com/go/compute/apiv1/computepb" + "cloud.google.com/go/resourcemanager/apiv3/resourcemanagerpb" + "github.com/codesphere-cloud/oms/internal/bootstrap" + "github.com/codesphere-cloud/oms/internal/bootstrap/gcp" + "github.com/codesphere-cloud/oms/internal/env" + "github.com/codesphere-cloud/oms/internal/installer" + "github.com/codesphere-cloud/oms/internal/installer/files" + "github.com/codesphere-cloud/oms/internal/installer/node" + "github.com/codesphere-cloud/oms/internal/util" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/stretchr/testify/mock" + "google.golang.org/api/cloudbilling/v1" + "google.golang.org/api/dns/v1" +) + +var _ = Describe("NewGCPBootstrapper", func() { + It("creates a valid GCPBootstrapper", func() { + env := env.NewEnv() + Expect(env).NotTo(BeNil()) + + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{} + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + Expect(bs).NotTo(BeNil()) + }) +}) + +var _ = Describe("Bootstrap", func() { + var ( + e env.Env + ctx context.Context + csEnv *gcp.CodesphereEnvironment + icg *installer.MockInstallConfigManager + gc *gcp.MockGCPClientManager + fw *util.MockFileIO + nm *node.MockNodeManager + bs *gcp.GCPBootstrapper + ) + + BeforeEach(func() { + e = env.NewEnv() + ctx = context.Background() + csEnv = &gcp.CodesphereEnvironment{ + InstallConfigPath: "fake-config-file", + SecretsFilePath: "fake-secret", + ProjectName: "test-project", + BillingAccount: "test-billing-account", + Region: "us-central1", + Zone: "us-central1-a", + BaseDomain: "example.com", + DNSProjectID: "dns-project", + DNSZoneName: "test-zone", + } + stlog := bootstrap.NewStepLogger(false) + + icg = installer.NewMockInstallConfigManager(GinkgoT()) + gc = gcp.NewMockGCPClientManager(GinkgoT()) + fw = util.NewMockFileIO(GinkgoT()) + nm = node.NewMockNodeManager(GinkgoT()) + + var err error + bs, err = gcp.NewGCPBootstrapper(ctx, e, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + }) + + It("runs bootstrap successfully", func() { + bs.Env.RegistryType = gcp.RegistryTypeArtifactRegistry + bs.Env.WriteConfig = true + bs.Env.SecretsDir = "/secrets" + + // 1. EnsureInstallConfig + fw.EXPECT().Exists("fake-config-file").Return(false) + icg.EXPECT().ApplyProfile("dev").Return(nil) + // Returning a real install config to avoid nil pointer dereferences later + icg.EXPECT().GetInstallConfig().RunAndReturn(func() *files.RootConfig { + realIcm := installer.NewInstallConfigManager() + realIcm.ApplyProfile("dev") + return realIcm.GetInstallConfig() + }) + + // 2. EnsureSecrets + fw.EXPECT().Exists("fake-secret").Return(false) + icg.EXPECT().GetVault().Return(&files.InstallVault{}) + + // 3. EnsureProject + gc.EXPECT().GetProjectByName(mock.Anything, "test-project").Return(nil, fmt.Errorf("project not found: test-project")) + gc.EXPECT().CreateProjectID("test-project").Return("test-project-id") + gc.EXPECT().CreateProject(mock.Anything, mock.Anything, "test-project").Return(mock.Anything, nil) + + // 4. EnsureBilling + gc.EXPECT().GetBillingInfo("test-project-id").Return(&cloudbilling.ProjectBillingInfo{BillingEnabled: false}, nil) + gc.EXPECT().EnableBilling("test-project-id", "test-billing-account").Return(nil) + + // 5. EnsureAPIsEnabled + gc.EXPECT().EnableAPIs("test-project-id", mock.Anything).Return(nil) + + // 6. EnsureArtifactRegistry + gc.EXPECT().GetArtifactRegistry("test-project-id", "us-central1", "codesphere-registry").Return(nil, fmt.Errorf("not found")) + gc.EXPECT().CreateArtifactRegistry("test-project-id", "us-central1", "codesphere-registry").Return(&artifactregistrypb.Repository{Name: "codesphere-registry"}, nil) + + // 7. EnsureServiceAccounts + gc.EXPECT().CreateServiceAccount("test-project-id", "cloud-controller", "cloud-controller").Return("cloud-controller@p.iam.gserviceaccount.com", false, nil) + gc.EXPECT().CreateServiceAccount("test-project-id", "artifact-registry-writer", "artifact-registry-writer").Return("writer@p.iam.gserviceaccount.com", true, nil) + gc.EXPECT().CreateServiceAccountKey("test-project-id", "writer@p.iam.gserviceaccount.com").Return("fake-key", nil) + + // 8. EnsureIAMRoles + gc.EXPECT().AssignIAMRole("test-project-id", "artifact-registry-writer", "roles/artifactregistry.writer").Return(nil) + gc.EXPECT().AssignIAMRole("test-project-id", "cloud-controller", "roles/compute.admin").Return(nil) + + // 9. EnsureVPC + gc.EXPECT().CreateVPC("test-project-id", "us-central1", "test-project-id-vpc", "test-project-id-us-central1-subnet", "test-project-id-router", "test-project-id-nat-gateway").Return(nil) + + // 10. EnsureFirewallRules (5 times) + gc.EXPECT().CreateFirewallRule("test-project-id", mock.Anything).Return(nil).Times(5) + + // 11. EnsureComputeInstances + gc.EXPECT().CreateInstance("test-project-id", "us-central1-a", mock.Anything).Return(nil).Times(9) + // GetInstance calls to retrieve IPs + ipResp := &computepb.Instance{ + NetworkInterfaces: []*computepb.NetworkInterface{ + { + NetworkIP: protoString("10.0.0.1"), + AccessConfigs: []*computepb.AccessConfig{ + {NatIP: protoString("1.2.3.4")}, + }, + }, + }, + } + gc.EXPECT().GetInstance("test-project-id", "us-central1-a", mock.Anything).Return(ipResp, nil).Times(9) + fw.EXPECT().ReadFile(mock.Anything).Return([]byte("fake-key"), nil).Times(9) + // UpdateNode is called once for the jumpbox to set its name and IPs + nm.EXPECT().UpdateNode("jumpbox", "1.2.3.4", "10.0.0.1") + // CreateSubNode is called 8 times for the other nodes + nm.EXPECT().CreateSubNode("postgres", "1.2.3.4", "10.0.0.1").Return(nm) + nm.EXPECT().CreateSubNode("ceph-1", "1.2.3.4", "10.0.0.1").Return(nm) + nm.EXPECT().CreateSubNode("ceph-2", "1.2.3.4", "10.0.0.1").Return(nm) + nm.EXPECT().CreateSubNode("ceph-3", "1.2.3.4", "10.0.0.1").Return(nm) + nm.EXPECT().CreateSubNode("ceph-4", "1.2.3.4", "10.0.0.1").Return(nm) + nm.EXPECT().CreateSubNode("k0s-1", "1.2.3.4", "10.0.0.1").Return(nm) + nm.EXPECT().CreateSubNode("k0s-2", "1.2.3.4", "10.0.0.1").Return(nm) + nm.EXPECT().CreateSubNode("k0s-3", "1.2.3.4", "10.0.0.1").Return(nm) + + nm.EXPECT().GetName().Return("mocknode").Maybe() + nm.EXPECT().GetInternalIP().Return("10.0.0.1").Maybe() + nm.EXPECT().GetExternalIP().Return("1.2.3.4").Maybe() + + // 12. EnsureGatewayIPAddresses + gc.EXPECT().GetAddress("test-project-id", "us-central1", "gateway").Return(nil, fmt.Errorf("not found")) + gc.EXPECT().CreateAddress("test-project-id", "us-central1", mock.MatchedBy(func(addr *computepb.Address) bool { return *addr.Name == "gateway" })).Return("1.1.1.1", nil) + gc.EXPECT().GetAddress("test-project-id", "us-central1", "gateway").Return(nil, fmt.Errorf("not found")) + gc.EXPECT().GetAddress("test-project-id", "us-central1", "public-gateway").Return(nil, fmt.Errorf("not found")) + gc.EXPECT().CreateAddress("test-project-id", "us-central1", mock.MatchedBy(func(addr *computepb.Address) bool { return *addr.Name == "public-gateway" })).Return("2.2.2.2", nil) + gc.EXPECT().GetAddress("test-project-id", "us-central1", "public-gateway").Return(&computepb.Address{Address: protoString("2.2.2.2")}, nil) + + // 13. EnsureRootLoginEnabled + nm.EXPECT().WaitForSSH(30 * time.Second).Return(nil).Times(9) + nm.EXPECT().HasRootLoginEnabled().Return(false).Times(9) + nm.EXPECT().EnableRootLogin().Return(nil).Times(9) + + // 14. EnsureJumpboxConfigured + nm.EXPECT().HasAcceptEnvConfigured().Return(false) + nm.EXPECT().ConfigureAcceptEnv().Return(nil) + nm.EXPECT().HasCommand("oms-cli").Return(false) + nm.EXPECT().InstallOms().Return(nil) + + // 15. EnsureInotifyWatches + nm.EXPECT().HasInotifyWatchesConfigured().Return(false) + nm.EXPECT().ConfigureInotifyWatches().Return(nil) + nm.EXPECT().HasMemoryMapConfigured().Return(false) + nm.EXPECT().ConfigureMemoryMap().Return(nil) + + // 16. UpdateInstallConfig + icg.EXPECT().GenerateSecrets().Return(nil) + icg.EXPECT().WriteInstallConfig("fake-config-file", true).Return(nil) + icg.EXPECT().WriteVault("fake-secret", true).Return(nil) + nm.EXPECT().CopyFile("fake-config-file", "/etc/codesphere/config.yaml").Return(nil) + nm.EXPECT().CopyFile("fake-secret", "/secrets/prod.vault.yaml").Return(nil) + + // 17. EnsureAgeKey + nm.EXPECT().HasFile("/secrets/age_key.txt").Return(false) + nm.EXPECT().RunSSHCommand("root", "mkdir -p /secrets; age-keygen -o /secrets/age_key.txt", true).Return(nil) + + // 18. EncryptVault + nm.EXPECT().RunSSHCommand("root", "cp /secrets/prod.vault.yaml{,.bak}", true).Return(nil) + nm.EXPECT().RunSSHCommand("root", mock.MatchedBy(func(cmd string) bool { + return strings.Contains(cmd, "sops --encrypt") + }), true).Return(nil) + + // 19. EnsureDNSRecords + gc.EXPECT().EnsureDNSManagedZone("dns-project", "test-zone", "example.com.", mock.Anything).Return(nil) + gc.EXPECT().EnsureDNSRecordSets("dns-project", "test-zone", mock.MatchedBy(func(records []*dns.ResourceRecordSet) bool { + return len(records) == 4 + })).Return(nil) + + // 20. GenerateK0sConfigScript + fw.EXPECT().WriteFile("configure-k0s.sh", mock.Anything, os.FileMode(0755)).Return(nil) + nm.EXPECT().CopyFile("configure-k0s.sh", "/root/configure-k0s.sh").Return(nil) + nm.EXPECT().RunSSHCommand("root", "chmod +x /root/configure-k0s.sh", true).Return(nil) + + err := bs.Bootstrap() + Expect(err).NotTo(HaveOccurred()) + Expect(bs.Env).NotTo(BeNil()) + Expect(bs.Env.ProjectID).To(HavePrefix("test-project-")) + + // Verify nodes are properly set in the environment + Expect(bs.Env.Jumpbox).NotTo(BeNil(), "Jumpbox should be created") + Expect(bs.Env.PostgreSQLNode).NotTo(BeNil(), "PostgreSQL node should be created") + Expect(bs.Env.CephNodes).To(HaveLen(4), "Should have 4 Ceph nodes") + Expect(bs.Env.ControlPlaneNodes).To(HaveLen(3), "Should have 3 K0s control plane nodes") + + // Verify mock returns expected values + Expect(bs.Env.Jumpbox.GetName()).To(Equal("mocknode")) + Expect(bs.Env.Jumpbox.GetExternalIP()).To(Equal("1.2.3.4")) + Expect(bs.Env.Jumpbox.GetInternalIP()).To(Equal("10.0.0.1")) + + Expect(bs.Env.PostgreSQLNode.GetName()).To(Equal("mocknode")) + Expect(bs.Env.PostgreSQLNode.GetExternalIP()).To(Equal("1.2.3.4")) + Expect(bs.Env.PostgreSQLNode.GetInternalIP()).To(Equal("10.0.0.1")) + + for _, cephNode := range bs.Env.CephNodes { + Expect(cephNode.GetName()).To(Equal("mocknode")) + Expect(cephNode.GetExternalIP()).To(Equal("1.2.3.4")) + Expect(cephNode.GetInternalIP()).To(Equal("10.0.0.1")) + } + + for _, cpNode := range bs.Env.ControlPlaneNodes { + Expect(cpNode.GetName()).To(Equal("mocknode")) + Expect(cpNode.GetExternalIP()).To(Equal("1.2.3.4")) + Expect(cpNode.GetInternalIP()).To(Equal("10.0.0.1")) + } + }) +}) + +func protoString(s string) *string { return &s } + +var _ = Describe("EnsureInstallConfig", func() { + Describe("Valid EnsureInstallConfig", func() { + It("uses existing when config file exists", func() { + env := env.NewEnv() + Expect(env).NotTo(BeNil()) + + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + InstallConfigPath: "existing-config-file", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + fw.EXPECT().Exists("existing-config-file").Return(true) + icg.EXPECT().LoadInstallConfigFromFile("existing-config-file").Return(nil) + icg.EXPECT().GetInstallConfig().Return(&files.RootConfig{}) + + err = bs.EnsureInstallConfig() + Expect(err).NotTo(HaveOccurred()) + }) + + It("creates install config when missing", func() { + env := env.NewEnv() + Expect(env).NotTo(BeNil()) + + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + InstallConfigPath: "nonexistent-config-file", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + fw.EXPECT().Exists("nonexistent-config-file").Return(false) + icg.EXPECT().ApplyProfile("dev").Return(nil) + icg.EXPECT().GetInstallConfig().Return(&files.RootConfig{}) + + err = bs.EnsureInstallConfig() + Expect(err).NotTo(HaveOccurred()) + Expect(bs.Env.InstallConfigPath).To(Equal("nonexistent-config-file")) + Expect(bs.Env.InstallConfig).NotTo(BeNil()) + }) + }) + + Describe("Invalid cases", func() { + It("returns error when config file exists but fails to load", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + InstallConfigPath: "existing-bad-config", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + fw.EXPECT().Exists("existing-bad-config").Return(true) + icg.EXPECT().LoadInstallConfigFromFile("existing-bad-config").Return(fmt.Errorf("bad format")) + + err = bs.EnsureInstallConfig() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to load config file")) + Expect(err.Error()).To(ContainSubstring("bad format")) + }) + + It("returns error when config file missing and applying profile fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + InstallConfigPath: "missing-config", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + fw.EXPECT().Exists("missing-config").Return(false) + icg.EXPECT().ApplyProfile("dev").Return(fmt.Errorf("profile error")) + + err = bs.EnsureInstallConfig() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to apply profile")) + Expect(err.Error()).To(ContainSubstring("profile error")) + }) + }) +}) + +var _ = Describe("EnsureSecrets", func() { + Describe("Valid EnsureSecrets", func() { + It("loads existing secrets file", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + SecretsFilePath: "existing-secrets", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + fw.EXPECT().Exists("existing-secrets").Return(true) + icg.EXPECT().LoadVaultFromFile("existing-secrets").Return(nil) + icg.EXPECT().MergeVaultIntoConfig().Return(nil) + icg.EXPECT().GetVault().Return(&files.InstallVault{}) + + err = bs.EnsureSecrets() + Expect(err).NotTo(HaveOccurred()) + }) + + It("skips when secrets file missing", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + SecretsFilePath: "missing-secrets", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + fw.EXPECT().Exists("missing-secrets").Return(false) + icg.EXPECT().GetVault().Return(&files.InstallVault{}) + + err = bs.EnsureSecrets() + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Describe("Invalid cases", func() { + It("returns error when secrets file load fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + SecretsFilePath: "bad-secrets", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + fw.EXPECT().Exists("bad-secrets").Return(true) + icg.EXPECT().LoadVaultFromFile("bad-secrets").Return(fmt.Errorf("load error")) + + err = bs.EnsureSecrets() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to load vault file")) + Expect(err.Error()).To(ContainSubstring("load error")) + }) + + It("returns error when merge fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + SecretsFilePath: "merr-secrets", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + fw.EXPECT().Exists("merr-secrets").Return(true) + icg.EXPECT().LoadVaultFromFile("merr-secrets").Return(nil) + icg.EXPECT().MergeVaultIntoConfig().Return(fmt.Errorf("merge error")) + + err = bs.EnsureSecrets() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to merge vault into config")) + Expect(err.Error()).To(ContainSubstring("merge error")) + }) + }) +}) + +var _ = Describe("EnsureProject", func() { + Describe("Valid EnsureProject", func() { + It("uses existing project", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectName: "existing-proj", + FolderID: "123", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + gc.EXPECT().GetProjectByName("123", "existing-proj").Return(&resourcemanagerpb.Project{ProjectId: "existing-id", Name: "existing-proj"}, nil) + + err = bs.EnsureProject() + Expect(err).NotTo(HaveOccurred()) + Expect(bs.Env.ProjectID).To(Equal("existing-id")) + }) + + It("creates project when missing", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectName: "new-proj", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + gc.EXPECT().GetProjectByName("", "new-proj").Return(nil, fmt.Errorf("project not found: new-proj")) + gc.EXPECT().CreateProjectID("new-proj").Return("new-proj-id") + gc.EXPECT().CreateProject("", "new-proj-id", "new-proj").Return("", nil) + + err = bs.EnsureProject() + Expect(err).NotTo(HaveOccurred()) + Expect(bs.Env.ProjectID).To(Equal("new-proj-id")) + }) + }) + + Describe("Invalid cases", func() { + It("returns error when GetProjectByName fails unexpectedly", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectName: "error-proj", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + gc.EXPECT().GetProjectByName("", "error-proj").Return(nil, fmt.Errorf("api error")) + + err = bs.EnsureProject() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to get project")) + Expect(err.Error()).To(ContainSubstring("api error")) + }) + + It("returns error when CreateProject fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectName: "fail-create-proj", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + gc.EXPECT().GetProjectByName("", "fail-create-proj").Return(nil, fmt.Errorf("project not found: fail-create-proj")) + gc.EXPECT().CreateProjectID("fail-create-proj").Return("fail-create-proj-id") + gc.EXPECT().CreateProject("", "fail-create-proj-id", "fail-create-proj").Return("", fmt.Errorf("create error")) + + err = bs.EnsureProject() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to create project")) + Expect(err.Error()).To(ContainSubstring("create error")) + }) + }) +}) + +var _ = Describe("EnsureBilling", func() { + Describe("Valid EnsureBilling", func() { + It("does nothing if billing already enabled correctly", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + BillingAccount: "billing-123", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + bi := &cloudbilling.ProjectBillingInfo{ + BillingEnabled: true, + BillingAccountName: "billing-123", + } + gc.EXPECT().GetBillingInfo("pid").Return(bi, nil) + + err = bs.EnsureBilling() + Expect(err).NotTo(HaveOccurred()) + }) + + It("enables billing if not enabled", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + BillingAccount: "billing-123", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + bi := &cloudbilling.ProjectBillingInfo{ + BillingEnabled: false, + } + gc.EXPECT().GetBillingInfo("pid").Return(bi, nil) + gc.EXPECT().EnableBilling("pid", "billing-123").Return(nil) + + err = bs.EnsureBilling() + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Describe("Invalid cases", func() { + It("fails when GetBillingInfo fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + gc.EXPECT().GetBillingInfo("pid").Return(nil, fmt.Errorf("billing info error")) + + err = bs.EnsureBilling() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to get billing info")) + Expect(err.Error()).To(ContainSubstring("billing info error")) + }) + + It("fails when EnableBilling fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + BillingAccount: "acc", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + bi := &cloudbilling.ProjectBillingInfo{ + BillingEnabled: false, + } + gc.EXPECT().GetBillingInfo("pid").Return(bi, nil) + gc.EXPECT().EnableBilling("pid", "acc").Return(fmt.Errorf("enable error")) + + err = bs.EnsureBilling() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to enable billing")) + Expect(err.Error()).To(ContainSubstring("enable error")) + }) + }) +}) + +var _ = Describe("EnsureAPIsEnabled", func() { + Describe("Valid EnsureAPIsEnabled", func() { + It("enables default APIs", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + gc.EXPECT().EnableAPIs("pid", []string{ + "compute.googleapis.com", + "serviceusage.googleapis.com", + "artifactregistry.googleapis.com", + "dns.googleapis.com", + }).Return(nil) + + err = bs.EnsureAPIsEnabled() + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Describe("Invalid cases", func() { + It("fails when EnableAPIs fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + gc.EXPECT().EnableAPIs("pid", mock.Anything).Return(fmt.Errorf("api error")) + + err = bs.EnsureAPIsEnabled() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to enable APIs")) + Expect(err.Error()).To(ContainSubstring("api error")) + }) + }) +}) + +var _ = Describe("EnsureArtifactRegistry", func() { + Describe("Valid EnsureArtifactRegistry", func() { + It("uses existing registry if present", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + Region: "us-central1", + InstallConfig: &files.RootConfig{ + Registry: &files.RegistryConfig{}, + }, + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + repo := &artifactregistrypb.Repository{Name: "projects/pid/locations/us-central1/repositories/codesphere-registry"} + gc.EXPECT().GetArtifactRegistry("pid", "us-central1", "codesphere-registry").Return(repo, nil) + + err = bs.EnsureArtifactRegistry() + Expect(err).NotTo(HaveOccurred()) + }) + + It("creates registry if missing", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + Region: "us-central1", + InstallConfig: &files.RootConfig{ + Registry: &files.RegistryConfig{}, + }, + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + gc.EXPECT().GetArtifactRegistry("pid", "us-central1", "codesphere-registry").Return(nil, fmt.Errorf("not found")) + + createdRepo := &artifactregistrypb.Repository{Name: "projects/pid/locations/us-central1/repositories/codesphere-registry"} + gc.EXPECT().CreateArtifactRegistry("pid", "us-central1", "codesphere-registry").Return(createdRepo, nil) + + err = bs.EnsureArtifactRegistry() + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Describe("Invalid cases", func() { + It("fails when CreateArtifactRegistry fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + Region: "us-central1", + InstallConfig: &files.RootConfig{ + Registry: &files.RegistryConfig{}, + }, + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + gc.EXPECT().GetArtifactRegistry("pid", "us-central1", "codesphere-registry").Return(nil, fmt.Errorf("not found")) + gc.EXPECT().CreateArtifactRegistry("pid", "us-central1", "codesphere-registry").Return(nil, fmt.Errorf("create error")) + + err = bs.EnsureArtifactRegistry() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to create artifact registry")) + Expect(err.Error()).To(ContainSubstring("create error")) + }) + }) +}) + +var _ = Describe("EnsureLocalContainerRegistry", func() { + Describe("Valid EnsureLocalContainerRegistry", func() { + It("installs local registry", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + InstallConfig: &files.RootConfig{ + Registry: &files.RegistryConfig{}, + }, + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + // Setup mocked node + bs.Env.PostgreSQLNode = nm + nm.EXPECT().GetInternalIP().Return("10.0.0.1").Maybe() + + // Check if running - return error to simulate not running + nm.EXPECT().RunSSHCommand("root", mock.MatchedBy(func(cmd string) bool { + return strings.Contains(cmd, "podman ps") + }), true).Return(fmt.Errorf("not running")) + + // Install commands (8 commands in list) + nm.EXPECT().RunSSHCommand("root", mock.Anything, false).Return(nil).Times(8) + + bs.Env.ControlPlaneNodes = []node.NodeManager{nm, nm} + bs.Env.CephNodes = []node.NodeManager{nm, nm} + + nm.EXPECT().RunSSHCommand("root", mock.Anything, true).Return(nil).Times(3 * 4) + + err = bs.EnsureLocalContainerRegistry() + Expect(err).NotTo(HaveOccurred()) + Expect(bs.Env.InstallConfig.Registry.Username).To(Equal("custom-registry")) + }) + }) + + Describe("Invalid cases", func() { + var ( + e env.Env + ctx context.Context + csEnv *gcp.CodesphereEnvironment + icg *installer.MockInstallConfigManager + gc *gcp.MockGCPClientManager + fw *util.MockFileIO + nm *node.MockNodeManager + bs *gcp.GCPBootstrapper + ) + + BeforeEach(func() { + e = env.NewEnv() + ctx = context.Background() + csEnv = &gcp.CodesphereEnvironment{ + ProjectID: "pid", + InstallConfig: &files.RootConfig{ + Registry: &files.RegistryConfig{}, + }, + } + stlog := bootstrap.NewStepLogger(false) + + icg = installer.NewMockInstallConfigManager(GinkgoT()) + gc = gcp.NewMockGCPClientManager(GinkgoT()) + fw = util.NewMockFileIO(GinkgoT()) + nm = node.NewMockNodeManager(GinkgoT()) + + var err error + bs, err = gcp.NewGCPBootstrapper(ctx, e, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + bs.Env.PostgreSQLNode = nm + bs.Env.ControlPlaneNodes = []node.NodeManager{nm, nm} + bs.Env.CephNodes = []node.NodeManager{nm, nm} + + nm.EXPECT().GetInternalIP().Return("10.0.0.1").Maybe() + }) + + It("fails when the 8th install command fails", func() { + // First check - registry not running + nm.EXPECT().RunSSHCommand("root", mock.MatchedBy(func(cmd string) bool { + return strings.Contains(cmd, "podman ps") + }), true).Return(fmt.Errorf("not running")) + + // First 7 install commands succeed + nm.EXPECT().RunSSHCommand("root", mock.Anything, false).Return(nil).Times(7) + + // 8th install command fails + nm.EXPECT().RunSSHCommand("root", mock.Anything, false).Return(fmt.Errorf("ssh error")).Once() + + err := bs.EnsureLocalContainerRegistry() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("ssh error")) + }) + + It("fails when the first scp command fails", func() { + // First check - registry not running + nm.EXPECT().RunSSHCommand("root", mock.MatchedBy(func(cmd string) bool { + return strings.Contains(cmd, "podman ps") + }), true).Return(fmt.Errorf("not running")) + + // All 8 install commands succeed + nm.EXPECT().RunSSHCommand("root", mock.Anything, false).Return(nil).Times(8) + + // First scp command fails + nm.EXPECT().RunSSHCommand("root", mock.MatchedBy(func(cmd string) bool { + return strings.HasPrefix(cmd, "scp ") + }), true).Return(fmt.Errorf("scp error")).Once() + + err := bs.EnsureLocalContainerRegistry() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to copy registry certificate")) + }) + + It("fails when update-ca-certificates fails", func() { + // Override node setup for this test + node1 := node.NewMockNodeManager(GinkgoT()) + bs.Env.ControlPlaneNodes = []node.NodeManager{node1} + bs.Env.CephNodes = []node.NodeManager{} + + node1.EXPECT().GetInternalIP().Return("10.0.0.2").Maybe() + + // First check - registry not running + nm.EXPECT().RunSSHCommand("root", mock.MatchedBy(func(cmd string) bool { + return strings.Contains(cmd, "podman ps") + }), true).Return(fmt.Errorf("not running")) + + // All 8 install commands succeed + nm.EXPECT().RunSSHCommand("root", mock.Anything, false).Return(nil).Times(8) + + // scp succeeds + nm.EXPECT().RunSSHCommand("root", mock.MatchedBy(func(cmd string) bool { + return strings.HasPrefix(cmd, "scp ") + }), true).Return(nil).Once() + + // update-ca-certificates fails + node1.EXPECT().RunSSHCommand("root", "update-ca-certificates", true).Return(fmt.Errorf("ca update error")).Once() + + err := bs.EnsureLocalContainerRegistry() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to update CA certificates")) + }) + + It("fails when docker restart fails", func() { + // Override node setup for this test + node1 := node.NewMockNodeManager(GinkgoT()) + bs.Env.ControlPlaneNodes = []node.NodeManager{node1} + bs.Env.CephNodes = []node.NodeManager{} + + node1.EXPECT().GetInternalIP().Return("10.0.0.2").Maybe() + + // First check - registry not running + nm.EXPECT().RunSSHCommand("root", mock.MatchedBy(func(cmd string) bool { + return strings.Contains(cmd, "podman ps") + }), true).Return(fmt.Errorf("not running")) + + // All 8 install commands succeed + nm.EXPECT().RunSSHCommand("root", mock.Anything, false).Return(nil).Times(8) + + // scp succeeds + nm.EXPECT().RunSSHCommand("root", mock.MatchedBy(func(cmd string) bool { + return strings.HasPrefix(cmd, "scp ") + }), true).Return(nil).Once() + + // update-ca-certificates succeeds + node1.EXPECT().RunSSHCommand("root", "update-ca-certificates", true).Return(nil).Once() + + // docker restart fails + node1.EXPECT().RunSSHCommand("root", "systemctl restart docker.service || true", true).Return(fmt.Errorf("docker restart error")).Once() + + err := bs.EnsureLocalContainerRegistry() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to restart docker service")) + }) + }) +}) + +var _ = Describe("EnsureServiceAccounts", func() { + Describe("Valid EnsureServiceAccounts", func() { + It("creates cloud-controller and skips writer if not artifact registry", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + RegistryType: gcp.RegistryTypeLocalContainer, + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + gc.EXPECT().CreateServiceAccount("pid", "cloud-controller", "cloud-controller").Return("email@sa", false, nil) + + err = bs.EnsureServiceAccounts() + Expect(err).NotTo(HaveOccurred()) + }) + + It("creates both accounts for artifact registry", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + RegistryType: gcp.RegistryTypeArtifactRegistry, + InstallConfig: &files.RootConfig{ + Registry: &files.RegistryConfig{}, + }, + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + gc.EXPECT().CreateServiceAccount("pid", "cloud-controller", "cloud-controller").Return("email@sa", false, nil) + gc.EXPECT().CreateServiceAccount("pid", "artifact-registry-writer", "artifact-registry-writer").Return("writer@sa", true, nil) + gc.EXPECT().CreateServiceAccountKey("pid", "writer@sa").Return("key-content", nil) + + err = bs.EnsureServiceAccounts() + Expect(err).NotTo(HaveOccurred()) + Expect(bs.Env.InstallConfig.Registry.Password).To(Equal("key-content")) + }) + }) + + Describe("Invalid cases", func() { + It("fails when cloud-controller creation fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + gc.EXPECT().CreateServiceAccount("pid", "cloud-controller", "cloud-controller").Return("", false, fmt.Errorf("create error")) + + err = bs.EnsureServiceAccounts() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("create error")) + }) + }) +}) + +var _ = Describe("EnsureIAMRoles", func() { + Describe("Valid EnsureIAMRoles", func() { + It("assigns roles correctly", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + RegistryType: gcp.RegistryTypeArtifactRegistry, + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + gc.EXPECT().AssignIAMRole("pid", "cloud-controller", "roles/compute.admin").Return(nil) + gc.EXPECT().AssignIAMRole("pid", "artifact-registry-writer", "roles/artifactregistry.writer").Return(nil) + + err = bs.EnsureIAMRoles() + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Describe("Invalid cases", func() { + It("fails when AssignIAMRole fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + gc.EXPECT().AssignIAMRole("pid", "cloud-controller", "roles/compute.admin").Return(fmt.Errorf("iam error")) + + err = bs.EnsureIAMRoles() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("iam error")) + }) + }) +}) + +var _ = Describe("EnsureVPC", func() { + Describe("Valid EnsureVPC", func() { + It("creates VPC, subnet, router, and nat", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + Region: "us-central1", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + gc.EXPECT().CreateVPC("pid", "us-central1", "pid-vpc", "pid-us-central1-subnet", "pid-router", "pid-nat-gateway").Return(nil) + + err = bs.EnsureVPC() + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Describe("Invalid cases", func() { + It("fails when CreateVPC fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + Region: "us-central1", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + gc.EXPECT().CreateVPC("pid", "us-central1", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("vpc error")) + + err = bs.EnsureVPC() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to ensure VPC")) + Expect(err.Error()).To(ContainSubstring("vpc error")) + }) + }) +}) + +var _ = Describe("EnsureFirewallRules", func() { + Describe("Valid EnsureFirewallRules", func() { + It("creates required firewall rules", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + // Expect 4 rules: allow-ssh-ext, allow-internal, allow-all-egress, allow-ingress-web, allow-ingress-postgres + // Wait, code showed 5 blocks? ssh, internal, egress, web, postgres. + gc.EXPECT().CreateFirewallRule("pid", mock.MatchedBy(func(r *computepb.Firewall) bool { + return *r.Name == "allow-ssh-ext" + })).Return(nil) + gc.EXPECT().CreateFirewallRule("pid", mock.MatchedBy(func(r *computepb.Firewall) bool { + return *r.Name == "allow-internal" + })).Return(nil) + gc.EXPECT().CreateFirewallRule("pid", mock.MatchedBy(func(r *computepb.Firewall) bool { + return *r.Name == "allow-all-egress" + })).Return(nil) + gc.EXPECT().CreateFirewallRule("pid", mock.MatchedBy(func(r *computepb.Firewall) bool { + return *r.Name == "allow-ingress-web" + })).Return(nil) + gc.EXPECT().CreateFirewallRule("pid", mock.MatchedBy(func(r *computepb.Firewall) bool { + return *r.Name == "allow-ingress-postgres" + })).Return(nil) + + err = bs.EnsureFirewallRules() + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Describe("Invalid cases", func() { + It("fails when first firewall rule creation fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + gc.EXPECT().CreateFirewallRule("pid", mock.Anything).Return(fmt.Errorf("firewall error")).Once() + + err = bs.EnsureFirewallRules() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to create jumpbox ssh firewall rule")) + }) + }) +}) + +var _ = Describe("EnsureComputeInstances", func() { + Describe("Valid EnsureComputeInstances", func() { + It("creates all instances", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + Region: "us-central1", + Zone: "us-central1-a", + SSHPublicKeyPath: "key.pub", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + // Mock ReadFile for SSH key (called 9 times in parallel) + fw.EXPECT().ReadFile("key.pub").Return([]byte("ssh-rsa AAA..."), nil).Times(9) + + // Mock CreateInstance (9 times) + gc.EXPECT().CreateInstance("pid", "us-central1-a", mock.Anything).Return(nil).Times(9) + + // Mock GetInstance (9 times) + ipResp := &computepb.Instance{ + NetworkInterfaces: []*computepb.NetworkInterface{ + { + NetworkIP: protoString("10.0.0.x"), + AccessConfigs: []*computepb.AccessConfig{ + {NatIP: protoString("1.2.3.x")}, + }, + }, + }, + } + gc.EXPECT().GetInstance("pid", "us-central1-a", mock.Anything).Return(ipResp, nil).Times(9) + + // Mock UpdateNode (called once for jumpbox to update the original NodeManager) + nm.EXPECT().UpdateNode(mock.Anything, mock.Anything, mock.Anything).Once() + + // Mock CreateSubNode (8 times for postgres, ceph, k0s - now in main goroutine after channel) + nm.EXPECT().CreateSubNode(mock.Anything, mock.Anything, mock.Anything).RunAndReturn(func(name, extIP, intIP string) node.NodeManager { + m := node.NewMockNodeManager(GinkgoT()) + m.EXPECT().GetName().Return(name).Maybe() // Allow Name() calls for sorting + return m + }).Times(8) + + err = bs.EnsureComputeInstances() + Expect(err).NotTo(HaveOccurred()) + Expect(len(bs.Env.ControlPlaneNodes)).To(Equal(3)) + Expect(len(bs.Env.CephNodes)).To(Equal(4)) + Expect(bs.Env.PostgreSQLNode).NotTo(BeNil()) + Expect(bs.Env.Jumpbox).NotTo(BeNil()) // Jumpbox is now the NodeManager itself after UpdateNode + }) + }) + + Describe("Invalid cases", func() { + It("fails when SSH key read fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + Region: "us-central1", + Zone: "us-central1-a", + SSHPublicKeyPath: "key.pub", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + fw.EXPECT().ReadFile("key.pub").Return(nil, fmt.Errorf("read error")).Maybe() + + err = bs.EnsureComputeInstances() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("error ensuring compute instances")) + }) + + It("fails when CreateInstance fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + Region: "us-central1", + Zone: "us-central1-a", + SSHPublicKeyPath: "key.pub", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + fw.EXPECT().ReadFile("key.pub").Return([]byte("ssh-rsa AAA..."), nil).Maybe() + gc.EXPECT().CreateInstance("pid", "us-central1-a", mock.Anything).Return(fmt.Errorf("create error")).Maybe() + + err = bs.EnsureComputeInstances() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("error ensuring compute instances")) + }) + + It("fails when GetInstance fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + Region: "us-central1", + Zone: "us-central1-a", + SSHPublicKeyPath: "key.pub", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + fw.EXPECT().ReadFile("key.pub").Return([]byte("ssh-rsa AAA..."), nil).Maybe() + gc.EXPECT().CreateInstance("pid", "us-central1-a", mock.Anything).Return(nil).Maybe() + gc.EXPECT().GetInstance("pid", "us-central1-a", mock.Anything).Return(nil, fmt.Errorf("get error")).Maybe() + + err = bs.EnsureComputeInstances() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("error ensuring compute instances")) + }) + }) +}) + +var _ = Describe("EnsureGatewayIPAddresses", func() { + Describe("Valid EnsureGatewayIPAddresses", func() { + It("creates two addresses", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + Region: "us-central1", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + // Gateway + gc.EXPECT().GetAddress("pid", "us-central1", "gateway").Return(nil, fmt.Errorf("not found")) + gc.EXPECT().CreateAddress("pid", "us-central1", mock.MatchedBy(func(a *computepb.Address) bool { + return *a.Name == "gateway" + })).Return("1.1.1.1", nil) + + // Public Gateway + gc.EXPECT().GetAddress("pid", "us-central1", "public-gateway").Return(nil, fmt.Errorf("not found")) + gc.EXPECT().CreateAddress("pid", "us-central1", mock.MatchedBy(func(a *computepb.Address) bool { + return *a.Name == "public-gateway" + })).Return("2.2.2.2", nil) + + err = bs.EnsureGatewayIPAddresses() + Expect(err).NotTo(HaveOccurred()) + Expect(bs.Env.GatewayIP).To(Equal("1.1.1.1")) + Expect(bs.Env.PublicGatewayIP).To(Equal("2.2.2.2")) + }) + }) + + Describe("Invalid cases", func() { + It("fails when gateway IP creation fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + Region: "us-central1", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + gc.EXPECT().GetAddress("pid", "us-central1", "gateway").Return(nil, fmt.Errorf("not found")) + gc.EXPECT().CreateAddress("pid", "us-central1", mock.Anything).Return("", fmt.Errorf("create error")) + + err = bs.EnsureGatewayIPAddresses() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to ensure gateway IP")) + }) + + It("fails when public gateway IP creation fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + ProjectID: "pid", + Region: "us-central1", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + gc.EXPECT().GetAddress("pid", "us-central1", "gateway").Return(nil, fmt.Errorf("not found")) + gc.EXPECT().CreateAddress("pid", "us-central1", mock.MatchedBy(func(a *computepb.Address) bool { + return *a.Name == "gateway" + })).Return("1.1.1.1", nil) + gc.EXPECT().GetAddress("pid", "us-central1", "public-gateway").Return(nil, fmt.Errorf("not found")) + gc.EXPECT().CreateAddress("pid", "us-central1", mock.MatchedBy(func(a *computepb.Address) bool { + return *a.Name == "public-gateway" + })).Return("", fmt.Errorf("create error")) + + err = bs.EnsureGatewayIPAddresses() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to ensure public gateway IP")) + }) + }) +}) + +var _ = Describe("EnsureRootLoginEnabled", func() { + Describe("Valid EnsureRootLoginEnabled", func() { + It("enables root login on all nodes", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{} + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + // Setup nodes + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + // Use the same mock for all for simplicity, but expect multiple calls + bs.Env.Jumpbox = nm + bs.Env.PostgreSQLNode = nm + bs.Env.ControlPlaneNodes = []node.NodeManager{nm} + bs.Env.CephNodes = []node.NodeManager{nm} + + // Total nodes: 1 (jumpbox) + 1 (pg) + 1 (cp) + 1 (ceph) = 4 + nm.EXPECT().GetName().Return("mock-node").Maybe() + nm.EXPECT().WaitForSSH(mock.Anything).Return(nil).Times(4) + nm.EXPECT().HasRootLoginEnabled().Return(false).Times(4) + nm.EXPECT().EnableRootLogin().Return(nil).Times(4) + + err = bs.EnsureRootLoginEnabled() + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Describe("Invalid cases", func() { + It("fails when WaitForSSH times out", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{} + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + bs.Env.Jumpbox = nm + bs.Env.PostgreSQLNode = nm + bs.Env.ControlPlaneNodes = []node.NodeManager{} + bs.Env.CephNodes = []node.NodeManager{} + + nm.EXPECT().GetName().Return("mock-node").Maybe() + nm.EXPECT().WaitForSSH(mock.Anything).Return(fmt.Errorf("timeout")).Once() + + err = bs.EnsureRootLoginEnabled() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("timed out waiting for SSH service")) + }) + + It("fails when EnableRootLogin fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{} + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + bs.Env.Jumpbox = nm + bs.Env.PostgreSQLNode = nm + bs.Env.ControlPlaneNodes = []node.NodeManager{} + bs.Env.CephNodes = []node.NodeManager{} + + nm.EXPECT().GetName().Return("mock-node").Maybe() + nm.EXPECT().WaitForSSH(mock.Anything).Return(nil).Once() + nm.EXPECT().HasRootLoginEnabled().Return(false).Once() + nm.EXPECT().EnableRootLogin().Return(fmt.Errorf("enable error")).Times(3) + + err = bs.EnsureRootLoginEnabled() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to enable root login")) + }) + }) +}) + +var _ = Describe("EnsureJumpboxConfigured", func() { + Describe("Valid EnsureJumpboxConfigured", func() { + It("configures jumpbox", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{} + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + bs.Env.Jumpbox = nm + + nm.EXPECT().HasAcceptEnvConfigured().Return(false) + nm.EXPECT().ConfigureAcceptEnv().Return(nil) + nm.EXPECT().HasCommand("oms-cli").Return(false) + nm.EXPECT().InstallOms().Return(nil) + + err = bs.EnsureJumpboxConfigured() + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Describe("Invalid cases", func() { + It("fails when ConfigureAcceptEnv fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{} + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + bs.Env.Jumpbox = nm + + nm.EXPECT().HasAcceptEnvConfigured().Return(false) + nm.EXPECT().ConfigureAcceptEnv().Return(fmt.Errorf("config error")) + + err = bs.EnsureJumpboxConfigured() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to configure AcceptEnv")) + }) + + It("fails when InstallOms fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{} + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + bs.Env.Jumpbox = nm + + nm.EXPECT().HasAcceptEnvConfigured().Return(true) + nm.EXPECT().HasCommand("oms-cli").Return(false) + nm.EXPECT().InstallOms().Return(fmt.Errorf("install error")) + + err = bs.EnsureJumpboxConfigured() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to install OMS")) + }) + }) +}) + +var _ = Describe("EnsureHostsConfigured", func() { + Describe("Valid EnsureHostsConfigured", func() { + It("configures hosts", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{} + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + // Setup nodes + bs.Env.PostgreSQLNode = nm + bs.Env.ControlPlaneNodes = []node.NodeManager{nm} + bs.Env.CephNodes = []node.NodeManager{} // Empty to reduce calls + + // Total nodes: 1 (pg) + 1 (cp) = 2 + nm.EXPECT().GetName().Return("mock-node").Maybe() + nm.EXPECT().HasInotifyWatchesConfigured().Return(false).Times(2) + nm.EXPECT().ConfigureInotifyWatches().Return(nil).Times(2) + nm.EXPECT().HasMemoryMapConfigured().Return(false).Times(2) + nm.EXPECT().ConfigureMemoryMap().Return(nil).Times(2) + + err = bs.EnsureHostsConfigured() + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Describe("Invalid cases", func() { + It("fails when ConfigureInotifyWatches fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{} + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + bs.Env.PostgreSQLNode = nm + bs.Env.ControlPlaneNodes = []node.NodeManager{} + bs.Env.CephNodes = []node.NodeManager{} + + nm.EXPECT().GetName().Return("mock-node").Maybe() + nm.EXPECT().HasInotifyWatchesConfigured().Return(false) + nm.EXPECT().ConfigureInotifyWatches().Return(fmt.Errorf("inotify error")) + + err = bs.EnsureHostsConfigured() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to configure inotify watches")) + }) + + It("fails when ConfigureMemoryMap fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{} + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + bs.Env.PostgreSQLNode = nm + bs.Env.ControlPlaneNodes = []node.NodeManager{} + bs.Env.CephNodes = []node.NodeManager{} + + nm.EXPECT().GetName().Return("mock-node").Maybe() + nm.EXPECT().HasInotifyWatchesConfigured().Return(true) + nm.EXPECT().HasMemoryMapConfigured().Return(false) + nm.EXPECT().ConfigureMemoryMap().Return(fmt.Errorf("memory map error")) + + err = bs.EnsureHostsConfigured() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to configure memory map")) + }) + }) +}) + +var _ = Describe("UpdateInstallConfig", func() { + Describe("Valid UpdateInstallConfig", func() { + It("updates config and writes files", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + SecretsDir: "/secrets", + InstallConfigPath: "config.yaml", + SecretsFilePath: "secrets.yaml", + DatacenterID: 1, + BaseDomain: "example.com", + GatewayIP: "1.1.1.1", + PublicGatewayIP: "2.2.2.2", + GithubAppClientID: "gh-id", + GithubAppClientSecret: "gh-secret", + InstallConfig: &files.RootConfig{ + Registry: &files.RegistryConfig{}, + Postgres: files.PostgresConfig{ + Primary: &files.PostgresPrimaryConfig{}, + }, + Cluster: files.ClusterConfig{}, + }, + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + // Setup Nodes + bs.Env.Jumpbox = nm + bs.Env.PostgreSQLNode = nm + bs.Env.CephNodes = []node.NodeManager{nm, nm, nm, nm} + bs.Env.ControlPlaneNodes = []node.NodeManager{nm, nm, nm} + + nm.EXPECT().GetName().Return("mock-node").Maybe() + nm.EXPECT().GetInternalIP().Return("10.0.0.1").Maybe() + nm.EXPECT().GetExternalIP().Return("8.8.8.8").Maybe() // For PublicIP + + // Expectations + icg.EXPECT().GenerateSecrets().Return(nil) + icg.EXPECT().WriteInstallConfig("config.yaml", true).Return(nil) + icg.EXPECT().WriteVault("secrets.yaml", true).Return(nil) + + nm.EXPECT().CopyFile("config.yaml", "/etc/codesphere/config.yaml").Return(nil) + nm.EXPECT().CopyFile("secrets.yaml", "/secrets/prod.vault.yaml").Return(nil) + + err = bs.UpdateInstallConfig() + Expect(err).NotTo(HaveOccurred()) + + Expect(bs.Env.InstallConfig.Datacenter.ID).To(Equal(1)) + Expect(bs.Env.InstallConfig.Codesphere.Domain).To(Equal("cs.example.com")) + }) + }) + + Describe("Invalid cases", func() { + It("fails when GenerateSecrets fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + SecretsDir: "/secrets", + InstallConfigPath: "config.yaml", + SecretsFilePath: "secrets.yaml", + DatacenterID: 1, + BaseDomain: "example.com", + GatewayIP: "1.1.1.1", + PublicGatewayIP: "2.2.2.2", + GithubAppClientID: "gh-id", + GithubAppClientSecret: "gh-secret", + InstallConfig: &files.RootConfig{ + Registry: &files.RegistryConfig{}, + Postgres: files.PostgresConfig{ + Primary: &files.PostgresPrimaryConfig{}, + }, + Cluster: files.ClusterConfig{}, + }, + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + bs.Env.Jumpbox = nm + bs.Env.PostgreSQLNode = nm + bs.Env.CephNodes = []node.NodeManager{nm, nm, nm, nm} + bs.Env.ControlPlaneNodes = []node.NodeManager{nm, nm, nm} + + nm.EXPECT().GetName().Return("mock-node").Maybe() + nm.EXPECT().GetInternalIP().Return("10.0.0.1").Maybe() + nm.EXPECT().GetExternalIP().Return("8.8.8.8").Maybe() + + icg.EXPECT().GenerateSecrets().Return(fmt.Errorf("generate error")) + + err = bs.UpdateInstallConfig() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to generate secrets")) + }) + + It("fails when WriteInstallConfig fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + SecretsDir: "/secrets", + InstallConfigPath: "config.yaml", + SecretsFilePath: "secrets.yaml", + DatacenterID: 1, + BaseDomain: "example.com", + GatewayIP: "1.1.1.1", + PublicGatewayIP: "2.2.2.2", + GithubAppClientID: "gh-id", + GithubAppClientSecret: "gh-secret", + InstallConfig: &files.RootConfig{ + Registry: &files.RegistryConfig{}, + Postgres: files.PostgresConfig{ + Primary: &files.PostgresPrimaryConfig{}, + }, + Cluster: files.ClusterConfig{}, + }, + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + bs.Env.Jumpbox = nm + bs.Env.PostgreSQLNode = nm + bs.Env.CephNodes = []node.NodeManager{nm, nm, nm, nm} + bs.Env.ControlPlaneNodes = []node.NodeManager{nm, nm, nm} + + nm.EXPECT().GetName().Return("mock-node").Maybe() + nm.EXPECT().GetInternalIP().Return("10.0.0.1").Maybe() + nm.EXPECT().GetExternalIP().Return("8.8.8.8").Maybe() + + icg.EXPECT().GenerateSecrets().Return(nil) + icg.EXPECT().WriteInstallConfig("config.yaml", true).Return(fmt.Errorf("write error")) + + err = bs.UpdateInstallConfig() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to write config file")) + }) + + It("fails when WriteVault fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + SecretsDir: "/secrets", + InstallConfigPath: "config.yaml", + SecretsFilePath: "secrets.yaml", + DatacenterID: 1, + BaseDomain: "example.com", + GatewayIP: "1.1.1.1", + PublicGatewayIP: "2.2.2.2", + GithubAppClientID: "gh-id", + GithubAppClientSecret: "gh-secret", + InstallConfig: &files.RootConfig{ + Registry: &files.RegistryConfig{}, + Postgres: files.PostgresConfig{ + Primary: &files.PostgresPrimaryConfig{}, + }, + Cluster: files.ClusterConfig{}, + }, + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + bs.Env.Jumpbox = nm + bs.Env.PostgreSQLNode = nm + bs.Env.CephNodes = []node.NodeManager{nm, nm, nm, nm} + bs.Env.ControlPlaneNodes = []node.NodeManager{nm, nm, nm} + + nm.EXPECT().GetName().Return("mock-node").Maybe() + nm.EXPECT().GetInternalIP().Return("10.0.0.1").Maybe() + nm.EXPECT().GetExternalIP().Return("8.8.8.8").Maybe() + + icg.EXPECT().GenerateSecrets().Return(nil) + icg.EXPECT().WriteInstallConfig("config.yaml", true).Return(nil) + icg.EXPECT().WriteVault("secrets.yaml", true).Return(fmt.Errorf("vault write error")) + + err = bs.UpdateInstallConfig() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to write vault file")) + }) + + It("fails when CopyFile config fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + SecretsDir: "/secrets", + InstallConfigPath: "config.yaml", + SecretsFilePath: "secrets.yaml", + DatacenterID: 1, + BaseDomain: "example.com", + GatewayIP: "1.1.1.1", + PublicGatewayIP: "2.2.2.2", + GithubAppClientID: "gh-id", + GithubAppClientSecret: "gh-secret", + InstallConfig: &files.RootConfig{ + Registry: &files.RegistryConfig{}, + Postgres: files.PostgresConfig{ + Primary: &files.PostgresPrimaryConfig{}, + }, + Cluster: files.ClusterConfig{}, + }, + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + bs.Env.Jumpbox = nm + bs.Env.PostgreSQLNode = nm + bs.Env.CephNodes = []node.NodeManager{nm, nm, nm, nm} + bs.Env.ControlPlaneNodes = []node.NodeManager{nm, nm, nm} + + nm.EXPECT().GetName().Return("mock-node").Maybe() + nm.EXPECT().GetInternalIP().Return("10.0.0.1").Maybe() + nm.EXPECT().GetExternalIP().Return("8.8.8.8").Maybe() + + icg.EXPECT().GenerateSecrets().Return(nil) + icg.EXPECT().WriteInstallConfig("config.yaml", true).Return(nil) + icg.EXPECT().WriteVault("secrets.yaml", true).Return(nil) + nm.EXPECT().CopyFile("config.yaml", "/etc/codesphere/config.yaml").Return(fmt.Errorf("copy error")) + + err = bs.UpdateInstallConfig() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to copy install config to jumpbox")) + }) + + It("fails when CopyFile secrets fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + SecretsDir: "/secrets", + InstallConfigPath: "config.yaml", + SecretsFilePath: "secrets.yaml", + DatacenterID: 1, + BaseDomain: "example.com", + GatewayIP: "1.1.1.1", + PublicGatewayIP: "2.2.2.2", + GithubAppClientID: "gh-id", + GithubAppClientSecret: "gh-secret", + InstallConfig: &files.RootConfig{ + Registry: &files.RegistryConfig{}, + Postgres: files.PostgresConfig{ + Primary: &files.PostgresPrimaryConfig{}, + }, + Cluster: files.ClusterConfig{}, + }, + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + bs.Env.Jumpbox = nm + bs.Env.PostgreSQLNode = nm + bs.Env.CephNodes = []node.NodeManager{nm, nm, nm, nm} + bs.Env.ControlPlaneNodes = []node.NodeManager{nm, nm, nm} + + nm.EXPECT().GetName().Return("mock-node").Maybe() + nm.EXPECT().GetInternalIP().Return("10.0.0.1").Maybe() + nm.EXPECT().GetExternalIP().Return("8.8.8.8").Maybe() + + icg.EXPECT().GenerateSecrets().Return(nil) + icg.EXPECT().WriteInstallConfig("config.yaml", true).Return(nil) + icg.EXPECT().WriteVault("secrets.yaml", true).Return(nil) + nm.EXPECT().CopyFile("config.yaml", "/etc/codesphere/config.yaml").Return(nil) + nm.EXPECT().CopyFile("secrets.yaml", "/secrets/prod.vault.yaml").Return(fmt.Errorf("copy error")) + + err = bs.UpdateInstallConfig() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to copy secrets file to jumpbox")) + }) + }) +}) + +var _ = Describe("EnsureAgeKey", func() { + Describe("Valid EnsureAgeKey", func() { + It("generates key if missing", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + SecretsDir: "/secrets", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + bs.Env.Jumpbox = nm + + nm.EXPECT().HasFile("/secrets/age_key.txt").Return(false) + nm.EXPECT().RunSSHCommand("root", mock.MatchedBy(func(cmd string) bool { + return strings.Contains(cmd, "age-keygen") + }), true).Return(nil) + + err = bs.EnsureAgeKey() + Expect(err).NotTo(HaveOccurred()) + }) + + It("skips if key exists", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + SecretsDir: "/secrets", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + bs.Env.Jumpbox = nm + + nm.EXPECT().HasFile("/secrets/age_key.txt").Return(true) + // No SSH command expected + + err = bs.EnsureAgeKey() + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Describe("Invalid cases", func() { + It("fails when age-keygen command fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + SecretsDir: "/secrets", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + bs.Env.Jumpbox = nm + + nm.EXPECT().HasFile("/secrets/age_key.txt").Return(false) + nm.EXPECT().RunSSHCommand("root", mock.MatchedBy(func(cmd string) bool { + return strings.Contains(cmd, "age-keygen") + }), true).Return(fmt.Errorf("keygen error")) + + err = bs.EnsureAgeKey() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to generate age key on jumpbox")) + }) + }) +}) + +var _ = Describe("EncryptVault", func() { + Describe("Valid EncryptVault", func() { + It("encrypts vault using sops", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + SecretsDir: "/secrets", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + bs.Env.Jumpbox = nm + + nm.EXPECT().RunSSHCommand("root", mock.MatchedBy(func(cmd string) bool { + return strings.HasPrefix(cmd, "cp ") + }), true).Return(nil) + + nm.EXPECT().RunSSHCommand("root", mock.MatchedBy(func(cmd string) bool { + return strings.Contains(cmd, "sops --encrypt") + }), true).Return(nil) + + err = bs.EncryptVault() + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Describe("Invalid cases", func() { + It("fails when backup vault command fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + SecretsDir: "/secrets", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + bs.Env.Jumpbox = nm + + nm.EXPECT().RunSSHCommand("root", mock.MatchedBy(func(cmd string) bool { + return strings.HasPrefix(cmd, "cp ") + }), true).Return(fmt.Errorf("backup error")) + + err = bs.EncryptVault() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed backup vault on jumpbox")) + }) + + It("fails when sops encrypt command fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + SecretsDir: "/secrets", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + bs.Env.Jumpbox = nm + + nm.EXPECT().RunSSHCommand("root", mock.MatchedBy(func(cmd string) bool { + return strings.HasPrefix(cmd, "cp ") + }), true).Return(nil) + + nm.EXPECT().RunSSHCommand("root", mock.MatchedBy(func(cmd string) bool { + return strings.Contains(cmd, "sops --encrypt") + }), true).Return(fmt.Errorf("encrypt error")) + + err = bs.EncryptVault() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to encrypt vault on jumpbox")) + }) + }) +}) + +var _ = Describe("EnsureDNSRecords", func() { + Describe("Valid EnsureDNSRecords", func() { + It("ensures DNS records", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + DNSProjectID: "dns-proj", + DNSZoneName: "zone", + BaseDomain: "example.com", + GatewayIP: "1.1.1.1", + PublicGatewayIP: "2.2.2.2", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + gc.EXPECT().EnsureDNSManagedZone("dns-proj", "zone", "example.com.", mock.Anything).Return(nil) + gc.EXPECT().EnsureDNSRecordSets("dns-proj", "zone", mock.MatchedBy(func(records []*dns.ResourceRecordSet) bool { + // Expect 4 records: *.ws, *.cs, cs, ws + return len(records) == 4 + })).Return(nil) + + err = bs.EnsureDNSRecords() + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Describe("Invalid cases", func() { + It("fails when EnsureDNSManagedZone fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + DNSProjectID: "dns-proj", + DNSZoneName: "zone", + BaseDomain: "example.com", + GatewayIP: "1.1.1.1", + PublicGatewayIP: "2.2.2.2", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + gc.EXPECT().EnsureDNSManagedZone("dns-proj", "zone", "example.com.", mock.Anything).Return(fmt.Errorf("zone error")) + + err = bs.EnsureDNSRecords() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to ensure DNS managed zone")) + }) + + It("fails when EnsureDNSRecordSets fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + DNSProjectID: "dns-proj", + DNSZoneName: "zone", + BaseDomain: "example.com", + GatewayIP: "1.1.1.1", + PublicGatewayIP: "2.2.2.2", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + gc.EXPECT().EnsureDNSManagedZone("dns-proj", "zone", "example.com.", mock.Anything).Return(nil) + gc.EXPECT().EnsureDNSRecordSets("dns-proj", "zone", mock.Anything).Return(fmt.Errorf("record error")) + + err = bs.EnsureDNSRecords() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to ensure DNS record sets")) + }) + }) +}) + +var _ = Describe("InstallCodesphere", func() { + Describe("Valid InstallCodesphere", func() { + It("downloads and installs codesphere", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + InstallCodesphereVersion: "v1.2.3", + SecretsDir: "/secrets", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + bs.Env.Jumpbox = nm + + // Expect download package + nm.EXPECT().RunSSHCommand("root", "oms-cli download package v1.2.3", false).Return(nil) + + // Expect install codesphere + nm.EXPECT().RunSSHCommand("root", "oms-cli install codesphere -c /etc/codesphere/config.yaml -k /secrets/age_key.txt -p v1.2.3.tar.gz", false).Return(nil) + + err = bs.InstallCodesphere() + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Describe("Invalid cases", func() { + It("fails when download package fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + InstallCodesphereVersion: "v1.2.3", + SecretsDir: "/secrets", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + bs.Env.Jumpbox = nm + + nm.EXPECT().RunSSHCommand("root", "oms-cli download package v1.2.3", false).Return(fmt.Errorf("download error")) + + err = bs.InstallCodesphere() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to download Codesphere package from jumpbox")) + }) + + It("fails when install codesphere fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + InstallCodesphereVersion: "v1.2.3", + SecretsDir: "/secrets", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + bs.Env.Jumpbox = nm + + nm.EXPECT().RunSSHCommand("root", "oms-cli download package v1.2.3", false).Return(nil) + nm.EXPECT().RunSSHCommand("root", "oms-cli install codesphere -c /etc/codesphere/config.yaml -k /secrets/age_key.txt -p v1.2.3.tar.gz", false).Return(fmt.Errorf("install error")) + + err = bs.InstallCodesphere() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to install Codesphere from jumpbox")) + }) + }) +}) + +var _ = Describe("GenerateK0sConfigScript", func() { + Describe("Valid GenerateK0sConfigScript", func() { + It("generates script", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + PublicGatewayIP: "2.2.2.2", + GatewayIP: "1.1.1.1", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + // Setup required nodes (indices 0, 1, 2 accessed) + bs.Env.ControlPlaneNodes = []node.NodeManager{nm, nm, nm} + + nm.EXPECT().GetInternalIP().Return("10.0.0.1").Maybe() + + fw.EXPECT().WriteFile("configure-k0s.sh", mock.Anything, os.FileMode(0755)).Return(nil) + nm.EXPECT().CopyFile("configure-k0s.sh", "/root/configure-k0s.sh").Return(nil) + nm.EXPECT().RunSSHCommand("root", "chmod +x /root/configure-k0s.sh", true).Return(nil) + + err = bs.GenerateK0sConfigScript() + Expect(err).NotTo(HaveOccurred()) + }) + }) + + Describe("Invalid cases", func() { + It("fails when WriteFile fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + PublicGatewayIP: "2.2.2.2", + GatewayIP: "1.1.1.1", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + bs.Env.ControlPlaneNodes = []node.NodeManager{nm, nm, nm} + + nm.EXPECT().GetInternalIP().Return("10.0.0.1").Maybe() + + fw.EXPECT().WriteFile("configure-k0s.sh", mock.Anything, os.FileMode(0755)).Return(fmt.Errorf("write error")) + + err = bs.GenerateK0sConfigScript() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to write configure-k0s.sh")) + }) + + It("fails when CopyFile fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + PublicGatewayIP: "2.2.2.2", + GatewayIP: "1.1.1.1", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + bs.Env.ControlPlaneNodes = []node.NodeManager{nm, nm, nm} + + nm.EXPECT().GetInternalIP().Return("10.0.0.1").Maybe() + + fw.EXPECT().WriteFile("configure-k0s.sh", mock.Anything, os.FileMode(0755)).Return(nil) + nm.EXPECT().CopyFile("configure-k0s.sh", "/root/configure-k0s.sh").Return(fmt.Errorf("copy error")) + + err = bs.GenerateK0sConfigScript() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to copy configure-k0s.sh to control plane node")) + }) + + It("fails when RunSSHCommand chmod fails", func() { + env := env.NewEnv() + ctx := context.Background() + csEnv := &gcp.CodesphereEnvironment{ + PublicGatewayIP: "2.2.2.2", + GatewayIP: "1.1.1.1", + } + stlog := bootstrap.NewStepLogger(false) + + icg := installer.NewMockInstallConfigManager(GinkgoT()) + gc := gcp.NewMockGCPClientManager(GinkgoT()) + fw := util.NewMockFileIO(GinkgoT()) + nm := node.NewMockNodeManager(GinkgoT()) + + bs, err := gcp.NewGCPBootstrapper(ctx, env, stlog, csEnv, icg, gc, nm, fw) + Expect(err).NotTo(HaveOccurred()) + + bs.Env.ControlPlaneNodes = []node.NodeManager{nm, nm, nm} + + nm.EXPECT().GetInternalIP().Return("10.0.0.1").Maybe() + + fw.EXPECT().WriteFile("configure-k0s.sh", mock.Anything, os.FileMode(0755)).Return(nil) + nm.EXPECT().CopyFile("configure-k0s.sh", "/root/configure-k0s.sh").Return(nil) + nm.EXPECT().RunSSHCommand("root", "chmod +x /root/configure-k0s.sh", true).Return(fmt.Errorf("chmod error")) + + err = bs.GenerateK0sConfigScript() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("failed to make configure-k0s.sh executable")) + }) + }) +}) diff --git a/internal/bootstrap/gcp/mocks.go b/internal/bootstrap/gcp/mocks.go new file mode 100644 index 00000000..03416a48 --- /dev/null +++ b/internal/bootstrap/gcp/mocks.go @@ -0,0 +1,1316 @@ +// Code generated by mockery; DO NOT EDIT. +// github.com/vektra/mockery +// template: testify + +package gcp + +import ( + "cloud.google.com/go/artifactregistry/apiv1/artifactregistrypb" + "cloud.google.com/go/compute/apiv1/computepb" + "cloud.google.com/go/resourcemanager/apiv3/resourcemanagerpb" + mock "github.com/stretchr/testify/mock" + "google.golang.org/api/cloudbilling/v1" + "google.golang.org/api/dns/v1" +) + +// NewMockGCPClientManager creates a new instance of MockGCPClientManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockGCPClientManager(t interface { + mock.TestingT + Cleanup(func()) +}) *MockGCPClientManager { + mock := &MockGCPClientManager{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} + +// MockGCPClientManager is an autogenerated mock type for the GCPClientManager type +type MockGCPClientManager struct { + mock.Mock +} + +type MockGCPClientManager_Expecter struct { + mock *mock.Mock +} + +func (_m *MockGCPClientManager) EXPECT() *MockGCPClientManager_Expecter { + return &MockGCPClientManager_Expecter{mock: &_m.Mock} +} + +// AssignIAMRole provides a mock function for the type MockGCPClientManager +func (_mock *MockGCPClientManager) AssignIAMRole(projectID string, saEmail string, role string) error { + ret := _mock.Called(projectID, saEmail, role) + + if len(ret) == 0 { + panic("no return value specified for AssignIAMRole") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(string, string, string) error); ok { + r0 = returnFunc(projectID, saEmail, role) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// MockGCPClientManager_AssignIAMRole_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AssignIAMRole' +type MockGCPClientManager_AssignIAMRole_Call struct { + *mock.Call +} + +// AssignIAMRole is a helper method to define mock.On call +// - projectID string +// - saEmail string +// - role string +func (_e *MockGCPClientManager_Expecter) AssignIAMRole(projectID interface{}, saEmail interface{}, role interface{}) *MockGCPClientManager_AssignIAMRole_Call { + return &MockGCPClientManager_AssignIAMRole_Call{Call: _e.mock.On("AssignIAMRole", projectID, saEmail, role)} +} + +func (_c *MockGCPClientManager_AssignIAMRole_Call) Run(run func(projectID string, saEmail string, role string)) *MockGCPClientManager_AssignIAMRole_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *MockGCPClientManager_AssignIAMRole_Call) Return(err error) *MockGCPClientManager_AssignIAMRole_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockGCPClientManager_AssignIAMRole_Call) RunAndReturn(run func(projectID string, saEmail string, role string) error) *MockGCPClientManager_AssignIAMRole_Call { + _c.Call.Return(run) + return _c +} + +// CreateAddress provides a mock function for the type MockGCPClientManager +func (_mock *MockGCPClientManager) CreateAddress(projectID string, region string, address *computepb.Address) (string, error) { + ret := _mock.Called(projectID, region, address) + + if len(ret) == 0 { + panic("no return value specified for CreateAddress") + } + + var r0 string + var r1 error + if returnFunc, ok := ret.Get(0).(func(string, string, *computepb.Address) (string, error)); ok { + return returnFunc(projectID, region, address) + } + if returnFunc, ok := ret.Get(0).(func(string, string, *computepb.Address) string); ok { + r0 = returnFunc(projectID, region, address) + } else { + r0 = ret.Get(0).(string) + } + if returnFunc, ok := ret.Get(1).(func(string, string, *computepb.Address) error); ok { + r1 = returnFunc(projectID, region, address) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// MockGCPClientManager_CreateAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateAddress' +type MockGCPClientManager_CreateAddress_Call struct { + *mock.Call +} + +// CreateAddress is a helper method to define mock.On call +// - projectID string +// - region string +// - address *computepb.Address +func (_e *MockGCPClientManager_Expecter) CreateAddress(projectID interface{}, region interface{}, address interface{}) *MockGCPClientManager_CreateAddress_Call { + return &MockGCPClientManager_CreateAddress_Call{Call: _e.mock.On("CreateAddress", projectID, region, address)} +} + +func (_c *MockGCPClientManager_CreateAddress_Call) Run(run func(projectID string, region string, address *computepb.Address)) *MockGCPClientManager_CreateAddress_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 *computepb.Address + if args[2] != nil { + arg2 = args[2].(*computepb.Address) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *MockGCPClientManager_CreateAddress_Call) Return(s string, err error) *MockGCPClientManager_CreateAddress_Call { + _c.Call.Return(s, err) + return _c +} + +func (_c *MockGCPClientManager_CreateAddress_Call) RunAndReturn(run func(projectID string, region string, address *computepb.Address) (string, error)) *MockGCPClientManager_CreateAddress_Call { + _c.Call.Return(run) + return _c +} + +// CreateArtifactRegistry provides a mock function for the type MockGCPClientManager +func (_mock *MockGCPClientManager) CreateArtifactRegistry(projectID string, region string, repoName string) (*artifactregistrypb.Repository, error) { + ret := _mock.Called(projectID, region, repoName) + + if len(ret) == 0 { + panic("no return value specified for CreateArtifactRegistry") + } + + var r0 *artifactregistrypb.Repository + var r1 error + if returnFunc, ok := ret.Get(0).(func(string, string, string) (*artifactregistrypb.Repository, error)); ok { + return returnFunc(projectID, region, repoName) + } + if returnFunc, ok := ret.Get(0).(func(string, string, string) *artifactregistrypb.Repository); ok { + r0 = returnFunc(projectID, region, repoName) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*artifactregistrypb.Repository) + } + } + if returnFunc, ok := ret.Get(1).(func(string, string, string) error); ok { + r1 = returnFunc(projectID, region, repoName) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// MockGCPClientManager_CreateArtifactRegistry_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateArtifactRegistry' +type MockGCPClientManager_CreateArtifactRegistry_Call struct { + *mock.Call +} + +// CreateArtifactRegistry is a helper method to define mock.On call +// - projectID string +// - region string +// - repoName string +func (_e *MockGCPClientManager_Expecter) CreateArtifactRegistry(projectID interface{}, region interface{}, repoName interface{}) *MockGCPClientManager_CreateArtifactRegistry_Call { + return &MockGCPClientManager_CreateArtifactRegistry_Call{Call: _e.mock.On("CreateArtifactRegistry", projectID, region, repoName)} +} + +func (_c *MockGCPClientManager_CreateArtifactRegistry_Call) Run(run func(projectID string, region string, repoName string)) *MockGCPClientManager_CreateArtifactRegistry_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *MockGCPClientManager_CreateArtifactRegistry_Call) Return(repository *artifactregistrypb.Repository, err error) *MockGCPClientManager_CreateArtifactRegistry_Call { + _c.Call.Return(repository, err) + return _c +} + +func (_c *MockGCPClientManager_CreateArtifactRegistry_Call) RunAndReturn(run func(projectID string, region string, repoName string) (*artifactregistrypb.Repository, error)) *MockGCPClientManager_CreateArtifactRegistry_Call { + _c.Call.Return(run) + return _c +} + +// CreateFirewallRule provides a mock function for the type MockGCPClientManager +func (_mock *MockGCPClientManager) CreateFirewallRule(projectID string, rule *computepb.Firewall) error { + ret := _mock.Called(projectID, rule) + + if len(ret) == 0 { + panic("no return value specified for CreateFirewallRule") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(string, *computepb.Firewall) error); ok { + r0 = returnFunc(projectID, rule) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// MockGCPClientManager_CreateFirewallRule_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateFirewallRule' +type MockGCPClientManager_CreateFirewallRule_Call struct { + *mock.Call +} + +// CreateFirewallRule is a helper method to define mock.On call +// - projectID string +// - rule *computepb.Firewall +func (_e *MockGCPClientManager_Expecter) CreateFirewallRule(projectID interface{}, rule interface{}) *MockGCPClientManager_CreateFirewallRule_Call { + return &MockGCPClientManager_CreateFirewallRule_Call{Call: _e.mock.On("CreateFirewallRule", projectID, rule)} +} + +func (_c *MockGCPClientManager_CreateFirewallRule_Call) Run(run func(projectID string, rule *computepb.Firewall)) *MockGCPClientManager_CreateFirewallRule_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 *computepb.Firewall + if args[1] != nil { + arg1 = args[1].(*computepb.Firewall) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *MockGCPClientManager_CreateFirewallRule_Call) Return(err error) *MockGCPClientManager_CreateFirewallRule_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockGCPClientManager_CreateFirewallRule_Call) RunAndReturn(run func(projectID string, rule *computepb.Firewall) error) *MockGCPClientManager_CreateFirewallRule_Call { + _c.Call.Return(run) + return _c +} + +// CreateInstance provides a mock function for the type MockGCPClientManager +func (_mock *MockGCPClientManager) CreateInstance(projectID string, zone string, instance *computepb.Instance) error { + ret := _mock.Called(projectID, zone, instance) + + if len(ret) == 0 { + panic("no return value specified for CreateInstance") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(string, string, *computepb.Instance) error); ok { + r0 = returnFunc(projectID, zone, instance) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// MockGCPClientManager_CreateInstance_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateInstance' +type MockGCPClientManager_CreateInstance_Call struct { + *mock.Call +} + +// CreateInstance is a helper method to define mock.On call +// - projectID string +// - zone string +// - instance *computepb.Instance +func (_e *MockGCPClientManager_Expecter) CreateInstance(projectID interface{}, zone interface{}, instance interface{}) *MockGCPClientManager_CreateInstance_Call { + return &MockGCPClientManager_CreateInstance_Call{Call: _e.mock.On("CreateInstance", projectID, zone, instance)} +} + +func (_c *MockGCPClientManager_CreateInstance_Call) Run(run func(projectID string, zone string, instance *computepb.Instance)) *MockGCPClientManager_CreateInstance_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 *computepb.Instance + if args[2] != nil { + arg2 = args[2].(*computepb.Instance) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *MockGCPClientManager_CreateInstance_Call) Return(err error) *MockGCPClientManager_CreateInstance_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockGCPClientManager_CreateInstance_Call) RunAndReturn(run func(projectID string, zone string, instance *computepb.Instance) error) *MockGCPClientManager_CreateInstance_Call { + _c.Call.Return(run) + return _c +} + +// CreateProject provides a mock function for the type MockGCPClientManager +func (_mock *MockGCPClientManager) CreateProject(parent string, projectName string, displayName string) (string, error) { + ret := _mock.Called(parent, projectName, displayName) + + if len(ret) == 0 { + panic("no return value specified for CreateProject") + } + + var r0 string + var r1 error + if returnFunc, ok := ret.Get(0).(func(string, string, string) (string, error)); ok { + return returnFunc(parent, projectName, displayName) + } + if returnFunc, ok := ret.Get(0).(func(string, string, string) string); ok { + r0 = returnFunc(parent, projectName, displayName) + } else { + r0 = ret.Get(0).(string) + } + if returnFunc, ok := ret.Get(1).(func(string, string, string) error); ok { + r1 = returnFunc(parent, projectName, displayName) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// MockGCPClientManager_CreateProject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateProject' +type MockGCPClientManager_CreateProject_Call struct { + *mock.Call +} + +// CreateProject is a helper method to define mock.On call +// - parent string +// - projectName string +// - displayName string +func (_e *MockGCPClientManager_Expecter) CreateProject(parent interface{}, projectName interface{}, displayName interface{}) *MockGCPClientManager_CreateProject_Call { + return &MockGCPClientManager_CreateProject_Call{Call: _e.mock.On("CreateProject", parent, projectName, displayName)} +} + +func (_c *MockGCPClientManager_CreateProject_Call) Run(run func(parent string, projectName string, displayName string)) *MockGCPClientManager_CreateProject_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *MockGCPClientManager_CreateProject_Call) Return(s string, err error) *MockGCPClientManager_CreateProject_Call { + _c.Call.Return(s, err) + return _c +} + +func (_c *MockGCPClientManager_CreateProject_Call) RunAndReturn(run func(parent string, projectName string, displayName string) (string, error)) *MockGCPClientManager_CreateProject_Call { + _c.Call.Return(run) + return _c +} + +// CreateProjectID provides a mock function for the type MockGCPClientManager +func (_mock *MockGCPClientManager) CreateProjectID(projectName string) string { + ret := _mock.Called(projectName) + + if len(ret) == 0 { + panic("no return value specified for CreateProjectID") + } + + var r0 string + if returnFunc, ok := ret.Get(0).(func(string) string); ok { + r0 = returnFunc(projectName) + } else { + r0 = ret.Get(0).(string) + } + return r0 +} + +// MockGCPClientManager_CreateProjectID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateProjectID' +type MockGCPClientManager_CreateProjectID_Call struct { + *mock.Call +} + +// CreateProjectID is a helper method to define mock.On call +// - projectName string +func (_e *MockGCPClientManager_Expecter) CreateProjectID(projectName interface{}) *MockGCPClientManager_CreateProjectID_Call { + return &MockGCPClientManager_CreateProjectID_Call{Call: _e.mock.On("CreateProjectID", projectName)} +} + +func (_c *MockGCPClientManager_CreateProjectID_Call) Run(run func(projectName string)) *MockGCPClientManager_CreateProjectID_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + run( + arg0, + ) + }) + return _c +} + +func (_c *MockGCPClientManager_CreateProjectID_Call) Return(s string) *MockGCPClientManager_CreateProjectID_Call { + _c.Call.Return(s) + return _c +} + +func (_c *MockGCPClientManager_CreateProjectID_Call) RunAndReturn(run func(projectName string) string) *MockGCPClientManager_CreateProjectID_Call { + _c.Call.Return(run) + return _c +} + +// CreateServiceAccount provides a mock function for the type MockGCPClientManager +func (_mock *MockGCPClientManager) CreateServiceAccount(projectID string, name string, displayName string) (string, bool, error) { + ret := _mock.Called(projectID, name, displayName) + + if len(ret) == 0 { + panic("no return value specified for CreateServiceAccount") + } + + var r0 string + var r1 bool + var r2 error + if returnFunc, ok := ret.Get(0).(func(string, string, string) (string, bool, error)); ok { + return returnFunc(projectID, name, displayName) + } + if returnFunc, ok := ret.Get(0).(func(string, string, string) string); ok { + r0 = returnFunc(projectID, name, displayName) + } else { + r0 = ret.Get(0).(string) + } + if returnFunc, ok := ret.Get(1).(func(string, string, string) bool); ok { + r1 = returnFunc(projectID, name, displayName) + } else { + r1 = ret.Get(1).(bool) + } + if returnFunc, ok := ret.Get(2).(func(string, string, string) error); ok { + r2 = returnFunc(projectID, name, displayName) + } else { + r2 = ret.Error(2) + } + return r0, r1, r2 +} + +// MockGCPClientManager_CreateServiceAccount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateServiceAccount' +type MockGCPClientManager_CreateServiceAccount_Call struct { + *mock.Call +} + +// CreateServiceAccount is a helper method to define mock.On call +// - projectID string +// - name string +// - displayName string +func (_e *MockGCPClientManager_Expecter) CreateServiceAccount(projectID interface{}, name interface{}, displayName interface{}) *MockGCPClientManager_CreateServiceAccount_Call { + return &MockGCPClientManager_CreateServiceAccount_Call{Call: _e.mock.On("CreateServiceAccount", projectID, name, displayName)} +} + +func (_c *MockGCPClientManager_CreateServiceAccount_Call) Run(run func(projectID string, name string, displayName string)) *MockGCPClientManager_CreateServiceAccount_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *MockGCPClientManager_CreateServiceAccount_Call) Return(s string, b bool, err error) *MockGCPClientManager_CreateServiceAccount_Call { + _c.Call.Return(s, b, err) + return _c +} + +func (_c *MockGCPClientManager_CreateServiceAccount_Call) RunAndReturn(run func(projectID string, name string, displayName string) (string, bool, error)) *MockGCPClientManager_CreateServiceAccount_Call { + _c.Call.Return(run) + return _c +} + +// CreateServiceAccountKey provides a mock function for the type MockGCPClientManager +func (_mock *MockGCPClientManager) CreateServiceAccountKey(projectID string, saEmail string) (string, error) { + ret := _mock.Called(projectID, saEmail) + + if len(ret) == 0 { + panic("no return value specified for CreateServiceAccountKey") + } + + var r0 string + var r1 error + if returnFunc, ok := ret.Get(0).(func(string, string) (string, error)); ok { + return returnFunc(projectID, saEmail) + } + if returnFunc, ok := ret.Get(0).(func(string, string) string); ok { + r0 = returnFunc(projectID, saEmail) + } else { + r0 = ret.Get(0).(string) + } + if returnFunc, ok := ret.Get(1).(func(string, string) error); ok { + r1 = returnFunc(projectID, saEmail) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// MockGCPClientManager_CreateServiceAccountKey_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateServiceAccountKey' +type MockGCPClientManager_CreateServiceAccountKey_Call struct { + *mock.Call +} + +// CreateServiceAccountKey is a helper method to define mock.On call +// - projectID string +// - saEmail string +func (_e *MockGCPClientManager_Expecter) CreateServiceAccountKey(projectID interface{}, saEmail interface{}) *MockGCPClientManager_CreateServiceAccountKey_Call { + return &MockGCPClientManager_CreateServiceAccountKey_Call{Call: _e.mock.On("CreateServiceAccountKey", projectID, saEmail)} +} + +func (_c *MockGCPClientManager_CreateServiceAccountKey_Call) Run(run func(projectID string, saEmail string)) *MockGCPClientManager_CreateServiceAccountKey_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *MockGCPClientManager_CreateServiceAccountKey_Call) Return(s string, err error) *MockGCPClientManager_CreateServiceAccountKey_Call { + _c.Call.Return(s, err) + return _c +} + +func (_c *MockGCPClientManager_CreateServiceAccountKey_Call) RunAndReturn(run func(projectID string, saEmail string) (string, error)) *MockGCPClientManager_CreateServiceAccountKey_Call { + _c.Call.Return(run) + return _c +} + +// CreateVPC provides a mock function for the type MockGCPClientManager +func (_mock *MockGCPClientManager) CreateVPC(projectID string, region string, networkName string, subnetName string, routerName string, natName string) error { + ret := _mock.Called(projectID, region, networkName, subnetName, routerName, natName) + + if len(ret) == 0 { + panic("no return value specified for CreateVPC") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(string, string, string, string, string, string) error); ok { + r0 = returnFunc(projectID, region, networkName, subnetName, routerName, natName) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// MockGCPClientManager_CreateVPC_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateVPC' +type MockGCPClientManager_CreateVPC_Call struct { + *mock.Call +} + +// CreateVPC is a helper method to define mock.On call +// - projectID string +// - region string +// - networkName string +// - subnetName string +// - routerName string +// - natName string +func (_e *MockGCPClientManager_Expecter) CreateVPC(projectID interface{}, region interface{}, networkName interface{}, subnetName interface{}, routerName interface{}, natName interface{}) *MockGCPClientManager_CreateVPC_Call { + return &MockGCPClientManager_CreateVPC_Call{Call: _e.mock.On("CreateVPC", projectID, region, networkName, subnetName, routerName, natName)} +} + +func (_c *MockGCPClientManager_CreateVPC_Call) Run(run func(projectID string, region string, networkName string, subnetName string, routerName string, natName string)) *MockGCPClientManager_CreateVPC_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + var arg3 string + if args[3] != nil { + arg3 = args[3].(string) + } + var arg4 string + if args[4] != nil { + arg4 = args[4].(string) + } + var arg5 string + if args[5] != nil { + arg5 = args[5].(string) + } + run( + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + ) + }) + return _c +} + +func (_c *MockGCPClientManager_CreateVPC_Call) Return(err error) *MockGCPClientManager_CreateVPC_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockGCPClientManager_CreateVPC_Call) RunAndReturn(run func(projectID string, region string, networkName string, subnetName string, routerName string, natName string) error) *MockGCPClientManager_CreateVPC_Call { + _c.Call.Return(run) + return _c +} + +// EnableAPIs provides a mock function for the type MockGCPClientManager +func (_mock *MockGCPClientManager) EnableAPIs(projectID string, apis []string) error { + ret := _mock.Called(projectID, apis) + + if len(ret) == 0 { + panic("no return value specified for EnableAPIs") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(string, []string) error); ok { + r0 = returnFunc(projectID, apis) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// MockGCPClientManager_EnableAPIs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EnableAPIs' +type MockGCPClientManager_EnableAPIs_Call struct { + *mock.Call +} + +// EnableAPIs is a helper method to define mock.On call +// - projectID string +// - apis []string +func (_e *MockGCPClientManager_Expecter) EnableAPIs(projectID interface{}, apis interface{}) *MockGCPClientManager_EnableAPIs_Call { + return &MockGCPClientManager_EnableAPIs_Call{Call: _e.mock.On("EnableAPIs", projectID, apis)} +} + +func (_c *MockGCPClientManager_EnableAPIs_Call) Run(run func(projectID string, apis []string)) *MockGCPClientManager_EnableAPIs_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 []string + if args[1] != nil { + arg1 = args[1].([]string) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *MockGCPClientManager_EnableAPIs_Call) Return(err error) *MockGCPClientManager_EnableAPIs_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockGCPClientManager_EnableAPIs_Call) RunAndReturn(run func(projectID string, apis []string) error) *MockGCPClientManager_EnableAPIs_Call { + _c.Call.Return(run) + return _c +} + +// EnableBilling provides a mock function for the type MockGCPClientManager +func (_mock *MockGCPClientManager) EnableBilling(projectID string, billingAccount string) error { + ret := _mock.Called(projectID, billingAccount) + + if len(ret) == 0 { + panic("no return value specified for EnableBilling") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(string, string) error); ok { + r0 = returnFunc(projectID, billingAccount) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// MockGCPClientManager_EnableBilling_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EnableBilling' +type MockGCPClientManager_EnableBilling_Call struct { + *mock.Call +} + +// EnableBilling is a helper method to define mock.On call +// - projectID string +// - billingAccount string +func (_e *MockGCPClientManager_Expecter) EnableBilling(projectID interface{}, billingAccount interface{}) *MockGCPClientManager_EnableBilling_Call { + return &MockGCPClientManager_EnableBilling_Call{Call: _e.mock.On("EnableBilling", projectID, billingAccount)} +} + +func (_c *MockGCPClientManager_EnableBilling_Call) Run(run func(projectID string, billingAccount string)) *MockGCPClientManager_EnableBilling_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *MockGCPClientManager_EnableBilling_Call) Return(err error) *MockGCPClientManager_EnableBilling_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockGCPClientManager_EnableBilling_Call) RunAndReturn(run func(projectID string, billingAccount string) error) *MockGCPClientManager_EnableBilling_Call { + _c.Call.Return(run) + return _c +} + +// EnsureDNSManagedZone provides a mock function for the type MockGCPClientManager +func (_mock *MockGCPClientManager) EnsureDNSManagedZone(projectID string, zoneName string, dnsName string, description string) error { + ret := _mock.Called(projectID, zoneName, dnsName, description) + + if len(ret) == 0 { + panic("no return value specified for EnsureDNSManagedZone") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(string, string, string, string) error); ok { + r0 = returnFunc(projectID, zoneName, dnsName, description) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// MockGCPClientManager_EnsureDNSManagedZone_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EnsureDNSManagedZone' +type MockGCPClientManager_EnsureDNSManagedZone_Call struct { + *mock.Call +} + +// EnsureDNSManagedZone is a helper method to define mock.On call +// - projectID string +// - zoneName string +// - dnsName string +// - description string +func (_e *MockGCPClientManager_Expecter) EnsureDNSManagedZone(projectID interface{}, zoneName interface{}, dnsName interface{}, description interface{}) *MockGCPClientManager_EnsureDNSManagedZone_Call { + return &MockGCPClientManager_EnsureDNSManagedZone_Call{Call: _e.mock.On("EnsureDNSManagedZone", projectID, zoneName, dnsName, description)} +} + +func (_c *MockGCPClientManager_EnsureDNSManagedZone_Call) Run(run func(projectID string, zoneName string, dnsName string, description string)) *MockGCPClientManager_EnsureDNSManagedZone_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + var arg3 string + if args[3] != nil { + arg3 = args[3].(string) + } + run( + arg0, + arg1, + arg2, + arg3, + ) + }) + return _c +} + +func (_c *MockGCPClientManager_EnsureDNSManagedZone_Call) Return(err error) *MockGCPClientManager_EnsureDNSManagedZone_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockGCPClientManager_EnsureDNSManagedZone_Call) RunAndReturn(run func(projectID string, zoneName string, dnsName string, description string) error) *MockGCPClientManager_EnsureDNSManagedZone_Call { + _c.Call.Return(run) + return _c +} + +// EnsureDNSRecordSets provides a mock function for the type MockGCPClientManager +func (_mock *MockGCPClientManager) EnsureDNSRecordSets(projectID string, zoneName string, records []*dns.ResourceRecordSet) error { + ret := _mock.Called(projectID, zoneName, records) + + if len(ret) == 0 { + panic("no return value specified for EnsureDNSRecordSets") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(string, string, []*dns.ResourceRecordSet) error); ok { + r0 = returnFunc(projectID, zoneName, records) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// MockGCPClientManager_EnsureDNSRecordSets_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EnsureDNSRecordSets' +type MockGCPClientManager_EnsureDNSRecordSets_Call struct { + *mock.Call +} + +// EnsureDNSRecordSets is a helper method to define mock.On call +// - projectID string +// - zoneName string +// - records []*dns.ResourceRecordSet +func (_e *MockGCPClientManager_Expecter) EnsureDNSRecordSets(projectID interface{}, zoneName interface{}, records interface{}) *MockGCPClientManager_EnsureDNSRecordSets_Call { + return &MockGCPClientManager_EnsureDNSRecordSets_Call{Call: _e.mock.On("EnsureDNSRecordSets", projectID, zoneName, records)} +} + +func (_c *MockGCPClientManager_EnsureDNSRecordSets_Call) Run(run func(projectID string, zoneName string, records []*dns.ResourceRecordSet)) *MockGCPClientManager_EnsureDNSRecordSets_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 []*dns.ResourceRecordSet + if args[2] != nil { + arg2 = args[2].([]*dns.ResourceRecordSet) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *MockGCPClientManager_EnsureDNSRecordSets_Call) Return(err error) *MockGCPClientManager_EnsureDNSRecordSets_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockGCPClientManager_EnsureDNSRecordSets_Call) RunAndReturn(run func(projectID string, zoneName string, records []*dns.ResourceRecordSet) error) *MockGCPClientManager_EnsureDNSRecordSets_Call { + _c.Call.Return(run) + return _c +} + +// GetAddress provides a mock function for the type MockGCPClientManager +func (_mock *MockGCPClientManager) GetAddress(projectID string, region string, addressName string) (*computepb.Address, error) { + ret := _mock.Called(projectID, region, addressName) + + if len(ret) == 0 { + panic("no return value specified for GetAddress") + } + + var r0 *computepb.Address + var r1 error + if returnFunc, ok := ret.Get(0).(func(string, string, string) (*computepb.Address, error)); ok { + return returnFunc(projectID, region, addressName) + } + if returnFunc, ok := ret.Get(0).(func(string, string, string) *computepb.Address); ok { + r0 = returnFunc(projectID, region, addressName) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*computepb.Address) + } + } + if returnFunc, ok := ret.Get(1).(func(string, string, string) error); ok { + r1 = returnFunc(projectID, region, addressName) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// MockGCPClientManager_GetAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAddress' +type MockGCPClientManager_GetAddress_Call struct { + *mock.Call +} + +// GetAddress is a helper method to define mock.On call +// - projectID string +// - region string +// - addressName string +func (_e *MockGCPClientManager_Expecter) GetAddress(projectID interface{}, region interface{}, addressName interface{}) *MockGCPClientManager_GetAddress_Call { + return &MockGCPClientManager_GetAddress_Call{Call: _e.mock.On("GetAddress", projectID, region, addressName)} +} + +func (_c *MockGCPClientManager_GetAddress_Call) Run(run func(projectID string, region string, addressName string)) *MockGCPClientManager_GetAddress_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *MockGCPClientManager_GetAddress_Call) Return(address *computepb.Address, err error) *MockGCPClientManager_GetAddress_Call { + _c.Call.Return(address, err) + return _c +} + +func (_c *MockGCPClientManager_GetAddress_Call) RunAndReturn(run func(projectID string, region string, addressName string) (*computepb.Address, error)) *MockGCPClientManager_GetAddress_Call { + _c.Call.Return(run) + return _c +} + +// GetArtifactRegistry provides a mock function for the type MockGCPClientManager +func (_mock *MockGCPClientManager) GetArtifactRegistry(projectID string, region string, repoName string) (*artifactregistrypb.Repository, error) { + ret := _mock.Called(projectID, region, repoName) + + if len(ret) == 0 { + panic("no return value specified for GetArtifactRegistry") + } + + var r0 *artifactregistrypb.Repository + var r1 error + if returnFunc, ok := ret.Get(0).(func(string, string, string) (*artifactregistrypb.Repository, error)); ok { + return returnFunc(projectID, region, repoName) + } + if returnFunc, ok := ret.Get(0).(func(string, string, string) *artifactregistrypb.Repository); ok { + r0 = returnFunc(projectID, region, repoName) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*artifactregistrypb.Repository) + } + } + if returnFunc, ok := ret.Get(1).(func(string, string, string) error); ok { + r1 = returnFunc(projectID, region, repoName) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// MockGCPClientManager_GetArtifactRegistry_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetArtifactRegistry' +type MockGCPClientManager_GetArtifactRegistry_Call struct { + *mock.Call +} + +// GetArtifactRegistry is a helper method to define mock.On call +// - projectID string +// - region string +// - repoName string +func (_e *MockGCPClientManager_Expecter) GetArtifactRegistry(projectID interface{}, region interface{}, repoName interface{}) *MockGCPClientManager_GetArtifactRegistry_Call { + return &MockGCPClientManager_GetArtifactRegistry_Call{Call: _e.mock.On("GetArtifactRegistry", projectID, region, repoName)} +} + +func (_c *MockGCPClientManager_GetArtifactRegistry_Call) Run(run func(projectID string, region string, repoName string)) *MockGCPClientManager_GetArtifactRegistry_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *MockGCPClientManager_GetArtifactRegistry_Call) Return(repository *artifactregistrypb.Repository, err error) *MockGCPClientManager_GetArtifactRegistry_Call { + _c.Call.Return(repository, err) + return _c +} + +func (_c *MockGCPClientManager_GetArtifactRegistry_Call) RunAndReturn(run func(projectID string, region string, repoName string) (*artifactregistrypb.Repository, error)) *MockGCPClientManager_GetArtifactRegistry_Call { + _c.Call.Return(run) + return _c +} + +// GetBillingInfo provides a mock function for the type MockGCPClientManager +func (_mock *MockGCPClientManager) GetBillingInfo(projectID string) (*cloudbilling.ProjectBillingInfo, error) { + ret := _mock.Called(projectID) + + if len(ret) == 0 { + panic("no return value specified for GetBillingInfo") + } + + var r0 *cloudbilling.ProjectBillingInfo + var r1 error + if returnFunc, ok := ret.Get(0).(func(string) (*cloudbilling.ProjectBillingInfo, error)); ok { + return returnFunc(projectID) + } + if returnFunc, ok := ret.Get(0).(func(string) *cloudbilling.ProjectBillingInfo); ok { + r0 = returnFunc(projectID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*cloudbilling.ProjectBillingInfo) + } + } + if returnFunc, ok := ret.Get(1).(func(string) error); ok { + r1 = returnFunc(projectID) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// MockGCPClientManager_GetBillingInfo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBillingInfo' +type MockGCPClientManager_GetBillingInfo_Call struct { + *mock.Call +} + +// GetBillingInfo is a helper method to define mock.On call +// - projectID string +func (_e *MockGCPClientManager_Expecter) GetBillingInfo(projectID interface{}) *MockGCPClientManager_GetBillingInfo_Call { + return &MockGCPClientManager_GetBillingInfo_Call{Call: _e.mock.On("GetBillingInfo", projectID)} +} + +func (_c *MockGCPClientManager_GetBillingInfo_Call) Run(run func(projectID string)) *MockGCPClientManager_GetBillingInfo_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + run( + arg0, + ) + }) + return _c +} + +func (_c *MockGCPClientManager_GetBillingInfo_Call) Return(projectBillingInfo *cloudbilling.ProjectBillingInfo, err error) *MockGCPClientManager_GetBillingInfo_Call { + _c.Call.Return(projectBillingInfo, err) + return _c +} + +func (_c *MockGCPClientManager_GetBillingInfo_Call) RunAndReturn(run func(projectID string) (*cloudbilling.ProjectBillingInfo, error)) *MockGCPClientManager_GetBillingInfo_Call { + _c.Call.Return(run) + return _c +} + +// GetInstance provides a mock function for the type MockGCPClientManager +func (_mock *MockGCPClientManager) GetInstance(projectID string, zone string, instanceName string) (*computepb.Instance, error) { + ret := _mock.Called(projectID, zone, instanceName) + + if len(ret) == 0 { + panic("no return value specified for GetInstance") + } + + var r0 *computepb.Instance + var r1 error + if returnFunc, ok := ret.Get(0).(func(string, string, string) (*computepb.Instance, error)); ok { + return returnFunc(projectID, zone, instanceName) + } + if returnFunc, ok := ret.Get(0).(func(string, string, string) *computepb.Instance); ok { + r0 = returnFunc(projectID, zone, instanceName) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*computepb.Instance) + } + } + if returnFunc, ok := ret.Get(1).(func(string, string, string) error); ok { + r1 = returnFunc(projectID, zone, instanceName) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// MockGCPClientManager_GetInstance_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetInstance' +type MockGCPClientManager_GetInstance_Call struct { + *mock.Call +} + +// GetInstance is a helper method to define mock.On call +// - projectID string +// - zone string +// - instanceName string +func (_e *MockGCPClientManager_Expecter) GetInstance(projectID interface{}, zone interface{}, instanceName interface{}) *MockGCPClientManager_GetInstance_Call { + return &MockGCPClientManager_GetInstance_Call{Call: _e.mock.On("GetInstance", projectID, zone, instanceName)} +} + +func (_c *MockGCPClientManager_GetInstance_Call) Run(run func(projectID string, zone string, instanceName string)) *MockGCPClientManager_GetInstance_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *MockGCPClientManager_GetInstance_Call) Return(instance *computepb.Instance, err error) *MockGCPClientManager_GetInstance_Call { + _c.Call.Return(instance, err) + return _c +} + +func (_c *MockGCPClientManager_GetInstance_Call) RunAndReturn(run func(projectID string, zone string, instanceName string) (*computepb.Instance, error)) *MockGCPClientManager_GetInstance_Call { + _c.Call.Return(run) + return _c +} + +// GetProjectByName provides a mock function for the type MockGCPClientManager +func (_mock *MockGCPClientManager) GetProjectByName(folderID string, displayName string) (*resourcemanagerpb.Project, error) { + ret := _mock.Called(folderID, displayName) + + if len(ret) == 0 { + panic("no return value specified for GetProjectByName") + } + + var r0 *resourcemanagerpb.Project + var r1 error + if returnFunc, ok := ret.Get(0).(func(string, string) (*resourcemanagerpb.Project, error)); ok { + return returnFunc(folderID, displayName) + } + if returnFunc, ok := ret.Get(0).(func(string, string) *resourcemanagerpb.Project); ok { + r0 = returnFunc(folderID, displayName) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*resourcemanagerpb.Project) + } + } + if returnFunc, ok := ret.Get(1).(func(string, string) error); ok { + r1 = returnFunc(folderID, displayName) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// MockGCPClientManager_GetProjectByName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetProjectByName' +type MockGCPClientManager_GetProjectByName_Call struct { + *mock.Call +} + +// GetProjectByName is a helper method to define mock.On call +// - folderID string +// - displayName string +func (_e *MockGCPClientManager_Expecter) GetProjectByName(folderID interface{}, displayName interface{}) *MockGCPClientManager_GetProjectByName_Call { + return &MockGCPClientManager_GetProjectByName_Call{Call: _e.mock.On("GetProjectByName", folderID, displayName)} +} + +func (_c *MockGCPClientManager_GetProjectByName_Call) Run(run func(folderID string, displayName string)) *MockGCPClientManager_GetProjectByName_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *MockGCPClientManager_GetProjectByName_Call) Return(project *resourcemanagerpb.Project, err error) *MockGCPClientManager_GetProjectByName_Call { + _c.Call.Return(project, err) + return _c +} + +func (_c *MockGCPClientManager_GetProjectByName_Call) RunAndReturn(run func(folderID string, displayName string) (*resourcemanagerpb.Project, error)) *MockGCPClientManager_GetProjectByName_Call { + _c.Call.Return(run) + return _c +} diff --git a/internal/bootstrap/gcp_client.go b/internal/bootstrap/gcp_client.go deleted file mode 100644 index 9e93e032..00000000 --- a/internal/bootstrap/gcp_client.go +++ /dev/null @@ -1,440 +0,0 @@ -// Copyright (c) Codesphere Inc. -// SPDX-License-Identifier: Apache-2.0 - -package bootstrap - -import ( - "context" - "fmt" - "log" - "strings" - "sync" - - "slices" - - artifact "cloud.google.com/go/artifactregistry/apiv1" - artifactpb "cloud.google.com/go/artifactregistry/apiv1/artifactregistrypb" - compute "cloud.google.com/go/compute/apiv1" - "cloud.google.com/go/compute/apiv1/computepb" - "cloud.google.com/go/iam/apiv1/iampb" - resourcemanager "cloud.google.com/go/resourcemanager/apiv3" - "cloud.google.com/go/resourcemanager/apiv3/resourcemanagerpb" - serviceusage "cloud.google.com/go/serviceusage/apiv1" - "cloud.google.com/go/serviceusage/apiv1/serviceusagepb" - "github.com/codesphere-cloud/oms/internal/util" - "google.golang.org/api/cloudbilling/v1" - "google.golang.org/api/iam/v1" - "google.golang.org/api/iterator" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -// Interface for high-level GCP operations -type GCPClient interface { - GetProjectByName(ctx context.Context, folderID string, displayName string) (*resourcemanagerpb.Project, error) - CreateProject(ctx context.Context, parent, projectName, displayName string) (string, error) - GetBillingInfo(projectID string) (*cloudbilling.ProjectBillingInfo, error) - EnableBilling(ctx context.Context, projectID, billingAccount string) error - EnableAPIs(ctx context.Context, projectID string, apis []string) error - GetArtifactRegistry(ctx context.Context, projectID, region, repoName string) (*artifactpb.Repository, error) - CreateArtifactRegistry(ctx context.Context, projectID, region, repoName string) (*artifactpb.Repository, error) - CreateServiceAccount(ctx context.Context, projectID, name, displayName string) (string, bool, error) - CreateServiceAccountKey(ctx context.Context, projectID, saEmail string) (string, error) - AssignIAMRole(ctx context.Context, projectID, saEmail, role string) error - CreateVPC(ctx context.Context, projectID, region, networkName, subnetName, routerName, natName string) error - CreateFirewallRule(ctx context.Context, projectID string, rule *computepb.Firewall) error -} - -// Concrete implementation -type RealGCPClient struct { - CredentialsFile string -} - -func NewGCPClient(credentialsFile string) *RealGCPClient { - return &RealGCPClient{ - CredentialsFile: credentialsFile, - } -} - -func (c *RealGCPClient) GetProjectByName(ctx context.Context, folderID string, displayName string) (*resourcemanagerpb.Project, error) { - client, err := resourcemanager.NewProjectsClient(ctx) - if err != nil { - return nil, err - } - defer util.IgnoreError(client.Close) - req := &resourcemanagerpb.ListProjectsRequest{ - Parent: fmt.Sprintf("folders/%s", folderID), - ShowDeleted: false, - } - - it := client.ListProjects(ctx, req) - - for { - project, err := it.Next() - if err == iterator.Done { - // No more results found - return nil, fmt.Errorf("project not found: %s", displayName) - } - if err != nil { - return nil, fmt.Errorf("error iterating projects: %w", err) - } - - // Because the filter is a prefix search on the display name, - // we should perform an exact match check here to be sure. - if project.GetDisplayName() == displayName { - return project, nil - } - } -} - -func (c *RealGCPClient) CreateProject(ctx context.Context, parent, projectID, displayName string) (string, error) { - client, err := resourcemanager.NewProjectsClient(ctx) - if err != nil { - return "", err - } - defer util.IgnoreError(client.Close) - project := &resourcemanagerpb.Project{ - ProjectId: projectID, - DisplayName: displayName, - Parent: parent, - } - op, err := client.CreateProject(ctx, &resourcemanagerpb.CreateProjectRequest{Project: project}) - if err != nil { - return "", err - } - resp, err := op.Wait(ctx) - if err != nil { - return "", err - } - return resp.ProjectId, nil -} - -func getProjectResourceName(projectID string) string { - return fmt.Sprintf("projects/%s", projectID) -} - -func (c *RealGCPClient) GetBillingInfo(projectID string) (*cloudbilling.ProjectBillingInfo, error) { - projectName := getProjectResourceName(projectID) - billingService, err := cloudbilling.NewService(context.Background()) - if err != nil { - return nil, err - } - billingInfo, err := billingService.Projects.GetBillingInfo(projectName).Do() - if err != nil { - return nil, err - } - return billingInfo, nil -} - -func (c *RealGCPClient) EnableBilling(ctx context.Context, projectID, billingAccount string) error { - billingService, err := cloudbilling.NewService(ctx) - if err != nil { - return err - } - projectName := getProjectResourceName(projectID) - billingInfo := &cloudbilling.ProjectBillingInfo{ - BillingAccountName: fmt.Sprintf("billingAccounts/%s", billingAccount), - } - _, err = billingService.Projects.UpdateBillingInfo(projectName, billingInfo).Context(ctx).Do() - return err -} - -func (c *RealGCPClient) EnableAPIs(ctx context.Context, projectID string, apis []string) error { - client, err := serviceusage.NewClient(ctx) - if err != nil { - return err - } - defer util.IgnoreError(client.Close) - // enable APIs in parallel - wg := sync.WaitGroup{} - errCh := make(chan error, len(apis)) - for _, api := range apis { - serviceName := fmt.Sprintf("projects/%s/services/%s", projectID, api) - wg.Add(1) - - go func(serviceName, api string) { - defer wg.Done() - - log.Printf("Enabling API %s", api) - - op, err := client.EnableService(ctx, &serviceusagepb.EnableServiceRequest{Name: serviceName}) - if status.Code(err) == codes.AlreadyExists { - log.Printf("API %s already enabled", api) - - return - } - if err != nil { - errCh <- fmt.Errorf("failed to enable API %s: %w", api, err) - } - if _, err := op.Wait(ctx); err != nil { - errCh <- fmt.Errorf("failed to enable API %s: %w", api, err) - } - - log.Printf("API %s enabled", api) - }(serviceName, api) - } - - wg.Wait() - close(errCh) - errStr := "" - for err := range errCh { - errStr += err.Error() + "; " - } - if len(errStr) > 0 { - return fmt.Errorf("errors occurred while enabling APIs: %s", errStr) - } - return nil -} - -func (c *RealGCPClient) CreateArtifactRegistry(ctx context.Context, projectID, region, repoName string) (*artifactpb.Repository, error) { - client, err := artifact.NewClient(ctx) - if err != nil { - return nil, err - } - defer util.IgnoreError(client.Close) - - parent := fmt.Sprintf("projects/%s/locations/%s", projectID, region) - repoReq := &artifactpb.CreateRepositoryRequest{ - Parent: parent, - RepositoryId: repoName, - Repository: &artifactpb.Repository{ - Format: artifactpb.Repository_DOCKER, - Description: "Codesphere managed registry", - }, - } - - op, err := client.CreateRepository(ctx, repoReq) - if err != nil && !strings.Contains(err.Error(), "already exists") { - return nil, err - } - - _, err = op.Wait(ctx) - if err != nil { - return nil, err - } - - // get repo again to ensure all infos are stored, else e.g. uri would be missing - repo, err := c.GetArtifactRegistry(ctx, projectID, region, repoName) - if err != nil { - return nil, fmt.Errorf("failed to get newly created artifact registry: %w", err) - } - - return repo, nil -} - -func (c *RealGCPClient) GetArtifactRegistry(ctx context.Context, projectID, region, repoName string) (*artifactpb.Repository, error) { - fullRepoName := fmt.Sprintf("projects/%s/locations/%s/repositories/%s", projectID, region, repoName) - client, err := artifact.NewClient(ctx) - if err != nil { - return nil, err - } - defer util.IgnoreError(client.Close) - repo, err := client.GetRepository(ctx, &artifactpb.GetRepositoryRequest{ - Name: fullRepoName, - }) - if err != nil { - return nil, fmt.Errorf("failed to get artifact registry repository: %w", err) - } - return repo, nil -} - -func (c *RealGCPClient) CreateServiceAccount(ctx context.Context, projectID, name, displayName string) (string, bool, error) { - saMail := fmt.Sprintf("%s@%s.iam.gserviceaccount.com", name, projectID) - iamService, err := iam.NewService(ctx) - if err != nil { - return saMail, false, err - } - saReq := &iam.CreateServiceAccountRequest{ - AccountId: name, - ServiceAccount: &iam.ServiceAccount{ - DisplayName: displayName, - }, - } - _, err = iamService.Projects.ServiceAccounts.Create(fmt.Sprintf("projects/%s", projectID), saReq).Context(ctx).Do() - if err != nil && !strings.Contains(err.Error(), "already exists") { - return saMail, false, err - } - if err != nil && strings.Contains(err.Error(), "already exists") { - return saMail, false, nil - } - return saMail, true, nil -} - -func (c *RealGCPClient) CreateServiceAccountKey(ctx context.Context, projectID, saEmail string) (string, error) { - iamService, err := iam.NewService(ctx) - if err != nil { - return "", err - } - keyReq := &iam.CreateServiceAccountKeyRequest{} - saName := fmt.Sprintf("projects/%s/serviceAccounts/%s", projectID, saEmail) - key, err := iamService.Projects.ServiceAccounts.Keys.Create(saName, keyReq).Context(ctx).Do() - if err != nil { - return "", err - } - return string(key.PrivateKeyData), nil -} - -func (c *RealGCPClient) AssignIAMRole(ctx context.Context, projectID, saName, role string) error { - saEmail := fmt.Sprintf("%s@%s.iam.gserviceaccount.com", saName, projectID) - client, err := resourcemanager.NewProjectsClient(ctx) - if err != nil { - return err - } - defer util.IgnoreError(client.Close) - getReq := &iampb.GetIamPolicyRequest{ - Resource: fmt.Sprintf("projects/%s", projectID), - } - policy, err := client.GetIamPolicy(ctx, getReq) - if err != nil { - return err - } - member := fmt.Sprintf("serviceAccount:%s", saEmail) - // Check if already assigned - for _, binding := range policy.Bindings { - if binding.Role == role { - if slices.Contains(binding.Members, member) { - return nil - } - } - } - policy.Bindings = append(policy.Bindings, &iampb.Binding{ - Role: role, - Members: []string{member}, - }) - setReq := &iampb.SetIamPolicyRequest{ - Resource: fmt.Sprintf("projects/%s", projectID), - Policy: policy, - } - _, err = client.SetIamPolicy(ctx, setReq) - return err -} - -func (c *RealGCPClient) CreateVPC(ctx context.Context, projectID, region, networkName, subnetName, routerName, natName string) error { - networksClient, err := compute.NewNetworksRESTClient(ctx) - if err != nil { - return err - } - defer util.IgnoreError(networksClient.Close) - network := &computepb.Network{ - Name: &networkName, - AutoCreateSubnetworks: protoBool(false), - } - op, err := networksClient.Insert(ctx, &computepb.InsertNetworkRequest{ - Project: projectID, - NetworkResource: network, - }) - if err != nil && !strings.Contains(err.Error(), "already exists") { - return err - } - if err == nil { - if err := op.Wait(ctx); err != nil { - return err - } - } - subnetsClient, err := compute.NewSubnetworksRESTClient(ctx) - if err != nil { - return err - } - defer util.IgnoreError(subnetsClient.Close) - subnet := &computepb.Subnetwork{ - Name: &subnetName, - IpCidrRange: protoString("10.10.0.0/20"), - Region: ®ion, - Network: protoString(fmt.Sprintf("projects/%s/global/networks/%s", projectID, networkName)), - } - op, err = subnetsClient.Insert(ctx, &computepb.InsertSubnetworkRequest{ - Project: projectID, - Region: region, - SubnetworkResource: subnet, - }) - if err != nil && !strings.Contains(err.Error(), "already exists") { - return err - } - if err == nil { - if err := op.Wait(ctx); err != nil { - return err - } - } - - // Create Router - routersClient, err := compute.NewRoutersRESTClient(ctx) - if err != nil { - return fmt.Errorf("failed to create routers client: %w", err) - } - defer util.IgnoreError(routersClient.Close) - - router := &computepb.Router{ - Name: &routerName, - Region: ®ion, - Network: protoString(fmt.Sprintf("projects/%s/global/networks/%s", projectID, networkName)), - } - op, err = routersClient.Insert(ctx, &computepb.InsertRouterRequest{ - Project: projectID, - Region: region, - RouterResource: router, - }) - if err != nil && !isAlreadyExistsError(err) { - return fmt.Errorf("failed to create router: %w", err) - } - if err == nil { - if err := op.Wait(ctx); err != nil { - return fmt.Errorf("failed to wait for router creation: %w", err) - } - } - - log.Printf("Router %s ensured", routerName) - - // Create NAT Gateway - natsClient, err := compute.NewRoutersRESTClient(ctx) - if err != nil { - return fmt.Errorf("failed to create routers client for NAT: %w", err) - } - defer util.IgnoreError(natsClient.Close) - - nat := &computepb.RouterNat{ - Name: &natName, - SourceSubnetworkIpRangesToNat: protoString("ALL_SUBNETWORKS_ALL_IP_RANGES"), - NatIpAllocateOption: protoString("AUTO_ONLY"), - LogConfig: &computepb.RouterNatLogConfig{ - Enable: protoBool(false), - Filter: protoString("ERRORS_ONLY"), - }, - } - // Patch NAT config to router - _, err = routersClient.Patch(ctx, &computepb.PatchRouterRequest{ - Project: projectID, - Region: region, - Router: routerName, - RouterResource: &computepb.Router{ - Name: &routerName, - Nats: []*computepb.RouterNat{nat}, - }, - }) - if err != nil && !isAlreadyExistsError(err) { - return fmt.Errorf("failed to create NAT gateway: %w", err) - } - - log.Printf("NAT gateway %s ensured", natName) - - return nil -} - -func (c *RealGCPClient) CreateFirewallRule(ctx context.Context, projectID string, rule *computepb.Firewall) error { - firewallsClient, err := compute.NewFirewallsRESTClient(ctx) - if err != nil { - return err - } - defer util.IgnoreError(firewallsClient.Close) - _, err = firewallsClient.Insert(ctx, &computepb.InsertFirewallRequest{ - Project: projectID, - FirewallResource: rule, - }) - if err != nil && !strings.Contains(err.Error(), "already exists") { - return err - } - return nil -} - -// Helper functions -func protoString(s string) *string { return &s } -func protoBool(b bool) *bool { return &b } diff --git a/internal/bootstrap/ovh/ovh.go b/internal/bootstrap/ovh/ovh.go new file mode 100644 index 00000000..cc7e224c --- /dev/null +++ b/internal/bootstrap/ovh/ovh.go @@ -0,0 +1,12 @@ +package ovh + +import "log" + +type OVHBootstrapper struct { + // Implementation details would go here +} + +func NewOVHBootstrapper() *OVHBootstrapper { + log.Println("OVH Bootstrapper not yet implemented") + return &OVHBootstrapper{} +} diff --git a/internal/installer/config_manager_profile.go b/internal/installer/config_manager_profile.go index fea5c44a..2709f6a9 100644 --- a/internal/installer/config_manager_profile.go +++ b/internal/installer/config_manager_profile.go @@ -5,7 +5,6 @@ package installer import ( "fmt" - "log" "github.com/codesphere-cloud/oms/internal/installer/files" ) @@ -121,7 +120,6 @@ func (g *InstallConfig) ApplyProfile(profile string) error { g.Config.Codesphere.WorkspaceHostingBaseDomain = "ws.local" g.Config.Codesphere.CustomDomains.CNameBaseDomain = "custom.local" g.Config.Codesphere.DNSServers = []string{"8.8.8.8", "1.1.1.1"} - log.Println("Applied 'dev' profile: single-node development setup") case PROFILE_PROD, PROFILE_PRODUCTION: g.Config.Datacenter.Name = "production" @@ -160,7 +158,6 @@ func (g *InstallConfig) ApplyProfile(profile string) error { OnDemand: true, }, } - log.Println("Applied 'production' profile: HA multi-node setup") case PROFILE_MINIMAL: g.Config.Datacenter.Name = "minimal" @@ -184,7 +181,6 @@ func (g *InstallConfig) ApplyProfile(profile string) error { OnDemand: true, }, } - log.Println("Applied 'minimal' profile: minimal single-node setup") default: return fmt.Errorf("unknown profile: %s, available profiles: dev, prod, minimal", profile) diff --git a/internal/installer/node/mocks.go b/internal/installer/node/mocks.go new file mode 100644 index 00000000..6b28e4fb --- /dev/null +++ b/internal/installer/node/mocks.go @@ -0,0 +1,955 @@ +// Code generated by mockery; DO NOT EDIT. +// github.com/vektra/mockery +// template: testify + +package node + +import ( + mock "github.com/stretchr/testify/mock" + "time" +) + +// NewMockNodeManager creates a new instance of MockNodeManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockNodeManager(t interface { + mock.TestingT + Cleanup(func()) +}) *MockNodeManager { + mock := &MockNodeManager{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} + +// MockNodeManager is an autogenerated mock type for the NodeManager type +type MockNodeManager struct { + mock.Mock +} + +type MockNodeManager_Expecter struct { + mock *mock.Mock +} + +func (_m *MockNodeManager) EXPECT() *MockNodeManager_Expecter { + return &MockNodeManager_Expecter{mock: &_m.Mock} +} + +// ConfigureAcceptEnv provides a mock function for the type MockNodeManager +func (_mock *MockNodeManager) ConfigureAcceptEnv() error { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for ConfigureAcceptEnv") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func() error); ok { + r0 = returnFunc() + } else { + r0 = ret.Error(0) + } + return r0 +} + +// MockNodeManager_ConfigureAcceptEnv_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConfigureAcceptEnv' +type MockNodeManager_ConfigureAcceptEnv_Call struct { + *mock.Call +} + +// ConfigureAcceptEnv is a helper method to define mock.On call +func (_e *MockNodeManager_Expecter) ConfigureAcceptEnv() *MockNodeManager_ConfigureAcceptEnv_Call { + return &MockNodeManager_ConfigureAcceptEnv_Call{Call: _e.mock.On("ConfigureAcceptEnv")} +} + +func (_c *MockNodeManager_ConfigureAcceptEnv_Call) Run(run func()) *MockNodeManager_ConfigureAcceptEnv_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockNodeManager_ConfigureAcceptEnv_Call) Return(err error) *MockNodeManager_ConfigureAcceptEnv_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockNodeManager_ConfigureAcceptEnv_Call) RunAndReturn(run func() error) *MockNodeManager_ConfigureAcceptEnv_Call { + _c.Call.Return(run) + return _c +} + +// ConfigureInotifyWatches provides a mock function for the type MockNodeManager +func (_mock *MockNodeManager) ConfigureInotifyWatches() error { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for ConfigureInotifyWatches") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func() error); ok { + r0 = returnFunc() + } else { + r0 = ret.Error(0) + } + return r0 +} + +// MockNodeManager_ConfigureInotifyWatches_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConfigureInotifyWatches' +type MockNodeManager_ConfigureInotifyWatches_Call struct { + *mock.Call +} + +// ConfigureInotifyWatches is a helper method to define mock.On call +func (_e *MockNodeManager_Expecter) ConfigureInotifyWatches() *MockNodeManager_ConfigureInotifyWatches_Call { + return &MockNodeManager_ConfigureInotifyWatches_Call{Call: _e.mock.On("ConfigureInotifyWatches")} +} + +func (_c *MockNodeManager_ConfigureInotifyWatches_Call) Run(run func()) *MockNodeManager_ConfigureInotifyWatches_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockNodeManager_ConfigureInotifyWatches_Call) Return(err error) *MockNodeManager_ConfigureInotifyWatches_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockNodeManager_ConfigureInotifyWatches_Call) RunAndReturn(run func() error) *MockNodeManager_ConfigureInotifyWatches_Call { + _c.Call.Return(run) + return _c +} + +// ConfigureMemoryMap provides a mock function for the type MockNodeManager +func (_mock *MockNodeManager) ConfigureMemoryMap() error { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for ConfigureMemoryMap") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func() error); ok { + r0 = returnFunc() + } else { + r0 = ret.Error(0) + } + return r0 +} + +// MockNodeManager_ConfigureMemoryMap_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConfigureMemoryMap' +type MockNodeManager_ConfigureMemoryMap_Call struct { + *mock.Call +} + +// ConfigureMemoryMap is a helper method to define mock.On call +func (_e *MockNodeManager_Expecter) ConfigureMemoryMap() *MockNodeManager_ConfigureMemoryMap_Call { + return &MockNodeManager_ConfigureMemoryMap_Call{Call: _e.mock.On("ConfigureMemoryMap")} +} + +func (_c *MockNodeManager_ConfigureMemoryMap_Call) Run(run func()) *MockNodeManager_ConfigureMemoryMap_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockNodeManager_ConfigureMemoryMap_Call) Return(err error) *MockNodeManager_ConfigureMemoryMap_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockNodeManager_ConfigureMemoryMap_Call) RunAndReturn(run func() error) *MockNodeManager_ConfigureMemoryMap_Call { + _c.Call.Return(run) + return _c +} + +// CopyFile provides a mock function for the type MockNodeManager +func (_mock *MockNodeManager) CopyFile(src string, dst string) error { + ret := _mock.Called(src, dst) + + if len(ret) == 0 { + panic("no return value specified for CopyFile") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(string, string) error); ok { + r0 = returnFunc(src, dst) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// MockNodeManager_CopyFile_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CopyFile' +type MockNodeManager_CopyFile_Call struct { + *mock.Call +} + +// CopyFile is a helper method to define mock.On call +// - src string +// - dst string +func (_e *MockNodeManager_Expecter) CopyFile(src interface{}, dst interface{}) *MockNodeManager_CopyFile_Call { + return &MockNodeManager_CopyFile_Call{Call: _e.mock.On("CopyFile", src, dst)} +} + +func (_c *MockNodeManager_CopyFile_Call) Run(run func(src string, dst string)) *MockNodeManager_CopyFile_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *MockNodeManager_CopyFile_Call) Return(err error) *MockNodeManager_CopyFile_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockNodeManager_CopyFile_Call) RunAndReturn(run func(src string, dst string) error) *MockNodeManager_CopyFile_Call { + _c.Call.Return(run) + return _c +} + +// CreateSubNode provides a mock function for the type MockNodeManager +func (_mock *MockNodeManager) CreateSubNode(name string, externalIP string, internalIP string) NodeManager { + ret := _mock.Called(name, externalIP, internalIP) + + if len(ret) == 0 { + panic("no return value specified for CreateSubNode") + } + + var r0 NodeManager + if returnFunc, ok := ret.Get(0).(func(string, string, string) NodeManager); ok { + r0 = returnFunc(name, externalIP, internalIP) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(NodeManager) + } + } + return r0 +} + +// MockNodeManager_CreateSubNode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateSubNode' +type MockNodeManager_CreateSubNode_Call struct { + *mock.Call +} + +// CreateSubNode is a helper method to define mock.On call +// - name string +// - externalIP string +// - internalIP string +func (_e *MockNodeManager_Expecter) CreateSubNode(name interface{}, externalIP interface{}, internalIP interface{}) *MockNodeManager_CreateSubNode_Call { + return &MockNodeManager_CreateSubNode_Call{Call: _e.mock.On("CreateSubNode", name, externalIP, internalIP)} +} + +func (_c *MockNodeManager_CreateSubNode_Call) Run(run func(name string, externalIP string, internalIP string)) *MockNodeManager_CreateSubNode_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *MockNodeManager_CreateSubNode_Call) Return(nodeManager NodeManager) *MockNodeManager_CreateSubNode_Call { + _c.Call.Return(nodeManager) + return _c +} + +func (_c *MockNodeManager_CreateSubNode_Call) RunAndReturn(run func(name string, externalIP string, internalIP string) NodeManager) *MockNodeManager_CreateSubNode_Call { + _c.Call.Return(run) + return _c +} + +// EnableRootLogin provides a mock function for the type MockNodeManager +func (_mock *MockNodeManager) EnableRootLogin() error { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for EnableRootLogin") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func() error); ok { + r0 = returnFunc() + } else { + r0 = ret.Error(0) + } + return r0 +} + +// MockNodeManager_EnableRootLogin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EnableRootLogin' +type MockNodeManager_EnableRootLogin_Call struct { + *mock.Call +} + +// EnableRootLogin is a helper method to define mock.On call +func (_e *MockNodeManager_Expecter) EnableRootLogin() *MockNodeManager_EnableRootLogin_Call { + return &MockNodeManager_EnableRootLogin_Call{Call: _e.mock.On("EnableRootLogin")} +} + +func (_c *MockNodeManager_EnableRootLogin_Call) Run(run func()) *MockNodeManager_EnableRootLogin_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockNodeManager_EnableRootLogin_Call) Return(err error) *MockNodeManager_EnableRootLogin_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockNodeManager_EnableRootLogin_Call) RunAndReturn(run func() error) *MockNodeManager_EnableRootLogin_Call { + _c.Call.Return(run) + return _c +} + +// GetExternalIP provides a mock function for the type MockNodeManager +func (_mock *MockNodeManager) GetExternalIP() string { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for GetExternalIP") + } + + var r0 string + if returnFunc, ok := ret.Get(0).(func() string); ok { + r0 = returnFunc() + } else { + r0 = ret.Get(0).(string) + } + return r0 +} + +// MockNodeManager_GetExternalIP_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetExternalIP' +type MockNodeManager_GetExternalIP_Call struct { + *mock.Call +} + +// GetExternalIP is a helper method to define mock.On call +func (_e *MockNodeManager_Expecter) GetExternalIP() *MockNodeManager_GetExternalIP_Call { + return &MockNodeManager_GetExternalIP_Call{Call: _e.mock.On("GetExternalIP")} +} + +func (_c *MockNodeManager_GetExternalIP_Call) Run(run func()) *MockNodeManager_GetExternalIP_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockNodeManager_GetExternalIP_Call) Return(s string) *MockNodeManager_GetExternalIP_Call { + _c.Call.Return(s) + return _c +} + +func (_c *MockNodeManager_GetExternalIP_Call) RunAndReturn(run func() string) *MockNodeManager_GetExternalIP_Call { + _c.Call.Return(run) + return _c +} + +// GetInternalIP provides a mock function for the type MockNodeManager +func (_mock *MockNodeManager) GetInternalIP() string { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for GetInternalIP") + } + + var r0 string + if returnFunc, ok := ret.Get(0).(func() string); ok { + r0 = returnFunc() + } else { + r0 = ret.Get(0).(string) + } + return r0 +} + +// MockNodeManager_GetInternalIP_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetInternalIP' +type MockNodeManager_GetInternalIP_Call struct { + *mock.Call +} + +// GetInternalIP is a helper method to define mock.On call +func (_e *MockNodeManager_Expecter) GetInternalIP() *MockNodeManager_GetInternalIP_Call { + return &MockNodeManager_GetInternalIP_Call{Call: _e.mock.On("GetInternalIP")} +} + +func (_c *MockNodeManager_GetInternalIP_Call) Run(run func()) *MockNodeManager_GetInternalIP_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockNodeManager_GetInternalIP_Call) Return(s string) *MockNodeManager_GetInternalIP_Call { + _c.Call.Return(s) + return _c +} + +func (_c *MockNodeManager_GetInternalIP_Call) RunAndReturn(run func() string) *MockNodeManager_GetInternalIP_Call { + _c.Call.Return(run) + return _c +} + +// GetName provides a mock function for the type MockNodeManager +func (_mock *MockNodeManager) GetName() string { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for GetName") + } + + var r0 string + if returnFunc, ok := ret.Get(0).(func() string); ok { + r0 = returnFunc() + } else { + r0 = ret.Get(0).(string) + } + return r0 +} + +// MockNodeManager_GetName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetName' +type MockNodeManager_GetName_Call struct { + *mock.Call +} + +// GetName is a helper method to define mock.On call +func (_e *MockNodeManager_Expecter) GetName() *MockNodeManager_GetName_Call { + return &MockNodeManager_GetName_Call{Call: _e.mock.On("GetName")} +} + +func (_c *MockNodeManager_GetName_Call) Run(run func()) *MockNodeManager_GetName_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockNodeManager_GetName_Call) Return(s string) *MockNodeManager_GetName_Call { + _c.Call.Return(s) + return _c +} + +func (_c *MockNodeManager_GetName_Call) RunAndReturn(run func() string) *MockNodeManager_GetName_Call { + _c.Call.Return(run) + return _c +} + +// HasAcceptEnvConfigured provides a mock function for the type MockNodeManager +func (_mock *MockNodeManager) HasAcceptEnvConfigured() bool { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for HasAcceptEnvConfigured") + } + + var r0 bool + if returnFunc, ok := ret.Get(0).(func() bool); ok { + r0 = returnFunc() + } else { + r0 = ret.Get(0).(bool) + } + return r0 +} + +// MockNodeManager_HasAcceptEnvConfigured_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HasAcceptEnvConfigured' +type MockNodeManager_HasAcceptEnvConfigured_Call struct { + *mock.Call +} + +// HasAcceptEnvConfigured is a helper method to define mock.On call +func (_e *MockNodeManager_Expecter) HasAcceptEnvConfigured() *MockNodeManager_HasAcceptEnvConfigured_Call { + return &MockNodeManager_HasAcceptEnvConfigured_Call{Call: _e.mock.On("HasAcceptEnvConfigured")} +} + +func (_c *MockNodeManager_HasAcceptEnvConfigured_Call) Run(run func()) *MockNodeManager_HasAcceptEnvConfigured_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockNodeManager_HasAcceptEnvConfigured_Call) Return(b bool) *MockNodeManager_HasAcceptEnvConfigured_Call { + _c.Call.Return(b) + return _c +} + +func (_c *MockNodeManager_HasAcceptEnvConfigured_Call) RunAndReturn(run func() bool) *MockNodeManager_HasAcceptEnvConfigured_Call { + _c.Call.Return(run) + return _c +} + +// HasCommand provides a mock function for the type MockNodeManager +func (_mock *MockNodeManager) HasCommand(command string) bool { + ret := _mock.Called(command) + + if len(ret) == 0 { + panic("no return value specified for HasCommand") + } + + var r0 bool + if returnFunc, ok := ret.Get(0).(func(string) bool); ok { + r0 = returnFunc(command) + } else { + r0 = ret.Get(0).(bool) + } + return r0 +} + +// MockNodeManager_HasCommand_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HasCommand' +type MockNodeManager_HasCommand_Call struct { + *mock.Call +} + +// HasCommand is a helper method to define mock.On call +// - command string +func (_e *MockNodeManager_Expecter) HasCommand(command interface{}) *MockNodeManager_HasCommand_Call { + return &MockNodeManager_HasCommand_Call{Call: _e.mock.On("HasCommand", command)} +} + +func (_c *MockNodeManager_HasCommand_Call) Run(run func(command string)) *MockNodeManager_HasCommand_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + run( + arg0, + ) + }) + return _c +} + +func (_c *MockNodeManager_HasCommand_Call) Return(b bool) *MockNodeManager_HasCommand_Call { + _c.Call.Return(b) + return _c +} + +func (_c *MockNodeManager_HasCommand_Call) RunAndReturn(run func(command string) bool) *MockNodeManager_HasCommand_Call { + _c.Call.Return(run) + return _c +} + +// HasFile provides a mock function for the type MockNodeManager +func (_mock *MockNodeManager) HasFile(filePath string) bool { + ret := _mock.Called(filePath) + + if len(ret) == 0 { + panic("no return value specified for HasFile") + } + + var r0 bool + if returnFunc, ok := ret.Get(0).(func(string) bool); ok { + r0 = returnFunc(filePath) + } else { + r0 = ret.Get(0).(bool) + } + return r0 +} + +// MockNodeManager_HasFile_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HasFile' +type MockNodeManager_HasFile_Call struct { + *mock.Call +} + +// HasFile is a helper method to define mock.On call +// - filePath string +func (_e *MockNodeManager_Expecter) HasFile(filePath interface{}) *MockNodeManager_HasFile_Call { + return &MockNodeManager_HasFile_Call{Call: _e.mock.On("HasFile", filePath)} +} + +func (_c *MockNodeManager_HasFile_Call) Run(run func(filePath string)) *MockNodeManager_HasFile_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + run( + arg0, + ) + }) + return _c +} + +func (_c *MockNodeManager_HasFile_Call) Return(b bool) *MockNodeManager_HasFile_Call { + _c.Call.Return(b) + return _c +} + +func (_c *MockNodeManager_HasFile_Call) RunAndReturn(run func(filePath string) bool) *MockNodeManager_HasFile_Call { + _c.Call.Return(run) + return _c +} + +// HasInotifyWatchesConfigured provides a mock function for the type MockNodeManager +func (_mock *MockNodeManager) HasInotifyWatchesConfigured() bool { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for HasInotifyWatchesConfigured") + } + + var r0 bool + if returnFunc, ok := ret.Get(0).(func() bool); ok { + r0 = returnFunc() + } else { + r0 = ret.Get(0).(bool) + } + return r0 +} + +// MockNodeManager_HasInotifyWatchesConfigured_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HasInotifyWatchesConfigured' +type MockNodeManager_HasInotifyWatchesConfigured_Call struct { + *mock.Call +} + +// HasInotifyWatchesConfigured is a helper method to define mock.On call +func (_e *MockNodeManager_Expecter) HasInotifyWatchesConfigured() *MockNodeManager_HasInotifyWatchesConfigured_Call { + return &MockNodeManager_HasInotifyWatchesConfigured_Call{Call: _e.mock.On("HasInotifyWatchesConfigured")} +} + +func (_c *MockNodeManager_HasInotifyWatchesConfigured_Call) Run(run func()) *MockNodeManager_HasInotifyWatchesConfigured_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockNodeManager_HasInotifyWatchesConfigured_Call) Return(b bool) *MockNodeManager_HasInotifyWatchesConfigured_Call { + _c.Call.Return(b) + return _c +} + +func (_c *MockNodeManager_HasInotifyWatchesConfigured_Call) RunAndReturn(run func() bool) *MockNodeManager_HasInotifyWatchesConfigured_Call { + _c.Call.Return(run) + return _c +} + +// HasMemoryMapConfigured provides a mock function for the type MockNodeManager +func (_mock *MockNodeManager) HasMemoryMapConfigured() bool { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for HasMemoryMapConfigured") + } + + var r0 bool + if returnFunc, ok := ret.Get(0).(func() bool); ok { + r0 = returnFunc() + } else { + r0 = ret.Get(0).(bool) + } + return r0 +} + +// MockNodeManager_HasMemoryMapConfigured_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HasMemoryMapConfigured' +type MockNodeManager_HasMemoryMapConfigured_Call struct { + *mock.Call +} + +// HasMemoryMapConfigured is a helper method to define mock.On call +func (_e *MockNodeManager_Expecter) HasMemoryMapConfigured() *MockNodeManager_HasMemoryMapConfigured_Call { + return &MockNodeManager_HasMemoryMapConfigured_Call{Call: _e.mock.On("HasMemoryMapConfigured")} +} + +func (_c *MockNodeManager_HasMemoryMapConfigured_Call) Run(run func()) *MockNodeManager_HasMemoryMapConfigured_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockNodeManager_HasMemoryMapConfigured_Call) Return(b bool) *MockNodeManager_HasMemoryMapConfigured_Call { + _c.Call.Return(b) + return _c +} + +func (_c *MockNodeManager_HasMemoryMapConfigured_Call) RunAndReturn(run func() bool) *MockNodeManager_HasMemoryMapConfigured_Call { + _c.Call.Return(run) + return _c +} + +// HasRootLoginEnabled provides a mock function for the type MockNodeManager +func (_mock *MockNodeManager) HasRootLoginEnabled() bool { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for HasRootLoginEnabled") + } + + var r0 bool + if returnFunc, ok := ret.Get(0).(func() bool); ok { + r0 = returnFunc() + } else { + r0 = ret.Get(0).(bool) + } + return r0 +} + +// MockNodeManager_HasRootLoginEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HasRootLoginEnabled' +type MockNodeManager_HasRootLoginEnabled_Call struct { + *mock.Call +} + +// HasRootLoginEnabled is a helper method to define mock.On call +func (_e *MockNodeManager_Expecter) HasRootLoginEnabled() *MockNodeManager_HasRootLoginEnabled_Call { + return &MockNodeManager_HasRootLoginEnabled_Call{Call: _e.mock.On("HasRootLoginEnabled")} +} + +func (_c *MockNodeManager_HasRootLoginEnabled_Call) Run(run func()) *MockNodeManager_HasRootLoginEnabled_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockNodeManager_HasRootLoginEnabled_Call) Return(b bool) *MockNodeManager_HasRootLoginEnabled_Call { + _c.Call.Return(b) + return _c +} + +func (_c *MockNodeManager_HasRootLoginEnabled_Call) RunAndReturn(run func() bool) *MockNodeManager_HasRootLoginEnabled_Call { + _c.Call.Return(run) + return _c +} + +// InstallOms provides a mock function for the type MockNodeManager +func (_mock *MockNodeManager) InstallOms() error { + ret := _mock.Called() + + if len(ret) == 0 { + panic("no return value specified for InstallOms") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func() error); ok { + r0 = returnFunc() + } else { + r0 = ret.Error(0) + } + return r0 +} + +// MockNodeManager_InstallOms_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'InstallOms' +type MockNodeManager_InstallOms_Call struct { + *mock.Call +} + +// InstallOms is a helper method to define mock.On call +func (_e *MockNodeManager_Expecter) InstallOms() *MockNodeManager_InstallOms_Call { + return &MockNodeManager_InstallOms_Call{Call: _e.mock.On("InstallOms")} +} + +func (_c *MockNodeManager_InstallOms_Call) Run(run func()) *MockNodeManager_InstallOms_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockNodeManager_InstallOms_Call) Return(err error) *MockNodeManager_InstallOms_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockNodeManager_InstallOms_Call) RunAndReturn(run func() error) *MockNodeManager_InstallOms_Call { + _c.Call.Return(run) + return _c +} + +// RunSSHCommand provides a mock function for the type MockNodeManager +func (_mock *MockNodeManager) RunSSHCommand(username string, command string, quiet bool) error { + ret := _mock.Called(username, command, quiet) + + if len(ret) == 0 { + panic("no return value specified for RunSSHCommand") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(string, string, bool) error); ok { + r0 = returnFunc(username, command, quiet) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// MockNodeManager_RunSSHCommand_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RunSSHCommand' +type MockNodeManager_RunSSHCommand_Call struct { + *mock.Call +} + +// RunSSHCommand is a helper method to define mock.On call +// - username string +// - command string +// - quiet bool +func (_e *MockNodeManager_Expecter) RunSSHCommand(username interface{}, command interface{}, quiet interface{}) *MockNodeManager_RunSSHCommand_Call { + return &MockNodeManager_RunSSHCommand_Call{Call: _e.mock.On("RunSSHCommand", username, command, quiet)} +} + +func (_c *MockNodeManager_RunSSHCommand_Call) Run(run func(username string, command string, quiet bool)) *MockNodeManager_RunSSHCommand_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 bool + if args[2] != nil { + arg2 = args[2].(bool) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *MockNodeManager_RunSSHCommand_Call) Return(err error) *MockNodeManager_RunSSHCommand_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockNodeManager_RunSSHCommand_Call) RunAndReturn(run func(username string, command string, quiet bool) error) *MockNodeManager_RunSSHCommand_Call { + _c.Call.Return(run) + return _c +} + +// UpdateNode provides a mock function for the type MockNodeManager +func (_mock *MockNodeManager) UpdateNode(name string, externalIP string, internalIP string) { + _mock.Called(name, externalIP, internalIP) + return +} + +// MockNodeManager_UpdateNode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateNode' +type MockNodeManager_UpdateNode_Call struct { + *mock.Call +} + +// UpdateNode is a helper method to define mock.On call +// - name string +// - externalIP string +// - internalIP string +func (_e *MockNodeManager_Expecter) UpdateNode(name interface{}, externalIP interface{}, internalIP interface{}) *MockNodeManager_UpdateNode_Call { + return &MockNodeManager_UpdateNode_Call{Call: _e.mock.On("UpdateNode", name, externalIP, internalIP)} +} + +func (_c *MockNodeManager_UpdateNode_Call) Run(run func(name string, externalIP string, internalIP string)) *MockNodeManager_UpdateNode_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *MockNodeManager_UpdateNode_Call) Return() *MockNodeManager_UpdateNode_Call { + _c.Call.Return() + return _c +} + +func (_c *MockNodeManager_UpdateNode_Call) RunAndReturn(run func(name string, externalIP string, internalIP string)) *MockNodeManager_UpdateNode_Call { + _c.Run(run) + return _c +} + +// WaitForSSH provides a mock function for the type MockNodeManager +func (_mock *MockNodeManager) WaitForSSH(timeout time.Duration) error { + ret := _mock.Called(timeout) + + if len(ret) == 0 { + panic("no return value specified for WaitForSSH") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(time.Duration) error); ok { + r0 = returnFunc(timeout) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// MockNodeManager_WaitForSSH_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WaitForSSH' +type MockNodeManager_WaitForSSH_Call struct { + *mock.Call +} + +// WaitForSSH is a helper method to define mock.On call +// - timeout time.Duration +func (_e *MockNodeManager_Expecter) WaitForSSH(timeout interface{}) *MockNodeManager_WaitForSSH_Call { + return &MockNodeManager_WaitForSSH_Call{Call: _e.mock.On("WaitForSSH", timeout)} +} + +func (_c *MockNodeManager_WaitForSSH_Call) Run(run func(timeout time.Duration)) *MockNodeManager_WaitForSSH_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 time.Duration + if args[0] != nil { + arg0 = args[0].(time.Duration) + } + run( + arg0, + ) + }) + return _c +} + +func (_c *MockNodeManager_WaitForSSH_Call) Return(err error) *MockNodeManager_WaitForSSH_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockNodeManager_WaitForSSH_Call) RunAndReturn(run func(timeout time.Duration) error) *MockNodeManager_WaitForSSH_Call { + _c.Call.Return(run) + return _c +} diff --git a/internal/installer/node/node.go b/internal/installer/node/node.go index 0edf691b..a11e8b4c 100644 --- a/internal/installer/node/node.go +++ b/internal/installer/node/node.go @@ -19,205 +19,321 @@ import ( "golang.org/x/term" ) -type Node struct { - Name string `json:"name"` - ExternalIP string `json:"external_ip"` - InternalIP string `json:"internal_ip"` +type NodeManager interface { + // Node + CreateSubNode(name string, externalIP string, internalIP string) NodeManager + UpdateNode(name string, externalIP string, internalIP string) + GetExternalIP() string + GetInternalIP() string + GetName() string + // SSH + WaitForSSH(timeout time.Duration) error + RunSSHCommand(username string, command string, quiet bool) error + // OMS + HasCommand(command string) bool + InstallOms() error + // AcceptEnv + HasAcceptEnvConfigured() bool + ConfigureAcceptEnv() error + // Root Login + HasRootLoginEnabled() bool + EnableRootLogin() error + // Host Config + HasInotifyWatchesConfigured() bool + ConfigureInotifyWatches() error + HasMemoryMapConfigured() bool + ConfigureMemoryMap() error + // Files + HasFile(filePath string) bool + CopyFile(src string, dst string) error } -type NodeManager struct { - FileIO util.FileIO - KeyPath string - cachedSigner ssh.Signer // cached signer to avoid repeated passphrase prompts +type Node struct { + FileIO util.FileIO `json:"-"` + // If connecting via the Jumpbox + Jumpbox *Node `json:"-"` + // Config + keyPath string `json:"-"` + Name string `json:"name"` + ExternalIP string `json:"external_ip"` + InternalIP string `json:"internal_ip"` + cachedSigner ssh.Signer `json:"-"` } -// getAuthMethods constructs a slice of ssh.AuthMethod, prioritizing the SSH agent. -func (n *NodeManager) getAuthMethods() ([]ssh.AuthMethod, error) { - var signers []ssh.Signer +const jumpboxUser = "ubuntu" - // 1. Get Agent Signers - if authSocket := os.Getenv("SSH_AUTH_SOCK"); authSocket != "" { - if conn, err := net.Dial("unix", authSocket); err == nil { - agentClient := agent.NewClient(conn) - if s, err := agentClient.Signers(); err == nil { - signers = append(signers, s...) - } - } +// NewNode creates a new Node with the given FileIO and SSH key path +func NewNode(fileIO util.FileIO, keyPath string) *Node { + return &Node{ + FileIO: fileIO, + keyPath: util.ExpandPath(keyPath), } +} - // 2. Add Private Key (File) if needed - if n.KeyPath != "" { - shouldLoad := true +// CreateSubNode creates a Node object representing a node behind a jumpbox +func (n *Node) CreateSubNode(name string, externalIP string, internalIP string) NodeManager { + return &Node{ + FileIO: n.FileIO, + Jumpbox: n, + keyPath: util.ExpandPath(n.keyPath), + Name: name, + ExternalIP: externalIP, + InternalIP: internalIP, + } +} - // Use cached signer if available - if n.cachedSigner != nil { - signers = append(signers, n.cachedSigner) - shouldLoad = false - } +// UpdateNode updates the node's name and IP addresses +func (n *Node) UpdateNode(name string, externalIP string, internalIP string) { + n.Name = name + n.ExternalIP = externalIP + n.InternalIP = internalIP +} - // Check if key is already in agent (requires .pub file) - if shouldLoad && len(signers) > 0 { - if pubBytes, err := n.FileIO.ReadFile(n.KeyPath + ".pub"); err == nil { - if targetPub, _, _, _, err := ssh.ParseAuthorizedKey(pubBytes); err == nil { - targetMarshaled := string(targetPub.Marshal()) - for _, s := range signers { - if string(s.PublicKey().Marshal()) == targetMarshaled { - shouldLoad = false - break - } - } - } - } - } +// GetExternalIP updates the external IP of the node +func (n *Node) GetExternalIP() string { + return n.ExternalIP +} - // Else load from file with passphrase prompt if needed - if shouldLoad { - if signer, err := n.loadPrivateKey(); err == nil { - n.cachedSigner = signer - signers = append(signers, signer) - } else { - log.Printf("Warning: failed to load private key: %v\n", err) - } - } - } +// GetInternalIP updates the internal IP of the node +func (n *Node) GetInternalIP() string { + return n.InternalIP +} - if len(signers) == 0 { - return nil, fmt.Errorf("no valid authentication methods configured. Check SSH_AUTH_SOCK and private key path") - } +// Name returns the name of the node +func (n *Node) GetName() string { + return n.Name +} - return []ssh.AuthMethod{ssh.PublicKeys(signers...)}, nil +// WaitForSSH tries to connect to the node via SSH until timeout +func (n *Node) WaitForSSH(timeout time.Duration) error { + start := time.Now() + jumpboxIp := "" + nodeIp := n.ExternalIP + if n.Jumpbox != nil { + jumpboxIp = n.Jumpbox.ExternalIP + nodeIp = n.InternalIP + } + for { + client, err := n.getClient(jumpboxIp, nodeIp, jumpboxUser) + if err == nil { + _ = client.Close() + return nil + } + if time.Since(start) > timeout { + return fmt.Errorf("timeout waiting for SSH on node %s (%s)", n.Name, n.ExternalIP) + } + time.Sleep(5 * time.Second) + } } -// loadPrivateKey reads and parses the private key, prompting for passphrase if needed. -func (n *NodeManager) loadPrivateKey() (ssh.Signer, error) { - key, err := n.FileIO.ReadFile(n.KeyPath) - if err != nil { - return nil, fmt.Errorf("failed to read private key file %s: %v", n.KeyPath, err) +// RunSSHCommand connects to the node, executes a command and streams the output. +// If quiet is true, command output is not printed to stdout/stderr. +func (n *Node) RunSSHCommand(username string, command string, quiet bool) error { + var jumpboxIp string + var ip string + if n.Jumpbox != nil { + jumpboxIp = n.Jumpbox.ExternalIP + ip = n.InternalIP + } else { + jumpboxIp = "" + ip = n.ExternalIP } - signer, err := ssh.ParsePrivateKey(key) - if err == nil { - return signer, nil + client, err := n.getClient(jumpboxIp, ip, username) + if err != nil { + return fmt.Errorf("failed to get client: %w", err) } + defer util.IgnoreError(client.Close) - if _, ok := err.(*ssh.PassphraseMissingError); !ok { - return nil, fmt.Errorf("failed to parse private key: %v", err) + session, err := client.NewSession() + if err != nil { + return fmt.Errorf("failed to create session on jumpbox: %v", err) } + defer util.IgnoreError(session.Close) - // Key is encrypted, prompt for passphrase - log.Printf("Enter passphrase for key '%s': ", n.KeyPath) - passphrase, err := term.ReadPassword(int(syscall.Stdin)) - log.Println() + _ = session.Setenv("OMS_PORTAL_API_KEY", os.Getenv("OMS_PORTAL_API_KEY")) + err = n.forwardAgent(client, session) if err != nil { - return nil, fmt.Errorf("failed to read passphrase: %v", err) + log.Printf(" Warning: Agent forwarding setup failed on session: %v\n", err) } - signer, err = ssh.ParsePrivateKeyWithPassphrase(key, passphrase) - // Clear passphrase from memory - for i := range passphrase { - passphrase[i] = 0 + if !quiet { + session.Stdout = os.Stdout + session.Stderr = os.Stderr } - if err != nil { - return nil, fmt.Errorf("failed to parse private key with passphrase: %v", err) + // Start the command + if err := session.Start(command); err != nil { + return fmt.Errorf("failed to start command: %v", err) } - return signer, nil + if err := session.Wait(); err != nil { + // A non-zero exit status from the remote command is also considered an error + return fmt.Errorf("command failed: %w", err) + } + + return nil } -func (n *NodeManager) connectToJumpbox(ip, username string) (*ssh.Client, error) { - authMethods, err := n.getAuthMethods() +// HasCommand checks if a command exists on the remote node via SSH +func (n *Node) HasCommand(command string) bool { + checkCommand := fmt.Sprintf("command -v %s >/dev/null 2>&1", command) + err := n.RunSSHCommand("root", checkCommand, true) if err != nil { - return nil, fmt.Errorf("jumpbox authentication setup failed: %v", err) + // If the command returns a non-zero exit status, it means the command is not found + return false } + return true +} - config := &ssh.ClientConfig{ - User: username, - Auth: authMethods, - Timeout: 10 * time.Second, - // WARNING: Still using InsecureIgnoreHostKey for simplicity. Use known_hosts in production. - HostKeyCallback: ssh.InsecureIgnoreHostKey(), +// InstallOms installs the OMS CLI on the remote node via SSH +func (n *Node) InstallOms() error { + remoteCommands := []string{ + "wget -qO- 'https://api.github.com/repos/codesphere-cloud/oms/releases/latest' | jq -r '.assets[] | select(.name | match(\"oms-cli.*linux_amd64\")) | .browser_download_url' | xargs wget -O oms-cli", + "chmod +x oms-cli; sudo mv oms-cli /usr/local/bin/", + "curl -LO https://github.com/getsops/sops/releases/download/v3.11.0/sops-v3.11.0.linux.amd64; sudo mv sops-v3.11.0.linux.amd64 /usr/local/bin/sops; sudo chmod +x /usr/local/bin/sops", + "wget https://dl.filippo.io/age/latest?for=linux/amd64 -O age.tar.gz; tar -xvf age.tar.gz; sudo mv age/age* /usr/local/bin/", } + for _, cmd := range remoteCommands { + err := n.RunSSHCommand("root", cmd, false) + if err != nil { + return fmt.Errorf("failed to run remote command '%s': %w", cmd, err) + } + } + return nil +} - addr := fmt.Sprintf("%s:22", ip) - jumpboxClient, err := ssh.Dial("tcp", addr, config) +// HasAcceptEnvConfigured checks if AcceptEnv is configured +func (n *Node) HasAcceptEnvConfigured() bool { + checkCommand := "sudo grep -E '^AcceptEnv OMS_PORTAL_API_KEY' /etc/ssh/sshd_config >/dev/null 2>&1" + err := n.RunSSHCommand("ubuntu", checkCommand, true) if err != nil { - return nil, fmt.Errorf("failed to dial jumpbox %s: %v", addr, err) + // If the command returns a NON-zero exit status, it means AcceptEnv is not configured + return false } + return true +} - // Enable Agent Forwarding on the jumpbox connection - if err := n.forwardAgent(jumpboxClient, nil); err != nil { - log.Printf(" Warning: Agent forwarding setup failed on jumpbox: %v\n", err) +// ConfigureAcceptEnv configures AcceptEnv for OMS_PORTAL_API_KEY +func (n *Node) ConfigureAcceptEnv() error { + cmds := []string{ + "sudo sed -i 's/^#\\?AcceptEnv.*/AcceptEnv OMS_PORTAL_API_KEY/' /etc/ssh/sshd_config", + "sudo systemctl restart sshd", } + for _, cmd := range cmds { + err := n.RunSSHCommand("ubuntu", cmd, true) + if err != nil { + return fmt.Errorf("failed to run command '%s': %w", cmd, err) + } + } + return nil +} - return jumpboxClient, nil +// HasRootLoginEnabled checks if root login is enabled on the remote node via SSH +func (n *Node) HasRootLoginEnabled() bool { + checkCommandPermit := "sudo grep -E '^PermitRootLogin yes' /etc/ssh/sshd_config >/dev/null 2>&1" + err := n.RunSSHCommand("ubuntu", checkCommandPermit, true) + if err != nil { + // If the command returns a NON-zero exit status, it means root login is not permitted + return false + } + checkCommandAuthorizedKeys := "sudo grep -E '^no-port-forwarding' /root/.ssh/authorized_keys >/dev/null 2>&1" + err = n.RunSSHCommand("ubuntu", checkCommandAuthorizedKeys, true) + if err == nil { + // If the command returns a ZERO exit status, it means root login is prevented + return false + } + return true } -func (n *NodeManager) forwardAgent(client *ssh.Client, session *ssh.Session) error { - authSocket := os.Getenv("SSH_AUTH_SOCK") - if authSocket == "" { - log.Printf("SSH_AUTH_SOCK not set. Cannot perform agent forwarding") - } else { - // Connect to the local SSH Agent socket - conn, err := net.Dial("unix", authSocket) +// EnableRootLogin enables root login on the remote node via SSH +func (n *Node) EnableRootLogin() error { + cmds := []string{ + "sudo sed -i 's/^#\\?PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config", + "sudo sed -i 's/no-port-forwarding.*$//g' /root/.ssh/authorized_keys", + "sudo systemctl restart sshd", + } + for _, cmd := range cmds { + err := n.RunSSHCommand("ubuntu", cmd, true) if err != nil { - log.Printf("failed to dial SSH agent socket: %v", err) - } else { - // Create an agent client for the local agent - ag := agent.NewClient(conn) - // This tells the remote server to proxy authentication requests back to us. - if err := agent.ForwardToAgent(client, ag); err != nil { - log.Printf("failed to forward agent to remote client: %v", err) - } - if session != nil { - if err := agent.RequestAgentForwarding(session); err != nil { - log.Printf("failed to request agent forwarding on session: %v", err) - } - } + return fmt.Errorf("failed to run command '%s': %w", cmd, err) } - } return nil } -const jumpboxUser = "ubuntu" +func (n *Node) HasInotifyWatchesConfigured() bool { + return n.hasSysctlLine("fs.inotify.max_user_watches=1048576") +} + +func (n *Node) ConfigureInotifyWatches() error { + return n.configureSysctlLine("fs.inotify.max_user_watches=1048576") +} + +func (n *Node) HasMemoryMapConfigured() bool { + return n.hasSysctlLine("vm.max_map_count=262144") +} + +func (n *Node) ConfigureMemoryMap() error { + return n.configureSysctlLine("vm.max_map_count=262144") +} -// RunSSHCommand connects to the node, executes a command and streams the output -func (n *NodeManager) RunSSHCommand(jumpboxIp string, ip string, username string, command string) error { - client, err := n.GetClient(jumpboxIp, ip, username) +// HasFile checks if a file exists on the remote node via SSH +func (n *Node) HasFile(filePath string) bool { + checkCommand := fmt.Sprintf("test -f '%s'", filePath) + err := n.RunSSHCommand("ubuntu", checkCommand, true) if err != nil { - return fmt.Errorf("failed to get client: %w", err) + // If the command returns a non-zero exit status, it means the file does not exist + return false } - defer util.IgnoreError(client.Close) - session, err := client.NewSession() + return true +} + +// CopyFile copies a file from the local system to the remote node via SFTP +func (n *Node) CopyFile(src string, dst string) error { + if n.Jumpbox == nil { + err := n.ensureDirectoryExists("root", filepath.Dir(dst)) + if err != nil { + return fmt.Errorf("failed to ensure directory exists: %w", err) + } + return n.copyFile("", n.ExternalIP, "root", src, dst) + } + err := n.ensureDirectoryExists("root", filepath.Dir(dst)) if err != nil { - return fmt.Errorf("failed to create session on jumpbox: %v", err) + return fmt.Errorf("failed to ensure directory exists: %w", err) } - defer util.IgnoreError(session.Close) - - _ = session.Setenv("OMS_PORTAL_API_KEY", os.Getenv("OMS_PORTAL_API_KEY")) + return n.copyFile(n.Jumpbox.ExternalIP, n.InternalIP, "root", src, dst) +} - err = n.forwardAgent(client, session) +// Helper functions +// hasSysctlLine checks if a specific line exists in /etc/sysctl.conf on the remote node via SSH +func (n *Node) hasSysctlLine(line string) bool { + checkCommand := fmt.Sprintf("sudo grep -E '^%s' /etc/sysctl.conf >/dev/null 2>&1", line) + err := n.RunSSHCommand("root", checkCommand, true) if err != nil { - log.Printf(" Warning: Agent forwarding setup failed on session: %v\n", err) + // If the command returns a NON-zero exit status, it means the setting is not configured + return false } + return true +} - session.Stdout = os.Stdout - session.Stderr = os.Stderr - // Start the command - if err := session.Start(command); err != nil { - return fmt.Errorf("failed to start command: %v", err) +// configureSysctlLine appends a specific line to /etc/sysctl.conf and applies the settings on the remote node via SSH +func (n *Node) configureSysctlLine(line string) error { + cmds := []string{ + fmt.Sprintf("echo '%s' | sudo tee -a /etc/sysctl.conf", line), + "sudo sysctl -p", } - - if err := session.Wait(); err != nil { - // A non-zero exit status from the remote command is also considered an error - return fmt.Errorf("command failed: %w", err) + for _, cmd := range cmds { + err := n.RunSSHCommand("root", cmd, true) + if err != nil { + return fmt.Errorf("failed to run command '%s': %w", cmd, err) + } } - return nil } -func (n *NodeManager) GetClient(jumpboxIp string, ip string, username string) (*ssh.Client, error) { +// getClient creates and returns an SSH client connected to the node +func (n *Node) getClient(jumpboxIp string, ip string, username string) (*ssh.Client, error) { authMethods, err := n.getAuthMethods() if err != nil { return nil, fmt.Errorf("failed to get authentication methods: %w", err) @@ -267,8 +383,9 @@ func (n *NodeManager) GetClient(jumpboxIp string, ip string, username string) (* return client, nil } -func (n *NodeManager) GetSFTPClient(jumpboxIp string, ip string, username string) (*sftp.Client, error) { - client, err := n.GetClient(jumpboxIp, ip, username) +// getSFTPClient creates and returns an SFTP client connected to the node +func (n *Node) getSFTPClient(jumpboxIp string, ip string, username string) (*sftp.Client, error) { + client, err := n.getClient(jumpboxIp, ip, username) if err != nil { return nil, fmt.Errorf("failed to get SSH client: %v", err) } @@ -279,14 +396,15 @@ func (n *NodeManager) GetSFTPClient(jumpboxIp string, ip string, username string return sftpClient, nil } -// EnsureDirectoryExists creates the directory on the remote node via SSH if it does not exist. -func (nm *NodeManager) EnsureDirectoryExists(jumpboxIp string, ip string, username string, dir string) error { +// ensureDirectoryExists creates the directory on the remote node via SSH if it does not exist. +func (nm *Node) ensureDirectoryExists(username string, dir string) error { cmd := fmt.Sprintf("mkdir -p '%s'", dir) - return nm.RunSSHCommand(jumpboxIp, ip, username, cmd) + return nm.RunSSHCommand(username, cmd, true) } -func (n *NodeManager) CopyFile(jumpboxIp string, ip string, username string, src string, dst string) error { - client, err := n.GetSFTPClient(jumpboxIp, ip, username) +// copyFile copies a file from the local system to the remote node via SFTP. +func (n *Node) copyFile(jumpboxIp string, ip string, username string, src string, dst string) error { + client, err := n.getSFTPClient(jumpboxIp, ip, username) if err != nil { return fmt.Errorf("failed to get SSH client: %v", err) } @@ -312,178 +430,150 @@ func (n *NodeManager) CopyFile(jumpboxIp string, ip string, username string, src return nil } -func (n *Node) HasCommand(nm *NodeManager, command string) bool { - checkCommand := fmt.Sprintf("command -v %s >/dev/null 2>&1", command) - err := nm.RunSSHCommand("", n.ExternalIP, "root", checkCommand) - if err != nil { - // If the command returns a non-zero exit status, it means the command is not found - return false - } - return true -} +// getAuthMethods constructs a slice of ssh.AuthMethod, prioritizing the SSH agent. +func (n *Node) getAuthMethods() ([]ssh.AuthMethod, error) { + var signers []ssh.Signer -func (n *Node) InstallOms(nm *NodeManager) error { - remoteCommands := []string{ - "wget -qO- 'https://api.github.com/repos/codesphere-cloud/oms/releases/latest' | jq -r '.assets[] | select(.name | match(\"oms-cli.*linux_amd64\")) | .browser_download_url' | xargs wget -O oms-cli", - "chmod +x oms-cli; sudo mv oms-cli /usr/local/bin/", - "curl -LO https://github.com/getsops/sops/releases/download/v3.11.0/sops-v3.11.0.linux.amd64; sudo mv sops-v3.11.0.linux.amd64 /usr/local/bin/sops; sudo chmod +x /usr/local/bin/sops", - "wget https://dl.filippo.io/age/latest?for=linux/amd64 -O age.tar.gz; tar -xvf age.tar.gz; sudo mv age/age* /usr/local/bin/", - } - for _, cmd := range remoteCommands { - err := nm.RunSSHCommand("", n.ExternalIP, "root", cmd) - if err != nil { - return fmt.Errorf("failed to run remote command '%s': %w", cmd, err) + // 1. Get Agent Signers + if authSocket := os.Getenv("SSH_AUTH_SOCK"); authSocket != "" { + if conn, err := net.Dial("unix", authSocket); err == nil { + agentClient := agent.NewClient(conn) + if s, err := agentClient.Signers(); err == nil { + signers = append(signers, s...) + } } } - return nil -} -func (n *Node) CopyFile(jumpbox *Node, nm *NodeManager, src string, dst string) error { - if jumpbox == nil { - err := nm.EnsureDirectoryExists("", n.ExternalIP, "root", filepath.Dir(dst)) - if err != nil { - return fmt.Errorf("failed to ensure directory exists: %w", err) + // 2. Add Private Key (File) if needed + if n.keyPath != "" { + shouldLoad := true + + // Use cached signer if available + if n.cachedSigner != nil { + signers = append(signers, n.cachedSigner) + shouldLoad = false } - return nm.CopyFile("", n.ExternalIP, "root", src, dst) - } - err := nm.EnsureDirectoryExists(jumpbox.ExternalIP, n.InternalIP, "root", filepath.Dir(dst)) - if err != nil { - return fmt.Errorf("failed to ensure directory exists: %w", err) - } - return nm.CopyFile(jumpbox.ExternalIP, n.InternalIP, "root", src, dst) -} -// HasAcceptEnvConfigured checks if AcceptEnv is configured -func (n *Node) HasAcceptEnvConfigured(jumpbox *Node, nm *NodeManager) bool { - checkCommand := "sudo grep -E '^AcceptEnv OMS_PORTAL_API_KEY' /etc/ssh/sshd_config >/dev/null 2>&1" - err := n.RunSSHCommand(jumpbox, nm, "ubuntu", checkCommand) - if err != nil { - // If the command returns a NON-zero exit status, it means AcceptEnv is not configured - return false - } - return true -} + // Check if key is already in agent (requires .pub file) + if shouldLoad && len(signers) > 0 { + if pubBytes, err := n.FileIO.ReadFile(n.keyPath + ".pub"); err == nil { + if targetPub, _, _, _, err := ssh.ParseAuthorizedKey(pubBytes); err == nil { + targetMarshaled := string(targetPub.Marshal()) + for _, s := range signers { + if string(s.PublicKey().Marshal()) == targetMarshaled { + shouldLoad = false + break + } + } + } + } + } -func (n *Node) ConfigureAcceptEnv(jumpbox *Node, nm *NodeManager) error { - cmds := []string{ - "sudo sed -i 's/^#\\?AcceptEnv.*/AcceptEnv OMS_PORTAL_API_KEY/' /etc/ssh/sshd_config", - "sudo systemctl restart sshd", - } - for _, cmd := range cmds { - err := n.RunSSHCommand(jumpbox, nm, "ubuntu", cmd) - if err != nil { - return fmt.Errorf("failed to run command '%s': %w", cmd, err) + // Else load from file with passphrase prompt if needed + if shouldLoad { + if signer, err := n.loadPrivateKey(); err == nil { + n.cachedSigner = signer + signers = append(signers, signer) + } else { + log.Printf("Warning: failed to load private key: %v\n", err) + } } } - return nil -} -func (n *Node) HasRootLoginEnabled(jumpbox *Node, nm *NodeManager) bool { - checkCommandPermit := "sudo grep -E '^PermitRootLogin yes' /etc/ssh/sshd_config >/dev/null 2>&1" - err := n.RunSSHCommand(jumpbox, nm, "ubuntu", checkCommandPermit) - if err != nil { - // If the command returns a NON-zero exit status, it means root login is not permitted - return false - } - checkCommandAuthorizedKeys := "sudo grep -E '^no-port-forwarding' /root/.ssh/authorized_keys >/dev/null 2>&1" - err = n.RunSSHCommand(jumpbox, nm, "ubuntu", checkCommandAuthorizedKeys) - if err == nil { - // If the command returns a ZERO exit status, it means root login is prevented - return false + if len(signers) == 0 { + return nil, fmt.Errorf("no valid authentication methods configured. Check SSH_AUTH_SOCK and private key path") } - return true + + return []ssh.AuthMethod{ssh.PublicKeys(signers...)}, nil } -func (n *Node) HasFile(jumpbox *Node, nm *NodeManager, filePath string) bool { - checkCommand := fmt.Sprintf("test -f '%s'", filePath) - err := n.RunSSHCommand(jumpbox, nm, "ubuntu", checkCommand) +// loadPrivateKey reads and parses the private key, prompting for passphrase if needed. +func (n *Node) loadPrivateKey() (ssh.Signer, error) { + key, err := n.FileIO.ReadFile(n.keyPath) if err != nil { - // If the command returns a non-zero exit status, it means the file does not exist - return false + return nil, fmt.Errorf("failed to read private key file %s: %v", n.keyPath, err) } - return true -} -func (n *Node) RunSSHCommand(jumpbox *Node, nm *NodeManager, username string, command string) error { - if jumpbox == nil { - return nm.RunSSHCommand("", n.ExternalIP, username, command) + signer, err := ssh.ParsePrivateKey(key) + if err == nil { + return signer, nil } - return nm.RunSSHCommand(jumpbox.ExternalIP, n.InternalIP, username, command) -} - -func (n *Node) EnableRootLogin(jumpbox *Node, nm *NodeManager) error { - cmds := []string{ - "sudo sed -i 's/^#\\?PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config", - "sudo sed -i 's/no-port-forwarding.*$//g' /root/.ssh/authorized_keys", - "sudo systemctl restart sshd", + if _, ok := err.(*ssh.PassphraseMissingError); !ok { + return nil, fmt.Errorf("failed to parse private key: %v", err) } - for _, cmd := range cmds { - err := n.RunSSHCommand(jumpbox, nm, "ubuntu", cmd) - if err != nil { - return fmt.Errorf("failed to run command '%s': %w", cmd, err) - } + + // Key is encrypted, prompt for passphrase + log.Printf("Enter passphrase for key '%s': ", n.keyPath) + passphrase, err := term.ReadPassword(int(syscall.Stdin)) + log.Println() + if err != nil { + return nil, fmt.Errorf("failed to read passphrase: %v", err) } - return nil -} -func (n *Node) WaitForSSH(jumpbox *Node, nm *NodeManager, timeout time.Duration) error { - start := time.Now() - jumpboxIp := "" - nodeIp := n.ExternalIP - if jumpbox != nil { - jumpboxIp = jumpbox.ExternalIP - nodeIp = n.InternalIP + signer, err = ssh.ParsePrivateKeyWithPassphrase(key, passphrase) + // Clear passphrase from memory + for i := range passphrase { + passphrase[i] = 0 } - for { - client, err := nm.GetClient(jumpboxIp, nodeIp, jumpboxUser) - if err == nil { - _ = client.Close() - return nil - } - if time.Since(start) > timeout { - return fmt.Errorf("timeout waiting for SSH on node %s (%s)", n.Name, n.ExternalIP) - } - time.Sleep(5 * time.Second) + if err != nil { + return nil, fmt.Errorf("failed to parse private key with passphrase: %v", err) } -} -func (n *Node) HasInotifyWatchesConfigured(jumpbox *Node, nm *NodeManager) bool { - return n.HasSysctlLine(jumpbox, "fs.inotify.max_user_watches=1048576", nm) -} - -func (n *Node) ConfigureInotifyWatches(jumpbox *Node, nm *NodeManager) error { - return n.ConfigureSysctlLine(jumpbox, "fs.inotify.max_user_watches=1048576", nm) + return signer, nil } -func (n *Node) HasMemoryMapConfigured(jumpbox *Node, nm *NodeManager) bool { - return n.HasSysctlLine(jumpbox, "vm.max_map_count=262144", nm) -} +func (n *Node) connectToJumpbox(ip, username string) (*ssh.Client, error) { + authMethods, err := n.getAuthMethods() + if err != nil { + return nil, fmt.Errorf("jumpbox authentication setup failed: %v", err) + } -func (n *Node) ConfigureMemoryMap(jumpbox *Node, nm *NodeManager) error { - return n.ConfigureSysctlLine(jumpbox, "vm.max_map_count=262144", nm) -} + config := &ssh.ClientConfig{ + User: username, + Auth: authMethods, + Timeout: 10 * time.Second, + // WARNING: Still using InsecureIgnoreHostKey for simplicity. Use known_hosts in production. + HostKeyCallback: ssh.InsecureIgnoreHostKey(), + } -func (n *Node) HasSysctlLine(jumpbox *Node, line string, nm *NodeManager) bool { - checkCommand := fmt.Sprintf("sudo grep -E '^%s' /etc/sysctl.conf >/dev/null 2>&1", line) - err := n.RunSSHCommand(jumpbox, nm, "root", checkCommand) + addr := fmt.Sprintf("%s:22", ip) + jumpboxClient, err := ssh.Dial("tcp", addr, config) if err != nil { - // If the command returns a NON-zero exit status, it means the setting is not configured - return false + return nil, fmt.Errorf("failed to dial jumpbox %s: %v", addr, err) } - return true -} -func (n *Node) ConfigureSysctlLine(jumpbox *Node, line string, nm *NodeManager) error { - cmds := []string{ - fmt.Sprintf("echo '%s' | sudo tee -a /etc/sysctl.conf", line), - "sudo sysctl -p", + // Enable Agent Forwarding on the jumpbox connection + if err := n.forwardAgent(jumpboxClient, nil); err != nil { + fmt.Printf(" Warning: Agent forwarding setup failed on jumpbox: %v\n", err) } - for _, cmd := range cmds { - err := n.RunSSHCommand(jumpbox, nm, "root", cmd) + + return jumpboxClient, nil +} + +func (n *Node) forwardAgent(client *ssh.Client, session *ssh.Session) error { + authSocket := os.Getenv("SSH_AUTH_SOCK") + if authSocket == "" { + log.Printf("SSH_AUTH_SOCK not set. Cannot perform agent forwarding") + } else { + // Connect to the local SSH Agent socket + conn, err := net.Dial("unix", authSocket) if err != nil { - return fmt.Errorf("failed to run command '%s': %w", cmd, err) + log.Printf("failed to dial SSH agent socket: %v", err) + } else { + // Create an agent client for the local agent + ag := agent.NewClient(conn) + // This tells the remote server to proxy authentication requests back to us. + if err := agent.ForwardToAgent(client, ag); err != nil { + log.Printf("failed to forward agent to remote client: %v", err) + } + if session != nil { + if err := agent.RequestAgentForwarding(session); err != nil { + log.Printf("failed to request agent forwarding on session: %v", err) + } + } } + } return nil } diff --git a/internal/util/path.go b/internal/util/path.go new file mode 100644 index 00000000..4a4f9bf4 --- /dev/null +++ b/internal/util/path.go @@ -0,0 +1,17 @@ +package util + +import ( + "os" + "path/filepath" + "strings" +) + +// ExpandPath expands ~ to the user's home directory +func ExpandPath(path string) string { + if strings.HasPrefix(path, "~/") { + if home, err := os.UserHomeDir(); err == nil { + return filepath.Join(home, path[2:]) + } + } + return path +} diff --git a/internal/util/string.go b/internal/util/string.go new file mode 100644 index 00000000..a7354ec5 --- /dev/null +++ b/internal/util/string.go @@ -0,0 +1,9 @@ +package util + +func Truncate(s string, max int) string { + runes := []rune(s) + if len(runes) <= max { + return s + } + return string(runes[:max-3]) + "..." +} From 4b3372e828683747bb6138d69cbd624e6ca9c7bc Mon Sep 17 00:00:00 2001 From: Simon Herrmann Date: Thu, 29 Jan 2026 13:04:20 +0100 Subject: [PATCH 02/12] update: small clean ups --- internal/bootstrap/gcp/gcp.go | 13 +++++------ internal/bootstrap/gcp/gcp_client.go | 2 ++ internal/bootstrap/gcp/gcp_test.go | 35 ++++++++++++++++------------ 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/internal/bootstrap/gcp/gcp.go b/internal/bootstrap/gcp/gcp.go index bfe55f8e..47c1a746 100644 --- a/internal/bootstrap/gcp/gcp.go +++ b/internal/bootstrap/gcp/gcp.go @@ -5,6 +5,7 @@ package gcp import ( "context" + "errors" "fmt" "sort" "strings" @@ -649,12 +650,12 @@ func (b *GCPBootstrapper) EnsureComputeInstances() error { close(errCh) close(resultCh) - errStr := "" + var errs []error for err := range errCh { - errStr += err.Error() + "; " + errs = append(errs, err) } - if errStr != "" { - return fmt.Errorf("error ensuring compute instances: %s", errStr) + if len(errs) > 0 { + return fmt.Errorf("error ensuring compute instances: %w", errors.Join(errs...)) } // Create nodes from results (in main goroutine, not in spawned goroutines) @@ -879,7 +880,7 @@ func (b *GCPBootstrapper) EnsureLocalContainerRegistry() error { if err != nil { return fmt.Errorf("failed to update CA certificates on node %s: %w", node.GetInternalIP(), err) } - err = node.RunSSHCommand("root", "systemctl restart docker.service || true", true) // docker is probably not yet instb.sshQuietd + err = node.RunSSHCommand("root", "systemctl restart docker.service || true", true) // docker is probably not yet installed if err != nil { return fmt.Errorf("failed to restart docker service on node %s: %w", node.GetInternalIP(), err) } @@ -1328,8 +1329,6 @@ systemctl restart k0scontroller } // Helper functions -func protoInt32(i int32) *int32 { return &i } -func protoInt64(i int64) *int64 { return &i } func isAlreadyExistsError(err error) bool { return status.Code(err) == codes.AlreadyExists || strings.Contains(err.Error(), "already exists") } diff --git a/internal/bootstrap/gcp/gcp_client.go b/internal/bootstrap/gcp/gcp_client.go index 21ee7024..64f19304 100644 --- a/internal/bootstrap/gcp/gcp_client.go +++ b/internal/bootstrap/gcp/gcp_client.go @@ -645,3 +645,5 @@ func (c *GCPClient) EnsureDNSRecordSets(projectID, zoneName string, records []*d // Helper functions func protoString(s string) *string { return &s } func protoBool(b bool) *bool { return &b } +func protoInt32(i int32) *int32 { return &i } +func protoInt64(i int64) *int64 { return &i } diff --git a/internal/bootstrap/gcp/gcp_test.go b/internal/bootstrap/gcp/gcp_test.go index 64a8bedb..774ad051 100644 --- a/internal/bootstrap/gcp/gcp_test.go +++ b/internal/bootstrap/gcp/gcp_test.go @@ -28,6 +28,8 @@ import ( "google.golang.org/api/dns/v1" ) +func protoString(s string) *string { return &s } + var _ = Describe("NewGCPBootstrapper", func() { It("creates a valid GCPBootstrapper", func() { env := env.NewEnv() @@ -254,8 +256,6 @@ var _ = Describe("Bootstrap", func() { }) }) -func protoString(s string) *string { return &s } - var _ = Describe("EnsureInstallConfig", func() { Describe("Valid EnsureInstallConfig", func() { It("uses existing when config file exists", func() { @@ -867,13 +867,13 @@ var _ = Describe("EnsureLocalContainerRegistry", func() { return strings.Contains(cmd, "podman ps") }), true).Return(fmt.Errorf("not running")) - // Install commands (8 commands in list) - nm.EXPECT().RunSSHCommand("root", mock.Anything, false).Return(nil).Times(8) + // Install commands (8 commands) + scp/update-ca/docker commands (3 per 4 nodes = 12) + nm.EXPECT().RunSSHCommand("root", mock.Anything, true).Return(nil).Times(8 + 12) bs.Env.ControlPlaneNodes = []node.NodeManager{nm, nm} bs.Env.CephNodes = []node.NodeManager{nm, nm} - nm.EXPECT().RunSSHCommand("root", mock.Anything, true).Return(nil).Times(3 * 4) + nm.EXPECT().GetName().Return("mocknode").Maybe() err = bs.EnsureLocalContainerRegistry() Expect(err).NotTo(HaveOccurred()) @@ -927,10 +927,10 @@ var _ = Describe("EnsureLocalContainerRegistry", func() { }), true).Return(fmt.Errorf("not running")) // First 7 install commands succeed - nm.EXPECT().RunSSHCommand("root", mock.Anything, false).Return(nil).Times(7) + nm.EXPECT().RunSSHCommand("root", mock.Anything, true).Return(nil).Times(7) // 8th install command fails - nm.EXPECT().RunSSHCommand("root", mock.Anything, false).Return(fmt.Errorf("ssh error")).Once() + nm.EXPECT().RunSSHCommand("root", mock.Anything, true).Return(fmt.Errorf("ssh error")).Once() err := bs.EnsureLocalContainerRegistry() Expect(err).To(HaveOccurred()) @@ -938,13 +938,16 @@ var _ = Describe("EnsureLocalContainerRegistry", func() { }) It("fails when the first scp command fails", func() { + // GetName is called in Logf + nm.EXPECT().GetName().Return("mocknode").Maybe() + // First check - registry not running nm.EXPECT().RunSSHCommand("root", mock.MatchedBy(func(cmd string) bool { return strings.Contains(cmd, "podman ps") }), true).Return(fmt.Errorf("not running")) // All 8 install commands succeed - nm.EXPECT().RunSSHCommand("root", mock.Anything, false).Return(nil).Times(8) + nm.EXPECT().RunSSHCommand("root", mock.Anything, true).Return(nil).Times(8) // First scp command fails nm.EXPECT().RunSSHCommand("root", mock.MatchedBy(func(cmd string) bool { @@ -963,6 +966,7 @@ var _ = Describe("EnsureLocalContainerRegistry", func() { bs.Env.CephNodes = []node.NodeManager{} node1.EXPECT().GetInternalIP().Return("10.0.0.2").Maybe() + node1.EXPECT().GetName().Return("node1").Maybe() // First check - registry not running nm.EXPECT().RunSSHCommand("root", mock.MatchedBy(func(cmd string) bool { @@ -970,7 +974,7 @@ var _ = Describe("EnsureLocalContainerRegistry", func() { }), true).Return(fmt.Errorf("not running")) // All 8 install commands succeed - nm.EXPECT().RunSSHCommand("root", mock.Anything, false).Return(nil).Times(8) + nm.EXPECT().RunSSHCommand("root", mock.Anything, true).Return(nil).Times(8) // scp succeeds nm.EXPECT().RunSSHCommand("root", mock.MatchedBy(func(cmd string) bool { @@ -992,6 +996,7 @@ var _ = Describe("EnsureLocalContainerRegistry", func() { bs.Env.CephNodes = []node.NodeManager{} node1.EXPECT().GetInternalIP().Return("10.0.0.2").Maybe() + node1.EXPECT().GetName().Return("node1").Maybe() // First check - registry not running nm.EXPECT().RunSSHCommand("root", mock.MatchedBy(func(cmd string) bool { @@ -999,7 +1004,7 @@ var _ = Describe("EnsureLocalContainerRegistry", func() { }), true).Return(fmt.Errorf("not running")) // All 8 install commands succeed - nm.EXPECT().RunSSHCommand("root", mock.Anything, false).Return(nil).Times(8) + nm.EXPECT().RunSSHCommand("root", mock.Anything, true).Return(nil).Times(8) // scp succeeds nm.EXPECT().RunSSHCommand("root", mock.MatchedBy(func(cmd string) bool { @@ -2371,10 +2376,10 @@ var _ = Describe("InstallCodesphere", func() { bs.Env.Jumpbox = nm // Expect download package - nm.EXPECT().RunSSHCommand("root", "oms-cli download package v1.2.3", false).Return(nil) + nm.EXPECT().RunSSHCommand("root", "oms-cli download package v1.2.3", true).Return(nil) // Expect install codesphere - nm.EXPECT().RunSSHCommand("root", "oms-cli install codesphere -c /etc/codesphere/config.yaml -k /secrets/age_key.txt -p v1.2.3.tar.gz", false).Return(nil) + nm.EXPECT().RunSSHCommand("root", "oms-cli install codesphere -c /etc/codesphere/config.yaml -k /secrets/age_key.txt -p v1.2.3.tar.gz", true).Return(nil) err = bs.InstallCodesphere() Expect(err).NotTo(HaveOccurred()) @@ -2400,7 +2405,7 @@ var _ = Describe("InstallCodesphere", func() { Expect(err).NotTo(HaveOccurred()) bs.Env.Jumpbox = nm - nm.EXPECT().RunSSHCommand("root", "oms-cli download package v1.2.3", false).Return(fmt.Errorf("download error")) + nm.EXPECT().RunSSHCommand("root", "oms-cli download package v1.2.3", true).Return(fmt.Errorf("download error")) err = bs.InstallCodesphere() Expect(err).To(HaveOccurred()) @@ -2425,8 +2430,8 @@ var _ = Describe("InstallCodesphere", func() { Expect(err).NotTo(HaveOccurred()) bs.Env.Jumpbox = nm - nm.EXPECT().RunSSHCommand("root", "oms-cli download package v1.2.3", false).Return(nil) - nm.EXPECT().RunSSHCommand("root", "oms-cli install codesphere -c /etc/codesphere/config.yaml -k /secrets/age_key.txt -p v1.2.3.tar.gz", false).Return(fmt.Errorf("install error")) + nm.EXPECT().RunSSHCommand("root", "oms-cli download package v1.2.3", true).Return(nil) + nm.EXPECT().RunSSHCommand("root", "oms-cli install codesphere -c /etc/codesphere/config.yaml -k /secrets/age_key.txt -p v1.2.3.tar.gz", true).Return(fmt.Errorf("install error")) err = bs.InstallCodesphere() Expect(err).To(HaveOccurred()) From 31708849f8a96aa1b3685d763a57c1d5cdfb55a5 Mon Sep 17 00:00:00 2001 From: siherrmann <25087590+siherrmann@users.noreply.github.com> Date: Thu, 29 Jan 2026 12:09:56 +0000 Subject: [PATCH 03/12] chore(docs): Auto-update docs and licenses Signed-off-by: siherrmann <25087590+siherrmann@users.noreply.github.com> --- internal/bootstrap/bootstrap_stepper.go | 3 +++ internal/bootstrap/ovh/ovh.go | 3 +++ internal/util/path.go | 3 +++ internal/util/string.go | 3 +++ 4 files changed, 12 insertions(+) diff --git a/internal/bootstrap/bootstrap_stepper.go b/internal/bootstrap/bootstrap_stepper.go index 37800fd6..2e53802a 100644 --- a/internal/bootstrap/bootstrap_stepper.go +++ b/internal/bootstrap/bootstrap_stepper.go @@ -1,3 +1,6 @@ +// Copyright (c) Codesphere Inc. +// SPDX-License-Identifier: Apache-2.0 + package bootstrap import ( diff --git a/internal/bootstrap/ovh/ovh.go b/internal/bootstrap/ovh/ovh.go index cc7e224c..08936af4 100644 --- a/internal/bootstrap/ovh/ovh.go +++ b/internal/bootstrap/ovh/ovh.go @@ -1,3 +1,6 @@ +// Copyright (c) Codesphere Inc. +// SPDX-License-Identifier: Apache-2.0 + package ovh import "log" diff --git a/internal/util/path.go b/internal/util/path.go index 4a4f9bf4..42dc6f59 100644 --- a/internal/util/path.go +++ b/internal/util/path.go @@ -1,3 +1,6 @@ +// Copyright (c) Codesphere Inc. +// SPDX-License-Identifier: Apache-2.0 + package util import ( diff --git a/internal/util/string.go b/internal/util/string.go index a7354ec5..bcabcbfd 100644 --- a/internal/util/string.go +++ b/internal/util/string.go @@ -1,3 +1,6 @@ +// Copyright (c) Codesphere Inc. +// SPDX-License-Identifier: Apache-2.0 + package util func Truncate(s string, max int) string { From 2d0910a7160a6f01906149f98f1ee9a791d8eb99 Mon Sep 17 00:00:00 2001 From: Simon Herrmann Date: Thu, 29 Jan 2026 13:14:04 +0100 Subject: [PATCH 04/12] fix: fix copilot review issues --- internal/bootstrap/gcp/gcp_client.go | 2 +- internal/installer/node/node.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/bootstrap/gcp/gcp_client.go b/internal/bootstrap/gcp/gcp_client.go index 64f19304..fd1baaf4 100644 --- a/internal/bootstrap/gcp/gcp_client.go +++ b/internal/bootstrap/gcp/gcp_client.go @@ -214,7 +214,7 @@ func (c *GCPClient) EnableAPIs(projectID string, apis []string) error { return nil } -// GetArtifactRegistry retrieves an Artifact Registry repository by its name. +// CreateArtifactRegistry creates and returns an Artifact Registry repository by its name. func (c *GCPClient) CreateArtifactRegistry(projectID, region, repoName string) (*artifactpb.Repository, error) { client, err := artifact.NewClient(c.ctx) if err != nil { diff --git a/internal/installer/node/node.go b/internal/installer/node/node.go index a11e8b4c..e6e94577 100644 --- a/internal/installer/node/node.go +++ b/internal/installer/node/node.go @@ -89,17 +89,17 @@ func (n *Node) UpdateNode(name string, externalIP string, internalIP string) { n.InternalIP = internalIP } -// GetExternalIP updates the external IP of the node +// GetExternalIP returns the external IP of the node func (n *Node) GetExternalIP() string { return n.ExternalIP } -// GetInternalIP updates the internal IP of the node +// GetInternalIP returns the internal IP of the node func (n *Node) GetInternalIP() string { return n.InternalIP } -// Name returns the name of the node +// GetName returns the name of the node func (n *Node) GetName() string { return n.Name } From 8a47f9d8f84693a3e7161cec0fa47c0e5e64d206 Mon Sep 17 00:00:00 2001 From: Simon Herrmann Date: Thu, 29 Jan 2026 13:19:22 +0100 Subject: [PATCH 05/12] fix: fix lint issues --- internal/bootstrap/gcp/gcp_client.go | 2 +- internal/bootstrap/gcp/gcp_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/bootstrap/gcp/gcp_client.go b/internal/bootstrap/gcp/gcp_client.go index fd1baaf4..320bbd9a 100644 --- a/internal/bootstrap/gcp/gcp_client.go +++ b/internal/bootstrap/gcp/gcp_client.go @@ -237,7 +237,7 @@ func (c *GCPClient) CreateArtifactRegistry(projectID, region, repoName string) ( } var repo *artifactpb.Repository if err == nil { - repo, err = op.Wait(c.ctx) + _, err = op.Wait(c.ctx) if err != nil { return nil, err } diff --git a/internal/bootstrap/gcp/gcp_test.go b/internal/bootstrap/gcp/gcp_test.go index 774ad051..0a2149e9 100644 --- a/internal/bootstrap/gcp/gcp_test.go +++ b/internal/bootstrap/gcp/gcp_test.go @@ -99,7 +99,7 @@ var _ = Describe("Bootstrap", func() { // Returning a real install config to avoid nil pointer dereferences later icg.EXPECT().GetInstallConfig().RunAndReturn(func() *files.RootConfig { realIcm := installer.NewInstallConfigManager() - realIcm.ApplyProfile("dev") + _ = realIcm.ApplyProfile("dev") return realIcm.GetInstallConfig() }) From 788a07915cf1d058d2c55c77fe23db7f43eba42a Mon Sep 17 00:00:00 2001 From: siherrmann <25087590+siherrmann@users.noreply.github.com> Date: Thu, 29 Jan 2026 12:31:47 +0000 Subject: [PATCH 06/12] chore(docs): Auto-update docs and licenses Signed-off-by: siherrmann <25087590+siherrmann@users.noreply.github.com> --- NOTICE | 24 ++++++++++++------------ internal/tmpl/NOTICE | 24 ++++++++++++------------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/NOTICE b/NOTICE index ab64d489..7bbe52e5 100644 --- a/NOTICE +++ b/NOTICE @@ -11,9 +11,9 @@ License URL: https://github.com/googleapis/google-cloud-go/blob/artifactregistry ---------- Module: cloud.google.com/go/auth -Version: v0.18.0 +Version: v0.18.1 License: Apache-2.0 -License URL: https://github.com/googleapis/google-cloud-go/blob/auth/v0.18.0/auth/LICENSE +License URL: https://github.com/googleapis/google-cloud-go/blob/auth/v0.18.1/auth/LICENSE ---------- Module: cloud.google.com/go/auth/oauth2adapt @@ -23,9 +23,9 @@ License URL: https://github.com/googleapis/google-cloud-go/blob/auth/oauth2adapt ---------- Module: cloud.google.com/go/compute -Version: v1.53.0 +Version: v1.54.0 License: Apache-2.0 -License URL: https://github.com/googleapis/google-cloud-go/blob/compute/v1.53.0/compute/LICENSE +License URL: https://github.com/googleapis/google-cloud-go/blob/compute/v1.54.0/compute/LICENSE ---------- Module: cloud.google.com/go/compute/metadata @@ -95,9 +95,9 @@ License URL: https://github.com/clipperhouse/uax29/blob/v2.3.0/LICENSE ---------- Module: github.com/codesphere-cloud/cs-go/pkg/io -Version: v0.15.0 +Version: v0.16.1 License: Apache-2.0 -License URL: https://github.com/codesphere-cloud/cs-go/blob/v0.15.0/LICENSE +License URL: https://github.com/codesphere-cloud/cs-go/blob/v0.16.1/LICENSE ---------- Module: github.com/codesphere-cloud/oms/internal/tmpl @@ -401,15 +401,15 @@ License URL: https://cs.opensource.google/go/x/time/+/v0.14.0:LICENSE ---------- Module: google.golang.org/api -Version: v0.261.0 +Version: v0.263.0 License: BSD-3-Clause -License URL: https://github.com/googleapis/google-api-go-client/blob/v0.261.0/LICENSE +License URL: https://github.com/googleapis/google-api-go-client/blob/v0.263.0/LICENSE ---------- Module: google.golang.org/api/internal/third_party/uritemplates -Version: v0.261.0 +Version: v0.263.0 License: BSD-3-Clause -License URL: https://github.com/googleapis/google-api-go-client/blob/v0.261.0/internal/third_party/uritemplates/LICENSE +License URL: https://github.com/googleapis/google-api-go-client/blob/v0.263.0/internal/third_party/uritemplates/LICENSE ---------- Module: google.golang.org/genproto/googleapis @@ -425,9 +425,9 @@ License URL: https://github.com/googleapis/go-genproto/blob/0a764e51fe1b/googlea ---------- Module: google.golang.org/genproto/googleapis/rpc -Version: v0.0.0-20260120174246-409b4a993575 +Version: v0.0.0-20260122232226-8e98ce8d340d License: Apache-2.0 -License URL: https://github.com/googleapis/go-genproto/blob/409b4a993575/googleapis/rpc/LICENSE +License URL: https://github.com/googleapis/go-genproto/blob/8e98ce8d340d/googleapis/rpc/LICENSE ---------- Module: google.golang.org/grpc diff --git a/internal/tmpl/NOTICE b/internal/tmpl/NOTICE index ab64d489..7bbe52e5 100644 --- a/internal/tmpl/NOTICE +++ b/internal/tmpl/NOTICE @@ -11,9 +11,9 @@ License URL: https://github.com/googleapis/google-cloud-go/blob/artifactregistry ---------- Module: cloud.google.com/go/auth -Version: v0.18.0 +Version: v0.18.1 License: Apache-2.0 -License URL: https://github.com/googleapis/google-cloud-go/blob/auth/v0.18.0/auth/LICENSE +License URL: https://github.com/googleapis/google-cloud-go/blob/auth/v0.18.1/auth/LICENSE ---------- Module: cloud.google.com/go/auth/oauth2adapt @@ -23,9 +23,9 @@ License URL: https://github.com/googleapis/google-cloud-go/blob/auth/oauth2adapt ---------- Module: cloud.google.com/go/compute -Version: v1.53.0 +Version: v1.54.0 License: Apache-2.0 -License URL: https://github.com/googleapis/google-cloud-go/blob/compute/v1.53.0/compute/LICENSE +License URL: https://github.com/googleapis/google-cloud-go/blob/compute/v1.54.0/compute/LICENSE ---------- Module: cloud.google.com/go/compute/metadata @@ -95,9 +95,9 @@ License URL: https://github.com/clipperhouse/uax29/blob/v2.3.0/LICENSE ---------- Module: github.com/codesphere-cloud/cs-go/pkg/io -Version: v0.15.0 +Version: v0.16.1 License: Apache-2.0 -License URL: https://github.com/codesphere-cloud/cs-go/blob/v0.15.0/LICENSE +License URL: https://github.com/codesphere-cloud/cs-go/blob/v0.16.1/LICENSE ---------- Module: github.com/codesphere-cloud/oms/internal/tmpl @@ -401,15 +401,15 @@ License URL: https://cs.opensource.google/go/x/time/+/v0.14.0:LICENSE ---------- Module: google.golang.org/api -Version: v0.261.0 +Version: v0.263.0 License: BSD-3-Clause -License URL: https://github.com/googleapis/google-api-go-client/blob/v0.261.0/LICENSE +License URL: https://github.com/googleapis/google-api-go-client/blob/v0.263.0/LICENSE ---------- Module: google.golang.org/api/internal/third_party/uritemplates -Version: v0.261.0 +Version: v0.263.0 License: BSD-3-Clause -License URL: https://github.com/googleapis/google-api-go-client/blob/v0.261.0/internal/third_party/uritemplates/LICENSE +License URL: https://github.com/googleapis/google-api-go-client/blob/v0.263.0/internal/third_party/uritemplates/LICENSE ---------- Module: google.golang.org/genproto/googleapis @@ -425,9 +425,9 @@ License URL: https://github.com/googleapis/go-genproto/blob/0a764e51fe1b/googlea ---------- Module: google.golang.org/genproto/googleapis/rpc -Version: v0.0.0-20260120174246-409b4a993575 +Version: v0.0.0-20260122232226-8e98ce8d340d License: Apache-2.0 -License URL: https://github.com/googleapis/go-genproto/blob/409b4a993575/googleapis/rpc/LICENSE +License URL: https://github.com/googleapis/go-genproto/blob/8e98ce8d340d/googleapis/rpc/LICENSE ---------- Module: google.golang.org/grpc From 303efae6e70c6f7d223a9a70f61683d647295265 Mon Sep 17 00:00:00 2001 From: Simon Herrmann Date: Thu, 29 Jan 2026 16:25:11 +0100 Subject: [PATCH 07/12] update: add ssh client caching, add ssh quiet flag --- cli/cmd/bootstrap_gcp.go | 6 +- internal/bootstrap/gcp/gcp.go | 42 +++---- internal/installer/node/node.go | 204 ++++++++++++++++++-------------- 3 files changed, 141 insertions(+), 111 deletions(-) diff --git a/cli/cmd/bootstrap_gcp.go b/cli/cmd/bootstrap_gcp.go index ed5b50aa..301b461a 100644 --- a/cli/cmd/bootstrap_gcp.go +++ b/cli/cmd/bootstrap_gcp.go @@ -26,6 +26,7 @@ type BootstrapGcpCmd struct { Env env.Env CodesphereEnv *gcp.CodesphereEnvironment InputRegistryType string + SSHQuiet bool } func (c *BootstrapGcpCmd) RunE(_ *cobra.Command, args []string) error { @@ -75,6 +76,7 @@ func AddBootstrapGcpCmd(root *cobra.Command, opts *GlobalOptions) { flags.StringVar(&bootstrapGcpCmd.CodesphereEnv.InstallCodesphereVersion, "install-codesphere-version", "", "Codesphere version to install (default: none)") flags.StringVar(&bootstrapGcpCmd.InputRegistryType, "registry-type", "local-container", "Container registry type to use (options: local-container, artifact-registry) (default: artifact-registry)") flags.BoolVar(&bootstrapGcpCmd.CodesphereEnv.WriteConfig, "write-config", true, "Write generated install config to file (default: true)") + flags.BoolVar(&bootstrapGcpCmd.SSHQuiet, "ssh-quiet", true, "Suppress SSH command output (default: true)") util.MarkFlagRequired(bootstrapGcpCmd.cmd, "project-name") util.MarkFlagRequired(bootstrapGcpCmd.cmd, "billing-account") @@ -90,7 +92,7 @@ func (c *BootstrapGcpCmd) BootstrapGcp() error { icg := installer.NewInstallConfigManager() gcpClient := gcp.NewGCPClient(ctx, stlog, os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")) fw := util.NewFilesystemWriter() - nm := node.NewNode(fw, c.CodesphereEnv.SSHPrivateKeyPath) + nm := node.NewNode(fw, c.CodesphereEnv.SSHPrivateKeyPath, c.SSHQuiet) bs, err := gcp.NewGCPBootstrapper(ctx, c.Env, stlog, c.CodesphereEnv, icg, gcpClient, nm, fw) if err != nil { @@ -112,7 +114,7 @@ func (c *BootstrapGcpCmd) BootstrapGcp() error { return fmt.Errorf("failed to bootstrap GCP: %w, env: %s", err, envString) } - log.Println("\nGCP infrastructure bootstrapped:") + log.Println("\n🎉🎉🎉 GCP infrastructure bootstrapped successfully!") log.Println(envString) log.Printf("Start the Codesphere installation using OMS from the jumpbox host:\nssh-add $SSH_KEY_PATH; ssh -o StrictHostKeyChecking=no -o ForwardAgent=yes -o SendEnv=OMS_PORTAL_API_KEY root@%s", bs.Env.Jumpbox.GetExternalIP()) log.Printf("When the installation is done, run the k0s configuration script generated at the k0s-1 host %s /root/configure-k0s.sh.", bs.Env.ControlPlaneNodes[0].GetInternalIP()) diff --git a/internal/bootstrap/gcp/gcp.go b/internal/bootstrap/gcp/gcp.go index 47c1a746..431ecba0 100644 --- a/internal/bootstrap/gcp/gcp.go +++ b/internal/bootstrap/gcp/gcp.go @@ -74,36 +74,36 @@ type CodesphereEnvironment struct { PostgreSQLNode node.NodeManager `json:"postgresql_node"` ControlPlaneNodes []node.NodeManager `json:"control_plane_nodes"` CephNodes []node.NodeManager `json:"ceph_nodes"` - ContainerRegistryURL string `json:"container_registry_url"` - ExistingConfigUsed bool `json:"existing_config_used"` + ContainerRegistryURL string `json:"-"` + ExistingConfigUsed bool `json:"-"` InstallCodesphereVersion string `json:"install_codesphere_version"` Preemptible bool `json:"preemptible"` - WriteConfig bool `json:"write_config"` + WriteConfig bool `json:"-"` GatewayIP string `json:"gateway_ip"` PublicGatewayIP string `json:"public_gateway_ip"` RegistryType RegistryType `json:"registry_type"` // Config - InstallConfigPath string - SecretsFilePath string - InstallConfig *files.RootConfig - Secrets *files.InstallVault + InstallConfigPath string `json:"-"` + SecretsFilePath string `json:"-"` + InstallConfig *files.RootConfig `json:"-"` + Secrets *files.InstallVault `json:"-"` // GCP Specific - ProjectDisplayName string - BillingAccount string - BaseDomain string - GithubAppClientID string - GithubAppClientSecret string - SecretsDir string - FolderID string - SSHPublicKeyPath string - SSHPrivateKeyPath string - DatacenterID int - CustomPgIP string - Region string - Zone string - DNSZoneName string + ProjectDisplayName string `json:"project_display_name"` + BillingAccount string `json:"billing_account"` + BaseDomain string `json:"base_domain"` + GithubAppClientID string `json:"-"` + GithubAppClientSecret string `json:"-"` + SecretsDir string `json:"secrets_dir"` + FolderID string `json:"folder_id"` + SSHPublicKeyPath string `json:"-"` + SSHPrivateKeyPath string `json:"-"` + DatacenterID int `json:"-"` + CustomPgIP string `json:"custom_pg_ip"` + Region string `json:"region"` + Zone string `json:"zone"` + DNSZoneName string `json:"dns_zone_name"` } func NewGCPBootstrapper(ctx context.Context, env env.Env, stlog *bootstrap.StepLogger, CodesphereEnv *CodesphereEnvironment, icg installer.InstallConfigManager, gcpClient GCPClientManager, nm node.NodeManager, fw util.FileIO) (*GCPBootstrapper, error) { diff --git a/internal/installer/node/node.go b/internal/installer/node/node.go index e6e94577..8223416f 100644 --- a/internal/installer/node/node.go +++ b/internal/installer/node/node.go @@ -9,6 +9,7 @@ import ( "net" "os" "path/filepath" + "sync" "syscall" "time" @@ -58,27 +59,37 @@ type Node struct { ExternalIP string `json:"external_ip"` InternalIP string `json:"internal_ip"` cachedSigner ssh.Signer `json:"-"` + sshQuiet bool `json:"-"` + // SSH client cache: map[username]*ssh.Client + clientCache map[string]*ssh.Client + clientMu sync.Mutex } const jumpboxUser = "ubuntu" // NewNode creates a new Node with the given FileIO and SSH key path -func NewNode(fileIO util.FileIO, keyPath string) *Node { +func NewNode(fileIO util.FileIO, keyPath string, sshQuiet bool) *Node { return &Node{ - FileIO: fileIO, - keyPath: util.ExpandPath(keyPath), + FileIO: fileIO, + keyPath: util.ExpandPath(keyPath), + clientCache: make(map[string]*ssh.Client), + sshQuiet: sshQuiet, } } // CreateSubNode creates a Node object representing a node behind a jumpbox func (n *Node) CreateSubNode(name string, externalIP string, internalIP string) NodeManager { return &Node{ - FileIO: n.FileIO, - Jumpbox: n, - keyPath: util.ExpandPath(n.keyPath), - Name: name, - ExternalIP: externalIP, - InternalIP: internalIP, + // Inherited from jumpbox + FileIO: n.FileIO, + Jumpbox: n, + keyPath: util.ExpandPath(n.keyPath), + sshQuiet: n.sshQuiet, + // Custom + Name: name, + ExternalIP: externalIP, + InternalIP: internalIP, + clientCache: make(map[string]*ssh.Client), } } @@ -104,7 +115,8 @@ func (n *Node) GetName() string { return n.Name } -// WaitForSSH tries to connect to the node via SSH until timeout +// WaitForSSH tries to connect to the node via SSH until timeout. +// Once successful, the connection is cached for reuse. func (n *Node) WaitForSSH(timeout time.Duration) error { start := time.Now() jumpboxIp := "" @@ -114,13 +126,14 @@ func (n *Node) WaitForSSH(timeout time.Duration) error { nodeIp = n.InternalIP } for { - client, err := n.getClient(jumpboxIp, nodeIp, jumpboxUser) + // Try to get or create a cached client + _, err := n.getOrCreateClient(jumpboxIp, nodeIp, jumpboxUser) if err == nil { - _ = client.Close() + // Connection successful and cached return nil } if time.Since(start) > timeout { - return fmt.Errorf("timeout waiting for SSH on node %s (%s)", n.Name, n.ExternalIP) + return fmt.Errorf("timeout: %w", err) } time.Sleep(5 * time.Second) } @@ -128,6 +141,7 @@ func (n *Node) WaitForSSH(timeout time.Duration) error { // RunSSHCommand connects to the node, executes a command and streams the output. // If quiet is true, command output is not printed to stdout/stderr. +// The SSH client connection is cached and reused for subsequent commands. func (n *Node) RunSSHCommand(username string, command string, quiet bool) error { var jumpboxIp string var ip string @@ -139,23 +153,29 @@ func (n *Node) RunSSHCommand(username string, command string, quiet bool) error ip = n.ExternalIP } - client, err := n.getClient(jumpboxIp, ip, username) + client, err := n.getOrCreateClient(jumpboxIp, ip, username) if err != nil { return fmt.Errorf("failed to get client: %w", err) } - defer util.IgnoreError(client.Close) + // Don't close the client - it's cached for reuse session, err := client.NewSession() if err != nil { - return fmt.Errorf("failed to create session on jumpbox: %v", err) + // Connection might be stale, try to reconnect + n.invalidateClient(username) + client, err = n.getOrCreateClient(jumpboxIp, ip, username) + if err != nil { + return fmt.Errorf("failed to reconnect client: %w", err) + } + session, err = client.NewSession() + if err != nil { + return fmt.Errorf("failed to create session: %v", err) + } } defer util.IgnoreError(session.Close) _ = session.Setenv("OMS_PORTAL_API_KEY", os.Getenv("OMS_PORTAL_API_KEY")) - err = n.forwardAgent(client, session) - if err != nil { - log.Printf(" Warning: Agent forwarding setup failed on session: %v\n", err) - } + _ = agent.RequestAgentForwarding(session) // Best effort, ignore errors if !quiet { session.Stdout = os.Stdout @@ -177,7 +197,7 @@ func (n *Node) RunSSHCommand(username string, command string, quiet bool) error // HasCommand checks if a command exists on the remote node via SSH func (n *Node) HasCommand(command string) bool { checkCommand := fmt.Sprintf("command -v %s >/dev/null 2>&1", command) - err := n.RunSSHCommand("root", checkCommand, true) + err := n.RunSSHCommand("root", checkCommand, n.sshQuiet) if err != nil { // If the command returns a non-zero exit status, it means the command is not found return false @@ -194,7 +214,7 @@ func (n *Node) InstallOms() error { "wget https://dl.filippo.io/age/latest?for=linux/amd64 -O age.tar.gz; tar -xvf age.tar.gz; sudo mv age/age* /usr/local/bin/", } for _, cmd := range remoteCommands { - err := n.RunSSHCommand("root", cmd, false) + err := n.RunSSHCommand("root", cmd, n.sshQuiet) if err != nil { return fmt.Errorf("failed to run remote command '%s': %w", cmd, err) } @@ -205,7 +225,7 @@ func (n *Node) InstallOms() error { // HasAcceptEnvConfigured checks if AcceptEnv is configured func (n *Node) HasAcceptEnvConfigured() bool { checkCommand := "sudo grep -E '^AcceptEnv OMS_PORTAL_API_KEY' /etc/ssh/sshd_config >/dev/null 2>&1" - err := n.RunSSHCommand("ubuntu", checkCommand, true) + err := n.RunSSHCommand("ubuntu", checkCommand, n.sshQuiet) if err != nil { // If the command returns a NON-zero exit status, it means AcceptEnv is not configured return false @@ -220,7 +240,7 @@ func (n *Node) ConfigureAcceptEnv() error { "sudo systemctl restart sshd", } for _, cmd := range cmds { - err := n.RunSSHCommand("ubuntu", cmd, true) + err := n.RunSSHCommand("ubuntu", cmd, n.sshQuiet) if err != nil { return fmt.Errorf("failed to run command '%s': %w", cmd, err) } @@ -231,13 +251,13 @@ func (n *Node) ConfigureAcceptEnv() error { // HasRootLoginEnabled checks if root login is enabled on the remote node via SSH func (n *Node) HasRootLoginEnabled() bool { checkCommandPermit := "sudo grep -E '^PermitRootLogin yes' /etc/ssh/sshd_config >/dev/null 2>&1" - err := n.RunSSHCommand("ubuntu", checkCommandPermit, true) + err := n.RunSSHCommand("ubuntu", checkCommandPermit, n.sshQuiet) if err != nil { // If the command returns a NON-zero exit status, it means root login is not permitted return false } checkCommandAuthorizedKeys := "sudo grep -E '^no-port-forwarding' /root/.ssh/authorized_keys >/dev/null 2>&1" - err = n.RunSSHCommand("ubuntu", checkCommandAuthorizedKeys, true) + err = n.RunSSHCommand("ubuntu", checkCommandAuthorizedKeys, n.sshQuiet) if err == nil { // If the command returns a ZERO exit status, it means root login is prevented return false @@ -253,7 +273,7 @@ func (n *Node) EnableRootLogin() error { "sudo systemctl restart sshd", } for _, cmd := range cmds { - err := n.RunSSHCommand("ubuntu", cmd, true) + err := n.RunSSHCommand("ubuntu", cmd, n.sshQuiet) if err != nil { return fmt.Errorf("failed to run command '%s': %w", cmd, err) } @@ -280,7 +300,7 @@ func (n *Node) ConfigureMemoryMap() error { // HasFile checks if a file exists on the remote node via SSH func (n *Node) HasFile(filePath string) bool { checkCommand := fmt.Sprintf("test -f '%s'", filePath) - err := n.RunSSHCommand("ubuntu", checkCommand, true) + err := n.RunSSHCommand("ubuntu", checkCommand, n.sshQuiet) if err != nil { // If the command returns a non-zero exit status, it means the file does not exist return false @@ -309,7 +329,7 @@ func (n *Node) CopyFile(src string, dst string) error { // hasSysctlLine checks if a specific line exists in /etc/sysctl.conf on the remote node via SSH func (n *Node) hasSysctlLine(line string) bool { checkCommand := fmt.Sprintf("sudo grep -E '^%s' /etc/sysctl.conf >/dev/null 2>&1", line) - err := n.RunSSHCommand("root", checkCommand, true) + err := n.RunSSHCommand("root", checkCommand, n.sshQuiet) if err != nil { // If the command returns a NON-zero exit status, it means the setting is not configured return false @@ -324,7 +344,7 @@ func (n *Node) configureSysctlLine(line string) error { "sudo sysctl -p", } for _, cmd := range cmds { - err := n.RunSSHCommand("root", cmd, true) + err := n.RunSSHCommand("root", cmd, n.sshQuiet) if err != nil { return fmt.Errorf("failed to run command '%s': %w", cmd, err) } @@ -332,22 +352,67 @@ func (n *Node) configureSysctlLine(line string) error { return nil } -// getClient creates and returns an SSH client connected to the node -func (n *Node) getClient(jumpboxIp string, ip string, username string) (*ssh.Client, error) { +// getOrCreateClient returns a cached SSH client or creates a new one if not cached. +func (n *Node) getOrCreateClient(jumpboxIp string, ip string, username string) (*ssh.Client, error) { + n.clientMu.Lock() + defer n.clientMu.Unlock() + + if client, ok := n.clientCache[username]; ok { + if _, _, err := client.SendRequest("keepalive@openssh.com", true, nil); err == nil { + return client, nil + } + util.IgnoreError(client.Close) + delete(n.clientCache, username) + } + + client, err := n.createClient(jumpboxIp, ip, username) + if err != nil { + return nil, err + } + + // Set up agent forwarding (best effort, ignore errors) + err = n.setupAgentForwarding(client) + if err != nil { + log.Printf("Warning: failed to set up agent forwarding: %v", err) + } + + n.clientCache[username] = client + return client, nil +} + +// invalidateClient removes a cached client for the given username +func (n *Node) invalidateClient(username string) { + n.clientMu.Lock() + defer n.clientMu.Unlock() + + if client, ok := n.clientCache[username]; ok { + util.IgnoreError(client.Close) + delete(n.clientCache, username) + } +} + +// createClient creates and returns a new SSH client connected to the node (internal, no caching) +func (n *Node) createClient(jumpboxIp string, ip string, username string) (*ssh.Client, error) { authMethods, err := n.getAuthMethods() if err != nil { return nil, fmt.Errorf("failed to get authentication methods: %w", err) } + if jumpboxIp != "" { - jbClient, err := n.connectToJumpbox(jumpboxIp, jumpboxUser) + // Use the Jumpbox's cached client if available + jbClient, err := n.Jumpbox.getOrCreateClient("", jumpboxIp, jumpboxUser) if err != nil { return nil, fmt.Errorf("failed to connect to jumpbox: %v", err) } finalTargetConfig := &ssh.ClientConfig{ - User: username, - Auth: authMethods, - Timeout: 10 * time.Second, + User: username, + Auth: authMethods, + Timeout: 10 * time.Second, + // WARNING: This is INSECURE for production! + // It tells the client to accept any host key. + // For production, you should implement a proper HostKeyCallback + // to verify the remote server's identity. HostKeyCallback: ssh.InsecureIgnoreHostKey(), } @@ -383,23 +448,26 @@ func (n *Node) getClient(jumpboxIp string, ip string, username string) (*ssh.Cli return client, nil } -// getSFTPClient creates and returns an SFTP client connected to the node +// getSFTPClient creates and returns an SFTP client connected to the node. +// Uses the cached SSH client for the connection. func (n *Node) getSFTPClient(jumpboxIp string, ip string, username string) (*sftp.Client, error) { - client, err := n.getClient(jumpboxIp, ip, username) + client, err := n.getOrCreateClient(jumpboxIp, ip, username) if err != nil { return nil, fmt.Errorf("failed to get SSH client: %v", err) } + sftpClient, err := sftp.NewClient(client) if err != nil { return nil, fmt.Errorf("failed to create SFTP client: %v", err) } + return sftpClient, nil } // ensureDirectoryExists creates the directory on the remote node via SSH if it does not exist. -func (nm *Node) ensureDirectoryExists(username string, dir string) error { +func (n *Node) ensureDirectoryExists(username string, dir string) error { cmd := fmt.Sprintf("mkdir -p '%s'", dir) - return nm.RunSSHCommand(username, cmd, true) + return n.RunSSHCommand(username, cmd, n.sshQuiet) } // copyFile copies a file from the local system to the remote node via SFTP. @@ -523,57 +591,17 @@ func (n *Node) loadPrivateKey() (ssh.Signer, error) { return signer, nil } -func (n *Node) connectToJumpbox(ip, username string) (*ssh.Client, error) { - authMethods, err := n.getAuthMethods() - if err != nil { - return nil, fmt.Errorf("jumpbox authentication setup failed: %v", err) - } - - config := &ssh.ClientConfig{ - User: username, - Auth: authMethods, - Timeout: 10 * time.Second, - // WARNING: Still using InsecureIgnoreHostKey for simplicity. Use known_hosts in production. - HostKeyCallback: ssh.InsecureIgnoreHostKey(), +// setupAgentForwarding sets up SSH agent forwarding on the client (best effort) +func (n *Node) setupAgentForwarding(client *ssh.Client) error { + authSocket := os.Getenv("SSH_AUTH_SOCK") + if authSocket == "" { + return nil } - addr := fmt.Sprintf("%s:22", ip) - jumpboxClient, err := ssh.Dial("tcp", addr, config) + conn, err := net.Dial("unix", authSocket) if err != nil { - return nil, fmt.Errorf("failed to dial jumpbox %s: %v", addr, err) - } - - // Enable Agent Forwarding on the jumpbox connection - if err := n.forwardAgent(jumpboxClient, nil); err != nil { - fmt.Printf(" Warning: Agent forwarding setup failed on jumpbox: %v\n", err) + return fmt.Errorf("failed to connect to SSH agent: %v", err) } - return jumpboxClient, nil -} - -func (n *Node) forwardAgent(client *ssh.Client, session *ssh.Session) error { - authSocket := os.Getenv("SSH_AUTH_SOCK") - if authSocket == "" { - log.Printf("SSH_AUTH_SOCK not set. Cannot perform agent forwarding") - } else { - // Connect to the local SSH Agent socket - conn, err := net.Dial("unix", authSocket) - if err != nil { - log.Printf("failed to dial SSH agent socket: %v", err) - } else { - // Create an agent client for the local agent - ag := agent.NewClient(conn) - // This tells the remote server to proxy authentication requests back to us. - if err := agent.ForwardToAgent(client, ag); err != nil { - log.Printf("failed to forward agent to remote client: %v", err) - } - if session != nil { - if err := agent.RequestAgentForwarding(session); err != nil { - log.Printf("failed to request agent forwarding on session: %v", err) - } - } - } - - } - return nil + return agent.ForwardToAgent(client, agent.NewClient(conn)) } From e96ac9630e65197da867aca60c158a64644f7658 Mon Sep 17 00:00:00 2001 From: Simon Herrmann Date: Thu, 29 Jan 2026 16:38:26 +0100 Subject: [PATCH 08/12] fix: fix dependencies --- go.mod | 185 ++++++++++++++++++++++++++++-------------------- go.sum | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 328 insertions(+), 74 deletions(-) diff --git a/go.mod b/go.mod index 951138aa..d360151f 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( cloud.google.com/go/iam v1.5.3 cloud.google.com/go/resourcemanager v1.10.7 cloud.google.com/go/serviceusage v1.9.7 - github.com/codesphere-cloud/cs-go v0.16.1 + github.com/codesphere-cloud/cs-go v0.16.2 github.com/creativeprojects/go-selfupdate v1.5.2 github.com/jedib0t/go-pretty/v6 v6.7.8 github.com/lithammer/shortuuid v3.0.0+incompatible @@ -34,16 +34,16 @@ require ( cloud.google.com/go/auth v0.18.1 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.9.0 // indirect - cloud.google.com/go/kms v1.23.2 // indirect - cloud.google.com/go/longrunning v0.7.0 // indirect + cloud.google.com/go/kms v1.25.0 // indirect + cloud.google.com/go/longrunning v0.8.0 // indirect cloud.google.com/go/monitoring v1.24.3 // indirect - cloud.google.com/go/storage v1.58.0 // indirect + cloud.google.com/go/storage v1.59.2 // indirect code.gitea.io/sdk/gitea v0.22.1 // indirect codeberg.org/chavacava/garif v0.2.0 // indirect codeberg.org/polyfloyd/go-errorlint v1.9.0 // indirect dario.cat/mergo v1.0.2 // indirect dev.gaijin.team/go/exhaustruct/v4 v4.0.0 // indirect - dev.gaijin.team/go/golib v0.8.0 // indirect + dev.gaijin.team/go/golib v0.8.1 // indirect github.com/42wim/httpsig v1.2.3 // indirect github.com/4meepo/tagalign v1.4.3 // indirect github.com/Abirdcfly/dupword v0.1.7 // indirect @@ -54,14 +54,14 @@ require ( github.com/Antonboom/nilnil v1.1.1 // indirect github.com/Antonboom/testifylint v1.6.4 // indirect github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.4.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.3 // indirect + github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.4 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest v0.11.30 // indirect @@ -75,51 +75,51 @@ require ( github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 // indirect github.com/BurntSushi/toml v1.6.0 // indirect github.com/Djarvur/go-err113 v0.1.1 // indirect - github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect - github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 // indirect - github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/sprig/v3 v3.3.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/MirrexOne/unqueryvet v1.4.0 // indirect + github.com/MirrexOne/unqueryvet v1.5.3 // indirect github.com/OpenPeeDeeP/depguard/v2 v2.2.1 // indirect github.com/ProtonMail/go-crypto v1.3.0 // indirect github.com/agnivade/levenshtein v1.2.1 // indirect - github.com/alecthomas/chroma/v2 v2.21.1 // indirect + github.com/alecthomas/chroma/v2 v2.23.1 // indirect github.com/alecthomas/go-check-sumtype v0.3.1 // indirect github.com/alexkohler/nakedret/v2 v2.0.6 // indirect - github.com/alexkohler/prealloc v1.0.1 // indirect + github.com/alexkohler/prealloc v1.0.2 // indirect github.com/alfatraining/structtag v1.0.0 // indirect github.com/alingse/asasalint v0.0.11 // indirect github.com/alingse/nilnesserr v0.2.0 // indirect - github.com/anchore/go-macholibre v0.0.0-20250826193721-3cd206ca93aa // indirect + github.com/anchore/go-macholibre v0.0.0-20260126173545-dd3034b5c75b // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/ashanbrown/forbidigo/v2 v2.3.0 // indirect github.com/ashanbrown/makezero/v2 v2.1.0 // indirect github.com/atc0005/go-teams-notify/v2 v2.14.0 // indirect github.com/avast/retry-go/v4 v4.7.0 // indirect - github.com/aws/aws-sdk-go-v2 v1.41.0 // indirect + github.com/aws/aws-sdk-go-v2 v1.41.1 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect - github.com/aws/aws-sdk-go-v2/config v1.32.6 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.19.6 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 // indirect - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.18 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 // indirect + github.com/aws/aws-sdk-go-v2/config v1.32.7 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.19.7 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 // indirect + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.21.1 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 // indirect - github.com/aws/aws-sdk-go-v2/service/ecr v1.55.0 // indirect - github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.8 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 // indirect + github.com/aws/aws-sdk-go-v2/service/ecr v1.55.1 // indirect + github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.9 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 // indirect - github.com/aws/aws-sdk-go-v2/service/kms v1.49.4 // indirect - github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0 // indirect - github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.30.8 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 // indirect + github.com/aws/aws-sdk-go-v2/service/kms v1.49.5 // indirect + github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 // indirect github.com/aws/smithy-go v1.24.0 // indirect github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.11.0 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect @@ -131,9 +131,9 @@ require ( github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb // indirect github.com/blang/semver v3.5.1+incompatible // indirect github.com/blizzy78/varnamelen v0.8.0 // indirect - github.com/bluesky-social/indigo v0.0.0-20260106221649-6fcd9317e725 // indirect + github.com/bluesky-social/indigo v0.0.0-20260128215158-cf0fe7589346 // indirect github.com/bombsimon/wsl/v4 v4.7.0 // indirect - github.com/bombsimon/wsl/v5 v5.3.0 // indirect + github.com/bombsimon/wsl/v5 v5.6.0 // indirect github.com/breml/bidichk v0.3.3 // indirect github.com/breml/errchkjson v0.4.1 // indirect github.com/brunoga/deep v1.2.5 // indirect @@ -155,21 +155,21 @@ require ( github.com/charmbracelet/colorprofile v0.4.1 // indirect github.com/charmbracelet/fang v0.4.4 // indirect github.com/charmbracelet/lipgloss v1.1.0 // indirect - github.com/charmbracelet/ultraviolet v0.0.0-20251217160852-6b0c0e26fad9 // indirect - github.com/charmbracelet/x/ansi v0.11.3 // indirect + github.com/charmbracelet/ultraviolet v0.0.0-20260123224754-f434aada8dbd // indirect + github.com/charmbracelet/x/ansi v0.11.4 // indirect github.com/charmbracelet/x/cellbuf v0.0.14 // indirect - github.com/charmbracelet/x/exp/charmtone v0.0.0-20251215102626-e0db08df7383 // indirect + github.com/charmbracelet/x/exp/charmtone v0.0.0-20260127155452-b72a9a918687 // indirect github.com/charmbracelet/x/term v0.2.2 // indirect github.com/charmbracelet/x/termios v0.1.1 // indirect github.com/charmbracelet/x/windows v0.2.2 // indirect github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect github.com/ckaznocha/intrange v0.3.1 // indirect - github.com/clipperhouse/displaywidth v0.6.1 // indirect - github.com/cloudflare/circl v1.6.2 // indirect - github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 // indirect + github.com/clipperhouse/displaywidth v0.8.0 // indirect + github.com/cloudflare/circl v1.6.3 // indirect + github.com/cncf/xds/go v0.0.0-20260121142036-a486691bba94 // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect - github.com/containerd/stargz-snapshotter/estargz v0.18.1 // indirect + github.com/containerd/stargz-snapshotter/estargz v0.18.2 // indirect github.com/coreos/go-oidc/v3 v3.17.0 // indirect github.com/curioswitch/go-reassign v0.3.0 // indirect github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 // indirect @@ -177,7 +177,7 @@ require ( github.com/daixiang0/gci v0.13.7 // indirect github.com/dave/dst v0.27.3 // indirect github.com/davidmz/go-pageant v1.0.2 // indirect - github.com/denis-tingaikin/go-header v0.5.0 // indirect + github.com/denis-tingaikin/go-header v1.0.0 // indirect github.com/dghubble/go-twitter v0.0.0-20221104224141-912508c3888b // indirect github.com/dghubble/oauth1 v0.7.3 // indirect github.com/dghubble/sling v1.4.2 // indirect @@ -186,10 +186,10 @@ require ( github.com/dimchansky/utfbom v1.1.1 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/dlclark/regexp2 v1.11.5 // indirect - github.com/docker/cli v29.2.0-rc.1.0.20251223174200-874b831c0e49+incompatible // indirect + github.com/docker/cli v29.2.0+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker v28.5.2+incompatible // indirect - github.com/docker/docker-credential-helpers v0.9.4 // indirect + github.com/docker/docker-credential-helpers v0.9.5 // indirect github.com/docker/go-connections v0.6.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect @@ -207,7 +207,7 @@ require ( github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fzipp/gocyclo v0.6.0 // indirect github.com/gabriel-vasile/mimetype v1.4.12 // indirect - github.com/ghostiam/protogetter v0.3.18 // indirect + github.com/ghostiam/protogetter v0.3.19 // indirect github.com/github/smimesign v0.2.0 // indirect github.com/go-critic/go-critic v0.14.3 // indirect github.com/go-fed/httpsig v1.1.0 // indirect @@ -246,19 +246,19 @@ require ( github.com/go-toolsmith/astp v1.1.0 // indirect github.com/go-toolsmith/strparse v1.1.0 // indirect github.com/go-toolsmith/typep v1.1.0 // indirect - github.com/go-viper/mapstructure/v2 v2.4.0 // indirect + github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/godoc-lint/godoc-lint v0.11.1 // indirect github.com/gofrs/flock v0.13.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.2 // indirect - github.com/golang-jwt/jwt/v5 v5.3.0 // indirect + github.com/golang-jwt/jwt/v5 v5.3.1 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golangci/asciicheck v0.5.0 // indirect github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 // indirect github.com/golangci/go-printf-func-name v0.1.1 // indirect - github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d // indirect + github.com/golangci/gofmt v0.0.0-20251215234548-e7be49a5ab4d // indirect github.com/golangci/golangci-lint/v2 v2.8.0 // indirect github.com/golangci/golines v0.14.0 // indirect github.com/golangci/misspell v0.7.0 // indirect @@ -281,14 +281,14 @@ require ( github.com/goreleaser/chglog v0.7.4 // indirect github.com/goreleaser/fileglob v1.4.0 // indirect github.com/goreleaser/goreleaser/v2 v2.13.3 // indirect - github.com/goreleaser/nfpm/v2 v2.44.1 // indirect + github.com/goreleaser/nfpm/v2 v2.44.2 // indirect github.com/goreleaser/quill v0.0.0-20251224035235-ab943733386f // indirect github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect github.com/gostaticanalysis/analysisutil v0.7.1 // indirect github.com/gostaticanalysis/comment v1.5.0 // indirect github.com/gostaticanalysis/forcetypeassert v0.2.0 // indirect github.com/gostaticanalysis/nilerr v0.1.2 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.6 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect @@ -300,10 +300,10 @@ require ( github.com/hexops/gotextdiff v1.0.3 // indirect github.com/huandu/xstrings v1.5.0 // indirect github.com/in-toto/attestation v1.1.2 // indirect - github.com/in-toto/in-toto-golang v0.9.0 // indirect + github.com/in-toto/in-toto-golang v0.10.0 // indirect github.com/invopop/jsonschema v0.13.0 // indirect github.com/ipfs/bbloom v0.0.4 // indirect - github.com/ipfs/boxo v0.34.0 // indirect + github.com/ipfs/boxo v0.36.0 // indirect github.com/ipfs/go-block-format v0.2.3 // indirect github.com/ipfs/go-cid v0.6.0 // indirect github.com/ipfs/go-datastore v0.9.0 // indirect @@ -312,7 +312,7 @@ require ( github.com/ipfs/go-ipld-cbor v0.2.1 // indirect github.com/ipfs/go-ipld-format v0.6.3 // indirect github.com/ipfs/go-log v1.0.5 // indirect - github.com/ipfs/go-log/v2 v2.9.0 // indirect + github.com/ipfs/go-log/v2 v2.9.1 // indirect github.com/ipfs/go-metrics-interface v0.3.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jedisct1/go-minisign v0.0.0-20241212093149-d2f9f49435c7 // indirect @@ -324,7 +324,7 @@ require ( github.com/kevinburke/ssh_config v1.4.0 // indirect github.com/kisielk/errcheck v1.9.0 // indirect github.com/kkHAIKE/contextcheck v1.1.6 // indirect - github.com/klauspost/compress v1.18.2 // indirect + github.com/klauspost/compress v1.18.3 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/klauspost/pgzip v1.2.6 // indirect github.com/knadh/koanf/maps v0.1.2 // indirect @@ -333,7 +333,7 @@ require ( github.com/knadh/koanf/providers/file v1.2.1 // indirect github.com/knadh/koanf/providers/posflag v1.0.1 // indirect github.com/knadh/koanf/providers/structs v1.0.0 // indirect - github.com/knadh/koanf/v2 v2.3.0 // indirect + github.com/knadh/koanf/v2 v2.3.2 // indirect github.com/kr/fs v0.1.0 // indirect github.com/kulti/thelper v0.7.1 // indirect github.com/kunwardeep/paralleltest v1.0.15 // indirect @@ -382,7 +382,7 @@ require ( github.com/nakabonne/nestif v0.3.1 // indirect github.com/nishanths/exhaustive v0.12.0 // indirect github.com/nishanths/predeclared v0.2.2 // indirect - github.com/nunnatsa/ginkgolinter v0.21.2 // indirect + github.com/nunnatsa/ginkgolinter v0.22.0 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect @@ -423,11 +423,11 @@ require ( github.com/sigstore/cosign/v2 v2.6.2 // indirect github.com/sigstore/protobuf-specs v0.5.0 // indirect github.com/sigstore/rekor v1.5.0 // indirect - github.com/sigstore/rekor-tiles/v2 v2.0.1 // indirect + github.com/sigstore/rekor-tiles/v2 v2.1.0 // indirect github.com/sigstore/sigstore v1.10.4 // indirect github.com/sigstore/sigstore-go v1.1.4 // indirect - github.com/sigstore/timestamp-authority/v2 v2.0.3 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sigstore/timestamp-authority/v2 v2.0.4 // indirect + github.com/sirupsen/logrus v1.9.4 // indirect github.com/sivchari/containedctx v1.0.3 // indirect github.com/skeema/knownhosts v1.3.2 // indirect github.com/slack-go/slack v0.17.3 // indirect @@ -444,12 +444,12 @@ require ( github.com/tetafro/godot v1.5.4 // indirect github.com/theupdateframework/go-tuf v0.7.0 // indirect github.com/theupdateframework/go-tuf/v2 v2.4.1 // indirect - github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 // indirect + github.com/timakin/bodyclose v0.0.0-20260129054331-73d1f95b84b4 // indirect github.com/timonwong/loggercheck v0.11.0 // indirect github.com/tomarrell/wrapcheck/v2 v2.12.0 // indirect github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect github.com/tomnomnom/linkheader v0.0.0-20250811210735-e5fe3b51442e // indirect - github.com/transparency-dev/formats v0.0.0-20251208091212-1378f9e1b1b7 // indirect + github.com/transparency-dev/formats v0.0.0-20260126105629-a1e81f2894be // indirect github.com/transparency-dev/merkle v0.0.2 // indirect github.com/ultraware/funlen v0.2.0 // indirect github.com/ultraware/whitespace v0.2.0 // indirect @@ -471,12 +471,12 @@ require ( github.com/ykadowak/zerologlint v0.1.5 // indirect gitlab.com/bosi/decorder v0.4.2 // indirect gitlab.com/digitalxero/go-conventional-commit v1.0.7 // indirect - gitlab.com/gitlab-org/api/client-go v1.11.0 // indirect + gitlab.com/gitlab-org/api/client-go v1.24.0 // indirect go-simpler.org/musttag v0.14.0 // indirect go-simpler.org/sloglint v0.11.1 // indirect - go.augendre.info/arangolint v0.3.1 // indirect + go.augendre.info/arangolint v0.4.0 // indirect go.augendre.info/fatcontext v0.9.0 // indirect - go.mongodb.org/mongo-driver v1.17.6 // indirect + go.mongodb.org/mongo-driver v1.17.7 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/detectors/gcp v1.39.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 // indirect @@ -492,13 +492,13 @@ require ( go.uber.org/zap v1.27.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect gocloud.dev v0.44.0 // indirect - golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect - golang.org/x/exp/typeparams v0.0.0-20251219203646-944ab1f22d93 // indirect + golang.org/x/exp v0.0.0-20260112195511-716be5621a96 // indirect + golang.org/x/exp/typeparams v0.0.0-20260112195511-716be5621a96 // indirect golang.org/x/time v0.14.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect - google.golang.org/genproto v0.0.0-20251222181119-0a764e51fe1b // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260122232226-8e98ce8d340d // indirect + google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/mail.v2 v2.3.1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect @@ -512,33 +512,70 @@ require ( ) require ( + github.com/DataDog/zstd v1.5.5 // indirect github.com/Masterminds/semver/v3 v3.4.0 // indirect + github.com/alecthomas/kingpin/v2 v2.4.0 // indirect + github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect + github.com/beevik/etree v1.6.0 // indirect + github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect + github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261 // indirect + github.com/chzyer/readline v1.5.1 // indirect github.com/clipperhouse/stringish v0.1.1 // indirect - github.com/clipperhouse/uax29/v2 v2.3.0 // indirect + github.com/clipperhouse/uax29/v2 v2.4.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect + github.com/danieljoos/wincred v1.2.3 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/dprotaso/go-yit v0.0.0-20250513223454-5ece0c5aa76c // indirect + github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect + github.com/godbus/dbus/v5 v5.2.2 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-querystring v1.2.0 // indirect - github.com/google/pprof v0.0.0-20260106004452-d7df1bf2cac7 // indirect + github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 // indirect + github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef // indirect + github.com/iancoleman/strcase v0.3.0 // indirect + github.com/ianlancetaylor/demangle v0.0.0-20250417193237-f615e6bd150b // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/kr/pretty v0.3.1 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/lib/pq v1.10.9 // indirect + github.com/lyft/protoc-gen-star/v2 v2.0.4-0.20230330145011-496ad1ac90a4 // indirect + github.com/magefile/mage v1.14.0 // indirect github.com/mattn/go-runewidth v0.0.19 // indirect + github.com/mgechev/dots v1.0.0 // indirect + github.com/miekg/pkcs11 v1.1.1 // indirect + github.com/pborman/getopt v0.0.0-20180811024354-2b5b3bfb099b // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71 // indirect + github.com/qur/ar v0.0.0-20130629153254-282534b91770 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sassoftware/go-rpmutils v0.4.0 // indirect + github.com/satori/go.uuid v1.2.0 // indirect github.com/spf13/pflag v1.0.10 // indirect + github.com/streadway/amqp v1.1.0 // indirect github.com/stretchr/objx v0.5.3 // indirect github.com/ulikunitz/xz v0.5.15 // indirect - golang.org/x/mod v0.31.0 // indirect + github.com/xhit/go-str2duration/v2 v2.1.0 // indirect + github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect + github.com/zalando/go-keyring v0.2.6 // indirect + golang.org/x/mod v0.32.0 // indirect golang.org/x/net v0.49.0 // indirect golang.org/x/oauth2 v0.34.0 // indirect golang.org/x/sync v0.19.0 // indirect golang.org/x/sys v0.40.0 // indirect golang.org/x/text v0.33.0 // indirect - golang.org/x/tools v0.40.0 // indirect + golang.org/x/tools v0.41.0 // indirect google.golang.org/protobuf v1.36.11 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/apimachinery v0.35.0 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/utils v0.0.0-20260106112306-0fe9cd71b2f8 // indirect ) tool ( diff --git a/go.sum b/go.sum index 17dfc041..e3580e65 100644 --- a/go.sum +++ b/go.sum @@ -24,10 +24,14 @@ cloud.google.com/go/iam v1.5.3 h1:+vMINPiDF2ognBJ97ABAYYwRgsaqxPbQDlMnbHMjolc= cloud.google.com/go/iam v1.5.3/go.mod h1:MR3v9oLkZCTlaqljW6Eb2d3HGDGK5/bDv93jhfISFvU= cloud.google.com/go/kms v1.23.2 h1:4IYDQL5hG4L+HzJBhzejUySoUOheh3Lk5YT4PCyyW6k= cloud.google.com/go/kms v1.23.2/go.mod h1:rZ5kK0I7Kn9W4erhYVoIRPtpizjunlrfU4fUkumUp8g= +cloud.google.com/go/kms v1.25.0 h1:gVqvGGUmz0nYCmtoxWmdc1wli2L1apgP8U4fghPGSbQ= +cloud.google.com/go/kms v1.25.0/go.mod h1:XIdHkzfj0bUO3E+LvwPg+oc7s58/Ns8Nd8Sdtljihbk= cloud.google.com/go/logging v1.13.1 h1:O7LvmO0kGLaHY/gq8cV7T0dyp6zJhYAOtZPX4TF3QtY= cloud.google.com/go/logging v1.13.1/go.mod h1:XAQkfkMBxQRjQek96WLPNze7vsOmay9H5PqfsNYDqvw= cloud.google.com/go/longrunning v0.7.0 h1:FV0+SYF1RIj59gyoWDRi45GiYUMM3K1qO51qoboQT1E= cloud.google.com/go/longrunning v0.7.0/go.mod h1:ySn2yXmjbK9Ba0zsQqunhDkYi0+9rlXIwnoAf+h+TPY= +cloud.google.com/go/longrunning v0.8.0 h1:LiKK77J3bx5gDLi4SMViHixjD2ohlkwBi+mKA7EhfW8= +cloud.google.com/go/longrunning v0.8.0/go.mod h1:UmErU2Onzi+fKDg2gR7dusz11Pe26aknR4kHmJJqIfk= cloud.google.com/go/monitoring v1.24.3 h1:dde+gMNc0UhPZD1Azu6at2e79bfdztVDS5lvhOdsgaE= cloud.google.com/go/monitoring v1.24.3/go.mod h1:nYP6W0tm3N9H/bOw8am7t62YTzZY+zUeQ+Bi6+2eonI= cloud.google.com/go/resourcemanager v1.10.7 h1:oPZKIdjyVTuag+D4HF7HO0mnSqcqgjcuA18xblwA0V0= @@ -36,6 +40,8 @@ cloud.google.com/go/serviceusage v1.9.7 h1:vrBBeI2ESmri4BLGPz1YH2o37loIQ3DDTloYi cloud.google.com/go/serviceusage v1.9.7/go.mod h1:JpBpv+4Zbe7+RiC9ydc6xgBUOntIL9tA85d2xKgV83g= cloud.google.com/go/storage v1.58.0 h1:PflFXlmFJjG/nBeR9B7pKddLQWaFaRWx4uUi/LyNxxo= cloud.google.com/go/storage v1.58.0/go.mod h1:cMWbtM+anpC74gn6qjLh+exqYcfmB9Hqe5z6adx+CLI= +cloud.google.com/go/storage v1.59.2 h1:gmOAuG1opU8YvycMNpP+DvHfT9BfzzK5Cy+arP+Nocw= +cloud.google.com/go/storage v1.59.2/go.mod h1:cMWbtM+anpC74gn6qjLh+exqYcfmB9Hqe5z6adx+CLI= cloud.google.com/go/trace v1.11.7 h1:kDNDX8JkaAG3R2nq1lIdkb7FCSi1rCmsEtKVsty7p+U= cloud.google.com/go/trace v1.11.7/go.mod h1:TNn9d5V3fQVf6s4SCveVMIBS2LJUqo73GACmq/Tky0s= code.gitea.io/sdk/gitea v0.22.1 h1:7K05KjRORyTcTYULQ/AwvlVS6pawLcWyXZcTr7gHFyA= @@ -50,6 +56,8 @@ dev.gaijin.team/go/exhaustruct/v4 v4.0.0 h1:873r7aNneqoBB3IaFIzhvt2RFYTuHgmMjoKf dev.gaijin.team/go/exhaustruct/v4 v4.0.0/go.mod h1:aZ/k2o4Y05aMJtiux15x8iXaumE88YdiB0Ai4fXOzPI= dev.gaijin.team/go/golib v0.8.0 h1:BiDNudpoFizoU5VHdQUiabtHSt9fyPX11Fr4OU9PaUQ= dev.gaijin.team/go/golib v0.8.0/go.mod h1:c5fu7t1RSGMxSQgcUYO1sODbzsYnOCXJLmHeNG1Eb+0= +dev.gaijin.team/go/golib v0.8.1 h1:JYju4x9BSo+QD/AYeHULVDcvEhiFg8wOi6pT0IaZF5E= +dev.gaijin.team/go/golib v0.8.1/go.mod h1:c5fu7t1RSGMxSQgcUYO1sODbzsYnOCXJLmHeNG1Eb+0= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/42wim/httpsig v1.2.3 h1:xb0YyWhkYj57SPtfSttIobJUPJZB9as1nsfo7KWVcEs= @@ -76,6 +84,8 @@ github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0 github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 h1:JXg2dwJUmPB9JmtVmdEB16APJ7jurfbY5jnfXpJoRMc= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 h1:fou+2+WFTib47nS+nz/ozhEBnvU96bKHy6LjRsY4E28= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0/go.mod h1:t76Ruy8AHvUAC8GfMWJMa0ElSbuIcO03NLpynfbgsPA= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= @@ -94,6 +104,8 @@ github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 h1:nCYfg github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0/go.mod h1:ucUjca2JtSZboY8IoUqyQyuuXvwbMBVwFOm0vdQPNhA= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.3 h1:ZJJNFaQ86GVKQ9ehwqyAFE6pIfyicpuJ8IkVaPBc6/4= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.3/go.mod h1:URuDvhmATVKqHBH9/0nOiNKk0+YcwfQ3WkK5PqHKxc8= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.4 h1:jWQK1GI+LeGGUKBADtcH2rRqPxYB1Ljwms5gFA2LqrM= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.4/go.mod h1:8mwH4klAm9DUgR2EEHyEEAQlRDvLPyg5fQry3y+cDew= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= @@ -137,12 +149,19 @@ github.com/Djarvur/go-err113 v0.1.1 h1:eHfopDqXRwAi+YmCUas75ZE0+hoBHJ2GQNLYRSxao github.com/Djarvur/go-err113 v0.1.1/go.mod h1:IaWJdYFLg76t2ihfflPZnM1LIQszWOsFDh2hhhAVF6k= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 h1:DHa2U07rk8syqvCge0QIGMCE1WxGj9njT44GH7zNJLQ= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 h1:lhhYARPUu3LmHysQ/igznQphfzynnqI3D75oUyw1HXk= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0/go.mod h1:l9rva3ApbBpEJxSNYnwT9N4CDLrWgtq3u8736C5hyJw= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 h1:UnDZ/zFfG1JhH/DqxIZYU/1CUAlTUScoXD/LcM2Ykk8= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0/go.mod h1:IA1C1U7jO/ENqm/vhi7V9YYpBsp+IMyqNrEN94N7tVc= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.54.0 h1:xfK3bbi6F2RDtaZFtUdKO3osOBIhNb+xTs8lFW6yx9o= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.54.0/go.mod h1:vB2GH9GAYYJTO3mEn8oYwzEdhlayZIdQz6zdzgUIRvA= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.55.0 h1:7t/qx5Ost0s0wbA/VDrByOooURhp+ikYwv20i9Y07TQ= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 h1:s0WlVbf9qpvkh1c/uDAPElam0WrL7fHRIidgZJ7UqZI= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 h1:0s6TxfCu2KHkkZPnBfsQ2y5qia0jl3MMrmBhu3nCOYk= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= @@ -154,6 +173,8 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/MirrexOne/unqueryvet v1.4.0 h1:6KAkqqW2KUnkl9Z0VuTphC3IXRPoFqEkJEtyxxHj5eQ= github.com/MirrexOne/unqueryvet v1.4.0/go.mod h1:IWwCwMQlSWjAIteW0t+28Q5vouyktfujzYznSIWiuOg= +github.com/MirrexOne/unqueryvet v1.5.3 h1:LpT3rsH+IY3cQddWF9bg4C7jsbASdGnrOSofY8IPEiw= +github.com/MirrexOne/unqueryvet v1.5.3/go.mod h1:fs9Zq6eh1LRIhsDIsxf9PONVUjYdFHdtkHIgZdJnyPU= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OpenPeeDeeP/depguard/v2 v2.2.1 h1:vckeWVESWp6Qog7UZSARNqfu/cZqvki8zsuj3piCMx4= @@ -172,14 +193,22 @@ github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8v github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/chroma/v2 v2.21.1 h1:FaSDrp6N+3pphkNKU6HPCiYLgm8dbe5UXIXcoBhZSWA= github.com/alecthomas/chroma/v2 v2.21.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o= +github.com/alecthomas/chroma/v2 v2.23.1 h1:nv2AVZdTyClGbVQkIzlDm/rnhk1E9bU9nXwmZ/Vk/iY= +github.com/alecthomas/chroma/v2 v2.23.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o= github.com/alecthomas/go-check-sumtype v0.3.1 h1:u9aUvbGINJxLVXiFvHUlPEaD7VDULsrxJb4Aq31NLkU= github.com/alecthomas/go-check-sumtype v0.3.1/go.mod h1:A8TSiN3UPRw3laIgWEUOHHLPa6/r9MtoigdlP5h3K/E= +github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY= +github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs= github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= +github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0= +github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs= github.com/alexkohler/nakedret/v2 v2.0.6 h1:ME3Qef1/KIKr3kWX3nti3hhgNxw6aqN5pZmQiFSsuzQ= github.com/alexkohler/nakedret/v2 v2.0.6/go.mod h1:l3RKju/IzOMQHmsEvXwkqMDzHHvurNQfAgE1eVmT40Q= github.com/alexkohler/prealloc v1.0.1 h1:A9P1haqowqUxWvU9nk6tQ7YktXIHf+LQM9wPRhuteEE= github.com/alexkohler/prealloc v1.0.1/go.mod h1:fT39Jge3bQrfA7nPMDngUfvUbQGQeJyGQnR+913SCig= +github.com/alexkohler/prealloc v1.0.2 h1:MPo8cIkGkZytq7WNH9UHv3DIX1mPz1RatPXnZb0zHWQ= +github.com/alexkohler/prealloc v1.0.2/go.mod h1:fT39Jge3bQrfA7nPMDngUfvUbQGQeJyGQnR+913SCig= github.com/alfatraining/structtag v1.0.0 h1:2qmcUqNcCoyVJ0up879K614L9PazjBSFruTB0GOFjCc= github.com/alfatraining/structtag v1.0.0/go.mod h1:p3Xi5SwzTi+Ryj64DqjLWz7XurHxbGsq6y3ubePJPus= github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw= @@ -188,6 +217,8 @@ github.com/alingse/nilnesserr v0.2.0 h1:raLem5KG7EFVb4UIDAXgrv3N2JIaffeKNtcEXkEW github.com/alingse/nilnesserr v0.2.0/go.mod h1:1xJPrXonEtX7wyTq8Dytns5P2hNzoWymVUIaKm4HNFg= github.com/anchore/go-macholibre v0.0.0-20250826193721-3cd206ca93aa h1:KPEP8f3enFJeus3Wo51I+riVuCvlf4OEYl2B4IfycbQ= github.com/anchore/go-macholibre v0.0.0-20250826193721-3cd206ca93aa/go.mod h1:7YJA6tAfRm4SzIF93b32pR4xnbf8g2nJIeQnp+2vzzI= +github.com/anchore/go-macholibre v0.0.0-20260126173545-dd3034b5c75b h1:P1aST8e0rhBd8xuQG/4XPlvlzTzZ6iuBdxTbZ0qo4RA= +github.com/anchore/go-macholibre v0.0.0-20260126173545-dd3034b5c75b/go.mod h1:eu0gbwaZ+ocVFJLePdmPPDKU8MboV1MKsUCr36Ckd5s= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= @@ -209,48 +240,86 @@ github.com/aws/aws-sdk-go v1.55.8 h1:JRmEUbU52aJQZ2AjX4q4Wu7t4uZjOu71uyNmaWlUkJQ github.com/aws/aws-sdk-go v1.55.8/go.mod h1:ZkViS9AqA6otK+JBBNH2++sx1sgxrPKcSzPPvQkUtXk= github.com/aws/aws-sdk-go-v2 v1.41.0 h1:tNvqh1s+v0vFYdA1xq0aOJH+Y5cRyZ5upu6roPgPKd4= github.com/aws/aws-sdk-go-v2 v1.41.0/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0= +github.com/aws/aws-sdk-go-v2 v1.41.1 h1:ABlyEARCDLN034NhxlRUSZr4l71mh+T5KAeGh6cerhU= +github.com/aws/aws-sdk-go-v2 v1.41.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4= github.com/aws/aws-sdk-go-v2/config v1.32.6 h1:hFLBGUKjmLAekvi1evLi5hVvFQtSo3GYwi+Bx4lpJf8= github.com/aws/aws-sdk-go-v2/config v1.32.6/go.mod h1:lcUL/gcd8WyjCrMnxez5OXkO3/rwcNmvfno62tnXNcI= +github.com/aws/aws-sdk-go-v2/config v1.32.7 h1:vxUyWGUwmkQ2g19n7JY/9YL8MfAIl7bTesIUykECXmY= +github.com/aws/aws-sdk-go-v2/config v1.32.7/go.mod h1:2/Qm5vKUU/r7Y+zUk/Ptt2MDAEKAfUtKc1+3U1Mo3oY= github.com/aws/aws-sdk-go-v2/credentials v1.19.6 h1:F9vWao2TwjV2MyiyVS+duza0NIRtAslgLUM0vTA1ZaE= github.com/aws/aws-sdk-go-v2/credentials v1.19.6/go.mod h1:SgHzKjEVsdQr6Opor0ihgWtkWdfRAIwxYzSJ8O85VHY= +github.com/aws/aws-sdk-go-v2/credentials v1.19.7 h1:tHK47VqqtJxOymRrNtUXN5SP/zUTvZKeLx4tH6PGQc8= +github.com/aws/aws-sdk-go-v2/credentials v1.19.7/go.mod h1:qOZk8sPDrxhf+4Wf4oT2urYJrYt3RejHSzgAquYeppw= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 h1:80+uETIWS1BqjnN9uJ0dBUaETh+P1XwFy5vwHwK5r9k= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16/go.mod h1:wOOsYuxYuB/7FlnVtzeBYRcjSRtQpAW0hCP7tIULMwo= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 h1:I0GyV8wiYrP8XpA70g1HBcQO1JlQxCMTW9npl5UbDHY= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17/go.mod h1:tyw7BOl5bBe/oqvoIeECFJjMdzXoa/dfVz3QQ5lgHGA= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.18 h1:9vWXHtaepwoAl/UuKzxwgOoJDXPCC3hvgNMfcmdS2Tk= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.18/go.mod h1:sKuUZ+MwUTuJbYvZ8pK0x10LvgcJK3Y4rmh63YBekwk= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.21.1 h1:1hWFp+52Vq8Fevy/KUhbW/1MEApMz7uitCF/PQXRJpk= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.21.1/go.mod h1:sIec8j802/rCkCKgZV678HFR0s7lhQUYXT77tIvlaa4= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 h1:rgGwPzb82iBYSvHMHXc8h9mRoOUBZIGFgKb9qniaZZc= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16/go.mod h1:L/UxsGeKpGoIj6DxfhOWHWQ/kGKcd4I1VncE4++IyKA= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 h1:xOLELNKGp2vsiteLsvLPwxC+mYmO6OZ8PYgiuPJzF8U= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17/go.mod h1:5M5CI3D12dNOtH3/mk6minaRwI2/37ifCURZISxA/IQ= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 h1:1jtGzuV7c82xnqOVfx2F0xmJcOw5374L7N6juGW6x6U= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16/go.mod h1:M2E5OQf+XLe+SZGmmpaI2yy+J326aFf6/+54PoxSANc= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 h1:WWLqlh79iO48yLkj1v3ISRNiv+3KdQoZ6JWyfcsyQik= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17/go.mod h1:EhG22vHRrvF8oXSTYStZhJc1aUgKtnJe+aOiFEV90cM= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 h1:CjMzUs78RDDv4ROu3JnJn/Ig1r6ZD7/T2DXLLRpejic= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16/go.mod h1:uVW4OLBqbJXSHJYA9svT9BluSvvwbzLQ2Crf6UPzR3c= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 h1:JqcdRG//czea7Ppjb+g/n4o8i/R50aTBHkA7vu0lK+k= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17/go.mod h1:CO+WeGmIdj/MlPel2KwID9Gt7CNq4M65HUfBW97liM0= github.com/aws/aws-sdk-go-v2/service/ecr v1.55.0 h1:Mz6rvVhqmqGPzZNDLolW9IwPzhL/V+QS+dvX+vm/zh8= github.com/aws/aws-sdk-go-v2/service/ecr v1.55.0/go.mod h1:8n8vVvu7LzveA0or4iWQwNndJStpKOX4HiVHM5jax2U= +github.com/aws/aws-sdk-go-v2/service/ecr v1.55.1 h1:B7f9R99lCF83XlolTg6d6Lvghyto+/VU83ZrneAVfK8= +github.com/aws/aws-sdk-go-v2/service/ecr v1.55.1/go.mod h1:cpYRXx5BkmS3mwWRKPbWSPKmyAUNL7aLWAPiiinwk/U= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.8 h1:2QlSMAimXfMKYRFlxGkbRMRtKN3OqIOB/CfxMcVdzjM= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.8/go.mod h1:esoP/SqS8FVryu4PPLX6ND925slId/IxPxvUBKuBqRk= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.9 h1:WxoqdNfGWj668u/NX7qBMPevmJu14LYNMMTRZthoclc= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.9/go.mod h1:4oMS/bVKMnYIIBgkcHPoru4DVeMGutHv03FZUTjvsvI= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 h1:DIBqIrJ7hv+e4CmIk2z3pyKT+3B6qVMgRsawHiR3qso= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7/go.mod h1:vLm00xmBke75UmpNvOcZQ/Q30ZFjbczeLFqGx5urmGo= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 h1:Z5EiPIzXKewUQK0QTMkutjiaPVeVYXX7KIqhXu/0fXs= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8/go.mod h1:FsTpJtvC4U1fyDXk7c71XoDv3HlRm8V3NiYLeYLh5YE= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 h1:oHjJHeUy0ImIV0bsrX0X91GkV5nJAyv1l1CC9lnO0TI= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16/go.mod h1:iRSNGgOYmiYwSCXxXaKb9HfOEj40+oTKn8pTxMlYkRM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 h1:RuNSMoozM8oXlgLG/n6WLaFGoea7/CddrCfIiSA+xdY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17/go.mod h1:F2xxQ9TZz5gDWsclCtPQscGpP0VUOc8RqgFM3vDENmU= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 h1:NSbvS17MlI2lurYgXnCOLvCFX38sBW4eiVER7+kkgsU= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16/go.mod h1:SwT8Tmqd4sA6G1qaGdzWCJN99bUmPGHfRwwq3G5Qb+A= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 h1:bGeHBsGZx0Dvu/eJC0Lh9adJa3M1xREcndxLNZlve2U= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17/go.mod h1:dcW24lbU0CzHusTE8LLHhRLI42ejmINN8Lcr22bwh/g= github.com/aws/aws-sdk-go-v2/service/kms v1.49.4 h1:2gom8MohxN0SnhHZBYAC4S8jHG+ENEnXjyJ5xKe3vLc= github.com/aws/aws-sdk-go-v2/service/kms v1.49.4/go.mod h1:HO31s0qt0lso/ADvZQyzKs8js/ku0fMHsfyXW8OPVYc= +github.com/aws/aws-sdk-go-v2/service/kms v1.49.5 h1:DKibav4XF66XSeaXcrn9GlWGHos6D/vJ4r7jsK7z5CE= +github.com/aws/aws-sdk-go-v2/service/kms v1.49.5/go.mod h1:1SdcmEGUEQE1mrU2sIgeHtcMSxHuybhPvuEPANzIDfI= github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0 h1:MIWra+MSq53CFaXXAywB2qg9YvVZifkk6vEGl/1Qor0= github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0/go.mod h1:79S2BdqCJpScXZA2y+cpZuocWsjGjJINyXnOsf5DTz8= +github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0 h1:oeu8VPlOre74lBA/PMhxa5vewaMIMmILM+RraSyB8KA= +github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0/go.mod h1:5jggDlZ2CLQhwJBiZJb4vfk4f0GxWdEDruWKEJ1xOdo= github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 h1:HpI7aMmJ+mm1wkSHIA2t5EaFFv5EFYXePW30p1EIrbQ= github.com/aws/aws-sdk-go-v2/service/signin v1.0.4/go.mod h1:C5RdGMYGlfM0gYq/tifqgn4EbyX99V15P2V3R+VHbQU= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 h1:VrhDvQib/i0lxvr3zqlUwLwJP4fpmpyD9wYG1vfSu+Y= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.5/go.mod h1:k029+U8SY30/3/ras4G/Fnv/b88N4mAfliNn08Dem4M= github.com/aws/aws-sdk-go-v2/service/sso v1.30.8 h1:aM/Q24rIlS3bRAhTyFurowU8A0SMyGDtEOY/l/s/1Uw= github.com/aws/aws-sdk-go-v2/service/sso v1.30.8/go.mod h1:+fWt2UHSb4kS7Pu8y+BMBvJF0EWx+4H0hzNwtDNRTrg= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 h1:v6EiMvhEYBoHABfbGB4alOYmCIrcgyPPiBE1wZAEbqk= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.9/go.mod h1:yifAsgBxgJWn3ggx70A3urX2AN49Y5sJTD1UQFlfqBw= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 h1:AHDr0DaHIAo8c9t1emrzAlVDFp+iMMKnPdYy6XO4MCE= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12/go.mod h1:GQ73XawFFiWxyWXMHWfhiomvP3tXtdNar/fi8z18sx0= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 h1:gd84Omyu9JLriJVCbGApcLzVR3XtmC4ZDPcAI6Ftvds= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13/go.mod h1:sTGThjphYE4Ohw8vJiRStAcu3rbjtXRsdNB0TvZ5wwo= github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 h1:SciGFVNZ4mHdm7gpD1dgZYnCuVdX1s+lFTg4+4DOy70= github.com/aws/aws-sdk-go-v2/service/sts v1.41.5/go.mod h1:iW40X4QBmUxdP+fZNOpfmkdMZqsovezbAeO+Ubiv2pk= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 h1:5fFjR/ToSOzB2OQ/XqWpZBmNvmP/pJ1jOWYlFDJTjRQ= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.6/go.mod h1:qgFDZQSD/Kys7nJnVqYlWKnh0SSdMjAi0uSwON4wgYQ= github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk= github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.11.0 h1:GOPttfOAf5qAgx7r6b+zCWZrvCsfKffkL4H6mSYx1kA= @@ -261,6 +330,8 @@ github.com/aymanbagabas/go-udiff v0.3.1 h1:LV+qyBQ2pqe0u42ZsUEtPiCaUoqgA9gYRDs3v github.com/aymanbagabas/go-udiff v0.3.1/go.mod h1:G0fsKmG+P6ylD0r6N/KgQD/nWzgfnl8ZBcNLgcbrw8E= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= +github.com/beevik/etree v1.6.0 h1:u8Kwy8pp9D9XeITj2Z0XtA5qqZEmtJtuXZRQi+j03eE= +github.com/beevik/etree v1.6.0/go.mod h1:bh4zJxiIr62SOf9pRzN7UUYaEDa9HEKafK25+sLc0Gc= 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/bkielbasa/cyclop v1.2.3 h1:faIVMIGDIANuGPWH031CZJTi2ymOQBULs9H21HSMa5w= @@ -277,10 +348,16 @@ github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= github.com/bluesky-social/indigo v0.0.0-20260106221649-6fcd9317e725 h1:gfrLAhE6PHun4MDypO/5hpnaHPd9Dbe9+JxZL0gC4ic= github.com/bluesky-social/indigo v0.0.0-20260106221649-6fcd9317e725/go.mod h1:KIy0FgNQacp4uv2Z7xhNkV3qZiUSGuRky97s7Pa4v+o= +github.com/bluesky-social/indigo v0.0.0-20260128215158-cf0fe7589346 h1:FfYnKHM+w5EDHFMBwTgMUpi3DLVxbMa2MRr0kI4Iqw0= +github.com/bluesky-social/indigo v0.0.0-20260128215158-cf0fe7589346/go.mod h1:KIy0FgNQacp4uv2Z7xhNkV3qZiUSGuRky97s7Pa4v+o= github.com/bombsimon/wsl/v4 v4.7.0 h1:1Ilm9JBPRczjyUs6hvOPKvd7VL1Q++PL8M0SXBDf+jQ= github.com/bombsimon/wsl/v4 v4.7.0/go.mod h1:uV/+6BkffuzSAVYD+yGyld1AChO7/EuLrCF/8xTiapg= github.com/bombsimon/wsl/v5 v5.3.0 h1:nZWREJFL6U3vgW/B1lfDOigl+tEF6qgs6dGGbFeR0UM= github.com/bombsimon/wsl/v5 v5.3.0/go.mod h1:Gp8lD04z27wm3FANIUPZycXp+8huVsn0oxc+n4qfV9I= +github.com/bombsimon/wsl/v5 v5.6.0 h1:4z+/sBqC5vUmSp1O0mS+czxwH9+LKXtCWtHH9rZGQL8= +github.com/bombsimon/wsl/v5 v5.6.0/go.mod h1:Uqt2EfrMj2NV8UGoN1f1Y3m0NpUVCsUdrNCdet+8LvU= +github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8bttX0bfZGmcGkjz7DLQXhAn3DNd3T0ous= +github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c= github.com/breml/bidichk v0.3.3 h1:WSM67ztRusf1sMoqH6/c4OBCUlRVTKq+CbSeo0R17sE= github.com/breml/bidichk v0.3.3/go.mod h1:ISbsut8OnjB367j5NseXEGGgO/th206dVa427kR8YTE= github.com/breml/errchkjson v0.4.1 h1:keFSS8D7A2T0haP9kzZTi7o26r7kE3vymjZNeNDRDwg= @@ -315,6 +392,7 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3 github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261 h1:6/yVvBsKeAw05IUj4AzvrxaCnDjN4nUqKjW9+w5wixg= github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -330,12 +408,18 @@ github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoF github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= github.com/charmbracelet/ultraviolet v0.0.0-20251217160852-6b0c0e26fad9 h1:dsDBRP9Iyco0EjVpCsAzl8VGbxk04fP3sa80ySJSAZw= github.com/charmbracelet/ultraviolet v0.0.0-20251217160852-6b0c0e26fad9/go.mod h1:Ns3cOzzY9hEFFeGxB6VpfgRnqOJZJFhQAPfRxPqflQs= +github.com/charmbracelet/ultraviolet v0.0.0-20260123224754-f434aada8dbd h1:TIjV5jgzCdmhE/cWl/e8pmOaTns/Ah4SoUFv4PTFlC0= +github.com/charmbracelet/ultraviolet v0.0.0-20260123224754-f434aada8dbd/go.mod h1:2I+V4H3xExk9BZ3W2UnU/RAkJPYzBOkY7RzEe7tH1vo= github.com/charmbracelet/x/ansi v0.11.3 h1:6DcVaqWI82BBVM/atTyq6yBoRLZFBsnoDoX9GCu2YOI= github.com/charmbracelet/x/ansi v0.11.3/go.mod h1:yI7Zslym9tCJcedxz5+WBq+eUGMJT0bM06Fqy1/Y4dI= +github.com/charmbracelet/x/ansi v0.11.4 h1:6G65PLu6HjmE858CnTUQY1LXT3ZUWwfvqEROLF8vqHI= +github.com/charmbracelet/x/ansi v0.11.4/go.mod h1:/5AZ+UfWExW3int5H5ugnsG/PWjNcSQcwYsHBlPFQN4= github.com/charmbracelet/x/cellbuf v0.0.14 h1:iUEMryGyFTelKW3THW4+FfPgi4fkmKnnaLOXuc+/Kj4= github.com/charmbracelet/x/cellbuf v0.0.14/go.mod h1:P447lJl49ywBbil/KjCk2HexGh4tEY9LH0/1QrZZ9rA= github.com/charmbracelet/x/exp/charmtone v0.0.0-20251215102626-e0db08df7383 h1:xGojlO6kHCDB1k6DolME79LG0u90TzVd8atGhmxFRIo= github.com/charmbracelet/x/exp/charmtone v0.0.0-20251215102626-e0db08df7383/go.mod h1:nsExn0DGyX0lh9LwLHTn2Gg+hafdzfSXnC+QmEJTZFY= +github.com/charmbracelet/x/exp/charmtone v0.0.0-20260127155452-b72a9a918687 h1:YSLsz8YEuMxY9SXJSKpjBWmOxjjjP4xEX2hZ56BP/2s= +github.com/charmbracelet/x/exp/charmtone v0.0.0-20260127155452-b72a9a918687/go.mod h1:nsExn0DGyX0lh9LwLHTn2Gg+hafdzfSXnC+QmEJTZFY= github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f h1:pk6gmGpCE7F3FcjaOEKYriCvpmIN4+6OS/RD0vm4uIA= github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f/go.mod h1:IfZAMTHB6XkZSeXUqriemErjAWCCzT0LwjKFYCZyw0I= github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk= @@ -346,22 +430,36 @@ github.com/charmbracelet/x/windows v0.2.2 h1:IofanmuvaxnKHuV04sC0eBy/smG6kIKrWG2 github.com/charmbracelet/x/windows v0.2.2/go.mod h1:/8XtdKZzedat74NQFn0NGlGL4soHB0YQZrETF96h75k= github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 h1:krfRl01rzPzxSxyLyrChD+U+MzsBXbm0OwYYB67uF+4= github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589/go.mod h1:OuDyvmLnMCwa2ep4Jkm6nyA0ocJuZlGyk2gGseVzERM= +github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= +github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= +github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= +github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/ckaznocha/intrange v0.3.1 h1:j1onQyXvHUsPWujDH6WIjhyH26gkRt/txNlV7LspvJs= github.com/ckaznocha/intrange v0.3.1/go.mod h1:QVepyz1AkUoFQkpEqksSYpNpUo3c5W7nWh/s6SHIJJk= github.com/clipperhouse/displaywidth v0.6.1 h1:/zMlAezfDzT2xy6acHBzwIfyu2ic0hgkT83UX5EY2gY= github.com/clipperhouse/displaywidth v0.6.1/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o= +github.com/clipperhouse/displaywidth v0.8.0 h1:/z8v+H+4XLluJKS7rAc7uHZTalT5Z+1430ld3lePSRI= +github.com/clipperhouse/displaywidth v0.8.0/go.mod h1:UpOXiIKep+TohQYwvAAM/VDU8v3Z5rnWTxiwueR0XvQ= github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs= github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4= github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= +github.com/clipperhouse/uax29/v2 v2.4.0 h1:RXqE/l5EiAbA4u97giimKNlmpvkmz+GrBVTelsoXy9g= +github.com/clipperhouse/uax29/v2 v2.4.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= github.com/cloudflare/circl v1.6.2 h1:hL7VBpHHKzrV5WTfHCaBsgx/HGbBYlgrwvNXEVDYYsQ= github.com/cloudflare/circl v1.6.2/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4= +github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8= +github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4= github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w= github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI= +github.com/cncf/xds/go v0.0.0-20260121142036-a486691bba94 h1:kkHPnzHm5Ln7WA0XYjrr2ITA0l9Vs6H++Ni//P+SZso= +github.com/cncf/xds/go v0.0.0-20260121142036-a486691bba94/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4= github.com/codesphere-cloud/cs-go v0.16.1 h1:Pa3UzfeU7G1JMNoVMMd2uiIYX4NyYY2bJM0EdT1Xncw= github.com/codesphere-cloud/cs-go v0.16.1/go.mod h1:2jJuJ5hYdbdeHlm7Ks0xkd8qvFt1gLAbpVTx2LFTIyQ= +github.com/codesphere-cloud/cs-go v0.16.2 h1:AtS4HKPngpYfB4uj28vo/eq+qPWXICjLmx9R0G0a2rQ= +github.com/codesphere-cloud/cs-go v0.16.2/go.mod h1:VvEsEx7dOlLOCqRFexl0ovuoDB9/N/fQQmMhg5wyE4Q= github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= @@ -372,6 +470,8 @@ github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/containerd/stargz-snapshotter/estargz v0.18.1 h1:cy2/lpgBXDA3cDKSyEfNOFMA/c10O1axL69EU7iirO8= github.com/containerd/stargz-snapshotter/estargz v0.18.1/go.mod h1:ALIEqa7B6oVDsrF37GkGN20SuvG/pIMm7FwP7ZmRb0Q= +github.com/containerd/stargz-snapshotter/estargz v0.18.2 h1:yXkZFYIzz3eoLwlTUZKz2iQ4MrckBxJjkmD16ynUTrw= +github.com/containerd/stargz-snapshotter/estargz v0.18.2/go.mod h1:XyVU5tcJ3PRpkA9XS2T5us6Eg35yM0214Y+wvrZTBrY= github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc= github.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= @@ -379,6 +479,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= github.com/cpuguy83/go-md2man/v2 v2.0.7/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/creativeprojects/go-selfupdate v1.5.2 h1:3KR3JLrq70oplb9yZzbmJ89qRP78D1AN/9u+l3k0LJ4= @@ -405,6 +506,8 @@ github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454Wv github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE= github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8= github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY= +github.com/denis-tingaikin/go-header v1.0.0 h1:QIwZWb3jLC6pOp9NEFldiD8raqRmCE/n0VUdZKW32x8= +github.com/denis-tingaikin/go-header v1.0.0/go.mod h1:NT3qKwqsXQYp8WHVgkwxL49qB5jsRmdr9dGQCDfpmZ0= github.com/dghubble/go-twitter v0.0.0-20221104224141-912508c3888b h1:XQu6o3AwJx/jsg9LZ41uIeUdXK5be099XFfFn6H9ikk= github.com/dghubble/go-twitter v0.0.0-20221104224141-912508c3888b/go.mod h1:B0/qdW5XUupJvcsx40hnVbfjzz9He5YpYXx6eVVdiSY= github.com/dghubble/oauth1 v0.7.3 h1:EkEM/zMDMp3zOsX2DC/ZQ2vnEX3ELK0/l9kb+vs4ptE= @@ -428,18 +531,24 @@ github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZ github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/docker/cli v29.2.0-rc.1.0.20251223174200-874b831c0e49+incompatible h1:qzsQ4KSWZG5dBSDv3XFBCvBcy6/jC1odDTwe2SbMBh0= github.com/docker/cli v29.2.0-rc.1.0.20251223174200-874b831c0e49+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v29.2.0+incompatible h1:9oBd9+YM7rxjZLfyMGxjraKBKE4/nVyvVfN4qNl9XRM= +github.com/docker/cli v29.2.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.9.4 h1:76ItO69/AP/V4yT9V4uuuItG0B1N8hvt0T0c0NN/DzI= github.com/docker/docker-credential-helpers v0.9.4/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c= +github.com/docker/docker-credential-helpers v0.9.5 h1:EFNN8DHvaiK8zVqFA2DT6BjXE0GzfLOZ38ggPTKePkY= +github.com/docker/docker-credential-helpers v0.9.5/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c= github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dprotaso/go-yit v0.0.0-20250513223454-5ece0c5aa76c h1:EMwsP/vaHQDLhAX1kNIng5mHEhg+CkS18m0AL825n6U= +github.com/dprotaso/go-yit v0.0.0-20250513223454-5ece0c5aa76c/go.mod h1:lHwJo6jMevQL9tNpW6vLyhkK13bYHBcoh9tUakMhbnE= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/earthboundkid/versioninfo/v2 v2.24.1 h1:SJTMHaoUx3GzjjnUO1QzP3ZXK6Ee/nbWyCm58eY3oUg= @@ -482,6 +591,8 @@ github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCK github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= github.com/ghostiam/protogetter v0.3.18 h1:yEpghRGtP9PjKvVXtEzGpYfQj1Wl/ZehAfU6fr62Lfo= github.com/ghostiam/protogetter v0.3.18/go.mod h1:FjIu5Yfs6FT391m+Fjp3fbAYJ6rkL/J6ySpZBfnODuI= +github.com/ghostiam/protogetter v0.3.19 h1:yGoXYWL66F41FZqwEvjSnS3ghbUhKbpJgzKpmOOMovU= +github.com/ghostiam/protogetter v0.3.19/go.mod h1:FjIu5Yfs6FT391m+Fjp3fbAYJ6rkL/J6ySpZBfnODuI= github.com/github/smimesign v0.2.0 h1:Hho4YcX5N1I9XNqhq0fNx0Sts8MhLonHd+HRXVGNjvk= github.com/github/smimesign v0.2.0/go.mod h1:iZiiwNT4HbtGRVqCQu7uJPEZCuEE5sfSSttcnePkDl4= github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs= @@ -597,6 +708,8 @@ github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUN github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= +github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-xmlfmt/xmlfmt v1.1.3 h1:t8Ey3Uy7jDSEisW2K3somuMKIpzktkWptA0iFCnRUWY= github.com/go-xmlfmt/xmlfmt v1.1.3/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= @@ -613,6 +726,7 @@ github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw= github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0= 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 v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= @@ -620,10 +734,14 @@ github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXe github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= +github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= 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/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/asciicheck v0.5.0 h1:jczN/BorERZwK8oiFBOGvlGPknhvq0bjnysTj4nUfo0= github.com/golangci/asciicheck v0.5.0/go.mod h1:5RMNAInbNFw2krqN6ibBxN/zfRFa9S6tA1nPdM0l8qQ= github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 h1:WUvBfQL6EW/40l6OmeSBYQJNSif4O11+bmWEz+C7FYw= @@ -632,6 +750,8 @@ github.com/golangci/go-printf-func-name v0.1.1 h1:hIYTFJqAGp1iwoIfsNTpoq1xZAarog github.com/golangci/go-printf-func-name v0.1.1/go.mod h1:Es64MpWEZbh0UBtTAICOZiB+miW53w/K9Or/4QogJss= github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d h1:viFft9sS/dxoYY0aiOTsLKO2aZQAPT4nlQCsimGcSGE= github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d/go.mod h1:ivJ9QDg0XucIkmwhzCDsqcnxxlDStoTl89jDMIoNxKY= +github.com/golangci/gofmt v0.0.0-20251215234548-e7be49a5ab4d h1:7Vk1kMg7H+H6YVOQlJj1Eac4TgpylbOXOQp8hJTTNgo= +github.com/golangci/gofmt v0.0.0-20251215234548-e7be49a5ab4d/go.mod h1:otKf/6iIqxE63jjoqGYpkwGAJmMyXS1HToujXO7T5CQ= github.com/golangci/golangci-lint/v2 v2.8.0 h1:wJnr3hJWY3eVzOUcfwbDc2qbi2RDEpvLmQeNFaPSNYA= github.com/golangci/golangci-lint/v2 v2.8.0/go.mod h1:xl+HafQ9xoP8rzw0z5AwnO5kynxtb80e8u02Ej/47RI= github.com/golangci/golines v0.14.0 h1:xt9d3RKBjhasA3qpoXs99J2xN2t6eBlpLHt0TrgyyXc= @@ -674,6 +794,8 @@ github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9 github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= github.com/google/pprof v0.0.0-20260106004452-d7df1bf2cac7 h1:kmPAX+IJBcUAFTddx2+xC0H7sk2U9ijIIxZLLrPLNng= github.com/google/pprof v0.0.0-20260106004452-d7df1bf2cac7/go.mod h1:67FPmZWbr+KDT/VlpWtw6sO9XSjpJmLuHpoLmWiTGgY= +github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc= +github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/rpmpack v0.7.1 h1:YdWh1IpzOjBz60Wvdw0TU0A5NWP+JTVHA5poDqwMO2o= github.com/google/rpmpack v0.7.1/go.mod h1:h1JL16sUTWCLI/c39ox1rDaTBo3BXUQGjczVJyK4toU= @@ -705,6 +827,8 @@ github.com/goreleaser/goreleaser/v2 v2.13.3 h1:S8d13YgzzFXxoUJ9NJInuyq3lPNCXTcuW github.com/goreleaser/goreleaser/v2 v2.13.3/go.mod h1:Rj+yhhXrO6WHc6cNh1GggpxzhhHXv9lczL5M4cSV3oA= github.com/goreleaser/nfpm/v2 v2.44.1 h1:g+QNjkEx+C2Zu8dB48t9da/VfV0CWS5TMjxT8HG1APY= github.com/goreleaser/nfpm/v2 v2.44.1/go.mod h1:drIYLqkla9SaOLbSnaFOmSIv5LXGfhHcbK54st97b4s= +github.com/goreleaser/nfpm/v2 v2.44.2 h1:h1DLjxoxlA85qru1IsRrqbJw51DLJ64kAiWmlPQ3zaA= +github.com/goreleaser/nfpm/v2 v2.44.2/go.mod h1:O0h9bB68D39NTnM9rSOJhVCYxQk7sU8i04q2bzczFdk= github.com/goreleaser/quill v0.0.0-20251224035235-ab943733386f h1:2HQF/pifDK7XnmVhQi3OecdUcHLOaXIKVKscW8qKzCk= github.com/goreleaser/quill v0.0.0-20251224035235-ab943733386f/go.mod h1:Xp6aA14QqdPBg7UHToFag7mrjsV7XaKEpw1t6fDfT6M= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= @@ -727,6 +851,8 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDa github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.6 h1:1ufTZkFXIQQ9EmgPjcIPIi2krfxG03lQ8OLoY1MJ3UM= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.6/go.mod h1:lW34nIZuQ8UDPdkon5fmfp2l3+ZkQ2me/+oecHYLOII= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -768,10 +894,16 @@ github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef h1:A9HsByNhogrvm9cWb github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= +github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/ianlancetaylor/demangle v0.0.0-20250417193237-f615e6bd150b h1:ogbOPx86mIhFy764gGkqnkFC8m5PJA7sPzlk9ppLVQA= +github.com/ianlancetaylor/demangle v0.0.0-20250417193237-f615e6bd150b/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= github.com/in-toto/attestation v1.1.2 h1:MBFn6lsMq6dptQZJBhalXTcWMb/aJy3V+GX3VYj/V1E= github.com/in-toto/attestation v1.1.2/go.mod h1:gYFddHMZj3DiQ0b62ltNi1Vj5rC879bTmBbrv9CRHpM= github.com/in-toto/in-toto-golang v0.9.0 h1:tHny7ac4KgtsfrG6ybU8gVOZux2H8jN05AXJ9EBM1XU= github.com/in-toto/in-toto-golang v0.9.0/go.mod h1:xsBVrVsHNsB61++S6Dy2vWosKhuA3lUTQd+eF9HdeMo= +github.com/in-toto/in-toto-golang v0.10.0 h1:+s2eZQSK3WmWfYV85qXVSBfqgawi/5L02MaqA4o/tpM= +github.com/in-toto/in-toto-golang v0.10.0/go.mod h1:wjT4RiyFlLWCmLUJjwB8oZcjaq7HA390aMJcD3xXgmg= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E= @@ -780,6 +912,8 @@ github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= github.com/ipfs/boxo v0.34.0 h1:pMP9bAsTs4xVh8R0ZmxIWviV7kjDa60U24QrlGgHb1g= github.com/ipfs/boxo v0.34.0/go.mod h1:kzdH/ewDybtO3+M8MCVkpwnIIc/d2VISX95DFrY4vQA= +github.com/ipfs/boxo v0.36.0 h1:DarrMBM46xCs6GU6Vz+AL8VUyXykqHAqZYx8mR0Oics= +github.com/ipfs/boxo v0.36.0/go.mod h1:92hnRXfP5ScKEIqlq9Ns7LR1dFXEVADKWVGH0fjk83k= github.com/ipfs/go-block-format v0.2.3 h1:mpCuDaNXJ4wrBJLrtEaGFGXkferrw5eqVvzaHhtFKQk= github.com/ipfs/go-block-format v0.2.3/go.mod h1:WJaQmPAKhD3LspLixqlqNFxiZ3BZ3xgqxxoSR/76pnA= github.com/ipfs/go-cid v0.6.0 h1:DlOReBV1xhHBhhfy/gBNNTSyfOM6rLiIx9J7A4DGf30= @@ -803,6 +937,8 @@ github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JP github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= github.com/ipfs/go-log/v2 v2.9.0 h1:l4b06AwVXwldIzbVPZy5z7sKp9lHFTX0KWfTBCtHaOk= github.com/ipfs/go-log/v2 v2.9.0/go.mod h1:UhIYAwMV7Nb4ZmihUxfIRM2Istw/y9cAk3xaK+4Zs2c= +github.com/ipfs/go-log/v2 v2.9.1 h1:3JXwHWU31dsCpvQ+7asz6/QsFJHqFr4gLgQ0FWteujk= +github.com/ipfs/go-log/v2 v2.9.1/go.mod h1:evFx7sBiohUN3AG12mXlZBw5hacBQld3ZPHrowlJYoo= github.com/ipfs/go-metrics-interface v0.3.0 h1:YwG7/Cy4R94mYDUuwsBfeziJCVm9pBMJ6q/JR9V40TU= github.com/ipfs/go-metrics-interface v0.3.0/go.mod h1:OxxQjZDGocXVdyTPocns6cOLwHieqej/jos7H4POwoY= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= @@ -831,6 +967,8 @@ github.com/jjti/go-spancheck v0.6.5 h1:lmi7pKxa37oKYIMScialXUK6hP3iY5F1gu+mLBPgY github.com/jjti/go-spancheck v0.6.5/go.mod h1:aEogkeatBrbYsyW6y5TgDfihCulDYciL1B7rG2vSsrU= github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 h1:liMMTbpW34dhU4az1GN0pTPADwNmvoRSeoZ6PItiqnY= github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +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/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE= github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= @@ -851,6 +989,8 @@ github.com/kkHAIKE/contextcheck v1.1.6 h1:7HIyRcnyzxL9Lz06NGhiKvenXq7Zw6Q0UQu/tt github.com/kkHAIKE/contextcheck v1.1.6/go.mod h1:3dDbMRNBFaq8HFXWC1JyvDSPm43CmE6IuHam8Wr0rkg= github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= +github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= @@ -869,6 +1009,8 @@ github.com/knadh/koanf/providers/structs v1.0.0 h1:DznjB7NQykhqCar2LvNug3MuxEQsZ github.com/knadh/koanf/providers/structs v1.0.0/go.mod h1:kjo5TFtgpaZORlpoJqcbeLowM2cINodv8kX+oFAeQ1w= github.com/knadh/koanf/v2 v2.3.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28= +github.com/knadh/koanf/v2 v2.3.2 h1:Ee6tuzQYFwcZXQpc2MiVeC6qHMandf5SMUJJNoFp/c4= +github.com/knadh/koanf/v2 v2.3.2/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -902,12 +1044,18 @@ github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84Yrj github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= github.com/letsencrypt/boulder v0.20260105.0 h1:P94haPlN1xm8MhIHSXbUu1cA0t0EoMhXQyMz/jLwR34= github.com/letsencrypt/boulder v0.20260105.0/go.mod h1:FWHD4EclPHIQ1y2AKEXyySrM3eKiwEyGzcwcupVEFyE= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lithammer/shortuuid v3.0.0+incompatible h1:NcD0xWW/MZYXEHa6ITy6kaXN5nwm/V115vj2YXfhS0w= github.com/lithammer/shortuuid v3.0.0+incompatible/go.mod h1:FR74pbAuElzOUuenUHTK2Tciko1/vKuIKS9dSkDrA4w= github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/lyft/protoc-gen-star/v2 v2.0.4-0.20230330145011-496ad1ac90a4 h1:sIXJOMrYnQZJu7OB7ANSF4MYri2fTEGIsRLz6LwI4xE= +github.com/lyft/protoc-gen-star/v2 v2.0.4-0.20230330145011-496ad1ac90a4/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= github.com/macabu/inamedparam v0.2.0 h1:VyPYpOc10nkhI2qeNUdh3Zket4fcZjEWe35poddBCpE= github.com/macabu/inamedparam v0.2.0/go.mod h1:+Pee9/YfGe5LJ62pYXqB89lJ+0k5bsR8Wgz/C0Zlq3U= +github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo= +github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/manuelarte/embeddedstructfieldcheck v0.4.0 h1:3mAIyaGRtjK6EO9E73JlXLtiy7ha80b2ZVGyacxgfww= @@ -938,8 +1086,12 @@ github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byF github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE= github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A= +github.com/mgechev/dots v1.0.0 h1:o+4OJ3OjWzgQHGJXKfJ8rbH4dqDugu5BiEy84nxg0k4= +github.com/mgechev/dots v1.0.0/go.mod h1:rykuMydC9t3wfkM+ccYH3U3ss03vZGg6h3hmOznXLH0= github.com/mgechev/revive v1.13.0 h1:yFbEVliCVKRXY8UgwEO7EOYNopvjb1BFbmYqm9hZjBM= github.com/mgechev/revive v1.13.0/go.mod h1:efJfeBVCX2JUumNQ7dtOLDja+QKj9mYGgEZA7rt5u+0= +github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= +github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= @@ -1006,8 +1158,12 @@ github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= github.com/nunnatsa/ginkgolinter v0.21.2 h1:khzWfm2/Br8ZemX8QM1pl72LwM+rMeW6VUbQ4rzh0Po= github.com/nunnatsa/ginkgolinter v0.21.2/go.mod h1:GItSI5fw7mCGLPmkvGYrr1kEetZe7B593jcyOpyabsY= +github.com/nunnatsa/ginkgolinter v0.22.0 h1:o9g7JN6efdBxAHhejvPkodEjWsOBze9zDnPePsvC/Qg= +github.com/nunnatsa/ginkgolinter v0.22.0/go.mod h1:zIFAk36fhcHQIiYOGXLbrGTXz7cvpufhRYem6ToCVnY= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.27.5 h1:ZeVgZMx2PDMdJm/+w5fE/OyG6ILo1Y3e+QX4zSR0zTE= github.com/onsi/ginkgo/v2 v2.27.5/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= github.com/onsi/gomega v1.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q= @@ -1029,6 +1185,7 @@ github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJ github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= +github.com/pborman/getopt v0.0.0-20180811024354-2b5b3bfb099b h1:K1wa7ads2Bu1PavI6LfBRMYSy6Zi+Rky0OhWBfrmkmY= github.com/pborman/getopt v0.0.0-20180811024354-2b5b3bfb099b/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= @@ -1038,6 +1195,7 @@ github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0= github.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM= 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= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -1062,26 +1220,36 @@ github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEo github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM= github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= +github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30= github.com/quasilyte/go-ruleguard v0.4.5 h1:AGY0tiOT5hJX9BTdx/xBdoCubQUAE2grkqY2lSwvZcA= github.com/quasilyte/go-ruleguard v0.4.5/go.mod h1:Vl05zJ538vcEEwu16V/Hdu7IYZWyKSwIy4c88Ro1kRE= +github.com/quasilyte/go-ruleguard/dsl v0.3.0/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/quasilyte/go-ruleguard/dsl v0.3.23 h1:lxjt5B6ZCiBeeNO8/oQsegE6fLeCzuMRoVWSkXC4uvY= github.com/quasilyte/go-ruleguard/dsl v0.3.23/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= +github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1/go.mod h1:7JTjp89EGyU1d6XfBiXihJNG37wB2VRkd125Q1u7Plc= +github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71 h1:CNooiryw5aisadVfzneSZPswRWvnVW8hF1bS/vo8ReI= +github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50= github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo= github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl980XxGFEZSS6KlBGIV0diGdySzxATTWoqaU= github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= +github.com/qur/ar v0.0.0-20130629153254-282534b91770 h1:A6sXY4zAECrW5Obx41PVMGr4kOw1rd1kmwcHa5M0dTg= +github.com/qur/ar v0.0.0-20130629153254-282534b91770/go.mod h1:SjlYv2m9lpV0UW6K7lDqVJwEIIvSjaHbGk7nIfY8Hxw= github.com/raeperd/recvcheck v0.2.0 h1:GnU+NsbiCqdC2XX5+vMZzP+jAJC5fht7rcVTAhX74UI= github.com/raeperd/recvcheck v0.2.0/go.mod h1:n04eYkwIR0JbgD73wT8wL4JjPC3wm0nFtzBnWNocnYU= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= 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/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= +github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= +github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -1107,6 +1275,8 @@ github.com/sassoftware/relic v7.2.1+incompatible h1:Pwyh1F3I0r4clFJXkSI8bOyJINGq github.com/sassoftware/relic v7.2.1+incompatible/go.mod h1:CWfAxv73/iLZ17rbyhIEq3K9hs5w6FpNMdUT//qR+zk= github.com/sassoftware/relic/v7 v7.6.2 h1:rS44Lbv9G9eXsukknS4mSjIAuuX+lMq/FnStgmZlUv4= github.com/sassoftware/relic/v7 v7.6.2/go.mod h1:kjmP0IBVkJZ6gXeAu35/KCEfca//+PKM6vTAsyDPY+k= +github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e h1:7q6NSFZDeGfvvtIRwBrU/aegEYJYmvev0cHAwo17zZQ= github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e/go.mod h1:DkpGd78rljTxKAnTDPFqXSGxvETQnJyuSOQwsHycqfs= github.com/secure-systems-lab/go-securesystemslib v0.10.0 h1:l+H5ErcW0PAehBNrBxoGv1jjNpGYdZ9RcheFkB2WI14= @@ -1131,6 +1301,8 @@ github.com/sigstore/rekor v1.5.0 h1:rL7SghHd5HLCtsCrxw0yQg+NczGvM75EjSPPWuGjaiQ= github.com/sigstore/rekor v1.5.0/go.mod h1:D7JoVCUkxwQOpPDNYeu+CE8zeBC18Y5uDo6tF8s2rcQ= github.com/sigstore/rekor-tiles/v2 v2.0.1 h1:1Wfz15oSRNGF5Dzb0lWn5W8+lfO50ork4PGIfEKjZeo= github.com/sigstore/rekor-tiles/v2 v2.0.1/go.mod h1:Pjsbhzj5hc3MKY8FfVTYHBUHQEnP0ozC4huatu4x7OU= +github.com/sigstore/rekor-tiles/v2 v2.1.0 h1:lSxhMwVYkMsCok2rFKU3eRJXz7ppTkLEVjUnH+g8aZY= +github.com/sigstore/rekor-tiles/v2 v2.1.0/go.mod h1:qRw4VXl35azi8ENjSWbdmGtzdviLd7H08fDcp5C+97Y= github.com/sigstore/sigstore v1.10.4 h1:ytOmxMgLdcUed3w1SbbZOgcxqwMG61lh1TmZLN+WeZE= github.com/sigstore/sigstore v1.10.4/go.mod h1:tDiyrdOref3q6qJxm2G+JHghqfmvifB7hw+EReAfnbI= github.com/sigstore/sigstore-go v1.1.4 h1:wTTsgCHOfqiEzVyBYA6mDczGtBkN7cM8mPpjJj5QvMg= @@ -1145,9 +1317,13 @@ github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.10.3 h1:lJSdaC/aOlF github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.10.3/go.mod h1:b2rV9qPbt/jv/Yy75AIOZThP8j+pe1ZdLEjOwmjPdoA= github.com/sigstore/timestamp-authority/v2 v2.0.3 h1:sRyYNtdED/ttLCMdaYnwpf0zre1A9chvjTnCmWWxN8Y= github.com/sigstore/timestamp-authority/v2 v2.0.3/go.mod h1:mDaHxkt3HmZYoIlwYj4QWo0RUr7VjYU52aVO5f5Qb3I= +github.com/sigstore/timestamp-authority/v2 v2.0.4 h1:65IBa4LUeFWDQu9hiTt5lBpi/F5jonJWZtH6VLn4InU= +github.com/sigstore/timestamp-authority/v2 v2.0.4/go.mod h1:EXJLiMDBqRPlzC02hPiFSiYTCqSuUpU68a4vr0DFePM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= +github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE= github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= github.com/skeema/knownhosts v1.3.2 h1:EDL9mgf4NzwMXCTfaxSD/o/a5fxDw/xL9nkU28JjdBg= @@ -1184,6 +1360,8 @@ github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YE github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= github.com/stbenjam/no-sprintf-host-port v0.3.1 h1:AyX7+dxI4IdLBPtDbsGAyqiTSLpCP9hWRrXQDU4Cm/g= github.com/stbenjam/no-sprintf-host-port v0.3.1/go.mod h1:ODbZesTCHMVKthBHskvUUexdcNHAQRXk9NpSsL8p/HQ= +github.com/streadway/amqp v1.1.0 h1:py12iX8XSyI7aN/3dUT8DFIDJazNJsVJdxNVEpnQTZM= +github.com/streadway/amqp v1.1.0/go.mod h1:WYSrTEYHOXHd0nwFeUXAe2G2hRnQT+deZJJf88uS9Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -1198,6 +1376,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2/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/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= @@ -1223,6 +1402,8 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 h1:9LPGD+jzxMlnk5r6+hJnar67cgpDIz/iyD+rfl5r2Vk= github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67/go.mod h1:mkjARE7Yr8qU23YcGMSALbIxTQ9r9QBVahQOBRfU460= +github.com/timakin/bodyclose v0.0.0-20260129054331-73d1f95b84b4 h1:SiHe5XLTn9sFWJ5pBwJ5FN/4j34q9ZlOAD//kMoMYp0= +github.com/timakin/bodyclose v0.0.0-20260129054331-73d1f95b84b4/go.mod h1:sDHLK7rb/59v/ZxZ7KtymgcoxuUMxjXq8gtu9VMOK8M= github.com/timonwong/loggercheck v0.11.0 h1:jdaMpYBl+Uq9mWPXv1r8jc5fC3gyXx4/WGwTnnNKn4M= github.com/timonwong/loggercheck v0.11.0/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8= github.com/tink-crypto/tink-go-awskms/v2 v2.1.0 h1:N9UxlsOzu5mttdjhxkDLbzwtEecuXmlxZVo/ds7JKJI= @@ -1231,6 +1412,7 @@ github.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0 h1:3B9i6XBXNTRspfkTC0asN5W0K6GhO github.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0/go.mod h1:jY5YN2BqD/KSCHM9SqZPIpJNG/u3zwfLXHgws4x2IRw= github.com/tink-crypto/tink-go-hcvault/v2 v2.3.0 h1:6nAX1aRGnkg2SEUMwO5toB2tQkP0Jd6cbmZ/K5Le1V0= github.com/tink-crypto/tink-go-hcvault/v2 v2.3.0/go.mod h1:HOC5NWW1wBI2Vke1FGcRBvDATkEYE7AUDiYbXqi2sBw= +github.com/tink-crypto/tink-go-hcvault/v2 v2.4.0 h1:j+S+WKBQ5ya26A5EM/uXoVe+a2IaPQN8KgBJZ22cJ+4= github.com/tink-crypto/tink-go/v2 v2.6.0 h1:+KHNBHhWH33Vn+igZWcsgdEPUxKwBMEe0QC60t388v4= github.com/tink-crypto/tink-go/v2 v2.6.0/go.mod h1:2WbBA6pfNsAfBwDCggboaHeB2X29wkU8XHtGwh2YIk8= github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0= @@ -1243,6 +1425,8 @@ github.com/tomnomnom/linkheader v0.0.0-20250811210735-e5fe3b51442e h1:tD38/4xg4n github.com/tomnomnom/linkheader v0.0.0-20250811210735-e5fe3b51442e/go.mod h1:krvJ5AY/MjdPkTeRgMYbIDhbbbVvnPQPzsIsDJO8xrY= github.com/transparency-dev/formats v0.0.0-20251208091212-1378f9e1b1b7 h1:PwfIAvobqihWBi1/KIsw0IzTEJ89rYJqmXfzmqacySw= github.com/transparency-dev/formats v0.0.0-20251208091212-1378f9e1b1b7/go.mod h1:mQ5ASe7MNPT+yRc47hLguwsNdE2Go0mT6piyzUO+ynw= +github.com/transparency-dev/formats v0.0.0-20260126105629-a1e81f2894be h1:JfUkmUSwqyTs2ziQDQN45dQhxM+t+XCDLPiw2VtF12k= +github.com/transparency-dev/formats v0.0.0-20260126105629-a1e81f2894be/go.mod h1:d2FibUOHfCMdCe/+/rbKt1IPLBbPTDfwj46kt541/mU= github.com/transparency-dev/merkle v0.0.2 h1:Q9nBoQcZcgPamMkGn7ghV8XiTZ/kRxn1yCG81+twTK4= github.com/transparency-dev/merkle v0.0.2/go.mod h1:pqSy+OXefQ1EDUVmAJ8MUhHB9TXGuzVAT58PqBoHz1A= github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= @@ -1279,6 +1463,8 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xen0n/gosmopolitan v1.3.0 h1:zAZI1zefvo7gcpbCOrPSHJZJYA9ZgLfJqtKzZ5pHqQM= github.com/xen0n/gosmopolitan v1.3.0/go.mod h1:rckfr5T6o4lBtM1ga7mLGKZmLxswUoH1zxHgNXOsEt4= +github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= +github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= @@ -1314,6 +1500,8 @@ gitlab.com/digitalxero/go-conventional-commit v1.0.7 h1:8/dO6WWG+98PMhlZowt/Yjui gitlab.com/digitalxero/go-conventional-commit v1.0.7/go.mod h1:05Xc2BFsSyC5tKhK0y+P3bs0AwUtNuTp+mTpbCU/DZ0= gitlab.com/gitlab-org/api/client-go v1.11.0 h1:L+qzw4kiCf3jKdKHQAwiqYKITvzBrW/tl8ampxNLlv0= gitlab.com/gitlab-org/api/client-go v1.11.0/go.mod h1:adtVJ4zSTEJ2fP5Pb1zF4Ox1OKFg0MH43yxpb0T0248= +gitlab.com/gitlab-org/api/client-go v1.24.0 h1:lTTuEw2oA3Ac5UOqLJ80tSusDclgq97zuqCTnXqlfHw= +gitlab.com/gitlab-org/api/client-go v1.24.0/go.mod h1:ctGKgv9bErQHO0NOrfhoyFtKMAkBhUE7y53F2xHFAkE= go-simpler.org/assert v0.9.0 h1:PfpmcSvL7yAnWyChSjOz6Sp6m9j5lyK8Ok9pEL31YkQ= go-simpler.org/assert v0.9.0/go.mod h1:74Eqh5eI6vCK6Y5l3PI8ZYFXG4Sa+tkr70OIPJAUr28= go-simpler.org/musttag v0.14.0 h1:XGySZATqQYSEV3/YTy+iX+aofbZZllJaqwFWs+RTtSo= @@ -1322,10 +1510,14 @@ go-simpler.org/sloglint v0.11.1 h1:xRbPepLT/MHPTCA6TS/wNfZrDzkGvCCqUv4Bdwc3H7s= go-simpler.org/sloglint v0.11.1/go.mod h1:2PowwiCOK8mjiF+0KGifVOT8ZsCNiFzvfyJeJOIt8MQ= go.augendre.info/arangolint v0.3.1 h1:n2E6p8f+zfXSFLa2e2WqFPp4bfvcuRdd50y6cT65pSo= go.augendre.info/arangolint v0.3.1/go.mod h1:6ZKzEzIZuBQwoSvlKT+qpUfIbBfFCE5gbAoTg0/117g= +go.augendre.info/arangolint v0.4.0 h1:xSCZjRoS93nXazBSg5d0OGCi9APPLNMmmLrC995tR50= +go.augendre.info/arangolint v0.4.0/go.mod h1:l+f/b4plABuFISuKnTGD4RioXiCCgghv2xqst/xOvAA= go.augendre.info/fatcontext v0.9.0 h1:Gt5jGD4Zcj8CDMVzjOJITlSb9cEch54hjRRlN3qDojE= go.augendre.info/fatcontext v0.9.0/go.mod h1:L94brOAT1OOUNue6ph/2HnwxoNlds9aXDF2FcUntbNw= go.mongodb.org/mongo-driver v1.17.6 h1:87JUG1wZfWsr6rIz3ZmpH90rL5tea7O3IHuSwHUpsss= go.mongodb.org/mongo-driver v1.17.6/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= +go.mongodb.org/mongo-driver v1.17.7 h1:a9w+U3Vt67eYzcfq3k/OAv284/uUUkL0uP75VE5rCOU= +go.mongodb.org/mongo-driver v1.17.7/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/bridges/prometheus v0.63.0 h1:/Rij/t18Y7rUayNg7Id6rPrEnHgorxYabm2E6wUdPP4= @@ -1354,6 +1546,7 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4D go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 h1:bDMKF3RUSxshZ5OjOTi8rsHGaPKsAt76FaqgvIUySLc= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0/go.mod h1:dDT67G/IkA46Mr2l9Uj7HsQVwsjASyV9SjGofsiUZDA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= go.opentelemetry.io/otel/exporters/prometheus v0.61.0 h1:cCyZS4dr67d30uDyh8etKM2QyDsQ4zC9ds3bdbrVoD0= go.opentelemetry.io/otel/exporters/prometheus v0.61.0/go.mod h1:iivMuj3xpR2DkUrUya3TPS/Z9h3dz7h01GxU+fQBRNg= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 h1:B/g+qde6Mkzxbry5ZZag0l7QrQBCtVm7lVjaLgmpje8= @@ -1362,6 +1555,7 @@ go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83 go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.37.0 h1:SNhVp/9q4Go/XHBkQ1/d5u9P/U+L1yaGPoi0x+mStaI= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.37.0/go.mod h1:tx8OOlGH6R4kLV67YaYO44GFXloEjGPZuMjEkaaqIp4= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= go.opentelemetry.io/otel/log v0.14.0 h1:2rzJ+pOAZ8qmZ3DDHg73NEKzSZkhkGIua9gXtxNGgrM= go.opentelemetry.io/otel/log v0.14.0/go.mod h1:5jRG92fEAgx0SU/vFPxmJvhIuDU9E1SUnEQrMlJpOno= go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= @@ -1416,10 +1610,14 @@ golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0= golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= +golang.org/x/exp v0.0.0-20260112195511-716be5621a96 h1:Z/6YuSHTLOHfNFdb8zVZomZr7cqNgTJvA8+Qz75D8gU= +golang.org/x/exp v0.0.0-20260112195511-716be5621a96/go.mod h1:nzimsREAkjBCIEFtHiYkrJyT+2uy9YZJB7H1k68CXZU= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20251219203646-944ab1f22d93 h1:PbC785RGO6yPO051ItgbG/adwoKRWC0VS7kXXeD/iqk= golang.org/x/exp/typeparams v0.0.0-20251219203646-944ab1f22d93/go.mod h1:4Mzdyp/6jzw9auFDJ3OMF5qksa7UvPnzKqTVGcb04ms= +golang.org/x/exp/typeparams v0.0.0-20260112195511-716be5621a96 h1:RMc8anw0hCPcg5CZYN2PEQ8nMwosk461R6vFwPrCFVg= +golang.org/x/exp/typeparams v0.0.0-20260112195511-716be5621a96/go.mod h1:4Mzdyp/6jzw9auFDJ3OMF5qksa7UvPnzKqTVGcb04ms= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -1433,6 +1631,8 @@ golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= +golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= +golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1477,6 +1677,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1522,6 +1723,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200812195022-5ae4c3c160a0/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20201230224404-63754364767c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= @@ -1533,6 +1736,8 @@ golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58 golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= +golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= +golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= @@ -1545,14 +1750,21 @@ golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhS golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= google.golang.org/api v0.263.0 h1:UFs7qn8gInIdtk1ZA6eXRXp5JDAnS4x9VRsRVCeKdbk= google.golang.org/api v0.263.0/go.mod h1:fAU1xtNNisHgOF5JooAs8rRaTkl2rT3uaoNGo9NS3R8= google.golang.org/genproto v0.0.0-20251222181119-0a764e51fe1b h1:kqShdsddZrS6q+DGBCA73CzHsKDu5vW4qw78tFnbVvY= google.golang.org/genproto v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:gw1DtiPCt5uh/HV9STVEeaO00S5ATsJiJ2LsZV8lcDI= +google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 h1:VQZ/yAbAtjkHgH80teYd2em3xtIkkHd7ZhqfH2N9CsM= +google.golang.org/genproto v0.0.0-20260128011058-8636f8732409/go.mod h1:rxKD3IEILWEu3P44seeNOAwZN4SaoKaQ/2eTg4mM6EM= google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b h1:uA40e2M6fYRBf0+8uN5mLlqUtV192iiksiICIBkYJ1E= google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:Xa7le7qx2vmqB/SzWUBa7KdMjpdpAHlh5QCSnjessQk= +google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 h1:merA0rdPeUV3YIIfHHcH4qBkiQAc1nfCKSI7lB4cV2M= +google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409/go.mod h1:fl8J1IvUjCilwZzQowmw2b7HQB2eAuYBabMXzWurF+I= google.golang.org/genproto/googleapis/rpc v0.0.0-20260122232226-8e98ce8d340d h1:xXzuihhT3gL/ntduUZwHECzAn57E8dA6l8SOtYWdD8Q= google.golang.org/genproto/googleapis/rpc v0.0.0-20260122232226-8e98ce8d340d/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 h1:H86B94AW+VfJWDqFeEbBPhEtHzJwJfTbgE2lZa54ZAQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= @@ -1571,6 +1783,7 @@ gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= @@ -1580,8 +1793,12 @@ gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.6.1 h1:R094WgE8K4JirYjBaOpz/AvTyUu/3wbmAoskKN/pxTI= honnef.co/go/tools v0.6.1/go.mod h1:3puzxxljPCe8RGJX7BIy1plGbxEOZni5mR2aXe3/uk4= +k8s.io/apimachinery v0.35.0 h1:Z2L3IHvPVv/MJ7xRxHEtk6GoJElaAqDCCU0S6ncYok8= +k8s.io/apimachinery v0.35.0/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/utils v0.0.0-20260106112306-0fe9cd71b2f8 h1:oV4uULAC2QPIdMQwjMaNIwykyhWhnhBwX40yd5h9u3U= +k8s.io/utils v0.0.0-20260106112306-0fe9cd71b2f8/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg= lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo= mvdan.cc/gofumpt v0.9.2 h1:zsEMWL8SVKGHNztrx6uZrXdp7AX8r421Vvp23sz7ik4= From 2d6186abb6dd38eafde0c2f6d31b3441b76e71cc Mon Sep 17 00:00:00 2001 From: siherrmann <25087590+siherrmann@users.noreply.github.com> Date: Thu, 29 Jan 2026 15:40:27 +0000 Subject: [PATCH 09/12] chore(docs): Auto-update docs and licenses Signed-off-by: siherrmann <25087590+siherrmann@users.noreply.github.com> --- NOTICE | 28 ++++++++++++++-------------- docs/oms-cli_beta_bootstrap-gcp.md | 1 + internal/tmpl/NOTICE | 28 ++++++++++++++-------------- 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/NOTICE b/NOTICE index 7bbe52e5..7a7191e0 100644 --- a/NOTICE +++ b/NOTICE @@ -41,9 +41,9 @@ License URL: https://github.com/googleapis/google-cloud-go/blob/iam/v1.5.3/iam/L ---------- Module: cloud.google.com/go/longrunning -Version: v0.7.0 +Version: v0.8.0 License: Apache-2.0 -License URL: https://github.com/googleapis/google-cloud-go/blob/longrunning/v0.7.0/longrunning/LICENSE +License URL: https://github.com/googleapis/google-cloud-go/blob/longrunning/v0.8.0/longrunning/LICENSE ---------- Module: cloud.google.com/go/resourcemanager @@ -89,15 +89,15 @@ License URL: https://github.com/clipperhouse/stringish/blob/v0.1.1/LICENSE ---------- Module: github.com/clipperhouse/uax29/v2 -Version: v2.3.0 +Version: v2.4.0 License: MIT -License URL: https://github.com/clipperhouse/uax29/blob/v2.3.0/LICENSE +License URL: https://github.com/clipperhouse/uax29/blob/v2.4.0/LICENSE ---------- Module: github.com/codesphere-cloud/cs-go/pkg/io -Version: v0.16.1 +Version: v0.16.2 License: Apache-2.0 -License URL: https://github.com/codesphere-cloud/cs-go/blob/v0.16.1/LICENSE +License URL: https://github.com/codesphere-cloud/cs-go/blob/v0.16.2/LICENSE ---------- Module: github.com/codesphere-cloud/oms/internal/tmpl @@ -275,9 +275,9 @@ License URL: https://github.com/ulikunitz/xz/blob/v0.5.15/LICENSE ---------- Module: gitlab.com/gitlab-org/api/client-go -Version: v1.11.0 +Version: v1.24.0 License: Apache-2.0 -License URL: https://gitlab.com/gitlab-org/api/client-go/-/blob/v1.11.0/LICENSE +License URL: https://gitlab.com/gitlab-org/api/client-go/-/blob/v1.24.0/LICENSE ---------- Module: go.opentelemetry.io/auto/sdk @@ -413,21 +413,21 @@ License URL: https://github.com/googleapis/google-api-go-client/blob/v0.263.0/in ---------- Module: google.golang.org/genproto/googleapis -Version: v0.0.0-20251222181119-0a764e51fe1b +Version: v0.0.0-20260128011058-8636f8732409 License: Apache-2.0 -License URL: https://github.com/googleapis/go-genproto/blob/0a764e51fe1b/LICENSE +License URL: https://github.com/googleapis/go-genproto/blob/8636f8732409/LICENSE ---------- Module: google.golang.org/genproto/googleapis/api -Version: v0.0.0-20251222181119-0a764e51fe1b +Version: v0.0.0-20260128011058-8636f8732409 License: Apache-2.0 -License URL: https://github.com/googleapis/go-genproto/blob/0a764e51fe1b/googleapis/api/LICENSE +License URL: https://github.com/googleapis/go-genproto/blob/8636f8732409/googleapis/api/LICENSE ---------- Module: google.golang.org/genproto/googleapis/rpc -Version: v0.0.0-20260122232226-8e98ce8d340d +Version: v0.0.0-20260128011058-8636f8732409 License: Apache-2.0 -License URL: https://github.com/googleapis/go-genproto/blob/8e98ce8d340d/googleapis/rpc/LICENSE +License URL: https://github.com/googleapis/go-genproto/blob/8636f8732409/googleapis/rpc/LICENSE ---------- Module: google.golang.org/grpc diff --git a/docs/oms-cli_beta_bootstrap-gcp.md b/docs/oms-cli_beta_bootstrap-gcp.md index 1984b14f..ecf06c0f 100644 --- a/docs/oms-cli_beta_bootstrap-gcp.md +++ b/docs/oms-cli_beta_bootstrap-gcp.md @@ -37,6 +37,7 @@ oms-cli beta bootstrap-gcp [flags] --secrets-file string Path to secrets files (optional) (default "prod.vault.yaml") --ssh-private-key-path string SSH Private Key Path (default: ~/.ssh/id_rsa) (default "~/.ssh/id_rsa") --ssh-public-key-path string SSH Public Key Path (default: ~/.ssh/id_rsa.pub) (default "~/.ssh/id_rsa.pub") + --ssh-quiet Suppress SSH command output (default: true) (default true) --write-config Write generated install config to file (default: true) (default true) --zone string GCP Zone (default: europe-west4-a) (default "europe-west4-a") ``` diff --git a/internal/tmpl/NOTICE b/internal/tmpl/NOTICE index 7bbe52e5..7a7191e0 100644 --- a/internal/tmpl/NOTICE +++ b/internal/tmpl/NOTICE @@ -41,9 +41,9 @@ License URL: https://github.com/googleapis/google-cloud-go/blob/iam/v1.5.3/iam/L ---------- Module: cloud.google.com/go/longrunning -Version: v0.7.0 +Version: v0.8.0 License: Apache-2.0 -License URL: https://github.com/googleapis/google-cloud-go/blob/longrunning/v0.7.0/longrunning/LICENSE +License URL: https://github.com/googleapis/google-cloud-go/blob/longrunning/v0.8.0/longrunning/LICENSE ---------- Module: cloud.google.com/go/resourcemanager @@ -89,15 +89,15 @@ License URL: https://github.com/clipperhouse/stringish/blob/v0.1.1/LICENSE ---------- Module: github.com/clipperhouse/uax29/v2 -Version: v2.3.0 +Version: v2.4.0 License: MIT -License URL: https://github.com/clipperhouse/uax29/blob/v2.3.0/LICENSE +License URL: https://github.com/clipperhouse/uax29/blob/v2.4.0/LICENSE ---------- Module: github.com/codesphere-cloud/cs-go/pkg/io -Version: v0.16.1 +Version: v0.16.2 License: Apache-2.0 -License URL: https://github.com/codesphere-cloud/cs-go/blob/v0.16.1/LICENSE +License URL: https://github.com/codesphere-cloud/cs-go/blob/v0.16.2/LICENSE ---------- Module: github.com/codesphere-cloud/oms/internal/tmpl @@ -275,9 +275,9 @@ License URL: https://github.com/ulikunitz/xz/blob/v0.5.15/LICENSE ---------- Module: gitlab.com/gitlab-org/api/client-go -Version: v1.11.0 +Version: v1.24.0 License: Apache-2.0 -License URL: https://gitlab.com/gitlab-org/api/client-go/-/blob/v1.11.0/LICENSE +License URL: https://gitlab.com/gitlab-org/api/client-go/-/blob/v1.24.0/LICENSE ---------- Module: go.opentelemetry.io/auto/sdk @@ -413,21 +413,21 @@ License URL: https://github.com/googleapis/google-api-go-client/blob/v0.263.0/in ---------- Module: google.golang.org/genproto/googleapis -Version: v0.0.0-20251222181119-0a764e51fe1b +Version: v0.0.0-20260128011058-8636f8732409 License: Apache-2.0 -License URL: https://github.com/googleapis/go-genproto/blob/0a764e51fe1b/LICENSE +License URL: https://github.com/googleapis/go-genproto/blob/8636f8732409/LICENSE ---------- Module: google.golang.org/genproto/googleapis/api -Version: v0.0.0-20251222181119-0a764e51fe1b +Version: v0.0.0-20260128011058-8636f8732409 License: Apache-2.0 -License URL: https://github.com/googleapis/go-genproto/blob/0a764e51fe1b/googleapis/api/LICENSE +License URL: https://github.com/googleapis/go-genproto/blob/8636f8732409/googleapis/api/LICENSE ---------- Module: google.golang.org/genproto/googleapis/rpc -Version: v0.0.0-20260122232226-8e98ce8d340d +Version: v0.0.0-20260128011058-8636f8732409 License: Apache-2.0 -License URL: https://github.com/googleapis/go-genproto/blob/8e98ce8d340d/googleapis/rpc/LICENSE +License URL: https://github.com/googleapis/go-genproto/blob/8636f8732409/googleapis/rpc/LICENSE ---------- Module: google.golang.org/grpc From 23a1e1dea35ace175a7876981a089effb31a11ef Mon Sep 17 00:00:00 2001 From: Simon Herrmann Date: Fri, 30 Jan 2026 09:17:18 +0100 Subject: [PATCH 10/12] fix: fix go mod --- go.mod | 39 +--------- go.sum | 242 ++------------------------------------------------------- 2 files changed, 6 insertions(+), 275 deletions(-) diff --git a/go.mod b/go.mod index d360151f..82d80759 100644 --- a/go.mod +++ b/go.mod @@ -258,7 +258,6 @@ require ( github.com/golangci/asciicheck v0.5.0 // indirect github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 // indirect github.com/golangci/go-printf-func-name v0.1.1 // indirect - github.com/golangci/gofmt v0.0.0-20251215234548-e7be49a5ab4d // indirect github.com/golangci/golangci-lint/v2 v2.8.0 // indirect github.com/golangci/golines v0.14.0 // indirect github.com/golangci/misspell v0.7.0 // indirect @@ -512,57 +511,25 @@ require ( ) require ( - github.com/DataDog/zstd v1.5.5 // indirect github.com/Masterminds/semver/v3 v3.4.0 // indirect - github.com/alecthomas/kingpin/v2 v2.4.0 // indirect - github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect - github.com/beevik/etree v1.6.0 // indirect - github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect - github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261 // indirect - github.com/chzyer/readline v1.5.1 // indirect github.com/clipperhouse/stringish v0.1.1 // indirect github.com/clipperhouse/uax29/v2 v2.4.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect - github.com/danieljoos/wincred v1.2.3 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/dprotaso/go-yit v0.0.0-20250513223454-5ece0c5aa76c // indirect - github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect - github.com/godbus/dbus/v5 v5.2.2 // indirect - github.com/golang/protobuf v1.5.4 // indirect - github.com/golang/snappy v0.0.4 // indirect + github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-querystring v1.2.0 // indirect github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 // indirect - github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef // indirect - github.com/iancoleman/strcase v0.3.0 // indirect - github.com/ianlancetaylor/demangle v0.0.0-20250417193237-f615e6bd150b // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/kr/pretty v0.3.1 // indirect - github.com/kr/text v0.2.0 // indirect - github.com/lib/pq v1.10.9 // indirect - github.com/lyft/protoc-gen-star/v2 v2.0.4-0.20230330145011-496ad1ac90a4 // indirect - github.com/magefile/mage v1.14.0 // indirect github.com/mattn/go-runewidth v0.0.19 // indirect - github.com/mgechev/dots v1.0.0 // indirect - github.com/miekg/pkcs11 v1.1.1 // indirect - github.com/pborman/getopt v0.0.0-20180811024354-2b5b3bfb099b // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71 // indirect - github.com/qur/ar v0.0.0-20130629153254-282534b91770 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/sassoftware/go-rpmutils v0.4.0 // indirect - github.com/satori/go.uuid v1.2.0 // indirect github.com/spf13/pflag v1.0.10 // indirect - github.com/streadway/amqp v1.1.0 // indirect github.com/stretchr/objx v0.5.3 // indirect github.com/ulikunitz/xz v0.5.15 // indirect - github.com/xhit/go-str2duration/v2 v2.1.0 // indirect - github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect - github.com/zalando/go-keyring v0.2.6 // indirect golang.org/x/mod v0.32.0 // indirect golang.org/x/net v0.49.0 // indirect golang.org/x/oauth2 v0.34.0 // indirect @@ -571,11 +538,7 @@ require ( golang.org/x/text v0.33.0 // indirect golang.org/x/tools v0.41.0 // indirect google.golang.org/protobuf v1.36.11 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apimachinery v0.35.0 // indirect - k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/utils v0.0.0-20260106112306-0fe9cd71b2f8 // indirect ) tool ( diff --git a/go.sum b/go.sum index e3580e65..49916f8c 100644 --- a/go.sum +++ b/go.sum @@ -22,14 +22,10 @@ cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdB cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= cloud.google.com/go/iam v1.5.3 h1:+vMINPiDF2ognBJ97ABAYYwRgsaqxPbQDlMnbHMjolc= cloud.google.com/go/iam v1.5.3/go.mod h1:MR3v9oLkZCTlaqljW6Eb2d3HGDGK5/bDv93jhfISFvU= -cloud.google.com/go/kms v1.23.2 h1:4IYDQL5hG4L+HzJBhzejUySoUOheh3Lk5YT4PCyyW6k= -cloud.google.com/go/kms v1.23.2/go.mod h1:rZ5kK0I7Kn9W4erhYVoIRPtpizjunlrfU4fUkumUp8g= cloud.google.com/go/kms v1.25.0 h1:gVqvGGUmz0nYCmtoxWmdc1wli2L1apgP8U4fghPGSbQ= cloud.google.com/go/kms v1.25.0/go.mod h1:XIdHkzfj0bUO3E+LvwPg+oc7s58/Ns8Nd8Sdtljihbk= cloud.google.com/go/logging v1.13.1 h1:O7LvmO0kGLaHY/gq8cV7T0dyp6zJhYAOtZPX4TF3QtY= cloud.google.com/go/logging v1.13.1/go.mod h1:XAQkfkMBxQRjQek96WLPNze7vsOmay9H5PqfsNYDqvw= -cloud.google.com/go/longrunning v0.7.0 h1:FV0+SYF1RIj59gyoWDRi45GiYUMM3K1qO51qoboQT1E= -cloud.google.com/go/longrunning v0.7.0/go.mod h1:ySn2yXmjbK9Ba0zsQqunhDkYi0+9rlXIwnoAf+h+TPY= cloud.google.com/go/longrunning v0.8.0 h1:LiKK77J3bx5gDLi4SMViHixjD2ohlkwBi+mKA7EhfW8= cloud.google.com/go/longrunning v0.8.0/go.mod h1:UmErU2Onzi+fKDg2gR7dusz11Pe26aknR4kHmJJqIfk= cloud.google.com/go/monitoring v1.24.3 h1:dde+gMNc0UhPZD1Azu6at2e79bfdztVDS5lvhOdsgaE= @@ -38,8 +34,6 @@ cloud.google.com/go/resourcemanager v1.10.7 h1:oPZKIdjyVTuag+D4HF7HO0mnSqcqgjcuA cloud.google.com/go/resourcemanager v1.10.7/go.mod h1:rScGkr6j2eFwxAjctvOP/8sqnEpDbQ9r5CKwKfomqjs= cloud.google.com/go/serviceusage v1.9.7 h1:vrBBeI2ESmri4BLGPz1YH2o37loIQ3DDTloYiDOe2lY= cloud.google.com/go/serviceusage v1.9.7/go.mod h1:JpBpv+4Zbe7+RiC9ydc6xgBUOntIL9tA85d2xKgV83g= -cloud.google.com/go/storage v1.58.0 h1:PflFXlmFJjG/nBeR9B7pKddLQWaFaRWx4uUi/LyNxxo= -cloud.google.com/go/storage v1.58.0/go.mod h1:cMWbtM+anpC74gn6qjLh+exqYcfmB9Hqe5z6adx+CLI= cloud.google.com/go/storage v1.59.2 h1:gmOAuG1opU8YvycMNpP+DvHfT9BfzzK5Cy+arP+Nocw= cloud.google.com/go/storage v1.59.2/go.mod h1:cMWbtM+anpC74gn6qjLh+exqYcfmB9Hqe5z6adx+CLI= cloud.google.com/go/trace v1.11.7 h1:kDNDX8JkaAG3R2nq1lIdkb7FCSi1rCmsEtKVsty7p+U= @@ -54,8 +48,6 @@ dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= dev.gaijin.team/go/exhaustruct/v4 v4.0.0 h1:873r7aNneqoBB3IaFIzhvt2RFYTuHgmMjoKfwODoI1Y= dev.gaijin.team/go/exhaustruct/v4 v4.0.0/go.mod h1:aZ/k2o4Y05aMJtiux15x8iXaumE88YdiB0Ai4fXOzPI= -dev.gaijin.team/go/golib v0.8.0 h1:BiDNudpoFizoU5VHdQUiabtHSt9fyPX11Fr4OU9PaUQ= -dev.gaijin.team/go/golib v0.8.0/go.mod h1:c5fu7t1RSGMxSQgcUYO1sODbzsYnOCXJLmHeNG1Eb+0= dev.gaijin.team/go/golib v0.8.1 h1:JYju4x9BSo+QD/AYeHULVDcvEhiFg8wOi6pT0IaZF5E= dev.gaijin.team/go/golib v0.8.1/go.mod h1:c5fu7t1RSGMxSQgcUYO1sODbzsYnOCXJLmHeNG1Eb+0= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= @@ -82,8 +74,6 @@ github.com/Antonboom/testifylint v1.6.4 h1:gs9fUEy+egzxkEbq9P4cpcMB6/G0DYdMeiFS8 github.com/Antonboom/testifylint v1.6.4/go.mod h1:YO33FROXX2OoUfwjz8g+gUxQXio5i9qpVy7nXGbxDD4= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 h1:JXg2dwJUmPB9JmtVmdEB16APJ7jurfbY5jnfXpJoRMc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 h1:fou+2+WFTib47nS+nz/ozhEBnvU96bKHy6LjRsY4E28= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0/go.mod h1:t76Ruy8AHvUAC8GfMWJMa0ElSbuIcO03NLpynfbgsPA= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4= @@ -102,8 +92,6 @@ github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.4.0 h1:E4MgwLB github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.4.0/go.mod h1:Y2b/1clN4zsAoUd/pgNAQHjLDnTis/6ROkUfyob6psM= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 h1:nCYfgcSyHZXJI8J0IWE5MsCGlb2xp9fJiXyxWgmOFg4= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0/go.mod h1:ucUjca2JtSZboY8IoUqyQyuuXvwbMBVwFOm0vdQPNhA= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.3 h1:ZJJNFaQ86GVKQ9ehwqyAFE6pIfyicpuJ8IkVaPBc6/4= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.3/go.mod h1:URuDvhmATVKqHBH9/0nOiNKk0+YcwfQ3WkK5PqHKxc8= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.4 h1:jWQK1GI+LeGGUKBADtcH2rRqPxYB1Ljwms5gFA2LqrM= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.4/go.mod h1:8mwH4klAm9DUgR2EEHyEEAQlRDvLPyg5fQry3y+cDew= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= @@ -147,19 +135,12 @@ github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Djarvur/go-err113 v0.1.1 h1:eHfopDqXRwAi+YmCUas75ZE0+hoBHJ2GQNLYRSxao4g= github.com/Djarvur/go-err113 v0.1.1/go.mod h1:IaWJdYFLg76t2ihfflPZnM1LIQszWOsFDh2hhhAVF6k= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 h1:DHa2U07rk8syqvCge0QIGMCE1WxGj9njT44GH7zNJLQ= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 h1:lhhYARPUu3LmHysQ/igznQphfzynnqI3D75oUyw1HXk= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0/go.mod h1:l9rva3ApbBpEJxSNYnwT9N4CDLrWgtq3u8736C5hyJw= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 h1:UnDZ/zFfG1JhH/DqxIZYU/1CUAlTUScoXD/LcM2Ykk8= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0/go.mod h1:IA1C1U7jO/ENqm/vhi7V9YYpBsp+IMyqNrEN94N7tVc= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.54.0 h1:xfK3bbi6F2RDtaZFtUdKO3osOBIhNb+xTs8lFW6yx9o= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.54.0/go.mod h1:vB2GH9GAYYJTO3mEn8oYwzEdhlayZIdQz6zdzgUIRvA= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.55.0 h1:7t/qx5Ost0s0wbA/VDrByOooURhp+ikYwv20i9Y07TQ= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 h1:s0WlVbf9qpvkh1c/uDAPElam0WrL7fHRIidgZJ7UqZI= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.55.0/go.mod h1:vB2GH9GAYYJTO3mEn8oYwzEdhlayZIdQz6zdzgUIRvA= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 h1:0s6TxfCu2KHkkZPnBfsQ2y5qia0jl3MMrmBhu3nCOYk= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= @@ -171,8 +152,6 @@ github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSC github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/MirrexOne/unqueryvet v1.4.0 h1:6KAkqqW2KUnkl9Z0VuTphC3IXRPoFqEkJEtyxxHj5eQ= -github.com/MirrexOne/unqueryvet v1.4.0/go.mod h1:IWwCwMQlSWjAIteW0t+28Q5vouyktfujzYznSIWiuOg= github.com/MirrexOne/unqueryvet v1.5.3 h1:LpT3rsH+IY3cQddWF9bg4C7jsbASdGnrOSofY8IPEiw= github.com/MirrexOne/unqueryvet v1.5.3/go.mod h1:fs9Zq6eh1LRIhsDIsxf9PONVUjYdFHdtkHIgZdJnyPU= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= @@ -191,22 +170,14 @@ github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KO github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= -github.com/alecthomas/chroma/v2 v2.21.1 h1:FaSDrp6N+3pphkNKU6HPCiYLgm8dbe5UXIXcoBhZSWA= -github.com/alecthomas/chroma/v2 v2.21.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o= github.com/alecthomas/chroma/v2 v2.23.1 h1:nv2AVZdTyClGbVQkIzlDm/rnhk1E9bU9nXwmZ/Vk/iY= github.com/alecthomas/chroma/v2 v2.23.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o= github.com/alecthomas/go-check-sumtype v0.3.1 h1:u9aUvbGINJxLVXiFvHUlPEaD7VDULsrxJb4Aq31NLkU= github.com/alecthomas/go-check-sumtype v0.3.1/go.mod h1:A8TSiN3UPRw3laIgWEUOHHLPa6/r9MtoigdlP5h3K/E= -github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY= -github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs= github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= -github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0= -github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs= github.com/alexkohler/nakedret/v2 v2.0.6 h1:ME3Qef1/KIKr3kWX3nti3hhgNxw6aqN5pZmQiFSsuzQ= github.com/alexkohler/nakedret/v2 v2.0.6/go.mod h1:l3RKju/IzOMQHmsEvXwkqMDzHHvurNQfAgE1eVmT40Q= -github.com/alexkohler/prealloc v1.0.1 h1:A9P1haqowqUxWvU9nk6tQ7YktXIHf+LQM9wPRhuteEE= -github.com/alexkohler/prealloc v1.0.1/go.mod h1:fT39Jge3bQrfA7nPMDngUfvUbQGQeJyGQnR+913SCig= github.com/alexkohler/prealloc v1.0.2 h1:MPo8cIkGkZytq7WNH9UHv3DIX1mPz1RatPXnZb0zHWQ= github.com/alexkohler/prealloc v1.0.2/go.mod h1:fT39Jge3bQrfA7nPMDngUfvUbQGQeJyGQnR+913SCig= github.com/alfatraining/structtag v1.0.0 h1:2qmcUqNcCoyVJ0up879K614L9PazjBSFruTB0GOFjCc= @@ -215,8 +186,6 @@ github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQ github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= github.com/alingse/nilnesserr v0.2.0 h1:raLem5KG7EFVb4UIDAXgrv3N2JIaffeKNtcEXkEWd/w= github.com/alingse/nilnesserr v0.2.0/go.mod h1:1xJPrXonEtX7wyTq8Dytns5P2hNzoWymVUIaKm4HNFg= -github.com/anchore/go-macholibre v0.0.0-20250826193721-3cd206ca93aa h1:KPEP8f3enFJeus3Wo51I+riVuCvlf4OEYl2B4IfycbQ= -github.com/anchore/go-macholibre v0.0.0-20250826193721-3cd206ca93aa/go.mod h1:7YJA6tAfRm4SzIF93b32pR4xnbf8g2nJIeQnp+2vzzI= github.com/anchore/go-macholibre v0.0.0-20260126173545-dd3034b5c75b h1:P1aST8e0rhBd8xuQG/4XPlvlzTzZ6iuBdxTbZ0qo4RA= github.com/anchore/go-macholibre v0.0.0-20260126173545-dd3034b5c75b/go.mod h1:eu0gbwaZ+ocVFJLePdmPPDKU8MboV1MKsUCr36Ckd5s= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= @@ -238,86 +207,48 @@ github.com/avast/retry-go/v4 v4.7.0 h1:yjDs35SlGvKwRNSykujfjdMxMhMQQM0TnIjJaHB+Z github.com/avast/retry-go/v4 v4.7.0/go.mod h1:ZMPDa3sY2bKgpLtap9JRUgk2yTAba7cgiFhqxY2Sg6Q= github.com/aws/aws-sdk-go v1.55.8 h1:JRmEUbU52aJQZ2AjX4q4Wu7t4uZjOu71uyNmaWlUkJQ= github.com/aws/aws-sdk-go v1.55.8/go.mod h1:ZkViS9AqA6otK+JBBNH2++sx1sgxrPKcSzPPvQkUtXk= -github.com/aws/aws-sdk-go-v2 v1.41.0 h1:tNvqh1s+v0vFYdA1xq0aOJH+Y5cRyZ5upu6roPgPKd4= -github.com/aws/aws-sdk-go-v2 v1.41.0/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0= github.com/aws/aws-sdk-go-v2 v1.41.1 h1:ABlyEARCDLN034NhxlRUSZr4l71mh+T5KAeGh6cerhU= github.com/aws/aws-sdk-go-v2 v1.41.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4= -github.com/aws/aws-sdk-go-v2/config v1.32.6 h1:hFLBGUKjmLAekvi1evLi5hVvFQtSo3GYwi+Bx4lpJf8= -github.com/aws/aws-sdk-go-v2/config v1.32.6/go.mod h1:lcUL/gcd8WyjCrMnxez5OXkO3/rwcNmvfno62tnXNcI= github.com/aws/aws-sdk-go-v2/config v1.32.7 h1:vxUyWGUwmkQ2g19n7JY/9YL8MfAIl7bTesIUykECXmY= github.com/aws/aws-sdk-go-v2/config v1.32.7/go.mod h1:2/Qm5vKUU/r7Y+zUk/Ptt2MDAEKAfUtKc1+3U1Mo3oY= -github.com/aws/aws-sdk-go-v2/credentials v1.19.6 h1:F9vWao2TwjV2MyiyVS+duza0NIRtAslgLUM0vTA1ZaE= -github.com/aws/aws-sdk-go-v2/credentials v1.19.6/go.mod h1:SgHzKjEVsdQr6Opor0ihgWtkWdfRAIwxYzSJ8O85VHY= github.com/aws/aws-sdk-go-v2/credentials v1.19.7 h1:tHK47VqqtJxOymRrNtUXN5SP/zUTvZKeLx4tH6PGQc8= github.com/aws/aws-sdk-go-v2/credentials v1.19.7/go.mod h1:qOZk8sPDrxhf+4Wf4oT2urYJrYt3RejHSzgAquYeppw= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 h1:80+uETIWS1BqjnN9uJ0dBUaETh+P1XwFy5vwHwK5r9k= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16/go.mod h1:wOOsYuxYuB/7FlnVtzeBYRcjSRtQpAW0hCP7tIULMwo= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 h1:I0GyV8wiYrP8XpA70g1HBcQO1JlQxCMTW9npl5UbDHY= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17/go.mod h1:tyw7BOl5bBe/oqvoIeECFJjMdzXoa/dfVz3QQ5lgHGA= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.18 h1:9vWXHtaepwoAl/UuKzxwgOoJDXPCC3hvgNMfcmdS2Tk= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.18/go.mod h1:sKuUZ+MwUTuJbYvZ8pK0x10LvgcJK3Y4rmh63YBekwk= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.21.1 h1:1hWFp+52Vq8Fevy/KUhbW/1MEApMz7uitCF/PQXRJpk= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.21.1/go.mod h1:sIec8j802/rCkCKgZV678HFR0s7lhQUYXT77tIvlaa4= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 h1:rgGwPzb82iBYSvHMHXc8h9mRoOUBZIGFgKb9qniaZZc= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16/go.mod h1:L/UxsGeKpGoIj6DxfhOWHWQ/kGKcd4I1VncE4++IyKA= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 h1:xOLELNKGp2vsiteLsvLPwxC+mYmO6OZ8PYgiuPJzF8U= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17/go.mod h1:5M5CI3D12dNOtH3/mk6minaRwI2/37ifCURZISxA/IQ= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 h1:1jtGzuV7c82xnqOVfx2F0xmJcOw5374L7N6juGW6x6U= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16/go.mod h1:M2E5OQf+XLe+SZGmmpaI2yy+J326aFf6/+54PoxSANc= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 h1:WWLqlh79iO48yLkj1v3ISRNiv+3KdQoZ6JWyfcsyQik= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17/go.mod h1:EhG22vHRrvF8oXSTYStZhJc1aUgKtnJe+aOiFEV90cM= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 h1:CjMzUs78RDDv4ROu3JnJn/Ig1r6ZD7/T2DXLLRpejic= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16/go.mod h1:uVW4OLBqbJXSHJYA9svT9BluSvvwbzLQ2Crf6UPzR3c= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 h1:JqcdRG//czea7Ppjb+g/n4o8i/R50aTBHkA7vu0lK+k= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17/go.mod h1:CO+WeGmIdj/MlPel2KwID9Gt7CNq4M65HUfBW97liM0= -github.com/aws/aws-sdk-go-v2/service/ecr v1.55.0 h1:Mz6rvVhqmqGPzZNDLolW9IwPzhL/V+QS+dvX+vm/zh8= -github.com/aws/aws-sdk-go-v2/service/ecr v1.55.0/go.mod h1:8n8vVvu7LzveA0or4iWQwNndJStpKOX4HiVHM5jax2U= github.com/aws/aws-sdk-go-v2/service/ecr v1.55.1 h1:B7f9R99lCF83XlolTg6d6Lvghyto+/VU83ZrneAVfK8= github.com/aws/aws-sdk-go-v2/service/ecr v1.55.1/go.mod h1:cpYRXx5BkmS3mwWRKPbWSPKmyAUNL7aLWAPiiinwk/U= -github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.8 h1:2QlSMAimXfMKYRFlxGkbRMRtKN3OqIOB/CfxMcVdzjM= -github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.8/go.mod h1:esoP/SqS8FVryu4PPLX6ND925slId/IxPxvUBKuBqRk= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.9 h1:WxoqdNfGWj668u/NX7qBMPevmJu14LYNMMTRZthoclc= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.9/go.mod h1:4oMS/bVKMnYIIBgkcHPoru4DVeMGutHv03FZUTjvsvI= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 h1:DIBqIrJ7hv+e4CmIk2z3pyKT+3B6qVMgRsawHiR3qso= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7/go.mod h1:vLm00xmBke75UmpNvOcZQ/Q30ZFjbczeLFqGx5urmGo= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 h1:Z5EiPIzXKewUQK0QTMkutjiaPVeVYXX7KIqhXu/0fXs= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8/go.mod h1:FsTpJtvC4U1fyDXk7c71XoDv3HlRm8V3NiYLeYLh5YE= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 h1:oHjJHeUy0ImIV0bsrX0X91GkV5nJAyv1l1CC9lnO0TI= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16/go.mod h1:iRSNGgOYmiYwSCXxXaKb9HfOEj40+oTKn8pTxMlYkRM= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 h1:RuNSMoozM8oXlgLG/n6WLaFGoea7/CddrCfIiSA+xdY= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17/go.mod h1:F2xxQ9TZz5gDWsclCtPQscGpP0VUOc8RqgFM3vDENmU= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 h1:NSbvS17MlI2lurYgXnCOLvCFX38sBW4eiVER7+kkgsU= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16/go.mod h1:SwT8Tmqd4sA6G1qaGdzWCJN99bUmPGHfRwwq3G5Qb+A= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 h1:bGeHBsGZx0Dvu/eJC0Lh9adJa3M1xREcndxLNZlve2U= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17/go.mod h1:dcW24lbU0CzHusTE8LLHhRLI42ejmINN8Lcr22bwh/g= -github.com/aws/aws-sdk-go-v2/service/kms v1.49.4 h1:2gom8MohxN0SnhHZBYAC4S8jHG+ENEnXjyJ5xKe3vLc= -github.com/aws/aws-sdk-go-v2/service/kms v1.49.4/go.mod h1:HO31s0qt0lso/ADvZQyzKs8js/ku0fMHsfyXW8OPVYc= github.com/aws/aws-sdk-go-v2/service/kms v1.49.5 h1:DKibav4XF66XSeaXcrn9GlWGHos6D/vJ4r7jsK7z5CE= github.com/aws/aws-sdk-go-v2/service/kms v1.49.5/go.mod h1:1SdcmEGUEQE1mrU2sIgeHtcMSxHuybhPvuEPANzIDfI= -github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0 h1:MIWra+MSq53CFaXXAywB2qg9YvVZifkk6vEGl/1Qor0= -github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0/go.mod h1:79S2BdqCJpScXZA2y+cpZuocWsjGjJINyXnOsf5DTz8= github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0 h1:oeu8VPlOre74lBA/PMhxa5vewaMIMmILM+RraSyB8KA= github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0/go.mod h1:5jggDlZ2CLQhwJBiZJb4vfk4f0GxWdEDruWKEJ1xOdo= -github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 h1:HpI7aMmJ+mm1wkSHIA2t5EaFFv5EFYXePW30p1EIrbQ= -github.com/aws/aws-sdk-go-v2/service/signin v1.0.4/go.mod h1:C5RdGMYGlfM0gYq/tifqgn4EbyX99V15P2V3R+VHbQU= github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 h1:VrhDvQib/i0lxvr3zqlUwLwJP4fpmpyD9wYG1vfSu+Y= github.com/aws/aws-sdk-go-v2/service/signin v1.0.5/go.mod h1:k029+U8SY30/3/ras4G/Fnv/b88N4mAfliNn08Dem4M= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.8 h1:aM/Q24rIlS3bRAhTyFurowU8A0SMyGDtEOY/l/s/1Uw= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.8/go.mod h1:+fWt2UHSb4kS7Pu8y+BMBvJF0EWx+4H0hzNwtDNRTrg= github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 h1:v6EiMvhEYBoHABfbGB4alOYmCIrcgyPPiBE1wZAEbqk= github.com/aws/aws-sdk-go-v2/service/sso v1.30.9/go.mod h1:yifAsgBxgJWn3ggx70A3urX2AN49Y5sJTD1UQFlfqBw= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 h1:AHDr0DaHIAo8c9t1emrzAlVDFp+iMMKnPdYy6XO4MCE= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12/go.mod h1:GQ73XawFFiWxyWXMHWfhiomvP3tXtdNar/fi8z18sx0= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 h1:gd84Omyu9JLriJVCbGApcLzVR3XtmC4ZDPcAI6Ftvds= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13/go.mod h1:sTGThjphYE4Ohw8vJiRStAcu3rbjtXRsdNB0TvZ5wwo= -github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 h1:SciGFVNZ4mHdm7gpD1dgZYnCuVdX1s+lFTg4+4DOy70= -github.com/aws/aws-sdk-go-v2/service/sts v1.41.5/go.mod h1:iW40X4QBmUxdP+fZNOpfmkdMZqsovezbAeO+Ubiv2pk= github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 h1:5fFjR/ToSOzB2OQ/XqWpZBmNvmP/pJ1jOWYlFDJTjRQ= github.com/aws/aws-sdk-go-v2/service/sts v1.41.6/go.mod h1:qgFDZQSD/Kys7nJnVqYlWKnh0SSdMjAi0uSwON4wgYQ= github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk= @@ -330,8 +261,6 @@ github.com/aymanbagabas/go-udiff v0.3.1 h1:LV+qyBQ2pqe0u42ZsUEtPiCaUoqgA9gYRDs3v github.com/aymanbagabas/go-udiff v0.3.1/go.mod h1:G0fsKmG+P6ylD0r6N/KgQD/nWzgfnl8ZBcNLgcbrw8E= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= -github.com/beevik/etree v1.6.0 h1:u8Kwy8pp9D9XeITj2Z0XtA5qqZEmtJtuXZRQi+j03eE= -github.com/beevik/etree v1.6.0/go.mod h1:bh4zJxiIr62SOf9pRzN7UUYaEDa9HEKafK25+sLc0Gc= 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/bkielbasa/cyclop v1.2.3 h1:faIVMIGDIANuGPWH031CZJTi2ymOQBULs9H21HSMa5w= @@ -346,18 +275,12 @@ github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdn github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M= github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= -github.com/bluesky-social/indigo v0.0.0-20260106221649-6fcd9317e725 h1:gfrLAhE6PHun4MDypO/5hpnaHPd9Dbe9+JxZL0gC4ic= -github.com/bluesky-social/indigo v0.0.0-20260106221649-6fcd9317e725/go.mod h1:KIy0FgNQacp4uv2Z7xhNkV3qZiUSGuRky97s7Pa4v+o= github.com/bluesky-social/indigo v0.0.0-20260128215158-cf0fe7589346 h1:FfYnKHM+w5EDHFMBwTgMUpi3DLVxbMa2MRr0kI4Iqw0= github.com/bluesky-social/indigo v0.0.0-20260128215158-cf0fe7589346/go.mod h1:KIy0FgNQacp4uv2Z7xhNkV3qZiUSGuRky97s7Pa4v+o= github.com/bombsimon/wsl/v4 v4.7.0 h1:1Ilm9JBPRczjyUs6hvOPKvd7VL1Q++PL8M0SXBDf+jQ= github.com/bombsimon/wsl/v4 v4.7.0/go.mod h1:uV/+6BkffuzSAVYD+yGyld1AChO7/EuLrCF/8xTiapg= -github.com/bombsimon/wsl/v5 v5.3.0 h1:nZWREJFL6U3vgW/B1lfDOigl+tEF6qgs6dGGbFeR0UM= -github.com/bombsimon/wsl/v5 v5.3.0/go.mod h1:Gp8lD04z27wm3FANIUPZycXp+8huVsn0oxc+n4qfV9I= github.com/bombsimon/wsl/v5 v5.6.0 h1:4z+/sBqC5vUmSp1O0mS+czxwH9+LKXtCWtHH9rZGQL8= github.com/bombsimon/wsl/v5 v5.6.0/go.mod h1:Uqt2EfrMj2NV8UGoN1f1Y3m0NpUVCsUdrNCdet+8LvU= -github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8bttX0bfZGmcGkjz7DLQXhAn3DNd3T0ous= -github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c= github.com/breml/bidichk v0.3.3 h1:WSM67ztRusf1sMoqH6/c4OBCUlRVTKq+CbSeo0R17sE= github.com/breml/bidichk v0.3.3/go.mod h1:ISbsut8OnjB367j5NseXEGGgO/th206dVa427kR8YTE= github.com/breml/errchkjson v0.4.1 h1:keFSS8D7A2T0haP9kzZTi7o26r7kE3vymjZNeNDRDwg= @@ -392,7 +315,6 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3 github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= -github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261 h1:6/yVvBsKeAw05IUj4AzvrxaCnDjN4nUqKjW9+w5wixg= github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -406,18 +328,12 @@ github.com/charmbracelet/keygen v0.5.4 h1:XQYgf6UEaTGgQSSmiPpIQ78WfseNQp4Pz8N/c1 github.com/charmbracelet/keygen v0.5.4/go.mod h1:t4oBRr41bvK7FaJsAaAQhhkUuHslzFXVjOBwA55CZNM= github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= -github.com/charmbracelet/ultraviolet v0.0.0-20251217160852-6b0c0e26fad9 h1:dsDBRP9Iyco0EjVpCsAzl8VGbxk04fP3sa80ySJSAZw= -github.com/charmbracelet/ultraviolet v0.0.0-20251217160852-6b0c0e26fad9/go.mod h1:Ns3cOzzY9hEFFeGxB6VpfgRnqOJZJFhQAPfRxPqflQs= github.com/charmbracelet/ultraviolet v0.0.0-20260123224754-f434aada8dbd h1:TIjV5jgzCdmhE/cWl/e8pmOaTns/Ah4SoUFv4PTFlC0= github.com/charmbracelet/ultraviolet v0.0.0-20260123224754-f434aada8dbd/go.mod h1:2I+V4H3xExk9BZ3W2UnU/RAkJPYzBOkY7RzEe7tH1vo= -github.com/charmbracelet/x/ansi v0.11.3 h1:6DcVaqWI82BBVM/atTyq6yBoRLZFBsnoDoX9GCu2YOI= -github.com/charmbracelet/x/ansi v0.11.3/go.mod h1:yI7Zslym9tCJcedxz5+WBq+eUGMJT0bM06Fqy1/Y4dI= github.com/charmbracelet/x/ansi v0.11.4 h1:6G65PLu6HjmE858CnTUQY1LXT3ZUWwfvqEROLF8vqHI= github.com/charmbracelet/x/ansi v0.11.4/go.mod h1:/5AZ+UfWExW3int5H5ugnsG/PWjNcSQcwYsHBlPFQN4= github.com/charmbracelet/x/cellbuf v0.0.14 h1:iUEMryGyFTelKW3THW4+FfPgi4fkmKnnaLOXuc+/Kj4= github.com/charmbracelet/x/cellbuf v0.0.14/go.mod h1:P447lJl49ywBbil/KjCk2HexGh4tEY9LH0/1QrZZ9rA= -github.com/charmbracelet/x/exp/charmtone v0.0.0-20251215102626-e0db08df7383 h1:xGojlO6kHCDB1k6DolME79LG0u90TzVd8atGhmxFRIo= -github.com/charmbracelet/x/exp/charmtone v0.0.0-20251215102626-e0db08df7383/go.mod h1:nsExn0DGyX0lh9LwLHTn2Gg+hafdzfSXnC+QmEJTZFY= github.com/charmbracelet/x/exp/charmtone v0.0.0-20260127155452-b72a9a918687 h1:YSLsz8YEuMxY9SXJSKpjBWmOxjjjP4xEX2hZ56BP/2s= github.com/charmbracelet/x/exp/charmtone v0.0.0-20260127155452-b72a9a918687/go.mod h1:nsExn0DGyX0lh9LwLHTn2Gg+hafdzfSXnC+QmEJTZFY= github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f h1:pk6gmGpCE7F3FcjaOEKYriCvpmIN4+6OS/RD0vm4uIA= @@ -430,34 +346,20 @@ github.com/charmbracelet/x/windows v0.2.2 h1:IofanmuvaxnKHuV04sC0eBy/smG6kIKrWG2 github.com/charmbracelet/x/windows v0.2.2/go.mod h1:/8XtdKZzedat74NQFn0NGlGL4soHB0YQZrETF96h75k= github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 h1:krfRl01rzPzxSxyLyrChD+U+MzsBXbm0OwYYB67uF+4= github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589/go.mod h1:OuDyvmLnMCwa2ep4Jkm6nyA0ocJuZlGyk2gGseVzERM= -github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= -github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= -github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= -github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/ckaznocha/intrange v0.3.1 h1:j1onQyXvHUsPWujDH6WIjhyH26gkRt/txNlV7LspvJs= github.com/ckaznocha/intrange v0.3.1/go.mod h1:QVepyz1AkUoFQkpEqksSYpNpUo3c5W7nWh/s6SHIJJk= -github.com/clipperhouse/displaywidth v0.6.1 h1:/zMlAezfDzT2xy6acHBzwIfyu2ic0hgkT83UX5EY2gY= -github.com/clipperhouse/displaywidth v0.6.1/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o= github.com/clipperhouse/displaywidth v0.8.0 h1:/z8v+H+4XLluJKS7rAc7uHZTalT5Z+1430ld3lePSRI= github.com/clipperhouse/displaywidth v0.8.0/go.mod h1:UpOXiIKep+TohQYwvAAM/VDU8v3Z5rnWTxiwueR0XvQ= github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs= github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= -github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4= -github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= github.com/clipperhouse/uax29/v2 v2.4.0 h1:RXqE/l5EiAbA4u97giimKNlmpvkmz+GrBVTelsoXy9g= github.com/clipperhouse/uax29/v2 v2.4.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= -github.com/cloudflare/circl v1.6.2 h1:hL7VBpHHKzrV5WTfHCaBsgx/HGbBYlgrwvNXEVDYYsQ= -github.com/cloudflare/circl v1.6.2/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4= github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8= github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4= -github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w= -github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI= github.com/cncf/xds/go v0.0.0-20260121142036-a486691bba94 h1:kkHPnzHm5Ln7WA0XYjrr2ITA0l9Vs6H++Ni//P+SZso= github.com/cncf/xds/go v0.0.0-20260121142036-a486691bba94/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4= -github.com/codesphere-cloud/cs-go v0.16.1 h1:Pa3UzfeU7G1JMNoVMMd2uiIYX4NyYY2bJM0EdT1Xncw= -github.com/codesphere-cloud/cs-go v0.16.1/go.mod h1:2jJuJ5hYdbdeHlm7Ks0xkd8qvFt1gLAbpVTx2LFTIyQ= github.com/codesphere-cloud/cs-go v0.16.2 h1:AtS4HKPngpYfB4uj28vo/eq+qPWXICjLmx9R0G0a2rQ= github.com/codesphere-cloud/cs-go v0.16.2/go.mod h1:VvEsEx7dOlLOCqRFexl0ovuoDB9/N/fQQmMhg5wyE4Q= github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= @@ -468,8 +370,6 @@ github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151X github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= -github.com/containerd/stargz-snapshotter/estargz v0.18.1 h1:cy2/lpgBXDA3cDKSyEfNOFMA/c10O1axL69EU7iirO8= -github.com/containerd/stargz-snapshotter/estargz v0.18.1/go.mod h1:ALIEqa7B6oVDsrF37GkGN20SuvG/pIMm7FwP7ZmRb0Q= github.com/containerd/stargz-snapshotter/estargz v0.18.2 h1:yXkZFYIzz3eoLwlTUZKz2iQ4MrckBxJjkmD16ynUTrw= github.com/containerd/stargz-snapshotter/estargz v0.18.2/go.mod h1:XyVU5tcJ3PRpkA9XS2T5us6Eg35yM0214Y+wvrZTBrY= github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc= @@ -479,7 +379,6 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= github.com/cpuguy83/go-md2man/v2 v2.0.7/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/creativeprojects/go-selfupdate v1.5.2 h1:3KR3JLrq70oplb9yZzbmJ89qRP78D1AN/9u+l3k0LJ4= @@ -504,8 +403,6 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0= github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE= -github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8= -github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY= github.com/denis-tingaikin/go-header v1.0.0 h1:QIwZWb3jLC6pOp9NEFldiD8raqRmCE/n0VUdZKW32x8= github.com/denis-tingaikin/go-header v1.0.0/go.mod h1:NT3qKwqsXQYp8WHVgkwxL49qB5jsRmdr9dGQCDfpmZ0= github.com/dghubble/go-twitter v0.0.0-20221104224141-912508c3888b h1:XQu6o3AwJx/jsg9LZ41uIeUdXK5be099XFfFn6H9ikk= @@ -529,16 +426,12 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr 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/docker/cli v29.2.0-rc.1.0.20251223174200-874b831c0e49+incompatible h1:qzsQ4KSWZG5dBSDv3XFBCvBcy6/jC1odDTwe2SbMBh0= -github.com/docker/cli v29.2.0-rc.1.0.20251223174200-874b831c0e49+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v29.2.0+incompatible h1:9oBd9+YM7rxjZLfyMGxjraKBKE4/nVyvVfN4qNl9XRM= github.com/docker/cli v29.2.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.9.4 h1:76ItO69/AP/V4yT9V4uuuItG0B1N8hvt0T0c0NN/DzI= -github.com/docker/docker-credential-helpers v0.9.4/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c= github.com/docker/docker-credential-helpers v0.9.5 h1:EFNN8DHvaiK8zVqFA2DT6BjXE0GzfLOZ38ggPTKePkY= github.com/docker/docker-credential-helpers v0.9.5/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c= github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= @@ -547,8 +440,6 @@ github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQ github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/dprotaso/go-yit v0.0.0-20250513223454-5ece0c5aa76c h1:EMwsP/vaHQDLhAX1kNIng5mHEhg+CkS18m0AL825n6U= -github.com/dprotaso/go-yit v0.0.0-20250513223454-5ece0c5aa76c/go.mod h1:lHwJo6jMevQL9tNpW6vLyhkK13bYHBcoh9tUakMhbnE= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/earthboundkid/versioninfo/v2 v2.24.1 h1:SJTMHaoUx3GzjjnUO1QzP3ZXK6Ee/nbWyCm58eY3oUg= @@ -589,8 +480,6 @@ github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw= github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= -github.com/ghostiam/protogetter v0.3.18 h1:yEpghRGtP9PjKvVXtEzGpYfQj1Wl/ZehAfU6fr62Lfo= -github.com/ghostiam/protogetter v0.3.18/go.mod h1:FjIu5Yfs6FT391m+Fjp3fbAYJ6rkL/J6ySpZBfnODuI= github.com/ghostiam/protogetter v0.3.19 h1:yGoXYWL66F41FZqwEvjSnS3ghbUhKbpJgzKpmOOMovU= github.com/ghostiam/protogetter v0.3.19/go.mod h1:FjIu5Yfs6FT391m+Fjp3fbAYJ6rkL/J6ySpZBfnODuI= github.com/github/smimesign v0.2.0 h1:Hho4YcX5N1I9XNqhq0fNx0Sts8MhLonHd+HRXVGNjvk= @@ -706,8 +595,6 @@ github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQi github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ= github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus= github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= -github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= -github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-xmlfmt/xmlfmt v1.1.3 h1:t8Ey3Uy7jDSEisW2K3somuMKIpzktkWptA0iFCnRUWY= @@ -726,22 +613,17 @@ github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw= github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0= 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 v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.5.0/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.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= -github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= 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/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/asciicheck v0.5.0 h1:jczN/BorERZwK8oiFBOGvlGPknhvq0bjnysTj4nUfo0= github.com/golangci/asciicheck v0.5.0/go.mod h1:5RMNAInbNFw2krqN6ibBxN/zfRFa9S6tA1nPdM0l8qQ= github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 h1:WUvBfQL6EW/40l6OmeSBYQJNSif4O11+bmWEz+C7FYw= @@ -750,8 +632,6 @@ github.com/golangci/go-printf-func-name v0.1.1 h1:hIYTFJqAGp1iwoIfsNTpoq1xZAarog github.com/golangci/go-printf-func-name v0.1.1/go.mod h1:Es64MpWEZbh0UBtTAICOZiB+miW53w/K9Or/4QogJss= github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d h1:viFft9sS/dxoYY0aiOTsLKO2aZQAPT4nlQCsimGcSGE= github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d/go.mod h1:ivJ9QDg0XucIkmwhzCDsqcnxxlDStoTl89jDMIoNxKY= -github.com/golangci/gofmt v0.0.0-20251215234548-e7be49a5ab4d h1:7Vk1kMg7H+H6YVOQlJj1Eac4TgpylbOXOQp8hJTTNgo= -github.com/golangci/gofmt v0.0.0-20251215234548-e7be49a5ab4d/go.mod h1:otKf/6iIqxE63jjoqGYpkwGAJmMyXS1HToujXO7T5CQ= github.com/golangci/golangci-lint/v2 v2.8.0 h1:wJnr3hJWY3eVzOUcfwbDc2qbi2RDEpvLmQeNFaPSNYA= github.com/golangci/golangci-lint/v2 v2.8.0/go.mod h1:xl+HafQ9xoP8rzw0z5AwnO5kynxtb80e8u02Ej/47RI= github.com/golangci/golines v0.14.0 h1:xt9d3RKBjhasA3qpoXs99J2xN2t6eBlpLHt0TrgyyXc= @@ -792,8 +672,6 @@ github.com/google/ko v0.18.1 h1:F2WDFIi/eZe5thmFCuk/uH0eVr7ilWCThl+UoTHEKSk= github.com/google/ko v0.18.1/go.mod h1:YjJWJhmZ7prVtHm/LFfwqeIAIhcyr/gxtztI8+Jrxl4= github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= -github.com/google/pprof v0.0.0-20260106004452-d7df1bf2cac7 h1:kmPAX+IJBcUAFTddx2+xC0H7sk2U9ijIIxZLLrPLNng= -github.com/google/pprof v0.0.0-20260106004452-d7df1bf2cac7/go.mod h1:67FPmZWbr+KDT/VlpWtw6sO9XSjpJmLuHpoLmWiTGgY= github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc= github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= @@ -825,8 +703,6 @@ github.com/goreleaser/fileglob v1.4.0 h1:Y7zcUnzQjT1gbntacGAkIIfLv+OwojxTXBFxjSF github.com/goreleaser/fileglob v1.4.0/go.mod h1:1pbHx7hhmJIxNZvm6fi6WVrnP0tndq6p3ayWdLn1Yf8= github.com/goreleaser/goreleaser/v2 v2.13.3 h1:S8d13YgzzFXxoUJ9NJInuyq3lPNCXTcuW8wSvM+rXnQ= github.com/goreleaser/goreleaser/v2 v2.13.3/go.mod h1:Rj+yhhXrO6WHc6cNh1GggpxzhhHXv9lczL5M4cSV3oA= -github.com/goreleaser/nfpm/v2 v2.44.1 h1:g+QNjkEx+C2Zu8dB48t9da/VfV0CWS5TMjxT8HG1APY= -github.com/goreleaser/nfpm/v2 v2.44.1/go.mod h1:drIYLqkla9SaOLbSnaFOmSIv5LXGfhHcbK54st97b4s= github.com/goreleaser/nfpm/v2 v2.44.2 h1:h1DLjxoxlA85qru1IsRrqbJw51DLJ64kAiWmlPQ3zaA= github.com/goreleaser/nfpm/v2 v2.44.2/go.mod h1:O0h9bB68D39NTnM9rSOJhVCYxQk7sU8i04q2bzczFdk= github.com/goreleaser/quill v0.0.0-20251224035235-ab943733386f h1:2HQF/pifDK7XnmVhQi3OecdUcHLOaXIKVKscW8qKzCk= @@ -849,8 +725,6 @@ github.com/gostaticanalysis/testutil v0.5.0 h1:Dq4wT1DdTwTGCQQv3rl3IvD5Ld0E6HiY+ github.com/gostaticanalysis/testutil v0.5.0/go.mod h1:OLQSbuM6zw2EvCcXTz1lVq5unyoNft372msDY0nY5Hs= 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/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.6 h1:1ufTZkFXIQQ9EmgPjcIPIi2krfxG03lQ8OLoY1MJ3UM= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.6/go.mod h1:lW34nIZuQ8UDPdkon5fmfp2l3+ZkQ2me/+oecHYLOII= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -894,14 +768,8 @@ github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef h1:A9HsByNhogrvm9cWb github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= -github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -github.com/ianlancetaylor/demangle v0.0.0-20250417193237-f615e6bd150b h1:ogbOPx86mIhFy764gGkqnkFC8m5PJA7sPzlk9ppLVQA= -github.com/ianlancetaylor/demangle v0.0.0-20250417193237-f615e6bd150b/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= github.com/in-toto/attestation v1.1.2 h1:MBFn6lsMq6dptQZJBhalXTcWMb/aJy3V+GX3VYj/V1E= github.com/in-toto/attestation v1.1.2/go.mod h1:gYFddHMZj3DiQ0b62ltNi1Vj5rC879bTmBbrv9CRHpM= -github.com/in-toto/in-toto-golang v0.9.0 h1:tHny7ac4KgtsfrG6ybU8gVOZux2H8jN05AXJ9EBM1XU= -github.com/in-toto/in-toto-golang v0.9.0/go.mod h1:xsBVrVsHNsB61++S6Dy2vWosKhuA3lUTQd+eF9HdeMo= github.com/in-toto/in-toto-golang v0.10.0 h1:+s2eZQSK3WmWfYV85qXVSBfqgawi/5L02MaqA4o/tpM= github.com/in-toto/in-toto-golang v0.10.0/go.mod h1:wjT4RiyFlLWCmLUJjwB8oZcjaq7HA390aMJcD3xXgmg= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -910,8 +778,6 @@ github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcI github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.34.0 h1:pMP9bAsTs4xVh8R0ZmxIWviV7kjDa60U24QrlGgHb1g= -github.com/ipfs/boxo v0.34.0/go.mod h1:kzdH/ewDybtO3+M8MCVkpwnIIc/d2VISX95DFrY4vQA= github.com/ipfs/boxo v0.36.0 h1:DarrMBM46xCs6GU6Vz+AL8VUyXykqHAqZYx8mR0Oics= github.com/ipfs/boxo v0.36.0/go.mod h1:92hnRXfP5ScKEIqlq9Ns7LR1dFXEVADKWVGH0fjk83k= github.com/ipfs/go-block-format v0.2.3 h1:mpCuDaNXJ4wrBJLrtEaGFGXkferrw5eqVvzaHhtFKQk= @@ -935,8 +801,6 @@ github.com/ipfs/go-ipld-format v0.6.3/go.mod h1:74ilVN12NXVMIV+SrBAyC05UJRk0jVvG github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8= github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo= github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= -github.com/ipfs/go-log/v2 v2.9.0 h1:l4b06AwVXwldIzbVPZy5z7sKp9lHFTX0KWfTBCtHaOk= -github.com/ipfs/go-log/v2 v2.9.0/go.mod h1:UhIYAwMV7Nb4ZmihUxfIRM2Istw/y9cAk3xaK+4Zs2c= github.com/ipfs/go-log/v2 v2.9.1 h1:3JXwHWU31dsCpvQ+7asz6/QsFJHqFr4gLgQ0FWteujk= github.com/ipfs/go-log/v2 v2.9.1/go.mod h1:evFx7sBiohUN3AG12mXlZBw5hacBQld3ZPHrowlJYoo= github.com/ipfs/go-metrics-interface v0.3.0 h1:YwG7/Cy4R94mYDUuwsBfeziJCVm9pBMJ6q/JR9V40TU= @@ -967,8 +831,6 @@ github.com/jjti/go-spancheck v0.6.5 h1:lmi7pKxa37oKYIMScialXUK6hP3iY5F1gu+mLBPgY github.com/jjti/go-spancheck v0.6.5/go.mod h1:aEogkeatBrbYsyW6y5TgDfihCulDYciL1B7rG2vSsrU= github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 h1:liMMTbpW34dhU4az1GN0pTPADwNmvoRSeoZ6PItiqnY= github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -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/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE= github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= @@ -987,8 +849,6 @@ github.com/kisielk/errcheck v1.9.0/go.mod h1:kQxWMMVZgIkDq7U8xtG/n2juOjbLgZtedi0 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkHAIKE/contextcheck v1.1.6 h1:7HIyRcnyzxL9Lz06NGhiKvenXq7Zw6Q0UQu/ttjfJCE= github.com/kkHAIKE/contextcheck v1.1.6/go.mod h1:3dDbMRNBFaq8HFXWC1JyvDSPm43CmE6IuHam8Wr0rkg= -github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= -github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= @@ -1007,8 +867,6 @@ github.com/knadh/koanf/providers/posflag v1.0.1 h1:EnMxHSrPkYCFnKgBUl5KBgrjed8gV github.com/knadh/koanf/providers/posflag v1.0.1/go.mod h1:3Wn3+YG3f4ljzRyCUgIwH7G0sZ1pMjCOsNBovrbKmAk= github.com/knadh/koanf/providers/structs v1.0.0 h1:DznjB7NQykhqCar2LvNug3MuxEQsZ5KvfgMbio+23u4= github.com/knadh/koanf/providers/structs v1.0.0/go.mod h1:kjo5TFtgpaZORlpoJqcbeLowM2cINodv8kX+oFAeQ1w= -github.com/knadh/koanf/v2 v2.3.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= -github.com/knadh/koanf/v2 v2.3.0/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28= github.com/knadh/koanf/v2 v2.3.2 h1:Ee6tuzQYFwcZXQpc2MiVeC6qHMandf5SMUJJNoFp/c4= github.com/knadh/koanf/v2 v2.3.2/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= @@ -1044,18 +902,12 @@ github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84Yrj github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= github.com/letsencrypt/boulder v0.20260105.0 h1:P94haPlN1xm8MhIHSXbUu1cA0t0EoMhXQyMz/jLwR34= github.com/letsencrypt/boulder v0.20260105.0/go.mod h1:FWHD4EclPHIQ1y2AKEXyySrM3eKiwEyGzcwcupVEFyE= -github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= -github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lithammer/shortuuid v3.0.0+incompatible h1:NcD0xWW/MZYXEHa6ITy6kaXN5nwm/V115vj2YXfhS0w= github.com/lithammer/shortuuid v3.0.0+incompatible/go.mod h1:FR74pbAuElzOUuenUHTK2Tciko1/vKuIKS9dSkDrA4w= github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/lyft/protoc-gen-star/v2 v2.0.4-0.20230330145011-496ad1ac90a4 h1:sIXJOMrYnQZJu7OB7ANSF4MYri2fTEGIsRLz6LwI4xE= -github.com/lyft/protoc-gen-star/v2 v2.0.4-0.20230330145011-496ad1ac90a4/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= github.com/macabu/inamedparam v0.2.0 h1:VyPYpOc10nkhI2qeNUdh3Zket4fcZjEWe35poddBCpE= github.com/macabu/inamedparam v0.2.0/go.mod h1:+Pee9/YfGe5LJ62pYXqB89lJ+0k5bsR8Wgz/C0Zlq3U= -github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo= -github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/manuelarte/embeddedstructfieldcheck v0.4.0 h1:3mAIyaGRtjK6EO9E73JlXLtiy7ha80b2ZVGyacxgfww= @@ -1086,12 +938,8 @@ github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byF github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE= github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A= -github.com/mgechev/dots v1.0.0 h1:o+4OJ3OjWzgQHGJXKfJ8rbH4dqDugu5BiEy84nxg0k4= -github.com/mgechev/dots v1.0.0/go.mod h1:rykuMydC9t3wfkM+ccYH3U3ss03vZGg6h3hmOznXLH0= github.com/mgechev/revive v1.13.0 h1:yFbEVliCVKRXY8UgwEO7EOYNopvjb1BFbmYqm9hZjBM= github.com/mgechev/revive v1.13.0/go.mod h1:efJfeBVCX2JUumNQ7dtOLDja+QKj9mYGgEZA7rt5u+0= -github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= -github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= @@ -1156,14 +1004,10 @@ github.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhK github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs= github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= -github.com/nunnatsa/ginkgolinter v0.21.2 h1:khzWfm2/Br8ZemX8QM1pl72LwM+rMeW6VUbQ4rzh0Po= -github.com/nunnatsa/ginkgolinter v0.21.2/go.mod h1:GItSI5fw7mCGLPmkvGYrr1kEetZe7B593jcyOpyabsY= github.com/nunnatsa/ginkgolinter v0.22.0 h1:o9g7JN6efdBxAHhejvPkodEjWsOBze9zDnPePsvC/Qg= github.com/nunnatsa/ginkgolinter v0.22.0/go.mod h1:zIFAk36fhcHQIiYOGXLbrGTXz7cvpufhRYem6ToCVnY= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.27.5 h1:ZeVgZMx2PDMdJm/+w5fE/OyG6ILo1Y3e+QX4zSR0zTE= github.com/onsi/ginkgo/v2 v2.27.5/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= github.com/onsi/gomega v1.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q= @@ -1185,7 +1029,6 @@ github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJ github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= -github.com/pborman/getopt v0.0.0-20180811024354-2b5b3bfb099b h1:K1wa7ads2Bu1PavI6LfBRMYSy6Zi+Rky0OhWBfrmkmY= github.com/pborman/getopt v0.0.0-20180811024354-2b5b3bfb099b/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= @@ -1195,7 +1038,6 @@ github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0= github.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM= 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= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -1220,36 +1062,26 @@ github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEo github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM= github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= -github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30= github.com/quasilyte/go-ruleguard v0.4.5 h1:AGY0tiOT5hJX9BTdx/xBdoCubQUAE2grkqY2lSwvZcA= github.com/quasilyte/go-ruleguard v0.4.5/go.mod h1:Vl05zJ538vcEEwu16V/Hdu7IYZWyKSwIy4c88Ro1kRE= -github.com/quasilyte/go-ruleguard/dsl v0.3.0/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/quasilyte/go-ruleguard/dsl v0.3.23 h1:lxjt5B6ZCiBeeNO8/oQsegE6fLeCzuMRoVWSkXC4uvY= github.com/quasilyte/go-ruleguard/dsl v0.3.23/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= -github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1/go.mod h1:7JTjp89EGyU1d6XfBiXihJNG37wB2VRkd125Q1u7Plc= -github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71 h1:CNooiryw5aisadVfzneSZPswRWvnVW8hF1bS/vo8ReI= -github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50= github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo= github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl980XxGFEZSS6KlBGIV0diGdySzxATTWoqaU= github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= -github.com/qur/ar v0.0.0-20130629153254-282534b91770 h1:A6sXY4zAECrW5Obx41PVMGr4kOw1rd1kmwcHa5M0dTg= -github.com/qur/ar v0.0.0-20130629153254-282534b91770/go.mod h1:SjlYv2m9lpV0UW6K7lDqVJwEIIvSjaHbGk7nIfY8Hxw= github.com/raeperd/recvcheck v0.2.0 h1:GnU+NsbiCqdC2XX5+vMZzP+jAJC5fht7rcVTAhX74UI= github.com/raeperd/recvcheck v0.2.0/go.mod h1:n04eYkwIR0JbgD73wT8wL4JjPC3wm0nFtzBnWNocnYU= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= 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/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= -github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= -github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -1275,8 +1107,6 @@ github.com/sassoftware/relic v7.2.1+incompatible h1:Pwyh1F3I0r4clFJXkSI8bOyJINGq github.com/sassoftware/relic v7.2.1+incompatible/go.mod h1:CWfAxv73/iLZ17rbyhIEq3K9hs5w6FpNMdUT//qR+zk= github.com/sassoftware/relic/v7 v7.6.2 h1:rS44Lbv9G9eXsukknS4mSjIAuuX+lMq/FnStgmZlUv4= github.com/sassoftware/relic/v7 v7.6.2/go.mod h1:kjmP0IBVkJZ6gXeAu35/KCEfca//+PKM6vTAsyDPY+k= -github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e h1:7q6NSFZDeGfvvtIRwBrU/aegEYJYmvev0cHAwo17zZQ= github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e/go.mod h1:DkpGd78rljTxKAnTDPFqXSGxvETQnJyuSOQwsHycqfs= github.com/secure-systems-lab/go-securesystemslib v0.10.0 h1:l+H5ErcW0PAehBNrBxoGv1jjNpGYdZ9RcheFkB2WI14= @@ -1299,8 +1129,6 @@ github.com/sigstore/protobuf-specs v0.5.0 h1:F8YTI65xOHw70NrvPwJ5PhAzsvTnuJMGLkA github.com/sigstore/protobuf-specs v0.5.0/go.mod h1:+gXR+38nIa2oEupqDdzg4qSBT0Os+sP7oYv6alWewWc= github.com/sigstore/rekor v1.5.0 h1:rL7SghHd5HLCtsCrxw0yQg+NczGvM75EjSPPWuGjaiQ= github.com/sigstore/rekor v1.5.0/go.mod h1:D7JoVCUkxwQOpPDNYeu+CE8zeBC18Y5uDo6tF8s2rcQ= -github.com/sigstore/rekor-tiles/v2 v2.0.1 h1:1Wfz15oSRNGF5Dzb0lWn5W8+lfO50ork4PGIfEKjZeo= -github.com/sigstore/rekor-tiles/v2 v2.0.1/go.mod h1:Pjsbhzj5hc3MKY8FfVTYHBUHQEnP0ozC4huatu4x7OU= github.com/sigstore/rekor-tiles/v2 v2.1.0 h1:lSxhMwVYkMsCok2rFKU3eRJXz7ppTkLEVjUnH+g8aZY= github.com/sigstore/rekor-tiles/v2 v2.1.0/go.mod h1:qRw4VXl35azi8ENjSWbdmGtzdviLd7H08fDcp5C+97Y= github.com/sigstore/sigstore v1.10.4 h1:ytOmxMgLdcUed3w1SbbZOgcxqwMG61lh1TmZLN+WeZE= @@ -1315,13 +1143,9 @@ github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.10.3 h1:AVWs0E6rVZMoDTE0Iy github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.10.3/go.mod h1:nxQYF0D6u7mVtiP1azj1YVDIrtz7S0RYCVTqUG8IcCk= github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.10.3 h1:lJSdaC/aOlFHlvqmmV696n1HdXLMLEKGwpNZMV0sKts= github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.10.3/go.mod h1:b2rV9qPbt/jv/Yy75AIOZThP8j+pe1ZdLEjOwmjPdoA= -github.com/sigstore/timestamp-authority/v2 v2.0.3 h1:sRyYNtdED/ttLCMdaYnwpf0zre1A9chvjTnCmWWxN8Y= -github.com/sigstore/timestamp-authority/v2 v2.0.3/go.mod h1:mDaHxkt3HmZYoIlwYj4QWo0RUr7VjYU52aVO5f5Qb3I= github.com/sigstore/timestamp-authority/v2 v2.0.4 h1:65IBa4LUeFWDQu9hiTt5lBpi/F5jonJWZtH6VLn4InU= github.com/sigstore/timestamp-authority/v2 v2.0.4/go.mod h1:EXJLiMDBqRPlzC02hPiFSiYTCqSuUpU68a4vr0DFePM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE= @@ -1360,8 +1184,6 @@ github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YE github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= github.com/stbenjam/no-sprintf-host-port v0.3.1 h1:AyX7+dxI4IdLBPtDbsGAyqiTSLpCP9hWRrXQDU4Cm/g= github.com/stbenjam/no-sprintf-host-port v0.3.1/go.mod h1:ODbZesTCHMVKthBHskvUUexdcNHAQRXk9NpSsL8p/HQ= -github.com/streadway/amqp v1.1.0 h1:py12iX8XSyI7aN/3dUT8DFIDJazNJsVJdxNVEpnQTZM= -github.com/streadway/amqp v1.1.0/go.mod h1:WYSrTEYHOXHd0nwFeUXAe2G2hRnQT+deZJJf88uS9Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -1371,12 +1193,10 @@ github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+Q github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2/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/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= @@ -1400,8 +1220,6 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= -github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 h1:9LPGD+jzxMlnk5r6+hJnar67cgpDIz/iyD+rfl5r2Vk= -github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67/go.mod h1:mkjARE7Yr8qU23YcGMSALbIxTQ9r9QBVahQOBRfU460= github.com/timakin/bodyclose v0.0.0-20260129054331-73d1f95b84b4 h1:SiHe5XLTn9sFWJ5pBwJ5FN/4j34q9ZlOAD//kMoMYp0= github.com/timakin/bodyclose v0.0.0-20260129054331-73d1f95b84b4/go.mod h1:sDHLK7rb/59v/ZxZ7KtymgcoxuUMxjXq8gtu9VMOK8M= github.com/timonwong/loggercheck v0.11.0 h1:jdaMpYBl+Uq9mWPXv1r8jc5fC3gyXx4/WGwTnnNKn4M= @@ -1410,9 +1228,8 @@ github.com/tink-crypto/tink-go-awskms/v2 v2.1.0 h1:N9UxlsOzu5mttdjhxkDLbzwtEecuX github.com/tink-crypto/tink-go-awskms/v2 v2.1.0/go.mod h1:PxSp9GlOkKL9rlybW804uspnHuO9nbD98V/fDX4uSis= github.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0 h1:3B9i6XBXNTRspfkTC0asN5W0K6GhOSgcujNiECNRNb0= github.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0/go.mod h1:jY5YN2BqD/KSCHM9SqZPIpJNG/u3zwfLXHgws4x2IRw= -github.com/tink-crypto/tink-go-hcvault/v2 v2.3.0 h1:6nAX1aRGnkg2SEUMwO5toB2tQkP0Jd6cbmZ/K5Le1V0= -github.com/tink-crypto/tink-go-hcvault/v2 v2.3.0/go.mod h1:HOC5NWW1wBI2Vke1FGcRBvDATkEYE7AUDiYbXqi2sBw= github.com/tink-crypto/tink-go-hcvault/v2 v2.4.0 h1:j+S+WKBQ5ya26A5EM/uXoVe+a2IaPQN8KgBJZ22cJ+4= +github.com/tink-crypto/tink-go-hcvault/v2 v2.4.0/go.mod h1:OCKJIujnTzDq7f+73NhVs99oA2c1TR6nsOpuasYM6Yo= github.com/tink-crypto/tink-go/v2 v2.6.0 h1:+KHNBHhWH33Vn+igZWcsgdEPUxKwBMEe0QC60t388v4= github.com/tink-crypto/tink-go/v2 v2.6.0/go.mod h1:2WbBA6pfNsAfBwDCggboaHeB2X29wkU8XHtGwh2YIk8= github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0= @@ -1423,8 +1240,6 @@ github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+ github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= github.com/tomnomnom/linkheader v0.0.0-20250811210735-e5fe3b51442e h1:tD38/4xg4nuQCASJ/JxcvCHNb46w0cdAaJfkzQOO1bA= github.com/tomnomnom/linkheader v0.0.0-20250811210735-e5fe3b51442e/go.mod h1:krvJ5AY/MjdPkTeRgMYbIDhbbbVvnPQPzsIsDJO8xrY= -github.com/transparency-dev/formats v0.0.0-20251208091212-1378f9e1b1b7 h1:PwfIAvobqihWBi1/KIsw0IzTEJ89rYJqmXfzmqacySw= -github.com/transparency-dev/formats v0.0.0-20251208091212-1378f9e1b1b7/go.mod h1:mQ5ASe7MNPT+yRc47hLguwsNdE2Go0mT6piyzUO+ynw= github.com/transparency-dev/formats v0.0.0-20260126105629-a1e81f2894be h1:JfUkmUSwqyTs2ziQDQN45dQhxM+t+XCDLPiw2VtF12k= github.com/transparency-dev/formats v0.0.0-20260126105629-a1e81f2894be/go.mod h1:d2FibUOHfCMdCe/+/rbKt1IPLBbPTDfwj46kt541/mU= github.com/transparency-dev/merkle v0.0.2 h1:Q9nBoQcZcgPamMkGn7ghV8XiTZ/kRxn1yCG81+twTK4= @@ -1463,8 +1278,6 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xen0n/gosmopolitan v1.3.0 h1:zAZI1zefvo7gcpbCOrPSHJZJYA9ZgLfJqtKzZ5pHqQM= github.com/xen0n/gosmopolitan v1.3.0/go.mod h1:rckfr5T6o4lBtM1ga7mLGKZmLxswUoH1zxHgNXOsEt4= -github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= -github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= @@ -1498,8 +1311,6 @@ gitlab.com/bosi/decorder v0.4.2 h1:qbQaV3zgwnBZ4zPMhGLW4KZe7A7NwxEhJx39R3shffo= gitlab.com/bosi/decorder v0.4.2/go.mod h1:muuhHoaJkA9QLcYHq4Mj8FJUwDZ+EirSHRiaTcTf6T8= gitlab.com/digitalxero/go-conventional-commit v1.0.7 h1:8/dO6WWG+98PMhlZowt/YjuiKhqhGlOCwlIV8SqqGh8= gitlab.com/digitalxero/go-conventional-commit v1.0.7/go.mod h1:05Xc2BFsSyC5tKhK0y+P3bs0AwUtNuTp+mTpbCU/DZ0= -gitlab.com/gitlab-org/api/client-go v1.11.0 h1:L+qzw4kiCf3jKdKHQAwiqYKITvzBrW/tl8ampxNLlv0= -gitlab.com/gitlab-org/api/client-go v1.11.0/go.mod h1:adtVJ4zSTEJ2fP5Pb1zF4Ox1OKFg0MH43yxpb0T0248= gitlab.com/gitlab-org/api/client-go v1.24.0 h1:lTTuEw2oA3Ac5UOqLJ80tSusDclgq97zuqCTnXqlfHw= gitlab.com/gitlab-org/api/client-go v1.24.0/go.mod h1:ctGKgv9bErQHO0NOrfhoyFtKMAkBhUE7y53F2xHFAkE= go-simpler.org/assert v0.9.0 h1:PfpmcSvL7yAnWyChSjOz6Sp6m9j5lyK8Ok9pEL31YkQ= @@ -1508,14 +1319,10 @@ go-simpler.org/musttag v0.14.0 h1:XGySZATqQYSEV3/YTy+iX+aofbZZllJaqwFWs+RTtSo= go-simpler.org/musttag v0.14.0/go.mod h1:uP8EymctQjJ4Z1kUnjX0u2l60WfUdQxCwSNKzE1JEOE= go-simpler.org/sloglint v0.11.1 h1:xRbPepLT/MHPTCA6TS/wNfZrDzkGvCCqUv4Bdwc3H7s= go-simpler.org/sloglint v0.11.1/go.mod h1:2PowwiCOK8mjiF+0KGifVOT8ZsCNiFzvfyJeJOIt8MQ= -go.augendre.info/arangolint v0.3.1 h1:n2E6p8f+zfXSFLa2e2WqFPp4bfvcuRdd50y6cT65pSo= -go.augendre.info/arangolint v0.3.1/go.mod h1:6ZKzEzIZuBQwoSvlKT+qpUfIbBfFCE5gbAoTg0/117g= go.augendre.info/arangolint v0.4.0 h1:xSCZjRoS93nXazBSg5d0OGCi9APPLNMmmLrC995tR50= go.augendre.info/arangolint v0.4.0/go.mod h1:l+f/b4plABuFISuKnTGD4RioXiCCgghv2xqst/xOvAA= go.augendre.info/fatcontext v0.9.0 h1:Gt5jGD4Zcj8CDMVzjOJITlSb9cEch54hjRRlN3qDojE= go.augendre.info/fatcontext v0.9.0/go.mod h1:L94brOAT1OOUNue6ph/2HnwxoNlds9aXDF2FcUntbNw= -go.mongodb.org/mongo-driver v1.17.6 h1:87JUG1wZfWsr6rIz3ZmpH90rL5tea7O3IHuSwHUpsss= -go.mongodb.org/mongo-driver v1.17.6/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= go.mongodb.org/mongo-driver v1.17.7 h1:a9w+U3Vt67eYzcfq3k/OAv284/uUUkL0uP75VE5rCOU= go.mongodb.org/mongo-driver v1.17.7/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= @@ -1544,18 +1351,16 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNl go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 h1:bDMKF3RUSxshZ5OjOTi8rsHGaPKsAt76FaqgvIUySLc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0/go.mod h1:dDT67G/IkA46Mr2l9Uj7HsQVwsjASyV9SjGofsiUZDA= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= go.opentelemetry.io/otel/exporters/prometheus v0.61.0 h1:cCyZS4dr67d30uDyh8etKM2QyDsQ4zC9ds3bdbrVoD0= go.opentelemetry.io/otel/exporters/prometheus v0.61.0/go.mod h1:iivMuj3xpR2DkUrUya3TPS/Z9h3dz7h01GxU+fQBRNg= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 h1:B/g+qde6Mkzxbry5ZZag0l7QrQBCtVm7lVjaLgmpje8= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0/go.mod h1:mOJK8eMmgW6ocDJn6Bn11CcZ05gi3P8GylBXEkZtbgA= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.37.0 h1:SNhVp/9q4Go/XHBkQ1/d5u9P/U+L1yaGPoi0x+mStaI= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.37.0/go.mod h1:tx8OOlGH6R4kLV67YaYO44GFXloEjGPZuMjEkaaqIp4= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= go.opentelemetry.io/otel/log v0.14.0 h1:2rzJ+pOAZ8qmZ3DDHg73NEKzSZkhkGIua9gXtxNGgrM= go.opentelemetry.io/otel/log v0.14.0/go.mod h1:5jRG92fEAgx0SU/vFPxmJvhIuDU9E1SUnEQrMlJpOno= go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= @@ -1603,19 +1408,13 @@ golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -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.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= -golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0= -golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= golang.org/x/exp v0.0.0-20260112195511-716be5621a96 h1:Z/6YuSHTLOHfNFdb8zVZomZr7cqNgTJvA8+Qz75D8gU= golang.org/x/exp v0.0.0-20260112195511-716be5621a96/go.mod h1:nzimsREAkjBCIEFtHiYkrJyT+2uy9YZJB7H1k68CXZU= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/exp/typeparams v0.0.0-20251219203646-944ab1f22d93 h1:PbC785RGO6yPO051ItgbG/adwoKRWC0VS7kXXeD/iqk= -golang.org/x/exp/typeparams v0.0.0-20251219203646-944ab1f22d93/go.mod h1:4Mzdyp/6jzw9auFDJ3OMF5qksa7UvPnzKqTVGcb04ms= golang.org/x/exp/typeparams v0.0.0-20260112195511-716be5621a96 h1:RMc8anw0hCPcg5CZYN2PEQ8nMwosk461R6vFwPrCFVg= golang.org/x/exp/typeparams v0.0.0-20260112195511-716be5621a96/go.mod h1:4Mzdyp/6jzw9auFDJ3OMF5qksa7UvPnzKqTVGcb04ms= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -1627,10 +1426,6 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= -golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -1646,8 +1441,6 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= -golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= @@ -1659,8 +1452,6 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/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.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1677,7 +1468,6 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1687,7 +1477,6 @@ 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.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.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= @@ -1695,8 +1484,6 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -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.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= @@ -1707,7 +1494,6 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -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.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= @@ -1723,8 +1509,6 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200812195022-5ae4c3c160a0/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20201230224404-63754364767c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= @@ -1732,10 +1516,6 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= -golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= -golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= @@ -1748,21 +1528,14 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= -gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= -gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= google.golang.org/api v0.263.0 h1:UFs7qn8gInIdtk1ZA6eXRXp5JDAnS4x9VRsRVCeKdbk= google.golang.org/api v0.263.0/go.mod h1:fAU1xtNNisHgOF5JooAs8rRaTkl2rT3uaoNGo9NS3R8= -google.golang.org/genproto v0.0.0-20251222181119-0a764e51fe1b h1:kqShdsddZrS6q+DGBCA73CzHsKDu5vW4qw78tFnbVvY= -google.golang.org/genproto v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:gw1DtiPCt5uh/HV9STVEeaO00S5ATsJiJ2LsZV8lcDI= google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 h1:VQZ/yAbAtjkHgH80teYd2em3xtIkkHd7ZhqfH2N9CsM= google.golang.org/genproto v0.0.0-20260128011058-8636f8732409/go.mod h1:rxKD3IEILWEu3P44seeNOAwZN4SaoKaQ/2eTg4mM6EM= -google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b h1:uA40e2M6fYRBf0+8uN5mLlqUtV192iiksiICIBkYJ1E= -google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:Xa7le7qx2vmqB/SzWUBa7KdMjpdpAHlh5QCSnjessQk= google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 h1:merA0rdPeUV3YIIfHHcH4qBkiQAc1nfCKSI7lB4cV2M= google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409/go.mod h1:fl8J1IvUjCilwZzQowmw2b7HQB2eAuYBabMXzWurF+I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260122232226-8e98ce8d340d h1:xXzuihhT3gL/ntduUZwHECzAn57E8dA6l8SOtYWdD8Q= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260122232226-8e98ce8d340d/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 h1:H86B94AW+VfJWDqFeEbBPhEtHzJwJfTbgE2lZa54ZAQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= @@ -1783,7 +1556,6 @@ gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= @@ -1793,12 +1565,8 @@ gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.6.1 h1:R094WgE8K4JirYjBaOpz/AvTyUu/3wbmAoskKN/pxTI= honnef.co/go/tools v0.6.1/go.mod h1:3puzxxljPCe8RGJX7BIy1plGbxEOZni5mR2aXe3/uk4= -k8s.io/apimachinery v0.35.0 h1:Z2L3IHvPVv/MJ7xRxHEtk6GoJElaAqDCCU0S6ncYok8= -k8s.io/apimachinery v0.35.0/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/utils v0.0.0-20260106112306-0fe9cd71b2f8 h1:oV4uULAC2QPIdMQwjMaNIwykyhWhnhBwX40yd5h9u3U= -k8s.io/utils v0.0.0-20260106112306-0fe9cd71b2f8/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg= lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo= mvdan.cc/gofumpt v0.9.2 h1:zsEMWL8SVKGHNztrx6uZrXdp7AX8r421Vvp23sz7ik4= From 368b0a23a81db08a25088ed6d7353e3aa7d08ef2 Mon Sep 17 00:00:00 2001 From: Simon Herrmann Date: Fri, 30 Jan 2026 10:52:43 +0100 Subject: [PATCH 11/12] fix: fix go mod --- go.mod | 124 ++++++++++++------------- go.sum | 283 ++++++++++++++++++++++++++++++--------------------------- 2 files changed, 211 insertions(+), 196 deletions(-) diff --git a/go.mod b/go.mod index 82d80759..8e6abb71 100644 --- a/go.mod +++ b/go.mod @@ -37,13 +37,13 @@ require ( cloud.google.com/go/kms v1.25.0 // indirect cloud.google.com/go/longrunning v0.8.0 // indirect cloud.google.com/go/monitoring v1.24.3 // indirect - cloud.google.com/go/storage v1.59.2 // indirect + cloud.google.com/go/storage v1.58.0 // indirect code.gitea.io/sdk/gitea v0.22.1 // indirect codeberg.org/chavacava/garif v0.2.0 // indirect codeberg.org/polyfloyd/go-errorlint v1.9.0 // indirect dario.cat/mergo v1.0.2 // indirect dev.gaijin.team/go/exhaustruct/v4 v4.0.0 // indirect - dev.gaijin.team/go/golib v0.8.1 // indirect + dev.gaijin.team/go/golib v0.8.0 // indirect github.com/42wim/httpsig v1.2.3 // indirect github.com/4meepo/tagalign v1.4.3 // indirect github.com/Abirdcfly/dupword v0.1.7 // indirect @@ -54,14 +54,14 @@ require ( github.com/Antonboom/nilnil v1.1.1 // indirect github.com/Antonboom/testifylint v1.6.4 // indirect github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.4.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.4 // indirect + github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.3 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest v0.11.30 // indirect @@ -75,51 +75,51 @@ require ( github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 // indirect github.com/BurntSushi/toml v1.6.0 // indirect github.com/Djarvur/go-err113 v0.1.1 // indirect - github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 // indirect - github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 // indirect - github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/sprig/v3 v3.3.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/MirrexOne/unqueryvet v1.5.3 // indirect + github.com/MirrexOne/unqueryvet v1.4.0 // indirect github.com/OpenPeeDeeP/depguard/v2 v2.2.1 // indirect github.com/ProtonMail/go-crypto v1.3.0 // indirect github.com/agnivade/levenshtein v1.2.1 // indirect - github.com/alecthomas/chroma/v2 v2.23.1 // indirect + github.com/alecthomas/chroma/v2 v2.21.1 // indirect github.com/alecthomas/go-check-sumtype v0.3.1 // indirect github.com/alexkohler/nakedret/v2 v2.0.6 // indirect - github.com/alexkohler/prealloc v1.0.2 // indirect + github.com/alexkohler/prealloc v1.0.1 // indirect github.com/alfatraining/structtag v1.0.0 // indirect github.com/alingse/asasalint v0.0.11 // indirect github.com/alingse/nilnesserr v0.2.0 // indirect - github.com/anchore/go-macholibre v0.0.0-20260126173545-dd3034b5c75b // indirect + github.com/anchore/go-macholibre v0.0.0-20250826193721-3cd206ca93aa // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/ashanbrown/forbidigo/v2 v2.3.0 // indirect github.com/ashanbrown/makezero/v2 v2.1.0 // indirect github.com/atc0005/go-teams-notify/v2 v2.14.0 // indirect github.com/avast/retry-go/v4 v4.7.0 // indirect - github.com/aws/aws-sdk-go-v2 v1.41.1 // indirect + github.com/aws/aws-sdk-go-v2 v1.41.0 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect - github.com/aws/aws-sdk-go-v2/config v1.32.7 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.19.7 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 // indirect - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.21.1 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 // indirect + github.com/aws/aws-sdk-go-v2/config v1.32.6 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.19.6 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 // indirect + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.18 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 // indirect - github.com/aws/aws-sdk-go-v2/service/ecr v1.55.1 // indirect - github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.9 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 // indirect + github.com/aws/aws-sdk-go-v2/service/ecr v1.55.0 // indirect + github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.8 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 // indirect - github.com/aws/aws-sdk-go-v2/service/kms v1.49.5 // indirect - github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0 // indirect - github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 // indirect + github.com/aws/aws-sdk-go-v2/service/kms v1.49.4 // indirect + github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.8 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 // indirect github.com/aws/smithy-go v1.24.0 // indirect github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.11.0 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect @@ -131,9 +131,9 @@ require ( github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb // indirect github.com/blang/semver v3.5.1+incompatible // indirect github.com/blizzy78/varnamelen v0.8.0 // indirect - github.com/bluesky-social/indigo v0.0.0-20260128215158-cf0fe7589346 // indirect + github.com/bluesky-social/indigo v0.0.0-20260106221649-6fcd9317e725 // indirect github.com/bombsimon/wsl/v4 v4.7.0 // indirect - github.com/bombsimon/wsl/v5 v5.6.0 // indirect + github.com/bombsimon/wsl/v5 v5.3.0 // indirect github.com/breml/bidichk v0.3.3 // indirect github.com/breml/errchkjson v0.4.1 // indirect github.com/brunoga/deep v1.2.5 // indirect @@ -155,21 +155,21 @@ require ( github.com/charmbracelet/colorprofile v0.4.1 // indirect github.com/charmbracelet/fang v0.4.4 // indirect github.com/charmbracelet/lipgloss v1.1.0 // indirect - github.com/charmbracelet/ultraviolet v0.0.0-20260123224754-f434aada8dbd // indirect - github.com/charmbracelet/x/ansi v0.11.4 // indirect + github.com/charmbracelet/ultraviolet v0.0.0-20251217160852-6b0c0e26fad9 // indirect + github.com/charmbracelet/x/ansi v0.11.3 // indirect github.com/charmbracelet/x/cellbuf v0.0.14 // indirect - github.com/charmbracelet/x/exp/charmtone v0.0.0-20260127155452-b72a9a918687 // indirect + github.com/charmbracelet/x/exp/charmtone v0.0.0-20251215102626-e0db08df7383 // indirect github.com/charmbracelet/x/term v0.2.2 // indirect github.com/charmbracelet/x/termios v0.1.1 // indirect github.com/charmbracelet/x/windows v0.2.2 // indirect github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect github.com/ckaznocha/intrange v0.3.1 // indirect - github.com/clipperhouse/displaywidth v0.8.0 // indirect - github.com/cloudflare/circl v1.6.3 // indirect - github.com/cncf/xds/go v0.0.0-20260121142036-a486691bba94 // indirect + github.com/clipperhouse/displaywidth v0.6.1 // indirect + github.com/cloudflare/circl v1.6.2 // indirect + github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect - github.com/containerd/stargz-snapshotter/estargz v0.18.2 // indirect + github.com/containerd/stargz-snapshotter/estargz v0.18.1 // indirect github.com/coreos/go-oidc/v3 v3.17.0 // indirect github.com/curioswitch/go-reassign v0.3.0 // indirect github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 // indirect @@ -177,7 +177,6 @@ require ( github.com/daixiang0/gci v0.13.7 // indirect github.com/dave/dst v0.27.3 // indirect github.com/davidmz/go-pageant v1.0.2 // indirect - github.com/denis-tingaikin/go-header v1.0.0 // indirect github.com/dghubble/go-twitter v0.0.0-20221104224141-912508c3888b // indirect github.com/dghubble/oauth1 v0.7.3 // indirect github.com/dghubble/sling v1.4.2 // indirect @@ -186,10 +185,10 @@ require ( github.com/dimchansky/utfbom v1.1.1 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/dlclark/regexp2 v1.11.5 // indirect - github.com/docker/cli v29.2.0+incompatible // indirect + github.com/docker/cli v29.2.0-rc.1.0.20251223174200-874b831c0e49+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker v28.5.2+incompatible // indirect - github.com/docker/docker-credential-helpers v0.9.5 // indirect + github.com/docker/docker-credential-helpers v0.9.4 // indirect github.com/docker/go-connections v0.6.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect @@ -207,7 +206,7 @@ require ( github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fzipp/gocyclo v0.6.0 // indirect github.com/gabriel-vasile/mimetype v1.4.12 // indirect - github.com/ghostiam/protogetter v0.3.19 // indirect + github.com/ghostiam/protogetter v0.3.18 // indirect github.com/github/smimesign v0.2.0 // indirect github.com/go-critic/go-critic v0.14.3 // indirect github.com/go-fed/httpsig v1.1.0 // indirect @@ -246,14 +245,14 @@ require ( github.com/go-toolsmith/astp v1.1.0 // indirect github.com/go-toolsmith/strparse v1.1.0 // indirect github.com/go-toolsmith/typep v1.1.0 // indirect - github.com/go-viper/mapstructure/v2 v2.5.0 // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/godoc-lint/godoc-lint v0.11.1 // indirect github.com/gofrs/flock v0.13.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.2 // indirect - github.com/golang-jwt/jwt/v5 v5.3.1 // indirect + github.com/golang-jwt/jwt/v5 v5.3.0 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golangci/asciicheck v0.5.0 // indirect github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 // indirect @@ -280,14 +279,14 @@ require ( github.com/goreleaser/chglog v0.7.4 // indirect github.com/goreleaser/fileglob v1.4.0 // indirect github.com/goreleaser/goreleaser/v2 v2.13.3 // indirect - github.com/goreleaser/nfpm/v2 v2.44.2 // indirect + github.com/goreleaser/nfpm/v2 v2.44.1 // indirect github.com/goreleaser/quill v0.0.0-20251224035235-ab943733386f // indirect github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect github.com/gostaticanalysis/analysisutil v0.7.1 // indirect github.com/gostaticanalysis/comment v1.5.0 // indirect github.com/gostaticanalysis/forcetypeassert v0.2.0 // indirect github.com/gostaticanalysis/nilerr v0.1.2 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.6 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect @@ -299,10 +298,10 @@ require ( github.com/hexops/gotextdiff v1.0.3 // indirect github.com/huandu/xstrings v1.5.0 // indirect github.com/in-toto/attestation v1.1.2 // indirect - github.com/in-toto/in-toto-golang v0.10.0 // indirect + github.com/in-toto/in-toto-golang v0.9.0 // indirect github.com/invopop/jsonschema v0.13.0 // indirect github.com/ipfs/bbloom v0.0.4 // indirect - github.com/ipfs/boxo v0.36.0 // indirect + github.com/ipfs/boxo v0.34.0 // indirect github.com/ipfs/go-block-format v0.2.3 // indirect github.com/ipfs/go-cid v0.6.0 // indirect github.com/ipfs/go-datastore v0.9.0 // indirect @@ -311,7 +310,7 @@ require ( github.com/ipfs/go-ipld-cbor v0.2.1 // indirect github.com/ipfs/go-ipld-format v0.6.3 // indirect github.com/ipfs/go-log v1.0.5 // indirect - github.com/ipfs/go-log/v2 v2.9.1 // indirect + github.com/ipfs/go-log/v2 v2.9.0 // indirect github.com/ipfs/go-metrics-interface v0.3.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jedisct1/go-minisign v0.0.0-20241212093149-d2f9f49435c7 // indirect @@ -323,7 +322,7 @@ require ( github.com/kevinburke/ssh_config v1.4.0 // indirect github.com/kisielk/errcheck v1.9.0 // indirect github.com/kkHAIKE/contextcheck v1.1.6 // indirect - github.com/klauspost/compress v1.18.3 // indirect + github.com/klauspost/compress v1.18.2 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/klauspost/pgzip v1.2.6 // indirect github.com/knadh/koanf/maps v0.1.2 // indirect @@ -332,7 +331,7 @@ require ( github.com/knadh/koanf/providers/file v1.2.1 // indirect github.com/knadh/koanf/providers/posflag v1.0.1 // indirect github.com/knadh/koanf/providers/structs v1.0.0 // indirect - github.com/knadh/koanf/v2 v2.3.2 // indirect + github.com/knadh/koanf/v2 v2.3.0 // indirect github.com/kr/fs v0.1.0 // indirect github.com/kulti/thelper v0.7.1 // indirect github.com/kunwardeep/paralleltest v1.0.15 // indirect @@ -381,7 +380,7 @@ require ( github.com/nakabonne/nestif v0.3.1 // indirect github.com/nishanths/exhaustive v0.12.0 // indirect github.com/nishanths/predeclared v0.2.2 // indirect - github.com/nunnatsa/ginkgolinter v0.22.0 // indirect + github.com/nunnatsa/ginkgolinter v0.21.2 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect @@ -422,11 +421,11 @@ require ( github.com/sigstore/cosign/v2 v2.6.2 // indirect github.com/sigstore/protobuf-specs v0.5.0 // indirect github.com/sigstore/rekor v1.5.0 // indirect - github.com/sigstore/rekor-tiles/v2 v2.1.0 // indirect + github.com/sigstore/rekor-tiles/v2 v2.0.1 // indirect github.com/sigstore/sigstore v1.10.4 // indirect github.com/sigstore/sigstore-go v1.1.4 // indirect - github.com/sigstore/timestamp-authority/v2 v2.0.4 // indirect - github.com/sirupsen/logrus v1.9.4 // indirect + github.com/sigstore/timestamp-authority/v2 v2.0.3 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/sivchari/containedctx v1.0.3 // indirect github.com/skeema/knownhosts v1.3.2 // indirect github.com/slack-go/slack v0.17.3 // indirect @@ -443,12 +442,12 @@ require ( github.com/tetafro/godot v1.5.4 // indirect github.com/theupdateframework/go-tuf v0.7.0 // indirect github.com/theupdateframework/go-tuf/v2 v2.4.1 // indirect - github.com/timakin/bodyclose v0.0.0-20260129054331-73d1f95b84b4 // indirect + github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 // indirect github.com/timonwong/loggercheck v0.11.0 // indirect github.com/tomarrell/wrapcheck/v2 v2.12.0 // indirect github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect github.com/tomnomnom/linkheader v0.0.0-20250811210735-e5fe3b51442e // indirect - github.com/transparency-dev/formats v0.0.0-20260126105629-a1e81f2894be // indirect + github.com/transparency-dev/formats v0.0.0-20251208091212-1378f9e1b1b7 // indirect github.com/transparency-dev/merkle v0.0.2 // indirect github.com/ultraware/funlen v0.2.0 // indirect github.com/ultraware/whitespace v0.2.0 // indirect @@ -473,9 +472,9 @@ require ( gitlab.com/gitlab-org/api/client-go v1.24.0 // indirect go-simpler.org/musttag v0.14.0 // indirect go-simpler.org/sloglint v0.11.1 // indirect - go.augendre.info/arangolint v0.4.0 // indirect + go.augendre.info/arangolint v0.3.1 // indirect go.augendre.info/fatcontext v0.9.0 // indirect - go.mongodb.org/mongo-driver v1.17.7 // indirect + go.mongodb.org/mongo-driver v1.17.6 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/detectors/gcp v1.39.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 // indirect @@ -491,8 +490,8 @@ require ( go.uber.org/zap v1.27.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect gocloud.dev v0.44.0 // indirect - golang.org/x/exp v0.0.0-20260112195511-716be5621a96 // indirect - golang.org/x/exp/typeparams v0.0.0-20260112195511-716be5621a96 // indirect + golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect + golang.org/x/exp/typeparams v0.0.0-20251219203646-944ab1f22d93 // indirect golang.org/x/time v0.14.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 // indirect @@ -516,6 +515,7 @@ require ( github.com/clipperhouse/uax29/v2 v2.4.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/denis-tingaikin/go-header v0.5.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d // indirect diff --git a/go.sum b/go.sum index 49916f8c..c6db73ce 100644 --- a/go.sum +++ b/go.sum @@ -34,8 +34,8 @@ cloud.google.com/go/resourcemanager v1.10.7 h1:oPZKIdjyVTuag+D4HF7HO0mnSqcqgjcuA cloud.google.com/go/resourcemanager v1.10.7/go.mod h1:rScGkr6j2eFwxAjctvOP/8sqnEpDbQ9r5CKwKfomqjs= cloud.google.com/go/serviceusage v1.9.7 h1:vrBBeI2ESmri4BLGPz1YH2o37loIQ3DDTloYiDOe2lY= cloud.google.com/go/serviceusage v1.9.7/go.mod h1:JpBpv+4Zbe7+RiC9ydc6xgBUOntIL9tA85d2xKgV83g= -cloud.google.com/go/storage v1.59.2 h1:gmOAuG1opU8YvycMNpP+DvHfT9BfzzK5Cy+arP+Nocw= -cloud.google.com/go/storage v1.59.2/go.mod h1:cMWbtM+anpC74gn6qjLh+exqYcfmB9Hqe5z6adx+CLI= +cloud.google.com/go/storage v1.58.0 h1:PflFXlmFJjG/nBeR9B7pKddLQWaFaRWx4uUi/LyNxxo= +cloud.google.com/go/storage v1.58.0/go.mod h1:cMWbtM+anpC74gn6qjLh+exqYcfmB9Hqe5z6adx+CLI= cloud.google.com/go/trace v1.11.7 h1:kDNDX8JkaAG3R2nq1lIdkb7FCSi1rCmsEtKVsty7p+U= cloud.google.com/go/trace v1.11.7/go.mod h1:TNn9d5V3fQVf6s4SCveVMIBS2LJUqo73GACmq/Tky0s= code.gitea.io/sdk/gitea v0.22.1 h1:7K05KjRORyTcTYULQ/AwvlVS6pawLcWyXZcTr7gHFyA= @@ -48,8 +48,8 @@ dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= dev.gaijin.team/go/exhaustruct/v4 v4.0.0 h1:873r7aNneqoBB3IaFIzhvt2RFYTuHgmMjoKfwODoI1Y= dev.gaijin.team/go/exhaustruct/v4 v4.0.0/go.mod h1:aZ/k2o4Y05aMJtiux15x8iXaumE88YdiB0Ai4fXOzPI= -dev.gaijin.team/go/golib v0.8.1 h1:JYju4x9BSo+QD/AYeHULVDcvEhiFg8wOi6pT0IaZF5E= -dev.gaijin.team/go/golib v0.8.1/go.mod h1:c5fu7t1RSGMxSQgcUYO1sODbzsYnOCXJLmHeNG1Eb+0= +dev.gaijin.team/go/golib v0.8.0 h1:BiDNudpoFizoU5VHdQUiabtHSt9fyPX11Fr4OU9PaUQ= +dev.gaijin.team/go/golib v0.8.0/go.mod h1:c5fu7t1RSGMxSQgcUYO1sODbzsYnOCXJLmHeNG1Eb+0= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/42wim/httpsig v1.2.3 h1:xb0YyWhkYj57SPtfSttIobJUPJZB9as1nsfo7KWVcEs= @@ -74,8 +74,8 @@ github.com/Antonboom/testifylint v1.6.4 h1:gs9fUEy+egzxkEbq9P4cpcMB6/G0DYdMeiFS8 github.com/Antonboom/testifylint v1.6.4/go.mod h1:YO33FROXX2OoUfwjz8g+gUxQXio5i9qpVy7nXGbxDD4= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 h1:fou+2+WFTib47nS+nz/ozhEBnvU96bKHy6LjRsY4E28= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0/go.mod h1:t76Ruy8AHvUAC8GfMWJMa0ElSbuIcO03NLpynfbgsPA= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 h1:JXg2dwJUmPB9JmtVmdEB16APJ7jurfbY5jnfXpJoRMc= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= @@ -92,8 +92,8 @@ github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.4.0 h1:E4MgwLB github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.4.0/go.mod h1:Y2b/1clN4zsAoUd/pgNAQHjLDnTis/6ROkUfyob6psM= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 h1:nCYfgcSyHZXJI8J0IWE5MsCGlb2xp9fJiXyxWgmOFg4= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0/go.mod h1:ucUjca2JtSZboY8IoUqyQyuuXvwbMBVwFOm0vdQPNhA= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.4 h1:jWQK1GI+LeGGUKBADtcH2rRqPxYB1Ljwms5gFA2LqrM= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.4/go.mod h1:8mwH4klAm9DUgR2EEHyEEAQlRDvLPyg5fQry3y+cDew= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.3 h1:ZJJNFaQ86GVKQ9ehwqyAFE6pIfyicpuJ8IkVaPBc6/4= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.3/go.mod h1:URuDvhmATVKqHBH9/0nOiNKk0+YcwfQ3WkK5PqHKxc8= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= @@ -135,14 +135,14 @@ github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Djarvur/go-err113 v0.1.1 h1:eHfopDqXRwAi+YmCUas75ZE0+hoBHJ2GQNLYRSxao4g= github.com/Djarvur/go-err113 v0.1.1/go.mod h1:IaWJdYFLg76t2ihfflPZnM1LIQszWOsFDh2hhhAVF6k= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 h1:DHa2U07rk8syqvCge0QIGMCE1WxGj9njT44GH7zNJLQ= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 h1:UnDZ/zFfG1JhH/DqxIZYU/1CUAlTUScoXD/LcM2Ykk8= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0/go.mod h1:IA1C1U7jO/ENqm/vhi7V9YYpBsp+IMyqNrEN94N7tVc= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.55.0 h1:7t/qx5Ost0s0wbA/VDrByOooURhp+ikYwv20i9Y07TQ= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.55.0/go.mod h1:vB2GH9GAYYJTO3mEn8oYwzEdhlayZIdQz6zdzgUIRvA= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 h1:0s6TxfCu2KHkkZPnBfsQ2y5qia0jl3MMrmBhu3nCOYk= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 h1:lhhYARPUu3LmHysQ/igznQphfzynnqI3D75oUyw1HXk= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0/go.mod h1:l9rva3ApbBpEJxSNYnwT9N4CDLrWgtq3u8736C5hyJw= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.54.0 h1:xfK3bbi6F2RDtaZFtUdKO3osOBIhNb+xTs8lFW6yx9o= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.54.0/go.mod h1:vB2GH9GAYYJTO3mEn8oYwzEdhlayZIdQz6zdzgUIRvA= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 h1:s0WlVbf9qpvkh1c/uDAPElam0WrL7fHRIidgZJ7UqZI= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= @@ -152,8 +152,8 @@ github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSC github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/MirrexOne/unqueryvet v1.5.3 h1:LpT3rsH+IY3cQddWF9bg4C7jsbASdGnrOSofY8IPEiw= -github.com/MirrexOne/unqueryvet v1.5.3/go.mod h1:fs9Zq6eh1LRIhsDIsxf9PONVUjYdFHdtkHIgZdJnyPU= +github.com/MirrexOne/unqueryvet v1.4.0 h1:6KAkqqW2KUnkl9Z0VuTphC3IXRPoFqEkJEtyxxHj5eQ= +github.com/MirrexOne/unqueryvet v1.4.0/go.mod h1:IWwCwMQlSWjAIteW0t+28Q5vouyktfujzYznSIWiuOg= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OpenPeeDeeP/depguard/v2 v2.2.1 h1:vckeWVESWp6Qog7UZSARNqfu/cZqvki8zsuj3piCMx4= @@ -170,24 +170,24 @@ github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KO github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= -github.com/alecthomas/chroma/v2 v2.23.1 h1:nv2AVZdTyClGbVQkIzlDm/rnhk1E9bU9nXwmZ/Vk/iY= -github.com/alecthomas/chroma/v2 v2.23.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o= +github.com/alecthomas/chroma/v2 v2.21.1 h1:FaSDrp6N+3pphkNKU6HPCiYLgm8dbe5UXIXcoBhZSWA= +github.com/alecthomas/chroma/v2 v2.21.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o= github.com/alecthomas/go-check-sumtype v0.3.1 h1:u9aUvbGINJxLVXiFvHUlPEaD7VDULsrxJb4Aq31NLkU= github.com/alecthomas/go-check-sumtype v0.3.1/go.mod h1:A8TSiN3UPRw3laIgWEUOHHLPa6/r9MtoigdlP5h3K/E= github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs= github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alexkohler/nakedret/v2 v2.0.6 h1:ME3Qef1/KIKr3kWX3nti3hhgNxw6aqN5pZmQiFSsuzQ= github.com/alexkohler/nakedret/v2 v2.0.6/go.mod h1:l3RKju/IzOMQHmsEvXwkqMDzHHvurNQfAgE1eVmT40Q= -github.com/alexkohler/prealloc v1.0.2 h1:MPo8cIkGkZytq7WNH9UHv3DIX1mPz1RatPXnZb0zHWQ= -github.com/alexkohler/prealloc v1.0.2/go.mod h1:fT39Jge3bQrfA7nPMDngUfvUbQGQeJyGQnR+913SCig= +github.com/alexkohler/prealloc v1.0.1 h1:A9P1haqowqUxWvU9nk6tQ7YktXIHf+LQM9wPRhuteEE= +github.com/alexkohler/prealloc v1.0.1/go.mod h1:fT39Jge3bQrfA7nPMDngUfvUbQGQeJyGQnR+913SCig= github.com/alfatraining/structtag v1.0.0 h1:2qmcUqNcCoyVJ0up879K614L9PazjBSFruTB0GOFjCc= github.com/alfatraining/structtag v1.0.0/go.mod h1:p3Xi5SwzTi+Ryj64DqjLWz7XurHxbGsq6y3ubePJPus= github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw= github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= github.com/alingse/nilnesserr v0.2.0 h1:raLem5KG7EFVb4UIDAXgrv3N2JIaffeKNtcEXkEWd/w= github.com/alingse/nilnesserr v0.2.0/go.mod h1:1xJPrXonEtX7wyTq8Dytns5P2hNzoWymVUIaKm4HNFg= -github.com/anchore/go-macholibre v0.0.0-20260126173545-dd3034b5c75b h1:P1aST8e0rhBd8xuQG/4XPlvlzTzZ6iuBdxTbZ0qo4RA= -github.com/anchore/go-macholibre v0.0.0-20260126173545-dd3034b5c75b/go.mod h1:eu0gbwaZ+ocVFJLePdmPPDKU8MboV1MKsUCr36Ckd5s= +github.com/anchore/go-macholibre v0.0.0-20250826193721-3cd206ca93aa h1:KPEP8f3enFJeus3Wo51I+riVuCvlf4OEYl2B4IfycbQ= +github.com/anchore/go-macholibre v0.0.0-20250826193721-3cd206ca93aa/go.mod h1:7YJA6tAfRm4SzIF93b32pR4xnbf8g2nJIeQnp+2vzzI= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= @@ -207,50 +207,50 @@ github.com/avast/retry-go/v4 v4.7.0 h1:yjDs35SlGvKwRNSykujfjdMxMhMQQM0TnIjJaHB+Z github.com/avast/retry-go/v4 v4.7.0/go.mod h1:ZMPDa3sY2bKgpLtap9JRUgk2yTAba7cgiFhqxY2Sg6Q= github.com/aws/aws-sdk-go v1.55.8 h1:JRmEUbU52aJQZ2AjX4q4Wu7t4uZjOu71uyNmaWlUkJQ= github.com/aws/aws-sdk-go v1.55.8/go.mod h1:ZkViS9AqA6otK+JBBNH2++sx1sgxrPKcSzPPvQkUtXk= -github.com/aws/aws-sdk-go-v2 v1.41.1 h1:ABlyEARCDLN034NhxlRUSZr4l71mh+T5KAeGh6cerhU= -github.com/aws/aws-sdk-go-v2 v1.41.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0= +github.com/aws/aws-sdk-go-v2 v1.41.0 h1:tNvqh1s+v0vFYdA1xq0aOJH+Y5cRyZ5upu6roPgPKd4= +github.com/aws/aws-sdk-go-v2 v1.41.0/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4= -github.com/aws/aws-sdk-go-v2/config v1.32.7 h1:vxUyWGUwmkQ2g19n7JY/9YL8MfAIl7bTesIUykECXmY= -github.com/aws/aws-sdk-go-v2/config v1.32.7/go.mod h1:2/Qm5vKUU/r7Y+zUk/Ptt2MDAEKAfUtKc1+3U1Mo3oY= -github.com/aws/aws-sdk-go-v2/credentials v1.19.7 h1:tHK47VqqtJxOymRrNtUXN5SP/zUTvZKeLx4tH6PGQc8= -github.com/aws/aws-sdk-go-v2/credentials v1.19.7/go.mod h1:qOZk8sPDrxhf+4Wf4oT2urYJrYt3RejHSzgAquYeppw= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 h1:I0GyV8wiYrP8XpA70g1HBcQO1JlQxCMTW9npl5UbDHY= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17/go.mod h1:tyw7BOl5bBe/oqvoIeECFJjMdzXoa/dfVz3QQ5lgHGA= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.21.1 h1:1hWFp+52Vq8Fevy/KUhbW/1MEApMz7uitCF/PQXRJpk= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.21.1/go.mod h1:sIec8j802/rCkCKgZV678HFR0s7lhQUYXT77tIvlaa4= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 h1:xOLELNKGp2vsiteLsvLPwxC+mYmO6OZ8PYgiuPJzF8U= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17/go.mod h1:5M5CI3D12dNOtH3/mk6minaRwI2/37ifCURZISxA/IQ= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 h1:WWLqlh79iO48yLkj1v3ISRNiv+3KdQoZ6JWyfcsyQik= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17/go.mod h1:EhG22vHRrvF8oXSTYStZhJc1aUgKtnJe+aOiFEV90cM= +github.com/aws/aws-sdk-go-v2/config v1.32.6 h1:hFLBGUKjmLAekvi1evLi5hVvFQtSo3GYwi+Bx4lpJf8= +github.com/aws/aws-sdk-go-v2/config v1.32.6/go.mod h1:lcUL/gcd8WyjCrMnxez5OXkO3/rwcNmvfno62tnXNcI= +github.com/aws/aws-sdk-go-v2/credentials v1.19.6 h1:F9vWao2TwjV2MyiyVS+duza0NIRtAslgLUM0vTA1ZaE= +github.com/aws/aws-sdk-go-v2/credentials v1.19.6/go.mod h1:SgHzKjEVsdQr6Opor0ihgWtkWdfRAIwxYzSJ8O85VHY= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 h1:80+uETIWS1BqjnN9uJ0dBUaETh+P1XwFy5vwHwK5r9k= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16/go.mod h1:wOOsYuxYuB/7FlnVtzeBYRcjSRtQpAW0hCP7tIULMwo= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.18 h1:9vWXHtaepwoAl/UuKzxwgOoJDXPCC3hvgNMfcmdS2Tk= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.18/go.mod h1:sKuUZ+MwUTuJbYvZ8pK0x10LvgcJK3Y4rmh63YBekwk= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 h1:rgGwPzb82iBYSvHMHXc8h9mRoOUBZIGFgKb9qniaZZc= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16/go.mod h1:L/UxsGeKpGoIj6DxfhOWHWQ/kGKcd4I1VncE4++IyKA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 h1:1jtGzuV7c82xnqOVfx2F0xmJcOw5374L7N6juGW6x6U= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16/go.mod h1:M2E5OQf+XLe+SZGmmpaI2yy+J326aFf6/+54PoxSANc= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 h1:JqcdRG//czea7Ppjb+g/n4o8i/R50aTBHkA7vu0lK+k= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17/go.mod h1:CO+WeGmIdj/MlPel2KwID9Gt7CNq4M65HUfBW97liM0= -github.com/aws/aws-sdk-go-v2/service/ecr v1.55.1 h1:B7f9R99lCF83XlolTg6d6Lvghyto+/VU83ZrneAVfK8= -github.com/aws/aws-sdk-go-v2/service/ecr v1.55.1/go.mod h1:cpYRXx5BkmS3mwWRKPbWSPKmyAUNL7aLWAPiiinwk/U= -github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.9 h1:WxoqdNfGWj668u/NX7qBMPevmJu14LYNMMTRZthoclc= -github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.9/go.mod h1:4oMS/bVKMnYIIBgkcHPoru4DVeMGutHv03FZUTjvsvI= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 h1:CjMzUs78RDDv4ROu3JnJn/Ig1r6ZD7/T2DXLLRpejic= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16/go.mod h1:uVW4OLBqbJXSHJYA9svT9BluSvvwbzLQ2Crf6UPzR3c= +github.com/aws/aws-sdk-go-v2/service/ecr v1.55.0 h1:Mz6rvVhqmqGPzZNDLolW9IwPzhL/V+QS+dvX+vm/zh8= +github.com/aws/aws-sdk-go-v2/service/ecr v1.55.0/go.mod h1:8n8vVvu7LzveA0or4iWQwNndJStpKOX4HiVHM5jax2U= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.8 h1:2QlSMAimXfMKYRFlxGkbRMRtKN3OqIOB/CfxMcVdzjM= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.8/go.mod h1:esoP/SqS8FVryu4PPLX6ND925slId/IxPxvUBKuBqRk= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 h1:Z5EiPIzXKewUQK0QTMkutjiaPVeVYXX7KIqhXu/0fXs= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8/go.mod h1:FsTpJtvC4U1fyDXk7c71XoDv3HlRm8V3NiYLeYLh5YE= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 h1:RuNSMoozM8oXlgLG/n6WLaFGoea7/CddrCfIiSA+xdY= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17/go.mod h1:F2xxQ9TZz5gDWsclCtPQscGpP0VUOc8RqgFM3vDENmU= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 h1:bGeHBsGZx0Dvu/eJC0Lh9adJa3M1xREcndxLNZlve2U= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17/go.mod h1:dcW24lbU0CzHusTE8LLHhRLI42ejmINN8Lcr22bwh/g= -github.com/aws/aws-sdk-go-v2/service/kms v1.49.5 h1:DKibav4XF66XSeaXcrn9GlWGHos6D/vJ4r7jsK7z5CE= -github.com/aws/aws-sdk-go-v2/service/kms v1.49.5/go.mod h1:1SdcmEGUEQE1mrU2sIgeHtcMSxHuybhPvuEPANzIDfI= -github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0 h1:oeu8VPlOre74lBA/PMhxa5vewaMIMmILM+RraSyB8KA= -github.com/aws/aws-sdk-go-v2/service/s3 v1.96.0/go.mod h1:5jggDlZ2CLQhwJBiZJb4vfk4f0GxWdEDruWKEJ1xOdo= -github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 h1:VrhDvQib/i0lxvr3zqlUwLwJP4fpmpyD9wYG1vfSu+Y= -github.com/aws/aws-sdk-go-v2/service/signin v1.0.5/go.mod h1:k029+U8SY30/3/ras4G/Fnv/b88N4mAfliNn08Dem4M= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 h1:v6EiMvhEYBoHABfbGB4alOYmCIrcgyPPiBE1wZAEbqk= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.9/go.mod h1:yifAsgBxgJWn3ggx70A3urX2AN49Y5sJTD1UQFlfqBw= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 h1:gd84Omyu9JLriJVCbGApcLzVR3XtmC4ZDPcAI6Ftvds= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13/go.mod h1:sTGThjphYE4Ohw8vJiRStAcu3rbjtXRsdNB0TvZ5wwo= -github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 h1:5fFjR/ToSOzB2OQ/XqWpZBmNvmP/pJ1jOWYlFDJTjRQ= -github.com/aws/aws-sdk-go-v2/service/sts v1.41.6/go.mod h1:qgFDZQSD/Kys7nJnVqYlWKnh0SSdMjAi0uSwON4wgYQ= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 h1:DIBqIrJ7hv+e4CmIk2z3pyKT+3B6qVMgRsawHiR3qso= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7/go.mod h1:vLm00xmBke75UmpNvOcZQ/Q30ZFjbczeLFqGx5urmGo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 h1:oHjJHeUy0ImIV0bsrX0X91GkV5nJAyv1l1CC9lnO0TI= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16/go.mod h1:iRSNGgOYmiYwSCXxXaKb9HfOEj40+oTKn8pTxMlYkRM= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 h1:NSbvS17MlI2lurYgXnCOLvCFX38sBW4eiVER7+kkgsU= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16/go.mod h1:SwT8Tmqd4sA6G1qaGdzWCJN99bUmPGHfRwwq3G5Qb+A= +github.com/aws/aws-sdk-go-v2/service/kms v1.49.4 h1:2gom8MohxN0SnhHZBYAC4S8jHG+ENEnXjyJ5xKe3vLc= +github.com/aws/aws-sdk-go-v2/service/kms v1.49.4/go.mod h1:HO31s0qt0lso/ADvZQyzKs8js/ku0fMHsfyXW8OPVYc= +github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0 h1:MIWra+MSq53CFaXXAywB2qg9YvVZifkk6vEGl/1Qor0= +github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0/go.mod h1:79S2BdqCJpScXZA2y+cpZuocWsjGjJINyXnOsf5DTz8= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 h1:HpI7aMmJ+mm1wkSHIA2t5EaFFv5EFYXePW30p1EIrbQ= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.4/go.mod h1:C5RdGMYGlfM0gYq/tifqgn4EbyX99V15P2V3R+VHbQU= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.8 h1:aM/Q24rIlS3bRAhTyFurowU8A0SMyGDtEOY/l/s/1Uw= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.8/go.mod h1:+fWt2UHSb4kS7Pu8y+BMBvJF0EWx+4H0hzNwtDNRTrg= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 h1:AHDr0DaHIAo8c9t1emrzAlVDFp+iMMKnPdYy6XO4MCE= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12/go.mod h1:GQ73XawFFiWxyWXMHWfhiomvP3tXtdNar/fi8z18sx0= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 h1:SciGFVNZ4mHdm7gpD1dgZYnCuVdX1s+lFTg4+4DOy70= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.5/go.mod h1:iW40X4QBmUxdP+fZNOpfmkdMZqsovezbAeO+Ubiv2pk= github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk= github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.11.0 h1:GOPttfOAf5qAgx7r6b+zCWZrvCsfKffkL4H6mSYx1kA= @@ -275,12 +275,12 @@ github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdn github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M= github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= -github.com/bluesky-social/indigo v0.0.0-20260128215158-cf0fe7589346 h1:FfYnKHM+w5EDHFMBwTgMUpi3DLVxbMa2MRr0kI4Iqw0= -github.com/bluesky-social/indigo v0.0.0-20260128215158-cf0fe7589346/go.mod h1:KIy0FgNQacp4uv2Z7xhNkV3qZiUSGuRky97s7Pa4v+o= +github.com/bluesky-social/indigo v0.0.0-20260106221649-6fcd9317e725 h1:gfrLAhE6PHun4MDypO/5hpnaHPd9Dbe9+JxZL0gC4ic= +github.com/bluesky-social/indigo v0.0.0-20260106221649-6fcd9317e725/go.mod h1:KIy0FgNQacp4uv2Z7xhNkV3qZiUSGuRky97s7Pa4v+o= github.com/bombsimon/wsl/v4 v4.7.0 h1:1Ilm9JBPRczjyUs6hvOPKvd7VL1Q++PL8M0SXBDf+jQ= github.com/bombsimon/wsl/v4 v4.7.0/go.mod h1:uV/+6BkffuzSAVYD+yGyld1AChO7/EuLrCF/8xTiapg= -github.com/bombsimon/wsl/v5 v5.6.0 h1:4z+/sBqC5vUmSp1O0mS+czxwH9+LKXtCWtHH9rZGQL8= -github.com/bombsimon/wsl/v5 v5.6.0/go.mod h1:Uqt2EfrMj2NV8UGoN1f1Y3m0NpUVCsUdrNCdet+8LvU= +github.com/bombsimon/wsl/v5 v5.3.0 h1:nZWREJFL6U3vgW/B1lfDOigl+tEF6qgs6dGGbFeR0UM= +github.com/bombsimon/wsl/v5 v5.3.0/go.mod h1:Gp8lD04z27wm3FANIUPZycXp+8huVsn0oxc+n4qfV9I= github.com/breml/bidichk v0.3.3 h1:WSM67ztRusf1sMoqH6/c4OBCUlRVTKq+CbSeo0R17sE= github.com/breml/bidichk v0.3.3/go.mod h1:ISbsut8OnjB367j5NseXEGGgO/th206dVa427kR8YTE= github.com/breml/errchkjson v0.4.1 h1:keFSS8D7A2T0haP9kzZTi7o26r7kE3vymjZNeNDRDwg= @@ -328,14 +328,14 @@ github.com/charmbracelet/keygen v0.5.4 h1:XQYgf6UEaTGgQSSmiPpIQ78WfseNQp4Pz8N/c1 github.com/charmbracelet/keygen v0.5.4/go.mod h1:t4oBRr41bvK7FaJsAaAQhhkUuHslzFXVjOBwA55CZNM= github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= -github.com/charmbracelet/ultraviolet v0.0.0-20260123224754-f434aada8dbd h1:TIjV5jgzCdmhE/cWl/e8pmOaTns/Ah4SoUFv4PTFlC0= -github.com/charmbracelet/ultraviolet v0.0.0-20260123224754-f434aada8dbd/go.mod h1:2I+V4H3xExk9BZ3W2UnU/RAkJPYzBOkY7RzEe7tH1vo= -github.com/charmbracelet/x/ansi v0.11.4 h1:6G65PLu6HjmE858CnTUQY1LXT3ZUWwfvqEROLF8vqHI= -github.com/charmbracelet/x/ansi v0.11.4/go.mod h1:/5AZ+UfWExW3int5H5ugnsG/PWjNcSQcwYsHBlPFQN4= +github.com/charmbracelet/ultraviolet v0.0.0-20251217160852-6b0c0e26fad9 h1:dsDBRP9Iyco0EjVpCsAzl8VGbxk04fP3sa80ySJSAZw= +github.com/charmbracelet/ultraviolet v0.0.0-20251217160852-6b0c0e26fad9/go.mod h1:Ns3cOzzY9hEFFeGxB6VpfgRnqOJZJFhQAPfRxPqflQs= +github.com/charmbracelet/x/ansi v0.11.3 h1:6DcVaqWI82BBVM/atTyq6yBoRLZFBsnoDoX9GCu2YOI= +github.com/charmbracelet/x/ansi v0.11.3/go.mod h1:yI7Zslym9tCJcedxz5+WBq+eUGMJT0bM06Fqy1/Y4dI= github.com/charmbracelet/x/cellbuf v0.0.14 h1:iUEMryGyFTelKW3THW4+FfPgi4fkmKnnaLOXuc+/Kj4= github.com/charmbracelet/x/cellbuf v0.0.14/go.mod h1:P447lJl49ywBbil/KjCk2HexGh4tEY9LH0/1QrZZ9rA= -github.com/charmbracelet/x/exp/charmtone v0.0.0-20260127155452-b72a9a918687 h1:YSLsz8YEuMxY9SXJSKpjBWmOxjjjP4xEX2hZ56BP/2s= -github.com/charmbracelet/x/exp/charmtone v0.0.0-20260127155452-b72a9a918687/go.mod h1:nsExn0DGyX0lh9LwLHTn2Gg+hafdzfSXnC+QmEJTZFY= +github.com/charmbracelet/x/exp/charmtone v0.0.0-20251215102626-e0db08df7383 h1:xGojlO6kHCDB1k6DolME79LG0u90TzVd8atGhmxFRIo= +github.com/charmbracelet/x/exp/charmtone v0.0.0-20251215102626-e0db08df7383/go.mod h1:nsExn0DGyX0lh9LwLHTn2Gg+hafdzfSXnC+QmEJTZFY= github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f h1:pk6gmGpCE7F3FcjaOEKYriCvpmIN4+6OS/RD0vm4uIA= github.com/charmbracelet/x/exp/golden v0.0.0-20250806222409-83e3a29d542f/go.mod h1:IfZAMTHB6XkZSeXUqriemErjAWCCzT0LwjKFYCZyw0I= github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk= @@ -348,16 +348,16 @@ github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb2 github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589/go.mod h1:OuDyvmLnMCwa2ep4Jkm6nyA0ocJuZlGyk2gGseVzERM= github.com/ckaznocha/intrange v0.3.1 h1:j1onQyXvHUsPWujDH6WIjhyH26gkRt/txNlV7LspvJs= github.com/ckaznocha/intrange v0.3.1/go.mod h1:QVepyz1AkUoFQkpEqksSYpNpUo3c5W7nWh/s6SHIJJk= -github.com/clipperhouse/displaywidth v0.8.0 h1:/z8v+H+4XLluJKS7rAc7uHZTalT5Z+1430ld3lePSRI= -github.com/clipperhouse/displaywidth v0.8.0/go.mod h1:UpOXiIKep+TohQYwvAAM/VDU8v3Z5rnWTxiwueR0XvQ= +github.com/clipperhouse/displaywidth v0.6.1 h1:/zMlAezfDzT2xy6acHBzwIfyu2ic0hgkT83UX5EY2gY= +github.com/clipperhouse/displaywidth v0.6.1/go.mod h1:R+kHuzaYWFkTm7xoMmK1lFydbci4X2CicfbGstSGg0o= github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs= github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= github.com/clipperhouse/uax29/v2 v2.4.0 h1:RXqE/l5EiAbA4u97giimKNlmpvkmz+GrBVTelsoXy9g= github.com/clipperhouse/uax29/v2 v2.4.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= -github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8= -github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4= -github.com/cncf/xds/go v0.0.0-20260121142036-a486691bba94 h1:kkHPnzHm5Ln7WA0XYjrr2ITA0l9Vs6H++Ni//P+SZso= -github.com/cncf/xds/go v0.0.0-20260121142036-a486691bba94/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI= +github.com/cloudflare/circl v1.6.2 h1:hL7VBpHHKzrV5WTfHCaBsgx/HGbBYlgrwvNXEVDYYsQ= +github.com/cloudflare/circl v1.6.2/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4= +github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w= +github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4= github.com/codesphere-cloud/cs-go v0.16.2 h1:AtS4HKPngpYfB4uj28vo/eq+qPWXICjLmx9R0G0a2rQ= @@ -370,8 +370,8 @@ github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151X github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= -github.com/containerd/stargz-snapshotter/estargz v0.18.2 h1:yXkZFYIzz3eoLwlTUZKz2iQ4MrckBxJjkmD16ynUTrw= -github.com/containerd/stargz-snapshotter/estargz v0.18.2/go.mod h1:XyVU5tcJ3PRpkA9XS2T5us6Eg35yM0214Y+wvrZTBrY= +github.com/containerd/stargz-snapshotter/estargz v0.18.1 h1:cy2/lpgBXDA3cDKSyEfNOFMA/c10O1axL69EU7iirO8= +github.com/containerd/stargz-snapshotter/estargz v0.18.1/go.mod h1:ALIEqa7B6oVDsrF37GkGN20SuvG/pIMm7FwP7ZmRb0Q= github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc= github.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= @@ -403,8 +403,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0= github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE= -github.com/denis-tingaikin/go-header v1.0.0 h1:QIwZWb3jLC6pOp9NEFldiD8raqRmCE/n0VUdZKW32x8= -github.com/denis-tingaikin/go-header v1.0.0/go.mod h1:NT3qKwqsXQYp8WHVgkwxL49qB5jsRmdr9dGQCDfpmZ0= +github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8= +github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY= github.com/dghubble/go-twitter v0.0.0-20221104224141-912508c3888b h1:XQu6o3AwJx/jsg9LZ41uIeUdXK5be099XFfFn6H9ikk= github.com/dghubble/go-twitter v0.0.0-20221104224141-912508c3888b/go.mod h1:B0/qdW5XUupJvcsx40hnVbfjzz9He5YpYXx6eVVdiSY= github.com/dghubble/oauth1 v0.7.3 h1:EkEM/zMDMp3zOsX2DC/ZQ2vnEX3ELK0/l9kb+vs4ptE= @@ -426,14 +426,14 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr 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/docker/cli v29.2.0+incompatible h1:9oBd9+YM7rxjZLfyMGxjraKBKE4/nVyvVfN4qNl9XRM= -github.com/docker/cli v29.2.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v29.2.0-rc.1.0.20251223174200-874b831c0e49+incompatible h1:qzsQ4KSWZG5dBSDv3XFBCvBcy6/jC1odDTwe2SbMBh0= +github.com/docker/cli v29.2.0-rc.1.0.20251223174200-874b831c0e49+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.9.5 h1:EFNN8DHvaiK8zVqFA2DT6BjXE0GzfLOZ38ggPTKePkY= -github.com/docker/docker-credential-helpers v0.9.5/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c= +github.com/docker/docker-credential-helpers v0.9.4 h1:76ItO69/AP/V4yT9V4uuuItG0B1N8hvt0T0c0NN/DzI= +github.com/docker/docker-credential-helpers v0.9.4/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c= github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= @@ -480,8 +480,8 @@ github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw= github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= -github.com/ghostiam/protogetter v0.3.19 h1:yGoXYWL66F41FZqwEvjSnS3ghbUhKbpJgzKpmOOMovU= -github.com/ghostiam/protogetter v0.3.19/go.mod h1:FjIu5Yfs6FT391m+Fjp3fbAYJ6rkL/J6ySpZBfnODuI= +github.com/ghostiam/protogetter v0.3.18 h1:yEpghRGtP9PjKvVXtEzGpYfQj1Wl/ZehAfU6fr62Lfo= +github.com/ghostiam/protogetter v0.3.18/go.mod h1:FjIu5Yfs6FT391m+Fjp3fbAYJ6rkL/J6ySpZBfnODuI= github.com/github/smimesign v0.2.0 h1:Hho4YcX5N1I9XNqhq0fNx0Sts8MhLonHd+HRXVGNjvk= github.com/github/smimesign v0.2.0/go.mod h1:iZiiwNT4HbtGRVqCQu7uJPEZCuEE5sfSSttcnePkDl4= github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs= @@ -595,8 +595,8 @@ github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQi github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ= github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus= github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= -github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= -github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-xmlfmt/xmlfmt v1.1.3 h1:t8Ey3Uy7jDSEisW2K3somuMKIpzktkWptA0iFCnRUWY= github.com/go-xmlfmt/xmlfmt v1.1.3/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= @@ -618,8 +618,8 @@ github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzw github.com/golang-jwt/jwt/v4 v4.5.0/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.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= -github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= +github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= 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/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= @@ -703,8 +703,8 @@ github.com/goreleaser/fileglob v1.4.0 h1:Y7zcUnzQjT1gbntacGAkIIfLv+OwojxTXBFxjSF github.com/goreleaser/fileglob v1.4.0/go.mod h1:1pbHx7hhmJIxNZvm6fi6WVrnP0tndq6p3ayWdLn1Yf8= github.com/goreleaser/goreleaser/v2 v2.13.3 h1:S8d13YgzzFXxoUJ9NJInuyq3lPNCXTcuW8wSvM+rXnQ= github.com/goreleaser/goreleaser/v2 v2.13.3/go.mod h1:Rj+yhhXrO6WHc6cNh1GggpxzhhHXv9lczL5M4cSV3oA= -github.com/goreleaser/nfpm/v2 v2.44.2 h1:h1DLjxoxlA85qru1IsRrqbJw51DLJ64kAiWmlPQ3zaA= -github.com/goreleaser/nfpm/v2 v2.44.2/go.mod h1:O0h9bB68D39NTnM9rSOJhVCYxQk7sU8i04q2bzczFdk= +github.com/goreleaser/nfpm/v2 v2.44.1 h1:g+QNjkEx+C2Zu8dB48t9da/VfV0CWS5TMjxT8HG1APY= +github.com/goreleaser/nfpm/v2 v2.44.1/go.mod h1:drIYLqkla9SaOLbSnaFOmSIv5LXGfhHcbK54st97b4s= github.com/goreleaser/quill v0.0.0-20251224035235-ab943733386f h1:2HQF/pifDK7XnmVhQi3OecdUcHLOaXIKVKscW8qKzCk= github.com/goreleaser/quill v0.0.0-20251224035235-ab943733386f/go.mod h1:Xp6aA14QqdPBg7UHToFag7mrjsV7XaKEpw1t6fDfT6M= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= @@ -725,8 +725,8 @@ github.com/gostaticanalysis/testutil v0.5.0 h1:Dq4wT1DdTwTGCQQv3rl3IvD5Ld0E6HiY+ github.com/gostaticanalysis/testutil v0.5.0/go.mod h1:OLQSbuM6zw2EvCcXTz1lVq5unyoNft372msDY0nY5Hs= 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/grpc-gateway/v2 v2.27.6 h1:1ufTZkFXIQQ9EmgPjcIPIi2krfxG03lQ8OLoY1MJ3UM= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.6/go.mod h1:lW34nIZuQ8UDPdkon5fmfp2l3+ZkQ2me/+oecHYLOII= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -770,16 +770,16 @@ github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/in-toto/attestation v1.1.2 h1:MBFn6lsMq6dptQZJBhalXTcWMb/aJy3V+GX3VYj/V1E= github.com/in-toto/attestation v1.1.2/go.mod h1:gYFddHMZj3DiQ0b62ltNi1Vj5rC879bTmBbrv9CRHpM= -github.com/in-toto/in-toto-golang v0.10.0 h1:+s2eZQSK3WmWfYV85qXVSBfqgawi/5L02MaqA4o/tpM= -github.com/in-toto/in-toto-golang v0.10.0/go.mod h1:wjT4RiyFlLWCmLUJjwB8oZcjaq7HA390aMJcD3xXgmg= +github.com/in-toto/in-toto-golang v0.9.0 h1:tHny7ac4KgtsfrG6ybU8gVOZux2H8jN05AXJ9EBM1XU= +github.com/in-toto/in-toto-golang v0.9.0/go.mod h1:xsBVrVsHNsB61++S6Dy2vWosKhuA3lUTQd+eF9HdeMo= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E= github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/boxo v0.36.0 h1:DarrMBM46xCs6GU6Vz+AL8VUyXykqHAqZYx8mR0Oics= -github.com/ipfs/boxo v0.36.0/go.mod h1:92hnRXfP5ScKEIqlq9Ns7LR1dFXEVADKWVGH0fjk83k= +github.com/ipfs/boxo v0.34.0 h1:pMP9bAsTs4xVh8R0ZmxIWviV7kjDa60U24QrlGgHb1g= +github.com/ipfs/boxo v0.34.0/go.mod h1:kzdH/ewDybtO3+M8MCVkpwnIIc/d2VISX95DFrY4vQA= github.com/ipfs/go-block-format v0.2.3 h1:mpCuDaNXJ4wrBJLrtEaGFGXkferrw5eqVvzaHhtFKQk= github.com/ipfs/go-block-format v0.2.3/go.mod h1:WJaQmPAKhD3LspLixqlqNFxiZ3BZ3xgqxxoSR/76pnA= github.com/ipfs/go-cid v0.6.0 h1:DlOReBV1xhHBhhfy/gBNNTSyfOM6rLiIx9J7A4DGf30= @@ -801,8 +801,8 @@ github.com/ipfs/go-ipld-format v0.6.3/go.mod h1:74ilVN12NXVMIV+SrBAyC05UJRk0jVvG github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8= github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo= github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= -github.com/ipfs/go-log/v2 v2.9.1 h1:3JXwHWU31dsCpvQ+7asz6/QsFJHqFr4gLgQ0FWteujk= -github.com/ipfs/go-log/v2 v2.9.1/go.mod h1:evFx7sBiohUN3AG12mXlZBw5hacBQld3ZPHrowlJYoo= +github.com/ipfs/go-log/v2 v2.9.0 h1:l4b06AwVXwldIzbVPZy5z7sKp9lHFTX0KWfTBCtHaOk= +github.com/ipfs/go-log/v2 v2.9.0/go.mod h1:UhIYAwMV7Nb4ZmihUxfIRM2Istw/y9cAk3xaK+4Zs2c= github.com/ipfs/go-metrics-interface v0.3.0 h1:YwG7/Cy4R94mYDUuwsBfeziJCVm9pBMJ6q/JR9V40TU= github.com/ipfs/go-metrics-interface v0.3.0/go.mod h1:OxxQjZDGocXVdyTPocns6cOLwHieqej/jos7H4POwoY= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= @@ -849,8 +849,8 @@ github.com/kisielk/errcheck v1.9.0/go.mod h1:kQxWMMVZgIkDq7U8xtG/n2juOjbLgZtedi0 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkHAIKE/contextcheck v1.1.6 h1:7HIyRcnyzxL9Lz06NGhiKvenXq7Zw6Q0UQu/ttjfJCE= github.com/kkHAIKE/contextcheck v1.1.6/go.mod h1:3dDbMRNBFaq8HFXWC1JyvDSPm43CmE6IuHam8Wr0rkg= -github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw= -github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= +github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= @@ -867,8 +867,8 @@ github.com/knadh/koanf/providers/posflag v1.0.1 h1:EnMxHSrPkYCFnKgBUl5KBgrjed8gV github.com/knadh/koanf/providers/posflag v1.0.1/go.mod h1:3Wn3+YG3f4ljzRyCUgIwH7G0sZ1pMjCOsNBovrbKmAk= github.com/knadh/koanf/providers/structs v1.0.0 h1:DznjB7NQykhqCar2LvNug3MuxEQsZ5KvfgMbio+23u4= github.com/knadh/koanf/providers/structs v1.0.0/go.mod h1:kjo5TFtgpaZORlpoJqcbeLowM2cINodv8kX+oFAeQ1w= -github.com/knadh/koanf/v2 v2.3.2 h1:Ee6tuzQYFwcZXQpc2MiVeC6qHMandf5SMUJJNoFp/c4= -github.com/knadh/koanf/v2 v2.3.2/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28= +github.com/knadh/koanf/v2 v2.3.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= +github.com/knadh/koanf/v2 v2.3.0/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -1004,8 +1004,8 @@ github.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhK github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs= github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= -github.com/nunnatsa/ginkgolinter v0.22.0 h1:o9g7JN6efdBxAHhejvPkodEjWsOBze9zDnPePsvC/Qg= -github.com/nunnatsa/ginkgolinter v0.22.0/go.mod h1:zIFAk36fhcHQIiYOGXLbrGTXz7cvpufhRYem6ToCVnY= +github.com/nunnatsa/ginkgolinter v0.21.2 h1:khzWfm2/Br8ZemX8QM1pl72LwM+rMeW6VUbQ4rzh0Po= +github.com/nunnatsa/ginkgolinter v0.21.2/go.mod h1:GItSI5fw7mCGLPmkvGYrr1kEetZe7B593jcyOpyabsY= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo/v2 v2.27.5 h1:ZeVgZMx2PDMdJm/+w5fE/OyG6ILo1Y3e+QX4zSR0zTE= @@ -1129,8 +1129,8 @@ github.com/sigstore/protobuf-specs v0.5.0 h1:F8YTI65xOHw70NrvPwJ5PhAzsvTnuJMGLkA github.com/sigstore/protobuf-specs v0.5.0/go.mod h1:+gXR+38nIa2oEupqDdzg4qSBT0Os+sP7oYv6alWewWc= github.com/sigstore/rekor v1.5.0 h1:rL7SghHd5HLCtsCrxw0yQg+NczGvM75EjSPPWuGjaiQ= github.com/sigstore/rekor v1.5.0/go.mod h1:D7JoVCUkxwQOpPDNYeu+CE8zeBC18Y5uDo6tF8s2rcQ= -github.com/sigstore/rekor-tiles/v2 v2.1.0 h1:lSxhMwVYkMsCok2rFKU3eRJXz7ppTkLEVjUnH+g8aZY= -github.com/sigstore/rekor-tiles/v2 v2.1.0/go.mod h1:qRw4VXl35azi8ENjSWbdmGtzdviLd7H08fDcp5C+97Y= +github.com/sigstore/rekor-tiles/v2 v2.0.1 h1:1Wfz15oSRNGF5Dzb0lWn5W8+lfO50ork4PGIfEKjZeo= +github.com/sigstore/rekor-tiles/v2 v2.0.1/go.mod h1:Pjsbhzj5hc3MKY8FfVTYHBUHQEnP0ozC4huatu4x7OU= github.com/sigstore/sigstore v1.10.4 h1:ytOmxMgLdcUed3w1SbbZOgcxqwMG61lh1TmZLN+WeZE= github.com/sigstore/sigstore v1.10.4/go.mod h1:tDiyrdOref3q6qJxm2G+JHghqfmvifB7hw+EReAfnbI= github.com/sigstore/sigstore-go v1.1.4 h1:wTTsgCHOfqiEzVyBYA6mDczGtBkN7cM8mPpjJj5QvMg= @@ -1143,11 +1143,11 @@ github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.10.3 h1:AVWs0E6rVZMoDTE0Iy github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.10.3/go.mod h1:nxQYF0D6u7mVtiP1azj1YVDIrtz7S0RYCVTqUG8IcCk= github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.10.3 h1:lJSdaC/aOlFHlvqmmV696n1HdXLMLEKGwpNZMV0sKts= github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.10.3/go.mod h1:b2rV9qPbt/jv/Yy75AIOZThP8j+pe1ZdLEjOwmjPdoA= -github.com/sigstore/timestamp-authority/v2 v2.0.4 h1:65IBa4LUeFWDQu9hiTt5lBpi/F5jonJWZtH6VLn4InU= -github.com/sigstore/timestamp-authority/v2 v2.0.4/go.mod h1:EXJLiMDBqRPlzC02hPiFSiYTCqSuUpU68a4vr0DFePM= +github.com/sigstore/timestamp-authority/v2 v2.0.3 h1:sRyYNtdED/ttLCMdaYnwpf0zre1A9chvjTnCmWWxN8Y= +github.com/sigstore/timestamp-authority/v2 v2.0.3/go.mod h1:mDaHxkt3HmZYoIlwYj4QWo0RUr7VjYU52aVO5f5Qb3I= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= -github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE= github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= github.com/skeema/knownhosts v1.3.2 h1:EDL9mgf4NzwMXCTfaxSD/o/a5fxDw/xL9nkU28JjdBg= @@ -1193,6 +1193,7 @@ github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+Q github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= @@ -1220,16 +1221,16 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= -github.com/timakin/bodyclose v0.0.0-20260129054331-73d1f95b84b4 h1:SiHe5XLTn9sFWJ5pBwJ5FN/4j34q9ZlOAD//kMoMYp0= -github.com/timakin/bodyclose v0.0.0-20260129054331-73d1f95b84b4/go.mod h1:sDHLK7rb/59v/ZxZ7KtymgcoxuUMxjXq8gtu9VMOK8M= +github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 h1:9LPGD+jzxMlnk5r6+hJnar67cgpDIz/iyD+rfl5r2Vk= +github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67/go.mod h1:mkjARE7Yr8qU23YcGMSALbIxTQ9r9QBVahQOBRfU460= github.com/timonwong/loggercheck v0.11.0 h1:jdaMpYBl+Uq9mWPXv1r8jc5fC3gyXx4/WGwTnnNKn4M= github.com/timonwong/loggercheck v0.11.0/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8= github.com/tink-crypto/tink-go-awskms/v2 v2.1.0 h1:N9UxlsOzu5mttdjhxkDLbzwtEecuXmlxZVo/ds7JKJI= github.com/tink-crypto/tink-go-awskms/v2 v2.1.0/go.mod h1:PxSp9GlOkKL9rlybW804uspnHuO9nbD98V/fDX4uSis= github.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0 h1:3B9i6XBXNTRspfkTC0asN5W0K6GhOSgcujNiECNRNb0= github.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0/go.mod h1:jY5YN2BqD/KSCHM9SqZPIpJNG/u3zwfLXHgws4x2IRw= -github.com/tink-crypto/tink-go-hcvault/v2 v2.4.0 h1:j+S+WKBQ5ya26A5EM/uXoVe+a2IaPQN8KgBJZ22cJ+4= -github.com/tink-crypto/tink-go-hcvault/v2 v2.4.0/go.mod h1:OCKJIujnTzDq7f+73NhVs99oA2c1TR6nsOpuasYM6Yo= +github.com/tink-crypto/tink-go-hcvault/v2 v2.3.0 h1:6nAX1aRGnkg2SEUMwO5toB2tQkP0Jd6cbmZ/K5Le1V0= +github.com/tink-crypto/tink-go-hcvault/v2 v2.3.0/go.mod h1:HOC5NWW1wBI2Vke1FGcRBvDATkEYE7AUDiYbXqi2sBw= github.com/tink-crypto/tink-go/v2 v2.6.0 h1:+KHNBHhWH33Vn+igZWcsgdEPUxKwBMEe0QC60t388v4= github.com/tink-crypto/tink-go/v2 v2.6.0/go.mod h1:2WbBA6pfNsAfBwDCggboaHeB2X29wkU8XHtGwh2YIk8= github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0= @@ -1240,8 +1241,8 @@ github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+ github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= github.com/tomnomnom/linkheader v0.0.0-20250811210735-e5fe3b51442e h1:tD38/4xg4nuQCASJ/JxcvCHNb46w0cdAaJfkzQOO1bA= github.com/tomnomnom/linkheader v0.0.0-20250811210735-e5fe3b51442e/go.mod h1:krvJ5AY/MjdPkTeRgMYbIDhbbbVvnPQPzsIsDJO8xrY= -github.com/transparency-dev/formats v0.0.0-20260126105629-a1e81f2894be h1:JfUkmUSwqyTs2ziQDQN45dQhxM+t+XCDLPiw2VtF12k= -github.com/transparency-dev/formats v0.0.0-20260126105629-a1e81f2894be/go.mod h1:d2FibUOHfCMdCe/+/rbKt1IPLBbPTDfwj46kt541/mU= +github.com/transparency-dev/formats v0.0.0-20251208091212-1378f9e1b1b7 h1:PwfIAvobqihWBi1/KIsw0IzTEJ89rYJqmXfzmqacySw= +github.com/transparency-dev/formats v0.0.0-20251208091212-1378f9e1b1b7/go.mod h1:mQ5ASe7MNPT+yRc47hLguwsNdE2Go0mT6piyzUO+ynw= github.com/transparency-dev/merkle v0.0.2 h1:Q9nBoQcZcgPamMkGn7ghV8XiTZ/kRxn1yCG81+twTK4= github.com/transparency-dev/merkle v0.0.2/go.mod h1:pqSy+OXefQ1EDUVmAJ8MUhHB9TXGuzVAT58PqBoHz1A= github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= @@ -1319,12 +1320,12 @@ go-simpler.org/musttag v0.14.0 h1:XGySZATqQYSEV3/YTy+iX+aofbZZllJaqwFWs+RTtSo= go-simpler.org/musttag v0.14.0/go.mod h1:uP8EymctQjJ4Z1kUnjX0u2l60WfUdQxCwSNKzE1JEOE= go-simpler.org/sloglint v0.11.1 h1:xRbPepLT/MHPTCA6TS/wNfZrDzkGvCCqUv4Bdwc3H7s= go-simpler.org/sloglint v0.11.1/go.mod h1:2PowwiCOK8mjiF+0KGifVOT8ZsCNiFzvfyJeJOIt8MQ= -go.augendre.info/arangolint v0.4.0 h1:xSCZjRoS93nXazBSg5d0OGCi9APPLNMmmLrC995tR50= -go.augendre.info/arangolint v0.4.0/go.mod h1:l+f/b4plABuFISuKnTGD4RioXiCCgghv2xqst/xOvAA= +go.augendre.info/arangolint v0.3.1 h1:n2E6p8f+zfXSFLa2e2WqFPp4bfvcuRdd50y6cT65pSo= +go.augendre.info/arangolint v0.3.1/go.mod h1:6ZKzEzIZuBQwoSvlKT+qpUfIbBfFCE5gbAoTg0/117g= go.augendre.info/fatcontext v0.9.0 h1:Gt5jGD4Zcj8CDMVzjOJITlSb9cEch54hjRRlN3qDojE= go.augendre.info/fatcontext v0.9.0/go.mod h1:L94brOAT1OOUNue6ph/2HnwxoNlds9aXDF2FcUntbNw= -go.mongodb.org/mongo-driver v1.17.7 h1:a9w+U3Vt67eYzcfq3k/OAv284/uUUkL0uP75VE5rCOU= -go.mongodb.org/mongo-driver v1.17.7/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= +go.mongodb.org/mongo-driver v1.17.6 h1:87JUG1wZfWsr6rIz3ZmpH90rL5tea7O3IHuSwHUpsss= +go.mongodb.org/mongo-driver v1.17.6/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/bridges/prometheus v0.63.0 h1:/Rij/t18Y7rUayNg7Id6rPrEnHgorxYabm2E6wUdPP4= @@ -1351,16 +1352,16 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNl go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 h1:bDMKF3RUSxshZ5OjOTi8rsHGaPKsAt76FaqgvIUySLc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0/go.mod h1:dDT67G/IkA46Mr2l9Uj7HsQVwsjASyV9SjGofsiUZDA= go.opentelemetry.io/otel/exporters/prometheus v0.61.0 h1:cCyZS4dr67d30uDyh8etKM2QyDsQ4zC9ds3bdbrVoD0= go.opentelemetry.io/otel/exporters/prometheus v0.61.0/go.mod h1:iivMuj3xpR2DkUrUya3TPS/Z9h3dz7h01GxU+fQBRNg= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 h1:B/g+qde6Mkzxbry5ZZag0l7QrQBCtVm7lVjaLgmpje8= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0/go.mod h1:mOJK8eMmgW6ocDJn6Bn11CcZ05gi3P8GylBXEkZtbgA= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.37.0 h1:SNhVp/9q4Go/XHBkQ1/d5u9P/U+L1yaGPoi0x+mStaI= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.37.0/go.mod h1:tx8OOlGH6R4kLV67YaYO44GFXloEjGPZuMjEkaaqIp4= go.opentelemetry.io/otel/log v0.14.0 h1:2rzJ+pOAZ8qmZ3DDHg73NEKzSZkhkGIua9gXtxNGgrM= go.opentelemetry.io/otel/log v0.14.0/go.mod h1:5jRG92fEAgx0SU/vFPxmJvhIuDU9E1SUnEQrMlJpOno= go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= @@ -1408,15 +1409,17 @@ golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +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.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= -golang.org/x/exp v0.0.0-20260112195511-716be5621a96 h1:Z/6YuSHTLOHfNFdb8zVZomZr7cqNgTJvA8+Qz75D8gU= -golang.org/x/exp v0.0.0-20260112195511-716be5621a96/go.mod h1:nzimsREAkjBCIEFtHiYkrJyT+2uy9YZJB7H1k68CXZU= +golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0= +golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/exp/typeparams v0.0.0-20260112195511-716be5621a96 h1:RMc8anw0hCPcg5CZYN2PEQ8nMwosk461R6vFwPrCFVg= -golang.org/x/exp/typeparams v0.0.0-20260112195511-716be5621a96/go.mod h1:4Mzdyp/6jzw9auFDJ3OMF5qksa7UvPnzKqTVGcb04ms= +golang.org/x/exp/typeparams v0.0.0-20251219203646-944ab1f22d93 h1:PbC785RGO6yPO051ItgbG/adwoKRWC0VS7kXXeD/iqk= +golang.org/x/exp/typeparams v0.0.0-20251219203646-944ab1f22d93/go.mod h1:4Mzdyp/6jzw9auFDJ3OMF5qksa7UvPnzKqTVGcb04ms= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -1426,6 +1429,8 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -1441,6 +1446,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= @@ -1452,6 +1459,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/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.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1477,6 +1486,7 @@ 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.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.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= @@ -1484,6 +1494,8 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +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.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= @@ -1494,6 +1506,7 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +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.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= @@ -1516,6 +1529,8 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= @@ -1528,8 +1543,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= -gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= -gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/api v0.263.0 h1:UFs7qn8gInIdtk1ZA6eXRXp5JDAnS4x9VRsRVCeKdbk= google.golang.org/api v0.263.0/go.mod h1:fAU1xtNNisHgOF5JooAs8rRaTkl2rT3uaoNGo9NS3R8= google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 h1:VQZ/yAbAtjkHgH80teYd2em3xtIkkHd7ZhqfH2N9CsM= From b73c0f115da25e4c89475ec2e972d0a50cfa7cf9 Mon Sep 17 00:00:00 2001 From: siherrmann <25087590+siherrmann@users.noreply.github.com> Date: Fri, 30 Jan 2026 10:02:00 +0000 Subject: [PATCH 12/12] chore(docs): Auto-update docs and licenses Signed-off-by: siherrmann <25087590+siherrmann@users.noreply.github.com> --- NOTICE | 8 ++++---- internal/tmpl/NOTICE | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/NOTICE b/NOTICE index 7a7191e0..641c2d98 100644 --- a/NOTICE +++ b/NOTICE @@ -401,15 +401,15 @@ License URL: https://cs.opensource.google/go/x/time/+/v0.14.0:LICENSE ---------- Module: google.golang.org/api -Version: v0.263.0 +Version: v0.264.0 License: BSD-3-Clause -License URL: https://github.com/googleapis/google-api-go-client/blob/v0.263.0/LICENSE +License URL: https://github.com/googleapis/google-api-go-client/blob/v0.264.0/LICENSE ---------- Module: google.golang.org/api/internal/third_party/uritemplates -Version: v0.263.0 +Version: v0.264.0 License: BSD-3-Clause -License URL: https://github.com/googleapis/google-api-go-client/blob/v0.263.0/internal/third_party/uritemplates/LICENSE +License URL: https://github.com/googleapis/google-api-go-client/blob/v0.264.0/internal/third_party/uritemplates/LICENSE ---------- Module: google.golang.org/genproto/googleapis diff --git a/internal/tmpl/NOTICE b/internal/tmpl/NOTICE index 7a7191e0..641c2d98 100644 --- a/internal/tmpl/NOTICE +++ b/internal/tmpl/NOTICE @@ -401,15 +401,15 @@ License URL: https://cs.opensource.google/go/x/time/+/v0.14.0:LICENSE ---------- Module: google.golang.org/api -Version: v0.263.0 +Version: v0.264.0 License: BSD-3-Clause -License URL: https://github.com/googleapis/google-api-go-client/blob/v0.263.0/LICENSE +License URL: https://github.com/googleapis/google-api-go-client/blob/v0.264.0/LICENSE ---------- Module: google.golang.org/api/internal/third_party/uritemplates -Version: v0.263.0 +Version: v0.264.0 License: BSD-3-Clause -License URL: https://github.com/googleapis/google-api-go-client/blob/v0.263.0/internal/third_party/uritemplates/LICENSE +License URL: https://github.com/googleapis/google-api-go-client/blob/v0.264.0/internal/third_party/uritemplates/LICENSE ---------- Module: google.golang.org/genproto/googleapis