Cybersecurity-Projects/PROJECTS/intermediate/security-news-scraper/cmd/nadezhda/cve.go

106 lines
2.1 KiB
Go

// ©AngelaMos | 2026
// cve.go
package main
import (
"database/sql"
"errors"
"fmt"
"strings"
"github.com/spf13/cobra"
"github.com/CarterPerez-dev/nadezhda/internal/store"
)
const naValue = "n/a"
var cveCmd = &cobra.Command{
Use: "cve CVE-YYYY-NNNN",
Short: "Show an enriched CVE and the articles mentioning it",
Args: cobra.ExactArgs(1),
RunE: runCVE,
}
func init() {
rootCmd.AddCommand(cveCmd)
}
func runCVE(cmd *cobra.Command, args []string) error {
cfg, err := loadConfig()
if err != nil {
return err
}
st, err := store.Open(cfg.DBPath)
if err != nil {
return err
}
defer st.Close()
id := strings.ToUpper(args[0])
c, err := st.GetCVE(id)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return fmt.Errorf("%s not found; run 'nadezhda scrape' to discover it", id)
}
return err
}
out := cmd.OutOrStdout()
fmt.Fprintf(out, "%s\n", c.ID)
if c.EnrichedAt == 0 {
fmt.Fprintln(out, " not enriched yet; run 'nadezhda enrich'")
} else {
fmt.Fprintf(out, " CVSS: %s\n", cvssLine(c))
fmt.Fprintf(out, " CWE: %s\n", orNA(c.CWE))
fmt.Fprintf(out, " KEV: %s\n", kevLine(c))
fmt.Fprintf(out, " EPSS: %s\n", epssLine(c))
if c.Description != "" {
fmt.Fprintf(out, "\n %s\n", c.Description)
}
}
articles, err := st.ArticlesForCVE(id)
if err != nil {
return err
}
fmt.Fprintf(out, "\nMentioned in %d article(s):\n", len(articles))
for _, a := range articles {
fmt.Fprintf(out, " [%s] %s\n %s\n", a.SourceName, a.Title, a.CanonicalURL)
}
return nil
}
func cvssLine(c store.CVE) string {
if c.CVSSScore == nil {
return naValue
}
return fmt.Sprintf("%.1f %s (%s) %s", *c.CVSSScore, orNA(c.CVSSSeverity), orNA(c.CVSSVersion), c.CVSSVector)
}
func kevLine(c store.CVE) string {
if !c.IsKEV {
return "no"
}
ransom := "no"
if c.KEVRansomware {
ransom = "yes"
}
return fmt.Sprintf("yes (added %s, ransomware: %s)", orNA(c.KEVDateAdded), ransom)
}
func epssLine(c store.CVE) string {
if c.EPSS == nil || c.EPSSPercentile == nil {
return naValue
}
return fmt.Sprintf("%.5f (percentile %.5f)", *c.EPSS, *c.EPSSPercentile)
}
func orNA(s string) string {
if s == "" {
return naValue
}
return s
}