File ksctl-2.8.0.obscpio of Package ksctl

07070100000000000081A40000000000000000000000016818E78D000005FE000000000000000000000000000000000000001D00000000ksctl-2.8.0/.goreleaser.yaml# This is an example .goreleaser.yml file with some sensible defaults.
# Make sure to check the documentation at https://goreleaser.com

# The lines below are called `modelines`. See `:help modeline`
# Feel free to remove those if you don't want/need to use them.
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
# vim: set ts=2 sw=2 tw=0 fo=cnqoj

version: 2

project_name: ksctl-cli

before:
  hooks:
    - go mod tidy

builds:
  - env:
      - CGO_ENABLED=0
    binary: ksctl
    goos:
      - linux
      - darwin
    goarch:
      - amd64
      - arm64
    ldflags:
      - -s -w -X "github.com/ksctl/cli/v2/pkg/config.BuildDate={{.Env.DATE}}"
      - -s -w -X "github.com/ksctl/cli/v2/pkg/config.Version={{.Env.VERSION}}"
      - -s -w -X "github.com/ksctl/cli/v2/pkg/config.KsctlCoreVer={{.Env.OCIVERSION}}"
      - -s -w -X "github.com/ksctl/cli/v2/pkg/telemetry.clientIdentity={{.Env.CLI_IDENTITY}}"

signs:
  - cmd: cosign
    certificate: '${artifact}.cert'
    args:
      - sign-blob
      - '--output-certificate=${certificate}'
      - '--output-signature=${signature}'
      - '${artifact}'
      - --yes
    artifacts: all
    output: true

changelog:
  sort: asc
  filters:
    exclude:
      - "^scripts:"
      - "^gen:"

release:
  draft: true
  make_latest: true
  header: >-
    # 🚀 Changelog

    This release contains a number of enhancements and bug fixes. For a full list of changes

  footer: >-

    ---

    Released by [GoReleaser](https://github.com/goreleaser/goreleaser).
07070100000001000081A40000000000000000000000016818E78D0000038A000000000000000000000000000000000000002400000000ksctl-2.8.0/.pre-commit-config.yamlrepos:
  - repo: local
    hooks:
      - id: add-license
        name: Add License Headers
        entry: addlicense
        language: system
        types: [go]
        args: ["-c", "Ksctl Authors"]

      - id: go-fmt
        name: go fmt
        entry: gofmt -l -w .
        language: system
        types: [go]

      - id: go-vet
        name: go vet
        entry: go vet ./...
        language: system
        types: [go]
        pass_filenames: false

      - id: go-mod-tidy
        name: go mod tidy
        entry: go mod tidy
        language: system
        pass_filenames: false

  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v5.0.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-added-large-files
      - id: mixed-line-ending
      - id: check-merge-conflict
      - id: check-executables-have-shebangs
07070100000002000081A40000000000000000000000016818E78D00001459000000000000000000000000000000000000001F00000000ksctl-2.8.0/CODE_OF_CONDUCT.md# Contributor Covenant Code of Conduct

## Our Pledge

We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.

We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.

## Our Standards

Examples of behavior that contributes to a positive environment for our
community include:

* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
  and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
  overall community

Examples of unacceptable behavior include:

* The use of sexualized language or imagery, and sexual attention or
  advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
  address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Enforcement Responsibilities

Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.

Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.

## Scope

This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
Discord.
All complaints will be reviewed and investigated promptly and fairly.

All community leaders are obligated to respect the privacy and security of the
reporter of any incident.

## Enforcement Guidelines

Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:

### 1. Correction

**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.

**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.

### 2. Warning

**Community Impact**: A violation through a single incident or series
of actions.

**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.

### 3. Temporary Ban

**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.

**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.

### 4. Permanent Ban

**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior,  harassment of an
individual, or aggression toward or disparagement of classes of individuals.

**Consequence**: A permanent ban from any sort of public interaction within
the community.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.

Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
07070100000003000081A40000000000000000000000016818E78D00000057000000000000000000000000000000000000001C00000000ksctl-2.8.0/CONTRIBUTING.mdThe contents are moved to [docs](https://docs.ksctl.com/docs/contribution-guidelines/)
07070100000004000081A40000000000000000000000016818E78D00002C5D000000000000000000000000000000000000001400000000ksctl-2.8.0/LICENSE                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
07070100000005000081A40000000000000000000000016818E78D00000099000000000000000000000000000000000000001B00000000ksctl-2.8.0/MAINTAINERS.mdPlease refer to [MAINTAINERS.md](https://github.com/ksctl/community/blob/main/MAINTAINERS.md) for more information on how to contribute to this project.
07070100000006000081A40000000000000000000000016818E78D00000AF3000000000000000000000000000000000000001500000000ksctl-2.8.0/MakefileGOOS_LINUX = linux
GOOS_MACOS = darwin

GOARCH_LINUX ?= amd64
GOARCH_MACOS = arm64
GOARCH_MACOS_INTEL = amd64

CURR_TIME = $(shell date +%s)

.PHONY: help
help: ## Display this help.
	@awk 'BEGIN {FS = ":.*##"; printf "\n\033[36m  _             _   _ \n | |           | | | |\n | | _____  ___| |_| |\n | |/ / __|/ __| __| |\n |   <\\__ \\ (__| |_| |\n |_|\\_\\___/\\___|\\__|_| \033[0m\n\nUsage:\n  make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf "  \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)

##@ Generate
.PHONY: gen-docs
gen-docs: ## Generates docs
	go run gen/docs.go

##@ Install (Dev)

.PHONY: install_linux
install_linux:  ## Install ksctl
	@echo "Started to Install ksctl"
	cd scripts && \
		env GOOS=${GOOS_LINUX} GOARCH=${GOARCH_LINUX} ./builder.sh

.PHONY: install_macos
install_macos: ## Install ksctl on macos m1,m2,..
	@echo "Started to Install ksctl"
	cd scripts && \
		env GOOS=${GOOS_MACOS} GOARCH=${GOARCH_MACOS} ./builder.sh

.PHONY: install_macos_intel
install_macos_intel: ## Install ksctl on macos intel
	@echo "Started to Install ksctl"
	cd scripts && \
		env GOOS=${GOOS_MACOS} GOARCH=${GOARCH_MACOS_INTEL} ./builder.sh

.PHONY: uninstall
uninstall:  ## Uninstall ksctl
	@echo "Started to Uninstall ksctl"
	cd scripts && \
		./uninstall.sh

##@ Linters
.PHONY: golangci-lint
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
$(GOLANGCI_LINT): $(LOCALBIN)
	$(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,${GOLANGCI_LINT_VERSION})

.PHONY: lint
lint: golangci-lint ## Run golangci-lint linter & yamllint
		$(GOLANGCI_LINT) run && echo -e "\n=========\n\033[91m✔ PASSED\033[0m\n=========\n" || echo -e "\n=========\n\033[91m✖ FAILED\033[0m\n=========\n"


##@ Dependencies

## Location to install dependencies to
LOCALBIN ?= /tmp/bin
$(LOCALBIN):
	mkdir -p $(LOCALBIN)

## Tool Binaries
GOLANGCI_LINT = $(LOCALBIN)/golangci-lint-$(GOLANGCI_LINT_VERSION)

## Tool Versions
GOLANGCI_LINT_VERSION ?= v1.54.2

.PHONY: golangci-lint
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
$(GOLANGCI_LINT): $(LOCALBIN)
	$(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,${GOLANGCI_LINT_VERSION})

# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist
# $1 - target path with name of binary (ideally with version)
# $2 - package url which can be installed
# $3 - specific version of package
define go-install-tool
@[ -f $(1) ] || { \
set -e; \
package=$(2)@$(3) ;\
echo "Downloading $${package}" ;\
GOBIN=$(LOCALBIN) go install $${package} ;\
mv "$$(echo "$(1)" | sed "s/-$(3)$$//")" $(1) ;\
}
endef
07070100000007000081A40000000000000000000000016818E78D000005E0000000000000000000000000000000000000001600000000ksctl-2.8.0/README.md![CoverPage Social Media](https://github.com/ksctl/ksctl/raw/main/img/cover.svg)

# Ksctl CLI

It utilizes [Ksctl](https://github.com/ksctl/ksctl) and builds on top to provide Command Line user experience

[![Go Report Card](https://goreportcard.com/badge/github.com/ksctl/cli)](https://goreportcard.com/report/github.com/ksctl/cli) [![](https://pkg.go.dev/badge/github.com/ksctl/cli.svg)](https://pkg.go.dev/github.com/ksctl/cli) [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/7469/badge)](https://www.bestpractices.dev/projects/7469)

![](https://img.shields.io/github/license/ksctl/cli?style=for-the-badge) ![](https://img.shields.io/github/issues/ksctl/cli?style=for-the-badge) ![](https://img.shields.io/github/forks/ksctl/cli?style=for-the-badge)


## All Repositories under (Ksctl Org)
Repo | Description
-|-
[Ksctl](https://github.com/ksctl/ksctl) | It provides the core components aka the internals of ksctl features
[Ksctl CLI](https://github.com/ksctl/cli) | It uses the ksctl repo to make a CLI tool
[Ksctl Docs](https://github.com/ksctl/docs) | It's for documentation purpose and to host the ksctl website

## Getting Started guide

[Getting Started guide](https://docs.ksctl.com/docs/getting-started/)

## Usage

Please refer to the [CLI Reference guide](https://docs.ksctl.com/docs/reference/cli/)

## Contribution Guidelines
Please refer to our [contribution guide](https://docs.ksctl.com/docs/contribution-guidelines/) if you wish to contribute to the project :smile:
07070100000008000081A40000000000000000000000016818E78D00000159000000000000000000000000000000000000001800000000ksctl-2.8.0/SECURITY.md# Security Policy

## Supported Versions


| Version | Supported          |
| ------- | ------------------ |
| 1.0.1   | :white_check_mark: |
| < 1.0.0   | :x:                |

## Reporting a Vulnerability

Check [contribution guide](./CONTRIBUTING.md) and also [website contribution page](https://docs.ksctl.com/docs/contribution-guidelines/)
07070100000009000041ED0000000000000000000000026818E78D00000000000000000000000000000000000000000000001000000000ksctl-2.8.0/cmd0707010000000A000081A40000000000000000000000016818E78D00001899000000000000000000000000000000000000001A00000000ksctl-2.8.0/cmd/addons.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"fmt"
	"os"
	"strconv"
	"strings"

	"github.com/ksctl/cli/v2/pkg/cli"
	"github.com/ksctl/cli/v2/pkg/telemetry"
	"github.com/ksctl/ksctl/v2/pkg/handler/cluster/controller"

	addonsHandler "github.com/ksctl/ksctl/v2/pkg/handler/addons"
	"github.com/spf13/cobra"
)

func (k *KsctlCommand) Addons() *cobra.Command {

	cmd := &cobra.Command{
		Use: "addons",
		Example: `
ksctl addons --help
`,
		Short: "Use to work with addons",
		Long:  "It is used to work with addons",
	}

	return cmd
}

func (k *KsctlCommand) EnableAddon() *cobra.Command {

	cmd := &cobra.Command{
		Use: "enable",
		Example: `
ksctl addons enable --help
`,
		Short: "Use to enable an addon",
		Long:  "It is used to enable an addon",
		Run: func(cmd *cobra.Command, args []string) {
			m, ok := k.addonClientSetup()
			if !ok {
				os.Exit(1)
			}

			if k.loadCloudProviderCreds(m.Provider) != nil {
				os.Exit(1)
			}

			c, err := addonsHandler.NewController(
				k.Ctx,
				k.l,
				&controller.Client{
					Metadata: *m,
				},
			)
			if err != nil {
				k.l.Error("Error in creating the controller", "Error", err)
				os.Exit(1)
			}

			addons, err := c.ListAllAddons()
			if err != nil {
				k.l.Error("Error in listing the addons", "Error", err)
				os.Exit(1)
			}

			addonSku, err := k.menuDriven.DropDownList(
				"Select the addon to enable",
				addons,
			)
			if err != nil {
				k.l.Error("Failed to get userinput", "Reason", err)
				os.Exit(1)
			}

			addonVers, err := c.ListAvailableVersions(addonSku)
			if err != nil {
				k.l.Error("Error in listing the versions", "Error", err)
				os.Exit(1)
			}

			addonVer, err := k.menuDriven.DropDownList(
				"Select the version to enable",
				addonVers,
				cli.WithDefaultValue(addonVers[0]),
			)
			if err != nil {
				k.l.Error("Failed to get userinput", "Reason", err)
				os.Exit(1)
			}

			if cc, err := c.GetAddon(addonSku); err != nil {
				k.l.Error("Error in getting the addon", "Error", err)
				os.Exit(1)
			} else {

				if err := k.telemetry.Send(k.Ctx, k.l, telemetry.EventClusterAddonEnable, telemetry.TelemetryMeta{
					Addons: []telemetry.TelemetryAddon{
						{
							Sku:     addonSku,
							Version: addonVer,
						},
					},
				}); err != nil {
					k.l.Debug(k.Ctx, "Failed to send the telemetry", "Reason", err)
				}

				if _err := cc.Install(addonVer); _err != nil {
					k.l.Error("Error in enabling the addon", "Error", _err)
					os.Exit(1)
				}
			}

			k.l.Success(k.Ctx, "Addon enabled successfully", "sku", addonSku, "version", addonVer)
		},
	}
	return cmd
}

func (k *KsctlCommand) DisableAddon() *cobra.Command {

	cmd := &cobra.Command{
		Use: "disable",
		Example: `
ksctl addons disable --help
`,
		Short: "Use to disable an addon",
		Long:  "It is used to disable an addon",
		Run: func(cmd *cobra.Command, args []string) {
			m, ok := k.addonClientSetup()
			if !ok {
				os.Exit(1)
			}

			if k.loadCloudProviderCreds(m.Provider) != nil {
				os.Exit(1)
			}

			c, err := addonsHandler.NewController(
				k.Ctx,
				k.l,
				&controller.Client{
					Metadata: *m,
				},
			)
			if err != nil {
				k.l.Error("Error in creating the controller", "Error", err)
				os.Exit(1)
			}

			addons, err := c.ListInstalledAddons()
			if err != nil {
				k.l.Error("Error in listing the installed addons", "Error", err)
				os.Exit(1)
			}

			vals := make(map[string]string, len(addons))
			for _, addon := range addons {
				ver := "NaN"
				if addon.Version != "" {
					ver = addon.Version
				}
				vals[fmt.Sprintf("%s@%s", addon.Name, ver)] = addon.Name + "@" + ver
			}

			_selectedAddon, err := k.menuDriven.DropDown(
				"Select the addon to disable",
				vals,
			)
			if err != nil {
				k.l.Error("Failed to get userinput", "Reason", err)
				os.Exit(1)
			}

			selectedAddon := strings.Split(_selectedAddon, "@")[0]

			if cc, err := c.GetAddon(selectedAddon); err != nil {
				k.l.Error("Error in getting the addon", "Error", err)
				os.Exit(1)
			} else {

				if err := k.telemetry.Send(k.Ctx, k.l, telemetry.EventClusterAddonDisable, telemetry.TelemetryMeta{
					Addons: []telemetry.TelemetryAddon{
						{
							Sku:     selectedAddon,
							Version: strings.Split(_selectedAddon, "@")[1],
						},
					},
				}); err != nil {
					k.l.Debug(k.Ctx, "Failed to send the telemetry", "Reason", err)
				}

				if _err := cc.Uninstall(); _err != nil {
					k.l.Error("Error in disabling the addon", "Error", _err)
					os.Exit(1)
				}
			}

			k.l.Success(k.Ctx, "Addon disabled successfully", "sku", selectedAddon)
		},
	}
	return cmd
}

func (k *KsctlCommand) addonClientSetup() (*controller.Metadata, bool) {
	clusters, err := k.fetchAllClusters()
	if err != nil {
		k.l.Error("Error in fetching the clusters", "Error", err)
		return nil, false
	}

	if len(clusters) == 0 {
		k.l.Error("No clusters found to delete")
		return nil, false
	}

	selectDisplay := make(map[string]string, len(clusters))
	valueMaping := make(map[string]controller.Metadata, len(clusters))

	for idx, cluster := range clusters {
		selectDisplay[makeHumanReadableList(cluster)] = strconv.Itoa(idx)
		valueMaping[strconv.Itoa(idx)] = controller.Metadata{
			ClusterName:   cluster.Name,
			ClusterType:   cluster.ClusterType,
			Provider:      cluster.CloudProvider,
			Region:        cluster.Region,
			StateLocation: k.KsctlConfig.PreferedStateStore,
			K8sDistro:     cluster.K8sDistro,
			K8sVersion:    cluster.K8sVersion,
		}
	}

	selectedCluster, err := k.menuDriven.DropDown(
		"Select the cluster for addon operation",
		selectDisplay,
	)
	if err != nil {
		k.l.Error("Failed to get userinput", "Reason", err)
		return nil, false
	}

	m := valueMaping[selectedCluster]
	return &m, true
}
0707010000000B000081A40000000000000000000000016818E78D0000086A000000000000000000000000000000000000001700000000ksctl-2.8.0/cmd/cli.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"context"
	"os"

	"github.com/ksctl/cli/v2/pkg/cli"
	"github.com/ksctl/cli/v2/pkg/config"
	cLogger "github.com/ksctl/cli/v2/pkg/logger"
	"github.com/ksctl/cli/v2/pkg/telemetry"
	"github.com/ksctl/ksctl/v2/pkg/consts"
	"github.com/ksctl/ksctl/v2/pkg/logger"
	"github.com/ksctl/ksctl/v2/pkg/provider"
	"github.com/ksctl/ksctl/v2/pkg/storage"
	"github.com/spf13/cobra"
)

type KsctlCommand struct {
	Ctx                     context.Context
	CliLog                  logger.Logger
	l                       logger.Logger
	ksctlStorage            storage.Storage
	root                    *cobra.Command
	verbose                 int
	debugMode               bool
	menuDriven              cli.MenuDriven
	KsctlConfig             *config.Config
	telemetry               *telemetry.Telemetry
	inMemInstanceTypesInReg provider.InstancesRegionOutput
}

func New() (*KsctlCommand, error) {
	k := new(KsctlCommand)
	k.KsctlConfig = new(config.Config)

	k.Ctx = context.WithValue(
		context.WithValue(
			context.Background(),
			consts.KsctlModuleNameKey,
			"cli",
		),
		consts.KsctlContextUserID,
		"cli",
	)

	k.root = k.NewRootCmd()

	k.CliLog = cLogger.NewLogger(0, os.Stdout)

	return k, nil
}

func (k *KsctlCommand) ForDocs() (*cobra.Command, error) {
	if err := k.CommandMapping(); err != nil {
		return nil, err
	}

	return k.root, nil
}

func (k *KsctlCommand) Execute() error {

	if err := config.LoadConfig(k.KsctlConfig); err != nil {
		return err
	}

	if err := k.CommandMapping(); err != nil {
		return err
	}

	return k.root.Execute()
}
0707010000000C000081A40000000000000000000000016818E78D000004A8000000000000000000000000000000000000001E00000000ksctl-2.8.0/cmd/completion.gopackage cmd

import (
	"fmt"
	"os"

	"github.com/spf13/cobra"
)

func (k *KsctlCommand) ShellCompletion() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "completion [bash|zsh|fish]",
		Short: "Generate shell completion scripts",
		Long: `To load completions:

Bash:

  $ source <(ksctl completion bash)

  # To load completions for each session, execute once:
  # Linux:
  $ ksctl completion bash > /etc/bash_completion.d/ksctl
  # macOS:
  $ ksctl completion bash > /usr/local/etc/bash_completion.d/ksctl

Zsh:

  $ echo "autoload -U compinit; compinit" >> ~/.zshrc
  $ ksctl completion zsh > "${fpath[1]}/_ksctl"

Fish:

  $ ksctl completion fish | source

  # To load completions for each session, execute once:
  $ ksctl completion fish > ~/.config/fish/completions/ksctl.fish
`,
		Args: cobra.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			switch args[0] {
			case "bash":
				return cmd.Root().GenBashCompletion(os.Stdout)
			case "zsh":
				return cmd.Root().GenZshCompletion(os.Stdout)
			case "fish":
				return cmd.Root().GenFishCompletion(os.Stdout, true)
			default:
				return fmt.Errorf("unsupported shell: %s", args[0])
			}
		},
	}

	return cmd
}
0707010000000D000081A40000000000000000000000016818E78D00001F02000000000000000000000000000000000000001D00000000ksctl-2.8.0/cmd/configure.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"context"
	"encoding/json"
	"os"
	"strconv"

	"github.com/fatih/color"
	"github.com/ksctl/cli/v2/pkg/cli"
	"github.com/ksctl/cli/v2/pkg/config"
	"github.com/ksctl/ksctl/v2/pkg/consts"
	"github.com/ksctl/ksctl/v2/pkg/statefile"
	"github.com/ksctl/ksctl/v2/pkg/utilities"
	"github.com/spf13/cobra"
)

func (k *KsctlCommand) Configure() *cobra.Command {

	cmd := &cobra.Command{
		Use: "configure",

		Short: "Configure ksctl cli",
		Long:  "It will display the current ksctl cli configuration",
		Run: func(cmd *cobra.Command, args []string) {
			headers := []string{"Property", "Value"}

			enabled := color.HiCyanString("✔")
			disabled := color.HiRedString("✘")
			telemetry := enabled

			if k.KsctlConfig.Telemetry != nil && !*k.KsctlConfig.Telemetry {
				telemetry = disabled
			}
			rows := [][]string{
				{"Storage Backend", string(k.KsctlConfig.PreferedStateStore)},
				{"Telemetry", telemetry},
			}

			if k.KsctlConfig.PreferedStateStore == consts.StoreExtMongo {
				if err := k.loadMongoCredentials(); err != nil {
					rows = append(rows, []string{"MongoDB 💾", disabled})
				} else {
					rows = append(rows, []string{"MongoDB 💾", enabled})
				}
			}

			if _, err := k.loadAwsCredentials(); err == nil {
				rows = append(rows, []string{"AWS ☁️", enabled})
			} else {
				rows = append(rows, []string{"AWS ☁️", disabled})
			}

			if _, err := k.loadAzureCredentials(); err == nil {
				rows = append(rows, []string{"Azure ☁️", enabled})
			} else {
				rows = append(rows, []string{"Azure ☁️", disabled})
			}

			k.l.Table(k.Ctx, headers, rows)
		},
	}

	return cmd
}

func (k *KsctlCommand) ConfigureStorage() *cobra.Command {
	cmd := &cobra.Command{
		Use: "storage",

		Short: "Configure storage",
		Long:  "It will help you to configure the storage",
		Run: func(cmd *cobra.Command, args []string) {
			if ok := k.handleStorageConfig(); !ok {
				os.Exit(1)
			}
		},
	}

	return cmd
}

func (k *KsctlCommand) ConfigureCloud() *cobra.Command {
	cmd := &cobra.Command{
		Use: "cloud",

		Short: "Configure cloud",
		Long:  "It will help you to configure the cloud",
		Run: func(cmd *cobra.Command, args []string) {
			if ok := k.handleCloudConfig(); !ok {
				os.Exit(1)
			}
		},
	}

	return cmd
}

func (k *KsctlCommand) ConfigureTelemetry() *cobra.Command {
	cmd := &cobra.Command{
		Use: "telemetry",

		Short: "Configure telemetry",
		Long:  "It will help you to configure the telemetry",
		Run: func(cmd *cobra.Command, args []string) {
			if v, err := k.menuDriven.Confirmation("Do you want to enable the telemetry?", cli.WithDefaultValue("yes")); err != nil {
				k.l.Error("Failed to get the telemetry status", "Reason", err)
				os.Exit(1)
			} else {
				k.KsctlConfig.Telemetry = utilities.Ptr(v)
				if err := config.SaveConfig(k.KsctlConfig); err != nil {
					k.l.Error("Failed to save the configuration", "Reason", err)
					os.Exit(1)
				}
			}
		},
	}

	return cmd
}

func (k *KsctlCommand) handleStorageConfig() bool {
	if v, err := k.menuDriven.DropDown(
		"What should be your default storageDriver?",
		map[string]string{
			"MongoDb": string(consts.StoreExtMongo),
			"Local":   string(consts.StoreLocal),
		},
		cli.WithDefaultValue("Local"),
	); err != nil {
		k.l.Error("Failed to get the storageDriver", "Reason", err)
		return false
	} else {
		k.KsctlConfig.PreferedStateStore = consts.KsctlStore(v)
		errL := config.SaveConfig(k.KsctlConfig)
		if errL != nil {
			k.l.Error("Failed to save the configuration", "Reason", errL)
			return false
		}

		if consts.KsctlStore(v) == consts.StoreExtMongo {
			k.l.Note(k.Ctx, "You need to provide the credentials for the MongoDB")
			if err := k.storeMongoCredentials(); err != nil {
				k.l.Error("Failed to store the MongoDB credentials", "Reason", err)
				return false
			}
		}
	}
	return true
}

func (k *KsctlCommand) handleCloudConfig() bool {
	if v, err := k.menuDriven.DropDown(
		"Credentials",
		map[string]string{
			"Amazon Web Services": string(consts.CloudAws),
			"Azure":               string(consts.CloudAzure),
		},
	); err != nil {
		k.l.Error("Failed to get the credentials", "Reason", err)
		return false
	} else {
		switch consts.KsctlCloud(v) {
		case consts.CloudAws:
			if err := k.storeAwsCredentials(); err != nil {
				k.l.Error("Failed to store the AWS credentials", "Reason", err)
				return false
			}
		case consts.CloudAzure:
			if err := k.storeAzureCredentials(); err != nil {
				k.l.Error("Failed to store the Azure credentials", "Reason", err)
				return false
			}
		}
	}

	return true
}

func (k *KsctlCommand) storeAwsCredentials() (err error) {
	c := new(statefile.CredentialsAws)
	c.AccessKeyId, err = k.menuDriven.TextInputPassword("Enter your AWS Access Key ID")
	if err != nil {
		return err
	}
	c.SecretAccessKey, err = k.menuDriven.TextInputPassword("Enter your AWS Secret Access Key")
	if err != nil {
		return err
	}

	return config.SaveCloudCreds(c, consts.CloudAws)
}

func (k *KsctlCommand) loadAwsCredentials() ([]byte, error) {
	c := new(statefile.CredentialsAws)
	if err := config.LoadCloudCreds(c, consts.CloudAws); err != nil {
		return nil, err
	}
	v, err := json.Marshal(c)
	if err != nil {
		return nil, err
	}
	return v, nil
}

func (k *KsctlCommand) storeAzureCredentials() (err error) {
	c := new(statefile.CredentialsAzure)
	c.SubscriptionID, err = k.menuDriven.TextInputPassword("Enter your Azure Subscription ID")
	if err != nil {
		return err
	}

	c.TenantID, err = k.menuDriven.TextInputPassword("Enter your Azure Tenant ID")
	if err != nil {
		return err
	}

	c.ClientID, err = k.menuDriven.TextInputPassword("Enter your Azure Client ID")
	if err != nil {
		return err
	}
	c.ClientSecret, err = k.menuDriven.TextInputPassword("Enter your Azure Client Secret")
	if err != nil {
		return err
	}

	return config.SaveCloudCreds(c, consts.CloudAzure)
}

func (k *KsctlCommand) loadAzureCredentials() ([]byte, error) {
	c := new(statefile.CredentialsAzure)
	if err := config.LoadCloudCreds(c, consts.CloudAzure); err != nil {
		return nil, err
	}
	v, err := json.Marshal(c)
	if err != nil {
		return nil, err
	}
	return v, nil
}

func (k *KsctlCommand) storeMongoCredentials() (err error) {
	c := new(statefile.CredentialsMongodb)
	srv, err := k.menuDriven.Confirmation("Enter whether MongoDB has SRV record or not", cli.WithDefaultValue("no"))
	if err != nil {
		return err
	}
	c.SRV = srv

	c.Domain, err = k.menuDriven.TextInput("Enter your MongoDB URI")
	if err != nil {
		return err
	}
	c.Username, err = k.menuDriven.TextInputPassword("Enter your MongoDB Username")
	if err != nil {
		return err
	}
	c.Password, err = k.menuDriven.TextInputPassword("Enter your MongoDB Password")
	if err != nil {
		return err
	}
	port := ""
	if port, err = k.menuDriven.TextInput("Enter your MongoDB Port"); err != nil {
		return err
	}
	if len(port) != 0 {
		v, err := strconv.Atoi(port)
		if err != nil {
			return err
		}
		c.Port = utilities.Ptr(v)
	}

	return config.SaveStorageCreds(c, consts.StoreExtMongo)
}

func (k *KsctlCommand) loadMongoCredentials() error {
	c := new(statefile.CredentialsMongodb)
	if err := config.LoadStorageCreds(c, consts.StoreExtMongo); err != nil {
		return err
	}
	v, err := json.Marshal(c)
	if err != nil {
		return err
	}

	k.Ctx = context.WithValue(k.Ctx, consts.KsctlMongodbCredentials, v)
	return nil
}
0707010000000E000081A40000000000000000000000016818E78D00001C81000000000000000000000000000000000000001B00000000ksctl-2.8.0/cmd/connect.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"fmt"
	"io"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"

	"github.com/creack/pty"
	"github.com/fatih/color"
	"github.com/ksctl/cli/v2/pkg/cli"
	"github.com/ksctl/cli/v2/pkg/telemetry"
	"github.com/ksctl/ksctl/v2/pkg/handler/cluster/common"
	"github.com/ksctl/ksctl/v2/pkg/handler/cluster/controller"
	"github.com/ksctl/ksctl/v2/pkg/logger"
	"github.com/spf13/cobra"
	"golang.org/x/term"
	"k8s.io/client-go/tools/clientcmd"
	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
)

func (k *KsctlCommand) Connect() *cobra.Command {

	cmd := &cobra.Command{
		Use: "connect",
		Example: `
ksctl connect --help
		`,
		Short: "Connect to existing cluster",
		Long:  "It is used to connect to existing cluster",

		Run: func(cmd *cobra.Command, args []string) {
			clusters, err := k.fetchAllClusters()
			if err != nil {
				k.l.Error("Error in fetching the clusters", "Error", err)
				os.Exit(1)
			}

			if len(clusters) == 0 {
				k.l.Error("No clusters found to connect")
				os.Exit(1)
			}

			selectDisplay := make(map[string]string, len(clusters))
			valueMaping := make(map[string]controller.Metadata, len(clusters))

			for idx, cluster := range clusters {
				selectDisplay[makeHumanReadableList(cluster)] = strconv.Itoa(idx)
				valueMaping[strconv.Itoa(idx)] = controller.Metadata{
					ClusterName:   cluster.Name,
					ClusterType:   cluster.ClusterType,
					Provider:      cluster.CloudProvider,
					Region:        cluster.Region,
					StateLocation: k.KsctlConfig.PreferedStateStore,
					K8sDistro:     cluster.K8sDistro,
					K8sVersion:    cluster.K8sVersion,
				}
			}

			selectedCluster, err := k.menuDriven.DropDown(
				"Select the cluster to delete",
				selectDisplay,
			)
			if err != nil {
				k.l.Error("Failed to get userinput", "Reason", err)
				os.Exit(1)
			}

			m := valueMaping[selectedCluster]

			if err := k.telemetry.Send(k.Ctx, k.l, telemetry.EventClusterConnect, telemetry.TelemetryMeta{
				CloudProvider:     m.Provider,
				StorageDriver:     m.StateLocation,
				Region:            m.Region,
				ClusterType:       m.ClusterType,
				BootstrapProvider: m.K8sDistro,
				K8sVersion:        m.K8sVersion,
				Addons:            telemetry.TranslateMetadata(m.Addons),
			}); err != nil {
				k.l.Debug(k.Ctx, "Failed to send the telemetry", "Reason", err)
			}

			if k.loadCloudProviderCreds(m.Provider) != nil {
				os.Exit(1)
			}

			c, err := common.NewController(
				k.Ctx,
				k.l,
				&controller.Client{
					Metadata: m,
				},
			)
			if err != nil {
				k.l.Error("Failed to create the controller", "Reason", err)
				os.Exit(1)
			}

			kubeconfig, err := c.Switch()
			if err != nil {
				k.l.Error("Failed to connect to the cluster", "Reason", err)
				os.Exit(1)
			}

			k.l.Note(k.Ctx, "Downloaded the kubeconfig")

			k.writeKubeconfig([]byte(*kubeconfig))

			accessMode, err := k.menuDriven.DropDown(
				"Select the access mode",
				map[string]string{
					"k9s":  "k9s",
					"bash": "shell",
					"none": "none",
				},
				cli.WithDefaultValue("none"),
			)
			if err != nil {
				k.l.Error("Failed to get userinput", "Reason", err)
				os.Exit(1)
			}

			if accessMode == "k9s" {
				K9sAccess(k.l)
			} else if accessMode == "shell" {
				shellAccess(k.l)
			} else {
				k.l.Box(k.Ctx, "Kubeconfig", "You can access the cluster using $ kubectl commands or any other k8s client as its saved to ~/.kube/config")
			}
		},
	}

	return cmd
}

func shellAccess(log logger.Logger) {
	home, err := os.UserHomeDir()
	if err != nil {
		log.Error("Failed to get home dir", "Reason", err)
		os.Exit(1)
	}

	home = filepath.Join(home, ".kube", "config")
	cmd := exec.Command("/bin/bash")

	cmd.Env = append(os.Environ(), "KUBECONFIG="+home)

	ptmx, err := pty.Start(cmd)
	if err != nil {
		fmt.Println("Error creating pseudo-terminal:", err)
		return
	}
	defer func() { _ = ptmx.Close() }()

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGWINCH)
	go func() {
		for range ch {
			if err := pty.InheritSize(os.Stdin, ptmx); err != nil {
				fmt.Println("Error resizing pty:", err)
			}
		}
	}()
	ch <- syscall.SIGWINCH

	oldState, err := term.MakeRaw(int(os.Stdin.Fd()))
	if err != nil {
		fmt.Println("Error setting raw mode:", err)
		return
	}
	defer func() { _ = term.Restore(int(os.Stdin.Fd()), oldState) }()

	fmt.Fprintln(ptmx, "echo Hi from Ksctl team! You are now in the shell session having cluster context.")
	fmt.Fprintln(ptmx, "kubectl get nodes -owide && kubectl cluster-info")

	go func() { _, _ = io.Copy(ptmx, os.Stdin) }()
	_, _ = io.Copy(os.Stdout, ptmx)
}

func K9sAccess(log logger.Logger) {
	// home = filepath.Join(home, ".ksctl", "kubeconfig")
	// _cmd := exec.Command("k9s", "--kubeconfig", home)
	_cmd := exec.Command("k9s")

	_bout := new(strings.Builder)
	_berr := new(strings.Builder)
	_cmd.Stdout = _bout
	_cmd.Stderr = _berr

	if err := _cmd.Run(); err != nil {
		log.Error("Failed to run k9s", "Reason", err)
	}
	_stdout, _stderr := _bout.String(), _berr.String()
	fmt.Println(color.HiBlueString(_stdout))
	fmt.Println(color.HiRedString(_stderr))
}

func mergeKubeConfigs(configs ...*clientcmdapi.Config) *clientcmdapi.Config {
	merged := clientcmdapi.NewConfig()
	for _, cfg := range configs {
		for name, cluster := range cfg.Clusters {
			merged.Clusters[name] = cluster
		}
		for name, authInfo := range cfg.AuthInfos {
			merged.AuthInfos[name] = authInfo
		}
		for name, context := range cfg.Contexts {
			merged.Contexts[name] = context
		}
		if cfg.CurrentContext != "" {
			merged.CurrentContext = cfg.CurrentContext
		}
	}
	return merged
}

func (k *KsctlCommand) writeKubeconfig(newKubeconfig []byte) {
	home, err := os.UserHomeDir()
	if err != nil {
		k.l.Error("Failed to get the home directory", "Reason", err)
		os.Exit(1)
	}
	orgConfig, err := os.ReadFile(filepath.Join(home, ".kube", "config"))
	if err != nil {
		k.l.Error("Failed to read the kubeconfig", "Reason", err)
		os.Exit(1)
	}

	config1, err := clientcmd.Load(orgConfig)
	if err != nil {
		k.l.Error("Failed to load the kubeconfig in ~/.kube/config", "Reason", err)
		os.Exit(1)
	}
	config2, err := clientcmd.Load(newKubeconfig)
	if err != nil {
		k.l.Error("Failed to load the new kubeconfig", "Reason", err)
		os.Exit(1)
	}

	mergedConfig := mergeKubeConfigs(config1, config2)

	mergedConfig.CurrentContext = config2.CurrentContext

	mergedYAML, err := clientcmd.Write(*mergedConfig)
	if err != nil {
		k.l.Error("Failed to write the merged kubeconfig", "Reason", err)
		os.Exit(1)
	}

	if err := os.WriteFile(filepath.Join(home, ".kube", "config"), mergedYAML, 0640); err != nil {
		k.l.Error("Failed to write the kubeconfig", "Reason", err)
		os.Exit(1)
	}
}
0707010000000F000081A40000000000000000000000016818E78D00003098000000000000000000000000000000000000001A00000000ksctl-2.8.0/cmd/create.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"os"
	"time"

	"github.com/ksctl/ksctl/v2/pkg/provider/optimizer"

	"github.com/fatih/color"
	"github.com/ksctl/ksctl/v2/pkg/consts"
	"github.com/ksctl/ksctl/v2/pkg/provider"

	"github.com/ksctl/cli/v2/pkg/cli"
	"github.com/ksctl/cli/v2/pkg/telemetry"
	"github.com/ksctl/ksctl/v2/pkg/handler/cluster/controller"

	controllerManaged "github.com/ksctl/ksctl/v2/pkg/handler/cluster/managed"
	controllerMeta "github.com/ksctl/ksctl/v2/pkg/handler/cluster/metadata"
	controllerSelfManaged "github.com/ksctl/ksctl/v2/pkg/handler/cluster/selfmanaged"
	"github.com/spf13/cobra"
)

func (k *KsctlCommand) Create() *cobra.Command {

	cmd := &cobra.Command{
		Use: "create",
		Example: `
ksctl create --help
		`,
		Short: "Use to create a cluster",
		Long:  "It is used to create cluster with the given name from user",

		Run: func(cmd *cobra.Command, args []string) {
			meta := controller.Metadata{}

			k.baseMetadataFields(&meta)

			if meta.ClusterType == consts.ClusterTypeMang {
				k.metadataForManagedCluster(&meta)
			} else {
				k.metadataForSelfManagedCluster(&meta)
			}

			k.l.Success(k.Ctx, "Created the cluster", "Name", meta.ClusterName)
		},
	}

	return cmd
}

type CliRecommendation struct {
	isOptimizeInstanceRegionReady *optimizer.RecommendationAcrossRegions
	errInRecommendation           error
}

func (k *KsctlCommand) CostOptimizeAcrossRegion(inp chan CliRecommendation, meta *controller.Metadata) {
	ticker := time.NewTicker(2 * time.Second)
	defer ticker.Stop()
	for {
		select {
		case o := <-inp:
			optimizeResp, errResp := o.isOptimizeInstanceRegionReady, o.errInRecommendation
			if errResp != nil {
				k.l.Warn(k.Ctx, "Failed to get the recommendation", "Reason", errResp)
				return
			}

			if len(optimizeResp.RegionRecommendations) == 0 {
				k.l.Success(k.Ctx, "✨ No recommendation available for the selected region")
				return
			}

			selectedReg, err := k.menuDriven.CardSelection(
				cli.ConverterForRecommendationIOutputForCards(optimizeResp, meta.ClusterType),
			)
			if err != nil {
				k.l.Error("Failed to get the recommendation options from user", "Reason", err)
				return
			}

			if selectedReg != "" {
				k.l.Print(k.Ctx, "changed the region", "from", color.HiRedString(meta.Region), "to", color.HiGreenString(selectedReg))
				meta.Region = selectedReg
			}

			return
		case <-ticker.C:
			k.l.Print(k.Ctx, "Still optimizing instance types...")
		}
	}
}

func (k *KsctlCommand) metadataForSelfManagedCluster(meta *controller.Metadata) {
	metaClient, err := controllerMeta.NewController(
		k.Ctx,
		k.l,
		&controller.Client{
			Metadata: *meta,
		},
	)
	if err != nil {
		k.l.Error("Failed to create the controller", "Reason", err)
		os.Exit(1)
	}

	allAvailRegions := k.handleRegionSelection(metaClient, meta)

	cp := k.handleInstanceTypeSelection(metaClient, meta, provider.ComputeIntensive, "Select instance_type for Control Plane")
	etcd := k.handleInstanceTypeSelection(metaClient, meta, provider.MemoryIntensive, "Select instance_type for Etcd Nodes")
	lb := k.handleInstanceTypeSelection(metaClient, meta, provider.GeneralPurpose, "Select instance_type for Load Balancer")

	category := provider.Unknown
	if meta.Provider != consts.CloudLocal {
		category = k.handleInstanceCategorySelection()
	}

	wp := k.handleInstanceTypeSelection(metaClient, meta, category, "Select instance_type for Worker Nodes")

	meta.ControlPlaneNodeType = cp.Sku
	meta.WorkerPlaneNodeType = wp.Sku
	meta.DataStoreNodeType = etcd.Sku
	meta.LoadBalancerNodeType = lb.Sku

	if v, ok := k.getCounterValue("Enter the number of Control Plane Nodes", func(v int) bool {
		return v >= 3
	}, 3); !ok {
		k.l.Error("Failed to get the number of control plane nodes")
		os.Exit(1)
	} else {
		meta.NoCP = v
	}

	if v, ok := k.getCounterValue("Enter the number of Worker Nodes", func(v int) bool {
		return v > 0
	}, 1); !ok {
		k.l.Error("Failed to get the number of worker nodes")
		os.Exit(1)
	} else {
		meta.NoWP = v
	}

	if v, ok := k.getCounterValue("Enter the number of Etcd Nodes", func(v int) bool {
		return v >= 3
	}, 3); !ok {
		k.l.Error("Failed to get the number of etcd nodes")
		os.Exit(1)
	} else {
		meta.NoDS = v
	}

	var (
		isOptimizeInstanceRegionReady chan CliRecommendation
	)
	isOptimizeInstanceRegionReady = make(chan CliRecommendation)

	go func() {
		res, err := metaClient.CostOptimizeAcrossRegions(
			allAvailRegions, meta.Region,
			controllerMeta.CostOptimizerInput{
				ControlPlane:             cp,
				WorkerPlane:              wp,
				DataStorePlane:           etcd,
				LoadBalancer:             lb,
				CountOfControlPlaneNodes: meta.NoCP,
				CountOfWorkerNodes:       meta.NoWP,
				CountOfEtcdNodes:         meta.NoDS,
			},
		)

		isOptimizeInstanceRegionReady <- CliRecommendation{
			isOptimizeInstanceRegionReady: res,
			errInRecommendation:           err,
		}
	}()

	bootstrapVers, err := metaClient.ListAllBootstrapVersions()
	if err != nil {
		k.l.Error("Failed to get the list of bootstrap versions", "Reason", err)
		os.Exit(1)
	}

	if v, err := k.menuDriven.DropDownList("Select the bootstrap version", bootstrapVers, cli.WithDefaultValue(bootstrapVers[0])); err != nil {
		k.l.Error("Failed to get the bootstrap version", "Reason", err)
		os.Exit(1)
	} else {
		k.l.Debug(k.Ctx, "Selected bootstrap version", "Version", v)
		meta.K8sVersion = v
	}

	etcdVers, err := metaClient.ListAllEtcdVersions()
	if err != nil {
		k.l.Error("Failed to get the list of etcd versions", "Reason", err)
		os.Exit(1)
	}
	if v, err := k.menuDriven.DropDownList("Select the etcd version", etcdVers, cli.WithDefaultValue(etcdVers[0])); err != nil {
		k.l.Error("Failed to get the etcd version", "Reason", err)
		os.Exit(1)
	} else {
		k.l.Debug(k.Ctx, "Selected etcd version", "Version", v)
		meta.EtcdVersion = v
	}

	k.l.Print(k.Ctx, "Current Selection will cost you")
	_, err = metaClient.PriceCalculator(
		controllerMeta.PriceCalculatorInput{
			Currency:              cp.Price.Currency,
			NoOfWorkerNodes:       meta.NoWP,
			NoOfControlPlaneNodes: meta.NoCP,
			NoOfEtcdNodes:         meta.NoDS,
			ControlPlaneMachine:   cp,
			WorkerMachine:         wp,
			EtcdMachine:           etcd,
			LoadBalancerMachine:   lb,
		})
	if err != nil {
		k.l.Error("Failed to calculate the price", "Reason", err)
		os.Exit(1)
	}

	k.CostOptimizeAcrossRegion(isOptimizeInstanceRegionReady, meta)

	managedCNI, defaultCNI, ksctlCNI, defaultKsctl, err := metaClient.ListBootstrapCNIs()
	if err != nil {
		k.l.Error("Failed to get the list of self managed CNIs", "Reason", err)
		os.Exit(1)
	}

	v, err := k.handleCNI(metaClient, managedCNI, defaultCNI, ksctlCNI, defaultKsctl)
	if err != nil {
		k.l.Error("Failed to get the CNI", "Reason", err)
		os.Exit(1)
	}

	meta.Addons = v

	k.metadataSummary(*meta)

	if err := k.telemetry.Send(k.Ctx, k.l, telemetry.EventClusterCreate, telemetry.TelemetryMeta{
		CloudProvider:     meta.Provider,
		StorageDriver:     meta.StateLocation,
		Region:            meta.Region,
		ClusterType:       meta.ClusterType,
		BootstrapProvider: meta.K8sDistro,
		K8sVersion:        meta.K8sVersion,
		Addons:            telemetry.TranslateMetadata(meta.Addons),
	}); err != nil {
		k.l.Debug(k.Ctx, "Failed to send the telemetry", "Reason", err)
	}

	if ok, _ := k.menuDriven.Confirmation("Do you want to proceed with the cluster creation", cli.WithDefaultValue("no")); !ok {
		os.Exit(1)
	}

	c, err := controllerSelfManaged.NewController(
		k.Ctx,
		k.l,
		&controller.Client{
			Metadata: *meta,
		},
	)
	if err != nil {
		k.l.Error("Failed to create the controller", "Reason", err)
		os.Exit(1)
	}

	if err := c.Create(); err != nil {
		k.l.Error("Failed to create the cluster", "Reason", err)
		os.Exit(1)
	}

	return
}

func (k *KsctlCommand) metadataForManagedCluster(meta *controller.Metadata) {
	metaClient, err := controllerMeta.NewController(
		k.Ctx,
		k.l,
		&controller.Client{
			Metadata: *meta,
		},
	)
	if err != nil {
		k.l.Error("Failed to create the controller", "Reason", err)
		os.Exit(1)
	}

	if v, ok := k.getCounterValue("Enter the number of Managed Nodes", func(v int) bool {
		return v > 0
	}, 1); !ok {
		k.l.Error("Failed to get the number of managed nodes")
		os.Exit(1)
	} else {
		meta.NoMP = v
	}

	var (
		isOptimizeInstanceRegionReady chan CliRecommendation
	)

	if meta.Provider != consts.CloudLocal {
		allAvailRegions := k.handleRegionSelection(metaClient, meta)

		category := provider.Unknown
		if meta.Provider != consts.CloudLocal {
			category = k.handleInstanceCategorySelection()
		}

		vm := k.handleInstanceTypeSelection(metaClient, meta, category, "Select instance_type for Managed Nodes")
		meta.ManagedNodeType = vm.Sku

		k.menuDriven.GetProgressAnimation().Start("Fetching the managed cluster offerings")

		listOfOfferings, err := metaClient.ListAllManagedClusterManagementOfferings(meta.Region, nil)
		if err != nil {
			k.menuDriven.GetProgressAnimation().Stop()
			k.l.Error("Failed to sync the metadata", "Reason", err)
			os.Exit(1)
		}
		k.menuDriven.GetProgressAnimation().Stop()

		offeringSelected := ""

		if v, ok := k.getSelectedManagedClusterOffering("Select the managed cluster offering", listOfOfferings); !ok {
			k.l.Error("Failed to get the managed cluster offering")
			os.Exit(1)
		} else {
			offeringSelected = v
		}

		isOptimizeInstanceRegionReady = make(chan CliRecommendation)

		go func() {
			res, err := metaClient.CostOptimizeAcrossRegions(
				allAvailRegions, meta.Region,
				controllerMeta.CostOptimizerInput{
					ManagedOffering:     listOfOfferings[offeringSelected],
					ManagedPlane:        vm,
					CountOfManagedNodes: meta.NoMP,
				},
			)
			isOptimizeInstanceRegionReady <- CliRecommendation{
				isOptimizeInstanceRegionReady: res,
				errInRecommendation:           err,
			}
		}()

		k.l.Print(k.Ctx, "Current Selection will cost you")

		_, err = metaClient.PriceCalculator(
			controllerMeta.PriceCalculatorInput{
				ManagedControlPlaneMachine: listOfOfferings[offeringSelected],
				NoOfWorkerNodes:            meta.NoMP,
				WorkerMachine:              vm,
			})
		if err != nil {
			k.l.Error("Failed to calculate the price", "Reason", err)
			os.Exit(1)
		}

		k.CostOptimizeAcrossRegion(isOptimizeInstanceRegionReady, meta)
	}

	managedCNI, defaultCNI, ksctlCNI, defaultKsctl, err := metaClient.ListManagedCNIs()
	if err != nil {
		k.l.Error("Failed to get the list of managed CNIs", "Reason", err)
		os.Exit(1)
	}

	if v, err := k.handleCNI(metaClient, managedCNI, defaultCNI, ksctlCNI, defaultKsctl); err != nil {
		k.l.Error("Failed to get the CNI", "Reason", err)
		os.Exit(1)
	} else {
		meta.Addons = v
	}

	k.handleManagedK8sVersion(metaClient, meta)

	k.metadataSummary(*meta)

	if err := k.telemetry.Send(k.Ctx, k.l, telemetry.EventClusterCreate, telemetry.TelemetryMeta{
		CloudProvider: meta.Provider,
		StorageDriver: meta.StateLocation,
		Region:        meta.Region,
		ClusterType:   meta.ClusterType,
		BootstrapProvider: func() consts.KsctlKubernetes {
			switch meta.Provider {
			case consts.CloudLocal:
				return consts.K8sKind
			case consts.CloudAzure:
				return consts.K8sAks
			case consts.CloudAws:
				return consts.K8sEks
			default:
				return ""
			}
		}(),
		K8sVersion: meta.K8sVersion,
		Addons:     telemetry.TranslateMetadata(meta.Addons),
	}); err != nil {
		k.l.Debug(k.Ctx, "Failed to send the telemetry", "Reason", err)
	}

	if ok, _ := k.menuDriven.Confirmation("Do you want to proceed with the cluster creation", cli.WithDefaultValue("no")); !ok {
		os.Exit(1)
	}

	c, err := controllerManaged.NewController(
		k.Ctx,
		k.l,
		&controller.Client{
			Metadata: *meta,
		},
	)
	if err != nil {
		k.l.Error("Failed to create the controller", "Reason", err)
		os.Exit(1)
	}

	if err := c.Create(); err != nil {
		k.l.Error("Failed to create the cluster", "Reason", err)
		os.Exit(1)
	}

	return
}
07070100000010000081A40000000000000000000000016818E78D000010C3000000000000000000000000000000000000001A00000000ksctl-2.8.0/cmd/delete.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"fmt"
	"os"
	"strconv"
	"strings"

	"github.com/ksctl/cli/v2/pkg/cli"
	"github.com/ksctl/cli/v2/pkg/telemetry"
	"github.com/ksctl/ksctl/v2/pkg/consts"
	"github.com/ksctl/ksctl/v2/pkg/handler/cluster/controller"
	"github.com/ksctl/ksctl/v2/pkg/handler/cluster/managed"
	"github.com/ksctl/ksctl/v2/pkg/handler/cluster/selfmanaged"
	"github.com/ksctl/ksctl/v2/pkg/provider"
	"github.com/spf13/cobra"
)

func (k *KsctlCommand) Delete() *cobra.Command {

	cmd := &cobra.Command{
		Use: "delete",
		Example: `
ksctl delete --help
		`,
		Short: "Use to delete a cluster",
		Long:  "It is used to delete cluster with the given name from user",

		Run: func(cmd *cobra.Command, args []string) {
			clusters, err := k.fetchAllClusters()
			if err != nil {
				k.l.Error("Error in fetching the clusters", "Error", err)
				os.Exit(1)
			}

			if len(clusters) == 0 {
				k.l.Error("No clusters found to delete")
				os.Exit(1)
			}

			selectDisplay := make(map[string]string, len(clusters))
			valueMaping := make(map[string]controller.Metadata, len(clusters))

			for idx, cluster := range clusters {
				selectDisplay[makeHumanReadableList(cluster)] = strconv.Itoa(idx)
				valueMaping[strconv.Itoa(idx)] = controller.Metadata{
					ClusterName:   cluster.Name,
					ClusterType:   cluster.ClusterType,
					Provider:      cluster.CloudProvider,
					Region:        cluster.Region,
					StateLocation: k.KsctlConfig.PreferedStateStore,
					K8sDistro:     cluster.K8sDistro,
				}
			}

			selectedCluster, err := k.menuDriven.DropDown(
				"Select the cluster to delete",
				selectDisplay,
			)
			if err != nil {
				k.l.Error("Failed to get userinput", "Reason", err)
				os.Exit(1)
			}

			m := valueMaping[selectedCluster]

			if err := k.telemetry.Send(k.Ctx, k.l, telemetry.EventClusterDelete, telemetry.TelemetryMeta{
				CloudProvider:     m.Provider,
				StorageDriver:     m.StateLocation,
				Region:            m.Region,
				ClusterType:       m.ClusterType,
				BootstrapProvider: m.K8sDistro,
				K8sVersion:        m.K8sVersion,
				Addons:            telemetry.TranslateMetadata(m.Addons),
			}); err != nil {
				k.l.Debug(k.Ctx, "Failed to send the telemetry", "Reason", err)
			}

			if ok, _ := k.menuDriven.Confirmation("Do you want to proceed with the cluster deletion", cli.WithDefaultValue("no")); !ok {
				os.Exit(1)
			}

			if k.loadCloudProviderCreds(m.Provider) != nil {
				os.Exit(1)
			}

			if m.ClusterType == consts.ClusterTypeMang {
				c, err := managed.NewController(
					k.Ctx,
					k.l,
					&controller.Client{
						Metadata: m,
					},
				)
				if err != nil {
					k.l.Error("Failed to create the controller", "Reason", err)
					os.Exit(1)
				}

				if err := c.Delete(); err != nil {
					k.l.Error("Failed to delete your managed cluster", "Reason", err)
					os.Exit(1)
				}

			} else {
				c, err := selfmanaged.NewController(
					k.Ctx,
					k.l,
					&controller.Client{
						Metadata: m,
					},
				)
				if err != nil {
					k.l.Error("Failed to create the controller", "Reason", err)
					os.Exit(1)
				}

				if err := c.Delete(); err != nil {
					k.l.Error("Failed to delete your selfmanaged cluster", "Reason", err)
					os.Exit(1)
				}
			}

			k.l.Success(k.Ctx, "Deleted your cluster", "Name", m.ClusterName)
		},
	}

	return cmd
}

func makeHumanReadableList(m provider.ClusterData) string {
	fields := []string{"%s", "[%s]", "=>"}
	args := []any{m.Name, m.ClusterType}
	if m.CloudProvider == consts.CloudLocal {
		fields = append(fields, "local")
	} else {
		fields = append(fields, "%s ⟨%s⟩")
		args = append(args, m.CloudProvider, m.Region)
	}

	return fmt.Sprintf(strings.Join(fields, " "), args...)
}
07070100000011000081A40000000000000000000000016818E78D00000F21000000000000000000000000000000000000001700000000ksctl-2.8.0/cmd/get.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"context"
	"os"
	"strconv"
	"strings"

	"github.com/ksctl/cli/v2/pkg/telemetry"
	"github.com/ksctl/ksctl/v2/pkg/consts"
	"github.com/ksctl/ksctl/v2/pkg/logger"
	"github.com/ksctl/ksctl/v2/pkg/provider"
	"github.com/spf13/cobra"
)

func (k *KsctlCommand) Get() *cobra.Command {

	cmd := &cobra.Command{
		Use: "get",
		Example: `
ksctl get --help
`,
		Short: "Use to get the cluster",
		Long:  "It is used to get the cluster created by the user",
		Run: func(cmd *cobra.Command, args []string) {
			clusters, err := k.fetchAllClusters()
			if err != nil {
				k.l.Error("Error in fetching the clusters", "Error", err)
				os.Exit(1)
			}

			if len(clusters) == 0 {
				k.l.Print(k.Ctx, "No clusters found")
				os.Exit(1)
			}

			selectDisplay := make(map[string]string, len(clusters))
			valueMaping := make(map[string]provider.ClusterData, len(clusters))

			for idx, cluster := range clusters {
				selectDisplay[makeHumanReadableList(cluster)] = strconv.Itoa(idx)
				valueMaping[strconv.Itoa(idx)] = cluster
			}

			selectedCluster, err := k.menuDriven.DropDown(
				"Select the cluster to delete",
				selectDisplay,
			)
			if err != nil {
				k.l.Error("Failed to get userinput", "Reason", err)
				os.Exit(1)
			}

			cluster := valueMaping[selectedCluster]

			if err := k.telemetry.Send(k.Ctx, k.l, telemetry.EventClusterGet, telemetry.TelemetryMeta{
				CloudProvider:     cluster.CloudProvider,
				StorageDriver:     k.KsctlConfig.PreferedStateStore,
				Region:            cluster.Region,
				ClusterType:       cluster.ClusterType,
				BootstrapProvider: cluster.K8sDistro,
				K8sVersion:        cluster.K8sVersion,
			}); err != nil {
				k.l.Debug(k.Ctx, "Failed to send the telemetry", "Reason", err)
			}

			handleTableOutputGet(k.Ctx, k.l, cluster)

		},
	}

	return cmd
}

func handleTableOutputGet(ctx context.Context, l logger.Logger, data provider.ClusterData) {

	headers := []string{"Attributes", "Values"}
	dataToPrint := [][]string{
		{"ClusterName", data.Name},
		{"CloudProvider", string(data.CloudProvider)},
		{"ClusterType", string(data.ClusterType)},
	}
	if data.CloudProvider != consts.CloudLocal {
		dataToPrint = append(dataToPrint,
			[]string{"Region", data.Region},
		)
	}

	if data.ClusterType == consts.ClusterTypeSelfMang {
		nodes := func(vm []provider.VMData) string {
			slice := make([]string, 0, len(vm))
			for _, v := range vm {
				slice = append(slice, v.VMSize)
			}
			return strings.Join(slice, ",")
		}

		dataToPrint = append(
			dataToPrint,
			[]string{"BootstrapProvider", string(data.K8sDistro)},
			[]string{"BootstrapKubernetesVersion", data.K8sVersion},
			[]string{"ControlPlaneNodes", nodes(data.CP)},
			[]string{"WorkerPlaneNodes", nodes(data.WP)},
			[]string{"EtcdNodes", nodes(data.DS)},
			[]string{"LoadBalancer", data.LB.VMSize},
			[]string{"EtcdVersion", data.EtcdVersion},
			[]string{"HaProxyVersion", data.HAProxyVersion},
		)
	} else {
		dataToPrint = append(
			dataToPrint,
			[]string{"ManagedNodes", strconv.Itoa(data.NoMgt) + " X " + data.Mgt.VMSize},
			[]string{"ManagedK8sVersion", data.K8sVersion},
		)
	}

	dataToPrint = append(dataToPrint,
		[]string{"Addons", strings.Join(data.Apps, ",")},
		[]string{"CNI", data.Cni},
	)

	l.Table(ctx, headers, dataToPrint)
}
07070100000012000081A40000000000000000000000016818E78D00002C16000000000000000000000000000000000000001F00000000ksctl-2.8.0/cmd/handle_meta.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"encoding/json"
	"fmt"
	"os"
	"os/exec"

	"github.com/ksctl/cli/v2/pkg/cli"
	"github.com/ksctl/ksctl/v2/pkg/addons"
	"github.com/ksctl/ksctl/v2/pkg/bootstrap/handler/cni"
	"github.com/ksctl/ksctl/v2/pkg/consts"
	"github.com/ksctl/ksctl/v2/pkg/errors"
	"github.com/ksctl/ksctl/v2/pkg/handler/cluster/controller"
	controllerMeta "github.com/ksctl/ksctl/v2/pkg/handler/cluster/metadata"
	"github.com/ksctl/ksctl/v2/pkg/provider"
	"github.com/ksctl/ksctl/v2/pkg/utilities"
	"gopkg.in/yaml.v3"
)

func (k *KsctlCommand) baseMetadataFields(m *controller.Metadata) {
	if v, ok := k.getClusterName(); !ok {
		os.Exit(1)
	} else {
		m.ClusterName = v
	}

	if v, ok := k.getSelectedClusterType(); !ok {
		os.Exit(1)
	} else {
		m.ClusterType = v
	}

	if v, ok := k.getSelectedCloudProvider(m.ClusterType); !ok {
		os.Exit(1)
	} else {
		m.Provider = v
	}

	if v, ok := k.getSelectedStorageDriver(); !ok {
		os.Exit(1)
	} else {
		m.StateLocation = consts.KsctlStore(v)
	}

	if m.ClusterType == consts.ClusterTypeSelfMang {
		if v, ok := k.getBootstrap(); ok {
			m.K8sDistro = v
		} else {
			os.Exit(1)
		}
	}
}

func (k *KsctlCommand) handleRegionSelection(meta *controllerMeta.Controller, m *controller.Metadata) []provider.RegionOutput {
	ss := k.menuDriven.GetProgressAnimation()
	ss.Start("Fetching the region list")

	listOfRegions, err := meta.ListAllRegions()
	if err != nil {
		ss.Stop()
		k.l.Error("Failed to sync the metadata", "Reason", err)
		os.Exit(1)
	}
	ss.Stop()

	k.l.Note(k.Ctx, "Carbon emission data shown represents monthly averages calculated over a one-year period")
	k.l.Note(k.Ctx, "Select the region for the cluster")

	if v, err := k.menuDriven.CardSelection(
		cli.ConverterForRegionOutputForCards(listOfRegions),
	); err != nil {
		k.l.Error("Failed to get the region", "Reason", err)
		os.Exit(1)
	} else {
		if v == "" {
			k.l.Error("Region not selected")
			os.Exit(1)
		}
		k.l.Debug(k.Ctx, "Selected region", "Region", v)
		m.Region = v
	}

	return listOfRegions
}

func (k *KsctlCommand) handleInstanceCategorySelection() provider.MachineCategory {
	v := provider.GetAvailableMachineCategories()

	_v, ok := k.getSelectedInstanceCategory(v)
	if !ok {
		k.l.Error("Failed to get the instance category")
		os.Exit(1)
	}
	return _v
}

func (k *KsctlCommand) handleInstanceTypeSelection(
	meta *controllerMeta.Controller,
	m *controller.Metadata,
	category provider.MachineCategory,
	prompt string,
) provider.InstanceRegionOutput {

	if len(k.inMemInstanceTypesInReg) == 0 {
		if len(category) == 0 {
			k.l.Error("Machine category is not provided")
			os.Exit(1)
		}
		ss := k.menuDriven.GetProgressAnimation()
		ss.Start("Fetching the instance type list")

		listOfVMs, err := meta.ListAllInstances(m.Region)
		if err != nil {
			ss.Stop()
			k.l.Error("Failed to sync the metadata", "Reason", err)
			os.Exit(1)
		}
		ss.Stop()
		k.inMemInstanceTypesInReg = listOfVMs
	}

	availableOptions := make(provider.InstancesRegionOutput, 0, len(k.inMemInstanceTypesInReg))

	k.l.Note(k.Ctx, prompt)

	for _, v := range k.inMemInstanceTypesInReg {
		if v.Category == category && v.CpuArch == provider.ArchAmd64 {
			availableOptions = append(availableOptions, v)
		}
	}

	v, err := k.menuDriven.CardSelection(
		cli.ConverterForInstanceTypesForCards(availableOptions),
	)
	if err != nil {
		k.l.Error("Failed to get the instance type from user", "Reason", err)
		os.Exit(1)
	}
	if v == "" {
		k.l.Error("Instance type not selected")
		os.Exit(1)
	}

	_v, ok := availableOptions.Get(v)
	if !ok {
		k.l.Error("Failed to get the instance type")
		os.Exit(1)
	}

	return *_v
}

func (k *KsctlCommand) getSpecificInstanceForScaledown(
	meta *controllerMeta.Controller,
	region string,
	instanceSku string,
) provider.InstanceRegionOutput {

	if len(k.inMemInstanceTypesInReg) == 0 {
		ss := k.menuDriven.GetProgressAnimation()
		ss.Start("Fetching the instance type list")

		listOfVMs, err := meta.ListAllInstances(region)
		if err != nil {
			ss.Stop()
			k.l.Error("Failed to sync the metadata", "Reason", err)
			os.Exit(1)
		}
		ss.Stop()
		k.inMemInstanceTypesInReg = listOfVMs
	}

	v, ok := k.inMemInstanceTypesInReg.Get(instanceSku)
	if !ok {
		k.l.Error("Failed to get the instance type")
		os.Exit(1)
	}
	return *v
}

func (k *KsctlCommand) handleManagedK8sVersion(meta *controllerMeta.Controller, m *controller.Metadata) {
	ss := k.menuDriven.GetProgressAnimation()
	ss.Start("Fetching the managed cluster k8s versions")

	listOfK8sVersions, err := meta.ListAllManagedClusterK8sVersions(m.Region)
	if err != nil {
		ss.Stop()
		k.l.Error("Failed to sync the metadata", "Reason", err)
		os.Exit(1)
	}
	ss.Stop()

	if v, ok := k.getSelectedK8sVersion("Select the k8s version for Managed Cluster", listOfK8sVersions); !ok {
		k.l.Error("Failed to get the k8s version")
		os.Exit(1)
	} else {
		m.K8sVersion = v
	}
}

func (k *KsctlCommand) metadataSummary(meta controller.Metadata) {
	// Use the new interactive cluster summary
	cli.NewBlueprintUI(os.Stdout).RenderClusterBlueprint(meta)
}

func (k *KsctlCommand) handleCNI(metaClient *controllerMeta.Controller, managedCNI addons.ClusterAddons, defaultOptionManaged string, ksctlCNI addons.ClusterAddons, defaultOptionKsctl string) (addons.ClusterAddons, error) {
	var v addons.ClusterAddons

	handleInput := func(
		vc addons.ClusterAddons,
		prompt string,
		defaultOpt string,
		errorPrompt string,
	) (addons.ClusterAddon, error) {
		cc := map[string]string{}
		cm := map[string]addons.ClusterAddon{}
		for _, c := range vc {
			cc[fmt.Sprintf("%s (From: %s)", c.Name, c.Label)] = c.Name
			cm[c.Name] = c
		}

		selected, err := k.menuDriven.DropDown(
			prompt,
			cc,
			cli.WithDefaultValue(defaultOpt),
		)
		if err != nil {
			return addons.ClusterAddon{}, errors.WrapError(
				errors.ErrInvalidUserInput,
				k.l.NewError(k.Ctx, errorPrompt, "Reason", err),
			)
		}

		return cm[selected], nil
	}

	_v0, err := handleInput(managedCNI, "Select the CNI addon provided by offering", defaultOptionManaged, "Failed to get the CNI addon provided by managed offering")
	if err != nil {
		return nil, err
	}

	v = append(v, _v0)

	if _v0.Name != string(consts.CNINone) {
		return v, nil
	}

	_v1, err := handleInput(ksctlCNI, "Select the CNI addon provided by ksctl", defaultOptionKsctl, "Failed to get the CNI addon provided by ksctl")
	if err != nil {
		return nil, err
	}

	ss := k.menuDriven.GetProgressAnimation()
	ss.Start("Fetching the CNI version list")

	config := make(map[string]map[string]any)
	if _v1.Name == string(consts.CNIFlannel) {
		vers, errF := metaClient.ListAllFlannelVersions()
		ss.Stop()
		if errF != nil { // Skip further processing if error
			k.l.Warn(k.Ctx, "Failed to get the Flannel version list", "Reason", errF)
		} else {
			if v, err := k.menuDriven.DropDownList("Select the flannel version", vers, cli.WithDefaultValue(vers[0])); err != nil {
				k.l.Error("Failed to get the flannel version", "Reason", err)
			} else {
				k.l.Debug(k.Ctx, "Selected flannel version", "Version", v)
				config[string(cni.FlannelComponentID)] = map[string]any{
					"version": v,
				}
			}
		}
	}

	if _v1.Name == string(consts.CNICilium) {
		vers, errC := metaClient.ListAllCiliumVersions()
		ss.Stop()
		if errC != nil { // Skip further processing if error
			k.l.Warn(k.Ctx, "Failed to get the Cilium version list", "Reason", errC)
		} else {
			if v, err := k.menuDriven.DropDownList("Select the cilium version", vers, cli.WithDefaultValue(vers[0])); err != nil {
				k.l.Error("Failed to get the cilium version", "Reason", err)
			} else {
				k.l.Debug(k.Ctx, "Selected cilium version", "Version", v)
				config[string(cni.CiliumComponentID)] = map[string]any{
					"version": v,
				}
			}
		}

		// Get the Cilium Specific options
		// where 2 modes are there one if guided and another is advance
		ciliumMode, err := k.menuDriven.DropDownList("Select the cilium mode", []string{"guided", "advanced", "ksctl default"}, cli.WithDefaultValue("ksctl default"))
		if err != nil {
			return nil, errors.WrapError(
				errors.ErrInvalidUserInput,
				k.l.NewError(k.Ctx, "Failed to get the cilium mode", "Reason", err),
			)
		}
		k.l.Print(k.Ctx, "Selected cilium mode", "Mode", ciliumMode)

		if ciliumMode == "guided" {
			availableGuidedSetup := cni.CiliumGuidedConfigurations()

			input := make(map[string]string, len(availableGuidedSetup))
			for _, v := range availableGuidedSetup {
				input[fmt.Sprintf("%s: %s", v.Name, v.Description)] = v.Name
			}

			selectedOption, err := k.menuDriven.MultiSelect("Select the cilium guided setup", input)
			if err != nil {
				return nil, errors.WrapError(
					errors.ErrInvalidUserInput,
					k.l.NewError(k.Ctx, "Failed to get the cilium guided setup", "Reason", err),
				)
			}
			k.l.Debug(k.Ctx, "Selected cilium guided setup", "Setup", selectedOption)
			config[string(cni.CiliumComponentID)]["guidedConfig"] = selectedOption

		} else if ciliumMode == "advanced" {
			editor := os.Getenv("EDITOR")
			if editor == "" {
				editor = "vim"
			}

			tempFile, err := os.CreateTemp("", "cilium_config_*.yaml")
			if err != nil {
				k.l.Error("Failed to create temporary file", "Reason", err)
				return nil, errors.WrapError(
					errors.ErrInvalidUserInput,
					k.l.NewError(k.Ctx, "Failed to create temporary file", "Reason", err),
				)
			}
			defer os.Remove(tempFile.Name())

			cmd := exec.Command(editor, tempFile.Name())
			cmd.Stdin = os.Stdin
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr

			if err := cmd.Run(); err != nil {
				k.l.Error("Failed to open editor", "Reason", err)
				return nil, errors.WrapError(
					errors.ErrInvalidUserInput,
					k.l.NewError(k.Ctx, "Failed to open editor", "Reason", err),
				)
			}

			content, err := os.ReadFile(tempFile.Name())
			if err != nil {
				k.l.Error("Failed to read temporary file", "Reason", err)
				return nil, errors.WrapError(
					errors.ErrInvalidUserInput,
					k.l.NewError(k.Ctx, "Failed to read temporary file", "Reason", err),
				)
			}

			var customConfig map[string]any
			if err := yaml.Unmarshal(content, &customConfig); err != nil {
				k.l.Error("Failed to parse YAML content", "Reason", err)
				return nil, errors.WrapError(
					errors.ErrInvalidUserInput,
					k.l.NewError(k.Ctx, "Failed to parse YAML content", "Reason", err),
				)
			}

			config[string(cni.CiliumComponentID)]["ciliumChartOverridings"] = customConfig
		}
	}

	_config, err := json.Marshal(config)
	if err != nil {
		return nil, errors.WrapError(
			errors.ErrInvalidUserInput,
			k.l.NewError(k.Ctx, "Failed to marshal the CNI config", "Reason", err),
		)
	}
	_v1.Config = utilities.Ptr(string(_config))

	v = append(v, _v1)
	return v, nil
}
07070100000013000081A40000000000000000000000016818E78D000004A6000000000000000000000000000000000000001B00000000ksctl-2.8.0/cmd/handler.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import "github.com/ksctl/cli/v2/pkg/cli"

func (k *KsctlCommand) CommandMapping() error {
	c := k.Cluster()
	cr := k.Configure()
	a := k.Addons()

	cli.RegisterCommand(
		k.root,
		c,
		k.Version(),
		k.SelfUpdate(),
		k.ShellCompletion(),
		cr,
	)
	cli.RegisterCommand(
		c,
		a,
		k.Create(),
		k.Delete(),
		k.List(),
		k.Get(),
		k.Connect(),
		k.ScaleUp(),
		k.ScaleDown(),
		k.Summary(),
	)

	cli.RegisterCommand(
		cr,
		k.ConfigureStorage(),
		k.ConfigureCloud(),
		k.ConfigureTelemetry(),
	)

	cli.RegisterCommand(
		a,
		k.EnableAddon(),
		k.DisableAddon(),
	)

	return nil
}
07070100000014000081A40000000000000000000000016818E78D00000BAF000000000000000000000000000000000000001800000000ksctl-2.8.0/cmd/list.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"context"
	"os"

	"github.com/ksctl/cli/v2/pkg/telemetry"
	"github.com/ksctl/ksctl/v2/pkg/consts"
	"github.com/ksctl/ksctl/v2/pkg/errors"
	"github.com/ksctl/ksctl/v2/pkg/handler/cluster/controller"
	"github.com/ksctl/ksctl/v2/pkg/logger"
	"github.com/ksctl/ksctl/v2/pkg/provider"
	"github.com/spf13/cobra"

	controllerCommon "github.com/ksctl/ksctl/v2/pkg/handler/cluster/common"
)

func (k *KsctlCommand) List() *cobra.Command {

	cmd := &cobra.Command{
		Use: "list",
		Example: `
ksctl list --help
`,
		Short: "Use to list all the clusters",
		Long:  "It is used to list all the clusters created by the user",
		Run: func(cmd *cobra.Command, args []string) {
			clusters, err := k.fetchAllClusters()
			if err != nil {
				k.l.Error("Error in fetching the clusters", "Error", err)
				os.Exit(1)
			}

			if err := k.telemetry.Send(k.Ctx, k.l, telemetry.EventClusterList, telemetry.TelemetryMeta{}); err != nil {
				k.l.Debug(k.Ctx, "Failed to send the telemetry", "Reason", err)
			}

			if len(clusters) == 0 {
				k.l.Print(k.Ctx, "No clusters found")
				return
			}

			HandleTableOutputListAll(k.Ctx, k.l, clusters)
		},
	}

	return cmd
}

func (k *KsctlCommand) fetchAllClusters() ([]provider.ClusterData, error) {
	m := controller.Metadata{}
	if v, ok := k.getSelectedStorageDriver(); !ok {
		return nil, errors.NewError(errors.ErrInvalidStorageProvider)
	} else {
		m.StateLocation = v
	}

	m.Provider = consts.CloudAll

	managerClient, err := controllerCommon.NewController(
		k.Ctx,
		k.l,
		&controller.Client{
			Metadata: m,
		},
	)
	if err != nil {
		k.l.Error("unable to initialize the ksctl manager", "Reason", err)
		return nil, err
	}

	clusters, err := managerClient.ListClusters()
	if err != nil {
		return nil, err
	}
	return clusters, nil
}

func HandleTableOutputListAll(ctx context.Context, l logger.Logger, data []provider.ClusterData) {
	headers := []string{"Name", "Type", "Cloud", "Region", "BootstrapProvider"}
	var dataToPrint [][]string = make([][]string, 0, len(data))
	for _, v := range data {
		var row []string
		row = append(row, v.Name, string(v.ClusterType), string(v.CloudProvider))
		if v.CloudProvider == consts.CloudLocal {
			row = append(row, "")
		} else {
			row = append(row, v.Region)
		}
		row = append(
			row,
			string(v.K8sDistro),
		)
		dataToPrint = append(dataToPrint, row)
	}

	l.Table(ctx, headers, dataToPrint)
}
07070100000015000081A40000000000000000000000016818E78D00000933000000000000000000000000000000000000001800000000ksctl-2.8.0/cmd/root.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"os"

	"github.com/ksctl/cli/v2/pkg/cli"
	"github.com/ksctl/cli/v2/pkg/telemetry"

	cLogger "github.com/ksctl/cli/v2/pkg/logger"
	"github.com/spf13/cobra"
)

// for the newController we should be able to pass some option fields for control more things
// for example whther it is a dry-run for testing

func (k *KsctlCommand) NewRootCmd() *cobra.Command {

	v := false

	cmd := &cobra.Command{
		Use:   "ksctl",
		Short: "CLI tool for managing multiple K8s clusters",
		Long:  "CLI tool which can manage multiple K8s clusters from local clusters to cloud provider specific clusters.",
		PersistentPreRun: func(cmd *cobra.Command, args []string) {

			telemetry.IntegrityCheck()

			if k.debugMode {
				k.CliLog.Box(k.Ctx, "CLI Mode", "CLI is running in debug mode")
				k.menuDriven = cli.NewDebugMenuDriven()
			} else {
				k.menuDriven = cli.NewMenuDriven()
			}

			_ = k.menuDriven.GetProgressAnimation() // Just boot it up...

			if v {
				k.CliLog.Box(k.Ctx, "CLI Mode", "Verbose mode is enabled")
				k.verbose = -1
			}

			k.l = cLogger.NewLogger(k.verbose, os.Stdout)

			k.telemetry = telemetry.NewTelemetry(k.KsctlConfig.Telemetry)

			cmdName := cmd.Name()
			if cmdName != "self-update" && cmdName != "version" {
				hasUpdates, err := k.CheckForUpdates()
				if err == nil && hasUpdates {
					k.NotifyAvailableUpdates()
				}
			}
		},
	}

	cmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
	cli.AddDebugMode(cmd, &k.debugMode)
	cli.AddVerboseFlag(cmd, &v)

	return cmd
}

func (k *KsctlCommand) Cluster() *cobra.Command {

	cmd := &cobra.Command{
		Use: "cluster",
		Example: `
ksctl cluster --help
		`,
		Short: "Use to work with clusters",
		Long:  "It is used to work with cluster",
	}

	return cmd
}
07070100000016000081A40000000000000000000000016818E78D0000298E000000000000000000000000000000000000001900000000ksctl-2.8.0/cmd/scale.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"fmt"
	"os"
	"strconv"
	"strings"

	"github.com/ksctl/cli/v2/pkg/cli"
	"github.com/ksctl/cli/v2/pkg/telemetry"
	"github.com/ksctl/ksctl/v2/pkg/consts"
	"github.com/ksctl/ksctl/v2/pkg/errors"
	controllerCommon "github.com/ksctl/ksctl/v2/pkg/handler/cluster/common"
	"github.com/ksctl/ksctl/v2/pkg/handler/cluster/controller"
	controllerMeta "github.com/ksctl/ksctl/v2/pkg/handler/cluster/metadata"
	"github.com/ksctl/ksctl/v2/pkg/handler/cluster/selfmanaged"
	"github.com/ksctl/ksctl/v2/pkg/provider"
	"github.com/spf13/cobra"
)

func (k *KsctlCommand) ScaleUp() *cobra.Command {
	cmd := &cobra.Command{
		Use: "scaleup",
		Example: `
ksctl update scaleup --help
		`,
		Short: "Use to manually scaleup a selfmanaged cluster",
		Long:  "It is used to manually scaleup a selfmanaged cluster",

		Run: func(cmd *cobra.Command, args []string) {
			clusters, err := k.fetchSelfManagedClusters()
			if err != nil {
				k.l.Error("Error in fetching the clusters", "Error", err)
				os.Exit(1)
			}

			if len(clusters) == 0 {
				k.l.Error("There is no SelfManaged cluster")
				os.Exit(1)
			}

			selectDisplay := make(map[string]string, len(clusters))
			valueMaping := make(map[string]controller.Metadata, len(clusters))

			for idx, cluster := range clusters {
				if cluster.ClusterType == consts.ClusterTypeSelfMang {
					selectDisplay[makeHumanReadableList(cluster)] = strconv.Itoa(idx)
					valueMaping[strconv.Itoa(idx)] = controller.Metadata{
						ClusterName:   cluster.Name,
						ClusterType:   cluster.ClusterType,
						Provider:      cluster.CloudProvider,
						Region:        cluster.Region,
						StateLocation: k.KsctlConfig.PreferedStateStore,
						K8sDistro:     cluster.K8sDistro,
						K8sVersion:    cluster.K8sVersion,
						NoWP:          cluster.NoWP,
					}
				}
			}

			selectedCluster, err := k.menuDriven.DropDown(
				"Select the cluster to scaleup",
				selectDisplay,
			)
			if err != nil {
				k.l.Error("Failed to get userinput", "Reason", err)
				os.Exit(1)
			}

			m := valueMaping[selectedCluster]

			if err := k.telemetry.Send(k.Ctx, k.l, telemetry.EventClusterScaleUp, telemetry.TelemetryMeta{
				CloudProvider:     m.Provider,
				StorageDriver:     m.StateLocation,
				Region:            m.Region,
				ClusterType:       m.ClusterType,
				BootstrapProvider: m.K8sDistro,
				K8sVersion:        m.K8sVersion,
			}); err != nil {
				k.l.Debug(k.Ctx, "Failed to send the telemetry", "Reason", err)
			}

			currWP := m.NoWP

			v, ok := k.getCounterValue(
				"Enter the desired number of worker nodes",
				func(i int) bool {
					return i > currWP
				},
				currWP,
			)
			if !ok {
				k.l.Warn(k.Ctx, "Make sure the no of workernodes should be more than the current workernodes")
				os.Exit(1)
			}

			m.NoWP = v

			if err := k.loadCloudProviderCreds(m.Provider); err != nil {
				k.l.Error("Error in loading the cloud provider creds", "Error", err)
				os.Exit(1)
			}

			metaClient, err := controllerMeta.NewController(
				k.Ctx,
				k.l,
				&controller.Client{
					Metadata: m,
				},
			)
			if err != nil {
				k.l.Error("Failed to create the controller", "Reason", err)
				os.Exit(1)
			}

			category := provider.Unknown
			if m.Provider != consts.CloudLocal {
				category = k.handleInstanceCategorySelection()
			}

			wp := k.handleInstanceTypeSelection(metaClient, &m, category, "Select instance_type for Worker Nodes")

			m.WorkerPlaneNodeType = wp.Sku

			curr := "$"
			if wp.Price.Currency == "USD" {
				curr = "$"
			} else if wp.Price.Currency == "INR" {
				curr = "₹"
			} else if wp.Price.Currency == "EUR" {
				curr = "€"
			}

			k.l.Box(k.Ctx, "Updated Cost", fmt.Sprintf("Cost of the cluster will +%s%.2f (%d X %s)", curr, float64(m.NoWP-currWP)*wp.GetCost(), m.NoWP-currWP, wp.Sku))

			// {
			// 	cc := m
			// 	cc.NoWP -= currWP
			// 	k.metadataSummary(cc)
			// }

			if ok, _ := k.menuDriven.Confirmation("Do you want to proceed with the cluster scaleup", cli.WithDefaultValue("no")); !ok {
				os.Exit(1)
			}

			c, err := selfmanaged.NewController(
				k.Ctx,
				k.l,
				&controller.Client{
					Metadata: m,
				},
			)
			if err != nil {
				k.l.Error("Error in creating the controller", "Error", err)
				os.Exit(1)
			}

			if err := c.AddWorkerNodes(); err != nil {
				k.l.Error("Error in scaling up the cluster", "Error", err)
				os.Exit(1)
			}

			k.l.Success(k.Ctx, "Cluster workernode scaled up successfully")
		},
	}
	return cmd
}

func (k *KsctlCommand) ScaleDown() *cobra.Command {
	cmd := &cobra.Command{
		Use: "scaledown",
		Example: `
ksctl update scaledown --help
		`,
		Short: "Use to manually scaledown a selfmanaged cluster",
		Long:  "It is used to manually scaledown a selfmanaged cluster",

		Run: func(cmd *cobra.Command, args []string) {
			clusters, err := k.fetchSelfManagedClusters()
			if err != nil {
				k.l.Error("Error in fetching the clusters", "Error", err)
				os.Exit(1)
			}

			if len(clusters) == 0 {
				k.l.Error("There is no SelfManaged cluster")
				os.Exit(1)
			}

			selectDisplay := make(map[string]string, len(clusters))
			valueMaping := make(map[string]controller.Metadata, len(clusters))

			for idx, cluster := range clusters {
				if cluster.ClusterType == consts.ClusterTypeSelfMang {
					selectDisplay[makeHumanReadableList(cluster)] = strconv.Itoa(idx)
					valueMaping[strconv.Itoa(idx)] = controller.Metadata{
						ClusterName:   cluster.Name,
						ClusterType:   cluster.ClusterType,
						Provider:      cluster.CloudProvider,
						Region:        cluster.Region,
						StateLocation: k.KsctlConfig.PreferedStateStore,
						K8sDistro:     cluster.K8sDistro,
						K8sVersion:    cluster.K8sVersion,
						NoWP:          cluster.NoWP,
						WorkerPlaneNodeType: func() string {
							g := []string{}
							for _, v := range cluster.WP {
								g = append(g, v.VMSize)
							}
							return strings.Join(g, ",")
						}(),
					}
				}
			}

			selectedCluster, err := k.menuDriven.DropDown(
				"Select the cluster to scaledown",
				selectDisplay,
			)
			if err != nil {
				k.l.Error("Failed to get userinput", "Reason", err)
				os.Exit(1)
			}

			m := valueMaping[selectedCluster]

			if err := k.telemetry.Send(k.Ctx, k.l, telemetry.EventClusterScaleDown, telemetry.TelemetryMeta{
				CloudProvider:     m.Provider,
				StorageDriver:     m.StateLocation,
				Region:            m.Region,
				ClusterType:       m.ClusterType,
				BootstrapProvider: m.K8sDistro,
				K8sVersion:        m.K8sVersion,
			}); err != nil {
				k.l.Debug(k.Ctx, "Failed to send the telemetry", "Reason", err)
			}

			if err := k.loadCloudProviderCreds(m.Provider); err != nil {
				k.l.Error("Error in loading the cloud provider creds", "Error", err)
				os.Exit(1)
			}

			currWP := m.NoWP
			if currWP == 0 {
				k.l.Error("There is no worker node to scale down")
				os.Exit(1)
			}

			v, ok := k.getCounterValue(
				"Enter the desired number of worker nodes",
				func(i int) bool {
					return i < currWP && i >= 0
				},
				currWP,
			)
			if !ok {
				k.l.Warn(k.Ctx, "Make sure the no of workernodes should be less than the current workernodes and not less than 0")
				os.Exit(1)
			}

			m.NoWP = v

			{
				// for just showing the costs changes
				cc := m

				metaClient, err := controllerMeta.NewController(
					k.Ctx,
					k.l,
					&controller.Client{
						Metadata: cc,
					},
				)
				if err != nil {
					k.l.Error("Failed to create the controller", "Reason", err)
					os.Exit(1)
				}

				vms := strings.Split(cc.WorkerPlaneNodeType, ",")

				g := map[string]struct {
					Count int
					VM    provider.InstanceRegionOutput
				}{}

				for i := cc.NoWP; i < len(vms); i++ {
					vm := vms[i]

					wp := k.getSpecificInstanceForScaledown(metaClient, cc.Region, vm)
					if _, ok := g[wp.Sku]; ok {
						g[wp.Sku] = struct {
							Count int
							VM    provider.InstanceRegionOutput
						}{
							Count: g[wp.Sku].Count + 1,
							VM:    wp,
						}
					} else {
						g[wp.Sku] = struct {
							Count int
							VM    provider.InstanceRegionOutput
						}{
							Count: 1,
							VM:    wp,
						}
					}
				}

				curr := "$"
				total := 0.0
				vmSize := []string{}
				for k, x := range g {
					if x.VM.Price.Currency == "USD" {
						curr = "$"
					} else if x.VM.Price.Currency == "INR" {
						curr = "₹"
					} else if x.VM.Price.Currency == "EUR" {
						curr = "€"
					}
					total += float64(x.Count) * x.VM.GetCost()
					vmSize = append(vmSize, fmt.Sprintf("(%d X %s)", x.Count, k))
				}

				k.l.Box(k.Ctx, "Updated Cost", fmt.Sprintf("Cost of the cluster will -%s%.2f <%s>", curr, total, strings.Join(vmSize, ",")))

				cc.NoWP -= currWP

				cc.WorkerPlaneNodeType = strings.Join(vmSize, ",")

				// k.metadataSummary(cc)
			}

			if ok, _ := k.menuDriven.Confirmation("Do you want to proceed with the cluster scaledown", cli.WithDefaultValue("no")); !ok {
				os.Exit(1)
			}

			c, err := selfmanaged.NewController(
				k.Ctx,
				k.l,
				&controller.Client{
					Metadata: m,
				},
			)
			if err != nil {
				k.l.Error("Error in creating the controller", "Error", err)
				os.Exit(1)
			}

			if err := c.DeleteWorkerNodes(); err != nil {
				k.l.Error("Error in scaling down the cluster", "Error", err)
				os.Exit(1)
			}

			k.l.Success(k.Ctx, "Cluster workernode scaled down successfully")
		},
	}
	return cmd
}

func (k *KsctlCommand) fetchSelfManagedClusters() ([]provider.ClusterData, error) {
	m := controller.Metadata{}
	if v, ok := k.getSelectedStorageDriver(); !ok {
		return nil, errors.NewError(errors.ErrInvalidStorageProvider)
	} else {
		m.StateLocation = v
	}

	m.Provider = consts.CloudAll
	m.ClusterType = consts.ClusterTypeSelfMang

	managerClient, err := controllerCommon.NewController(
		k.Ctx,
		k.l,
		&controller.Client{
			Metadata: m,
		},
	)
	if err != nil {
		k.l.Error("unable to initialize the ksctl manager", "Reason", err)
		return nil, err
	}

	clusters, err := managerClient.ListClusters()
	if err != nil {
		return nil, err
	}
	return clusters, nil
}
07070100000017000081A40000000000000000000000016818E78D00000A94000000000000000000000000000000000000001B00000000ksctl-2.8.0/cmd/summary.gopackage cmd

import (
	"os"
	"strconv"

	"github.com/ksctl/cli/v2/pkg/cli"
	"github.com/ksctl/cli/v2/pkg/telemetry"
	"github.com/ksctl/ksctl/v2/pkg/handler/cluster/common"
	"github.com/ksctl/ksctl/v2/pkg/handler/cluster/controller"
	"github.com/spf13/cobra"
)

func (k *KsctlCommand) Summary() *cobra.Command {

	cmd := &cobra.Command{
		Use: "summary",
		Example: `
ksctl cluster summary --help
		`,
		Short: "Use to get summary of the created cluster",
		Long:  "It is used to get summary cluster",

		Run: func(cmd *cobra.Command, args []string) {
			clusters, err := k.fetchAllClusters()
			if err != nil {
				k.l.Error("Error in fetching the clusters", "Error", err)
				os.Exit(1)
			}

			if len(clusters) == 0 {
				k.l.Error("No clusters found to connect")
				os.Exit(1)
			}

			selectDisplay := make(map[string]string, len(clusters))
			valueMaping := make(map[string]controller.Metadata, len(clusters))

			for idx, cluster := range clusters {
				selectDisplay[makeHumanReadableList(cluster)] = strconv.Itoa(idx)
				valueMaping[strconv.Itoa(idx)] = controller.Metadata{
					ClusterName:   cluster.Name,
					ClusterType:   cluster.ClusterType,
					Provider:      cluster.CloudProvider,
					Region:        cluster.Region,
					StateLocation: k.KsctlConfig.PreferedStateStore,
					K8sDistro:     cluster.K8sDistro,
					K8sVersion:    cluster.K8sVersion,
				}
			}

			selectedCluster, err := k.menuDriven.DropDown(
				"Select the cluster to for summary",
				selectDisplay,
			)
			if err != nil {
				k.l.Error("Failed to get userinput", "Reason", err)
				os.Exit(1)
			}

			m := valueMaping[selectedCluster]

			if err := k.telemetry.Send(k.Ctx, k.l, telemetry.EventClusterConnect, telemetry.TelemetryMeta{
				CloudProvider:     m.Provider,
				StorageDriver:     m.StateLocation,
				Region:            m.Region,
				ClusterType:       m.ClusterType,
				BootstrapProvider: m.K8sDistro,
				K8sVersion:        m.K8sVersion,
				Addons:            telemetry.TranslateMetadata(m.Addons),
			}); err != nil {
				k.l.Debug(k.Ctx, "Failed to send the telemetry", "Reason", err)
			}

			if k.loadCloudProviderCreds(m.Provider) != nil {
				os.Exit(1)
			}

			c, err := common.NewController(
				k.Ctx,
				k.l,
				&controller.Client{
					Metadata: m,
				},
			)
			if err != nil {
				k.l.Error("Failed to create the controller", "Reason", err)
				os.Exit(1)
			}

			health, err := c.ClusterSummary()
			if err != nil {
				k.l.Error("Failed to connect to the cluster", "Reason", err)
				os.Exit(1)
			}
			printClusterSummary(health)
		},
	}

	return cmd
}

func printClusterSummary(summary *common.SummaryOutput) {
	cli.NewSummaryUI(os.Stdout).RenderClusterSummary(summary)
}
07070100000018000081A40000000000000000000000016818E78D00002372000000000000000000000000000000000000001A00000000ksctl-2.8.0/cmd/update.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"archive/tar"
	"compress/gzip"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/ksctl/cli/v2/pkg/cli"
	"github.com/ksctl/cli/v2/pkg/config"
	"github.com/ksctl/cli/v2/pkg/telemetry"
	"github.com/ksctl/ksctl/v2/pkg/poller"
	"github.com/spf13/cobra"
	"golang.org/x/mod/semver"
)

func (k *KsctlCommand) CheckForUpdates() (bool, error) {

	cacheFile := &config.UpdateCache{}
	if errC := config.LoadUpdateCache(cacheFile); errC != nil {
		k.l.Error("Failed to load update cache", "error", errC)
		return false, errC
	}
	if config.InDevMode() {
		return false, nil
	}

	if !cacheFile.LastChecked.IsZero() && time.Since(cacheFile.LastChecked) < cacheFile.UpdateCheckInterval {
		return cacheFile.AvailableVersions, nil
	}

	versions, err := k.fetchLatestVersion()
	if err != nil {
		return false, err
	}

	upgradeableVersions := k.filterToUpgradeableVersions(versions)

	cacheFile.LastChecked = time.Now()
	cacheFile.AvailableVersions = len(upgradeableVersions) > 0

	if err := config.SaveUpdateCache(cacheFile); err != nil {
		k.l.Error("Failed to save update cache", "error", err)
		return false, err
	}

	return cacheFile.AvailableVersions, nil
}

func (k *KsctlCommand) NotifyAvailableUpdates() {
	k.l.Box(k.Ctx, "Update Available! ✨", "Run 'ksctl self-update' to upgrade to the latest version!")
}

func (k *KsctlCommand) SelfUpdate() *cobra.Command {

	cmd := &cobra.Command{
		Use: "self-update",
		Example: `
ksctl self-update --help
`,
		Short: "Use to update the ksctl cli",
		Long:  "It is used to update the ksctl cli",
		Run: func(cmd *cobra.Command, args []string) {

			if config.InDevMode() {
				k.l.Error("Cannot update dev version", "msg", "Please use a stable version to update")
				os.Exit(1)
			}

			k.l.Warn(k.Ctx, "Currently no migrations are supported", "msg", "Please help us by creating a PR to support migrations. Thank you!")

			k.l.Print(k.Ctx, "Fetching available versions")
			vers, err := k.fetchLatestVersion()
			if err != nil {
				k.l.Error("Failed to fetch latest version", "error", err)
				os.Exit(1)
			}
			vers = k.filterToUpgradeableVersions(vers)

			if len(vers) == 0 {
				k.l.Note(k.Ctx, "You are already on the latest version", "version", config.Version)
				os.Exit(0)
			}

			selectedOption, err := k.menuDriven.DropDownList("Select a version to update", vers, cli.WithDefaultValue(vers[0]))
			if err != nil {
				return
			}

			newVer := selectedOption

			if err := k.telemetry.Send(k.Ctx, k.l, telemetry.EventClusterUpgrade, telemetry.TelemetryMeta{}); err != nil {
				k.l.Debug(k.Ctx, "Failed to send the telemetry", "Reason", err)
			}

			{
				c := &config.UpdateCache{}
				err := config.LoadUpdateCache(c)
				if err == nil {
					c.LastChecked = time.Now()
					c.AvailableVersions = false
					if err := config.SaveUpdateCache(c); err != nil {
						k.l.Error("Failed to save update cache", "error", err)
					}
				} else {
					k.l.Error("Failed to load update cache", "error", err)
				}
			}

			if err := k.update(newVer); err != nil {
				k.l.Error("Failed to update ksctl cli", "error", err)
				os.Exit(1)
			}

			k.l.Box(k.Ctx, "Updated Successful 🎉", "ksctl has been updated to version "+newVer)
		},
	}

	return cmd
}

func (k *KsctlCommand) fetchLatestVersion() ([]string, error) {

	poller.InitSharedGithubReleasePoller()
	return poller.GetSharedPoller().Get("ksctl", "cli")
}

func (k *KsctlCommand) filterToUpgradeableVersions(versions []string) []string {
	var upgradeableVersions []string
	for _, version := range versions {
		if semver.Compare(version, config.Version) > 0 {
			upgradeableVersions = append(upgradeableVersions, version)
		}
	}
	return upgradeableVersions
}

func (k *KsctlCommand) downloadFile(url, localFilename string) error {
	k.l.Print(k.Ctx, "Downloading file", "url", url, "localFilename", localFilename)

	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	out, err := os.Create(localFilename)
	if err != nil {
		return err
	}
	defer out.Close()

	_, err = io.Copy(out, resp.Body)
	return err
}
func (k *KsctlCommand) verifyChecksum(filePath, checksumfileLoc string) (bool, error) {
	k.l.Print(k.Ctx, "Verifying checksum", "file", filePath, "checksumfile", checksumfileLoc)

	rawChecksum, err := os.ReadFile(checksumfileLoc)
	if err != nil {
		return false, err
	}
	checksums := strings.Split(string(rawChecksum), "\n")

	var expectedChecksum string = "LOL"
	for _, line := range checksums {
		if strings.Contains(line, filePath) {
			expectedChecksum = strings.Fields(line)[0]
			break
		}
	}
	if expectedChecksum == "LOL" {
		return false, k.l.NewError(k.Ctx, "Checksum not found in checksum file")
	}

	file, err := os.Open(filePath)
	if err != nil {
		return false, err
	}
	defer file.Close()

	hash := sha256.New()
	if _, err := io.Copy(hash, file); err != nil {
		return false, err
	}

	calculatedChecksum := hex.EncodeToString(hash.Sum(nil))
	return calculatedChecksum == expectedChecksum, nil
}

func (k *KsctlCommand) getOsArch() (string, error) {
	arch := runtime.GOARCH

	if arch != "amd64" && arch != "arm64" {
		return "", k.l.NewError(k.Ctx, "Unsupported architecture")
	}
	return arch, nil
}

func (k *KsctlCommand) getOs() (string, error) {
	goos := runtime.GOOS

	if goos != "linux" && goos != "darwin" {
		return "", k.l.NewError(k.Ctx, "Unsupported OS", "message", "will provide support for windows based OS soon")
	}
	return goos, nil
}

func (k *KsctlCommand) update(version string) error {
	osName, err := k.getOs()
	if err != nil {
		return err
	}
	archName, err := k.getOsArch()
	if err != nil {
		return err
	}

	k.l.Print(k.Ctx, "Delected System", "OS", osName, "Arch", archName)
	downloadURLBase := fmt.Sprintf("https://github.com/ksctl/cli/releases/download/%s", version)
	tarFile := fmt.Sprintf("ksctl-cli_%s_%s_%s.tar.gz", version[1:], osName, archName)
	checksumFile := fmt.Sprintf("ksctl-cli_%s_checksums.txt", version[1:])

	tarUri := fmt.Sprintf("%s/%s", downloadURLBase, tarFile)
	checksumUri := fmt.Sprintf("%s/%s", downloadURLBase, checksumFile)

	defer func() {
		k.l.Print(k.Ctx, "Cleaning up")
		if err := os.Remove(checksumFile); err != nil {
			k.l.Error("Failed to remove checksum file", "error", err)
		}

		if err := os.Remove(tarFile); err != nil {
			k.l.Error("Failed to remove checksum file", "error", err)
		}
	}()

	if err := k.downloadFile(tarUri, tarFile); err != nil {
		return err
	}

	if err := k.downloadFile(checksumUri, checksumFile); err != nil {
		return err
	}

	match, err := k.verifyChecksum(tarFile, checksumFile)
	if err != nil {
		return k.l.NewError(k.Ctx, "Failed to verify checksum", "error", err)
	}
	if !match {
		return k.l.NewError(k.Ctx, "Checksum verification failed")
	}
	k.l.Success(k.Ctx, "Checksum verification successful")

	tempDir, err := os.MkdirTemp("", "ksctl-update")
	if err != nil {
		return k.l.NewError(k.Ctx, "Failed to create temp dir", "error", err)
	}
	file, err := os.Open(tarFile)
	if err != nil {
		return k.l.NewError(k.Ctx, "Failed to open tar file", "error", err)
	}
	defer file.Close()

	gzr, err := gzip.NewReader(file)
	if err != nil {
		return k.l.NewError(k.Ctx, "Failed to read gzip file", "error", err)
	}
	defer gzr.Close()
	tr := tar.NewReader(gzr)
	for {
		header, err := tr.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return k.l.NewError(k.Ctx, "Failed to read tar file", "error", err)
		}
		if header.Name == "ksctl" {
			outFile, err := os.Create(filepath.Join(tempDir, "ksctl"))
			if err != nil {
				return k.l.NewError(k.Ctx, "Failed to create ksctl binary", "error", err)
			}
			defer outFile.Close()

			if _, err := io.Copy(outFile, tr); err != nil {
				return k.l.NewError(k.Ctx, "Failed to copy ksctl binary", "error", err)
			}
			break
		}
	}

	k.l.Print(k.Ctx, "Making ksctl executable...")
	if err := os.Chmod(filepath.Join(tempDir, "ksctl"), 0550); err != nil {
		return k.l.NewError(k.Ctx, "Failed to make ksctl executable", "error", err)
	}

	k.l.Print(k.Ctx, "Moving ksctl to /usr/local/bin (requires sudo)...")
	cmd := exec.Command("sudo", "mv", "-v", filepath.Join(tempDir, "ksctl"), "/usr/local/bin/ksctl")
	err = cmd.Run()
	if err != nil {
		return k.l.NewError(k.Ctx, "Failed to move ksctl to /usr/local/bin", "error", err)
	}

	_, err = exec.LookPath("ksctl")
	if err != nil {
		return k.l.NewError(k.Ctx, "Failed to find ksctl in PATH", "error", err)
	}

	return nil
}
07070100000019000081A40000000000000000000000016818E78D000023D7000000000000000000000000000000000000001D00000000ksctl-2.8.0/cmd/userinput.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"context"
	"fmt"
	"strconv"
	"strings"

	"github.com/ksctl/cli/v2/pkg/cli"
	"github.com/ksctl/ksctl/v2/pkg/consts"
	"github.com/ksctl/ksctl/v2/pkg/provider"
)

func (k *KsctlCommand) getClusterName() (string, bool) {
	v, err := k.menuDriven.TextInput("Enter Cluster Name")
	if err != nil {
		k.l.Error("Failed to get userinput", "Reason", err)
		return "", false
	}
	if len(v) == 0 {
		k.l.Error("Cluster name cannot be empty")
		return "", false
	}
	k.l.Debug(k.Ctx, "Text input", "clusterName", v)
	return v, true
}

func (k *KsctlCommand) getBootstrap() (consts.KsctlKubernetes, bool) {
	v, err := k.menuDriven.DropDown(
		"Select the bootstrap type",
		map[string]string{
			"Kubeadm": string(consts.K8sKubeadm),
			"K3s":     string(consts.K8sK3s),
		},
		cli.WithDefaultValue(string(consts.K8sK3s)),
	)
	if err != nil {
		k.l.Error("Failed to get userinput", "Reason", err)
		return "", false
	}
	k.l.Debug(k.Ctx, "DropDown input", "bootstrapType", v)
	return consts.KsctlKubernetes(v), true
}

type userInputValidation func(int) bool

func (k *KsctlCommand) getCounterValue(prompt string, validate userInputValidation, defaultVal int) (int, bool) {
	v, err := k.menuDriven.TextInput(prompt, cli.WithDefaultValue(strconv.Itoa(defaultVal)))
	if err != nil {
		k.l.Error("Failed to get userinput", "Reason", err)
		return 0, false
	}
	_v, err := strconv.Atoi(v)
	if err != nil {
		k.l.Error("Invalid input", "Reason", err)
		return 0, false
	}

	if !validate(_v) {
		k.l.Error("Invalid input")
		return 0, false
	}
	k.l.Debug(k.Ctx, "Text input", "counterValue", v)
	return _v, true
}

func (k *KsctlCommand) getSelectedRegion(regions provider.RegionsOutput) (string, bool) {
	k.l.Debug(k.Ctx, "Regions", "regions", regions)

	if v, err := k.menuDriven.DropDown(
		"Select the region",
		CliRegions(regions).S(),
	); err != nil {
		k.l.Error("Failed to get userinput", "Reason", err)
		return "", false
	} else {
		k.l.Debug(k.Ctx, "DropDown input", "region", v)
		return v, true
	}
}

func (k *KsctlCommand) getSelectedInstanceCategory(categories map[string]provider.MachineCategory) (provider.MachineCategory, bool) {
	k.l.Debug(k.Ctx, "Instance categories", "categories", categories)

	vr := make(map[string]string, len(categories))

	for k, _v := range categories {
		useCases := strings.Join(_v.UseCases(), ", ")
		key := fmt.Sprintf("%s\n   Used for: %s\n", k, useCases)
		vr[key] = string(_v)
	}

	if v, err := k.menuDriven.DropDown(
		"Let us know about your workload type",
		vr,
	); err != nil {
		k.l.Error("Failed to get userinput", "Reason", err)
		return "", false
	} else {
		k.l.Debug(k.Ctx, "DropDown input", "instanceCategory", v)
		return provider.MachineCategory(v), true
	}
}

func (k *KsctlCommand) getSelectedK8sVersion(prompt string, vers []string) (string, bool) {
	k.l.Debug(k.Ctx, "List of k8s versions", "versions", vers)

	if v, err := k.menuDriven.DropDownList(
		prompt,
		vers,
		cli.WithDefaultValue(vers[0]),
	); err != nil {
		k.l.Error("Failed to get userinput", "Reason", err)
		return "", false
	} else {
		k.l.Debug(k.Ctx, "DropDown input", "k8sVersion", v)
		return v, true
	}
}

type CliRegions provider.RegionsOutput

func (r CliRegions) S() map[string]string {
	m := make(map[string]string, len(r))
	for _, region := range r {
		desc := region.Name
		if region.Emission != nil {
			emissionEmoji := "🔴" // High emissions (default)
			if region.Emission.DirectCarbonIntensity < 200 {
				emissionEmoji = "🟢" // Low emissions
			} else if region.Emission.DirectCarbonIntensity < 400 {
				emissionEmoji = "🟡" // Medium emissions
			}

			carbonInfo := fmt.Sprintf("🏭 Direct %.2f %s, Lifecycle %.2f %s",
				region.Emission.DirectCarbonIntensity,
				region.Emission.Unit,
				region.Emission.LCACarbonIntensity,
				region.Emission.Unit)

			percentageInfo := ""
			if region.Emission.RenewablePercentage > 0 {
				percentageInfo += fmt.Sprintf(", ♻️ %.1f%% renewable", region.Emission.RenewablePercentage)
			}
			if region.Emission.LowCarbonPercentage > 0 {
				percentageInfo += fmt.Sprintf(", 👣 %.1f%% low-carbon", region.Emission.LowCarbonPercentage)
			}

			desc += fmt.Sprintf(" %s (%s: %s%s)", emissionEmoji, region.Emission.CalcMethod, carbonInfo, percentageInfo)
		}
		m[desc] = region.Sku
	}
	return m
}

type CliInstances provider.InstancesRegionOutput

func (I CliInstances) S() map[string]string {
	m := make(map[string]string, len(I))
	for _, vm := range I {
		if vm.CpuArch == provider.ArchAmd64 {
			displayName := fmt.Sprintf("%s (vCPUs: %d, Memory: %dGB)",
				vm.Description,
				vm.VCpus,
				vm.Memory,
			)
			displayName += fmt.Sprintf(", Price: %.2f %s/month",
				vm.GetCost(),
				vm.Price.Currency,
			)

			if vm.EmboddedEmissions != nil {
				displayName += fmt.Sprintf(", Embodied Emission: %.2f %s",
					vm.EmboddedEmissions.EmboddedCo2,
					vm.EmboddedEmissions.Co2Unit,
				)
			}

			m[displayName] = vm.Sku
		}
	}
	return m
}

func (k *KsctlCommand) getSelectedInstanceType(
	prompt string,
	vms provider.InstancesRegionOutput,
) (string, bool) {
	vr := CliInstances(vms).S()

	k.l.Debug(k.Ctx, "Instance types", "vms", vr)

	if v, err := k.menuDriven.DropDown(
		prompt,
		vr,
	); err != nil {
		k.l.Error("Failed to get userinput", "Reason", err)
		return "", false
	} else {
		k.l.Debug(k.Ctx, "DropDown input", "instanceType", v)
		return v, true
	}
}

func (k *KsctlCommand) getSelectedManagedClusterOffering(
	prompt string,
	offerings map[string]provider.ManagedClusterOutput,
) (string, bool) {
	vr := make(map[string]string, len(offerings))
	for _, o := range offerings {
		displayName := fmt.Sprintf("%s, Price: %.2f %s/month",
			o.Description,
			o.GetCost(),
			o.Price.Currency,
		)

		vr[displayName] = o.Sku
	}

	k.l.Debug(k.Ctx, "Offerings", "offerings", vr)

	if v, err := k.menuDriven.DropDown(
		prompt,
		vr,
	); err != nil {
		k.l.Error("Failed to get userinput", "Reason", err)
		return "", false
	} else {
		k.l.Debug(k.Ctx, "DropDown input", "managedClusterOffering", v)
		return v, true
	}
}

func (k *KsctlCommand) getSelectedClusterType() (consts.KsctlClusterType, bool) {
	if v, err := k.menuDriven.DropDown(
		"Select the cluster type",
		map[string]string{
			"Cloud Managed (For ex. EKS, AKS, Kind)":   string(consts.ClusterTypeMang),
			"Self Managed (For example, K3s, Kubeadm)": string(consts.ClusterTypeSelfMang),
		},
		cli.WithDefaultValue(string(consts.ClusterTypeMang)),
	); err != nil {
		k.l.Error("Failed to get userinput", "Reason", err)
		return "", false
	} else {
		k.l.Debug(k.Ctx, "DropDown input", "clusterType", v)
		return consts.KsctlClusterType(v), true
	}
}

func (k *KsctlCommand) getSelectedCloudProvider(v consts.KsctlClusterType) (consts.KsctlCloud, bool) {
	options := map[string]string{
		"Amazon Web Services": string(consts.CloudAws),
		"Azure":               string(consts.CloudAzure),
	}

	if v == consts.ClusterTypeMang {
		options["Kind"] = string(consts.CloudLocal)
	}

	if v, err := k.menuDriven.DropDown(
		"Select the cloud provider",
		options,
	); err != nil {
		k.l.Error("Failed to get userinput", "Reason", err)
		return "", false
	} else {
		k.l.Debug(k.Ctx, "DropDown input", "cloudProvider", v)

		if err := k.loadCloudProviderCreds(consts.KsctlCloud(v)); err != nil {
			return "", false
		}

		return consts.KsctlCloud(v), true
	}
}

func (k *KsctlCommand) loadCloudProviderCreds(v consts.KsctlCloud) error {
	switch v {
	case consts.CloudAws:
		if v, err := k.loadAwsCredentials(); err != nil {
			k.l.Error("Failed to load the AWS credentials", "Reason", err)
			return err
		} else {
			k.Ctx = context.WithValue(k.Ctx, consts.KsctlAwsCredentials, v)
		}

	case consts.CloudAzure:
		if v, err := k.loadAzureCredentials(); err != nil {
			k.l.Error("Failed to load the Azure credentials", "Reason", err)
			return err
		} else {
			k.Ctx = context.WithValue(k.Ctx, consts.KsctlAzureCredentials, v)
		}
	}
	return nil
}

func (k *KsctlCommand) getSelectedStorageDriver() (consts.KsctlStore, bool) {
	if k.KsctlConfig.PreferedStateStore != consts.StoreExtMongo && k.KsctlConfig.PreferedStateStore != consts.StoreLocal {
		k.l.Error("Failed to determine StorageDriver", "message", "Please use $ksctl configure to set the storage driver", "currentSetValue", k.KsctlConfig.PreferedStateStore)
		return "", false
	}

	if k.KsctlConfig.PreferedStateStore == consts.StoreExtMongo {
		if errS := k.loadMongoCredentials(); errS != nil {
			k.l.Error("Failed to load the MongoDB credentials", "Reason", errS)
			return "", false
		}
	}

	return k.KsctlConfig.PreferedStateStore, true
}
0707010000001A000081A40000000000000000000000016818E78D00005444000000000000000000000000000000000000001B00000000ksctl-2.8.0/cmd/version.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"fmt"

	"github.com/fatih/color"
	"github.com/ksctl/cli/v2/pkg/config"
	"github.com/spf13/cobra"
)

func (k *KsctlCommand) Version() *cobra.Command {

	logoKsctl := `
[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⣗[0m[48;2;218;226;214m⣗[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⡪[0m[48;2;218;226;214m⣗[0m[48;2;218;226;214m⡽[0m[48;2;218;226;214m⠵[0m[48;2;218;226;214m⡳[0m[48;2;218;226;214m⠽[0m[48;2;218;226;214m⢝[0m[48;2;218;226;214m⡮[0m[48;2;218;226;214m⣳[0m[48;2;218;226;214m⣝[0m[48;2;218;226;214m⡮[0m[48;2;218;226;214m⠷[0m[48;2;218;226;214m⠝[0m[48;2;218;226;214m⣗[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⡪[0m[48;2;218;226;214m⣗[0m[48;2;218;226;214m⢷[0m[48;2;218;226;214m⢝[0m[48;2;218;226;214m⣗[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⡪[0m[48;2;218;226;214m⣯[0m[48;2;218;226;214m⡳[0m[48;2;218;226;214m⡽[0m[48;2;218;226;214m⣝[0m[48;2;218;226;214m⢮[0m[48;2;218;226;214m⢯[0m[48;2;218;226;214m⣳[0m[48;2;218;226;214m⡳[0m[48;2;218;226;214m⡽[0m[48;2;218;226;214m⣝[0m[48;2;218;226;214m⣞[0m[48;2;218;226;214m⢮[0m[48;2;218;226;214m⣳[0m[48;2;218;226;214m⡳[0m[48;2;218;226;214m⡽[0m[48;2;218;226;214m⣝[0m[48;2;218;226;214m⢞[0m[48;2;218;226;214m⢮[0m[48;2;218;226;214m⣳[0m[48;2;218;226;214m⡳[0m[48;2;218;226;214m⡽[0m[48;2;218;226;214m⣝[0m[48;2;218;226;214m⢞[0m[48;2;218;226;214m⢮[0m[48;2;218;226;214m⣳[0m[48;2;218;226;214m⡳[0m[48;2;218;226;214m⡽[0m[48;2;218;226;214m⣝[0m[48;2;218;226;214m⢮[0m[48;2;218;226;214m⢯[0m[48;2;218;226;214m⡳[0m
[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⣗[0m[48;2;218;226;214m⣗[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⡺[0m[48;2;218;226;214m⡜[0m[48;2;216;224;212m⢊[0m[48;2;226;233;220m⠡[0m[48;2;128;155;149m⡀[0m[48;2;58;99;97m⢁[0m[48;2;53;95;94m⠠[0m[48;2;56;98;96m⠀[0m[48;2;55;97;95m⢔[0m[48;2;224;231;219m⡯[0m[48;2;218;226;214m⣞[0m[48;2;216;224;212m⠎[0m[48;2;182;198;188m⠠[0m[48;2;51;94;92m⢐[0m[48;2;47;91;90m⣰[0m[48;2;192;205;195m⡳[0m[48;2;217;225;213m⣝[0m[48;2;218;226;214m⢮[0m[48;2;218;226;214m⣳[0m[48;2;218;226;214m⢝[0m[48;2;218;226;214m⣗[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⣕[0m[48;2;218;226;214m⢯[0m[48;2;218;226;214m⡺[0m[48;2;218;226;214m⡮[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⣗[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢝[0m[48;2;218;226;214m⡮[0m[48;2;218;226;214m⡮[0m[48;2;218;226;214m⣳[0m[48;2;218;226;214m⡳[0m[48;2;218;226;214m⣝[0m[48;2;218;226;214m⣞[0m[48;2;218;226;214m⢮[0m[48;2;218;226;214m⢯[0m[48;2;218;226;214m⣳[0m[48;2;218;226;214m⡳[0m[48;2;215;224;212m⠙[0m[48;2;217;225;214m⠚[0m[48;2;222;229;217m⠊[0m[48;2;228;234;221m⢹[0m[48;2;218;226;214m⡳[0m[48;2;218;226;214m⡵[0m[48;2;218;226;214m⣝[0m[48;2;218;226;214m⣞[0m[48;2;218;226;214m⢮[0m[48;2;218;226;214m⢯[0m[48;2;218;226;214m⡳[0m[48;2;218;226;214m⡽[0m
[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⣗[0m[48;2;218;226;214m⢗[0m[48;2;218;226;214m⡗[0m[48;2;229;234;222m⠡[0m[48;2;61;101;99m⠐[0m[48;2;65;105;103m⣰[0m[48;2;156;176;168m⢝[0m[48;2;212;221;210m⠂[0m[48;2;61;101;99m⠄[0m[48;2;63;103;101m⡀[0m[48;2;65;104;102m⠂[0m[48;2;171;189;180m⣯[0m[48;2;216;225;213m⡺[0m[48;2;227;233;220m⠁[0m[48;2;59;100;98m⠂[0m[48;2;66;106;104m⣡[0m[48;2;133;159;152m⢞[0m[48;2;216;224;212m⣞[0m[48;2;218;226;214m⢮[0m[48;2;218;226;214m⡳[0m[48;2;218;226;214m⣝[0m[48;2;218;226;214m⡮[0m[48;2;218;226;214m⣳[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⣕[0m[48;2;218;226;214m⢷[0m[48;2;218;226;214m⢝[0m[48;2;218;226;214m⡮[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢵[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢝[0m[48;2;218;226;214m⡵[0m[48;2;218;226;214m⣫[0m[48;2;218;226;214m⢯[0m[48;2;220;228;216m⠎[0m[48;2;171;188;179m⢈[0m[48;2;131;157;150m⠀[0m[48;2;93;127;123m⡀[0m[48;2;73;111;108m⢜[0m[48;2;222;229;217m⣗[0m[48;2;218;226;214m⢵[0m[48;2;220;227;215m⠅[0m[48;2;59;100;98m⠐[0m[48;2;65;104;102m⠈[0m[48;2;66;105;103m⡀[0m[48;2;147;169;162m⣽[0m[48;2;216;224;212m⣪[0m[48;2;218;226;214m⣻[0m[48;2;218;226;214m⡺[0m[48;2;218;226;214m⣪[0m[48;2;218;226;214m⢯[0m[48;2;218;226;214m⡳[0m[48;2;218;226;214m⡽[0m[48;2;218;226;214m⣝[0m
[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢵[0m[48;2;218;226;214m⢽[0m[48;2;216;224;212m⡝[0m[48;2;144;167;160m⢀[0m[48;2;66;106;104m⠐[0m[48;2;55;96;95m⡸[0m[48;2;228;234;221m⣕[0m[48;2;218;226;214m⡯[0m[48;2;89;124;120m⠐[0m[48;2;64;104;102m⢀[0m[48;2;63;103;101m⠐[0m[48;2;52;94;93m⢸[0m[48;2;227;233;220m⠎[0m[48;2;186;200;190m⠐[0m[48;2;65;104;102m⣈[0m[48;2;69;108;106m⢮[0m[48;2;225;231;219m⣳[0m[48;2;218;226;214m⢝[0m[48;2;218;226;214m⡮[0m[48;2;218;226;214m⣳[0m[48;2;218;226;214m⢝[0m[48;2;218;226;214m⡮[0m[48;2;218;226;214m⠻[0m[48;2;217;225;213m⠪[0m[48;2;216;224;212m⠓[0m[48;2;217;225;213m⢳[0m[48;2;218;226;214m⣝[0m[48;2;218;226;214m⣗[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢝[0m[48;2;218;226;214m⡮[0m[48;2;218;226;214m⣳[0m[48;2;218;226;214m⠽[0m[48;2;218;226;214m⠵[0m[48;2;218;226;214m⡫[0m[48;2;218;226;214m⢗[0m[48;2;218;226;214m⡽[0m[48;2;218;226;214m⣪[0m[48;2;217;225;213m⢯[0m[48;2;191;204;194m⠁[0m[48;2;63;103;101m⠄[0m[48;2;63;103;101m⠠[0m[48;2;63;103;101m⢀[0m[48;2;191;204;194m⢯[0m[48;2;217;225;213m⢮[0m[48;2;216;225;213m⠯[0m[48;2;111;141;136m⠀[0m[48;2;65;105;103m⠌[0m[48;2;63;103;101m⢀[0m[48;2;52;94;93m⢰[0m[48;2;228;234;222m⡳[0m[48;2;218;226;214m⣕[0m[48;2;218;226;214m⣗[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⡪[0m[48;2;218;226;214m⣗[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⣝[0m[48;2;218;226;214m⢮[0m
[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢕[0m[48;2;229;235;222m⡧[0m[48;2;52;94;93m⡀[0m[48;2;65;105;103m⠄[0m[48;2;164;184;175m⢝[0m[48;2;216;224;212m⣞[0m[48;2;226;232;220m⠆[0m[48;2;54;96;94m⠐[0m[48;2;63;103;101m⠀[0m[48;2;65;105;103m⠄[0m[48;2;133;158;152m⠑[0m[48;2;58;99;98m⠠[0m[48;2;52;94;93m⠼[0m[48;2;228;234;221m⢮[0m[48;2;218;226;214m⢯[0m[48;2;218;226;214m⡺[0m[48;2;218;226;214m⡵[0m[48;2;218;226;214m⣻[0m[48;2;218;226;214m⡪[0m[48;2;216;224;212m⡟[0m[48;2;170;188;179m⡀[0m[48;2;60;101;99m⠐[0m[48;2;63;103;101m⠀[0m[48;2;67;107;104m⠂[0m[48;2;110;141;136m⢱[0m[48;2;216;225;213m⡳[0m[48;2;218;226;214m⣕[0m[48;2;218;226;214m⢯[0m[48;2;218;226;214m⡳[0m[48;2;217;225;213m⠋[0m[48;2;198;211;200m⡀[0m[48;2;70;109;106m⠂[0m[48;2;52;95;93m⣄[0m[48;2;52;94;93m⡤[0m[48;2;55;97;95m⠀[0m[48;2;175;192;183m⠙[0m[48;2;214;223;211m⣞[0m[48;2;108;138;134m⡤[0m[48;2;64;104;102m⠐[0m[48;2;63;103;101m⠀[0m[48;2;63;103;101m⠂[0m[48;2;63;103;101m⢤[0m[48;2;58;99;97m⣢[0m[48;2;160;180;172m⣺[0m[48;2;227;233;220m⢃[0m[48;2;52;94;93m⠁[0m[48;2;63;103;101m⠐[0m[48;2;65;104;102m⡀[0m[48;2;101;134;129m⢼[0m[48;2;217;225;213m⣺[0m[48;2;218;226;214m⡺[0m[48;2;218;226;214m⣪[0m[48;2;218;226;214m⢗[0m[48;2;218;226;214m⡽[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⢷[0m[48;2;218;226;214m⢝[0m
[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⡯[0m[48;2;219;227;215m⡳[0m[48;2;80;117;113m⡦[0m[48;2;106;138;133m⡳[0m[48;2;214;223;211m⣝[0m[48;2;131;157;151m⠀[0m[48;2;66;105;103m⠌[0m[48;2;63;103;101m⠠[0m[48;2;63;103;101m⢨[0m[48;2;59;100;98m⢤[0m[48;2;64;104;102m⡅[0m[48;2;51;94;92m⠐[0m[48;2;57;98;96m⢀[0m[48;2;120;148;142m⠈[0m[48;2;222;229;217m⢫[0m[48;2;218;226;214m⢯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⣺[0m[48;2;227;233;220m⠁[0m[48;2;53;95;94m⣐[0m[48;2;63;103;101m⠈[0m[48;2;63;103;101m⡀[0m[48;2;64;104;102m⢁[0m[48;2;83;119;116m⢸[0m[48;2;219;227;215m⢝[0m[48;2;218;226;214m⡮[0m[48;2;215;224;212m⡏[0m[48;2;149;171;163m⠠[0m[48;2;66;106;103m⠀[0m[48;2;63;103;101m⠄[0m[48;2;52;94;93m⣲[0m[48;2;231;236;224m⢳[0m[48;2;220;228;216m⢝[0m[48;2;69;108;105m⠀[0m[48;2;57;98;97m⣢[0m[48;2;221;229;216m⣳[0m[48;2;219;227;215m⠅[0m[48;2;57;98;97m⠐[0m[48;2;63;103;101m⠈[0m[48;2;66;105;103m⡀[0m[48;2;144;167;160m⣗[0m[48;2;215;224;212m⢵[0m[48;2;216;224;212m⢽[0m[48;2;156;177;169m⠀[0m[48;2;65;105;103m⠄[0m[48;2;63;103;101m⢁[0m[48;2;58;99;97m⢠[0m[48;2;215;224;212m⡻[0m[48;2;218;226;214m⣜[0m[48;2;218;226;214m⢮[0m[48;2;218;226;214m⣳[0m[48;2;218;226;214m⢝[0m[48;2;218;226;214m⡮[0m[48;2;218;226;214m⣗[0m[48;2;218;226;214m⢯[0m[48;2;218;226;214m⢯[0m[48;2;218;226;214m⣫[0m
[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣫[0m[48;2;218;226;214m⢯[0m[48;2;229;235;222m⡃[0m[48;2;52;94;93m⠄[0m[48;2;63;103;101m⠂[0m[48;2;64;104;102m⠐[0m[48;2;86;121;118m⣸[0m[48;2;218;226;214m⣕[0m[48;2;217;226;214m⢯[0m[48;2;81;118;114m⠂[0m[48;2;64;104;102m⢀[0m[48;2;64;104;102m⠂[0m[48;2;84;120;116m⢸[0m[48;2;219;227;215m⡳[0m[48;2;218;226;214m⡵[0m[48;2;227;233;221m⡃[0m[48;2;53;95;94m⢠[0m[48;2;214;223;211m⡗[0m[48;2;53;95;94m⡀[0m[48;2;63;103;101m⠄[0m[48;2;63;103;101m⠠[0m[48;2;60;101;99m⠨[0m[48;2;225;231;219m⣗[0m[48;2;216;224;212m⡝[0m[48;2;119;148;142m⠀[0m[48;2;66;105;103m⡐[0m[48;2;63;103;101m⠀[0m[48;2;53;95;93m⢢[0m[48;2;228;234;221m⢯[0m[48;2;218;226;214m⡫[0m[48;2;217;225;213m⣏[0m[48;2;228;234;221m⢯[0m[48;2;226;232;220m⡺[0m[48;2;216;225;213m⡮[0m[48;2;110;141;135m⠀[0m[48;2;65;105;102m⡈[0m[48;2;63;103;101m⠄[0m[48;2;53;95;93m⢰[0m[48;2;228;234;221m⢝[0m[48;2;218;226;214m⡽[0m[48;2;226;233;220m⡕[0m[48;2;56;98;96m⠀[0m[48;2;63;103;101m⡐[0m[48;2;64;103;101m⠀[0m[48;2;68;107;105m⣸[0m[48;2;222;229;217m⢮[0m[48;2;218;226;214m⣳[0m[48;2;218;226;214m⡫[0m[48;2;218;226;214m⣞[0m[48;2;218;226;214m⢵[0m[48;2;218;226;214m⡫[0m[48;2;218;226;214m⣞[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⣕[0m[48;2;218;226;214m⣗[0m
[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;216;225;213m⢵[0m[48;2;177;193;184m⠁[0m[48;2;64;104;102m⠠[0m[48;2;63;103;101m⠈[0m[48;2;61;101;99m⢠[0m[48;2;204;215;204m⡳[0m[48;2;217;225;213m⣳[0m[48;2;227;233;221m⠣[0m[48;2;55;97;95m⠐[0m[48;2;63;103;101m⠀[0m[48;2;66;105;103m⠄[0m[48;2;140;164;157m⡽[0m[48;2;216;224;212m⡪[0m[48;2;224;230;218m⠃[0m[48;2;61;101;100m⠄[0m[48;2;182;197;187m⢷[0m[48;2;218;226;214m⢽[0m[48;2;77;115;112m⠀[0m[48;2;64;104;102m⠐[0m[48;2;63;103;101m⡀[0m[48;2;52;94;93m⠌[0m[48;2;229;235;222m⣞[0m[48;2;213;222;210m⠆[0m[48;2;59;100;98m⠁[0m[48;2;63;103;101m⠠[0m[48;2;66;105;103m⠈[0m[48;2;136;161;154m⡮[0m[48;2;215;224;212m⣳[0m[48;2;218;226;214m⢝[0m[48;2;218;226;214m⡮[0m[48;2;218;226;214m⣗[0m[48;2;218;226;214m⢽[0m[48;2;229;235;222m⠕[0m[48;2;52;94;93m⠀[0m[48;2;63;103;101m⠄[0m[48;2;65;104;102m⠂[0m[48;2;100;133;128m⡼[0m[48;2;217;225;213m⡳[0m[48;2;217;225;213m⣝[0m[48;2;196;208;198m⠂[0m[48;2;62;103;101m⠄[0m[48;2;63;103;101m⠐[0m[48;2;64;104;102m⢀[0m[48;2;183;198;189m⣗[0m[48;2;216;225;213m⢗[0m[48;2;218;226;214m⣗[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⡺[0m[48;2;218;226;214m⣝[0m[48;2;218;226;214m⢮[0m[48;2;218;226;214m⢗[0m[48;2;218;226;214m⣗[0m[48;2;218;226;214m⣗[0m[48;2;218;226;214m⢵[0m
[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⡺[0m[48;2;223;230;218m⡇[0m[48;2;65;104;102m⠂[0m[48;2;63;103;101m⢁[0m[48;2;63;103;101m⠈[0m[48;2;60;101;99m⡰[0m[48;2;225;231;219m⡯[0m[48;2;216;224;212m⣺[0m[48;2;171;188;179m⠁[0m[48;2;65;104;102m⠠[0m[48;2;63;103;101m⠁[0m[48;2;52;94;93m⣨[0m[48;2;227;233;221m⣻[0m[48;2;176;193;184m⠀[0m[48;2;65;105;103m⢡[0m[48;2;68;107;105m⡠[0m[48;2;154;175;168m⡯[0m[48;2;213;222;211m⡫[0m[48;2;118;147;141m⠂[0m[48;2;65;105;103m⠁[0m[48;2;63;103;101m⠠[0m[48;2;54;96;95m⠐[0m[48;2;225;232;219m⠩[0m[48;2;134;159;153m⡀[0m[48;2;66;105;103m⠌[0m[48;2;63;103;101m⠀[0m[48;2;61;102;100m⠂[0m[48;2;202;213;202m⢯[0m[48;2;217;225;213m⡺[0m[48;2;218;226;214m⣝[0m[48;2;218;226;214m⡮[0m[48;2;218;226;214m⡗[0m[48;2;218;226;214m⠋[0m[48;2;115;144;139m⠠[0m[48;2;65;104;102m⠈[0m[48;2;63;103;101m⡀[0m[48;2;58;99;98m⠂[0m[48;2;215;223;212m⡯[0m[48;2;218;226;214m⡯[0m[48;2;219;227;215m⠎[0m[48;2;78;115;112m⢀[0m[48;2;64;104;102m⠂[0m[48;2;63;103;101m⢁[0m[48;2;53;95;94m⢰[0m[48;2;228;234;221m⡳[0m[48;2;218;226;214m⣝[0m[48;2;218;226;214m⢮[0m[48;2;218;226;214m⡳[0m[48;2;218;226;214m⣝[0m[48;2;218;226;214m⢮[0m[48;2;218;226;214m⢯[0m[48;2;218;226;214m⣳[0m[48;2;218;226;214m⡳[0m[48;2;218;226;214m⡳[0m[48;2;218;226;214m⡽[0m
[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣫[0m[48;2;217;226;214m⣻[0m[48;2;211;220;209m⠂[0m[48;2;59;100;98m⢈[0m[48;2;63;103;101m⠀[0m[48;2;65;105;103m⠄[0m[48;2;166;185;176m⡯[0m[48;2;216;224;212m⣫[0m[48;2;227;233;221m⡎[0m[48;2;55;97;95m⠀[0m[48;2;63;103;101m⠂[0m[48;2;65;105;103m⡐[0m[48;2;129;155;149m⢸[0m[48;2;214;223;211m⡺[0m[48;2;104;135;131m⣄[0m[48;2;56;97;96m⠠[0m[48;2;231;237;224m⠉[0m[48;2;229;235;222m⡉[0m[48;2;183;198;188m⠄[0m[48;2;59;100;98m⢁[0m[48;2;63;103;101m⠈[0m[48;2;63;103;101m⣠[0m[48;2;57;99;97m⣢[0m[48;2;133;159;152m⡻[0m[48;2;195;208;197m⣆[0m[48;2;63;103;101m⠠[0m[48;2;63;103;101m⠁[0m[48;2;64;104;102m⠂[0m[48;2;74;112;109m⡈[0m[48;2;222;229;217m⢉[0m[48;2;223;230;217m⠈[0m[48;2;192;205;195m⢄[0m[48;2;69;108;105m⡰[0m[48;2;66;105;103m⣼[0m[48;2;122;149;144m⡐[0m[48;2;65;105;103m⠠[0m[48;2;63;103;101m⠐[0m[48;2;63;103;101m⢀[0m[48;2;123;151;145m⠡[0m[48;2;140;164;157m⠐[0m[48;2;56;98;96m⣰[0m[48;2;62;102;100m⡀[0m[48;2;63;103;101m⠐[0m[48;2;63;103;101m⡀[0m[48;2;59;100;99m⠄[0m[48;2;138;163;156m⢈[0m[48;2;143;167;159m⣜[0m[48;2;217;225;213m⣗[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⡺[0m[48;2;218;226;214m⡽[0m[48;2;218;226;214m⣕[0m[48;2;218;226;214m⢷[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢝[0m[48;2;218;226;214m⡽[0m
[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⡺[0m[48;2;89;124;120m⣔[0m[48;2;59;100;98m⢦[0m[48;2;57;98;97m⢖[0m[48;2;46;89;89m⡼[0m[48;2;229;235;222m⣝[0m[48;2;218;226;214m⢞[0m[48;2;224;230;218m⣞[0m[48;2;59;100;98m⡤[0m[48;2;62;102;100m⡥[0m[48;2;61;101;100m⡤[0m[48;2;49;92;91m⡦[0m[48;2;220;228;216m⣻[0m[48;2;216;224;213m⡪[0m[48;2;207;218;206m⣗[0m[48;2;66;106;104m⢦[0m[48;2;52;94;93m⢦[0m[48;2;52;94;93m⢦[0m[48;2;57;98;97m⣲[0m[48;2;125;152;146m⢳[0m[48;2;228;234;222m⡳[0m[48;2;217;225;213m⡵[0m[48;2;218;226;214m⣝[0m[48;2;218;226;214m⢮[0m[48;2;227;233;220m⡳[0m[48;2;96;129;125m⡧[0m[48;2;53;95;94m⡦[0m[48;2;52;94;93m⡦[0m[48;2;53;95;94m⣲[0m[48;2;82;118;115m⡺[0m[48;2;198;210;199m⣪[0m[48;2;219;227;215m⢞[0m[48;2;218;226;214m⣞[0m[48;2;219;227;215m⢞[0m[48;2;127;154;148m⢶[0m[48;2;52;94;93m⢴[0m[48;2;52;94;93m⢔[0m[48;2;65;105;103m⣖[0m[48;2;179;196;186m⢯[0m[48;2;218;226;214m⣳[0m[48;2;226;232;220m⡳[0m[48;2;82;119;115m⡵[0m[48;2;52;94;93m⡴[0m[48;2;53;95;93m⣔[0m[48;2;145;168;161m⣗[0m[48;2;218;226;214m⢵[0m[48;2;218;226;214m⡳[0m[48;2;218;226;214m⣝[0m[48;2;218;226;214m⢮[0m[48;2;218;226;214m⣻[0m[48;2;218;226;214m⡪[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣳[0m[48;2;218;226;214m⢝[0m[48;2;218;226;214m⣞[0m
[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⡮[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢽[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⡯[0m[48;2;218;226;214m⣺[0m[48;2;218;226;214m⢕[0m[48;2;218;226;214m⣗[0m[48;2;218;226;214m⢽[0m[48;2;217;225;213m⢝[0m[48;2;217;225;213m⣝[0m[48;2;218;226;214m⢮[0m[48;2;218;226;214m⡳[0m[48;2;218;226;214m⣝[0m[48;2;218;226;214m⢮[0m[48;2;218;226;214m⢯[0m[48;2;218;226;214m⡳[0m[48;2;218;226;214m⣳[0m[48;2;218;226;214m⡳[0m[48;2;218;226;214m⣝[0m[48;2;218;226;214m⢮[0m[48;2;218;226;214m⢯[0m[48;2;218;226;214m⡺[0m[48;2;218;226;214m⡵[0m[48;2;218;226;214m⣫[0m[48;2;218;226;214m⡳[0m[48;2;218;226;214m⣝[0m[48;2;218;226;214m⢮[0m[48;2;218;226;214m⡳[0m[48;2;218;226;214m⣝[0m[48;2;218;226;214m⢮[0m[48;2;218;226;214m⣳[0m[48;2;218;226;214m⡳[0m[48;2;218;226;214m⡽[0m[48;2;218;226;214m⣝[0m[48;2;218;226;214m⢵[0m[48;2;218;226;214m⣫[0m[48;2;218;226;214m⢮[0m[48;2;218;226;214m⣳[0m[48;2;218;226;214m⡣[0m[48;2;218;226;214m⣯[0m[48;2;218;226;214m⡺[0m[48;2;218;226;214m⣕[0m[48;2;218;226;214m⣗[0m[48;2;218;226;214m⢵[0m[48;2;218;226;214m⡫[0m[48;2;218;226;214m⣞[0m[48;2;218;226;214m⢵[0m[48;2;218;226;214m⡫[0m[48;2;218;226;214m⣞[0m[48;2;218;226;214m⢮[0m[48;2;218;226;214m⣻[0m[48;2;218;226;214m⡪[0m[48;2;218;226;214m⣗[0m[48;2;218;226;214m⣗[0m
`

	cmd := &cobra.Command{
		Use: "version",
		Example: `
ksctl version --help
		`,
		Short: "ksctl version",
		Long:  "To get version for ksctl components",
		Run: func(cmd *cobra.Command, args []string) {

			fmt.Println(logoKsctl)

			k.l.Note(k.Ctx, "Components", color.HiGreenString("ksctl:cli"), color.HiBlueString(config.Version), color.HiGreenString("ksctl:core"), color.HiBlueString(config.KsctlCoreVer))
			k.l.Note(k.Ctx, "Build Information", "date", config.BuildDate)
		},
	}

	return cmd
}
0707010000001B000041ED0000000000000000000000026818E78D00000000000000000000000000000000000000000000001000000000ksctl-2.8.0/gen0707010000001C000081A40000000000000000000000016818E78D000005E8000000000000000000000000000000000000001800000000ksctl-2.8.0/gen/docs.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"log"
	"os"
	"path/filepath"

	"github.com/ksctl/cli/v2/cmd"
	"github.com/spf13/cobra/doc"
)

func filePrepender(filename string) string {
	cmdName := filepath.Base(filename)
	cmdName = cmdName[:len(cmdName)-3] // Remove .md extension

	return fmt.Sprintf(`---
title: %s
description: Command documentation for %s
---

`, cmdName, cmdName)
}

func linkHandler(name string) string {
	return name
}

func main() {
	outputDir := filepath.Join("gen", "docs")
	if err := os.MkdirAll(outputDir, 0755); err != nil {
		log.Fatal(err)
	}

	c, err := cmd.New()
	if err != nil {
		c.CliLog.Error("cli initialization failed", "Reason", err)
		os.Exit(1)
	}
	cc, err := c.ForDocs()
	if err != nil {
		c.CliLog.Error("failed to get the cobra root command", "Reason", err)
		os.Exit(1)
	}

	if err := doc.GenMarkdownTreeCustom(cc, outputDir, filePrepender, linkHandler); err != nil {
		log.Fatal(err)
	}
}
0707010000001D000081A40000000000000000000000016818E78D00002C72000000000000000000000000000000000000001300000000ksctl-2.8.0/go.modmodule github.com/ksctl/cli/v2

go 1.24.1

require (
	github.com/charmbracelet/bubbles v0.21.0
	github.com/charmbracelet/bubbletea v1.3.4
	github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834
	github.com/creack/pty v1.1.24
	github.com/fatih/color v1.18.0
	github.com/ksctl/ksctl/v2 v2.6.0
	github.com/pterm/pterm v0.12.80
	github.com/rodaine/table v1.3.0
	github.com/spf13/cobra v1.9.1
	golang.org/x/mod v0.22.0
	golang.org/x/term v0.31.0
	gopkg.in/yaml.v3 v3.0.1
	k8s.io/client-go v0.32.2
)

require (
	al.essio.dev/pkg/shellescape v1.5.1 // indirect
	atomicgo.dev/cursor v0.2.0 // indirect
	atomicgo.dev/keyboard v0.2.9 // indirect
	atomicgo.dev/schedule v0.1.0 // indirect
	dario.cat/mergo v1.0.1 // indirect
	github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
	github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 // indirect
	github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 // indirect
	github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6 v6.3.0 // indirect
	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v6 v6.3.0 // indirect
	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.1.0 // indirect
	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 // indirect
	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armsubscriptions v1.3.0 // indirect
	github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
	github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2 // indirect
	github.com/BurntSushi/toml v1.4.0 // indirect
	github.com/MakeNowJust/heredoc v1.0.0 // indirect
	github.com/Masterminds/goutils v1.1.1 // indirect
	github.com/Masterminds/semver/v3 v3.3.0 // indirect
	github.com/Masterminds/sprig/v3 v3.3.0 // indirect
	github.com/Masterminds/squirrel v1.5.4 // indirect
	github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
	github.com/aws/aws-sdk-go-v2 v1.36.2 // indirect
	github.com/aws/aws-sdk-go-v2/config v1.28.7 // indirect
	github.com/aws/aws-sdk-go-v2/credentials v1.17.48 // indirect
	github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22 // indirect
	github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33 // indirect
	github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33 // indirect
	github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
	github.com/aws/aws-sdk-go-v2/service/ec2 v1.198.1 // indirect
	github.com/aws/aws-sdk-go-v2/service/eks v1.56.0 // indirect
	github.com/aws/aws-sdk-go-v2/service/iam v1.39.2 // indirect
	github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect
	github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7 // indirect
	github.com/aws/aws-sdk-go-v2/service/pricing v1.32.8 // indirect
	github.com/aws/aws-sdk-go-v2/service/sso v1.24.8 // indirect
	github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.7 // indirect
	github.com/aws/aws-sdk-go-v2/service/sts v1.33.3 // indirect
	github.com/aws/smithy-go v1.22.2 // indirect
	github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
	github.com/beorn7/perks v1.0.1 // indirect
	github.com/blang/semver/v4 v4.0.0 // indirect
	github.com/cespare/xxhash/v2 v2.3.0 // indirect
	github.com/chai2010/gettext-go v1.0.2 // indirect
	github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
	github.com/charmbracelet/x/ansi v0.8.0 // indirect
	github.com/charmbracelet/x/cellbuf v0.0.13 // indirect
	github.com/charmbracelet/x/term v0.2.1 // indirect
	github.com/containerd/console v1.0.3 // indirect
	github.com/containerd/containerd v1.7.23 // indirect
	github.com/containerd/errdefs v0.3.0 // indirect
	github.com/containerd/log v0.1.0 // indirect
	github.com/containerd/platforms v0.2.1 // indirect
	github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
	github.com/cyphar/filepath-securejoin v0.3.4 // indirect
	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
	github.com/distribution/reference v0.6.0 // indirect
	github.com/docker/cli v26.1.1+incompatible // indirect
	github.com/docker/distribution v2.8.3+incompatible // indirect
	github.com/docker/docker v28.0.0+incompatible // indirect
	github.com/docker/docker-credential-helpers v0.7.0 // indirect
	github.com/docker/go-connections v0.5.0 // indirect
	github.com/docker/go-metrics v0.0.1 // indirect
	github.com/emicklei/go-restful/v3 v3.11.0 // indirect
	github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
	github.com/evanphx/json-patch v5.9.0+incompatible // indirect
	github.com/evanphx/json-patch/v5 v5.9.0 // indirect
	github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
	github.com/felixge/httpsnoop v1.0.4 // indirect
	github.com/fxamacker/cbor/v2 v2.7.0 // indirect
	github.com/go-errors/errors v1.4.2 // indirect
	github.com/go-gorp/gorp/v3 v3.1.0 // indirect
	github.com/go-logr/logr v1.4.2 // indirect
	github.com/go-logr/stdr v1.2.2 // indirect
	github.com/go-openapi/jsonpointer v0.21.0 // indirect
	github.com/go-openapi/jsonreference v0.20.4 // indirect
	github.com/go-openapi/swag v0.23.0 // indirect
	github.com/gobwas/glob v0.2.3 // indirect
	github.com/gogo/protobuf v1.3.2 // indirect
	github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
	github.com/golang/protobuf v1.5.4 // indirect
	github.com/golang/snappy v0.0.4 // indirect
	github.com/google/btree v1.0.1 // indirect
	github.com/google/gnostic-models v0.6.8 // indirect
	github.com/google/go-cmp v0.6.0 // indirect
	github.com/google/gofuzz v1.2.0 // indirect
	github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 // indirect
	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
	github.com/google/uuid v1.6.0 // indirect
	github.com/gookit/color v1.5.4 // indirect
	github.com/gorilla/mux v1.8.0 // indirect
	github.com/gorilla/websocket v1.5.0 // indirect
	github.com/gosuri/uitable v0.0.4 // indirect
	github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
	github.com/hashicorp/errwrap v1.1.0 // indirect
	github.com/hashicorp/go-multierror v1.1.1 // indirect
	github.com/huandu/xstrings v1.5.0 // indirect
	github.com/inconshreveable/mousetrap v1.1.0 // indirect
	github.com/jmespath/go-jmespath v0.4.0 // indirect
	github.com/jmoiron/sqlx v1.4.0 // indirect
	github.com/josharian/intern v1.0.0 // indirect
	github.com/json-iterator/go v1.1.12 // indirect
	github.com/klauspost/compress v1.16.7 // indirect
	github.com/kylelemons/godebug v1.1.0 // indirect
	github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
	github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
	github.com/lib/pq v1.10.9 // indirect
	github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
	github.com/lithammer/fuzzysearch v1.1.8 // indirect
	github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
	github.com/mailru/easyjson v0.7.7 // indirect
	github.com/mattn/go-colorable v0.1.13 // indirect
	github.com/mattn/go-isatty v0.0.20 // indirect
	github.com/mattn/go-localereader v0.0.1 // indirect
	github.com/mattn/go-runewidth v0.0.16 // indirect
	github.com/mitchellh/copystructure v1.2.0 // indirect
	github.com/mitchellh/go-wordwrap v1.0.1 // indirect
	github.com/mitchellh/reflectwalk v1.0.2 // indirect
	github.com/moby/locker v1.0.1 // indirect
	github.com/moby/spdystream v0.5.0 // indirect
	github.com/moby/term v0.5.0 // indirect
	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
	github.com/modern-go/reflect2 v1.0.2 // indirect
	github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
	github.com/montanaflynn/stats v0.7.1 // indirect
	github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
	github.com/muesli/cancelreader v0.2.2 // indirect
	github.com/muesli/termenv v0.16.0 // indirect
	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
	github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
	github.com/opencontainers/go-digest v1.0.0 // indirect
	github.com/opencontainers/image-spec v1.1.0 // indirect
	github.com/pelletier/go-toml v1.9.5 // indirect
	github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
	github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
	github.com/pkg/errors v0.9.1 // indirect
	github.com/prometheus/client_golang v1.19.1 // indirect
	github.com/prometheus/client_model v0.6.1 // indirect
	github.com/prometheus/common v0.55.0 // indirect
	github.com/prometheus/procfs v0.15.1 // indirect
	github.com/rivo/uniseg v0.4.7 // indirect
	github.com/rubenv/sql-migrate v1.7.0 // indirect
	github.com/russross/blackfriday/v2 v2.1.0 // indirect
	github.com/shopspring/decimal v1.4.0 // indirect
	github.com/sirupsen/logrus v1.9.3 // indirect
	github.com/spf13/cast v1.7.0 // indirect
	github.com/spf13/pflag v1.0.6 // indirect
	github.com/x448/float16 v0.8.4 // indirect
	github.com/xdg-go/pbkdf2 v1.0.0 // indirect
	github.com/xdg-go/scram v1.1.2 // indirect
	github.com/xdg-go/stringprep v1.0.4 // indirect
	github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
	github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
	github.com/xeipuuv/gojsonschema v1.2.0 // indirect
	github.com/xlab/treeprint v1.2.0 // indirect
	github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
	github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
	go.mongodb.org/mongo-driver v1.17.1 // indirect
	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
	go.opentelemetry.io/otel v1.28.0 // indirect
	go.opentelemetry.io/otel/metric v1.28.0 // indirect
	go.opentelemetry.io/otel/trace v1.28.0 // indirect
	go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
	golang.org/x/crypto v0.32.0 // indirect
	golang.org/x/net v0.34.0 // indirect
	golang.org/x/oauth2 v0.23.0 // indirect
	golang.org/x/sync v0.13.0 // indirect
	golang.org/x/sys v0.32.0 // indirect
	golang.org/x/text v0.24.0 // indirect
	golang.org/x/time v0.7.0 // indirect
	google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 // indirect
	google.golang.org/grpc v1.65.0 // indirect
	google.golang.org/protobuf v1.36.5 // indirect
	gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
	gopkg.in/inf.v0 v0.9.1 // indirect
	gopkg.in/yaml.v2 v2.4.0 // indirect
	gotest.tools/v3 v3.5.1 // indirect
	helm.sh/helm/v3 v3.16.4 // indirect
	k8s.io/api v0.32.2 // indirect
	k8s.io/apiextensions-apiserver v0.32.2 // indirect
	k8s.io/apimachinery v0.32.2 // indirect
	k8s.io/apiserver v0.32.2 // indirect
	k8s.io/cli-runtime v0.31.3 // indirect
	k8s.io/component-base v0.32.2 // indirect
	k8s.io/klog/v2 v2.130.1 // indirect
	k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect
	k8s.io/kubectl v0.31.3 // indirect
	k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
	oras.land/oras-go v1.2.5 // indirect
	sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
	sigs.k8s.io/kind v0.27.0 // indirect
	sigs.k8s.io/kustomize/api v0.17.2 // indirect
	sigs.k8s.io/kustomize/kyaml v0.17.1 // indirect
	sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
	sigs.k8s.io/yaml v1.4.0 // indirect
)
0707010000001E000081A40000000000000000000000016818E78D00012134000000000000000000000000000000000000001300000000ksctl-2.8.0/go.sumal.essio.dev/pkg/shellescape v1.5.1 h1:86HrALUujYS/h+GtqoB26SBEdkWfmMI6FubjXlsXyho=
al.essio.dev/pkg/shellescape v1.5.1/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890=
atomicgo.dev/assert v0.0.2 h1:FiKeMiZSgRrZsPo9qn/7vmr7mCsh5SZyXY4YGYiYwrg=
atomicgo.dev/assert v0.0.2/go.mod h1:ut4NcI3QDdJtlmAxQULOmA13Gz6e2DWbSAS8RUOmNYQ=
atomicgo.dev/cursor v0.2.0 h1:H6XN5alUJ52FZZUkI7AlJbUc1aW38GWZalpYRPpoPOw=
atomicgo.dev/cursor v0.2.0/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU=
atomicgo.dev/keyboard v0.2.9 h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8=
atomicgo.dev/keyboard v0.2.9/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ=
atomicgo.dev/schedule v0.1.0 h1:nTthAbhZS5YZmgYbb2+DH8uQIZcTlIrd4eYr3UQxEjs=
atomicgo.dev/schedule v0.1.0/go.mod h1:xeUa3oAkiuHYh8bKiQBRojqAMq3PXXbJujjb0hw8pEU=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 h1:B/dfvscEQtew9dVuoxqxrUKKv8Ih2f55PydknDamU+g=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0/go.mod h1:fiPSssYvltE08HJchL04dOy+RD4hgrjph0cwGGMntdI=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0 h1:+m0M/LFxN43KvULkDNfdXOgrjtg6UYJPFBJyuEcRCAw=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0/go.mod h1:PwOyop78lveYMRs6oCxjiVyBdyCgIYH6XHIVZO9/SFQ=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6 v6.3.0 h1:Dc9miZr1Mhaqbb3cmJCRokkG16uk8JKkqOADf084zy4=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6 v6.3.0/go.mod h1:CHo9QYhWEvrKVeXsEMJSl2bpmYYNu6aG12JsSaFBXlY=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v5 v5.0.0 h1:5n7dPVqsWfVKw+ZiEKSd3Kzu7gwBkbEBkeXb8rgaE9Q=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v5 v5.0.0/go.mod h1:HcZY0PHPo/7d75p99lB6lK0qYOP4vLRJUBpiehYXtLQ=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v6 v6.3.0 h1:4ZTvMq5AWtRIPM06RzdfKwKyVJ0eUOfm4QUBVDQFqQ4=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v6 v6.3.0/go.mod h1:drbnYtukMoZqUQq9hJASf41w3RB4VoTJPoPpe+XDHPU=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.0.0 h1:lMW1lD/17LUA5z1XTURo7LcVG2ICBPlyMHjIUrcFZNQ=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.0.0/go.mod h1:ceIuwmxDWptoW3eCqSXlnPsZFKh4X+R38dWPv7GS9Vs=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0 h1:PTFGRSlMKCQelWwxUyYVEUqseBJVemLyqWJjvMyt0do=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0/go.mod h1:LRr2FzBTQlONPPa5HREE5+RjSCTXl7BwOvYOaWTqCaI=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v3 v3.1.0 h1:2qsIIvxVT+uE6yrNldntJKlLRgxGbZ85kgtz5SNBhMw=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v3 v3.1.0/go.mod h1:AW8VEadnhw9xox+VaVd9sP7NjzOAnaZBLRH6Tq3cJ38=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/managementgroups/armmanagementgroups v1.0.0 h1:pPvTJ1dY0sA35JOeFq6TsY2xj6Z85Yo23Pj4wCCvu4o=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/managementgroups/armmanagementgroups v1.0.0/go.mod h1:mLfWfj8v3jfWKsL9G4eoBoXVcsqcIUTapmdKy7uGOp0=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.1.0 h1:QM6sE5k2ZT/vI5BEe0r7mqjsUSnhVBFbOsVkEuaEfiA=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.1.0/go.mod h1:243D9iHbcQXoFUtgHJwL7gl2zx1aDuDMjvBZVGr2uW0=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 h1:Dd+RhdJn0OTtVGaeDLZpcumkIVCtA/3/Fo42+eoYvVM=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0/go.mod h1:5kakwfW5CjC9KK+Q4wjXAg+ShuIm2mBMua0ZFj2C8PE=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armsubscriptions v1.3.0 h1:wxQx2Bt4xzPIKvW59WQf1tJNx/ZZKPfN+EhPX3Z6CYY=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armsubscriptions v1.3.0/go.mod h1:TpiwjwnW/khS0LKs4vW5UmmT9OWcxaveS8U7+tlknzo=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2 h1:kYRSnvJju5gYVyhkij+RTJ/VR6QIUaCfWeaFm2ycsjQ=
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs=
github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8=
github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII=
github.com/MarvinJWendt/testza v0.2.10/go.mod h1:pd+VWsoGUiFtq+hRKSU1Bktnn+DMCSrDrXDpX2bG66k=
github.com/MarvinJWendt/testza v0.2.12/go.mod h1:JOIegYyV7rX+7VZ9r77L/eH6CfJHHzXjB69adAhzZkI=
github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/2oUqKc6bF2c=
github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE=
github.com/MarvinJWendt/testza v0.5.2 h1:53KDo64C1z/h/d/stCYCPY69bt/OSwjq5KpFNwi+zB4=
github.com/MarvinJWendt/testza v0.5.2/go.mod h1:xu53QFE5sCdjtMCKk8YMQ2MnymimEctc4n3EjyIYvEY=
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.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0=
github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=
github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM=
github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/Microsoft/hcsshim v0.11.7 h1:vl/nj3Bar/CvJSYo7gIQPyRWc9f3c6IeSNavBTSZNZQ=
github.com/Microsoft/hcsshim v0.11.7/go.mod h1:MV8xMfmECjl5HdO7U/3/hFVnkmSBjAjmA09d4bExKcU=
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs=
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk=
github.com/aws/aws-sdk-go-v2 v1.36.2 h1:Ub6I4lq/71+tPb/atswvToaLGVMxKZvjYDVOWEExOcU=
github.com/aws/aws-sdk-go-v2 v1.36.2/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
github.com/aws/aws-sdk-go-v2/config v1.28.7 h1:GduUnoTXlhkgnxTD93g1nv4tVPILbdNQOzav+Wpg7AE=
github.com/aws/aws-sdk-go-v2/config v1.28.7/go.mod h1:vZGX6GVkIE8uECSUHB6MWAUsd4ZcG2Yq/dMa4refR3M=
github.com/aws/aws-sdk-go-v2/credentials v1.17.48 h1:IYdLD1qTJ0zanRavulofmqut4afs45mOWEI+MzZtTfQ=
github.com/aws/aws-sdk-go-v2/credentials v1.17.48/go.mod h1:tOscxHN3CGmuX9idQ3+qbkzrjVIx32lqDSU1/0d/qXs=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22 h1:kqOrpojG71DxJm/KDPO+Z/y1phm1JlC8/iT+5XRmAn8=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22/go.mod h1:NtSFajXVVL8TA2QNngagVZmUtXciyrHOt7xgz4faS/M=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33 h1:knLyPMw3r3JsU8MFHWctE4/e2qWbPaxDYLlohPvnY8c=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33/go.mod h1:EBp2HQ3f+XCB+5J+IoEbGhoV7CpJbnrsd4asNXmTL0A=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33 h1:K0+Ne08zqti8J9jwENxZ5NoUyBnaFDTu3apwQJWrwwA=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33/go.mod h1:K97stwwzaWzmqxO8yLGHhClbVW1tC6VT1pDLk1pGrq4=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.198.1 h1:YbNopxjd9baM83YEEmkaYHi+NuJt0AszeaSLqo0CVr0=
github.com/aws/aws-sdk-go-v2/service/ec2 v1.198.1/go.mod h1:mwr3iRm8u1+kkEx4ftDM2Q6Yr0XQFBKrP036ng+k5Lk=
github.com/aws/aws-sdk-go-v2/service/eks v1.56.0 h1:x31cGGE/t/QkrHVh5m2uWvYwDiaDXpj88nh6OdnI5r0=
github.com/aws/aws-sdk-go-v2/service/eks v1.56.0/go.mod h1:kNUWaiotRWCnfQlprrxSMg8ALqbZyA9xLCwKXuLumSk=
github.com/aws/aws-sdk-go-v2/service/iam v1.39.2 h1:2JLLGua711n8vn773xw2iwGh0zxLJJ3UDWQ2L7fy0wY=
github.com/aws/aws-sdk-go-v2/service/iam v1.39.2/go.mod h1:ZpAQJqd/i2bgRVa4vTa1ZX96sWgd3MZ/dxkABRXqvyI=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhvDxB6kPvEXgsDhGaZCSC6LQET5ZHSdJozeI0Y=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7 h1:8eUsivBQzZHqe/3FE+cqwfH+0p5Jo8PFM/QYQSmeZ+M=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7/go.mod h1:kLPQvGUmxn/fqiCrDeohwG33bq2pQpGeY62yRO6Nrh0=
github.com/aws/aws-sdk-go-v2/service/pricing v1.32.8 h1:R3X3UwwZKYLCNVVeJ+WLefvrjI5HonYCMlf40BYvJ8E=
github.com/aws/aws-sdk-go-v2/service/pricing v1.32.8/go.mod h1:4kkTK4zhY31emmt9VGgq3S+ElECNsiI5h6bqSBt71b0=
github.com/aws/aws-sdk-go-v2/service/sso v1.24.8 h1:CvuUmnXI7ebaUAhbJcDy9YQx8wHR69eZ9I7q5hszt/g=
github.com/aws/aws-sdk-go-v2/service/sso v1.24.8/go.mod h1:XDeGv1opzwm8ubxddF0cgqkZWsyOtw4lr6dxwmb6YQg=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.7 h1:F2rBfNAL5UyswqoeWv9zs74N/NanhK16ydHW1pahX6E=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.7/go.mod h1:JfyQ0g2JG8+Krq0EuZNnRwX0mU0HrwY/tG6JNfcqh4k=
github.com/aws/aws-sdk-go-v2/service/sts v1.33.3 h1:Xgv/hyNgvLda/M9l9qxXc4UFSgppnRczLxlMs5Ae/QY=
github.com/aws/aws-sdk-go-v2/service/sts v1.33.3/go.mod h1:5Gn+d+VaaRgsjewpMvGazt0WfcFO+Md4wLOuBfGR9Bc=
github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ=
github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70=
github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng=
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ=
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
github.com/charmbracelet/bubbletea v1.3.4 h1:kCg7B+jSCFPLYRA52SDZjr51kG/fMUEoPoZrkaDHyoI=
github.com/charmbracelet/bubbletea v1.3.4/go.mod h1:dtcUCyCGEX3g9tosuYiut3MXgY/Jsv9nKVdibKKRRXo=
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834 h1:ZR7e0ro+SZZiIZD7msJyA+NjkCNNavuiPBLgerbOziE=
github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834/go.mod h1:aKC/t2arECF6rNOnaKaVU6y4t4ZeHQzqfxedE/VkVhA=
github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k=
github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ=
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
github.com/containerd/containerd v1.7.23 h1:H2CClyUkmpKAGlhQp95g2WXHfLYc7whAuvZGBNYOOwQ=
github.com/containerd/containerd v1.7.23/go.mod h1:7QUzfURqZWCZV7RLNEn1XjUCQLEf0bkaK4GjUaZehxw=
github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM=
github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
github.com/containerd/errdefs v0.3.0 h1:FSZgGOeK4yuT/+DnF07/Olde/q4KBoMsaamhXxIMDp4=
github.com/containerd/errdefs v0.3.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
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/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
github.com/cyphar/filepath-securejoin v0.3.4 h1:VBWugsJh2ZxJmLFSM06/0qzQyiQX2Qs0ViKrUAcqdZ8=
github.com/cyphar/filepath-securejoin v0.3.4/go.mod h1:8s/MCNJREmFK0H02MF6Ihv1nakJe4L/w3WZLHNkvlYM=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc=
github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2/go.mod h1:WHNsWjnIn2V1LYOrME7e8KxSeKunYHsxEm4am0BUtcI=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/cli v26.1.1+incompatible h1:bE1/uE2tCa08fMv+7ikLR/RDPoCqytwrLtkIkSzxLvw=
github.com/docker/cli v26.1.1+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.0.0+incompatible h1:Olh0KS820sJ7nPsBKChVhk5pzqcwDR15fumfAd/p9hM=
github.com/docker/docker v28.0.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4=
github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls=
github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM=
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI=
github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs=
github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.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/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k=
github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+IrK7d0gGgpjGGvd2kz+FzTHVzdqI=
github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
github.com/gookit/goutil v0.6.18 h1:MUVj0G16flubWT8zYVicIuisUiHdgirPAkmnfD2kKgw=
github.com/gookit/goutil v0.6.18/go.mod h1:AY/5sAwKe7Xck+mEbuxj0n/bc3qwrGNe3Oeulln7zBA=
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY=
github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
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/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs=
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU=
github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/ksctl/ksctl/v2 v2.6.0 h1:Rt74UievbnEECZBzy92OsECqafgXihMyGIlKu2aozS4=
github.com/ksctl/ksctl/v2 v2.6.0/go.mod h1:0+AcbNu7OpWLX3a6GU9ZhkZSG8oJDfOrnoJ9KUXAUdE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78=
github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY=
github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI=
github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg=
github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE=
github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEejaWgXU=
github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE=
github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8=
github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s=
github.com/pterm/pterm v0.12.80 h1:mM55B+GnKUnLMUSqhdINe4s6tOuVQIetQ3my8JGyAIg=
github.com/pterm/pterm v0.12.80/go.mod h1:c6DeF9bSnOSeFPZlfs4ZRAFcf5SCoTwvwQ5xaKGQlHo=
github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4=
github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rodaine/table v1.3.0 h1:4/3S3SVkHnVZX91EHFvAMV7K42AnJ0XuymRR2C5HlGE=
github.com/rodaine/table v1.3.0/go.mod h1:47zRsHar4zw0jgxGxL9YtFfs7EGN6B/TaS+/Dmk4WxU=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/rubenv/sql-migrate v1.7.0 h1:HtQq1xyTN2ISmQDggnh0c9U3JlP8apWh8YO2jzlXpTI=
github.com/rubenv/sql-migrate v1.7.0/go.mod h1:S4wtDEG1CKn+0ShpTtzWhFpHHI5PvCUtiGI+C+Z2THE=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI=
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE=
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY=
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
go.mongodb.org/mongo-driver v1.17.1 h1:Wic5cJIwJgSpBhe3lx3+/RybR5PiYRMpVFgO7cOHyIM=
go.mongodb.org/mongo-driver v1.17.1/go.mod h1:wwWm/+BuOddhcq3n68LKRmgk2wXzmF6s0SFOa0GINL4=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY=
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-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.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/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.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
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.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 h1:2035KHhUv+EpyB+hWgJnaWKJOdX1E95w2S8Rr4uWKTs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
helm.sh/helm/v3 v3.16.4 h1:rBn/h9MACw+QlhxQTjpl8Ifx+VTWaYsw3rguGBYBzr0=
helm.sh/helm/v3 v3.16.4/go.mod h1:k8QPotUt57wWbi90w3LNmg3/MWcLPigVv+0/X4B8BzA=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.32.2 h1:bZrMLEkgizC24G9eViHGOPbW+aRo9duEISRIJKfdJuw=
k8s.io/api v0.32.2/go.mod h1:hKlhk4x1sJyYnHENsrdCWw31FEmCijNGPJO5WzHiJ6Y=
k8s.io/apiextensions-apiserver v0.32.2 h1:2YMk285jWMk2188V2AERy5yDwBYrjgWYggscghPCvV4=
k8s.io/apiextensions-apiserver v0.32.2/go.mod h1:GPwf8sph7YlJT3H6aKUWtd0E+oyShk/YHWQHf/OOgCA=
k8s.io/apimachinery v0.32.2 h1:yoQBR9ZGkA6Rgmhbp/yuT9/g+4lxtsGYwW6dR6BDPLQ=
k8s.io/apimachinery v0.32.2/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
k8s.io/apiserver v0.32.2 h1:WzyxAu4mvLkQxwD9hGa4ZfExo3yZZaYzoYvvVDlM6vw=
k8s.io/apiserver v0.32.2/go.mod h1:PEwREHiHNU2oFdte7BjzA1ZyjWjuckORLIK/wLV5goM=
k8s.io/cli-runtime v0.31.3 h1:fEQD9Xokir78y7pVK/fCJN090/iYNrLHpFbGU4ul9TI=
k8s.io/cli-runtime v0.31.3/go.mod h1:Q2jkyTpl+f6AtodQvgDI8io3jrfr+Z0LyQBPJJ2Btq8=
k8s.io/client-go v0.32.2 h1:4dYCD4Nz+9RApM2b/3BtVvBHw54QjMFUl1OLcJG5yOA=
k8s.io/client-go v0.32.2/go.mod h1:fpZ4oJXclZ3r2nDOv+Ux3XcJutfrwjKTCHz2H3sww94=
k8s.io/component-base v0.32.2 h1:1aUL5Vdmu7qNo4ZsE+569PV5zFatM9hl+lb3dEea2zU=
k8s.io/component-base v0.32.2/go.mod h1:PXJ61Vx9Lg+P5mS8TLd7bCIr+eMJRQTyXe8KvkrvJq0=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y=
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4=
k8s.io/kubectl v0.31.3 h1:3r111pCjPsvnR98oLLxDMwAeM6OPGmPty6gSKaLTQes=
k8s.io/kubectl v0.31.3/go.mod h1:lhMECDCbJN8He12qcKqs2QfmVo9Pue30geovBVpH5fs=
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
oras.land/oras-go v1.2.5 h1:XpYuAwAb0DfQsunIyMfeET92emK8km3W4yEzZvUbsTo=
oras.land/oras-go v1.2.5/go.mod h1:PuAwRShRZCsZb7g8Ar3jKKQR/2A/qN+pkYxIOd/FAoo=
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
sigs.k8s.io/kind v0.27.0 h1:PQ3f0iAWNIj66LYkZ1ivhEg/+Zb6UPMbO+qVei/INZA=
sigs.k8s.io/kind v0.27.0/go.mod h1:RZVFmy6qcwlSWwp6xeIUv7kXCPF3i8MXsEXxW/J+gJY=
sigs.k8s.io/kustomize/api v0.17.2 h1:E7/Fjk7V5fboiuijoZHgs4aHuexi5Y2loXlVOAVAG5g=
sigs.k8s.io/kustomize/api v0.17.2/go.mod h1:UWTz9Ct+MvoeQsHcJ5e+vziRRkwimm3HytpZgIYqye0=
sigs.k8s.io/kustomize/kyaml v0.17.1 h1:TnxYQxFXzbmNG6gOINgGWQt09GghzgTP6mIurOgrLCQ=
sigs.k8s.io/kustomize/kyaml v0.17.1/go.mod h1:9V0mCjIEYjlXuCdYsSXvyoy2BTsLESH7TlGV81S282U=
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA=
sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
0707010000001F000081A40000000000000000000000016818E78D00000345000000000000000000000000000000000000001200000000ksctl-2.8.0/kt.md## here is the kt for the profiling of the code cli

```go
package main

import (
	"fmt"
	"log"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"sync"

	"github.com/ksctl/cli/cli/cmd"
)

func main() {
	cc := make(chan os.Signal, 1)

	signal.Notify(cc, os.Interrupt)
	signal.Notify(cc, os.Kill)

	wg := new(sync.WaitGroup)

	go func() {
		wg.Add(1)
		fmt.Println(http.ListenAndServe("localhost:8080", nil))
	}()

	cmd.Execute()

	select {
	case sig := <-cc:
		log.Println("Received terminate, graceful shutdown", sig)
		os.Exit(1)
	}

	wg.Wait()
}

```

```shell
go run . create local -n demo --yes
```

```shell
go tool pprof \
  -raw -output=cpu.txt \
  'http://localhost:8080/debug/pprof/profile?seconds=120'
```

```shell
./stackcollapse-go.pl cpu.txt | flamegraph.pl > flame.svg
```

<https://github.com/brendangregg/FlameGraph>
07070100000020000081A40000000000000000000000016818E78D00000383000000000000000000000000000000000000001400000000ksctl-2.8.0/main.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"os"

	"github.com/ksctl/cli/v2/cmd"
)

func main() {
	c, err := cmd.New()
	if err != nil {
		c.CliLog.Error("cli initialization failed", "Reason", err)
		os.Exit(1)
	}

	err = c.Execute()
	if err != nil {
		c.CliLog.Error("command execution failed", "Reason", err)
		os.Exit(1)
	}
}
07070100000021000041ED0000000000000000000000026818E78D00000000000000000000000000000000000000000000001000000000ksctl-2.8.0/pkg07070100000022000041ED0000000000000000000000026818E78D00000000000000000000000000000000000000000000001400000000ksctl-2.8.0/pkg/cli07070100000023000081A40000000000000000000000016818E78D00001B44000000000000000000000000000000000000002400000000ksctl-2.8.0/pkg/cli/blueprint_ui.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cli

import (
	"encoding/json"
	"fmt"
	"io"
	"strings"

	"github.com/charmbracelet/lipgloss"
	"github.com/fatih/color"
	"github.com/ksctl/ksctl/v2/pkg/handler/cluster/controller"
)

// BlueprintUI is responsible for rendering the cluster blueprint with enhanced UI
type BlueprintUI struct {
	writer io.Writer
}

// NewBlueprintUI creates a new instance of BlueprintUI
func NewBlueprintUI(w io.Writer) *BlueprintUI {
	return &BlueprintUI{
		writer: w,
	}
}

// RenderClusterBlueprint renders the cluster metadata with enhanced UI
func (ui *BlueprintUI) RenderClusterBlueprint(meta controller.Metadata) {
	parentBox := lipgloss.NewStyle().
		BorderStyle(lipgloss.RoundedBorder()).
		BorderForeground(lipgloss.Color("8")).
		Padding(1, 2).
		Width(80).
		Align(lipgloss.Center)

	banner := lipgloss.NewStyle().
		Padding(0, 1).
		Width(70).
		Align(lipgloss.Center)

	sectionTitle := lipgloss.NewStyle().
		Foreground(lipgloss.Color("13")).
		Bold(true).
		MarginTop(1).
		Padding(0, 1)

	infoBlock := lipgloss.NewStyle().
		BorderStyle(lipgloss.RoundedBorder()).
		BorderForeground(lipgloss.Color("10")).
		Padding(1, 2).
		MarginTop(1).
		Width(70)

	keyValueRow := func(key, value string) string {
		return lipgloss.JoinHorizontal(lipgloss.Top,
			lipgloss.NewStyle().Foreground(lipgloss.Color("14")).PaddingRight(3).Width(22).Align(lipgloss.Left).Render(key),
			lipgloss.NewStyle().Width(40).Render(value),
		)
	}

	var parentBoxContent strings.Builder

	bannerContent := fmt.Sprintf("✨ %s ✨\n\n%s",
		lipgloss.NewStyle().Bold(true).Align(lipgloss.Center).Foreground(lipgloss.Color("#FFFFFF")).Render("Cluster Blueprint"),
		lipgloss.NewStyle().Italic(true).Align(lipgloss.Center).Foreground(lipgloss.Color("#DDDDDD")).Render("Your Kubernetes cluster plan"))

	parentBoxContent.WriteString(banner.Render(bannerContent))
	parentBoxContent.WriteString("\n\n")

	{
		var content strings.Builder
		content.WriteString(keyValueRow("Name", meta.ClusterName))
		content.WriteString("\n")
		content.WriteString(keyValueRow("Region", meta.Region))
		content.WriteString("\n")
		content.WriteString(keyValueRow("Cloud", string(meta.Provider)))
		content.WriteString("\n")
		content.WriteString(keyValueRow("Type", string(meta.ClusterType)))

		contentBlock := infoBlock.Render(content.String())
		titleBlock := sectionTitle.Render("🔑 Key Attributes")
		fullSection := lipgloss.JoinVertical(lipgloss.Left, titleBlock, contentBlock)

		parentBoxContent.WriteString(fullSection)
		parentBoxContent.WriteString("\n")
	}

	// Infrastructure section
	if meta.NoCP > 0 || meta.NoWP > 0 || meta.NoDS > 0 || len(meta.ManagedNodeType) > 0 {
		var content strings.Builder
		if meta.NoCP > 0 {
			content.WriteString(keyValueRow("Control Plane", fmt.Sprintf("%d × %s", meta.NoCP, color.HiMagentaString(meta.ControlPlaneNodeType))))
			content.WriteString("\n")
		}
		if meta.NoWP > 0 {
			content.WriteString(keyValueRow("Worker Nodes", fmt.Sprintf("%d × %s", meta.NoWP, color.HiMagentaString(meta.WorkerPlaneNodeType))))
			content.WriteString("\n")
		}
		if meta.NoDS > 0 {
			content.WriteString(keyValueRow("Etcd Nodes", fmt.Sprintf("%d × %s", meta.NoDS, color.HiMagentaString(meta.DataStoreNodeType))))
			content.WriteString("\n")
		}
		if meta.LoadBalancerNodeType != "" {
			content.WriteString(keyValueRow("Load Balancer", color.HiMagentaString(meta.LoadBalancerNodeType)))
			content.WriteString("\n")
		}
		if len(meta.ManagedNodeType) > 0 {
			content.WriteString(keyValueRow("Managed Nodes", fmt.Sprintf("%d × %s", meta.NoMP, color.HiMagentaString(meta.ManagedNodeType))))
		}

		// Trim trailing newline if present
		contentStr := strings.TrimSuffix(content.String(), "\n")
		contentBlock := infoBlock.Render(contentStr)
		titleBlock := sectionTitle.Render("💻 Infrastructure")
		fullSection := lipgloss.JoinVertical(lipgloss.Left, titleBlock, contentBlock)

		parentBoxContent.WriteString(fullSection)
		parentBoxContent.WriteString("\n")
	}

	// Kubernetes configuration section
	if meta.K8sDistro != "" || meta.EtcdVersion != "" || meta.K8sVersion != "" {
		var content strings.Builder
		if meta.K8sDistro != "" {
			content.WriteString(keyValueRow("Bootstrap Provider", string(meta.K8sDistro)))
			content.WriteString("\n")
		}
		if meta.K8sVersion != "" {
			content.WriteString(keyValueRow("Kubernetes Version", meta.K8sVersion))
			content.WriteString("\n")
		}
		if meta.EtcdVersion != "" {
			content.WriteString(keyValueRow("Etcd Version", meta.EtcdVersion))
		}

		contentStr := strings.TrimSuffix(content.String(), "\n")
		contentBlock := infoBlock.Render(contentStr)
		titleBlock := sectionTitle.Render("🔧 Kubernetes Configuration")
		fullSection := lipgloss.JoinVertical(lipgloss.Left, titleBlock, contentBlock)

		parentBoxContent.WriteString(fullSection)
		parentBoxContent.WriteString("\n")
	}

	if len(meta.Addons) > 0 {
		var contentBuilder strings.Builder

		for i, addon := range meta.Addons {
			addonTitle := color.HiMagentaString(addon.Name)

			config := addon.Config
			vConfig := ""
			if config == nil {
				vConfig = "No configuration available"
			} else {
				var v any
				if err := json.Unmarshal([]byte(*config), &v); err != nil {
					vConfig = "Invalid configuration format"
				} else {
					_v, _ := json.MarshalIndent(v, "\t", "  ")
					vConfig = string(_v)
				}
			}
			addonInfo := fmt.Sprintf("%s\n\t%s: %s\n\t%s: %s",
				addonTitle,
				color.HiCyanString("From"),
				color.HiGreenString(addon.Label),
				color.HiCyanString("Config"),
				color.HiGreenString(vConfig),
			)
			if addon.IsCNI {
				addonInfo += "\n\t" + color.HiCyanString("CNI Add-on")
			}

			contentBuilder.WriteString(addonInfo)
			if i < len(meta.Addons)-1 {
				contentBuilder.WriteString("\n\n") // Add spacing between addons
			}
		}

		contentBlock := infoBlock.Render(contentBuilder.String())
		titleBlock := sectionTitle.Render("🧩 Add-ons")
		fullSection := lipgloss.JoinVertical(lipgloss.Left, titleBlock, contentBlock)

		parentBoxContent.WriteString(fullSection)
	}

	noteStyle := lipgloss.NewStyle().
		Italic(true).
		Foreground(lipgloss.Color("#919191")).
		Padding(1, 0).
		MarginTop(1).
		Align(lipgloss.Center)

	parentBoxContent.WriteString("\n\n")
	parentBoxContent.WriteString(noteStyle.Render("Your cluster will be provisioned with these specifications"))

	fmt.Fprintln(ui.writer, parentBox.Render(parentBoxContent.String()))
}
07070100000024000081A40000000000000000000000016818E78D00001C11000000000000000000000000000000000000002800000000ksctl-2.8.0/pkg/cli/card_recommend_1.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cli

import (
	"fmt"
	"github.com/fatih/color"
	"github.com/ksctl/ksctl/v2/pkg/consts"
	"github.com/ksctl/ksctl/v2/pkg/provider/optimizer"
	"strings"
)

type cardRecommendation struct {
	rr          optimizer.RegionRecommendation
	oo          *optimizer.RecommendationAcrossRegions
	clusterType consts.KsctlClusterType
}

const (
	RenewableLowThreshold             = 10.0
	RenewableMediumThreshold          = 40.0
	LowCarbonLowThreshold             = 10.0
	LowCarbonMediumThreshold          = 40.0
	DirectCo2LowThreshold             = 200.0
	DirectCo2MediumThreshold          = 400.0
	LCACarbonIntensityMediumThreshold = 100.0
	LCACarbonIntensityHighThreshold   = 200.0
)

func (c cardRecommendation) GetUpper() string {
	priceStr := strings.Builder{}
	priceDrop := (c.oo.CurrentTotalCost - c.rr.TotalCost) / c.oo.CurrentTotalCost * 100
	priceStr.WriteString(fmt.Sprintf(
		"Price: %s %s\n",
		color.MagentaString(fmt.Sprintf("$%.2f", c.rr.TotalCost)),
		color.HiGreenString(fmt.Sprintf("↓ %.0f%%", priceDrop)),
	))

	if c.rr.Region.Emission != nil {
		dco2Val := fmt.Sprintf("%.2f %s", c.rr.Region.Emission.DirectCarbonIntensity, c.rr.Region.Emission.Unit)
		if c.rr.Region.Emission.DirectCarbonIntensity > DirectCo2MediumThreshold {
			dco2Val = color.HiRedString(dco2Val)
		} else if c.rr.Region.Emission.DirectCarbonIntensity > DirectCo2LowThreshold {
			dco2Val = color.HiYellowString(dco2Val)
		} else {
			dco2Val = color.HiGreenString(dco2Val)
		}

		renewableVal := fmt.Sprintf("%.1f%%", c.rr.Region.Emission.RenewablePercentage)
		if c.rr.Region.Emission.RenewablePercentage < RenewableLowThreshold {
			renewableVal = color.HiRedString(renewableVal)
		} else if c.rr.Region.Emission.RenewablePercentage < RenewableMediumThreshold {
			renewableVal = color.HiYellowString(renewableVal)
		} else {
			renewableVal = color.HiGreenString(renewableVal)
		}

		lowco2Val := fmt.Sprintf("%.1f%%", c.rr.Region.Emission.LowCarbonPercentage)
		if c.rr.Region.Emission.LowCarbonPercentage < LowCarbonLowThreshold {
			lowco2Val = color.HiRedString(lowco2Val)
		} else if c.rr.Region.Emission.LowCarbonPercentage < LowCarbonMediumThreshold {
			lowco2Val = color.HiYellowString(lowco2Val)
		} else {
			lowco2Val = color.HiGreenString(lowco2Val)
		}

		lcaintensityVal := fmt.Sprintf("%.1f %s", c.rr.Region.Emission.LCACarbonIntensity, c.rr.Region.Emission.Unit)
		if c.rr.Region.Emission.LCACarbonIntensity > LCACarbonIntensityHighThreshold {
			lcaintensityVal = color.HiRedString(lcaintensityVal)
		} else if c.rr.Region.Emission.LCACarbonIntensity > LCACarbonIntensityMediumThreshold {
			lcaintensityVal = color.HiYellowString(lcaintensityVal)
		} else {
			lcaintensityVal = color.HiGreenString(lcaintensityVal)
		}

		e_r := c.rr.Region.Emission
		e_R := c.oo.CurrentRegion.Emission

		if e_R != nil {
			dco2Change := (e_r.DirectCarbonIntensity - e_R.DirectCarbonIntensity) / e_R.DirectCarbonIntensity * 100
			if dco2Change > 0 {
				dco2Val += color.HiRedString(fmt.Sprintf(" ↑ %.0f%%", dco2Change))
			} else {
				dco2Val += color.HiGreenString(fmt.Sprintf(" ↓ %.0f%%", -dco2Change))
			}

			renewableChange := (e_r.RenewablePercentage - e_R.RenewablePercentage) / e_R.RenewablePercentage * 100
			if renewableChange > 0 {
				renewableVal += color.HiGreenString(fmt.Sprintf(" ↑ %.0f%%", renewableChange))
			} else {
				renewableVal += color.HiRedString(fmt.Sprintf(" ↓ %.0f%%", -renewableChange))
			}

			lowco2Change := (e_r.LowCarbonPercentage - e_R.LowCarbonPercentage) / e_R.LowCarbonPercentage * 100
			if lowco2Change > 0 {
				lowco2Val += color.HiGreenString(fmt.Sprintf(" ↑ %.0f%%", lowco2Change))
			} else {
				lowco2Val += color.HiRedString(fmt.Sprintf(" ↓ %.0f%%", -lowco2Change))
			}

			lcaintensityChange := (e_r.LCACarbonIntensity - e_R.LCACarbonIntensity) / e_R.LCACarbonIntensity * 100
			if lcaintensityChange > 0 {
				lcaintensityVal += color.HiRedString(fmt.Sprintf(" ↑ %.0f%%", lcaintensityChange))
			} else {
				lcaintensityVal += color.HiGreenString(fmt.Sprintf(" ↓ %.0f%%", -lcaintensityChange))
			}
		}

		priceStr.WriteString(fmt.Sprintf("🌍 Direct Co2: %s\n", dco2Val))
		priceStr.WriteString(fmt.Sprintf("🌱 Renewable: %s\n", renewableVal))
		priceStr.WriteString(fmt.Sprintf("💨 Low Carbon: %s\n", lowco2Val))
		priceStr.WriteString(fmt.Sprintf("🔄 Lifecycle Co2: %s\n", lcaintensityVal))
	} else {
		priceStr.WriteString(color.HiYellowString("Emissions data is currently unavailable 🌍\n"))
	}

	return priceStr.String()
}

func (c cardRecommendation) GetLower() string {
	specsStr := strings.Builder{}
	specsStr.WriteString(fmt.Sprintf("Region: %s\n", color.HiCyanString(c.rr.Region.Name)))
	if c.clusterType == consts.ClusterTypeSelfMang {
		specsStr.WriteString(fmt.Sprintf("ControlPlane: %s x %d\n", c.oo.InstanceTypeCP, c.oo.ControlPlaneCount))
		specsStr.WriteString(fmt.Sprintf("Worker: %s x %d\n", c.oo.InstanceTypeWP, c.oo.WorkerPlaneCount))
		specsStr.WriteString(fmt.Sprintf("Etcd: %s x %d\n", c.oo.InstanceTypeDS, c.oo.DataStoreCount))
		specsStr.WriteString(fmt.Sprintf("LoadBalancer: %s\n", c.oo.InstanceTypeLB))
	} else {
		specsStr.WriteString(fmt.Sprintf("ManagedOffering: %s\n", c.oo.ManagedOffering))
		specsStr.WriteString(fmt.Sprintf("Worker: %s x %d\n", c.oo.InstanceTypeWP, c.oo.WorkerPlaneCount))
	}

	return specsStr.String()
}

type cardRecommendations struct {
	mm         consts.KsctlClusterType
	oo         *optimizer.RecommendationAcrossRegions
	tt         []cardRecommendation
	lenOfItems int
}

func (c cardRecommendations) LenOfItems() int {
	return c.lenOfItems
}

func (c cardRecommendations) GetItem(i int) CardItem {
	return c.tt[i]
}

func (c cardRecommendations) GetInstruction() string {
	instructions := "← → to navigate • enter to select plan • q to skip changing region"
	instructions += " • Currently it costs " + fmt.Sprintf("`$%.2f`", c.oo.CurrentTotalCost) + " in " + color.HiCyanString(c.oo.CurrentRegion.Name)

	return instructions
}

func (c cardRecommendations) GetResult(i int) string {
	return c.oo.RegionRecommendations[i].Region.Sku
}

func (c cardRecommendations) GetCardConfiguration() (cardWidth, noOfVisibleItems int) {
	return 45, 2
}

func ConverterForRecommendationIOutputForCards(oo *optimizer.RecommendationAcrossRegions, tt consts.KsctlClusterType) CardPack {
	res := new(cardRecommendations)
	res.oo = oo
	res.mm = tt
	res.lenOfItems = len(oo.RegionRecommendations)

	for i, _ := range oo.RegionRecommendations {
		res.tt = append(res.tt, cardRecommendation{
			oo.RegionRecommendations[i],
			oo,
			tt,
		})
	}

	return res
}
07070100000025000081A40000000000000000000000016818E78D00000EA6000000000000000000000000000000000000002300000000ksctl-2.8.0/pkg/cli/card_region.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cli

import (
	"fmt"
	"github.com/fatih/color"
	"github.com/ksctl/ksctl/v2/pkg/provider"
	"strings"
)

type cardRegion struct {
	b provider.RegionOutput
}

func (c cardRegion) GetUpper() string {
	priceStr := strings.Builder{}

	if c.b.Emission != nil {
		dco2Val := fmt.Sprintf("%.2f %s", c.b.Emission.DirectCarbonIntensity, c.b.Emission.Unit)
		if c.b.Emission.DirectCarbonIntensity > DirectCo2MediumThreshold {
			dco2Val = color.HiRedString(dco2Val)
		} else if c.b.Emission.DirectCarbonIntensity > DirectCo2LowThreshold {
			dco2Val = color.HiYellowString(dco2Val)
		} else {
			dco2Val = color.HiGreenString(dco2Val)
		}

		renewableVal := fmt.Sprintf("%.1f%%", c.b.Emission.RenewablePercentage)
		if c.b.Emission.RenewablePercentage < RenewableLowThreshold {
			renewableVal = color.HiRedString(renewableVal)
		} else if c.b.Emission.RenewablePercentage < RenewableMediumThreshold {
			renewableVal = color.HiYellowString(renewableVal)
		} else {
			renewableVal = color.HiGreenString(renewableVal)
		}

		lowco2Val := fmt.Sprintf("%.1f%%", c.b.Emission.LowCarbonPercentage)
		if c.b.Emission.LowCarbonPercentage < LowCarbonLowThreshold {
			lowco2Val = color.HiRedString(lowco2Val)
		} else if c.b.Emission.LowCarbonPercentage < LowCarbonMediumThreshold {
			lowco2Val = color.HiYellowString(lowco2Val)
		} else {
			lowco2Val = color.HiGreenString(lowco2Val)
		}

		lcaintensityVal := fmt.Sprintf("%.1f %s", c.b.Emission.LCACarbonIntensity, c.b.Emission.Unit)
		if c.b.Emission.LCACarbonIntensity > LCACarbonIntensityHighThreshold {
			lcaintensityVal = color.HiRedString(lcaintensityVal)
		} else if c.b.Emission.LCACarbonIntensity > LCACarbonIntensityMediumThreshold {
			lcaintensityVal = color.HiYellowString(lcaintensityVal)
		} else {
			lcaintensityVal = color.HiGreenString(lcaintensityVal)
		}
		priceStr.WriteString(fmt.Sprintf("🌍 Direct Co2: %s\n", dco2Val))
		priceStr.WriteString(fmt.Sprintf("🌱 Renewable: %s\n", renewableVal))
		priceStr.WriteString(fmt.Sprintf("💨 Low Carbon: %s\n", lowco2Val))
		priceStr.WriteString(fmt.Sprintf("🔄 Lifecycle Co2: %s\n", lcaintensityVal))
	} else {
		priceStr.WriteString(color.HiYellowString("Emissions data is currently unavailable 🌍\n"))
	}

	return priceStr.String()
}

func (c cardRegion) GetLower() string {
	return "Name: " + color.HiMagentaString(c.b.Name) + "\nCode: " + color.HiCyanString(c.b.Sku)
}

type cardRegions struct {
	rr       []provider.RegionOutput
	tt       []cardRegion
	lenItems int
}

func (c cardRegions) LenOfItems() int {
	return c.lenItems
}

func (c cardRegions) GetItem(i int) CardItem {
	return c.tt[i]
}

func (c cardRegions) GetInstruction() string {
	return "← → to navigate • enter to select region • q to quit"
}

func (c cardRegions) GetResult(i int) string {
	return c.rr[i].Sku
}

func (c cardRegions) GetCardConfiguration() (cardWidth, noOfVisibleItems int) {
	return 45, 2
}

func ConverterForRegionOutputForCards(regions provider.RegionsOutput) CardPack {
	res := new(cardRegions)
	res.lenItems = len(regions)
	res.rr = regions

	for i, _ := range regions {
		res.tt = append(res.tt, cardRegion{regions[i]})
	}

	return res
}
07070100000026000081A40000000000000000000000016818E78D00000B01000000000000000000000000000000000000001F00000000ksctl-2.8.0/pkg/cli/card_vm.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cli

import (
	"fmt"
	"github.com/fatih/color"
	"github.com/ksctl/ksctl/v2/pkg/provider"
	"strings"
)

type cardVM struct {
	rr provider.InstanceRegionOutput
}

func (c cardVM) GetUpper() string {
	resp := strings.Builder{}

	resp.WriteString(fmt.Sprintf(
		"Price: %s\n",
		color.HiMagentaString("%s %.2f", c.rr.Price.Currency, c.rr.GetCost()),
	))
	if c.rr.EmboddedEmissions != nil {
		resp.WriteString(fmt.Sprintf("🏭 Embodied: %.2f %s\n", c.rr.EmboddedEmissions.EmboddedCo2, c.rr.EmboddedEmissions.Co2Unit))
	} else {
		resp.WriteString(color.HiYellowString("Emissions data is currently unavailable 🌍\n"))
	}

	return resp.String()
}

func (c cardVM) GetLower() string {
	resp := strings.Builder{}

	resp.WriteString(fmt.Sprintf("Code: %s\n", color.HiMagentaString(c.rr.Sku)))
	resp.WriteString(fmt.Sprintf("vCPUs: %d\n", c.rr.VCpus))
	resp.WriteString(fmt.Sprintf("Memory: %d GB\n", c.rr.Memory))
	arch := string(c.rr.CpuArch)
	if arch == string(provider.ArchArm64) {
		arch = color.HiCyanString(arch)
	} else {
		arch = color.HiBlueString(arch)
	}
	resp.WriteString(fmt.Sprintf("Arch: %s\n", arch))

	diskSku := c.rr.Disk.Sku
	diskSize := c.rr.Disk.Size
	diskTier := c.rr.Disk.Tier

	if diskSku != nil {
		resp.WriteString(fmt.Sprintf("Disk: %s\n", *diskSku))
	}

	if diskTier != nil {
		resp.WriteString(fmt.Sprintf("DiskTier: %s\n", *diskTier))
	}

	if diskSize != nil {
		resp.WriteString(fmt.Sprintf("DiskSize: %d GB", *diskSize))
	}

	return resp.String()
}

type cardVMs struct {
	rr         provider.InstancesRegionOutput
	tt         []cardVM
	lenOfItems int
}

func (c cardVMs) LenOfItems() int {
	return c.lenOfItems
}

func (c cardVMs) GetItem(i int) CardItem {
	return c.tt[i]
}

func (c cardVMs) GetInstruction() string {
	return "← → to navigate • enter to select instanceType • q to quit"
}

func (c cardVMs) GetResult(i int) string {
	return c.rr[i].Sku
}

func (c cardVMs) GetCardConfiguration() (cardWidth, noOfVisibleItems int) {
	return 33, 3
}

func ConverterForInstanceTypesForCards(vms provider.InstancesRegionOutput) CardPack {
	res := new(cardVMs)
	res.lenOfItems = len(vms)
	res.rr = vms

	for i, _ := range vms {
		res.tt = append(res.tt, cardVM{vms[i]})
	}

	return res
}
07070100000027000081A40000000000000000000000016818E78D000018D2000000000000000000000000000000000000001D00000000ksctl-2.8.0/pkg/cli/cards.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cli

import (
	"fmt"
	"github.com/charmbracelet/bubbles/help"
	"github.com/charmbracelet/bubbles/key"
	tea "github.com/charmbracelet/bubbletea"
	"github.com/charmbracelet/lipgloss"
	"strings"
)

func (p *genericMenuDriven) CardSelection(pack CardPack) (string, error) {
	t := tea.NewProgram(newCardRunner(pack))
	finalModel, err := t.Run()
	if err != nil {
		return "", err
	}

	m, ok := finalModel.(cardRunner)
	if !ok {
		return "", fmt.Errorf("failed to cast final model to cardRunner type")
	}

	if m.selectedPlan >= 0 && m.selectedPlan < pack.LenOfItems() {
		plan := pack.GetResult(m.selectedPlan)
		return plan, nil
	}

	if m.quitting {
		return "", nil
	}
	return "", fmt.Errorf("internal problem. invalid selected plan index: %d", m.selectedPlan)
}

type cardRunner struct {
	b            CardPack
	currentPlan  int
	windowWidth  int
	windowHeight int
	help         help.Model
	keys         keyMap
	quitting     bool
	selectedPlan int // -1 means no selection yet
}

type keyMap struct {
	left     key.Binding
	right    key.Binding
	selected key.Binding
	quit     key.Binding
	help     key.Binding
}

func (k keyMap) ShortHelp() []key.Binding {
	return []key.Binding{k.help, k.quit}
}

func (k keyMap) FullHelp() [][]key.Binding {
	return [][]key.Binding{
		{k.left, k.right, k.selected},
		{k.help, k.quit},
	}
}

func newKeyMap() keyMap {
	return keyMap{
		left: key.NewBinding(
			key.WithKeys("left", "h"),
			key.WithHelp("←/h", "previous plan"),
		),
		right: key.NewBinding(
			key.WithKeys("right", "l"),
			key.WithHelp("→/l", "next plan"),
		),
		selected: key.NewBinding(
			key.WithKeys("enter", " "),
			key.WithHelp("enter/space", "select plan"),
		),
		help: key.NewBinding(
			key.WithKeys("?"),
			key.WithHelp("?", "toggle help"),
		),
		quit: key.NewBinding(
			key.WithKeys("q", "esc", "ctrl+c"),
			key.WithHelp("q/esc", "quit"),
		),
	}
}

func newCardRunner(b CardPack) cardRunner {
	return cardRunner{
		b:            b,
		currentPlan:  0,
		help:         help.New(),
		keys:         newKeyMap(),
		selectedPlan: -1,
	}
}

func (m cardRunner) Init() tea.Cmd {
	return nil
}

func (m cardRunner) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	switch msg := msg.(type) {
	case tea.KeyMsg:
		switch {
		case key.Matches(msg, m.keys.quit):
			m.quitting = true
			return m, tea.Quit

		case key.Matches(msg, m.keys.help):
			m.help.ShowAll = !m.help.ShowAll
			return m, nil

		case key.Matches(msg, m.keys.left):
			// Move to previous plan
			if m.currentPlan > 0 {
				m.currentPlan--
			}
			return m, nil

		case key.Matches(msg, m.keys.right):
			// Move to next plan
			if m.currentPlan < m.b.LenOfItems()-1 {
				m.currentPlan++
			}
			return m, nil

		case key.Matches(msg, m.keys.selected):
			// Select current plan
			m.selectedPlan = m.currentPlan
			return m, tea.Quit
		}

	case tea.WindowSizeMsg:
		m.windowWidth = msg.Width
		m.windowHeight = msg.Height
		return m, nil
	}

	return m, nil
}

func (m cardRunner) View() string {
	if m.quitting {
		if m.selectedPlan >= 0 && m.selectedPlan < m.b.LenOfItems() {
			return m.b.GetResult(m.selectedPlan)
		}
		return ""
	}

	maxWidth := m.windowWidth
	if maxWidth == 0 {
		maxWidth = 100 // Default width
	}

	cardWidth, visibleCards := m.b.GetCardConfiguration()

	// Add some top padding
	var builder strings.Builder
	builder.WriteString("\n\n")

	// Determine which cards to show
	var startIdx int

	implLen := m.b.LenOfItems()
	if m.currentPlan == 0 {
		startIdx = 0
	} else if m.currentPlan == implLen-1 {
		startIdx = max(0, implLen-visibleCards)
	} else {
		startIdx = max(0, m.currentPlan-1)
	}
	endIdx := min(implLen, startIdx+visibleCards)

	cards := make([]string, endIdx-startIdx)

	for i := startIdx; i < endIdx; i++ {
		plan := m.b.GetItem(i)
		isActive := i == m.currentPlan

		var borderColor, textColor, separatorColor lipgloss.Color
		var borderStyle lipgloss.Border

		if isActive {
			borderColor = lipgloss.Color("10")
			textColor = lipgloss.Color("#EEEEC7")
			separatorColor = lipgloss.Color("#555555")
			borderStyle = lipgloss.RoundedBorder()
		} else {
			borderColor = lipgloss.Color("#555555")
			textColor = lipgloss.Color("#AAAAAA")
			separatorColor = lipgloss.Color("#555555")
			borderStyle = lipgloss.RoundedBorder()
		}

		priceStyle := lipgloss.NewStyle().
			Foreground(textColor).
			Width(cardWidth - 3).
			Align(lipgloss.Center).
			PaddingTop(1)

		if isActive {
			priceStyle = priceStyle.Bold(true)
		}

		priceSection := priceStyle.Render(plan.GetUpper())

		separator := lipgloss.NewStyle().
			Foreground(separatorColor).
			Width(cardWidth - 3).
			Align(lipgloss.Center).
			PaddingTop(1).
			PaddingBottom(1).
			Render(strings.Repeat("─", cardWidth-6))

		specsStyle := lipgloss.NewStyle().
			Foreground(textColor).
			Width(cardWidth - 3).
			Align(lipgloss.Center).
			PaddingLeft(1)

		if isActive {
			specsStyle = specsStyle.Bold(true)
		}

		specsSection := specsStyle.Render(plan.GetLower())

		cardStyle := lipgloss.NewStyle().
			Border(borderStyle).
			BorderForeground(borderColor).
			Width(cardWidth).
			Padding(0, 1)

		cardContent := lipgloss.JoinVertical(lipgloss.Left,
			priceSection,
			separator,
			specsSection,
		)

		cards[i-startIdx] = cardStyle.Render(cardContent)
	}

	var rowContent strings.Builder

	rowContent.WriteString(lipgloss.JoinHorizontal(lipgloss.Top, cards...))

	centeredStyle := lipgloss.NewStyle().Width(maxWidth).Align(lipgloss.Center)
	builder.WriteString(centeredStyle.Render(rowContent.String()))
	builder.WriteString("\n\n")

	instructionStyle := lipgloss.NewStyle().
		Foreground(lipgloss.Color("#888888")).
		Align(lipgloss.Center).
		Width(maxWidth)

	builder.WriteString(instructionStyle.Render(m.b.GetInstruction() + "\n\n"))

	return builder.String()
}
07070100000028000081A40000000000000000000000016818E78D0000178A000000000000000000000000000000000000001D00000000ksctl-2.8.0/pkg/cli/debug.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cli

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/fatih/color"
)

type debugMenuDriven struct {
	progress ProgressAnimation
}

func (p *debugMenuDriven) CardSelection(element CardPack) (string, error) {
	for i := 0; i < element.LenOfItems(); i++ {
		e := element.GetItem(i)
		gg := fmt.Sprintf("--[%d]--%s\n%s\n-------\n", i, e.GetUpper(), e.GetLower())
		fmt.Println(gg)
	}
	fmt.Sprintln(element.GetInstruction())

	fmt.Printf("Enter the index? for not selecting press -1")
	var response string
	_, err := fmt.Scanln(&response)
	if err != nil {
		return "", err
	}
	if len(response) == 0 {
		return "", nil
	}

	if response == "-1" {
		return "", nil
	}

	v, err := strconv.Atoi(response)
	if err != nil {
		return "", err
	}

	return element.GetResult(v), nil
}

type debugSpinner struct {
	chars     []string
	done      chan bool
	active    bool
	startTime time.Time
}

func NewDebugMenuDriven() *debugMenuDriven {
	return &debugMenuDriven{}
}

func (p *debugMenuDriven) GetProgressAnimation() ProgressAnimation {
	if p.progress != nil {
		return p.progress
	}
	p.progress = &debugSpinner{
		chars:  []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"},
		done:   make(chan bool),
		active: false,
	}

	return p.progress
}

func (s *debugSpinner) Start(msg ...any) {
	if s.active {
		return
	}
	s.done = make(chan bool)
	fmt.Println(msg...)
	s.active = true
	s.startTime = time.Now()

	go func() {
		for i := 0; ; i = (i + 1) % len(s.chars) {
			select {
			case <-s.done:
				fmt.Println() // Clear the spinner
				return
			default:
				elapsed := time.Since(s.startTime).Round(time.Second)
				fmt.Printf("%s %s", s.chars[i], elapsed)
				time.Sleep(100 * time.Millisecond)
			}
		}
	}()
}

func (s *debugSpinner) StopWithSuccess(msg ...any) {
	if !s.active {
		return
	}
	fmt.Println(msg...)
	s.done <- true
	s.active = false
}

func (s *debugSpinner) StopWithFailure(msg ...any) {
	if !s.active {
		return
	}
	fmt.Println(msg...)
	s.done <- true
	s.active = false
}

func (s *debugSpinner) Stop() {
	if !s.active {
		return
	}
	s.done <- true
	s.active = false
}

func (p *debugMenuDriven) Confirmation(prompt string, opts ...func(*option) error) (proceed bool, err error) {
	o, err := processOptions(opts)
	if err != nil {
		return false, err
	}

	fmt.Println(prompt)
	fmt.Printf("Proceed? [y/N]{default: %s}: ", color.HiGreenString(o.defaultValue))
	var response string
	_, err = fmt.Scanln(&response)
	if err != nil {
		return false, err
	}
	if len(response) == 0 {
		if o.defaultValue != "" {
			response = o.defaultValue
		} else {
			return false, nil
		}
	}
	if response != "y" && response != "Y" && response != "yes" {
		return false, nil
	}

	fmt.Println()

	return true, nil
}

func (p *debugMenuDriven) TextInput(prompt string, opts ...func(*option) error) (string, error) {
	o, err := processOptions(opts)
	if err != nil {
		return "", err
	}

	reader := bufio.NewReader(os.Stdin)
	fmt.Printf("%s {default: %s}: ", prompt, color.HiGreenString(o.defaultValue))
	response, err := reader.ReadString('\n')
	if err != nil && io.EOF != err {
		return "", err
	}
	response = strings.TrimSpace(response)

	if len(response) == 0 {
		if o.defaultValue != "" {
			response = o.defaultValue
		}
	}

	fmt.Println("Got response:", response)
	fmt.Println()

	return response, nil
}

func (p *debugMenuDriven) TextInputPassword(prompt string) (string, error) {
	fmt.Println(prompt)
	var response string
	_, err := fmt.Scanln(&response)
	if err != nil {
		return "", err
	}

	return response, nil
}

func (p *debugMenuDriven) DropDown(prompt string, options map[string]string, opts ...func(*option) error) (string, error) {
	o, err := processOptions(opts)
	if err != nil {
		return "", err
	}

	fmt.Printf("%s {default: %s}\n", prompt, color.HiGreenString(o.defaultValue))
	fmt.Println("Options[make sure to enter value and not the key]:")
	for k, v := range options {
		fmt.Printf("%s: %s\n", k, color.HiCyanString(v))
	}

	var response string
	_, err = fmt.Scanln(&response)
	if err != nil {
		return "", err
	}

	if len(response) == 0 {
		if o.defaultValue != "" {
			response = o.defaultValue
		}
	}

	fmt.Println("Got response:", response)
	fmt.Println()

	return response, nil
}

func (p *debugMenuDriven) DropDownList(prompt string, options []string, opts ...func(*option) error) (string, error) {
	o, err := processOptions(opts)
	if err != nil {
		return "", err
	}

	fmt.Printf("%s {default: %s}\n", prompt, color.HiGreenString(o.defaultValue))
	fmt.Println("Options:")
	for _, v := range options {
		fmt.Println(color.HiCyanString(v))
	}

	var response string
	_, err = fmt.Scanln(&response)
	if err != nil {
		return "", err
	}

	if len(response) == 0 {
		if o.defaultValue != "" {
			response = o.defaultValue
		}
	}

	fmt.Println("Got response:", response)
	fmt.Println()

	return response, nil
}

func (p *debugMenuDriven) MultiSelect(prompt string, options map[string]string, opts ...func(*option) error) ([]string, error) {
	fmt.Println("Options[make sure to enter value and not the key]:")
	for k, v := range options {
		fmt.Printf("%s: %s\n", k, color.HiCyanString(v))
	}

	var response string
	_, err := fmt.Scanln(&response)
	if err != nil {
		return nil, err
	}

	if len(response) == 0 {
		return nil, fmt.Errorf("No response provided")
	}

	fmt.Println("Got response:", response)
	fmt.Println()

	return strings.Split(response, ","), nil
}
07070100000029000081A40000000000000000000000016818E78D000004AD000000000000000000000000000000000000001D00000000ksctl-2.8.0/pkg/cli/flags.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cli

import "github.com/spf13/cobra"

func MarkFlagsRequired(command *cobra.Command, flagNames ...string) error {
	for _, flagName := range flagNames {
		if err := command.MarkFlagRequired(flagName); err != nil {
			return err
		}
	}
	return nil
}

func AddVerboseFlag(command *cobra.Command, verbose *bool) {
	command.PersistentFlags().BoolVarP(verbose, "verbose", "v", false, "Enable verbose output")
}

func AddDebugMode(command *cobra.Command, debugRun *bool) {
	command.PersistentFlags().BoolVar(debugRun, "debug-cli", false, "Its used to run debug mode against cli's menudriven interface")
}
0707010000002A000081A40000000000000000000000016818E78D00000309000000000000000000000000000000000000001F00000000ksctl-2.8.0/pkg/cli/mapping.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cli

import "github.com/spf13/cobra"

func RegisterCommand(parent *cobra.Command, children ...*cobra.Command) {
	for _, child := range children {
		parent.AddCommand(child)
	}
}
0707010000002B000081A40000000000000000000000016818E78D000007B4000000000000000000000000000000000000002200000000ksctl-2.8.0/pkg/cli/menudriven.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cli

type ProgressAnimation interface {
	Start(msg ...any)
	StopWithSuccess(msg ...any)
	StopWithFailure(msg ...any)
	Stop()
}

type option struct {
	defaultValue string
}

func WithDefaultValue(defaultValue string) func(*option) error {
	return func(o *option) error {
		o.defaultValue = defaultValue
		return nil
	}
}

type CardItem interface {
	GetUpper() string
	GetLower() string
}

type CardPack interface {
	LenOfItems() int
	GetItem(i int) CardItem
	GetInstruction() string
	GetResult(index int) string
	GetCardConfiguration() (cardWidth, noOfVisibleItems int)
}

type MenuDriven interface {
	GetProgressAnimation() ProgressAnimation
	Confirmation(prompt string, opts ...func(*option) error) (proceed bool, err error)
	TextInput(prompt string, opts ...func(*option) error) (string, error)
	TextInputPassword(prompt string) (string, error)
	DropDown(prompt string, options map[string]string, opts ...func(*option) error) (string, error)
	DropDownList(prompt string, options []string, opts ...func(*option) error) (string, error)
	MultiSelect(prompt string, options map[string]string, opts ...func(*option) error) ([]string, error)
	CardSelection(element CardPack) (string, error)
}

func processOptions(opts []func(*option) error) (option, error) {
	var o option
	for _, opt := range opts {
		if err := opt(&o); err != nil {
			return o, err
		}
	}
	return o, nil
}
0707010000002C000081A40000000000000000000000016818E78D00001012000000000000000000000000000000000000001D00000000ksctl-2.8.0/pkg/cli/pterm.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cli

import (
	"fmt"
	"os"
	"strings"

	"github.com/pterm/pterm"
)

type genericMenuDriven struct {
	progress ProgressAnimation
}

type spinner struct {
	c      pterm.SpinnerPrinter
	s      *pterm.SpinnerPrinter
	active bool
}

func NewMenuDriven() *genericMenuDriven {
	return &genericMenuDriven{}
}

func (p *genericMenuDriven) GetProgressAnimation() ProgressAnimation {
	if p.progress != nil {
		return p.progress
	}

	spin := pterm.DefaultSpinner
	spin.Sequence = []string{"⡏", "⡟", "⡿", "⢿", "⣻", "⣽", "⣾", "⣷", "⣯", "⣏"}

	p.progress = &spinner{
		c: spin,
	}
	return p.progress
}

func (s *spinner) Start(msg ...any) {
	if s.active {
		return
	}
	s.s, _ = s.c.Start(msg...)
}

func (s *spinner) StopWithSuccess(msg ...any) {
	s.s.Success(msg...)
	s.s = nil
	s.active = false
}

func (s *spinner) Stop() {
	_, _ = fmt.Fprint(os.Stderr, "\r"+strings.Repeat(" ", pterm.GetTerminalWidth())) // Clear the spinner
	_ = s.s.Stop()
	s.s = nil
	s.active = false
}

func (s *spinner) StopWithFailure(msg ...any) {
	s.s.Fail(msg...)
	s.s = nil
	s.active = false
}

func (p *genericMenuDriven) Confirmation(prompt string, opts ...func(*option) error) (proceed bool, err error) {
	o, err := processOptions(opts)
	if err != nil {
		return false, err
	}

	x := pterm.DefaultInteractiveConfirm
	if len(o.defaultValue) != 0 {
		x = *x.WithDefaultValue(o.defaultValue == "yes")
	}
	return x.Show(prompt)
}

func (p *genericMenuDriven) TextInput(prompt string, opts ...func(*option) error) (string, error) {
	o, err := processOptions(opts)
	if err != nil {
		return "", err
	}

	if len(o.defaultValue) == 0 {
		return pterm.DefaultInteractiveTextInput.Show(prompt)
	}
	x := pterm.DefaultInteractiveTextInput.WithDefaultValue(o.defaultValue)
	return x.Show(prompt)
}

func (p *genericMenuDriven) TextInputPassword(prompt string) (string, error) {
	x := pterm.DefaultInteractiveTextInput.WithMask("*")
	return x.Show(prompt)
}

func (p *genericMenuDriven) DropDown(prompt string, options map[string]string, opts ...func(*option) error) (string, error) {
	o, err := processOptions(opts)
	if err != nil {
		return "", err
	}

	var _options []string
	for k := range options {
		_options = append(_options, k)
	}

	x := pterm.DefaultInteractiveSelect.WithOptions(_options)
	if len(o.defaultValue) != 0 {
		for k, v := range options {
			if v == o.defaultValue {
				o.defaultValue = k
				break
			}
		}
		x = x.WithDefaultOption(o.defaultValue)
	}

	if v, err := x.Show(prompt); err != nil {
		return "", err
	} else {
		return options[v], nil
	}

}

func (p *genericMenuDriven) DropDownList(prompt string, options []string, opts ...func(*option) error) (string, error) {
	o, err := processOptions(opts)
	if err != nil {
		return "", err
	}

	x := pterm.DefaultInteractiveSelect.WithOptions(options)
	if len(o.defaultValue) != 0 {
		x = x.WithDefaultOption(o.defaultValue)
	}

	if v, err := x.Show(prompt); err != nil {
		return "", err
	} else {
		return v, nil
	}
}

func (p *genericMenuDriven) MultiSelect(prompt string, options map[string]string, opts ...func(*option) error) ([]string, error) {
	var _options []string
	for k, _ := range options {
		_options = append(_options, k)
	}

	x := pterm.DefaultInteractiveMultiselect.WithOptions(_options)

	if v, err := x.Show(prompt); err != nil {
		return nil, err
	} else {
		if len(v) == 0 {
			return nil, fmt.Errorf("no options selected")
		}
		_v := make([]string, 0, len(v))
		for _, k := range v {
			_v = append(_v, options[k])
		}
		return _v, nil
	}
}
0707010000002D000081A40000000000000000000000016818E78D000031C5000000000000000000000000000000000000002200000000ksctl-2.8.0/pkg/cli/summary_ui.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cli

import (
	"fmt"
	"io"
	"strings"

	"github.com/charmbracelet/lipgloss"
	"github.com/fatih/color"
	"github.com/ksctl/ksctl/v2/pkg/handler/cluster/common"
)

// SummaryUI is responsible for rendering cluster summary with enhanced UI
type SummaryUI struct {
	writer io.Writer
}

// NewSummaryUI creates a new instance of SummaryUI
func NewSummaryUI(w io.Writer) *SummaryUI {
	return &SummaryUI{
		writer: w,
	}
}

// RenderClusterSummary renders the cluster summary with enhanced UI
func (ui *SummaryUI) RenderClusterSummary(summary *common.SummaryOutput) {
	parentBox := lipgloss.NewStyle().
		BorderStyle(lipgloss.RoundedBorder()).
		BorderForeground(lipgloss.Color("8")).
		Padding(1, 2).
		Width(90).
		Align(lipgloss.Center)

	banner := lipgloss.NewStyle().
		Padding(0, 1).
		Width(80).
		Align(lipgloss.Center)

	sectionTitle := lipgloss.NewStyle().
		Foreground(lipgloss.Color("13")).
		Bold(true).
		MarginTop(1).
		Padding(0, 1)

	infoBlock := lipgloss.NewStyle().
		BorderStyle(lipgloss.RoundedBorder()).
		BorderForeground(lipgloss.Color("10")).
		Padding(1, 2).
		MarginTop(1).
		Width(80)

	keyValueRow := func(key, value string) string {
		return lipgloss.JoinHorizontal(lipgloss.Top,
			lipgloss.NewStyle().Foreground(lipgloss.Color("14")).PaddingRight(3).Width(28).Align(lipgloss.Left).Render(key),
			lipgloss.NewStyle().Width(50).Render(value),
		)
	}

	var parentBoxContent strings.Builder

	bannerContent := fmt.Sprintf("✨ %s ✨\n\n%s",
		lipgloss.NewStyle().Bold(true).Align(lipgloss.Center).Foreground(lipgloss.Color("#FFFFFF")).Render("Cluster Summary"),
		lipgloss.NewStyle().Italic(true).Align(lipgloss.Center).Foreground(lipgloss.Color("#DDDDDD")).Render("Health and status of your Kubernetes cluster"))

	parentBoxContent.WriteString(banner.Render(bannerContent))
	parentBoxContent.WriteString("\n\n")

	// Cluster basics section
	{
		var content strings.Builder

		if summary.ClusterName != "" {
			content.WriteString(keyValueRow("Name", summary.ClusterName))
			content.WriteString("\n")
		}
		if summary.CloudProvider != "" {
			content.WriteString(keyValueRow("Cloud", summary.CloudProvider))
			content.WriteString("\n")
		}
		if summary.ClusterType != "" {
			content.WriteString(keyValueRow("Type", summary.ClusterType))
			content.WriteString("\n")
		}
		if summary.RoundTripLatency != "" {
			content.WriteString(keyValueRow("Round Trip Latency", summary.RoundTripLatency))
			content.WriteString("\n")
		}
		if summary.KubernetesVersion != "" {
			content.WriteString(keyValueRow("Kubernetes Version", summary.KubernetesVersion))
			content.WriteString("\n")
		}

		if summary.APIServerHealthCheck != nil {
			if !summary.APIServerHealthCheck.Healthy {
				content.WriteString(keyValueRow("API Server Health", color.HiRedString("Unhealthy")))
			} else {
				content.WriteString(keyValueRow("API Server Health", color.HiGreenString("Healthy")))
			}
			content.WriteString("\n")
			if len(summary.APIServerHealthCheck.FailedComponents) > 0 {
				v := color.HiRedString(strings.Join(summary.APIServerHealthCheck.FailedComponents, ", "))
				content.WriteString(keyValueRow("Components Unhealthy", v))
				content.WriteString("\n")
			}
		}
		for k, v := range summary.ControlPlaneComponentVers {
			content.WriteString(keyValueRow(k, v))
			content.WriteString("\n")
		}

		contentStr := strings.TrimSuffix(content.String(), "\n")
		contentBlock := infoBlock.Render(contentStr)
		titleBlock := sectionTitle.Render("🔑 Key Attributes")
		fullSection := lipgloss.JoinVertical(lipgloss.Left, titleBlock, contentBlock)

		parentBoxContent.WriteString(fullSection)
		parentBoxContent.WriteString("\n")
	}
	yesNoColor := func(v bool, inverse bool) (string, func(format string, a ...interface{}) string) {
		if v {
			if inverse {
				return "Yes", color.HiRedString
			}
			return "Yes", color.HiGreenString
		}
		if inverse {
			return "No", color.HiGreenString
		}
		return "No", color.HiRedString
	}
	applyYesNoColor := func(msg string, formatter func(format string, a ...interface{}) string) string {
		return formatter(msg)
	}

	{
		// Nodes section
		var content strings.Builder
		for _, node := range summary.Nodes {
			content.WriteString("\n")
			content.WriteString(color.HiMagentaString(node.Name))
			content.WriteString("\n")
			content.WriteString(keyValueRow(" Ready", applyYesNoColor(yesNoColor(node.Ready, false))))
			content.WriteString("\n")
			content.WriteString(keyValueRow(" Kubelet Healthy", applyYesNoColor(yesNoColor(node.KubeletHealthy, false))))
			content.WriteString("\n")
			content.WriteString(keyValueRow(" Memory Pressure", applyYesNoColor(yesNoColor(node.MemoryPressure, true))))
			content.WriteString("\n")
			content.WriteString(keyValueRow(" Disk Pressure", applyYesNoColor(yesNoColor(node.DiskPressure, true))))
			content.WriteString("\n")
			content.WriteString(keyValueRow(" Unreachable", applyYesNoColor(yesNoColor(node.NetworkUnavailable, true))))
			content.WriteString("\n")

			content.WriteString(keyValueRow(" Kubelet Version", node.KubeletVersion))
			content.WriteString("\n")

			content.WriteString(keyValueRow(" CRI", node.ContainerRuntimeVersion))
			content.WriteString("\n")

			cpuUtlization := "😢 Currently Unavailable"
			if node.CPUUtilization > 0 {
				cpuUtlization = fmt.Sprintf("%.2f%% (Total: %s)", node.CPUUtilization, node.CPUUnits)
			}
			memoryUtlization := "😢 Currently Unavailable"
			if node.MemoryUtilization > 0 {
				memoryUtlization = fmt.Sprintf("%.2f%% (Total: %s)", node.MemoryUtilization, node.MemUnits)
			}
			content.WriteString(keyValueRow(" CPU Usage", cpuUtlization))
			content.WriteString("\n")
			content.WriteString(keyValueRow(" Memory Usage", memoryUtlization))
			content.WriteString("\n")
		}

		contentStr := strings.TrimSuffix(content.String(), "\n")
		contentBlock := infoBlock.Render(contentStr)
		titleBlock := sectionTitle.Render("🤖 Nodes")
		fullSection := lipgloss.JoinVertical(lipgloss.Left, titleBlock, contentBlock)

		parentBoxContent.WriteString(fullSection)
		parentBoxContent.WriteString("\n")
	}
	{
		// Workload section
		var content strings.Builder
		workloads := summary.WorkloadSummary
		content.WriteString(keyValueRow("Deployments", fmt.Sprintf("%d", workloads.Deployments)))
		content.WriteString("\n")
		content.WriteString(keyValueRow("StatefulSets", fmt.Sprintf("%d", workloads.StatefulSets)))
		content.WriteString("\n")
		content.WriteString(keyValueRow("DaemonSets", fmt.Sprintf("%d", workloads.DaemonSets)))
		content.WriteString("\n")
		content.WriteString(keyValueRow("CronJobs", fmt.Sprintf("%d", workloads.CronJobs)))
		content.WriteString("\n")
		content.WriteString(keyValueRow("Namespaces", fmt.Sprintf("%d", workloads.Namespaces)))
		content.WriteString("\n")
		content.WriteString(keyValueRow("Persistent Volumes", fmt.Sprintf("%d", workloads.PV)))
		content.WriteString("\n")
		content.WriteString(keyValueRow("Persistent Volume Claims", fmt.Sprintf("%d", workloads.PVC)))
		content.WriteString("\n")
		content.WriteString(keyValueRow("Storage Class", fmt.Sprintf("%d", workloads.SC)))
		content.WriteString("\n")
		content.WriteString(keyValueRow("Service (ClusterIP)", fmt.Sprintf("%d", workloads.ClusterIPSVC)))
		content.WriteString("\n")
		content.WriteString(keyValueRow("Service (LoadBalancer)", fmt.Sprintf("%d", workloads.LoadbalancerSVC)))
		content.WriteString("\n")
		content.WriteString(keyValueRow("Pods (Running)", fmt.Sprintf("%d", workloads.RunningPods)))
		content.WriteString("\n")

		if len(workloads.UnHealthyPods) > 0 {
			content.WriteString(color.HiMagentaString("Unhealthy Pods"))
			content.WriteString("\n")
		}

		for _, pod := range workloads.UnHealthyPods {
			content.WriteString("\n")
			content.WriteString(" " + color.HiRedString(pod.Name+"@"+pod.Namespace))
			content.WriteString("\n")
			objectRef := []string{}
			for _, ref := range pod.OwnerRef {
				v := fmt.Sprintf("%s/%s@%s", ref.Kind, ref.Name, pod.Namespace)
				objectRef = append(objectRef, v)
			}
			if len(objectRef) == 0 {
				objectRef = append(objectRef, "No Owner Reference")
			}
			content.WriteString(keyValueRow("  "+"Owner Ref", strings.Join(objectRef, ", ")))
			content.WriteString("\n")
			content.WriteString(keyValueRow("  "+"Failed", applyYesNoColor(yesNoColor(pod.IsFailed, true))))
			content.WriteString("\n")
			content.WriteString(keyValueRow("  "+"Pending", applyYesNoColor(yesNoColor(pod.IsPending, true))))
			content.WriteString("\n")
			for _, container := range pod.FailedContainers {
				content.WriteString("\n")
				content.WriteString(keyValueRow("  "+"Container", container.Name))
				content.WriteString("\n")
				content.WriteString(keyValueRow("   "+"Restart Count", fmt.Sprintf("%d", container.RestartCount)))
				content.WriteString("\n")
				content.WriteString(keyValueRow("   "+"Reason", container.WaitingProblem.Reason))
				content.WriteString("\n")
				content.WriteString(keyValueRow("   "+"Message", container.WaitingProblem.Message))
				content.WriteString("\n")
			}
			content.WriteString("\n")
		}

		contentStr := strings.TrimSuffix(content.String(), "\n")
		contentBlock := infoBlock.Render(contentStr)
		titleBlock := sectionTitle.Render("📦 Workloads")
		fullSection := lipgloss.JoinVertical(lipgloss.Left, titleBlock, contentBlock)

		parentBoxContent.WriteString(fullSection)
		parentBoxContent.WriteString("\n")
	}
	{
		// Recent events section
		var content strings.Builder
		if len(summary.RecentWarningEvents) == 0 {
			content.WriteString(color.HiGreenString("No recent events"))
			content.WriteString("\n")
		} else {
			content.WriteString(color.HiMagentaString("Recent Warning Events (Past 24h)"))
			content.WriteString("\n")
			for _, event := range summary.RecentWarningEvents {
				content.WriteString("\n")
				content.WriteString(color.HiMagentaString(fmt.Sprintf("%s/%s@%s", event.Kind, event.Name, event.Namespace)))
				content.WriteString("\n")
				content.WriteString(keyValueRow("  Reason", event.Reason))
				content.WriteString("\n")
				content.WriteString(keyValueRow("  Message", event.Message))
				content.WriteString("\n")
				content.WriteString(keyValueRow("  Happened On", event.Time.String()))
				content.WriteString("\n")
				content.WriteString(keyValueRow("  Reported By", event.ReportedBy))
				content.WriteString("\n")
			}
		}

		contentStr := strings.TrimSuffix(content.String(), "\n")
		contentBlock := infoBlock.Render(contentStr)
		titleBlock := sectionTitle.Render("📢 Events")
		fullSection := lipgloss.JoinVertical(lipgloss.Left, titleBlock, contentBlock)

		parentBoxContent.WriteString(fullSection)
		parentBoxContent.WriteString("\n")
	}
	{
		// Issues section
		var content strings.Builder
		if len(summary.DetectedIssues) == 0 {
			content.WriteString(color.HiGreenString("No issues detected"))
			content.WriteString("\n")
		} else {
			content.WriteString(color.HiMagentaString("Detected Issues"))
			content.WriteString("\n")
			severityColor := func(severity string) string {
				switch severity {
				case "Critical":
					return color.New(color.BgRed, color.FgBlack).Add(color.Bold).Sprintf("%s", severity)
				case "Error":
					return color.HiRedString(severity)
				case "Warning":
					return color.HiYellowString(severity)
				default:
					return severity
				}
			}
			for _, issue := range summary.DetectedIssues {
				content.WriteString(color.HiMagentaString(issue.Component))
				content.WriteString("\n")
				content.WriteString(keyValueRow(" Severity", severityColor(issue.Severity)))
				content.WriteString("\n")
				content.WriteString(keyValueRow(" Message", issue.Message))
				content.WriteString("\n")
				content.WriteString(keyValueRow(" Recommendation", issue.Recommendation))
				content.WriteString("\n")
			}
		}

		contentStr := strings.TrimSuffix(content.String(), "\n")
		contentBlock := infoBlock.Render(contentStr)
		titleBlock := sectionTitle.Render("🚩 Problems")
		fullSection := lipgloss.JoinVertical(lipgloss.Left, titleBlock, contentBlock)

		parentBoxContent.WriteString(fullSection)
		parentBoxContent.WriteString("\n")
	}

	fmt.Fprintln(ui.writer, parentBox.Render(parentBoxContent.String()))
}
0707010000002E000041ED0000000000000000000000026818E78D00000000000000000000000000000000000000000000001700000000ksctl-2.8.0/pkg/config0707010000002F000081A40000000000000000000000016818E78D00000883000000000000000000000000000000000000002000000000ksctl-2.8.0/pkg/config/cache.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package config

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"time"
)

type UpdateCache struct {
	LastChecked         time.Time     `json:"lastChecked"`
	AvailableVersions   bool          `json:"availableVersions"`
	UpdateCheckInterval time.Duration `json:"updateCheckInterval"`
}

var DefaultUpdateCache = &UpdateCache{
	UpdateCheckInterval: time.Hour * 24,
}

func locateUpdateCacheFile() (string, error) {
	homeDir, err := os.UserHomeDir()
	if err != nil {
		return "", err
	}

	configDir := filepath.Join(homeDir, ".config", "ksctl")
	configFile := filepath.Join(configDir, "cache-update.json")
	if _, err := os.Stat(configDir); os.IsNotExist(err) {
		if err := os.MkdirAll(configDir, 0755); err != nil {
			return configFile, fmt.Errorf("failed to create directory %s: %v", configDir, err)
		}
	}
	return configFile, nil
}

func LoadUpdateCache(c *UpdateCache) (errC error) {

	configFile, err := locateUpdateCacheFile()
	if err != nil {
		return err
	}

	file, err := os.Open(configFile)
	if err != nil {
		if os.IsNotExist(err) {
			// NOTE: writing default config
			c = DefaultUpdateCache
			return SaveUpdateCache(c)
		}
		return fmt.Errorf("failed to open file %s: %v", configFile, err)
	}
	defer file.Close()

	return json.NewDecoder(file).Decode(c)
}

func SaveUpdateCache(c *UpdateCache) error {
	configFile, err := locateUpdateCacheFile()
	if err != nil {
		return err
	}

	file, err := os.Create(configFile)
	if err != nil {
		return fmt.Errorf("failed to create file %s: %v", configFile, err)
	}
	defer file.Close()

	return json.NewEncoder(file).Encode(c)
}
07070100000030000081A40000000000000000000000016818E78D00000B53000000000000000000000000000000000000002100000000ksctl-2.8.0/pkg/config/config.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package config

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"

	"github.com/ksctl/ksctl/v2/pkg/consts"
	"github.com/ksctl/ksctl/v2/pkg/utilities"
)

// ksctl config in ~/.config/ksctl/config.json (handled by ksctl:cli)
// ksctl credentials in ~/.config/ksctl/creds/(aws|azure|mongodb).json (handled by ksctl:cli)
// ksctl state in ~/.ksctl/state/..... (handled by the ksctl:core:storage)

// NOTE
// store all the credentials in the local file system and for state we decide on the external storage
// we will retrieve the credentials and load them in the context.Background() and pass it to the respective clients
// So we need to initialize the HostStorage() to get the credentials from the local file system once thats done
// we can populate the context.Background() with the credentials. and initialze the client which that preferedstateStore unless specified in the command argument

type Config struct {
	PreferedStateStore consts.KsctlStore `json:"preferedStateStore"`
	Telemetry          *bool             `json:"telemetry,omitempty"`
}

func LoadConfig(c *Config) (errC error) {

	configFile, err := locateConfig()
	if err != nil {
		return err
	}

	file, err := os.Open(configFile)
	if err != nil {
		if os.IsNotExist(err) {
			// NOTE: writing default config
			*c = Config{
				PreferedStateStore: consts.StoreLocal,
				Telemetry:          utilities.Ptr(true),
			}
			return SaveConfig(c)
		}
		return fmt.Errorf("failed to open file %s: %v", configFile, err)
	}
	defer file.Close()

	return json.NewDecoder(file).Decode(c)
}

func locateConfig() (fileLoc string, err error) {
	homeDir, err := os.UserHomeDir()
	if err != nil {
		return "", err
	}

	configDir := filepath.Join(homeDir, ".config", "ksctl")
	configFile := filepath.Join(configDir, "config.json")
	if _, err := os.Stat(configDir); os.IsNotExist(err) {
		if err := os.MkdirAll(configDir, 0755); err != nil {
			return configFile, fmt.Errorf("failed to create directory %s: %v", configDir, err)
		}
	}
	return configFile, nil
}

func SaveConfig(c *Config) error {
	configFile, err := locateConfig()
	if err != nil {
		return err
	}

	file, err := os.Create(configFile)
	if err != nil {
		return fmt.Errorf("failed to create file %s: %v", configFile, err)
	}
	defer file.Close()

	return json.NewEncoder(file).Encode(c)
}
07070100000031000081A40000000000000000000000016818E78D00000C52000000000000000000000000000000000000002000000000ksctl-2.8.0/pkg/config/creds.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package config

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"

	"github.com/ksctl/ksctl/v2/pkg/consts"
	ksctlErrors "github.com/ksctl/ksctl/v2/pkg/errors"
	"github.com/ksctl/ksctl/v2/pkg/statefile"
)

func locateCreds(s, prefix string) (fileLoc string, err error) {
	if len(s) == 0 {
		return "", fmt.Errorf("sku is empty")
	}

	homeDir, err := os.UserHomeDir()
	if err != nil {
		return "", err
	}

	configDir := filepath.Join(homeDir, ".config", "ksctl", "creds")
	configFile := filepath.Join(configDir, prefix+s+".json")
	if _, err := os.Stat(configDir); os.IsNotExist(err) {
		if err := os.MkdirAll(configDir, 0755); err != nil {
			return configFile, fmt.Errorf("failed to create directory %s: %v", configDir, err)
		}
	}
	return configFile, nil
}

func SaveStorageCreds[T statefile.CredentialsMongodb](c *T, s consts.KsctlStore) error {
	credsFile, err := locateCreds(string(s), "s-")
	if err != nil {
		return err
	}

	file, err := os.Create(credsFile)
	if err != nil {
		return fmt.Errorf("failed to create file %s: %v", credsFile, err)
	}
	defer file.Close()

	return json.NewEncoder(file).Encode(c)
}

func LoadStorageCreds[T statefile.CredentialsMongodb](c *T, s consts.KsctlStore) (errC error) {
	credsFile, err := locateCreds(string(s), "s-")
	if err != nil {
		return err
	}

	file, err := os.Open(credsFile)
	if err != nil {
		if os.IsNotExist(err) {
			return ksctlErrors.WrapErrorf(
				ksctlErrors.ErrNilCredentials,
				"credentials for storage driver %s not found",
				s,
			)
		}
		return fmt.Errorf("failed to open file %s: %v", credsFile, err)
	}
	defer file.Close()

	return json.NewDecoder(file).Decode(c)
}

func SaveCloudCreds[T statefile.CredentialsAws | statefile.CredentialsAzure](c *T, s consts.KsctlCloud) error {
	credsFile, err := locateCreds(string(s), "c-")
	if err != nil {
		return err
	}

	file, err := os.Create(credsFile)
	if err != nil {
		return fmt.Errorf("failed to create file %s: %v", credsFile, err)
	}
	defer file.Close()

	return json.NewEncoder(file).Encode(c)
}

func LoadCloudCreds[T statefile.CredentialsAws | statefile.CredentialsAzure](c *T, s consts.KsctlCloud) (errC error) {
	credsFile, err := locateCreds(string(s), "c-")
	if err != nil {
		return err
	}

	file, err := os.Open(credsFile)
	if err != nil {
		if os.IsNotExist(err) {
			return ksctlErrors.WrapErrorf(
				ksctlErrors.ErrNilCredentials,
				"credentials for cloud %s not found",
				s,
			)
		}

		return fmt.Errorf("failed to open file %s: %v", credsFile, err)
	}
	defer file.Close()

	return json.NewDecoder(file).Decode(c)
}
07070100000032000081A40000000000000000000000016818E78D00000307000000000000000000000000000000000000001F00000000ksctl-2.8.0/pkg/config/vars.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package config

// change this using ldflags
var (
	Version      string = "dev"
	KsctlCoreVer string = "dev"
	BuildDate    string
)

func InDevMode() bool {
	return Version == "dev"
}
07070100000033000041ED0000000000000000000000026818E78D00000000000000000000000000000000000000000000001700000000ksctl-2.8.0/pkg/logger07070100000034000081A40000000000000000000000016818E78D00002A45000000000000000000000000000000000000002A00000000ksctl-2.8.0/pkg/logger/general_logging.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package logger

import (
	"context"
	"fmt"
	"io"
	"os"
	"reflect"
	"strings"
	"sync"

	"github.com/charmbracelet/lipgloss"
	"github.com/fatih/color"
	"github.com/ksctl/ksctl/v2/pkg/logger"
	"github.com/rodaine/table"
	"golang.org/x/term"

	"time"
)

type GeneralLog struct {
	mu      *sync.Mutex
	writter io.Writer
	level   uint
	started time.Time
}

var (
	warnLvl = logger.CustomExternalLogLevel(color.New(color.FgBlack, color.BgYellow).Sprintf("[W]"))
	infoLvl = logger.CustomExternalLogLevel(color.New(color.FgBlack, color.BgBlue).Sprintf("[I]"))
	noteLvl = logger.CustomExternalLogLevel(color.New(color.FgBlack, color.BgCyan).Sprintf("[N]"))
	dbgLvl  = logger.CustomExternalLogLevel(color.New(color.FgBlack, color.BgMagenta).Sprintf("[D]"))
	passLvl = logger.CustomExternalLogLevel(color.New(color.FgBlack, color.BgGreen).Sprintf("[S]"))
	errLvl  = logger.CustomExternalLogLevel(color.New(color.FgBlack, color.BgRed).Sprintf("[E]"))
)

func NewLogger(verbose int, out io.Writer) *GeneralLog {

	var ve uint

	if verbose < 0 {
		ve = 9
	}

	return &GeneralLog{
		writter: out,
		level:   ve,
		mu:      new(sync.Mutex),
		started: time.Now().UTC(),
	}
}

func (l *GeneralLog) getTime() string {
	return color.HiBlackString(fmt.Sprintf("(%s)", time.Since(l.started).Round(time.Second).String()))
}

func formGroups(v ...any) (format string, vals []any) {
	if len(v) == 0 {
		return "\n", nil
	}
	_format := strings.Builder{}

	defer func() {
		format = _format.String()
	}()

	i := 0
	for ; i+1 < len(v); i += 2 {
		if !reflect.TypeOf(v[i+1]).Implements(reflect.TypeOf((*error)(nil)).Elem()) &&
			(reflect.TypeOf(v[i+1]).Kind() == reflect.Interface ||
				reflect.TypeOf(v[i+1]).Kind() == reflect.Ptr ||
				reflect.TypeOf(v[i+1]).Kind() == reflect.Struct) {
			_format.WriteString(fmt.Sprintf("%s", v[i]) + "=%#v ")
		} else {
			_format.WriteString(fmt.Sprintf("%s", v[i]) + "=%v ")
		}

		vals = append(vals, v[i+1])
	}

	for ; i < len(v); i++ {
		_format.WriteString("!!EXTRA:%v ")
		vals = append(vals, v[i])
	}
	_format.WriteString("\n")
	return
}

func isLogEnabled(level uint, msgType logger.CustomExternalLogLevel) bool {
	if msgType == dbgLvl {
		return level >= 9
	}
	return true
}

func (l *GeneralLog) logErrorf(disablePrefix bool, msg string, args ...any) error {
	l.mu.Lock()
	defer l.mu.Unlock()
	if !disablePrefix {
		prefix := fmt.Sprintf("%s%s ", l.getTime(), errLvl)
		msg = prefix + msg
	}
	format, _args := formGroups(args...)

	var errMsg error
	if _args == nil {
		errMsg = fmt.Errorf("%s %s", msg, format)
	} else {
		errMsg = fmt.Errorf(msg+" "+format, _args...)
	}

	return errMsg
}

func (l *GeneralLog) log(useGroupFormer bool, msgType logger.CustomExternalLogLevel, msg string, args ...any) {
	if !isLogEnabled(l.level, msgType) {
		return
	}
	l.mu.Lock()
	defer l.mu.Unlock()

	prefix := fmt.Sprintf("%s ", msgType)
	elapsedTime := color.HiBlackString(fmt.Sprintf("(%s)", time.Since(l.started).Round(time.Second).String()))

	// Get terminal width for right-aligned time
	width, _, err := term.GetSize(int(os.Stdout.Fd()))
	if err != nil || width <= 0 {
		// Fallback to a reasonable default width if we can't determine terminal size
		width = 120
	}

	if useGroupFormer {
		msgColored := ""
		switch msgType {
		case passLvl:
			msgColored = color.HiGreenString(msg)
		case warnLvl:
			msgColored = color.HiYellowString(msg)
		case dbgLvl:
			msgColored = color.HiMagentaString(msg)
		case noteLvl:
			msgColored = color.HiCyanString(msg)
		case infoLvl:
			msgColored = color.HiBlueString(msg)
		case errLvl:
			msgColored = color.HiRedString(msg)
		}

		// Create the base message with prefix and colored text
		baseMsg := prefix + msgColored

		format, _args := formGroups(args...)

		if _args == nil {
			if msgType == errLvl {
				l.boxBox(
					"🛑 We Have Problem", msgColored+" "+format, "Red")
				return
			}

			// Format the message with right-aligned elapsed time
			formattedMessage := formatWithRightAlignedTime(baseMsg+" "+format, elapsedTime, width)
			fmt.Fprint(l.writter, formattedMessage)
		} else {
			if msgType == errLvl {
				l.boxBox(
					"🛑 We Have Problem", fmt.Sprintf(msgColored+" "+format, _args...), "Red")
				return
			}

			// Format the message with args and right-aligned elapsed time
			fullMsg := fmt.Sprintf(baseMsg+" "+format, _args...)
			formattedMessage := formatWithRightAlignedTime(fullMsg, elapsedTime, width)
			fmt.Fprint(l.writter, formattedMessage)
		}
	} else {
		// Format non-group messages with right-aligned time
		fullMsg := fmt.Sprintf(prefix+msg+"\n", args...)
		formattedMessage := formatWithRightAlignedTime(fullMsg, elapsedTime, width)
		fmt.Fprint(l.writter, formattedMessage)
	}
}

func (l *GeneralLog) ExternalLogHandler(ctx context.Context, msgType logger.CustomExternalLogLevel, message string) {
	if msgType == logger.LogDebug {
		msgType = dbgLvl
	} else if msgType == logger.LogError {
		msgType = errLvl
	} else if msgType == logger.LogInfo {
		msgType = infoLvl
	} else if msgType == logger.LogWarning {
		msgType = warnLvl
	} else if msgType == logger.LogSuccess {
		msgType = passLvl
	} else if msgType == logger.LogNote {
		msgType = noteLvl
	}
	l.log(false, msgType, message)
}

func (l *GeneralLog) ExternalLogHandlerf(ctx context.Context, msgType logger.CustomExternalLogLevel, format string, args ...interface{}) {
	if msgType == logger.LogDebug {
		msgType = dbgLvl
	} else if msgType == logger.LogError {
		msgType = errLvl
	} else if msgType == logger.LogInfo {
		msgType = infoLvl
	} else if msgType == logger.LogWarning {
		msgType = warnLvl
	} else if msgType == logger.LogSuccess {
		msgType = passLvl
	} else if msgType == logger.LogNote {
		msgType = noteLvl
	}
	l.log(false, msgType, format, args...)
}

func (l *GeneralLog) Print(ctx context.Context, msg string, args ...any) {
	l.log(true, infoLvl, msg, args...)
}

func (l *GeneralLog) Success(ctx context.Context, msg string, args ...any) {
	l.log(true, passLvl, msg, args...)
}

func (l *GeneralLog) Note(ctx context.Context, msg string, args ...any) {
	l.log(true, noteLvl, msg, args...)
}

func (l *GeneralLog) Debug(ctx context.Context, msg string, args ...any) {
	l.log(true, dbgLvl, msg, args...)
}

func (l *GeneralLog) Error(msg string, args ...any) {
	l.log(true, errLvl, msg, args...)
}

func (l *GeneralLog) NewError(ctx context.Context, msg string, args ...any) error {
	return l.logErrorf(true, msg, args...)
}

func (l *GeneralLog) Warn(ctx context.Context, msg string, args ...any) {
	l.log(true, warnLvl, msg, args...)
}

func (l *GeneralLog) Table(ctx context.Context, headers []string, data [][]string) {
	headerFmt := color.New(color.FgHiBlack, color.Underline).SprintfFunc()
	columnFmt := color.New(color.FgHiGreen).SprintfFunc()

	var dataToPrint [][]interface{} = make([][]interface{}, 0, len(data))
	for _, v := range data {
		var row []interface{}
		for _, vv := range v {
			row = append(row, vv)
		}
		dataToPrint = append(dataToPrint, row)
	}

	var header []interface{}
	for _, v := range headers {
		header = append(header, v)
	}

	tbl := table.New(header...)
	tbl.WithHeaderFormatter(headerFmt).WithFirstColumnFormatter(columnFmt)

	for _, row := range dataToPrint {
		tbl.AddRow(row...)
	}
	tbl.Print()
}

func (l *GeneralLog) boxBox(title, lines string, colorName string) {
	var borderColor lipgloss.Color
	switch colorName {
	case "Red":
		borderColor = lipgloss.Color("9") // Bright red
	case "Green":
		borderColor = lipgloss.Color("10") // Bright green
	default:
		borderColor = lipgloss.Color("#555555") // Default gray
	}

	width := max(min(len(lines), 80), min(len(title), 80)) + 2

	var builder strings.Builder
	builder.WriteString("\n\n")

	boxStyle := lipgloss.NewStyle().
		BorderStyle(lipgloss.RoundedBorder()).
		BorderForeground(borderColor).
		Padding(1)

	contentStyle := lipgloss.NewStyle().
		Foreground(lipgloss.Color("#FFFFFF")).
		Align(lipgloss.Center).
		PaddingLeft(1).
		PaddingRight(1).Width(width)

	titleStyle := lipgloss.NewStyle().
		Foreground(borderColor).
		Align(lipgloss.Center).
		Bold(true).
		PaddingBottom(1).
		PaddingLeft(1).
		PaddingRight(1).Width(width)

	cardContent := lipgloss.JoinVertical(lipgloss.Center,
		titleStyle.Render(title),
		contentStyle.Render(lines),
	)

	builder.WriteString(boxStyle.Render(cardContent))
	builder.WriteString("\n\n")

	fmt.Fprintln(l.writter, builder.String())
}

func (l *GeneralLog) Box(ctx context.Context, title string, lines string) {

	l.Debug(ctx, "PostUpdate Box", "title", len(title), "lines", len(lines))

	l.boxBox(title, lines, "Green")
}

// formatWithRightAlignedTime formats a log message with the elapsed time right-aligned
func formatWithRightAlignedTime(message string, elapsedTime string, width int) string {
	// Strip ANSI color codes for length calculation
	plainMessage := stripANSIColors(message)
	plainTime := stripANSIColors(elapsedTime)

	// Check if message has newline
	endsWithNewline := strings.HasSuffix(plainMessage, "\n")

	// Remove trailing newline for calculations
	if endsWithNewline {
		plainMessage = plainMessage[:len(plainMessage)-1]
	}

	// Get the actual message without newline for length calculation
	messageWithoutNewline := message
	if endsWithNewline && len(message) > 0 {
		messageWithoutNewline = message[:len(message)-1]
	}

	// Calculate available space and padding needed
	msgLen := len(plainMessage)
	timeLen := len(plainTime)

	// Ensure we have enough space, accounting for at least 2 spaces between message and time
	padding := max(width-msgLen-timeLen, 2)

	// Build the formatted line
	var result strings.Builder
	result.WriteString(messageWithoutNewline)
	result.WriteString(strings.Repeat(" ", padding))
	result.WriteString(elapsedTime)
	if endsWithNewline {
		result.WriteString("\n")
	}

	return result.String()
}

// stripANSIColors removes ANSI color codes from a string to get its visual length
func stripANSIColors(s string) string {
	// ANSI escape code regex: \x1b\[[0-9;]*m
	var result strings.Builder
	inEscapeSeq := false

	for _, r := range s {
		if inEscapeSeq {
			if r == 'm' {
				inEscapeSeq = false
			}
			continue
		}

		if r == '\x1b' {
			inEscapeSeq = true
			continue
		}

		if !inEscapeSeq {
			result.WriteRune(r)
		}
	}

	return result.String()
}
07070100000035000081A40000000000000000000000016818E78D00000742000000000000000000000000000000000000002600000000ksctl-2.8.0/pkg/logger/logger_test.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package logger

import (
	"context"
	"fmt"
	"os"
	"testing"

	"github.com/ksctl/ksctl/v2/pkg/logger"
)

var (
	gL       logger.Logger
	dummyCtx = context.TODO()
)

func TestMain(m *testing.M) {
	gL = NewLogger(-1, os.Stdout)
	_ = NewLogger(0, os.Stdout)
	exitVal := m.Run()

	os.Exit(exitVal)
}

func TestPrinters(t *testing.T) {

	t.Run("Success", func(t *testing.T) {
		gL.Success(dummyCtx, "FAKE", "type", "success")
	})

	t.Run("Warn", func(t *testing.T) {
		gL.Warn(dummyCtx, "FAKE", "type", "warn")
	})

	t.Run("Error", func(t *testing.T) {
		gL.Error("FAKE", "type", "error")
	})

	t.Run("Debug", func(t *testing.T) {
		gL.Debug(dummyCtx, "FAKE", "type", "debugging")
	})

	t.Run("Note", func(t *testing.T) {
		gL.Note(dummyCtx, "FAKE", "type", "note")
	})

	t.Run("Print", func(t *testing.T) {
		gL.Print(dummyCtx, "FAKE", "type", "print")
	})

	t.Run("Box", func(t *testing.T) {
		gL.Box(dummyCtx, "Abcd", "1")
		gL.Box(dummyCtx, "Abcddedefe", "1")
		gL.Box(dummyCtx, "KUBECONFIG env var", "/jknc/csdc")
		gL.Box(dummyCtx, "KUBECONFIG env var", "jknc")
	})

	t.Run("external", func(t *testing.T) {
		gL.ExternalLogHandler(dummyCtx, logger.LogSuccess, "cdcc")
		gL.ExternalLogHandlerf(dummyCtx, logger.LogSuccess, "cdcc", "Reason", fmt.Errorf("Error"))
	})
}
07070100000036000041ED0000000000000000000000026818E78D00000000000000000000000000000000000000000000001A00000000ksctl-2.8.0/pkg/telemetry07070100000037000081A40000000000000000000000016818E78D000011F8000000000000000000000000000000000000002700000000ksctl-2.8.0/pkg/telemetry/telemetry.go// Copyright 2025 Ksctl Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package telemetry

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"runtime"

	"github.com/fatih/color"
	"github.com/ksctl/cli/v2/pkg/config"
	"github.com/ksctl/ksctl/v2/pkg/addons"
	"github.com/ksctl/ksctl/v2/pkg/consts"
	"github.com/ksctl/ksctl/v2/pkg/logger"
)

var (
	clientIdentity string
)

type TelemetryEvent string

const (
	EventClusterCreate       TelemetryEvent = "cluster_create"
	EventClusterDelete       TelemetryEvent = "cluster_delete"
	EventClusterConnect      TelemetryEvent = "cluster_connect"
	EventClusterList         TelemetryEvent = "cluster_list"
	EventClusterGet          TelemetryEvent = "cluster_get"
	EventClusterScaleDown    TelemetryEvent = "cluster_scaledown"
	EventClusterScaleUp      TelemetryEvent = "cluster_scaleup"
	EventClusterUpgrade      TelemetryEvent = "cli_upgrade"
	EventClusterAddonEnable  TelemetryEvent = "cluster_addon_enable"
	EventClusterAddonDisable TelemetryEvent = "cluster_addon_disable"
)

type TelemetryAddon struct {
	Sku     string `json:"sku"`
	Version string `json:"version"`
	Label   string `json:"label"`
}

func TranslateMetadata(addons addons.ClusterAddons) []TelemetryAddon {
	var telemetryAddons []TelemetryAddon

	for _, addon := range addons {
		telemetryAddons = append(telemetryAddons, TelemetryAddon{
			Sku:   addon.Name,
			Label: addon.Label,
		})
	}

	return telemetryAddons
}

type TelemetryMeta struct {
	CloudProvider     consts.KsctlCloud       `json:"cloud_provider"`
	StorageDriver     consts.KsctlStore       `json:"storage_driver"`
	Region            string                  `json:"cloud_provider_region"`
	ClusterType       consts.KsctlClusterType `json:"cluster_type"`
	BootstrapProvider consts.KsctlKubernetes  `json:"bootstrap_provider"`
	K8sVersion        string                  `json:"k8s_version"`
	Addons            []TelemetryAddon        `json:"addons"`
}

type TelemetryData struct {
	ClientIdentity string         `json:"client_identity"`
	UserId         string         `json:"client_id"`
	Event          TelemetryEvent `json:"event"`

	KsctlVer string        `json:"ksctl_ver"`
	OS       string        `json:"os"`
	Arch     string        `json:"arch"`
	Data     TelemetryMeta `json:"meta"`
}

type Telemetry struct {
	userId   string
	ksctlVer string
	endpoint string
	active   bool
	os       string
	arch     string
}

func NewTelemetry(active *bool) *Telemetry {
	return &Telemetry{
		userId:   "ksctl:cli",
		endpoint: "https://telemetry.ksctl.com",
		ksctlVer: config.Version,
		active:   active == nil || *active,
		os:       runtime.GOOS,
		arch:     runtime.GOARCH,
	}
}

func IntegrityCheck() {
	if config.InDevMode() {
		return
	}

	if len(config.Version) == 0 {
		color.New(color.BgHiRed, color.FgHiBlack).Println("corrupted version")
		os.Exit(2)
	}

	if len(clientIdentity) == 0 {
		color.New(color.BgHiRed, color.FgHiBlack).Println("corrupted cli identity")
		os.Exit(2)
	}

	if len(config.KsctlCoreVer) == 0 {
		color.New(color.BgHiRed, color.FgHiBlack).Println("corrupted core version")
		os.Exit(2)
	}

	if len(config.BuildDate) == 0 {
		color.New(color.BgHiRed, color.FgHiBlack).Println("corrupted build date")
		os.Exit(2)
	}
}

func (t *Telemetry) Send(ctx context.Context, l logger.Logger, event TelemetryEvent, data TelemetryMeta) error {
	if !t.active {
		return nil
	}

	telemetryData := TelemetryData{
		ClientIdentity: clientIdentity,
		UserId:         t.userId,
		KsctlVer:       t.ksctlVer,
		Event:          event,
		Data:           data,
		OS:             t.os,
		Arch:           t.arch,
	}

	if config.InDevMode() {
		return nil
	}

	payloadBuf := new(bytes.Buffer)

	if err := json.NewEncoder(payloadBuf).Encode(telemetryData); err != nil {
		return err
	}

	if res, err := http.Post(t.endpoint, "application/json", payloadBuf); err != nil {
		return err
	} else {
		if res.StatusCode != http.StatusOK {
			return fmt.Errorf("failed to send telemetry, status code: %d", res.StatusCode)
		}

		l.Debug(ctx, "Telemetry sent successfully")

		return nil
	}
}
07070100000038000041ED0000000000000000000000026818E78D00000000000000000000000000000000000000000000001400000000ksctl-2.8.0/scripts07070100000039000081ED0000000000000000000000016818E78D000000D9000000000000000000000000000000000000001F00000000ksctl-2.8.0/scripts/builder.sh#!/bin/bash

cd .. || echo -e "\033[1;31mUnable to cd into ksctl root\033[0m\n"

go mod tidy
go build -v -o ksctl .
chmod +x ksctl

sudo mv -v ksctl /usr/local/bin/ksctl

echo -e "\033[1;32mINSTALL COMPLETE\033[0m\n"
0707010000003A000081A40000000000000000000000016818E78D00000A33000000000000000000000000000000000000002000000000ksctl-2.8.0/scripts/install.ps1#Requires -Version 5

$erroractionpreference = 'stop' # quit if anything goes wrong

if (($PSVersionTable.PSVersion.Major) -lt 5) {
    Write-Output "PowerShell 5 or later is required to run Ksctl."
    Write-Output "Upgrade PowerShell: https://docs.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell"
    break
}

Write-Host "Welcome to Installation" -ForegroundColor DarkGreen


Write-Host "Available Releases"  -ForegroundColor Cyan

$response = Invoke-RestMethod "https://api.github.com/repos/ksctl/cli/releases"
# get the release version

foreach ($release in $response.tag_name) {
    Write-Host "${release}" -ForegroundColor Cyan
}
$ReleaseVersion= Read-Host -Prompt "Enter the ksctl version to install"
$Arch= Read-Host -Prompt "Enter [1] for amd64 or x86_64 and [0] for arm64"

Set-Location $env:USERPROFILE

if ($Arch -eq 1) {
  $Arch="amd64"
} elseif ($Arch -eq 0) {
  $Arch="arm64"
} else {
  Write-Host "Invalid Arch" -ForegroundColor Red
  Exit 1
}

Invoke-WebRequest -Uri https://github.com/ksctl/cli/releases/download/v${ReleaseVersion}/ksctl-cli_${ReleaseVersion}_checksums.txt -OutFile ksctl_${ReleaseVersion}_checksums.txt
Invoke-WebRequest -Uri https://github.com/ksctl/cli/releases/download/v${ReleaseVersion}/ksctl-cli_${ReleaseVersion}_windows_${Arch}.tar.gz -OutFile ksctl_${ReleaseVersion}_windows_${Arch}.tar.gz
Invoke-WebRequest -Uri https://github.com/ksctl/cli/releases/download/v${ReleaseVersion}/ksctl-cli_${ReleaseVersion}_windows_${Arch}.tar.gz.cert -OutFile ksctl_${ReleaseVersion}_windows_${Arch}.tar.gz.cert

# TODO: Add the checksum verification
# file=$(sha256sum ksctl_${RELEASE_VERSION}_${OS}_${ARCH}.tar.gz | awk '{print $1}')
# checksum=$(cat ksctl_${RELEASE_VERSION}_checksums.txt | grep ksctl_${RELEASE_VERSION}_${OS}_${ARCH}.tar.gz | awk '{print $1}')

# if [[ $file != $checksum ]]; then
#   echo -e "${Red}Checksum didn't matched!${NoColor}"
#   exit 1
# else
#   echo -e "${Green}CheckSum are verified${NoColor}"
# fi

tar -xvf ksctl_${ReleaseVersion}_windows_${Arch}.tar.gz


$localAppDataPath = $env:LOCALAPPDATA
$ksctl = Join-Path "$localAppDataPath" 'ksctl'

Write-Information "Path of AppDataPath $ksctl"

New-Item -ItemType Directory -Force -Path $ksctl | Out-Null

Copy-Item ksctl.exe -Destination "$ksctl/" -Force | Out-Null

Remove-Item ksctl*


Write-Host "[V] Finished Installation" -ForegroundColor DarkGreen
Write-Host ""
Write-Host "To run ksctl globally, please follow these steps:" -ForegroundColor Cyan
Write-Host ""
Write-Host "    1. Run the following command as administrator: ``setx PATH `"`$env:path;$ksctl`" -m``"
0707010000003B000081ED0000000000000000000000016818E78D0000106E000000000000000000000000000000000000001F00000000ksctl-2.8.0/scripts/install.sh#!/usr/bin/env python3

import os
import platform
import subprocess
import urllib.request
import hashlib
import tarfile
import shutil
import json

class Colors:
    Red = '\033[1;31m'
    Green = '\033[1;32m'
    Blue = '\033[1;34m'
    Yellow = '\033[1;33m'
    NoColor = '\033[0m'

def print_colored(message, color):
    print(f"{color}{message}{Colors.NoColor}")

def get_latest_release():
    url = "https://api.github.com/repos/ksctl/cli/releases/latest"
    with urllib.request.urlopen(url) as response:
        data = response.read()
        release_info = json.loads(data)
        return release_info["tag_name"]

def download_file(url, local_filename):
    print_colored(f"Downloading {url} to {local_filename}", Colors.Blue)
    try:
        with urllib.request.urlopen(url) as response:
            with open(local_filename, 'wb') as out_file:
                shutil.copyfileobj(response, out_file)
    except urllib.error.HTTPError as e:
        print_colored(f"HTTP Error: {e.code} - {e.reason}", Colors.Red)
        exit(1)
    except urllib.error.URLError as e:
        print_colored(f"URL Error: {e.reason}", Colors.Red)
        exit(1)

def verify_checksum(file_path, expected_checksum):
    sha256_hash = hashlib.sha256()
    with open(file_path, "rb") as f:
        for byte_block in iter(lambda: f.read(4096), b""):
            sha256_hash.update(byte_block)
    calculated_checksum = sha256_hash.hexdigest()
    return calculated_checksum == expected_checksum

def main():
    print_colored("All necessary dependencies are present.", Colors.Green)

    ksctl_version = os.getenv("KSCTL_VERSION")
    if not ksctl_version:
        print_colored("Fetching latest release version...", Colors.Blue)
        ksctl_version = get_latest_release()
    print_colored(f"Using version: {ksctl_version}", Colors.Green)

    os_name = platform.system()
    arch = platform.machine()

    if arch == "x86_64":
        arch = "amd64"
    elif arch == "arm64":
        arch = "arm64"
    else:
        print_colored(f"Unsupported architecture: {arch}", Colors.Red)
        exit(1)

    if os_name not in ["Linux", "Darwin"]:
        print_colored(f"Unsupported OS: {os_name}", Colors.Red)
        exit(1)

    os_name = os_name.lower()
    print_colored(f"Detected OS: {os_name}, Architecture: {arch}", Colors.Green)

    print_colored("Downloading files...", Colors.Blue)
    download_url_base = f"https://github.com/ksctl/cli/releases/download/{ksctl_version}"
    tar_file = f"ksctl-cli_{ksctl_version[1:]}_{os_name}_{arch}.tar.gz"
    checksum_file = f"ksctl-cli_{ksctl_version[1:]}_checksums.txt"
    download_file(f"{download_url_base}/{tar_file}", tar_file)
    download_file(f"{download_url_base}/{checksum_file}", checksum_file)

    print_colored("Verifying checksum...", Colors.Blue)
    with open(checksum_file, 'r') as f:
        checksums = f.readlines()
    expected_checksum = [line.split()[0] for line in checksums if tar_file in line][0]

    if not verify_checksum(tar_file, expected_checksum):
        print_colored("Checksum verification failed!", Colors.Red)
        exit(1)
    print_colored("Checksum verification passed.", Colors.Green)

    print_colored("Installing ksctl...", Colors.Blue)

    temp_dir = "/tmp/ksctl"
    os.makedirs(temp_dir, exist_ok=True)

    try:
        with tarfile.open(tar_file, "r:gz") as tar:
            tar.extractall(temp_dir)

        ksctl_binary = os.path.join(temp_dir, "ksctl")
        if not os.path.isfile(ksctl_binary):
            print_colored(f"ksctl binary not found in the tarball", Colors.Red)
            exit(1)

        print_colored("Moving ksctl to /usr/local/bin (requires sudo)...", Colors.Blue)
        subprocess.run(["sudo", "mv", "-v", ksctl_binary, "/usr/local/bin/ksctl"])

        if shutil.which("ksctl"):
            print_colored("INSTALL COMPLETE!", Colors.Green)
        else:
            print_colored("Installation failed. Please check the output for errors.", Colors.Red)
            exit(1)
    finally:
        print_colored("Cleaning up temporary files...", Colors.Blue)
        shutil.rmtree(temp_dir)
        os.remove(tar_file)
        os.remove(checksum_file)

if __name__ == "__main__":
    main()
0707010000003C000081A40000000000000000000000016818E78D000002CA000000000000000000000000000000000000002200000000ksctl-2.8.0/scripts/uninstall.ps1#Requires -Version 5

$old_erroractionpreference = $erroractionpreference
$erroractionpreference = 'stop' # quit if anything goes wrong

if (($PSVersionTable.PSVersion.Major) -lt 5) {
    Write-Output "PowerShell 5 or later is required to run Ksctl."
    Write-Output "Upgrade PowerShell: https://docs.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell"
    break
}

Write-Host "Sorry to see you go" -ForegroundColor DarkGreen

$localAppDataPath = $env:LOCALAPPDATA
$ksctl = Join-Path "$localAppDataPath" 'ksctl'

Remove-Item -Force $ksctl | Out-Null
Remove-Item -Force $env:USERPROFILE\.ksctl | Out-Null

Write-Host "[V] Finished Uninstallation" -ForegroundColor DarkGreen
Write-Host ""
0707010000003D000081ED0000000000000000000000016818E78D0000005F000000000000000000000000000000000000002100000000ksctl-2.8.0/scripts/uninstall.sh#!/bin/bash

sudo rm -vf /usr/local/bin/ksctl

echo -e "\033[1;32mUNINSTALL COMPLETE\033[0m\n"
07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!637 blocks
openSUSE Build Service is sponsored by