diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 9866022c..d1df856b 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -55,53 +55,28 @@ jobs: CGO_ENABLED: 1 run: python3 --version && python3 build.py - - name: Upload release binaries (Windows / MacOS) + - name: Upload release assets (Windows / MacOS) id: upload-release-asset-win-macos - uses: actions/upload-release-asset@v1 + uses: shogo82148/actions-upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ needs.create-release.outputs.upload_url }} - asset_path: build/${{ matrix.os }}/kubescape - asset_name: kubescape-${{ matrix.os }} - asset_content_type: application/octet-stream + asset_path: build/${{ matrix.os }}/* if: matrix.os != 'ubuntu-20.04' - - name: Upload release binaries (Linux) + - name: Upload release assets (Linux) id: upload-release-asset-linux - uses: actions/upload-release-asset@v1 + uses: shogo82148/actions-upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ needs.create-release.outputs.upload_url }} - asset_path: build/ubuntu-latest/kubescape - asset_name: kubescape-ubuntu-latest - asset_content_type: application/octet-stream + asset_path: build/ubuntu-latest/* if: matrix.os == 'ubuntu-20.04' - - name: Upload release hash (Windows / MacOS) - id: upload-release-hash-win-macos - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ needs.create-release.outputs.upload_url }} - asset_path: build/${{ matrix.os }}/kubescape.sha256 - asset_name: kubescape-${{ matrix.os }}-sha256 - asset_content_type: application/octet-stream - if: matrix.os != 'ubuntu-20.04' - - - name: Upload release hash (Linux) - id: upload-release-hash-linux - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ needs.create-release.outputs.upload_url }} - asset_path: build/ubuntu-latest/kubescape.sha256 - asset_name: kubescape-ubuntu-latest-sha256 - asset_content_type: application/octet-stream - if: matrix.os == 'ubuntu-20.04' + # - name: Update new version in krew-index + # uses: rajatjindal/krew-release-bot@v0.0.43 publish-image: uses: ./.github/workflows/build-image.yaml diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 9129adea..c8216d00 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -89,12 +89,12 @@ jobs: env: RELEASE: ${{ inputs.release }} KUBESCAPE_SKIP_UPDATE_CHECK: "true" - run: python3 smoke_testing/init.py ${PWD}/build/${{ matrix.os }}/kubescape + run: python3 smoke_testing/init.py ${PWD}/build/${{ matrix.os }}/kubescape-${{ matrix.os }} if: matrix.os != 'ubuntu-20.04' - name: Smoke Testing (Linux) env: RELEASE: ${{ inputs.release }} KUBESCAPE_SKIP_UPDATE_CHECK: "true" - run: python3 smoke_testing/init.py ${PWD}/build/ubuntu-latest/kubescape + run: python3 smoke_testing/init.py ${PWD}/build/ubuntu-latest/kubescape-ubuntu-latest if: matrix.os == 'ubuntu-20.04' diff --git a/.krew.yaml b/.krew.yaml new file mode 100644 index 00000000..153dc275 --- /dev/null +++ b/.krew.yaml @@ -0,0 +1,36 @@ +apiVersion: krew.googlecontainertools.github.com/v1alpha2 +kind: Plugin +metadata: + name: kubescape +spec: + homepage: https://www.armosec.io/kubescape/ + shortDescription: An open-source Kubernetes security platform for your IDE, CI/CD pipelines, and clusters + version: {{ .TagName }} + description: | + Kubescape is an open-source Kubernetes security platform. + It includes risk analysis, security compliance, and misconfiguration scanning. + Targeted at the DevSecOps practitioner or platform engineer, + it offers an easy-to-use CLI interface, flexible output formats, and automated scanning capabilities. + It saves Kubernetes users and admins precious time, effort, and resources. + + Kubescape was created by [ARMO](https://www.armosec.io/?utm_source=github&utm_medium=repository) + and is a [Cloud Native Computing Foundation (CNCF) sandbox project](https://www.cncf.io/sandbox-projects/). + platforms: + - selector: + matchLabels: + os: darwin + arch: amd64 + {{ addURIAndSha "https://github.com/kubescape/kubescape/releases/download/{{ .TagName }}/kubescape-macos-latest" .TagName }} + bin: kubectl-kubescape + - selector: + matchLabels: + os: linux + arch: amd64 + {{ addURIAndSha "https://github.com/kubescape/kubescape/releases/download/{{ .TagName }}/kubescape-ubuntu-latest" .TagName }} + bin: kubectl-kubescape + - selector: + matchLabels: + os: windows + arch: amd64 + {{ addURIAndSha "https://github.com/kubescape/kubescape/releases/download/{{ .TagName }}/kubescape-windows-latest" .TagName }} + bin: kubectl-kubescape.exe diff --git a/build.py b/build.py index f2f0ade5..b4dd7601 100644 --- a/build.py +++ b/build.py @@ -3,9 +3,16 @@ import sys import hashlib import platform import subprocess +import tarfile BASE_GETTER_CONST = "github.com/kubescape/kubescape/v2/core/cautils/getter" +platformSuffixes = { + "Windows": "windows-latest", + "Linux": "ubuntu-latest", + "Darwin": "macos-latest", +} + def check_status(status, msg): if status != 0: sys.stderr.write(msg) @@ -14,20 +21,18 @@ def check_status(status, msg): def get_build_dir(): current_platform = platform.system() - build_dir = "" - if current_platform == "Windows": build_dir = "windows-latest" - elif current_platform == "Linux": build_dir = "ubuntu-latest" - elif current_platform == "Darwin": build_dir = "macos-latest" - else: raise OSError("Platform %s is not supported!" % (current_platform)) + if current_platform not in platformSuffixes: raise OSError("Platform %s is not supported!" % (current_platform)) - return os.path.join("build", build_dir) + return os.path.join("build", platformSuffixes[current_platform]) def get_package_name(): - package_name = "kubescape" + current_platform = platform.system() - return package_name + if current_platform not in platformSuffixes: raise OSError("Platform %s is not supported!" % (current_platform)) + + return "kubescape-" + platformSuffixes[current_platform] def main(): @@ -46,6 +51,7 @@ def main(): ks_file = os.path.join(build_dir, package_name) hash_file = ks_file + ".sha256" + tar_file = ks_file + ".tar.gz" if not os.path.isdir(build_dir): os.makedirs(build_dir) @@ -73,6 +79,9 @@ def main(): print("kubescape hash: {}, file: {}".format(hash, hash_file)) kube_sha.write(sha256.hexdigest()) + with tarfile.open(tar_file, 'w:gz') as archive: + archive.add(ks_file, "kubescape") + print("Build Done") diff --git a/build/Dockerfile b/build/Dockerfile index db5ac948..47dd43ce 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -31,7 +31,7 @@ RUN ls -ltr build/ubuntu-latest WORKDIR /work RUN python build.py -RUN /work/build/ubuntu-latest/kubescape download artifacts -o /work/artifacts +RUN /work/build/ubuntu-latest/kubescape-ubuntu-latest download artifacts -o /work/artifacts FROM alpine:3.16.2 @@ -45,7 +45,7 @@ USER ks WORKDIR /home/ks -COPY --from=builder /work/httphandler/build/ubuntu-latest/kubescape /usr/bin/ksserver -COPY --from=builder /work/build/ubuntu-latest/kubescape /usr/bin/kubescape +COPY --from=builder /work/httphandler/build/ubuntu-latest/kubescape-ubuntu-latest /usr/bin/ksserver +COPY --from=builder /work/build/ubuntu-latest/kubescape-ubuntu-latest /usr/bin/kubescape ENTRYPOINT ["ksserver"] diff --git a/cmd/completion/completion.go b/cmd/completion/completion.go index 453cb12b..5177ca64 100644 --- a/cmd/completion/completion.go +++ b/cmd/completion/completion.go @@ -1,23 +1,23 @@ package completion import ( + "fmt" "os" "strings" + "github.com/kubescape/kubescape/v2/core/cautils" "github.com/spf13/cobra" ) -var completionCmdExamples = ` - +var completionCmdExamples = fmt.Sprintf(` # Enable BASH shell autocompletion - $ source <(kubescape completion bash) - $ echo 'source <(kubescape completion bash)' >> ~/.bashrc + $ source <(%[1]s completion bash) + $ echo 'source <(%[1]s completion bash)' >> ~/.bashrc # Enable ZSH shell autocompletion $ source <(kubectl completion zsh) $ echo 'source <(kubectl completion zsh)' >> "${fpath[1]}/_kubectl" - -` +`, cautils.ExecName()) func GetCompletionCmd() *cobra.Command { completionCmd := &cobra.Command{ diff --git a/cmd/config/config.go b/cmd/config/config.go index 4fc4bba2..5f276ec7 100644 --- a/cmd/config/config.go +++ b/cmd/config/config.go @@ -1,34 +1,37 @@ package config import ( + "fmt" + + "github.com/kubescape/kubescape/v2/core/cautils" "github.com/kubescape/kubescape/v2/core/meta" "github.com/spf13/cobra" ) var ( - configExample = ` + configExample = fmt.Sprintf(` # View cached configurations - kubescape config view + %[1]s config view # Delete cached configurations - kubescape config delete + %[1]s config delete # Set cached configurations - kubescape config set --help -` - setConfigExample = ` + %[1]s config set --help +`, cautils.ExecName()) + setConfigExample = fmt.Sprintf(` # Set account id - kubescape config set accountID + %[1]s config set accountID # Set client id - kubescape config set clientID + %[1]s config set clientID # Set access key - kubescape config set secretKey + %[1]s config set secretKey # Set cloudAPIURL - kubescape config set cloudAPIURL -` + %[1]s config set cloudAPIURL +`, cautils.ExecName()) ) func GetConfigCmd(ks meta.IKubescape) *cobra.Command { diff --git a/cmd/delete/delete.go b/cmd/delete/delete.go index 1967889c..d3af0746 100644 --- a/cmd/delete/delete.go +++ b/cmd/delete/delete.go @@ -1,18 +1,21 @@ package delete import ( + "fmt" + + "github.com/kubescape/kubescape/v2/core/cautils" "github.com/kubescape/kubescape/v2/core/meta" v1 "github.com/kubescape/kubescape/v2/core/meta/datastructures/v1" "github.com/spf13/cobra" ) -var deleteExceptionsExamples = ` +var deleteExceptionsExamples = fmt.Sprintf(` # Delete single exception - kubescape delete exceptions "exception name" + %[1]s delete exceptions "exception name" # Delete multiple exceptions - kubescape delete exceptions "first exception;second exception;third exception" -` + %[1]s delete exceptions "first exception;second exception;third exception" +`, cautils.ExecName()) func GetDeleteCmd(ks meta.IKubescape) *cobra.Command { var deleteInfo v1.Delete diff --git a/cmd/delete/exceptions.go b/cmd/delete/exceptions.go index ce16fbd3..f4fe0477 100644 --- a/cmd/delete/exceptions.go +++ b/cmd/delete/exceptions.go @@ -5,6 +5,7 @@ import ( "strings" logger "github.com/kubescape/go-logger" + "github.com/kubescape/kubescape/v2/core/cautils" "github.com/kubescape/kubescape/v2/core/meta" v1 "github.com/kubescape/kubescape/v2/core/meta/datastructures/v1" "github.com/spf13/cobra" @@ -13,7 +14,7 @@ import ( func getExceptionsCmd(ks meta.IKubescape, deleteInfo *v1.Delete) *cobra.Command { return &cobra.Command{ Use: "exceptions ", - Short: "Delete exceptions from Kubescape SaaS version. Run 'kubescape list exceptions' for all exceptions names", + Short: fmt.Sprintf("Delete exceptions from Kubescape SaaS version. Run '%[1]s list exceptions' for all exceptions names", cautils.ExecName()), Example: deleteExceptionsExamples, Args: func(cmd *cobra.Command, args []string) error { if len(args) != 1 { diff --git a/cmd/download/download.go b/cmd/download/download.go index 3c1519ec..fd5f3603 100644 --- a/cmd/download/download.go +++ b/cmd/download/download.go @@ -14,31 +14,31 @@ import ( ) var ( - downloadExample = ` + downloadExample = fmt.Sprintf(` # Download all artifacts and save them in the default path (~/.kubescape) - kubescape download artifacts + %[1]s download artifacts # Download all artifacts and save them in /tmp path - kubescape download artifacts --output /tmp + %[1]s download artifacts --output /tmp - # Download the NSA framework. Run 'kubescape list frameworks' for all frameworks names - kubescape download framework nsa + # Download the NSA framework. Run '%[1]s list frameworks' for all frameworks names + %[1]s download framework nsa - # Download the "C-0001" control. Run 'kubescape list controls --id' for all controls ids - kubescape download control "C-0001" + # Download the "C-0001" control. Run '%[1]s list controls --id' for all controls ids + %[1]s download control "C-0001" - # Download the "C-0001" control. Run 'kubescape list controls --id' for all controls ids - kubescape download control C-0001 + # Download the "C-0001" control. Run '%[1]s list controls --id' for all controls ids + %[1]s download control C-0001 # Download the configured exceptions - kubescape download exceptions + %[1]s download exceptions # Download the configured controls-inputs - kubescape download controls-inputs + %[1]s download controls-inputs # Download the attack tracks - kubescape download attack-tracks -` + %[1]s download attack-tracks +`, cautils.ExecName()) ) func GeDownloadCmd(ks meta.IKubescape) *cobra.Command { diff --git a/cmd/list/list.go b/cmd/list/list.go index 689481c2..49934714 100644 --- a/cmd/list/list.go +++ b/cmd/list/list.go @@ -13,19 +13,19 @@ import ( ) var ( - listExample = ` + listExample = fmt.Sprintf(` # List default supported frameworks names - kubescape list frameworks + %[1]s list frameworks # List all supported frameworks names - kubescape list frameworks --account + %[1]s list frameworks --account # List all supported controls names with ids - kubescape list controls + %[1]s list controls Control documentation: https://hub.armosec.io/docs/controls -` +`, cautils.ExecName()) ) func GetListCmd(ks meta.IKubescape) *cobra.Command { @@ -65,7 +65,7 @@ func GetListCmd(ks meta.IKubescape) *cobra.Command { listCmd.PersistentFlags().StringVarP(&listPolicies.Credentials.ClientID, "client-id", "", "", "Kubescape SaaS client ID. Default will load client ID from cache, read more - https://hub.armosec.io/docs/authentication") listCmd.PersistentFlags().StringVarP(&listPolicies.Credentials.SecretKey, "secret-key", "", "", "Kubescape SaaS secret key. Default will load secret key from cache, read more - https://hub.armosec.io/docs/authentication") listCmd.PersistentFlags().StringVar(&listPolicies.Format, "format", "pretty-print", "output format. supported: 'pretty-print'/'json'") - listCmd.PersistentFlags().MarkDeprecated("id", "Control ID's are included in list outpus") + listCmd.PersistentFlags().MarkDeprecated("id", "Control ID's are included in list outputs") return listCmd } diff --git a/cmd/root.go b/cmd/root.go index bcd3d671..2da408de 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -25,19 +25,19 @@ import ( var rootInfo cautils.RootInfo -var ksExamples = ` +var ksExamples = fmt.Sprintf(` # Scan command - kubescape scan + %[1]s scan # List supported frameworks - kubescape list frameworks + %[1]s list frameworks # Download artifacts (air-gapped environment support) - kubescape download artifacts + %[1]s download artifacts # View cached configurations - kubescape config view -` + %[1]s config view +`, cautils.ExecName()) func NewDefaultKubescapeCommand() *cobra.Command { ks := core.NewKubescape() @@ -52,6 +52,16 @@ func getRootCmd(ks meta.IKubescape) *cobra.Command { Example: ksExamples, } + if cautils.IsKrewPlugin() { + // Invoked as a kubectl plugin. + + // Cobra doesn't have a way to specify a two word command (i.e. "kubectl kubescape"), so set a custom usage template + // with kubectl in it. Cobra will use this template for the root and all child commands. + oldUsageTemplate := rootCmd.UsageTemplate() + newUsageTemplate := strings.NewReplacer("{{.UseLine}}", "kubectl {{.UseLine}}", "{{.CommandPath}}", "kubectl {{.CommandPath}}").Replace(oldUsageTemplate) + rootCmd.SetUsageTemplate(newUsageTemplate) + } + rootCmd.PersistentFlags().StringVar(&rootInfo.KSCloudBEURLsDep, "environment", "", envFlagUsage) rootCmd.PersistentFlags().StringVar(&rootInfo.KSCloudBEURLs, "env", "", envFlagUsage) rootCmd.PersistentFlags().MarkDeprecated("environment", "use 'env' instead") diff --git a/cmd/scan/control.go b/cmd/scan/control.go index 19ca7447..845516ed 100644 --- a/cmd/scan/control.go +++ b/cmd/scan/control.go @@ -18,28 +18,28 @@ import ( ) var ( - controlExample = ` + controlExample = fmt.Sprintf(` # Scan the 'privileged container' control - kubescape scan control "privileged container" + %[1]s scan control "privileged container" # Scan list of controls separated with a comma - kubescape scan control "privileged container","HostPath mount" + %[1]s scan control "privileged container","HostPath mount" # Scan list of controls using the control ID separated with a comma - kubescape scan control C-0058,C-0057 + %[1]s scan control C-0058,C-0057 - Run 'kubescape list controls' for the list of supported controls + Run '%[1]s list controls' for the list of supported controls Control documentation: https://hub.armosec.io/docs/controls -` +`, cautils.ExecName()) ) // controlCmd represents the control command func getControlCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Command { return &cobra.Command{ Use: "control /", - Short: "The controls you wish to use. Run 'kubescape list controls' for the list of supported controls", + Short: fmt.Sprintf("The controls you wish to use. Run '%[1]s list controls' for the list of supported controls", cautils.ExecName()), Example: controlExample, Args: func(cmd *cobra.Command, args []string) error { if len(args) > 0 { @@ -67,7 +67,7 @@ func getControlCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comman if len(args) == 0 { scanInfo.ScanAll = true - } else { // expected control or list of control sepparated by "," + } else { // expected control or list of control separated by "," // Read controls from input args scanInfo.SetPolicyIdentifiers(strings.Split(args[0], ","), apisv1.KindControl) diff --git a/cmd/scan/framework.go b/cmd/scan/framework.go index ba11a3ff..f2d8a3fd 100644 --- a/cmd/scan/framework.go +++ b/cmd/scan/framework.go @@ -20,24 +20,24 @@ import ( ) var ( - frameworkExample = ` + frameworkExample = fmt.Sprintf(` # Scan all frameworks - kubescape scan framework all + %[1]s scan framework all # Scan the NSA framework - kubescape scan framework nsa + %[1]s scan framework nsa # Scan the NSA and MITRE framework - kubescape scan framework nsa,mitre + %[1]s scan framework nsa,mitre # Scan all frameworks - kubescape scan framework all + %[1]s scan framework all # Scan kubernetes YAML manifest files (single file or glob) - kubescape scan framework nsa . + %[1]s scan framework nsa . - Run 'kubescape list frameworks' for the list of supported frameworks -` + Run '%[1]s list frameworks' for the list of supported frameworks +`, cautils.ExecName()) ErrUnknownSeverity = errors.New("unknown severity") ) @@ -46,7 +46,7 @@ func getFrameworkCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comm return &cobra.Command{ Use: "framework [``/`-`] [flags]", - Short: "The framework you wish to use. Run 'kubescape list frameworks' for the list of supported frameworks", + Short: fmt.Sprintf("The framework you wish to use. Run '%[1]s list frameworks' for the list of supported frameworks", cautils.ExecName()), Example: frameworkExample, Long: "Execute a scan on a running Kubernetes cluster or `yaml`/`json` files (use glob) or `-` for stdin", Args: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/scan/scan.go b/cmd/scan/scan.go index ac87f2e7..411607c0 100644 --- a/cmd/scan/scan.go +++ b/cmd/scan/scan.go @@ -10,25 +10,24 @@ import ( "github.com/spf13/cobra" ) -var scanCmdExamples = ` +var scanCmdExamples = fmt.Sprintf(` Scan command is for scanning an existing cluster or kubernetes manifest files based on pre-defined frameworks # Scan current cluster with all frameworks - kubescape scan --enable-host-scan --verbose + %[1]s scan --enable-host-scan --verbose # Scan kubernetes YAML manifest files - kubescape scan . + %[1]s scan . # Scan and save the results in the JSON format - kubescape scan --format json --output results.json --format-version=v2 + %[1]s scan --format json --output results.json --format-version=v2 # Display all resources - kubescape scan --verbose + %[1]s scan --verbose # Scan different clusters from the kubectl context - kubescape scan --kube-context - -` + %[1]s scan --kube-context +`, cautils.ExecName()) func GetScanCommand(ks meta.IKubescape) *cobra.Command { var scanInfo cautils.ScanInfo diff --git a/cmd/submit/rbac.go b/cmd/submit/rbac.go index 4bb5e085..8fca1ef7 100644 --- a/cmd/submit/rbac.go +++ b/cmd/submit/rbac.go @@ -19,13 +19,13 @@ import ( ) var ( - rbacExamples = ` + rbacExamples = fmt.Sprintf(` # Submit cluster's Role-Based Access Control(RBAC) - kubescape submit rbac + %[1]s submit rbac # Submit cluster's Role-Based Access Control(RBAC) with account ID - kubescape submit rbac --account - ` + %[1]s submit rbac --account + `, cautils.ExecName()) ) // getRBACCmd represents the RBAC command @@ -36,7 +36,7 @@ func getRBACCmd(ks meta.IKubescape, submitInfo *v1.Submit) *cobra.Command { Example: rbacExamples, Short: "Submit cluster's Role-Based Access Control(RBAC)", Long: ``, - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(_ *cobra.Command, args []string) error { if err := flagValidationSubmit(submitInfo); err != nil { return err @@ -51,7 +51,7 @@ func getRBACCmd(ks meta.IKubescape, submitInfo *v1.Submit) *cobra.Command { } if clusterConfig.GetAccountID() == "" { - return fmt.Errorf("account ID is not set, run 'kubescape submit rbac --account '") + return fmt.Errorf("account ID is not set, run '%[1]s submit rbac --account '", cautils.ExecName()) } // list RBAC diff --git a/cmd/submit/results.go b/cmd/submit/results.go index 2872556b..fa98bc02 100644 --- a/cmd/submit/results.go +++ b/cmd/submit/results.go @@ -6,6 +6,7 @@ import ( "os" "github.com/google/uuid" + "github.com/kubescape/kubescape/v2/core/cautils" reporthandlingv2 "github.com/kubescape/opa-utils/reporthandling/v2" logger "github.com/kubescape/go-logger" @@ -50,7 +51,7 @@ func (resultsObject *ResultsObject) ListAllResources() (map[string]workloadinter func getResultsCmd(ks meta.IKubescape, submitInfo *v1.Submit) *cobra.Command { var resultsCmd = &cobra.Command{ - Use: "results \nExample:\n$ kubescape submit results path/to/results.json --format-version v2", + Use: fmt.Sprintf("results \nExample:\n$ %[1]s submit results path/to/results.json --format-version v2", cautils.ExecName()), Short: "Submit a pre scanned results file. The file must be in json format", Long: ``, RunE: func(cmd *cobra.Command, args []string) error { @@ -87,7 +88,7 @@ func getResultsCmd(ks meta.IKubescape, submitInfo *v1.Submit) *cobra.Command { return nil }, } - resultsCmd.PersistentFlags().StringVar(&formatVersion, "format-version", "v1", "Output object can be differnet between versions, this is for maintaining backward and forward compatibility. Supported:'v1'/'v2'") + resultsCmd.PersistentFlags().StringVar(&formatVersion, "format-version", "v1", "Output object can be different between versions, this is for maintaining backward and forward compatibility. Supported:'v1'/'v2'") return resultsCmd } diff --git a/cmd/submit/submit.go b/cmd/submit/submit.go index c05caf52..59d048b8 100644 --- a/cmd/submit/submit.go +++ b/cmd/submit/submit.go @@ -1,18 +1,21 @@ package submit import ( + "fmt" + + "github.com/kubescape/kubescape/v2/core/cautils" "github.com/kubescape/kubescape/v2/core/meta" metav1 "github.com/kubescape/kubescape/v2/core/meta/datastructures/v1" "github.com/spf13/cobra" ) -var submitCmdExamples = ` +var submitCmdExamples = fmt.Sprintf(` # Submit Kubescape scan results file -kubescape submit results +%[1]s submit results # Submit exceptions file to Kubescape SaaS -kubescape submit exceptions -` +%[1]s submit exceptions +`, cautils.ExecName()) func GetSubmitCmd(ks meta.IKubescape) *cobra.Command { var submitInfo metav1.Submit diff --git a/core/cautils/krewutils.go b/core/cautils/krewutils.go new file mode 100644 index 00000000..729dc4f4 --- /dev/null +++ b/core/cautils/krewutils.go @@ -0,0 +1,20 @@ +package cautils + +import ( + "os" + "path/filepath" + "strings" +) + +// ExecName returns the correct name to use in examples depending on how kubescape is invoked +func ExecName() string { + n := "kubescape" + if IsKrewPlugin() { + return "kubectl " + n + } + return n +} + +func IsKrewPlugin() bool { + return strings.HasPrefix(filepath.Base(os.Args[0]), "kubectl-") +}