From a84d32dba21609a76029fece60cc27acc244d98f Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Mon, 18 Dec 2023 17:39:58 -0500 Subject: [PATCH 1/3] add cataloger list command Signed-off-by: Alex Goodman --- cmd/syft/cli/cli.go | 1 + cmd/syft/cli/commands/attest.go | 2 +- cmd/syft/cli/commands/cataloger.go | 20 ++ cmd/syft/cli/commands/cataloger_list.go | 240 ++++++++++++++++++++++++ go.mod | 9 +- 5 files changed, 265 insertions(+), 7 deletions(-) create mode 100644 cmd/syft/cli/commands/cataloger.go create mode 100644 cmd/syft/cli/commands/cataloger_list.go diff --git a/cmd/syft/cli/cli.go b/cmd/syft/cli/cli.go index 15c33067905..179533ce4dd 100644 --- a/cmd/syft/cli/cli.go +++ b/cmd/syft/cli/cli.go @@ -86,6 +86,7 @@ func create(id clio.Identification, out io.Writer) (clio.Application, *cobra.Com rootCmd.AddCommand( scanCmd, commands.Packages(app, scanCmd), // this is currently an alias for the scan command + commands.Cataloger(app), commands.Attest(app), commands.Convert(app), clio.VersionCommand(id), diff --git a/cmd/syft/cli/commands/attest.go b/cmd/syft/cli/commands/attest.go index b1ec9fc6790..166ad63d303 100644 --- a/cmd/syft/cli/commands/attest.go +++ b/cmd/syft/cli/commands/attest.go @@ -232,7 +232,7 @@ func attestCommand(sbomFilepath string, opts *attestOptions, userInput string) ( } func predicateType(outputName string) string { - // Select Cosign predicate type based on defined output type + // select the Cosign predicate type based on defined output type // As orientation, check: https://github.com/sigstore/cosign/blob/main/pkg/cosign/attestation/attestation.go switch strings.ToLower(outputName) { case "cyclonedx-json": diff --git a/cmd/syft/cli/commands/cataloger.go b/cmd/syft/cli/commands/cataloger.go new file mode 100644 index 00000000000..0baf5b5231a --- /dev/null +++ b/cmd/syft/cli/commands/cataloger.go @@ -0,0 +1,20 @@ +package commands + +import ( + "github.com/spf13/cobra" + + "github.com/anchore/clio" +) + +func Cataloger(app clio.Application) *cobra.Command { + cmd := &cobra.Command{ + Use: "cataloger", + Short: "Show available catalogers and configuration", + } + + cmd.AddCommand( + CatalogerList(app), + ) + + return cmd +} diff --git a/cmd/syft/cli/commands/cataloger_list.go b/cmd/syft/cli/commands/cataloger_list.go new file mode 100644 index 00000000000..be371309721 --- /dev/null +++ b/cmd/syft/cli/commands/cataloger_list.go @@ -0,0 +1,240 @@ +package commands + +import ( + "encoding/json" + "fmt" + "sort" + "strings" + + "github.com/charmbracelet/lipgloss" + "github.com/jedib0t/go-pretty/v6/table" + "github.com/scylladb/go-set/strset" + "github.com/spf13/cobra" + + "github.com/anchore/clio" + "github.com/anchore/syft/internal/bus" + "github.com/anchore/syft/internal/task" + "github.com/anchore/syft/syft/cataloging/pkgcataloging" +) + +type catalogerListOptions struct { + Output string `yaml:"output" json:"output" mapstructure:"output"` + DefaultCatalogers []string `yaml:"default-catalogers" json:"default-catalogers" mapstructure:"default-catalogers"` + SelectCatalogers []string `yaml:"select-catalogers" json:"select-catalogers" mapstructure:"select-catalogers"` + ShowHidden bool `yaml:"show-hidden" json:"show-hidden" mapstructure:"show-hidden"` +} + +func (o *catalogerListOptions) AddFlags(flags clio.FlagSet) { + flags.StringVarP(&o.Output, "output", "o", "format to output the cataloger list (available: table, json)") + + flags.StringArrayVarP(&o.DefaultCatalogers, "override-default-catalogers", "", "override the default catalogers with an expression") + + flags.StringArrayVarP(&o.SelectCatalogers, "select-catalogers", "", "select catalogers with an expression") + + flags.BoolVarP(&o.ShowHidden, "show-hidden", "s", "show catalogers that have been de-selected") +} + +func CatalogerList(app clio.Application) *cobra.Command { + opts := &catalogerListOptions{ + DefaultCatalogers: []string{"all"}, + } + + return app.SetupCommand(&cobra.Command{ + Use: "list [OPTIONS]", + Short: "List available catalogers", + RunE: func(cmd *cobra.Command, args []string) error { + return runCatalogerList(opts) + }, + }, opts) +} + +func runCatalogerList(opts *catalogerListOptions) error { + factories := task.DefaultPackageTaskFactories() + allTasks, err := factories.Tasks(task.DefaultCatalogingFactoryConfig()) + if err != nil { + return fmt.Errorf("unable to create cataloger tasks: %w", err) + } + + selectedTasks, selectionEvidence, err := task.Select(allTasks, + pkgcataloging.NewSelectionRequest(). + WithDefaults(opts.DefaultCatalogers...). + WithExpression(opts.SelectCatalogers...), + ) + if err != nil { + return fmt.Errorf("unable to select catalogers: %w", err) + } + + var report string + + switch opts.Output { + case "json": + report, err = renderCatalogerListJSON(selectedTasks, selectionEvidence, opts.SelectCatalogers) + case "table", "": + if opts.ShowHidden { + report = renderCatalogerListTable(allTasks, selectionEvidence, opts.SelectCatalogers) + } else { + report = renderCatalogerListTable(selectedTasks, selectionEvidence, opts.SelectCatalogers) + } + } + + if err != nil { + return fmt.Errorf("unable to render cataloger list: %w", err) + } + + bus.Report(report) + + return nil +} + +func renderCatalogerListJSON(tasks []task.Task, selection task.Selection, expressions []string) (string, error) { + type node struct { + Name string `json:"name"` + Tags []string `json:"tags"` + } + + names, tagsByName := extractTaskInfo(tasks) + + nodesByName := make(map[string]node) + + for name := range tagsByName { + tagsSelected := selection.TokensByTask[name].SelectedOn.List() + sort.Strings(tagsSelected) + + if tagsSelected == nil { + // ensure collections are not null + tagsSelected = []string{} + } + + nodesByName[name] = node{ + Name: name, + Tags: tagsSelected, + } + } + + type document struct { + Expressions []string `json:"expressions"` + Catalogers []node `json:"catalogers"` + } + + if expressions == nil { + // ensure collections are not null + expressions = []string{} + } + + doc := document{ + Expressions: expressions, + } + + for _, name := range names { + doc.Catalogers = append(doc.Catalogers, nodesByName[name]) + } + + by, err := json.Marshal(doc) + + return string(by), err +} + +func renderCatalogerListTable(tasks []task.Task, selection task.Selection, expressions []string) string { + t := table.NewWriter() + t.SetStyle(table.StyleLight) + t.AppendHeader(table.Row{"Cataloger", "Tags"}) + + names, tagsByName := extractTaskInfo(tasks) + + rowsByName := make(map[string]table.Row) + + for name, tags := range tagsByName { + rowsByName[name] = formatRow(name, tags, selection) + } + + for _, name := range names { + t.AppendRow(rowsByName[name]) + } + + report := t.Render() + + if len(expressions) > 0 { + header := "Selected by expressions:\n" + for _, expr := range expressions { + header += fmt.Sprintf(" - %q\n", expr) + } + report = header + report + } + + return report +} + +func formatRow(name string, tags []string, selection task.Selection) table.Row { + isIncluded := selection.Result.Has(name) + var selections *task.TokenSelection + if s, exists := selection.TokensByTask[name]; exists { + selections = &s + } + + var formattedTags []string + for _, tag := range tags { + formattedTags = append(formattedTags, formatToken(tag, selections, isIncluded)) + } + + var tagStr string + if isIncluded { + tagStr = strings.Join(formattedTags, ", ") + } else { + tagStr = strings.Join(formattedTags, grey.Render(", ")) + } + + // TODO: selection should keep warnings (non-selections) in struct + + return table.Row{ + formatToken(name, selections, isIncluded), + tagStr, + } +} + +var ( + green = lipgloss.NewStyle().Foreground(lipgloss.Color("10")) // hi green + grey = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) // dark grey + red = lipgloss.NewStyle().Foreground(lipgloss.Color("9")) // high red +) + +func formatToken(token string, selection *task.TokenSelection, included bool) string { + if included && selection != nil { + // format all tokens in selection in green + if selection.SelectedOn.Has(token) { + return green.Render(token) + } + + return token + } + + // format all tokens in selection in red, all others in grey + if selection != nil && selection.DeselectedOn.Has(token) { + return red.Render(token) + } + + return grey.Render(token) +} + +func extractTaskInfo(tasks []task.Task) ([]string, map[string][]string) { + tagsByName := make(map[string][]string) + var names []string + + for _, tsk := range tasks { + var tags []string + name := tsk.Name() + + if s, ok := tsk.(task.Selector); ok { + set := strset.New(s.Selectors()...) + set.Remove(name) + tags = set.List() + sort.Strings(tags) + } + + tagsByName[name] = tags + names = append(names, name) + } + + sort.Strings(names) + + return names, tagsByName +} diff --git a/go.mod b/go.mod index e8c2fa6e3f8..3728415fffd 100644 --- a/go.mod +++ b/go.mod @@ -17,10 +17,12 @@ require ( github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b github.com/anchore/packageurl-go v0.1.1-0.20230104203445-02e0a6721501 github.com/anchore/stereoscope v0.0.0-20231220161148-590920dabc54 + github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // we are hinting brotli to latest due to warning when installing archiver v3: // go: warning: github.com/andybalholm/brotli@v1.0.1: retracted by module author: occasional panics and data corruption github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 github.com/bmatcuk/doublestar/v4 v4.6.1 + github.com/charmbracelet/bubbles v0.17.1 github.com/charmbracelet/bubbletea v0.25.0 github.com/charmbracelet/lipgloss v0.9.1 github.com/dave/jennifer v1.7.0 @@ -42,6 +44,7 @@ require ( github.com/hashicorp/go-multierror v1.1.1 github.com/iancoleman/strcase v0.3.0 github.com/invopop/jsonschema v0.7.0 + github.com/jedib0t/go-pretty/v6 v6.5.2 github.com/jinzhu/copier v0.4.0 github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953 github.com/knqyf263/go-rpmdb v0.0.0-20230301153543-ba94b245509b @@ -76,12 +79,6 @@ require ( modernc.org/sqlite v1.28.0 ) -require ( - github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be - github.com/charmbracelet/bubbles v0.17.1 - github.com/jedib0t/go-pretty/v6 v6.5.2 -) - require ( dario.cat/mergo v1.0.0 // indirect github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect From 9540dbefea2b093da92520f0558cf721ee1d2e3e Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Mon, 15 Jan 2024 14:36:14 -0500 Subject: [PATCH 2/3] add tests Signed-off-by: Alex Goodman --- cmd/syft/cli/commands/attest.go | 2 +- cmd/syft/cli/commands/cataloger_list.go | 67 +++++-- cmd/syft/cli/commands/cataloger_list_test.go | 201 +++++++++++++++++++ cmd/syft/cli/commands/packages.go | 14 +- 4 files changed, 258 insertions(+), 26 deletions(-) create mode 100644 cmd/syft/cli/commands/cataloger_list_test.go diff --git a/cmd/syft/cli/commands/attest.go b/cmd/syft/cli/commands/attest.go index 166ad63d303..71e69b558a9 100644 --- a/cmd/syft/cli/commands/attest.go +++ b/cmd/syft/cli/commands/attest.go @@ -30,7 +30,7 @@ import ( ) const ( - attestExample = ` {{.appName}} {{.command}} --output [FORMAT] alpine:latest defaults to using images from a Docker daemon. If Docker is not present, the image is pulled directly from the registry + attestExample = ` {{.appName}} {{.command}} --output [FORMAT] alpine:latest defaults to using images from a Docker daemon. If Docker is not present, the image is pulled directly from the registry ` attestSchemeHelp = "\n " + schemeHelpHeader + "\n" + imageSchemeHelp attestHelp = attestExample + attestSchemeHelp diff --git a/cmd/syft/cli/commands/cataloger_list.go b/cmd/syft/cli/commands/cataloger_list.go index be371309721..265f260102c 100644 --- a/cmd/syft/cli/commands/cataloger_list.go +++ b/cmd/syft/cli/commands/cataloger_list.go @@ -34,10 +34,14 @@ func (o *catalogerListOptions) AddFlags(flags clio.FlagSet) { flags.BoolVarP(&o.ShowHidden, "show-hidden", "s", "show catalogers that have been de-selected") } -func CatalogerList(app clio.Application) *cobra.Command { - opts := &catalogerListOptions{ +func defaultCatalogerListOptions() *catalogerListOptions { + return &catalogerListOptions{ DefaultCatalogers: []string{"all"}, } +} + +func CatalogerList(app clio.Application) *cobra.Command { + opts := defaultCatalogerListOptions() return app.SetupCommand(&cobra.Command{ Use: "list [OPTIONS]", @@ -55,38 +59,46 @@ func runCatalogerList(opts *catalogerListOptions) error { return fmt.Errorf("unable to create cataloger tasks: %w", err) } + report, err := catalogerListReport(opts, allTasks) + if err != nil { + return fmt.Errorf("unable to generate cataloger list report: %w", err) + } + + bus.Report(report) + + return nil +} + +func catalogerListReport(opts *catalogerListOptions, allTasks []task.Task) (string, error) { selectedTasks, selectionEvidence, err := task.Select(allTasks, pkgcataloging.NewSelectionRequest(). WithDefaults(opts.DefaultCatalogers...). WithExpression(opts.SelectCatalogers...), ) if err != nil { - return fmt.Errorf("unable to select catalogers: %w", err) + return "", fmt.Errorf("unable to select catalogers: %w", err) } - var report string switch opts.Output { case "json": - report, err = renderCatalogerListJSON(selectedTasks, selectionEvidence, opts.SelectCatalogers) + report, err = renderCatalogerListJSON(selectedTasks, selectionEvidence, opts.DefaultCatalogers, opts.SelectCatalogers) case "table", "": if opts.ShowHidden { - report = renderCatalogerListTable(allTasks, selectionEvidence, opts.SelectCatalogers) + report = renderCatalogerListTable(allTasks, selectionEvidence, opts.DefaultCatalogers, opts.SelectCatalogers) } else { - report = renderCatalogerListTable(selectedTasks, selectionEvidence, opts.SelectCatalogers) + report = renderCatalogerListTable(selectedTasks, selectionEvidence, opts.DefaultCatalogers, opts.SelectCatalogers) } } if err != nil { - return fmt.Errorf("unable to render cataloger list: %w", err) + return "", fmt.Errorf("unable to render cataloger list: %w", err) } - bus.Report(report) - - return nil + return report, nil } -func renderCatalogerListJSON(tasks []task.Task, selection task.Selection, expressions []string) (string, error) { +func renderCatalogerListJSON(tasks []task.Task, selection task.Selection, defaultSelections, selections []string) (string, error) { type node struct { Name string `json:"name"` Tags []string `json:"tags"` @@ -98,6 +110,11 @@ func renderCatalogerListJSON(tasks []task.Task, selection task.Selection, expres for name := range tagsByName { tagsSelected := selection.TokensByTask[name].SelectedOn.List() + + if len(tagsSelected) == 1 && tagsSelected[0] == "all" { + tagsSelected = tagsByName[name] + } + sort.Strings(tagsSelected) if tagsSelected == nil { @@ -112,17 +129,19 @@ func renderCatalogerListJSON(tasks []task.Task, selection task.Selection, expres } type document struct { - Expressions []string `json:"expressions"` - Catalogers []node `json:"catalogers"` + DefaultSelection []string `json:"default"` + Selection []string `json:"selection"` + Catalogers []node `json:"catalogers"` } - if expressions == nil { + if selections == nil { // ensure collections are not null - expressions = []string{} + selections = []string{} } doc := document{ - Expressions: expressions, + DefaultSelection: defaultSelections, + Selection: selections, } for _, name := range names { @@ -134,7 +153,7 @@ func renderCatalogerListJSON(tasks []task.Task, selection task.Selection, expres return string(by), err } -func renderCatalogerListTable(tasks []task.Task, selection task.Selection, expressions []string) string { +func renderCatalogerListTable(tasks []task.Task, selection task.Selection, defaultSelections, selections []string) string { t := table.NewWriter() t.SetStyle(table.StyleLight) t.AppendHeader(table.Row{"Cataloger", "Tags"}) @@ -153,9 +172,17 @@ func renderCatalogerListTable(tasks []task.Task, selection task.Selection, expre report := t.Render() - if len(expressions) > 0 { + if len(selections) > 0 { header := "Selected by expressions:\n" - for _, expr := range expressions { + for _, expr := range selections { + header += fmt.Sprintf(" - %q\n", expr) + } + report = header + report + } + + if len(defaultSelections) > 0 { + header := "Default selections:\n" + for _, expr := range defaultSelections { header += fmt.Sprintf(" - %q\n", expr) } report = header + report diff --git a/cmd/syft/cli/commands/cataloger_list_test.go b/cmd/syft/cli/commands/cataloger_list_test.go new file mode 100644 index 00000000000..24d8ab1f20c --- /dev/null +++ b/cmd/syft/cli/commands/cataloger_list_test.go @@ -0,0 +1,201 @@ +package commands + +import ( + "context" + "strings" + "testing" + + "github.com/scylladb/go-set/strset" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/anchore/syft/internal/sbomsync" + "github.com/anchore/syft/internal/task" + "github.com/anchore/syft/syft/file" +) + +var _ interface { + task.Task + task.Selector +} = (*dummyTask)(nil) + +type dummyTask struct { + name string + selectors []string +} + +func (d dummyTask) HasAllSelectors(s ...string) bool { + return strset.New(d.selectors...).Has(s...) +} + +func (d dummyTask) Selectors() []string { + return d.selectors +} + +func (d dummyTask) Name() string { + return d.name +} + +func (d dummyTask) Execute(_ context.Context, _ file.Resolver, _ sbomsync.Builder) error { + panic("implement me") +} + +func testTasks() []task.Task { + return []task.Task{ + dummyTask{ + name: "task1", + selectors: []string{"image", "a", "b", "1"}, + }, + dummyTask{ + name: "task2", + selectors: []string{"image", "b", "c", "2"}, + }, + dummyTask{ + name: "task3", + selectors: []string{"directory", "c", "d", "3"}, + }, + dummyTask{ + name: "task4", + selectors: []string{"directory", "d", "e", "4"}, + }, + } +} + +func Test_catalogerListReport(t *testing.T) { + tests := []struct { + name string + options *catalogerListOptions + want string + wantErr require.ErrorAssertionFunc + }{ + { + name: "no expressions, table", + options: func() *catalogerListOptions { + c := defaultCatalogerListOptions() + c.Output = "table" + return c + }(), + want: ` +Default selections: + - "all" +┌───────────┬────────────────────┐ +│ CATALOGER │ TAGS │ +├───────────┼────────────────────┤ +│ task1 │ 1, a, b, image │ +│ task2 │ 2, b, c, image │ +│ task3 │ 3, c, d, directory │ +│ task4 │ 4, d, directory, e │ +└───────────┴────────────────────┘ +`, + }, + { + name: "no expressions, json", + options: func() *catalogerListOptions { + c := defaultCatalogerListOptions() + c.Output = "json" + return c + }(), + want: ` +{"default":["all"],"selection":[],"catalogers":[{"name":"task1","tags":["1","a","b","image"]},{"name":"task2","tags":["2","b","c","image"]},{"name":"task3","tags":["3","c","d","directory"]},{"name":"task4","tags":["4","d","directory","e"]}]} +`, + }, + { + name: "no expressions, default selection, table", + options: func() *catalogerListOptions { + c := defaultCatalogerListOptions() + c.Output = "table" + c.DefaultCatalogers = []string{ + "image", + } + return c + }(), + want: ` +Default selections: + - "image" +┌───────────┬────────────────┐ +│ CATALOGER │ TAGS │ +├───────────┼────────────────┤ +│ task1 │ 1, a, b, image │ +│ task2 │ 2, b, c, image │ +└───────────┴────────────────┘ +`, + }, + { + name: "no expressions, default selection, json", + options: func() *catalogerListOptions { + c := defaultCatalogerListOptions() + c.Output = "json" + c.DefaultCatalogers = []string{ + "image", + } + return c + }(), + want: ` +{"default":["image"],"selection":[],"catalogers":[{"name":"task1","tags":["image"]},{"name":"task2","tags":["image"]}]} +`, + }, + { + name: "with expressions, default selection, table", + options: func() *catalogerListOptions { + c := defaultCatalogerListOptions() + c.Output = "table" + c.DefaultCatalogers = []string{ + "image", + } + c.SelectCatalogers = []string{ + "-directory", + "+task3", + "-c", + "b", + } + return c + }(), + want: ` +Default selections: + - "image" +Selected by expressions: + - "-directory" + - "+task3" + - "-c" + - "b" +┌───────────┬────────────────────┐ +│ CATALOGER │ TAGS │ +├───────────┼────────────────────┤ +│ task1 │ 1, a, b, image │ +│ task3 │ 3, c, d, directory │ +└───────────┴────────────────────┘ +`, + }, + { + name: "with expressions, default selection, json", + options: func() *catalogerListOptions { + c := defaultCatalogerListOptions() + c.Output = "json" + c.DefaultCatalogers = []string{ + "image", + } + c.SelectCatalogers = []string{ + "-directory", + "+task3", + "-c", + "b", + } + return c + }(), + want: ` +{"default":["image"],"selection":["-directory","+task3","-c","b"],"catalogers":[{"name":"task1","tags":["b","image"]},{"name":"task3","tags":["task3"]}]} +`, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.wantErr == nil { + tt.wantErr = require.NoError + } + + got, err := catalogerListReport(tt.options, testTasks()) + tt.wantErr(t, err) + assert.Equal(t, strings.TrimSpace(tt.want), strings.TrimSpace(got)) + }) + } +} diff --git a/cmd/syft/cli/commands/packages.go b/cmd/syft/cli/commands/packages.go index 18d29cf07ba..92f225d1d57 100644 --- a/cmd/syft/cli/commands/packages.go +++ b/cmd/syft/cli/commands/packages.go @@ -5,6 +5,7 @@ import ( "github.com/anchore/clio" "github.com/anchore/syft/cmd/syft/internal/ui" + "github.com/anchore/syft/internal" ) func Packages(app clio.Application, scanCmd *cobra.Command) *cobra.Command { @@ -13,11 +14,14 @@ func Packages(app clio.Application, scanCmd *cobra.Command) *cobra.Command { opts := defaultScanOptions() cmd := app.SetupCommand(&cobra.Command{ - Use: "packages [SOURCE]", - Short: scanCmd.Short, - Long: scanCmd.Long, - Args: scanCmd.Args, - Example: scanCmd.Example, + Use: "packages [SOURCE]", + Short: scanCmd.Short, + Long: scanCmd.Long, + Args: scanCmd.Args, + Example: internal.Tprintf(scanHelp, map[string]interface{}{ + "appName": id.Name, + "command": "packages", + }), PreRunE: applicationUpdateCheck(id, &opts.UpdateCheck), RunE: func(cmd *cobra.Command, args []string) error { restoreStdout := ui.CaptureStdoutToTraceLog() From 0bf4b0883c22bbb56a55f9d419ed6306753bd2c9 Mon Sep 17 00:00:00 2001 From: Christopher Phillips Date: Tue, 16 Jan 2024 09:00:00 -0500 Subject: [PATCH 3/3] chore: tidy go mod Signed-off-by: Christopher Phillips --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index e20d31db6eb..3728415fffd 100644 --- a/go.mod +++ b/go.mod @@ -242,4 +242,4 @@ require ( retract ( v0.53.2 v0.53.1 // Published accidentally with incorrect license in depdencies -) \ No newline at end of file +) diff --git a/go.sum b/go.sum index da9b98bcef3..a401e8de869 100644 --- a/go.sum +++ b/go.sum @@ -466,8 +466,8 @@ github.com/invopop/jsonschema v0.7.0 h1:2vgQcBz1n256N+FpX3Jq7Y17AjYt46Ig3zIWyy77 github.com/invopop/jsonschema v0.7.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jedib0t/go-pretty/v6 v6.5.3 h1:GIXn6Er/anHTkVUoufs7ptEvxdD6KIhR7Axa2wYCPF0= -github.com/jedib0t/go-pretty/v6 v6.5.3/go.mod h1:5LQIxa52oJ/DlDSLv0HEkWOFMDGoWkJb9ss5KqPpJBg= +github.com/jedib0t/go-pretty/v6 v6.5.2 h1:1zphkAo77tdoCkdqIYsMHoXmEGTnTy3GZ6Mn+NyIro0= +github.com/jedib0t/go-pretty/v6 v6.5.2/go.mod h1:5LQIxa52oJ/DlDSLv0HEkWOFMDGoWkJb9ss5KqPpJBg= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=