Add prefix options for the status command
This commit is contained in:
@@ -32,6 +32,7 @@ import (
|
||||
|
||||
var (
|
||||
sessionNameFlag string
|
||||
sessionPrefixFlag string
|
||||
outputDirFlag string
|
||||
downloadDBsFlag bool
|
||||
nwoFlag string
|
||||
|
||||
184
cmd/status.go
184
cmd/status.go
@@ -1,126 +1,156 @@
|
||||
/*
|
||||
Copyright © 2023 NAME HERE <EMAIL ADDRESS>
|
||||
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"log"
|
||||
|
||||
"github.com/GitHubSecurityLab/gh-mrva/models"
|
||||
"github.com/GitHubSecurityLab/gh-mrva/utils"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/GitHubSecurityLab/gh-mrva/utils"
|
||||
"github.com/GitHubSecurityLab/gh-mrva/models"
|
||||
)
|
||||
|
||||
var statusCmd = &cobra.Command{
|
||||
Use: "status",
|
||||
Short: "Checks the status of a given session.",
|
||||
Long: `Checks the status of a given session.`,
|
||||
Long: `Checks the status of a given session.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
sessionStatus()
|
||||
sessionStatus()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(statusCmd)
|
||||
statusCmd.Flags().StringVarP(&sessionNameFlag, "session", "s", "", "Session name be deleted")
|
||||
statusCmd.Flags().StringVarP(&sessionNameFlag, "session", "s", "", "Selects the named session")
|
||||
statusCmd.Flags().StringVarP(&sessionPrefixFlag, "prefix", "p", "", "Select all sessions starting with a given prefix")
|
||||
statusCmd.Flags().BoolVarP(&jsonFlag, "json", "j", false, "Output in JSON format (default: false)")
|
||||
statusCmd.MarkFlagRequired("session")
|
||||
}
|
||||
|
||||
func sessionStatus() {
|
||||
|
||||
controller, runs, _, err := utils.LoadSession(sessionNameFlag)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if len(runs) == 0 {
|
||||
log.Fatal("No runs found for run name", sessionNameFlag)
|
||||
}
|
||||
var err error
|
||||
var sessions []string
|
||||
|
||||
|
||||
var results models.Results
|
||||
|
||||
for _, run := range runs {
|
||||
if sessionNameFlag != "" {
|
||||
sessions = []string{sessionNameFlag}
|
||||
} else if sessionPrefixFlag != "" {
|
||||
sessions, err = utils.GetSessionsStartingWith(sessionPrefixFlag)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
runDetails, err := utils.GetRunDetails(controller, run.Id)
|
||||
} else {
|
||||
fmt.Println("Please specify a session name or prefix")
|
||||
return
|
||||
}
|
||||
|
||||
var sessionResults []models.Results
|
||||
|
||||
for _, session := range sessions {
|
||||
controller, runs, _, err := utils.LoadSession(session)
|
||||
if err != nil {
|
||||
fmt.Printf("Error loading session %s\n", session)
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
status := runDetails["status"].(string)
|
||||
var failure_reason string
|
||||
if status == "failed" {
|
||||
failure_reason = runDetails["failure_reason"].(string)
|
||||
} else {
|
||||
failure_reason = ""
|
||||
if len(runs) == 0 {
|
||||
fmt.Printf("No runs found for run name %s\n", session)
|
||||
continue
|
||||
}
|
||||
|
||||
results.Runs = append(results.Runs, models.RunStatus{
|
||||
Id: run.Id,
|
||||
Query: run.Query,
|
||||
Status: status,
|
||||
FailureReason: failure_reason,
|
||||
})
|
||||
var results models.Results
|
||||
|
||||
for _, repo := range runDetails["scanned_repositories"].([]interface{}) {
|
||||
if repo.(map[string]interface{})["analysis_status"].(string) == "succeeded" {
|
||||
results.TotalSuccessfulScans += 1
|
||||
if repo.(map[string]interface{})["result_count"].(float64) > 0 {
|
||||
results.TotalRepositoriesWithFindings += 1
|
||||
results.TotalFindingsCount += int(repo.(map[string]interface{})["result_count"].(float64))
|
||||
repoInfo := repo.(map[string]interface{})["repository"].(map[string]interface{})
|
||||
results.ResositoriesWithFindings = append(results.ResositoriesWithFindings, models.RepoWithFindings{
|
||||
Nwo: repoInfo["full_name"].(string),
|
||||
Count: int(repo.(map[string]interface{})["result_count"].(float64)),
|
||||
RunId: run.Id,
|
||||
Stars: int(repoInfo["stargazers_count"].(float64)),
|
||||
})
|
||||
}
|
||||
} else if repo.(map[string]interface{})["analysis_status"].(string) == "failed" {
|
||||
results.TotalFailedScans += 1
|
||||
global_status := "succeeded"
|
||||
|
||||
for _, run := range runs {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
runDetails, err := utils.GetRunDetails(controller, run.Id)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
status := runDetails["status"].(string)
|
||||
if status != "succeeded" {
|
||||
global_status = "in_progress"
|
||||
}
|
||||
var failure_reason string
|
||||
if status == "failed" {
|
||||
failure_reason = runDetails["failure_reason"].(string)
|
||||
} else {
|
||||
failure_reason = ""
|
||||
}
|
||||
|
||||
results.Name = session
|
||||
results.Runs = append(results.Runs, models.RunStatus{
|
||||
Id: run.Id,
|
||||
Query: run.Query,
|
||||
Status: status,
|
||||
FailureReason: failure_reason,
|
||||
})
|
||||
|
||||
for _, repo := range runDetails["scanned_repositories"].([]interface{}) {
|
||||
if repo.(map[string]interface{})["analysis_status"].(string) == "succeeded" {
|
||||
results.TotalSuccessfulScans += 1
|
||||
if repo.(map[string]interface{})["result_count"].(float64) > 0 {
|
||||
results.TotalRepositoriesWithFindings += 1
|
||||
results.TotalFindingsCount += int(repo.(map[string]interface{})["result_count"].(float64))
|
||||
repoInfo := repo.(map[string]interface{})["repository"].(map[string]interface{})
|
||||
results.ResositoriesWithFindings = append(results.ResositoriesWithFindings, models.RepoWithFindings{
|
||||
Nwo: repoInfo["full_name"].(string),
|
||||
Count: int(repo.(map[string]interface{})["result_count"].(float64)),
|
||||
RunId: run.Id,
|
||||
Stars: int(repoInfo["stargazers_count"].(float64)),
|
||||
})
|
||||
}
|
||||
} else if repo.(map[string]interface{})["analysis_status"].(string) == "failed" {
|
||||
results.TotalFailedScans += 1
|
||||
}
|
||||
}
|
||||
|
||||
skipped_repositories := runDetails["skipped_repositories"].(map[string]interface{})
|
||||
access_mismatch_repos := skipped_repositories["access_mismatch_repos"].(map[string]interface{})
|
||||
not_found_repos := skipped_repositories["not_found_repos"].(map[string]interface{})
|
||||
no_codeql_db_repos := skipped_repositories["no_codeql_db_repos"].(map[string]interface{})
|
||||
over_limit_repos := skipped_repositories["over_limit_repos"].(map[string]interface{})
|
||||
total_skipped_repos := access_mismatch_repos["repository_count"].(float64) + not_found_repos["repository_count"].(float64) + no_codeql_db_repos["repository_count"].(float64) + over_limit_repos["repository_count"].(float64)
|
||||
|
||||
results.TotalSkippedAccessMismatchRepositories += int(access_mismatch_repos["repository_count"].(float64))
|
||||
results.TotalSkippedNotFoundRepositories += int(not_found_repos["repository_count"].(float64))
|
||||
results.TotalSkippedNoDatabaseRepositories += int(no_codeql_db_repos["repository_count"].(float64))
|
||||
results.TotalSkippedOverLimitRepositories += int(over_limit_repos["repository_count"].(float64))
|
||||
results.TotalSkippedRepositories += int(total_skipped_repos)
|
||||
}
|
||||
|
||||
skipped_repositories := runDetails["skipped_repositories"].(map[string]interface{})
|
||||
access_mismatch_repos := skipped_repositories["access_mismatch_repos"].(map[string]interface{})
|
||||
not_found_repos := skipped_repositories["not_found_repos"].(map[string]interface{})
|
||||
no_codeql_db_repos := skipped_repositories["no_codeql_db_repos"].(map[string]interface{})
|
||||
over_limit_repos := skipped_repositories["over_limit_repos"].(map[string]interface{})
|
||||
total_skipped_repos := access_mismatch_repos["repository_count"].(float64) + not_found_repos["repository_count"].(float64) + no_codeql_db_repos["repository_count"].(float64) + over_limit_repos["repository_count"].(float64)
|
||||
|
||||
results.TotalSkippedAccessMismatchRepositories += int(access_mismatch_repos["repository_count"].(float64))
|
||||
results.TotalSkippedNotFoundRepositories += int(not_found_repos["repository_count"].(float64))
|
||||
results.TotalSkippedNoDatabaseRepositories += int(no_codeql_db_repos["repository_count"].(float64))
|
||||
results.TotalSkippedOverLimitRepositories += int(over_limit_repos["repository_count"].(float64))
|
||||
results.TotalSkippedRepositories += int(total_skipped_repos)
|
||||
results.Status = global_status
|
||||
sessionResults = append(sessionResults, results)
|
||||
}
|
||||
|
||||
if jsonFlag {
|
||||
data, err := json.MarshalIndent(results, "", " ")
|
||||
data, err := json.MarshalIndent(sessionResults, "", " ")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println(string(data))
|
||||
} else {
|
||||
fmt.Println("Run name:", sessionNameFlag)
|
||||
fmt.Println("Total runs:", len(results.Runs))
|
||||
fmt.Println("Total successful scans:", results.TotalSuccessfulScans)
|
||||
fmt.Println("Total failed scans:", results.TotalFailedScans)
|
||||
fmt.Println("Total skipped repositories:", results.TotalSkippedRepositories)
|
||||
fmt.Println("Total skipped repositories due to access mismatch:", results.TotalSkippedAccessMismatchRepositories)
|
||||
fmt.Println("Total skipped repositories due to not found:", results.TotalSkippedNotFoundRepositories)
|
||||
fmt.Println("Total skipped repositories due to no database:", results.TotalSkippedNoDatabaseRepositories)
|
||||
fmt.Println("Total skipped repositories due to over limit:", results.TotalSkippedOverLimitRepositories)
|
||||
fmt.Println("Total repositories with findings:", results.TotalRepositoriesWithFindings)
|
||||
fmt.Println("Total findings:", results.TotalFindingsCount)
|
||||
fmt.Println("Repositories with findings:")
|
||||
for _, repo := range results.ResositoriesWithFindings {
|
||||
fmt.Println(" ", repo.Nwo, ":", repo.Count)
|
||||
for _, results := range sessionResults {
|
||||
fmt.Println("Run name:", sessionNameFlag)
|
||||
fmt.Println("Status:", results.Status)
|
||||
fmt.Println("Total runs:", len(results.Runs))
|
||||
fmt.Println("Total successful scans:", results.TotalSuccessfulScans)
|
||||
fmt.Println("Total failed scans:", results.TotalFailedScans)
|
||||
fmt.Println("Total skipped repositories:", results.TotalSkippedRepositories)
|
||||
fmt.Println("Total skipped repositories due to access mismatch:", results.TotalSkippedAccessMismatchRepositories)
|
||||
fmt.Println("Total skipped repositories due to not found:", results.TotalSkippedNotFoundRepositories)
|
||||
fmt.Println("Total skipped repositories due to no database:", results.TotalSkippedNoDatabaseRepositories)
|
||||
fmt.Println("Total skipped repositories due to over limit:", results.TotalSkippedOverLimitRepositories)
|
||||
fmt.Println("Total repositories with findings:", results.TotalRepositoriesWithFindings)
|
||||
fmt.Println("Total findings:", results.TotalFindingsCount)
|
||||
fmt.Println("Repositories with findings:")
|
||||
for _, repo := range results.ResositoriesWithFindings {
|
||||
fmt.Println(" ", repo.Nwo, ":", repo.Count)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,8 @@ type RepoWithFindings struct {
|
||||
}
|
||||
|
||||
type Results struct {
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
Runs []RunStatus `json:"runs"`
|
||||
ResositoriesWithFindings []RepoWithFindings `json:"repositories_with_findings"`
|
||||
TotalFindingsCount int `json:"total_findings_count"`
|
||||
|
||||
@@ -71,6 +71,22 @@ func LoadSession(name string) (string, []models.Run, string, error) {
|
||||
return "", nil, "", errors.New("No session found for " + name)
|
||||
}
|
||||
|
||||
func GetSessionsStartingWith(prefix string) ([]string, error) {
|
||||
sessions, err := GetSessions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var matchingSessions []string
|
||||
if sessions != nil {
|
||||
for session := range sessions {
|
||||
if strings.HasPrefix(session, prefix) {
|
||||
matchingSessions = append(matchingSessions, session)
|
||||
}
|
||||
}
|
||||
}
|
||||
return matchingSessions, nil
|
||||
}
|
||||
|
||||
func GetRunDetails(controller string, runId int) (map[string]interface{}, error) {
|
||||
opts := api.ClientOptions{
|
||||
Headers: map[string]string{"Accept": "application/vnd.github.v3+json"},
|
||||
|
||||
Reference in New Issue
Block a user