Help > Usage, Naming, Markdown Help, Spelling, File name Sanitization

This commit is contained in:
luke-hagar-sp
2023-08-04 16:01:26 -05:00
parent a75043ad8f
commit b2f330fd48
65 changed files with 683 additions and 412 deletions

1
.gitignore vendored
View File

@@ -6,6 +6,7 @@ transform_files
search_results search_results
spconfig-exports spconfig-exports
reports reports
workflows
# CLI binary # CLI binary
sailpoint-cli sailpoint-cli

View File

@@ -20,7 +20,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func NewReportCmd() *cobra.Command { func NewReportCommand() *cobra.Command {
var save bool var save bool
var folderPath string var folderPath string
var template string var template string
@@ -70,10 +70,10 @@ func NewReportCmd() *cobra.Command {
log.Warn("multiple template matches, the first match will be used", "template", template) log.Warn("multiple template matches, the first match will be used", "template", template)
} }
selectedTemplate = matches[0] selectedTemplate = matches[0]
varCount := len(selectedTemplate.Variables)
if varCount > 0 { if len(selectedTemplate.Variables) > 0 {
for i := 0; i < varCount; i++ { for _, varEntry := range selectedTemplate.Variables {
varEntry := selectedTemplate.Variables[i]
resp := terminal.InputPrompt("Input " + varEntry.Prompt + ":") resp := terminal.InputPrompt("Input " + varEntry.Prompt + ":")
selectedTemplate.Raw = []byte(strings.ReplaceAll(string(selectedTemplate.Raw), "{{"+varEntry.Name+"}}", resp)) selectedTemplate.Raw = []byte(strings.ReplaceAll(string(selectedTemplate.Raw), "{{"+varEntry.Name+"}}", resp))
} }
@@ -83,9 +83,7 @@ func NewReportCmd() *cobra.Command {
} }
} }
for i := 0; i < len(selectedTemplate.Queries); i++ { for i, currentQuery := range selectedTemplate.Queries {
currentQuery := selectedTemplate.Queries[i]
searchQuery := v3.NewSearch() searchQuery := v3.NewSearch()
query := v3.NewQuery() query := v3.NewQuery()
@@ -100,11 +98,6 @@ func NewReportCmd() *cobra.Command {
selectedTemplate.Queries[i].ResultCount = resp.Header["X-Total-Count"][0] selectedTemplate.Queries[i].ResultCount = resp.Header["X-Total-Count"][0]
} }
// for i := 0; i < len(selectedTemplate.Queries); i++ {
// currentQuery := selectedTemplate.Queries[i]
// fmt.Println(currentQuery.QueryTitle + ": " + currentQuery.ResultCount)
// }
if save { if save {
fileName := selectedTemplate.Name + ".json" fileName := selectedTemplate.Name + ".json"
err := output.SaveJSONFile(selectedTemplate.Queries, fileName, folderPath) err := output.SaveJSONFile(selectedTemplate.Queries, fileName, folderPath)

View File

@@ -2,7 +2,7 @@
package root package root
import ( import (
"fmt" _ "embed"
"github.com/sailpoint-oss/sailpoint-cli/cmd/connector" "github.com/sailpoint-oss/sailpoint-cli/cmd/connector"
"github.com/sailpoint-oss/sailpoint-cli/cmd/environment" "github.com/sailpoint-oss/sailpoint-cli/cmd/environment"
@@ -13,18 +13,26 @@ import (
"github.com/sailpoint-oss/sailpoint-cli/cmd/spconfig" "github.com/sailpoint-oss/sailpoint-cli/cmd/spconfig"
"github.com/sailpoint-oss/sailpoint-cli/cmd/transform" "github.com/sailpoint-oss/sailpoint-cli/cmd/transform"
"github.com/sailpoint-oss/sailpoint-cli/cmd/va" "github.com/sailpoint-oss/sailpoint-cli/cmd/va"
"github.com/sailpoint-oss/sailpoint-cli/internal/config" "github.com/sailpoint-oss/sailpoint-cli/cmd/workflow"
"github.com/sailpoint-oss/sailpoint-cli/internal/terminal" "github.com/sailpoint-oss/sailpoint-cli/internal/terminal"
"github.com/sailpoint-oss/sailpoint-cli/internal/util"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper"
) )
var version = "1.2.0" var version = "1.2.0"
func NewRootCmd() *cobra.Command { //go:embed root.md
var rootHelp string
func NewRootCommand() *cobra.Command {
help := util.ParseHelp(rootHelp)
var env string var env string
var debug bool
root := &cobra.Command{ root := &cobra.Command{
Use: "sail", Use: "sail",
Short: "The SailPoint CLI allows you to administer your IdentityNow tenant from the command line.\nNavigate to https://developer.sailpoint.com/idn/tools/cli to learn more.", Long: help.Long,
Example: help.Example,
Version: version, Version: version,
SilenceUsage: true, SilenceUsage: true,
CompletionOptions: cobra.CompletionOptions{ CompletionOptions: cobra.CompletionOptions{
@@ -33,17 +41,7 @@ func NewRootCmd() *cobra.Command {
DisableDescriptions: true, DisableDescriptions: true,
}, },
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
var tempEnv string cmd.Help()
if env != "" {
tempEnv = config.GetActiveEnvironment()
config.SetActiveEnvironment(env)
}
_, _ = fmt.Fprint(cmd.OutOrStdout(), cmd.UsageString())
if tempEnv != "" {
config.SetActiveEnvironment(tempEnv)
}
}, },
} }
@@ -51,17 +49,21 @@ func NewRootCmd() *cobra.Command {
root.AddCommand( root.AddCommand(
set.NewSetCmd(t), set.NewSetCmd(t),
environment.NewEnvironmentCmd(), environment.NewEnvironmentCommand(),
connector.NewConnCmd(t), connector.NewConnCmd(t),
transform.NewTransformCmd(), transform.NewTransformCommand(),
va.NewVACmd(t), va.NewVACommand(t),
search.NewSearchCmd(), search.NewSearchCommand(),
spconfig.NewSPConfigCmd(), spconfig.NewSPConfigCommand(),
report.NewReportCmd(), report.NewReportCommand(),
sdk.NewSDKCmd(), sdk.NewSDKCommand(),
workflow.NewWorkflowCommand(),
) )
root.PersistentFlags().StringVar(&env, "env", "", "Environment to use for SailPoint CLI commands") root.PersistentFlags().StringVarP(&env, "env", "", "", "Environment to use for SailPoint CLI commands")
root.PersistentFlags().BoolVarP(&debug, "debug", "", false, "Enable debug logging")
viper.BindPFlag("activeenvironment", root.PersistentFlags().Lookup("env"))
viper.BindPFlag("debug", root.PersistentFlags().Lookup("debug"))
return root return root
} }

13
cmd/root/root.md Normal file
View File

@@ -0,0 +1,13 @@
==Long==
# SailPoint CLI
The SailPoint CLI allows you to administer your IdentityNow tenant from the command line.
Navigate to the [CLI Documentation](https://developer.sailpoint.com/idn/tools/cli) for more information.
====
==Example==
```bash
sail search template
```
====

View File

@@ -19,7 +19,7 @@ func TestNewRootCmd_noArgs(t *testing.T) {
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
defer ctrl.Finish() defer ctrl.Finish()
cmd := NewRootCmd() cmd := NewRootCommand()
if len(cmd.Commands()) != numRootSubcommands { if len(cmd.Commands()) != numRootSubcommands {
t.Fatalf("expected: %d, actual: %d", len(cmd.Commands()), numRootSubcommands) t.Fatalf("expected: %d, actual: %d", len(cmd.Commands()), numRootSubcommands)
} }
@@ -47,7 +47,7 @@ func TestNewRootCmd_completionDisabled(t *testing.T) {
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
defer ctrl.Finish() defer ctrl.Finish()
cmd := NewRootCmd() cmd := NewRootCommand()
b := new(bytes.Buffer) b := new(bytes.Buffer)
cmd.SetOut(b) cmd.SetOut(b)

View File

@@ -24,7 +24,7 @@ func (c Config) printEnv() {
fmt.Println("CLIENT_SECRT=" + c.ClientSecret) fmt.Println("CLIENT_SECRT=" + c.ClientSecret)
} }
func newConfigCmd() *cobra.Command { func newConfigCommand() *cobra.Command {
var env bool var env bool
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "config", Use: "config",

View File

@@ -13,7 +13,7 @@ var goTemplateContents embed.FS
const goTemplateDirName = "golang" const goTemplateDirName = "golang"
func newGolangCmd() *cobra.Command { func newGolangCommand() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "golang", Use: "golang",

View File

@@ -2,12 +2,10 @@
package sdk package sdk
import ( import (
"fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func newInitCmd() *cobra.Command { func newInitCommand() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "init", Use: "init",
@@ -17,15 +15,15 @@ func newInitCmd() *cobra.Command {
Aliases: []string{"temp"}, Aliases: []string{"temp"},
Args: cobra.MaximumNArgs(1), Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
_, _ = fmt.Fprint(cmd.OutOrStdout(), cmd.UsageString()) cmd.Help()
}, },
} }
cmd.AddCommand( cmd.AddCommand(
newTypescriptCmd(), newTypescriptCommand(),
newGolangCmd(), newGolangCommand(),
newPowerShellCmd(), newPowerShellCommand(),
newConfigCmd(), newConfigCommand(),
) )
return cmd return cmd

View File

@@ -13,7 +13,7 @@ var pwshTemplateContents embed.FS
const pwshTemplateDirName = "powershell" const pwshTemplateDirName = "powershell"
func newPowerShellCmd() *cobra.Command { func newPowerShellCommand() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "powershell", Use: "powershell",

View File

@@ -2,12 +2,10 @@
package sdk package sdk
import ( import (
"fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func NewSDKCmd() *cobra.Command { func NewSDKCommand() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "sdk", Use: "sdk",
Short: "Initialize or configure SDK projects", Short: "Initialize or configure SDK projects",
@@ -15,12 +13,12 @@ func NewSDKCmd() *cobra.Command {
Example: "sail sdk", Example: "sail sdk",
Args: cobra.MaximumNArgs(1), Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
_, _ = fmt.Fprint(cmd.OutOrStdout(), cmd.UsageString()) cmd.Help()
}, },
} }
cmd.AddCommand( cmd.AddCommand(
newInitCmd(), newInitCommand(),
) )
return cmd return cmd

View File

@@ -13,7 +13,7 @@ var tsTemplateContents embed.FS
const tsTemplateDirName = "typescript" const tsTemplateDirName = "typescript"
func newTypescriptCmd() *cobra.Command { func newTypescriptCommand() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "typescript", Use: "typescript",

View File

@@ -7,22 +7,29 @@ import (
"github.com/charmbracelet/log" "github.com/charmbracelet/log"
"github.com/sailpoint-oss/sailpoint-cli/internal/config" "github.com/sailpoint-oss/sailpoint-cli/internal/config"
"github.com/sailpoint-oss/sailpoint-cli/internal/search" "github.com/sailpoint-oss/sailpoint-cli/internal/search"
"github.com/sailpoint-oss/sailpoint-cli/internal/util"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func newQueryCmd() *cobra.Command { func newQueryCmd(folderPath string, save bool) *cobra.Command {
var folderPath string
var indices []string var indices []string
var outputTypes []string
var sort []string var sort []string
var searchQuery string var searchQuery string
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "query", Use: "query",
Short: "Manually Search using a specific Query and Indicies", Short: "Manually Search using a specific Query and Indicies",
Long: "\nRun a search query in IdentityNow using a specific Query and Indicies\n\n", Long: "\nRun a search query in IdentityNow using a specific Query and Indicies\n\n",
Example: "sail search query \"(type:provisioning AND created:[now-90d TO now])\" --indicies events", Example: "sail search query \"(type:provisioning AND created:[now-90d TO now])\" --indices events",
Aliases: []string{"que"}, Aliases: []string{"que"},
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
PreRun: func(cmd *cobra.Command, args []string) {
folderPath, _ := cmd.Flags().GetString("folderPath")
if folderPath == "" {
cmd.MarkFlagRequired("save")
}
},
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
err := config.InitConfig() err := config.InitConfig()
@@ -50,20 +57,21 @@ func newQueryCmd() *cobra.Command {
return err return err
} }
err = search.IterateIndices(formattedResponse, searchQuery, folderPath, outputTypes) if save {
if err != nil { err = search.IterateIndices(formattedResponse, searchQuery, folderPath, []string{"json"})
return err if err != nil {
return err
}
} else {
cmd.Println(util.PrettyPrint(formattedResponse))
} }
return nil return nil
}, },
} }
cmd.Flags().StringArrayVarP(&indices, "indices", "i", []string{}, "indices to perform the search query on (accessprofiles, accountactivities, entitlements, events, identities, roles)") cmd.Flags().StringArrayVar(&indices, "indices", []string{}, "indices to perform the search query on (accessprofiles, accountactivities, entitlements, events, identities, roles)")
cmd.Flags().StringArrayVarP(&sort, "sort", "s", []string{}, "the sort value for the api call (displayName, +id...)") cmd.Flags().StringArrayVar(&sort, "sort", []string{}, "the sort value for the api call (displayName, +id...)")
cmd.Flags().StringArrayVarP(&outputTypes, "outputTypes", "o", []string{"json"}, "the output types for the results (csv, json)")
cmd.Flags().StringVarP(&folderPath, "folderPath", "f", "search_results", "folder path to save the search results in. If the directory doesn't exist, then it will be automatically created. (default is the current working directory)")
cmd.MarkFlagRequired("indices") cmd.MarkFlagRequired("indices")
return cmd return cmd

View File

@@ -2,12 +2,12 @@
package search package search
import ( import (
"fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func NewSearchCmd() *cobra.Command { func NewSearchCommand() *cobra.Command {
var folderPath string
var save bool
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "search", Use: "search",
Short: "Perform Search operations in IdentityNow with a specific query or a template", Short: "Perform Search operations in IdentityNow with a specific query or a template",
@@ -16,15 +16,18 @@ func NewSearchCmd() *cobra.Command {
Aliases: []string{"se"}, Aliases: []string{"se"},
Args: cobra.MaximumNArgs(1), Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
_, _ = fmt.Fprint(cmd.OutOrStdout(), cmd.UsageString()) cmd.Help()
}, },
} }
cmd.AddCommand( cmd.AddCommand(
newQueryCmd(), newQueryCmd(folderPath, save),
newTemplateCmd(), newTemplateCmd(folderPath, save),
) )
cmd.PersistentFlags().StringVarP(&folderPath, "folderPath", "f", "", "Folder path to save the search results to. If the directory doesn't exist, then it will be created. (defaults to the current working directory)")
cmd.PersistentFlags().BoolVarP(&save, "save", "s", false, "Save the search results to a file")
return cmd return cmd
} }

View File

@@ -19,7 +19,7 @@ func TestNewSearchCommand(t *testing.T) {
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
defer ctrl.Finish() defer ctrl.Finish()
cmd := NewSearchCmd() cmd := NewSearchCommand()
b := new(bytes.Buffer) b := new(bytes.Buffer)
cmd.SetOut(b) cmd.SetOut(b)

View File

@@ -12,12 +12,11 @@ import (
"github.com/sailpoint-oss/sailpoint-cli/internal/templates" "github.com/sailpoint-oss/sailpoint-cli/internal/templates"
"github.com/sailpoint-oss/sailpoint-cli/internal/terminal" "github.com/sailpoint-oss/sailpoint-cli/internal/terminal"
"github.com/sailpoint-oss/sailpoint-cli/internal/types" "github.com/sailpoint-oss/sailpoint-cli/internal/types"
"github.com/sailpoint-oss/sailpoint-cli/internal/util"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func newTemplateCmd() *cobra.Command { func newTemplateCmd(folderPath string, save bool) *cobra.Command {
var outputTypes []string
var folderPath string
var template string var template string
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "template", Use: "template",
@@ -26,6 +25,12 @@ func newTemplateCmd() *cobra.Command {
Example: "sail search template", Example: "sail search template",
Aliases: []string{"temp"}, Aliases: []string{"temp"},
Args: cobra.MaximumNArgs(1), Args: cobra.MaximumNArgs(1),
PreRun: func(cmd *cobra.Command, args []string) {
folderPath, _ := cmd.Flags().GetString("folderPath")
if folderPath == "" {
cmd.MarkFlagRequired("save")
}
},
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
err := config.InitConfig() err := config.InitConfig()
@@ -65,10 +70,10 @@ func newTemplateCmd() *cobra.Command {
log.Warn("multiple template matches, the first match will be used", "template", template) log.Warn("multiple template matches, the first match will be used", "template", template)
} }
selectedTemplate = matches[0] selectedTemplate = matches[0]
varCount := len(selectedTemplate.Variables)
if varCount > 0 { if len(selectedTemplate.Variables) > 0 {
for i := 0; i < varCount; i++ { for _, varEntry := range selectedTemplate.Variables {
varEntry := selectedTemplate.Variables[i]
resp := terminal.InputPrompt("Input " + varEntry.Prompt + ":") resp := terminal.InputPrompt("Input " + varEntry.Prompt + ":")
selectedTemplate.Raw = []byte(strings.ReplaceAll(string(selectedTemplate.Raw), "{{"+varEntry.Name+"}}", resp)) selectedTemplate.Raw = []byte(strings.ReplaceAll(string(selectedTemplate.Raw), "{{"+varEntry.Name+"}}", resp))
} }
@@ -85,17 +90,17 @@ func newTemplateCmd() *cobra.Command {
return err return err
} }
err = search.IterateIndices(formattedResponse, selectedTemplate.SearchQuery.Query.GetQuery(), folderPath, outputTypes) if save {
if err != nil { err = search.IterateIndices(formattedResponse, selectedTemplate.SearchQuery.Query.GetQuery(), folderPath, []string{"json"})
return err if err != nil {
return err
}
} else {
cmd.Println(util.PrettyPrint(formattedResponse))
} }
return nil return nil
}, },
} }
cmd.Flags().StringArrayVarP(&outputTypes, "output types", "o", []string{"json"}, "the sort value for the api call (examples)")
cmd.Flags().StringVarP(&folderPath, "folderPath", "f", "search_results", "folder path to save the search results in. If the directory doesn't exist, then it will be automatically created. (default is the current working directory)")
return cmd return cmd
} }

View File

@@ -19,7 +19,7 @@ func TestNewTemplateCommand(t *testing.T) {
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
defer ctrl.Finish() defer ctrl.Finish()
cmd := newTemplateCmd() cmd := newTemplateCmd("", false)
b := new(bytes.Buffer) b := new(bytes.Buffer)
cmd.SetOut(b) cmd.SetOut(b)

View File

@@ -55,7 +55,7 @@ func newAuthCommand() *cobra.Command {
log.Info("Authentication method set to OAuth") log.Info("Authentication method set to OAuth")
default: default:
log.Error("Invalid Selection") log.Warn("No selection made")
} }
return nil return nil

View File

@@ -2,8 +2,6 @@
package set package set
import ( import (
"fmt"
"github.com/sailpoint-oss/sailpoint-cli/internal/terminal" "github.com/sailpoint-oss/sailpoint-cli/internal/terminal"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@@ -16,7 +14,7 @@ func NewSetCmd(term terminal.Terminal) *cobra.Command {
Example: "sail set", Example: "sail set",
Args: cobra.MaximumNArgs(1), Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
_, _ = fmt.Fprint(cmd.OutOrStdout(), cmd.UsageString()) cmd.Help()
}, },
} }

View File

@@ -2,21 +2,28 @@
package spconfig package spconfig
import ( import (
_ "embed"
"github.com/charmbracelet/log" "github.com/charmbracelet/log"
"github.com/sailpoint-oss/sailpoint-cli/internal/config" "github.com/sailpoint-oss/sailpoint-cli/internal/config"
"github.com/sailpoint-oss/sailpoint-cli/internal/spconfig" "github.com/sailpoint-oss/sailpoint-cli/internal/spconfig"
"github.com/sailpoint-oss/sailpoint-cli/internal/util"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func newDownloadCmd() *cobra.Command { //go:embed download.md
var downloadHelp string
func newDownloadCommand() *cobra.Command {
help := util.ParseHelp(downloadHelp)
var importIDs []string var importIDs []string
var exportIDs []string var exportIDs []string
var folderPath string var folderPath string
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "download", Use: "download {--import <importID> --export <exportID>}",
Short: "Download the results of import or export job from IdentityNow", Short: "Download the results of import or export jobs from IdentityNow",
Long: "\nDownload the results of import or export job from IdentityNow\n\n", Long: help.Long,
Example: "sail spconfig download -export <export job id> -import <import job id>", Example: help.Example,
Aliases: []string{"down"}, Aliases: []string{"down"},
Args: cobra.NoArgs, Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
@@ -26,38 +33,28 @@ func newDownloadCmd() *cobra.Command {
return err return err
} }
if len(importIDs) > 0 { for _, jobId := range importIDs {
for i := 0; i < len(importIDs); i++ { log.Info("Checking Import Job", "JobID", jobId)
jobId := importIDs[i] err := spconfig.DownloadImport(*apiClient, jobId, "spconfig-import-"+jobId+".json", folderPath)
log.Info("Checking Import Job", "JobID", jobId) if err != nil {
err := spconfig.DownloadImport(*apiClient, jobId, "spconfig-import-"+jobId+".json", folderPath) return err
if err != nil {
return err
}
} }
} else {
log.Info("No Import Job IDs provided")
} }
if len(exportIDs) > 0 { for _, jobId := range exportIDs {
for i := 0; i < len(exportIDs); i++ { log.Info("Checking Export Job", "JobID", jobId)
jobId := exportIDs[i] err := spconfig.DownloadExport(*apiClient, jobId, "spconfig-export-"+jobId+".json", folderPath)
log.Info("Checking Export Job", "JobID", jobId) if err != nil {
err := spconfig.DownloadExport(*apiClient, jobId, "spconfig-export-"+jobId+".json", folderPath) return err
if err != nil {
return err
}
} }
} else {
log.Info("No Export Job IDs provided")
} }
return nil return nil
}, },
} }
cmd.Flags().StringArrayVarP(&importIDs, "import", "i", []string{}, "specify the IDs of the import jobs to download results for") cmd.Flags().StringArrayVarP(&importIDs, "import", "", []string{}, "specify the IDs of the import jobs to download results for")
cmd.Flags().StringArrayVarP(&exportIDs, "export", "e", []string{}, "specify the IDs of the export jobs to download results for") cmd.Flags().StringArrayVarP(&exportIDs, "export", "", []string{}, "specify the IDs of the export jobs to download results for")
cmd.Flags().StringVarP(&folderPath, "folderPath", "f", "spconfig-exports", "folder path to save the search results in. If the directory doesn't exist, then it will be automatically created. (default is the current working directory)") cmd.Flags().StringVarP(&folderPath, "folderPath", "f", "spconfig-exports", "folder path to save the search results in. If the directory doesn't exist, then it will be automatically created. (default is the current working directory)")
return cmd return cmd

12
cmd/spconfig/download.md Normal file
View File

@@ -0,0 +1,12 @@
==Long==
# Download
Download the results of Import or Export jobs from IdentityNow
====
==Example==
```bash
sail spconfig download
```
====

View File

@@ -3,41 +3,55 @@ package spconfig
import ( import (
"context" "context"
_ "embed"
"encoding/json"
"github.com/charmbracelet/log" "github.com/charmbracelet/log"
sailpointbetasdk "github.com/sailpoint-oss/golang-sdk/beta" "github.com/sailpoint-oss/golang-sdk/beta"
"github.com/sailpoint-oss/sailpoint-cli/internal/config" "github.com/sailpoint-oss/sailpoint-cli/internal/config"
"github.com/sailpoint-oss/sailpoint-cli/internal/spconfig" "github.com/sailpoint-oss/sailpoint-cli/internal/spconfig"
"github.com/sailpoint-oss/sailpoint-cli/internal/util"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func newExportCmd() *cobra.Command { //go:embed export.md
var exportHelp string
func newExportCommand() *cobra.Command {
help := util.ParseHelp(exportHelp)
var objectOptions string
var folderPath string var folderPath string
var description string var description string
var includeTypes []string var includeTypes []string
var excludeTypes []string var excludeTypes []string
var wait bool var wait bool
var payload *sailpointbetasdk.ExportPayload
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "export", Use: "export",
Short: "Start an Export job in IdentityNow", Short: "Start an Export job in IdentityNow",
Long: "\nStart an Export job in IdentityNow\n\n", Long: help.Long,
Example: "sail spconfig export", Example: help.Example,
Aliases: []string{"exp"}, Aliases: []string{"exp"},
Args: cobra.NoArgs, Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
var options *map[string]beta.ObjectExportImportOptions
apiClient, err := config.InitAPIClient() apiClient, err := config.InitAPIClient()
if err != nil { if err != nil {
return err return err
} }
payload = sailpointbetasdk.NewExportPayload() if objectOptions != "" {
payload.Description = &description err = json.Unmarshal([]byte(objectOptions), &options)
payload.IncludeTypes = includeTypes if err != nil {
payload.ExcludeTypes = excludeTypes return err
}
}
job, _, err := apiClient.Beta.SPConfigApi.ExportSpConfig(context.TODO()).ExportPayload(*payload).Execute() job, _, err := apiClient.Beta.SPConfigApi.ExportSpConfig(context.TODO()).ExportPayload(beta.ExportPayload{Description: &description, IncludeTypes: includeTypes, ExcludeTypes: excludeTypes, ObjectOptions: options}).Execute()
if err != nil { if err != nil {
return err return err
} }
@@ -54,9 +68,10 @@ func newExportCmd() *cobra.Command {
} }
cmd.Flags().StringVarP(&folderPath, "folderPath", "f", "spconfig-exports", "folder path to save the search results in. If the directory doesn't exist, then it will be automatically created. (default is the current working directory)") cmd.Flags().StringVarP(&folderPath, "folderPath", "f", "spconfig-exports", "folder path to save the search results in. If the directory doesn't exist, then it will be automatically created. (default is the current working directory)")
cmd.Flags().StringVarP(&description, "description", "d", "", "optional description for the export job") cmd.Flags().StringVarP(&description, "description", "", "", "optional description for the export job")
cmd.Flags().StringArrayVarP(&includeTypes, "include", "i", []string{}, "types to include in export job") cmd.Flags().StringArrayVarP(&includeTypes, "include", "i", []string{}, "types to include in export job")
cmd.Flags().StringArrayVarP(&excludeTypes, "exclude", "e", []string{}, "types to exclude in export job") cmd.Flags().StringArrayVarP(&excludeTypes, "exclude", "e", []string{}, "types to exclude in export job")
cmd.Flags().StringVarP(&objectOptions, "objectOptions", "o", "", "options for the object types being exported")
cmd.Flags().BoolVarP(&wait, "wait", "w", false, "wait for the export job to finish, and download the results") cmd.Flags().BoolVarP(&wait, "wait", "w", false, "wait for the export job to finish, and download the results")
return cmd return cmd

44
cmd/spconfig/export.md Normal file
View File

@@ -0,0 +1,44 @@
==Long==
# Export
Start an Export job in IdentityNow
Valid Types that can be included or excluded are:
- ACCESS_PROFILE
- ACCESS_REQUEST_CONFIG
- ATTR_SYNC_SOURCE_CONFIG
- AUTH_ORG
- CAMPAIGN_FILTER
- FORM_DEFINITION
- GOVERNANCE_GROUP
- IDENTITY_OBJECT_CONFIG
- IDENTITY_PROFILE
- LIFECYCLE_STATE
- NOTIFICATION_TEMPLATE
- PASSWORD_POLICY
- PASSWORD_SYNC_GROUP
- PUBLIC_IDENTITIES_CONFIG
- ROLE
- RULE
- SERVICE_DESK_INTEGRATION
- SOD_POLICY
- SOURCE
- TRANSFORM
- TRIGGER_SUBSCRIPTION
- WORKFLOWS
====
==Example==
```bash
sail spconfig export --include WORKFLOWS --include SOURCE
sail spconfig export --include SOURCE --wait
sail spconfig export --include TRANSFORM --objectOptions '{
"TRANSFORM": {
"includedIds": [],
"includedNames": [
"Remove Diacritical Marks",
"Common - Location Lookup"
]
}
}'
```
====

View File

@@ -2,29 +2,34 @@
package spconfig package spconfig
import ( import (
"fmt" _ "embed"
"github.com/sailpoint-oss/sailpoint-cli/internal/util"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func NewSPConfigCmd() *cobra.Command { //go:embed spconfig.md
var spconfigHelp string
func NewSPConfigCommand() *cobra.Command {
help := util.ParseHelp(spconfigHelp)
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "spconfig", Use: "spconfig",
Short: "Perform SPConfig operations in IdentityNow", Short: "Perform SPConfig operations in IdentityNow",
Long: "\nPerform SPConfig operations in IdentityNow\n\n", Long: help.Long,
Example: "sail spconfig", Example: help.Example,
Aliases: []string{"spcon"}, Aliases: []string{"spcon"},
Args: cobra.MaximumNArgs(1), Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
_, _ = fmt.Fprint(cmd.OutOrStdout(), cmd.UsageString()) cmd.Help()
}, },
} }
cmd.AddCommand( cmd.AddCommand(
newExportCmd(), newExportCommand(),
newStatusCmd(), newStatusCommand(),
newTemplateCmd(), newTemplateCommand(),
newDownloadCmd(), newDownloadCommand(),
newImportCommand(), newImportCommand(),
) )

16
cmd/spconfig/spconfig.md Normal file
View File

@@ -0,0 +1,16 @@
==Long==
# SPConfig
Perform SP-Config operations in IdentityNow
API References:
- https://developer.sailpoint.com/idn/api/beta/sp-config
====
==Example==
```bash
sail spconfig export --include WORKFLOWS --include SOURCE --wait
sail spconfig import
```
====

View File

@@ -19,7 +19,7 @@ func TestNewSPConfigCommand(t *testing.T) {
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
defer ctrl.Finish() defer ctrl.Finish()
cmd := NewSPConfigCmd() cmd := NewSPConfigCommand()
b := new(bytes.Buffer) b := new(bytes.Buffer)
cmd.SetOut(b) cmd.SetOut(b)

View File

@@ -9,7 +9,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func newStatusCmd() *cobra.Command { func newStatusCommand() *cobra.Command {
var exportJobs []string var exportJobs []string
var importJobs []string var importJobs []string
cmd := &cobra.Command{ cmd := &cobra.Command{
@@ -26,20 +26,18 @@ func newStatusCmd() *cobra.Command {
return err return err
} }
for i := 0; i < len(exportJobs); i++ { for _, jobId := range exportJobs {
job := exportJobs[i]
status, _, err := apiClient.Beta.SPConfigApi.ExportSpConfigJobStatus(context.TODO(), job).Execute() //SPConfigApi.SpConfigExportJobStatus(ctx, job).Execute() status, _, err := apiClient.Beta.SPConfigApi.GetSpConfigExportStatus(context.TODO(), jobId).Execute()
if err != nil { if err != nil {
return err return err
} }
spconfig.PrintJob(*status) spconfig.PrintJob(*status)
} }
for i := 0; i < len(importJobs); i++ { for _, jobId := range importJobs {
job := importJobs[i]
status, _, err := apiClient.Beta.SPConfigApi.ImportSpConfigJobStatus(context.TODO(), job).Execute() status, _, err := apiClient.Beta.SPConfigApi.GetSpConfigImportStatus(context.TODO(), jobId).Execute()
if err != nil { if err != nil {
return err return err
} }
@@ -50,8 +48,8 @@ func newStatusCmd() *cobra.Command {
}, },
} }
cmd.Flags().StringArrayVarP(&importJobs, "import", "i", []string{}, "a list of import job ids to return the status of") cmd.Flags().StringArrayVarP(&importJobs, "import", "", []string{}, "a list of import job ids to return the status of")
cmd.Flags().StringArrayVarP(&exportJobs, "export", "e", []string{}, "a list of export job ids to return the status of") cmd.Flags().StringArrayVarP(&exportJobs, "export", "", []string{}, "a list of export job ids to return the status of")
return cmd return cmd
} }

View File

@@ -3,6 +3,7 @@ package spconfig
import ( import (
"context" "context"
_ "embed"
"encoding/json" "encoding/json"
"fmt" "fmt"
"strings" "strings"
@@ -13,19 +14,23 @@ import (
"github.com/sailpoint-oss/sailpoint-cli/internal/templates" "github.com/sailpoint-oss/sailpoint-cli/internal/templates"
"github.com/sailpoint-oss/sailpoint-cli/internal/terminal" "github.com/sailpoint-oss/sailpoint-cli/internal/terminal"
"github.com/sailpoint-oss/sailpoint-cli/internal/types" "github.com/sailpoint-oss/sailpoint-cli/internal/types"
"github.com/sailpoint-oss/sailpoint-cli/internal/util"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func newTemplateCmd() *cobra.Command { //go:embed template.md
var outputTypes []string var templateHelp string
func newTemplateCommand() *cobra.Command {
help := util.ParseHelp(templateHelp)
var folderPath string var folderPath string
var template string var template string
var wait bool var wait bool
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "template", Use: "template",
Short: "Begin an SPConfig Export task in IdentityNow using a template", Short: "Begin an SPConfig Export task in IdentityNow using a template",
Long: "\nBegin an SPConfig Export task in IdentityNow using a template\n\n", Long: help.Long,
Example: "sail spconfig template --wait", Example: help.Example,
Aliases: []string{"temp"}, Aliases: []string{"temp"},
Args: cobra.MaximumNArgs(1), Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
@@ -91,7 +96,6 @@ func newTemplateCmd() *cobra.Command {
}, },
} }
cmd.Flags().StringArrayVarP(&outputTypes, "outputTypes", "o", []string{"json"}, "the sort value for the api call (examples)")
cmd.Flags().StringVarP(&folderPath, "folderPath", "f", "spconfig-exports", "folder path to save the search results in. If the directory doesn't exist, then it will be automatically created. (default is the current working directory)") cmd.Flags().StringVarP(&folderPath, "folderPath", "f", "spconfig-exports", "folder path to save the search results in. If the directory doesn't exist, then it will be automatically created. (default is the current working directory)")
cmd.Flags().BoolVarP(&wait, "wait", "w", false, "wait for the export job to finish, and download the results") cmd.Flags().BoolVarP(&wait, "wait", "w", false, "wait for the export job to finish, and download the results")

15
cmd/spconfig/template.md Normal file
View File

@@ -0,0 +1,15 @@
==Long==
# Template
Begin an SPConfig Export task in IdentityNow using a template
====
==Example==
```bash
sail spconfig template --wait
```
====

View File

@@ -19,7 +19,7 @@ func TestNewTemplateCommand(t *testing.T) {
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
defer ctrl.Finish() defer ctrl.Finish()
cmd := newTemplateCmd() cmd := newTemplateCommand()
b := new(bytes.Buffer) b := new(bytes.Buffer)
cmd.SetOut(b) cmd.SetOut(b)

View File

@@ -16,7 +16,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func newCreateCmd() *cobra.Command { func newCreateCommand() *cobra.Command {
var filepath string var filepath string
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "create", Use: "create",

View File

@@ -104,7 +104,7 @@ func TestNewCRUDCmd(t *testing.T) {
// ctrl := gomock.NewController(t) // ctrl := gomock.NewController(t)
// defer ctrl.Finish() // defer ctrl.Finish()
createCMD := newCreateCmd() createCMD := newCreateCommand()
createBuffer := new(bytes.Buffer) createBuffer := new(bytes.Buffer)
createCMD.SetOut(createBuffer) createCMD.SetOut(createBuffer)
@@ -134,7 +134,7 @@ func TestNewCRUDCmd(t *testing.T) {
t.Fatalf("Unable to save test data: %v", err) t.Fatalf("Unable to save test data: %v", err)
} }
cmd := newUpdateCmd() cmd := newUpdateCommand()
cmd.Flags().Set("file", PATH.Join(path, updateFile)) cmd.Flags().Set("file", PATH.Join(path, updateFile))
@@ -143,7 +143,7 @@ func TestNewCRUDCmd(t *testing.T) {
t.Fatalf("error execute cmd: %v", err) t.Fatalf("error execute cmd: %v", err)
} }
deleteCMD := newDeleteCmd() deleteCMD := newDeleteCommand()
deleteBuffer := new(bytes.Buffer) deleteBuffer := new(bytes.Buffer)
deleteCMD.SetOut(deleteBuffer) deleteCMD.SetOut(deleteBuffer)

View File

@@ -16,7 +16,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func newDeleteCmd() *cobra.Command { func newDeleteCommand() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "delete", Use: "delete",
Short: "Delete an IdentityNow Transform", Short: "Delete an IdentityNow Transform",

View File

@@ -13,7 +13,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func newDownloadCmd() *cobra.Command { func newDownloadCommand() *cobra.Command {
var destination string var destination string
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "download", Use: "download",

View File

@@ -20,7 +20,7 @@ func TestNewDownloadCmd(t *testing.T) {
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
defer ctrl.Finish() defer ctrl.Finish()
cmd := newListCmd() cmd := newListCommand()
b := new(bytes.Buffer) b := new(bytes.Buffer)
cmd.SetOut(b) cmd.SetOut(b)

View File

@@ -7,7 +7,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func newListCmd() *cobra.Command { func newListCommand() *cobra.Command {
return &cobra.Command{ return &cobra.Command{
Use: "list", Use: "list",
Short: "List all Transforms in IdentityNow", Short: "List all Transforms in IdentityNow",

View File

@@ -20,7 +20,7 @@ func TestNewListCmd(t *testing.T) {
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
defer ctrl.Finish() defer ctrl.Finish()
cmd := newListCmd() cmd := newListCommand()
b := new(bytes.Buffer) b := new(bytes.Buffer)
cmd.SetOut(b) cmd.SetOut(b)

View File

@@ -19,7 +19,7 @@ import (
var implicitInput bool var implicitInput bool
func newPreviewCmd() *cobra.Command { func newPreviewCommand() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "preview", Use: "preview",
Short: "Preview the effects of an IdentityNow Transform", Short: "Preview the effects of an IdentityNow Transform",

View File

@@ -2,8 +2,6 @@
package transform package transform
import ( import (
"fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@@ -14,7 +12,7 @@ const (
userEndpoint = "/cc/api/identity/list" userEndpoint = "/cc/api/identity/list"
) )
func NewTransformCmd() *cobra.Command { func NewTransformCommand() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "transform", Use: "transform",
Short: "Manage Transforms in IdentityNow", Short: "Manage Transforms in IdentityNow",
@@ -22,19 +20,19 @@ func NewTransformCmd() *cobra.Command {
Example: "sail transform | sail tran", Example: "sail transform | sail tran",
Aliases: []string{"tran"}, Aliases: []string{"tran"},
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
_, _ = fmt.Fprint(cmd.OutOrStdout(), cmd.UsageString()) cmd.Help()
}, },
} }
cmd.PersistentFlags().StringP("transforms-endpoint", "e", transformsEndpoint, "Override transforms endpoint") cmd.PersistentFlags().StringP("transforms-endpoint", "e", transformsEndpoint, "Override transforms endpoint")
cmd.AddCommand( cmd.AddCommand(
newListCmd(), newListCommand(),
newDownloadCmd(), newDownloadCommand(),
newCreateCmd(), newCreateCommand(),
newUpdateCmd(), newUpdateCommand(),
newDeleteCmd(), newDeleteCommand(),
newPreviewCmd(), newPreviewCommand(),
) )
return cmd return cmd

View File

@@ -14,7 +14,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func newUpdateCmd() *cobra.Command { func newUpdateCommand() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "update", Use: "update",
Short: "Update a Transform in IdentityNow from a File", Short: "Update a Transform in IdentityNow from a File",

View File

@@ -1,41 +1,54 @@
package va package va
import ( import (
_ "embed"
"os" "os"
"sync" "sync"
"time" "time"
"github.com/charmbracelet/log" "github.com/charmbracelet/log"
"github.com/sailpoint-oss/sailpoint-cli/internal/terminal" "github.com/sailpoint-oss/sailpoint-cli/internal/terminal"
"github.com/sailpoint-oss/sailpoint-cli/internal/util"
"github.com/sailpoint-oss/sailpoint-cli/internal/va" "github.com/sailpoint-oss/sailpoint-cli/internal/va"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/vbauerster/mpb/v8" "github.com/vbauerster/mpb/v8"
) )
func newCollectCmd(term terminal.Terminal) *cobra.Command { //go:embed collect.md
var collectHelp string
func newCollectCommand(term terminal.Terminal) *cobra.Command {
help := util.ParseHelp(collectHelp)
var credentials []string var credentials []string
var output string var output string
var logs bool var logs bool
var config bool var config bool
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "collect", Use: "collect [-c | -l] [-o output] VA-Network-Address... [-p va-password]",
Short: "Collect Configuration or Log Files from a SailPoint Virtual Appliance", Short: "Collect files from a SailPoint Virtual Appliance",
Long: "\nCollect Configuration or Log Files from a SailPoint Virtual Appliance\n\n", Long: help.Long,
Example: "sail va collect 10.10.10.25, 10.10.10.26 -p S@ilp0int -p S@ilp0int \n\nLog Files:\n/home/sailpoint/log/ccg.log\n/home/sailpoint/log/charon.log\n/home/sailpoint/stuntlog.txt\n\nConfig Files:\n/home/sailpoint/proxy.yaml\n/etc/systemd/network/static.network\n/etc/resolv.conf\n", Example: help.Example,
Args: cobra.MinimumNArgs(1), Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
var err error var err error
logFiles := []string{"/home/sailpoint/log/ccg.log", "/home/sailpoint/log/charon.log"}
configFiles := []string{"/home/sailpoint/proxy.yaml", "/etc/systemd/network/static.network", "/etc/resolv.conf"}
if output == "" { if output == "" {
output, _ = os.Getwd() output, _ = os.Getwd()
} }
var files []string var files []string
if logs { if logs {
files = []string{"/home/sailpoint/log/ccg.log", "/home/sailpoint/log/charon.log", "/home/sailpoint/stuntlog.txt"} files = append(files, logFiles...)
} else if config { }
files = []string{"/home/sailpoint/proxy.yaml", "/etc/systemd/network/static.network", "/etc/resolv.conf"} if config {
} else { files = append(files, configFiles...)
files = []string{"/home/sailpoint/log/ccg.log", "/home/sailpoint/log/charon.log", "/home/sailpoint/stuntlog.txt", "/home/sailpoint/proxy.yaml", "/etc/systemd/network/static.network", "/etc/resolv.conf"} }
if !config && !logs {
files = append(files, logFiles...)
files = append(files, configFiles...)
} }
var wg sync.WaitGroup var wg sync.WaitGroup
@@ -75,12 +88,12 @@ func newCollectCmd(term terminal.Terminal) *cobra.Command {
}, },
} }
cmd.Flags().StringVarP(&output, "Output", "o", "", "The path to save the log files") cmd.Flags().StringVarP(&output, "output", "o", "", "The path to save the log files")
cmd.Flags().BoolVarP(&logs, "logs", "l", false, "Retrieve log files") cmd.Flags().BoolVarP(&logs, "log", "l", false, "retrieve log files")
cmd.Flags().BoolVarP(&config, "config", "c", false, "Retrieve config files") cmd.Flags().BoolVarP(&config, "config", "c", false, "retrieve config files")
cmd.Flags().StringArrayVarP(&credentials, "Passwords", "p", []string{}, "You can enter the Passwords for the servers in the same order that the servers are listed as arguments") cmd.Flags().StringArrayVarP(&credentials, "passwords", "p", []string{}, "passwords for the servers in the same order that the servers are listed as arguments")
cmd.MarkFlagsMutuallyExclusive("config", "logs") cmd.MarkFlagsMutuallyExclusive("config", "log")
return cmd return cmd
} }

30
cmd/va/collect.md Normal file
View File

@@ -0,0 +1,30 @@
==Long==
# Collect
Collect files from a remote Virtual Appliance
Files are collected over SFTP. Passwords are provided via the --password (-p) flag or they will be prompted for at runtime. Server addresses can be DNS names or IP addresses, and are provided as arguments separated by spaces.
Log Files:
```bash
/home/sailpoint/log/ccg.log
/home/sailpoint/log/charon.log
```
Config Files:
```bash
/home/sailpoint/proxy.yaml
/etc/systemd/network/static.network
/etc/resolv.conf
```
====
==Example==
```bash
sail va collect 10.10.10.25 10.10.10.26 -p S@ilp0int -p S@ilp0int
sail va collect 10.10.10.25 --config
sail va collect 10.10.10.26 --log
sail va collect 10.10.10.25 --log --output log_files
sail va collect 10.10.10.25 --output all_files
```
====

View File

@@ -1,22 +1,27 @@
package va package list
import ( import (
"context" "context"
_ "embed"
sailpoint "github.com/sailpoint-oss/golang-sdk" sailpoint "github.com/sailpoint-oss/golang-sdk"
sailpointbetasdk "github.com/sailpoint-oss/golang-sdk/beta" "github.com/sailpoint-oss/golang-sdk/beta"
"github.com/sailpoint-oss/sailpoint-cli/internal/config" "github.com/sailpoint-oss/sailpoint-cli/internal/config"
"github.com/sailpoint-oss/sailpoint-cli/internal/sdk" "github.com/sailpoint-oss/sailpoint-cli/internal/sdk"
"github.com/sailpoint-oss/sailpoint-cli/internal/util" "github.com/sailpoint-oss/sailpoint-cli/internal/util"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func newListCmd() *cobra.Command { //go:embed list.md
var listHelp string
func NewListCommand() *cobra.Command {
help := util.ParseHelp(listHelp)
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "list", Use: "list",
Short: "List the Clusters and Virtual Appliances configured in IdentityNow", Short: "List the Clusters and Virtual Appliances configured in IdentityNow",
Long: "\nList the Clusters and Virtual Appliances configured in IdentityNow\n\n", Long: help.Long,
Example: "sail va list", Example: help.Example,
Args: cobra.NoArgs, Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
@@ -25,7 +30,7 @@ func newListCmd() *cobra.Command {
return err return err
} }
clusters, resp, err := sailpoint.PaginateWithDefaults[sailpointbetasdk.ManagedCluster](apiClient.Beta.ManagedClustersApi.GetManagedClusters(context.TODO())) clusters, resp, err := sailpoint.PaginateWithDefaults[beta.ManagedCluster](apiClient.Beta.ManagedClustersApi.GetManagedClusters(context.TODO()))
if err != nil { if err != nil {
return sdk.HandleSDKError(resp, err) return sdk.HandleSDKError(resp, err)
} }

13
cmd/va/list/list.md Normal file
View File

@@ -0,0 +1,13 @@
==Long==
# List
List the Clusters and Virtual Appliances in the configured IdentityNow tenant
====
==Example==
```bash
sail va list
```
====

View File

@@ -2,6 +2,7 @@ package logConfig
import ( import (
"context" "context"
_ "embed"
"github.com/sailpoint-oss/golang-sdk/beta" "github.com/sailpoint-oss/golang-sdk/beta"
"github.com/sailpoint-oss/sailpoint-cli/internal/config" "github.com/sailpoint-oss/sailpoint-cli/internal/config"
@@ -10,12 +11,16 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func newGetCmd() *cobra.Command { //go:embed get.md
var getHelp string
func newGetCommand() *cobra.Command {
help := util.ParseHelp(getHelp)
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "get", Use: "get",
Short: "Return a Virtual Appliances log configuration", Short: "Get a Virtual Appliances clusters log configuration",
Long: "\nReturn a Virtual Appliances log configuration\n\n", Long: help.Long,
Example: "sail va log get", Example: help.Example,
Args: cobra.MinimumNArgs(1), Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
@@ -26,9 +31,7 @@ func newGetCmd() *cobra.Command {
return err return err
} }
for i := 0; i < len(args); i++ { for _, clusterId := range args {
clusterId := args[i]
configuration, resp, err := apiClient.Beta.ManagedClustersApi.GetClientLogConfiguration(context.TODO(), clusterId).Execute() configuration, resp, err := apiClient.Beta.ManagedClustersApi.GetClientLogConfiguration(context.TODO(), clusterId).Execute()
if err != nil { if err != nil {

9
cmd/va/logConfig/get.md Normal file
View File

@@ -0,0 +1,9 @@
==Long==
# Get
Get a Virtual Appliances clusters log configuration
====
==Example==
sail va log get
====

View File

@@ -2,25 +2,23 @@
package logConfig package logConfig
import ( import (
"fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func NewLogCmd() *cobra.Command { func NewLogCommand() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "log", Use: "log",
Short: "Interact with a SailPoint Virtual Appliances log configuration", Short: "Interact with a SailPoint Virtual Appliances log configuration",
Long: "\nInteract with SailPoint Virtual Appliances log configuration\n\n", Long: "\nInteract with SailPoint Virtual Appliances log configuration\n\n",
Aliases: []string{"l"}, Aliases: []string{"l"},
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
_, _ = fmt.Fprint(cmd.OutOrStdout(), cmd.UsageString()) cmd.Help()
}, },
} }
cmd.AddCommand( cmd.AddCommand(
newGetCmd(), newGetCommand(),
newSetCmd(), newSetCommand(),
) )
return cmd return cmd

View File

View File

@@ -12,7 +12,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func newSetCmd() *cobra.Command { func newSetCommand() *cobra.Command {
var level string var level string
var durationInMinutes int32 var durationInMinutes int32
var connectors []string var connectors []string
@@ -27,7 +27,7 @@ func newSetCmd() *cobra.Command {
rootLevel := beta.StandardLevel(level) rootLevel := beta.StandardLevel(level)
if rootLevel.IsValid() == false { if !rootLevel.IsValid() {
log.Fatal("logLevel provided is invalid", "level", level) log.Fatal("logLevel provided is invalid", "level", level)
} }
@@ -57,9 +57,7 @@ func newSetCmd() *cobra.Command {
logConfig := beta.NewClientLogConfiguration(durationInMinutes, rootLevel) logConfig := beta.NewClientLogConfiguration(durationInMinutes, rootLevel)
logConfig.LogLevels = &logLevels logConfig.LogLevels = &logLevels
for i := 0; i < len(args); i++ { for _, clusterId := range args {
clusterId := args[i]
configuration, resp, err := apiClient.Beta.ManagedClustersApi.PutClientLogConfiguration(context.TODO(), clusterId).ClientLogConfiguration(*logConfig).Execute() configuration, resp, err := apiClient.Beta.ManagedClustersApi.PutClientLogConfiguration(context.TODO(), clusterId).ClientLogConfiguration(*logConfig).Execute()
if err != nil { if err != nil {

0
cmd/va/logConfig/set.md Normal file
View File

View File

@@ -3,6 +3,7 @@ package va
import ( import (
"bufio" "bufio"
"bytes" "bytes"
_ "embed"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@@ -13,6 +14,7 @@ import (
"time" "time"
"github.com/charmbracelet/log" "github.com/charmbracelet/log"
"github.com/sailpoint-oss/sailpoint-cli/internal/util"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/vbauerster/mpb/v8" "github.com/vbauerster/mpb/v8"
"github.com/vbauerster/mpb/v8/decor" "github.com/vbauerster/mpb/v8/decor"
@@ -174,7 +176,7 @@ func ErrorCheck(token []byte) bool {
return bytes.Contains(token, errorString) || bytes.Contains(token, exceptionString) return bytes.Contains(token, errorString) || bytes.Contains(token, exceptionString)
} }
func ParseCCGFile(p *mpb.Progress, filepath string, everything bool) error { func ParseCCGFile(p *mpb.Progress, filepath string, all bool) error {
file, err := os.Open(filepath) file, err := os.Open(filepath)
if err != nil { if err != nil {
return err return err
@@ -230,7 +232,7 @@ func ParseCCGFile(p *mpb.Progress, filepath string, everything bool) error {
if err != nil { if err != nil {
break break
} else { } else {
if ErrorCheck(token) || everything { if ErrorCheck(token) || all {
var line CCG var line CCG
unErr := json.Unmarshal(token, &line) unErr := json.Unmarshal(token, &line)
if unErr == nil && line.Org != "" { if unErr == nil && line.Org != "" {
@@ -250,7 +252,7 @@ func ParseCCGFile(p *mpb.Progress, filepath string, everything bool) error {
return nil return nil
} }
func ParseCanalFile(p *mpb.Progress, filepath string, everything bool) error { func ParseCanalFile(p *mpb.Progress, filepath string, all bool) error {
file, err := os.Open(filepath) file, err := os.Open(filepath)
if err != nil { if err != nil {
return err return err
@@ -318,15 +320,19 @@ func ParseCanalFile(p *mpb.Progress, filepath string, everything bool) error {
return nil return nil
} }
func newParseCmd() *cobra.Command { //go:embed parse.md
var parseHelp string
func newParseCommand() *cobra.Command {
help := util.ParseHelp(parseHelp)
var ccg bool var ccg bool
var canal bool var canal bool
var everything bool var all bool
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "parse", Use: "parse",
Short: "Parse Log Files from SailPoint Virtual Appliances", Short: "Parse Log Files from SailPoint Virtual Appliances",
Long: "\nParse Log Files from SailPoint Virtual Appliances\n\n", Long: help.Long,
Example: "sail va parse ./path/to/ccg.log ./path/to/ccg.log ./path/to/canal.log ./path/to/canal.log", Example: help.Example,
Args: cobra.MinimumNArgs(1), Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
if ccg || canal { if ccg || canal {
@@ -341,27 +347,25 @@ func newParseCmd() *cobra.Command {
log.Info("Parsing Log Files", "files", args) log.Info("Parsing Log Files", "files", args)
log.SetOutput(p) log.SetOutput(p)
for i := 0; i < len(args); i++ { for _, filepath := range args {
wg.Add(1) wg.Add(1)
filepath := args[i]
if ccg { if ccg {
go func() { go func(filepath string) {
defer wg.Done() defer wg.Done()
err := ParseCCGFile(p, filepath, everything) err := ParseCCGFile(p, filepath, all)
if err != nil { if err != nil {
log.Error("Issue Parsing log file", "file", filepath, "error", err) log.Error("Issue Parsing log file", "file", filepath, "error", err)
} }
}() }(filepath)
} else if canal { } else if canal {
go func() { go func(filepath string) {
defer wg.Done() defer wg.Done()
err := ParseCanalFile(p, filepath, everything) err := ParseCanalFile(p, filepath, all)
if err != nil { if err != nil {
log.Error("Issue Parsing log file", "file", filepath, "error", err) log.Error("Issue Parsing log file", "file", filepath, "error", err)
} }
}() }(filepath)
} }
} }
wg.Wait() wg.Wait()
@@ -375,9 +379,9 @@ func newParseCmd() *cobra.Command {
cmd.Flags().BoolVarP(&ccg, "ccg", "", false, "Specifies the provided files are CCG Files") cmd.Flags().BoolVarP(&ccg, "ccg", "", false, "Specifies the provided files are CCG Files")
cmd.Flags().BoolVarP(&canal, "canal", "", false, "Specifies the provided files are CANAL Files") cmd.Flags().BoolVarP(&canal, "canal", "", false, "Specifies the provided files are CANAL Files")
cmd.Flags().BoolVarP(&everything, "everything", "e", false, "Specifies all log traffic should be parsed, not just errors") cmd.Flags().BoolVarP(&all, "all", "a", false, "Specifies all log traffic should be parsed, not just errors")
cmd.MarkFlagsMutuallyExclusive("ccg", "canal") cmd.MarkFlagsMutuallyExclusive("ccg", "canal")
cmd.MarkFlagsMutuallyExclusive("everything", "canal") cmd.MarkFlagsMutuallyExclusive("all", "canal")
return cmd return cmd
} }

17
cmd/va/parse.md Normal file
View File

@@ -0,0 +1,17 @@
==Long==
# Parse
Parse Log Files from SailPoint Virtual Appliances
====
==Example==
```bash
sail va parse --ccg ./path/to/ccg.log ./path/to/ccg.log
sail va parse --canal ./path/to/canal.log ./path/to/canal.log
```
====

0
cmd/va/troubleshoot.md Normal file
View File

View File

@@ -19,7 +19,7 @@ func updateAndRebootVA(endpoint, password string) {
log.Info("Virtual Appliance Updating", "VA", endpoint) log.Info("Virtual Appliance Updating", "VA", endpoint)
reboot, rebootErr := va.RunVACmd(endpoint, password, RebootCommand) reboot, rebootErr := va.RunVACmd(endpoint, password, RebootCommand)
if rebootErr != nil && rebootErr.Error() != "wait: remote command exited without exit status or exit signal" { if rebootErr != nil && rebootErr.Error() != "wait: remote command exited without exit status or exit signal" {
log.Error("Problem Rebooting", "VA", endpoint, "err", rebootErr, "resp", reboot) log.Error("Problem Rebooting", "Server", endpoint, "err", rebootErr, "resp", reboot)
} else { } else {
log.Info("Virtual Appliance Rebooting", "VA", endpoint) log.Info("Virtual Appliance Rebooting", "VA", endpoint)
} }
@@ -28,7 +28,7 @@ func updateAndRebootVA(endpoint, password string) {
fmt.Println() fmt.Println()
} }
func newUpdateCmd(term terminal.Terminal) *cobra.Command { func newUpdateCommand(term terminal.Terminal) *cobra.Command {
var credentials []string var credentials []string
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "update", Use: "update",

0
cmd/va/update.md Normal file
View File

View File

@@ -2,31 +2,37 @@
package va package va
import ( import (
"fmt" _ "embed"
"github.com/sailpoint-oss/sailpoint-cli/cmd/va/list"
"github.com/sailpoint-oss/sailpoint-cli/cmd/va/logConfig" "github.com/sailpoint-oss/sailpoint-cli/cmd/va/logConfig"
"github.com/sailpoint-oss/sailpoint-cli/internal/terminal" "github.com/sailpoint-oss/sailpoint-cli/internal/terminal"
"github.com/sailpoint-oss/sailpoint-cli/internal/util"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func NewVACmd(term terminal.Terminal) *cobra.Command { //go:embed va.md
var vaHelp string
func NewVACommand(term terminal.Terminal) *cobra.Command {
help := util.ParseHelp(vaHelp)
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "va", Use: "va",
Short: "Interact with SailPoint Virtual Appliances", Short: "Manage Virtual Appliances in IdentityNow",
Long: "\nInteract with SailPoint Virtual Appliances\n\n", Long: help.Long,
Aliases: []string{"va"}, Example: help.Example,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
_, _ = fmt.Fprint(cmd.OutOrStdout(), cmd.UsageString()) cmd.Help()
}, },
} }
cmd.AddCommand( cmd.AddCommand(
newCollectCmd(term), newCollectCommand(term),
// newTroubleshootCmd(), // newTroubleshootCommand(),
newListCmd(), newParseCommand(),
newParseCmd(), newUpdateCommand(term),
newUpdateCmd(term), list.NewListCommand(),
logConfig.NewLogCmd(), logConfig.NewLogCommand(),
) )
return cmd return cmd

16
cmd/va/va.md Normal file
View File

@@ -0,0 +1,16 @@
==Long==
# VA
Manage Virtual Appliances in IdentityNow
====
==Example==
```bash
sail va
```
====

57
go.mod
View File

@@ -3,28 +3,29 @@ module github.com/sailpoint-oss/sailpoint-cli
go 1.19 go 1.19
require ( require (
github.com/charmbracelet/bubbles v0.15.0 github.com/charmbracelet/bubbles v0.16.1
github.com/charmbracelet/bubbletea v0.24.0 github.com/charmbracelet/bubbletea v0.24.2
github.com/charmbracelet/glamour v0.6.0
github.com/charmbracelet/lipgloss v0.7.1 github.com/charmbracelet/lipgloss v0.7.1
github.com/charmbracelet/log v0.2.1 github.com/charmbracelet/log v0.2.2
github.com/fatih/color v1.15.0 github.com/fatih/color v1.15.0
github.com/gocarina/gocsv v0.0.0-20230513223533-9ddd7fd60602
github.com/golang/mock v1.6.0 github.com/golang/mock v1.6.0
github.com/kr/pretty v0.3.1 github.com/kr/pretty v0.3.1
github.com/logrusorgru/aurora v2.0.3+incompatible github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/mitchellh/mapstructure v1.5.0 github.com/mitchellh/mapstructure v1.5.0
github.com/mrz1836/go-sanitize v1.3.0
github.com/olekukonko/tablewriter v0.0.5 github.com/olekukonko/tablewriter v0.0.5
github.com/pkg/sftp v1.13.5 github.com/pkg/sftp v1.13.5
github.com/sailpoint-oss/golang-sdk v1.0.5 github.com/sailpoint-oss/golang-sdk v1.1.6
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
github.com/spf13/cobra v1.7.0 github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.15.0 github.com/spf13/viper v1.16.0
github.com/vbauerster/mpb/v8 v8.4.0 github.com/vbauerster/mpb/v8 v8.5.2
golang.org/x/crypto v0.9.0 github.com/zalando/go-keyring v0.2.3
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc golang.org/x/crypto v0.11.0
golang.org/x/oauth2 v0.8.0 golang.org/x/oauth2 v0.10.0
golang.org/x/term v0.8.0 golang.org/x/term v0.10.0
gopkg.in/alessio/shellescape.v1 v1.0.0-20170105083845-52074bc9df61 gopkg.in/alessio/shellescape.v1 v1.0.0-20170105083845-52074bc9df61
gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/square/go-jose.v2 v2.6.0
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
@@ -32,21 +33,26 @@ require (
require ( require (
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.4 // indirect
) )
require ( require (
github.com/VividCortex/ewma v1.2.0 // indirect github.com/VividCortex/ewma v1.2.0 // indirect
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
github.com/alessio/shellescape v1.4.1 // indirect github.com/alecthomas/chroma v0.10.0 // indirect
github.com/alessio/shellescape v1.4.2 // indirect
github.com/atotto/clipboard v0.1.4 // indirect github.com/atotto/clipboard v0.1.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/danieljoos/wincred v1.2.0 // indirect github.com/danieljoos/wincred v1.2.0 // indirect
github.com/dlclark/regexp2 v1.10.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.3 // indirect
github.com/gorilla/css v1.0.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/kr/fs v0.1.0 // indirect github.com/kr/fs v0.1.0 // indirect
@@ -54,28 +60,31 @@ require (
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.18 // indirect github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-localereader v0.0.1 // indirect github.com/mattn/go-localereader v0.0.1 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/microcosm-cc/bluemonday v1.0.25 // indirect
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.1 // indirect github.com/muesli/termenv v0.15.2 // indirect
github.com/pelletier/go-toml/v2 v2.0.7 // indirect github.com/pelletier/go-toml/v2 v2.0.9 // indirect
github.com/rivo/uniseg v0.4.4 // indirect github.com/rivo/uniseg v0.4.4 // indirect
github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sahilm/fuzzy v0.1.0 // indirect github.com/sahilm/fuzzy v0.1.0 // indirect
github.com/spf13/afero v1.9.5 // indirect github.com/spf13/afero v1.9.5 // indirect
github.com/spf13/cast v1.5.1 // indirect github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/subosito/gotenv v1.4.2 // indirect github.com/subosito/gotenv v1.4.2 // indirect
github.com/zalando/go-keyring v0.2.3 // indirect github.com/yuin/goldmark v1.5.5 // indirect
golang.org/x/net v0.10.0 // indirect github.com/yuin/goldmark-emoji v1.0.2 // indirect
golang.org/x/sync v0.2.0 // indirect golang.org/x/net v0.12.0 // indirect
golang.org/x/sys v0.8.0 // indirect golang.org/x/sync v0.3.0 // indirect
golang.org/x/text v0.9.0 // indirect golang.org/x/sys v0.10.0 // indirect
golang.org/x/text v0.11.0 // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.30.0 // indirect google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

153
go.sum
View File

@@ -42,28 +42,28 @@ github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1o
github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
github.com/alessio/shellescape v1.4.2 h1:MHPfaU+ddJ0/bYWpgIeUnQUqKrlJ1S7BfEYPM4uEoM0=
github.com/alessio/shellescape v1.4.2/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4= github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=
github.com/aymanbagabas/go-osc52 v1.2.1/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= 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-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/charmbracelet/bubbles v0.15.0 h1:c5vZ3woHV5W2b8YZI1q7v4ZNQaPetfHuoHzx+56Z6TI= github.com/charmbracelet/bubbles v0.16.1 h1:6uzpAAaT9ZqKssntbvZMlksWHruQLNxg49H5WdeuYSY=
github.com/charmbracelet/bubbles v0.15.0/go.mod h1:Y7gSFbBzlMpUDR/XM9MhZI374Q+1p1kluf1uLl8iK74= github.com/charmbracelet/bubbles v0.16.1/go.mod h1:2QCp9LFlEsBQMvIYERr7Ww2H2bA7xen1idUDIzm/+Xc=
github.com/charmbracelet/bubbletea v0.23.1/go.mod h1:JAfGK/3/pPKHTnAS8JIE2u9f61BjWTQY57RbT25aMXU= github.com/charmbracelet/bubbletea v0.24.2 h1:uaQIKx9Ai6Gdh5zpTbGiWpytMU+CfsPp06RaW2cx/SY=
github.com/charmbracelet/bubbletea v0.23.2 h1:vuUJ9HJ7b/COy4I30e8xDVQ+VRDUEFykIjryPfgsdps= github.com/charmbracelet/bubbletea v0.24.2/go.mod h1:XdrNrV4J8GiyshTtx3DNuYkR1FDaJmO3l2nejekbsgg=
github.com/charmbracelet/bubbletea v0.23.2/go.mod h1:FaP3WUivcTM0xOKNmhciz60M6I+weYLF76mr1JyI7sM= github.com/charmbracelet/glamour v0.6.0 h1:wi8fse3Y7nfcabbbDuwolqTqMQPMnVPeZhDM273bISc=
github.com/charmbracelet/bubbletea v0.24.0 h1:l8PHrft/GIeikDPCUhQe53AJrDD8xGSn0Agirh8xbe8= github.com/charmbracelet/glamour v0.6.0/go.mod h1:taqWV4swIMMbWALc0m7AfE9JkPSU8om2538k9ITBxOc=
github.com/charmbracelet/bubbletea v0.24.0/go.mod h1:rK3g/2+T8vOSEkNHvtq40umJpeVYDn6bLaqbgzhL/hg=
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
github.com/charmbracelet/lipgloss v0.6.0/go.mod h1:tHh2wr34xcHjC2HCXIlGSG1jaDF0S0atAUvBMP6Ppuk=
github.com/charmbracelet/lipgloss v0.7.1 h1:17WMwi7N1b1rVWOjMT+rCh7sQkvDU75B2hbZpc5Kc1E= github.com/charmbracelet/lipgloss v0.7.1 h1:17WMwi7N1b1rVWOjMT+rCh7sQkvDU75B2hbZpc5Kc1E=
github.com/charmbracelet/lipgloss v0.7.1/go.mod h1:yG0k3giv8Qj8edTCbbg6AlQ5e8KNWpFujkNawKNhE2c= github.com/charmbracelet/lipgloss v0.7.1/go.mod h1:yG0k3giv8Qj8edTCbbg6AlQ5e8KNWpFujkNawKNhE2c=
github.com/charmbracelet/log v0.2.1 h1:1z7jpkk4yKyjwlmKmKMM5qnEDSpV32E7XtWhuv0mTZE= github.com/charmbracelet/log v0.2.2 h1:CaXgos+ikGn5tcws5Cw3paQuk9e/8bIwuYGhnkqQFjo=
github.com/charmbracelet/log v0.2.1/go.mod h1:GwFfjewhcVDWLrpAbY5A0Hin9YOlEn40eWT4PNaxFT4= github.com/charmbracelet/log v0.2.2/go.mod h1:Zs11hKpb8l+UyX4y1srwZIGW+MPCXJHIty3MB9l/sno=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 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/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/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -71,10 +71,9 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
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/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY= github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY=
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE= github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE=
@@ -82,6 +81,9 @@ github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0S
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -90,7 +92,6 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
@@ -99,10 +100,6 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/gocarina/gocsv v0.0.0-20230406101422-6445c2b15027 h1:LCGzZb4kMUUjMUzLxxqSJBwo9szUO0tK8cOxnEOT4Jc=
github.com/gocarina/gocsv v0.0.0-20230406101422-6445c2b15027/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI=
github.com/gocarina/gocsv v0.0.0-20230513223533-9ddd7fd60602 h1:HSpPf+lPYwzoJNup34uegmOQk5Qm83S+wpu8anTDJkg=
github.com/gocarina/gocsv v0.0.0-20230513223533-9ddd7fd60602/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -166,12 +163,14 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM=
github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUDDYFRKq/RAd0= github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA=
github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
@@ -193,7 +192,6 @@ 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 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
@@ -202,39 +200,36 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 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-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.18/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 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM=
github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg=
github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= github.com/mrz1836/go-sanitize v1.3.0 h1:ExJE6BCn1YWdopt1NPyMTfxDdTMxOMs8WsJ2GrfN1zo=
github.com/mrz1836/go-sanitize v1.3.0/go.mod h1:oakqgm7YGr+k591N0m8FVx7cOywaHr95FWmI4cDYkIc=
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= 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/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 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ=
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs=
github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc= github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc=
github.com/muesli/termenv v0.14.0/go.mod h1:kG/pF1E7fh949Xhe156crRUrHNyK221IuGO7Ez60Uc8= github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
github.com/muesli/termenv v0.15.1 h1:UzuTb/+hhlBugQz28rpzey4ZuKcZ03MeKsoG7IJZIxs= github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
github.com/muesli/termenv v0.15.1/go.mod h1:HeAQPTzpfs016yGtA4g00CsdYnVLJvxsS4ANqrZs2sQ=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us= github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
@@ -249,23 +244,18 @@ github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
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/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI= github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
github.com/sailpoint-oss/golang-sdk v1.0.3 h1:uJzKJ2+gOdVY7sbpjpvm4O4c3woAjBSx9ASMYi3bh8E= github.com/sailpoint-oss/golang-sdk v1.1.6 h1:5EZkxVDeJXl2ZZDfhnc/mgRPExCzBi1oOJSakcdItlM=
github.com/sailpoint-oss/golang-sdk v1.0.3/go.mod h1:k8tO4zw0wmivf5NjrPE2tF+ToCr6AJUV9BJnyGW4/rA= github.com/sailpoint-oss/golang-sdk v1.1.6/go.mod h1:llHaEhgszkfXiImwiwwe50WpRQm4xhFXqt19mnmcbk0=
github.com/sailpoint-oss/golang-sdk v1.0.4 h1:NLdExj3bb7NWKhHnzReP0ZiSUNR+Nlqd58HjHJtue+I=
github.com/sailpoint-oss/golang-sdk v1.0.4/go.mod h1:k8tO4zw0wmivf5NjrPE2tF+ToCr6AJUV9BJnyGW4/rA=
github.com/sailpoint-oss/golang-sdk v1.0.5 h1:eu0JGrpfzgWDXrdSXkY2sjs0vZ+2iGRN7zcntEDAE7U=
github.com/sailpoint-oss/golang-sdk v1.0.5/go.mod h1:k8tO4zw0wmivf5NjrPE2tF+ToCr6AJUV9BJnyGW4/rA=
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
@@ -274,10 +264,11 @@ github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmq
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU= github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc=
github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA= github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -285,17 +276,24 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.7.0/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.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.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
github.com/vbauerster/mpb/v8 v8.4.0 h1:Jq2iNA7T6SydpMVOwaT+2OBWlXS9Th8KEvBqeu5eeTo= github.com/vbauerster/mpb/v8 v8.5.2 h1:zanzt1cZpSEG5uGNYKcv43+97f0IgEnXpuBFaMxKbM0=
github.com/vbauerster/mpb/v8 v8.4.0/go.mod h1:vjp3hSTuCtR+x98/+2vW3eZ8XzxvGoP8CPseHMhiPyc= github.com/vbauerster/mpb/v8 v8.5.2/go.mod h1:YqKyR4ZR6Gd34yD3cDHPMmQxc+uUQMwjgO/LkxiJQ6I=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.3.7/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.5.2/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.5.5 h1:IJznPe8wOzfIKETmMkd06F8nXkmlhaHqFRM9l1hAGsU=
github.com/yuin/goldmark v1.5.5/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark-emoji v1.0.1/go.mod h1:2w1E6FEWLcDQkoTE+7HU6QF1F6SLlNGjRIBbIZQFqkQ=
github.com/yuin/goldmark-emoji v1.0.2 h1:c/RgTShNgHTtc6xdz2KKI74jJr6rWi7FPgnP9GAsO5s=
github.com/yuin/goldmark-emoji v1.0.2/go.mod h1:RhP/RWpexdp+KHs7ghKnifRoIs/Bq4nDS7tRbCkOwKY=
github.com/zalando/go-keyring v0.2.3 h1:v9CUu9phlABObO4LPWycf+zwMG7nlbb3t/B5wa97yms= github.com/zalando/go-keyring v0.2.3 h1:v9CUu9phlABObO4LPWycf+zwMG7nlbb3t/B5wa97yms=
github.com/zalando/go-keyring v0.2.3/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk= github.com/zalando/go-keyring v0.2.3/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
@@ -312,8 +310,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -324,10 +322,6 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o=
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU=
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -385,8 +379,9 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -396,8 +391,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8=
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -409,10 +404,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -444,26 +437,24 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -472,8 +463,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -620,8 +611,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/alessio/shellescape.v1 v1.0.0-20170105083845-52074bc9df61 h1:8ajkpB4hXVftY5ko905id+dOnmorcS2CHNxxHLLDcFM= gopkg.in/alessio/shellescape.v1 v1.0.0-20170105083845-52074bc9df61 h1:8ajkpB4hXVftY5ko905id+dOnmorcS2CHNxxHLLDcFM=
gopkg.in/alessio/shellescape.v1 v1.0.0-20170105083845-52074bc9df61/go.mod h1:IfMagxm39Ys4ybJrDb7W3Ob8RwxftP0Yy+or/NVz1O8= gopkg.in/alessio/shellescape.v1 v1.0.0-20170105083845-52074bc9df61/go.mod h1:IfMagxm39Ys4ybJrDb7W3Ob8RwxftP0Yy+or/NVz1O8=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@@ -50,7 +50,7 @@ type CLIConfig struct {
ActiveEnvironment string `mapstructure:"activeenvironment"` ActiveEnvironment string `mapstructure:"activeenvironment"`
Environments map[string]Environment `mapstructure:"environments"` Environments map[string]Environment `mapstructure:"environments"`
//Pipline Variables //Pipeline Variables
ClientID string `mapstructure:"clientid, omitempty"` ClientID string `mapstructure:"clientid, omitempty"`
ClientSecret string `mapstructure:"clientsecret, omitempty"` ClientSecret string `mapstructure:"clientsecret, omitempty"`
BaseURL string `mapstructure:"base_url, omitempty"` BaseURL string `mapstructure:"base_url, omitempty"`

View File

@@ -5,57 +5,45 @@ import (
"encoding/json" "encoding/json"
"os" "os"
"path" "path"
"strings"
"github.com/gocarina/gocsv" "github.com/charmbracelet/log"
"github.com/mrz1836/go-sanitize"
) )
func SaveJSONFile[T any](formattedResponse T, fileName string, folderPath string) error { func SaveJSONFile[T any](formattedResponse T, fileName string, folderPath string) error {
savePath := GetSanitizedPath(folderPath, fileName) savePath := GetSanitizedPath(folderPath, fileName, "json")
log.Debug("Saving JSON file", "file path", savePath)
dataToSave, err := json.MarshalIndent(formattedResponse, "", " ") dataToSave, err := json.MarshalIndent(formattedResponse, "", " ")
if err != nil { if err != nil {
return err return err
} }
// Make sure the output dir exists first log.Debug("Formatted Data", "data", string(dataToSave))
err = os.MkdirAll(folderPath, os.ModePerm)
if err != nil {
return err
}
file, err := os.OpenFile(savePath, os.O_CREATE|os.O_RDWR, 0777) return WriteFile(savePath, dataToSave)
}
func WriteFile(path string, data []byte) error {
file, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, 0777)
if err != nil { if err != nil {
return err return err
} }
fileWriter := bufio.NewWriter(file) fileWriter := bufio.NewWriter(file)
_, err = fileWriter.Write(dataToSave) _, err = fileWriter.Write(data)
if err != nil { if err != nil {
return err return err
} }
return nil err = fileWriter.Flush()
}
func SaveCSVFile[T any](formattedResponse T, fileName string, folderPath string) error {
savePath := GetSanitizedPath(folderPath, fileName)
// Make sure the output dir exists first
err := os.MkdirAll(folderPath, os.ModePerm)
if err != nil { if err != nil {
return err return err
} }
file, err := os.OpenFile(savePath, os.O_CREATE|os.O_RDWR, 0777) err = file.Close()
if err != nil {
return err
}
defer file.Close()
err = gocsv.MarshalFile(formattedResponse, file)
if err != nil { if err != nil {
return err return err
} }
@@ -64,7 +52,6 @@ func SaveCSVFile[T any](formattedResponse T, fileName string, folderPath string)
} }
// GetSanitizedPath makes sure the provided path works on all OS // GetSanitizedPath makes sure the provided path works on all OS
func GetSanitizedPath(filePath string, fileName string) string { func GetSanitizedPath(filePath string, fileName string, extension string) string {
p := path.Join(filePath, fileName) return path.Join(filePath, sanitize.PathName(fileName)+"."+extension)
return strings.ReplaceAll(p, ":", " ")
} }

View File

@@ -4,7 +4,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io/ioutil" "io"
"net/http" "net/http"
"github.com/charmbracelet/log" "github.com/charmbracelet/log"
@@ -26,7 +26,7 @@ type SDKResp struct {
func HandleSDKError(resp *http.Response, sdkErr error) error { func HandleSDKError(resp *http.Response, sdkErr error) error {
defer resp.Body.Close() defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body) body, err := io.ReadAll(resp.Body)
if err != nil { if err != nil {
log.Error(err) log.Error(err)
} }
@@ -43,8 +43,8 @@ func HandleSDKError(resp *http.Response, sdkErr error) error {
for _, v := range formattedBody.Messages { for _, v := range formattedBody.Messages {
outputErr = outputErr + fmt.Sprintf("%s\n", v.Text) outputErr = outputErr + fmt.Sprintf("%s\n", v.Text)
} }
} else { } else if len(body) > 0 {
outputErr = outputErr + fmt.Sprintf("%s\n", string(body))
} }
return errors.New(outputErr) return errors.New(outputErr)

View File

@@ -26,8 +26,9 @@ func ParseIndices(indices string) (sailpointsdk.Index, error) {
return sailpointsdk.INDEX_IDENTITIES, nil return sailpointsdk.INDEX_IDENTITIES, nil
case "roles": case "roles":
return sailpointsdk.INDEX_ROLES, nil return sailpointsdk.INDEX_ROLES, nil
default:
return "*", fmt.Errorf("index provided is invalid")
} }
return "*", fmt.Errorf("index provided is invalid")
} }
func BuildSearch(searchQuery string, sort []string, indices []string) (sailpointsdk.Search, error) { func BuildSearch(searchQuery string, sort []string, indices []string) (sailpointsdk.Search, error) {
@@ -120,45 +121,44 @@ func PerformSearch(apiClient sailpoint.APIClient, search sailpointsdk.Search) (S
} }
func IterateIndices(SearchResults SearchResults, searchQuery string, folderPath string, outputTypes []string) error { func IterateIndices(SearchResults SearchResults, searchQuery string, folderPath string, outputTypes []string) error {
var err error
if len(SearchResults.AccountActivities) > 0 { if len(SearchResults.AccountActivities) > 0 {
fileName := "query=" + searchQuery + "&indices=AccountActivities" fileName := "query=" + searchQuery + "&indices=AccountActivities"
err = SaveResults(SearchResults.AccountActivities, fileName, folderPath, outputTypes) err := SaveResults(SearchResults.AccountActivities, fileName, folderPath, outputTypes)
if err != nil { if err != nil {
return err return err
} }
} }
if len(SearchResults.AccessProfiles) > 0 { if len(SearchResults.AccessProfiles) > 0 {
fileName := "query=" + searchQuery + "&indices=AccessProfiles" fileName := "query=" + searchQuery + "&indices=AccessProfiles"
err = SaveResults(SearchResults.AccessProfiles, fileName, folderPath, outputTypes) err := SaveResults(SearchResults.AccessProfiles, fileName, folderPath, outputTypes)
if err != nil { if err != nil {
return err return err
} }
} }
if len(SearchResults.Entitlements) > 0 { if len(SearchResults.Entitlements) > 0 {
fileName := "query=" + searchQuery + "&indices=Entitlements" fileName := "query=" + searchQuery + "&indices=Entitlements"
err = SaveResults(SearchResults.Entitlements, fileName, folderPath, outputTypes) err := SaveResults(SearchResults.Entitlements, fileName, folderPath, outputTypes)
if err != nil { if err != nil {
return err return err
} }
} }
if len(SearchResults.Events) > 0 { if len(SearchResults.Events) > 0 {
fileName := "query=" + searchQuery + "&indices=Events" fileName := "query=" + searchQuery + "&indices=Events"
err = SaveResults(SearchResults.Events, fileName, folderPath, outputTypes) err := SaveResults(SearchResults.Events, fileName, folderPath, outputTypes)
if err != nil { if err != nil {
return err return err
} }
} }
if len(SearchResults.Identities) > 0 { if len(SearchResults.Identities) > 0 {
fileName := "query=" + searchQuery + "&indices=Identities" fileName := "query=" + searchQuery + "&indices=Identities"
err = SaveResults(SearchResults.Identities, fileName, folderPath, outputTypes) err := SaveResults(SearchResults.Identities, fileName, folderPath, outputTypes)
if err != nil { if err != nil {
return err return err
} }
} }
if len(SearchResults.Roles) > 0 { if len(SearchResults.Roles) > 0 {
fileName := "query=" + searchQuery + "&indices=Roles" fileName := "query=" + searchQuery + "&indices=Roles"
err = SaveResults(SearchResults.Roles, fileName, folderPath, outputTypes) err := SaveResults(SearchResults.Roles, fileName, folderPath, outputTypes)
if err != nil { if err != nil {
return err return err
} }
@@ -171,21 +171,12 @@ func SaveResults[T any](formattedResponse []T, fileName string, filePath string,
outputType := outputTypes[i] outputType := outputTypes[i]
switch outputType { switch outputType {
case "json": case "json":
fileName = fileName + ".json" savePath := output.GetSanitizedPath(filePath, fileName, "json")
savePath := output.GetSanitizedPath(filePath, fileName)
log.Info("Saving Results", "file", savePath) log.Info("Saving Results", "file", savePath)
err := output.SaveJSONFile(formattedResponse, fileName, filePath) err := output.SaveJSONFile(formattedResponse, fileName, filePath)
if err != nil { if err != nil {
return err return err
} }
case "csv":
fileName = fileName + ".csv"
savePath := output.GetSanitizedPath(filePath, fileName)
log.Info("Saving Results", "file", savePath)
err := output.SaveCSVFile(formattedResponse, fileName, filePath)
if err != nil {
return err
}
default: default:
return fmt.Errorf("invalid output type provided %s", outputType) return fmt.Errorf("invalid output type provided %s", outputType)
} }

View File

@@ -20,7 +20,7 @@ func PrintJob(job sailpointbetasdk.SpConfigJob) {
func DownloadExport(apiClient sailpoint.APIClient, jobId string, fileName string, folderPath string) error { func DownloadExport(apiClient sailpoint.APIClient, jobId string, fileName string, folderPath string) error {
for { for {
response, _, err := apiClient.Beta.SPConfigApi.ExportSpConfigJobStatus(context.TODO(), jobId).Execute() response, _, err := apiClient.Beta.SPConfigApi.GetSpConfigExportStatus(context.TODO(), jobId).Execute()
if err != nil { if err != nil {
return err return err
} }
@@ -31,7 +31,7 @@ func DownloadExport(apiClient sailpoint.APIClient, jobId string, fileName string
switch response.Status { switch response.Status {
case "COMPLETE": case "COMPLETE":
log.Info("Job Complete") log.Info("Job Complete")
exportData, _, err := apiClient.Beta.SPConfigApi.ExportSpConfigDownload(context.TODO(), jobId).Execute() exportData, _, err := apiClient.Beta.SPConfigApi.GetSpConfigExport(context.TODO(), jobId).Execute()
if err != nil { if err != nil {
return err return err
} }
@@ -55,7 +55,7 @@ func DownloadExport(apiClient sailpoint.APIClient, jobId string, fileName string
func DownloadImport(apiClient sailpoint.APIClient, jobId string, fileName string, folderPath string) error { func DownloadImport(apiClient sailpoint.APIClient, jobId string, fileName string, folderPath string) error {
for { for {
response, _, err := apiClient.Beta.SPConfigApi.ImportSpConfigJobStatus(context.TODO(), jobId).Execute() response, _, err := apiClient.Beta.SPConfigApi.GetSpConfigImportStatus(context.TODO(), jobId).Execute()
if err != nil { if err != nil {
return err return err
} }
@@ -66,7 +66,7 @@ func DownloadImport(apiClient sailpoint.APIClient, jobId string, fileName string
switch response.Status { switch response.Status {
case "COMPLETE": case "COMPLETE":
color.Green("Downloading Import Data") color.Green("Downloading Import Data")
importData, _, err := apiClient.Beta.SPConfigApi.ImportSpConfigDownload(context.TODO(), jobId).Execute() importData, _, err := apiClient.Beta.SPConfigApi.GetSpConfigImport(context.TODO(), jobId).Execute()
if err != nil { if err != nil {
return err return err
} }

View File

@@ -2,13 +2,71 @@ package util
import ( import (
"encoding/json" "encoding/json"
"fmt" "regexp"
"strings"
"github.com/charmbracelet/glamour"
"github.com/charmbracelet/log"
"github.com/mrz1836/go-sanitize"
) )
var renderer *glamour.TermRenderer
func init() {
var err error
renderer, err = glamour.NewTermRenderer(
// detect background color and pick either the default dark or light theme
glamour.WithAutoStyle(),
)
if err != nil {
panic(err)
}
}
func PrettyPrint(v interface{}) string { func PrettyPrint(v interface{}) string {
b, err := json.MarshalIndent(v, "", " ") b, err := json.MarshalIndent(v, "", " ")
if err != nil { if err != nil {
fmt.Println("error:", err) log.Error("Error marshalling interface", "error", err)
} }
return (string(b)) return (string(b))
} }
func SanitizeFileName(fileName string) string {
return sanitize.PathName(fileName)
}
func RenderMarkdown(markdown string) string {
out, err := renderer.Render(markdown)
if err != nil {
panic(err)
}
return out
}
type Help struct {
Long string
Example string
}
func ParseHelp(help string) Help {
helpParser, err := regexp.Compile(`==([A-Za-z]+)==([\s\S]*?)====`)
if err != nil {
panic(err)
}
matches := helpParser.FindAllStringSubmatch(help, -1)
var helpObj Help
for _, set := range matches {
switch strings.ToLower(set[1]) {
case "long":
helpObj.Long = RenderMarkdown(set[2])
case "example":
helpObj.Example = RenderMarkdown(set[2])
}
}
return helpObj
}

View File

@@ -13,7 +13,7 @@ var rootCmd *cobra.Command
func init() { func init() {
cobra.CheckErr(config.InitConfig()) cobra.CheckErr(config.InitConfig())
rootCmd = root.NewRootCmd() rootCmd = root.NewRootCommand()
} }