diff --git a/cmd/harbor/root/cmd.go b/cmd/harbor/root/cmd.go index 1bdc448d..3ff9f46e 100644 --- a/cmd/harbor/root/cmd.go +++ b/cmd/harbor/root/cmd.go @@ -9,6 +9,7 @@ import ( "github.com/goharbor/harbor-cli/cmd/harbor/root/registry" repositry "github.com/goharbor/harbor-cli/cmd/harbor/root/repository" "github.com/goharbor/harbor-cli/cmd/harbor/root/schedule" + "github.com/goharbor/harbor-cli/cmd/harbor/root/securityhub" "github.com/goharbor/harbor-cli/cmd/harbor/root/user" "github.com/goharbor/harbor-cli/pkg/utils" "github.com/spf13/cobra" @@ -69,6 +70,7 @@ harbor help HealthCommand(), schedule.Schedule(), labels.Labels(), + securityhub.SecurityHub(), ) return root diff --git a/cmd/harbor/root/securityhub/cmd.go b/cmd/harbor/root/securityhub/cmd.go new file mode 100644 index 00000000..edb2b1a9 --- /dev/null +++ b/cmd/harbor/root/securityhub/cmd.go @@ -0,0 +1,18 @@ +package securityhub + +import ( + "github.com/spf13/cobra" +) + +func SecurityHub() *cobra.Command { + cmd := &cobra.Command{ + Use: "security-hub", + Short: "Security Hub for managing security vulnerability", + Long: "Security Hub provides tools to manage, monitor, and remediate security issues in repositories", + } + cmd.AddCommand( + ListVulnerabilityCommand(), + ) + + return cmd +} diff --git a/cmd/harbor/root/securityhub/list.go b/cmd/harbor/root/securityhub/list.go new file mode 100644 index 00000000..af77f917 --- /dev/null +++ b/cmd/harbor/root/securityhub/list.go @@ -0,0 +1,42 @@ +package securityhub + +import ( + "github.com/goharbor/harbor-cli/pkg/api" + "github.com/goharbor/harbor-cli/pkg/utils" + "github.com/goharbor/harbor-cli/pkg/views/securityhub/list" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +func ListVulnerabilityCommand() *cobra.Command { + var opts api.ListFlags + + cmd := &cobra.Command{ + Use: "list", + Short: "Show all the vulnerability list", + Run: func(cmd *cobra.Command, args []string) { + vulnerability, err := api.ListVulnerability(opts) + if err != nil { + log.Fatalf("failed to get vulnerability list: %v", err) + return + } + + FormatFlag := viper.GetString("output-format") + if FormatFlag != "" { + err = utils.PrintFormat(vulnerability, FormatFlag) + if err != nil { + log.Error(err) + } + } else { + list.ListVulnerability(vulnerability.Payload) + } + }, + } + + flags := cmd.Flags() + flags.Int64VarP(&opts.Page, "page", "", 1, "Page number") + flags.Int64VarP(&opts.PageSize, "page-size", "", 10, "Size of per page") + + return cmd +} diff --git a/pkg/api/securityhub_handler.go b/pkg/api/securityhub_handler.go new file mode 100644 index 00000000..709d3dbf --- /dev/null +++ b/pkg/api/securityhub_handler.go @@ -0,0 +1,28 @@ +package api + +import ( + "github.com/goharbor/go-client/pkg/sdk/v2.0/client/securityhub" + "github.com/goharbor/harbor-cli/pkg/utils" +) + +func ListVulnerability(opts ...ListFlags) (*securityhub.ListVulnerabilitiesOK, error) { + ctx, client, err := utils.ContextWithClient() + if err != nil { + return &securityhub.ListVulnerabilitiesOK{}, err + } + + var listFlags ListFlags + if len(opts) > 0 { + listFlags = opts[0] + } + + response, err := client.Securityhub.ListVulnerabilities(ctx, + &securityhub.ListVulnerabilitiesParams{ + Page: &listFlags.Page, + PageSize: &listFlags.PageSize, + }) + if err != nil { + return &securityhub.ListVulnerabilitiesOK{}, err + } + return response, nil +} diff --git a/pkg/views/securityhub/list/view.go b/pkg/views/securityhub/list/view.go new file mode 100644 index 00000000..f452c48d --- /dev/null +++ b/pkg/views/securityhub/list/view.go @@ -0,0 +1,52 @@ +package list + +import ( + "fmt" + "os" + "strings" + + "github.com/charmbracelet/bubbles/table" + tea "github.com/charmbracelet/bubbletea" + "github.com/goharbor/go-client/pkg/sdk/v2.0/models" + "github.com/goharbor/harbor-cli/pkg/views/base/tablelist" +) + +var columns = []table.Column{ + {Title: "CVE ID", Width: 12}, + {Title: "Repository Name", Width: 12}, + {Title: "Digest", Width: 12}, + {Title: "Tags", Width: 12}, + {Title: "CVSS3", Width: 5}, + {Title: "Severity", Width: 10}, + {Title: "Package", Width: 10}, + {Title: "Current version", Width: 15}, + {Title: "Fixed in version", Width: 15}, +} + +func ListVulnerability(vulnerability []*models.VulnerabilityItem) { + var rows []table.Row + for _, vul := range vulnerability { + var tags string + if len(tags) != 0 { + tags = strings.Join(vul.Tags, ",") + } + rows = append(rows, table.Row{ + vul.CVEID, + vul.RepositoryName, + vul.Digest, + tags, + fmt.Sprintf("%.1f", vul.CvssV3Score), + vul.Severity, + vul.Package, + vul.Version, + vul.FixedVersion, + }) + } + + m := tablelist.NewModel(columns, rows, len(rows)) + + if _, err := tea.NewProgram(m).Run(); err != nil { + fmt.Println("Error running program:", err) + os.Exit(1) + } +}