Skip to content

Commit

Permalink
feat: add summary subcommand
Browse files Browse the repository at this point in the history
Signed-off-by: Alan Tang <jmtangcs@gmail.com>
  • Loading branch information
Standing-Man committed Jan 8, 2025
1 parent bdc32f1 commit 27c9ec3
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 12 deletions.
7 changes: 4 additions & 3 deletions cmd/harbor/root/securityhub/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import (

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",
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(),
SummaryVulnerabilityCommand(),
)

return cmd
Expand Down
106 changes: 106 additions & 0 deletions cmd/harbor/root/securityhub/summay.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
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/summary"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

func SummaryVulnerabilityCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "summary",
Short: "The vulnerability summary of the system",
}

cmd.AddCommand(
totalVulnerabilities(),
MostDangerousArtifacts(),
MostDangerousCVE(),
)

return cmd
}

func totalVulnerabilities() *cobra.Command {
cmd := &cobra.Command{
Use: "total",
Short: "Total Vulnerabilities",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
sum, err := api.GetTotalVulnerabilities(false, false)

if err != nil {
log.Fatalf("failed to get vulnerability summary: %v", err)
return
}
FormatFlag := viper.GetString("output-format")
if FormatFlag != "" {
err = utils.PrintFormat(sum, FormatFlag)
if err != nil {
log.Error(err)
}
} else {
summary.GetTotalVulnerability(sum.Payload)
}
},
}

return cmd
}

func MostDangerousArtifacts() *cobra.Command {
cmd := &cobra.Command{
Use: "artifact",
Short: "Top 5 Most Dangerous Artifacts",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
sum, err := api.GetTotalVulnerabilities(true, false)

if err != nil {
log.Fatalf("failed to get most dangerous artifacts: %v", err)
return
}
FormatFlag := viper.GetString("output-format")
if FormatFlag != "" {
err = utils.PrintFormat(sum, FormatFlag)
if err != nil {
log.Error(err)
}
} else {
summary.ShowMostDangerousArtifacts(sum.Payload)
}
},
}

return cmd
}

func MostDangerousCVE() *cobra.Command {
cmd := &cobra.Command{
Use: "cvelist",
Short: "Top 5 Most Dangerous CVEs",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
sum, err := api.GetTotalVulnerabilities(false, true)

if err != nil {
log.Fatalf("failed to get most dangerous cvelist: %v", err)
return
}
FormatFlag := viper.GetString("output-format")
if FormatFlag != "" {
err = utils.PrintFormat(sum, FormatFlag)
if err != nil {
log.Error(err)
}
} else {
summary.ShowMostDangerousCVE(sum.Payload)
}
},
}

return cmd
}
16 changes: 16 additions & 0 deletions pkg/api/securityhub_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,19 @@ func ListVulnerability(opts ...ListFlags) (*securityhub.ListVulnerabilitiesOK, e
}
return response, nil
}

func GetTotalVulnerabilities(withArtifact, WithCVE bool) (*securityhub.GetSecuritySummaryOK, error) {
ctx, client, err := utils.ContextWithClient()
if err != nil {
return &securityhub.GetSecuritySummaryOK{}, err
}
response, err := client.Securityhub.GetSecuritySummary(ctx, &securityhub.GetSecuritySummaryParams{
WithDangerousArtifact: &withArtifact,
WithDangerousCVE: &WithCVE,
})
if err != nil {
return &securityhub.GetSecuritySummaryOK{}, err
}

return response, nil
}
18 changes: 9 additions & 9 deletions pkg/views/securityhub/list/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package list
import (
"fmt"
"os"
"strings"

"github.com/charmbracelet/bubbles/table"
tea "github.com/charmbracelet/bubbletea"
Expand All @@ -12,28 +11,28 @@ import (
)

var columns = []table.Column{
{Title: "CVE ID", Width: 12},
{Title: "Repository Name", Width: 12},
{Title: "Digest", Width: 12},
{Title: "CVE ID", Width: 15},
{Title: "Repository Name", Width: 20},
{Title: "Digest", Width: 20},
{Title: "Tags", Width: 12},
{Title: "CVSS3", Width: 5},
{Title: "Severity", Width: 10},
{Title: "Package", Width: 10},
{Title: "Package", Width: 20},
{Title: "Current version", Width: 15},
{Title: "Fixed in version", Width: 15},
{Title: "Fixed in version", Width: 20},
}

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, ",")
for tag := range vul.Tags {
fmt.Println(tag)
}
rows = append(rows, table.Row{
vul.CVEID,
vul.RepositoryName,
vul.Digest,
vul.Digest[:16],
tags,
fmt.Sprintf("%.1f", vul.CvssV3Score),
vul.Severity,
Expand All @@ -50,3 +49,4 @@ func ListVulnerability(vulnerability []*models.VulnerabilityItem) {
os.Exit(1)
}
}

94 changes: 94 additions & 0 deletions pkg/views/securityhub/summary/view.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package summary

import (
"fmt"
"os"

"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_total = []table.Column{
{Title: "Critical", Width: 10},
{Title: "High", Width: 10},
{Title: "Medium", Width: 10},
{Title: "Low", Width: 10},
{Title: "N/A", Width: 10},
{Title: "None", Width: 10},
}

func GetTotalVulnerability(item *models.SecuritySummary) {
var rows []table.Row
fmt.Printf("%d total with %d fixable\n", item.TotalVuls, item.FixableCnt)
rows = append(rows, table.Row{
fmt.Sprintf("%d", item.CriticalCnt),
fmt.Sprintf("%d", item.HighCnt),
fmt.Sprintf("%d", item.MediumCnt),
fmt.Sprintf("%d", item.LowCnt),
fmt.Sprintf("%d", item.UnknownCnt),
fmt.Sprintf("%d", item.NoneCnt),
})

m := tablelist.NewModel(columns_total, rows, len(rows)+1)

if _, err := tea.NewProgram(m).Run(); err != nil {
fmt.Println("Error running program:", err)
os.Exit(1)
}
}

var columns_artifact = []table.Column{
{Title: "Repository Name", Width: 15},
{Title: "Digest", Width: 15},
{Title: "Critical", Width: 10},
{Title: "High", Width: 10},
{Title: "Medium", Width: 10},
}

func ShowMostDangerousArtifacts(item *models.SecuritySummary) {
var rows []table.Row
for _, artifact := range item.DangerousArtifacts {
rows = append(rows, table.Row{
artifact.RepositoryName,
artifact.Digest[:16],
fmt.Sprintf("%d", item.CriticalCnt),
fmt.Sprintf("%d", item.HighCnt),
fmt.Sprintf("%d", item.MediumCnt),
})
}

m := tablelist.NewModel(columns_artifact, rows, len(rows)+1)

if _, err := tea.NewProgram(m).Run(); err != nil {
fmt.Println("Error running program:", err)
os.Exit(1)
}
}

var columns_cve = []table.Column{
{Title: "CVE ID", Width: 15},
{Title: "Severity", Width: 15},
{Title: "CVSS3", Width: 5},
{Title: "Package", Width: 15},
}

func ShowMostDangerousCVE(item *models.SecuritySummary) {
var rows []table.Row
for _, cve := range item.DangerousCves {
rows = append(rows, table.Row{
cve.CVEID,
cve.Severity,
fmt.Sprintf("%.1f", cve.CvssScoreV3),
cve.Package,
})
}

m := tablelist.NewModel(columns_cve, rows, len(rows)+1)

if _, err := tea.NewProgram(m).Run(); err != nil {
fmt.Println("Error running program:", err)
os.Exit(1)
}
}

0 comments on commit 27c9ec3

Please sign in to comment.