fix(suse): fix openSUSE, openSUSE Leap, SLES, SLED scan (#1384)
* fix(suse): fix openSUSE, openSUSE Leap scan * docs: update README * fix: unknown CveContent.Type * fix: tui reporting * fix: listening port was duplicated in format-full-text * fix .gitignore * fix: add EOL data for SLES12.5 Co-authored-by: Kota Kanbe <kotakanbe@gmail.com>
This commit is contained in:
		@@ -5,7 +5,6 @@ package oval
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/future-architect/vuls/config"
 | 
			
		||||
@@ -225,8 +224,8 @@ func (o RedHatBase) convertToModel(cveID string, def *ovalmodels.Definition) *mo
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		score2, vec2 := o.parseCvss2(cve.Cvss2)
 | 
			
		||||
		score3, vec3 := o.parseCvss3(cve.Cvss3)
 | 
			
		||||
		score2, vec2 := parseCvss2(cve.Cvss2)
 | 
			
		||||
		score3, vec3 := parseCvss3(cve.Cvss3)
 | 
			
		||||
 | 
			
		||||
		sev2, sev3, severity := "", "", def.Advisory.Severity
 | 
			
		||||
		if cve.Impact != "" {
 | 
			
		||||
@@ -262,39 +261,6 @@ func (o RedHatBase) convertToModel(cveID string, def *ovalmodels.Definition) *mo
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseCvss2 divide CVSSv2 string into score and vector
 | 
			
		||||
// 5/AV:N/AC:L/Au:N/C:N/I:N/A:P
 | 
			
		||||
func (o RedHatBase) parseCvss2(scoreVector string) (score float64, vector string) {
 | 
			
		||||
	var err error
 | 
			
		||||
	ss := strings.Split(scoreVector, "/")
 | 
			
		||||
	if 1 < len(ss) {
 | 
			
		||||
		if score, err = strconv.ParseFloat(ss[0], 64); err != nil {
 | 
			
		||||
			return 0, ""
 | 
			
		||||
		}
 | 
			
		||||
		return score, strings.Join(ss[1:], "/")
 | 
			
		||||
	}
 | 
			
		||||
	return 0, ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseCvss3 divide CVSSv3 string into score and vector
 | 
			
		||||
// 5.6/CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L
 | 
			
		||||
func (o RedHatBase) parseCvss3(scoreVector string) (score float64, vector string) {
 | 
			
		||||
	var err error
 | 
			
		||||
	for _, s := range []string{
 | 
			
		||||
		"/CVSS:3.0/",
 | 
			
		||||
		"/CVSS:3.1/",
 | 
			
		||||
	} {
 | 
			
		||||
		ss := strings.Split(scoreVector, s)
 | 
			
		||||
		if 1 < len(ss) {
 | 
			
		||||
			if score, err = strconv.ParseFloat(ss[0], 64); err != nil {
 | 
			
		||||
				return 0, ""
 | 
			
		||||
			}
 | 
			
		||||
			return score, strings.TrimPrefix(s, "/") + ss[1]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return 0, ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RedHat is the interface for RedhatBase OVAL
 | 
			
		||||
type RedHat struct {
 | 
			
		||||
	RedHatBase
 | 
			
		||||
 
 | 
			
		||||
@@ -11,79 +11,6 @@ import (
 | 
			
		||||
	ovalmodels "github.com/vulsio/goval-dictionary/models"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestParseCvss2(t *testing.T) {
 | 
			
		||||
	type out struct {
 | 
			
		||||
		score  float64
 | 
			
		||||
		vector string
 | 
			
		||||
	}
 | 
			
		||||
	var tests = []struct {
 | 
			
		||||
		in  string
 | 
			
		||||
		out out
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			in: "5/AV:N/AC:L/Au:N/C:N/I:N/A:P",
 | 
			
		||||
			out: out{
 | 
			
		||||
				score:  5.0,
 | 
			
		||||
				vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			in: "",
 | 
			
		||||
			out: out{
 | 
			
		||||
				score:  0,
 | 
			
		||||
				vector: "",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		s, v := RedHatBase{}.parseCvss2(tt.in)
 | 
			
		||||
		if s != tt.out.score || v != tt.out.vector {
 | 
			
		||||
			t.Errorf("\nexpected: %f, %s\n  actual: %f, %s",
 | 
			
		||||
				tt.out.score, tt.out.vector, s, v)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestParseCvss3(t *testing.T) {
 | 
			
		||||
	type out struct {
 | 
			
		||||
		score  float64
 | 
			
		||||
		vector string
 | 
			
		||||
	}
 | 
			
		||||
	var tests = []struct {
 | 
			
		||||
		in  string
 | 
			
		||||
		out out
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			in: "5.6/CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
 | 
			
		||||
			out: out{
 | 
			
		||||
				score:  5.6,
 | 
			
		||||
				vector: "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			in: "6.1/CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
 | 
			
		||||
			out: out{
 | 
			
		||||
				score:  6.1,
 | 
			
		||||
				vector: "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			in: "",
 | 
			
		||||
			out: out{
 | 
			
		||||
				score:  0,
 | 
			
		||||
				vector: "",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		s, v := RedHatBase{}.parseCvss3(tt.in)
 | 
			
		||||
		if s != tt.out.score || v != tt.out.vector {
 | 
			
		||||
			t.Errorf("\nexpected: %f, %s\n  actual: %f, %s",
 | 
			
		||||
				tt.out.score, tt.out.vector, s, v)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestPackNamesOfUpdate(t *testing.T) {
 | 
			
		||||
	var tests = []struct {
 | 
			
		||||
		in       models.ScanResult
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										26
									
								
								oval/suse.go
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								oval/suse.go
									
									
									
									
									
								
							@@ -4,8 +4,9 @@
 | 
			
		||||
package oval
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/future-architect/vuls/config"
 | 
			
		||||
	"github.com/future-architect/vuls/constant"
 | 
			
		||||
	"github.com/future-architect/vuls/logging"
 | 
			
		||||
	"github.com/future-architect/vuls/models"
 | 
			
		||||
	ovalmodels "github.com/vulsio/goval-dictionary/models"
 | 
			
		||||
@@ -17,11 +18,10 @@ type SUSE struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewSUSE creates OVAL client for SUSE
 | 
			
		||||
func NewSUSE(cnf config.VulnDictInterface) SUSE {
 | 
			
		||||
	// TODO implement other family
 | 
			
		||||
func NewSUSE(cnf config.VulnDictInterface, family string) SUSE {
 | 
			
		||||
	return SUSE{
 | 
			
		||||
		Base{
 | 
			
		||||
			family: constant.SUSEEnterpriseServer,
 | 
			
		||||
			family: family,
 | 
			
		||||
			Cnf:    cnf,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
@@ -56,7 +56,7 @@ func (o SUSE) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
 | 
			
		||||
	for _, vuln := range r.ScannedCves {
 | 
			
		||||
		if conts, ok := vuln.CveContents[models.SUSE]; ok {
 | 
			
		||||
			for i, cont := range conts {
 | 
			
		||||
				cont.SourceLink = "https://security-tracker.debian.org/tracker/" + cont.CveID
 | 
			
		||||
				cont.SourceLink = fmt.Sprintf("https://www.suse.com/security/cve/%s.html", cont.CveID)
 | 
			
		||||
				vuln.CveContents[models.SUSE][i] = cont
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -117,11 +117,23 @@ func (o SUSE) convertToModel(def *ovalmodels.Definition) *models.CveContent {
 | 
			
		||||
			RefID:  r.RefID,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &models.CveContent{
 | 
			
		||||
	cveCont := models.CveContent{
 | 
			
		||||
		CveID:      def.Title,
 | 
			
		||||
		Title:      def.Title,
 | 
			
		||||
		Summary:    def.Description,
 | 
			
		||||
		References: refs,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if 0 < len(def.Advisory.Cves) {
 | 
			
		||||
		if len(def.Advisory.Cves) == 1 {
 | 
			
		||||
			cve := def.Advisory.Cves[0]
 | 
			
		||||
			score3, vec3 := parseCvss3(cve.Cvss3)
 | 
			
		||||
			cveCont.Cvss3Score = score3
 | 
			
		||||
			cveCont.Cvss3Vector = vec3
 | 
			
		||||
			cveCont.Cvss3Severity = cve.Impact
 | 
			
		||||
		} else {
 | 
			
		||||
			logging.Log.Warnf("Unknown Oval format. Please register the issue as it needs to be investigated. https://github.com/future-architect/vuls/issues family: %s, defID: %s", o.family, def.DefinitionID)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return &cveCont
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										56
									
								
								oval/util.go
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								oval/util.go
									
									
									
									
									
								
							@@ -9,6 +9,7 @@ import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
@@ -398,7 +399,10 @@ func isOvalDefAffected(def ovalmodels.Definition, req request, family string, ru
 | 
			
		||||
				constant.Fedora,
 | 
			
		||||
				constant.Amazon,
 | 
			
		||||
				constant.Oracle,
 | 
			
		||||
				constant.OpenSUSE,
 | 
			
		||||
				constant.OpenSUSELeap,
 | 
			
		||||
				constant.SUSEEnterpriseServer,
 | 
			
		||||
				constant.SUSEEnterpriseDesktop,
 | 
			
		||||
				constant.Debian,
 | 
			
		||||
				constant.Raspbian,
 | 
			
		||||
				constant.Ubuntu:
 | 
			
		||||
@@ -457,7 +461,10 @@ func lessThan(family, newVer string, packInOVAL ovalmodels.Package) (bool, error
 | 
			
		||||
		return vera.LessThan(verb), nil
 | 
			
		||||
 | 
			
		||||
	case constant.Oracle,
 | 
			
		||||
		constant.OpenSUSE,
 | 
			
		||||
		constant.OpenSUSELeap,
 | 
			
		||||
		constant.SUSEEnterpriseServer,
 | 
			
		||||
		constant.SUSEEnterpriseDesktop,
 | 
			
		||||
		constant.Amazon,
 | 
			
		||||
		constant.Fedora:
 | 
			
		||||
		vera := rpmver.NewVersion(newVer)
 | 
			
		||||
@@ -500,9 +507,14 @@ func NewOVALClient(family string, cnf config.GovalDictConf) (Client, error) {
 | 
			
		||||
		return NewRocky(&cnf), nil
 | 
			
		||||
	case constant.Oracle:
 | 
			
		||||
		return NewOracle(&cnf), nil
 | 
			
		||||
	case constant.OpenSUSE:
 | 
			
		||||
		return NewSUSE(&cnf, constant.OpenSUSE), nil
 | 
			
		||||
	case constant.OpenSUSELeap:
 | 
			
		||||
		return NewSUSE(&cnf, constant.OpenSUSELeap), nil
 | 
			
		||||
	case constant.SUSEEnterpriseServer:
 | 
			
		||||
		// TODO other suse family
 | 
			
		||||
		return NewSUSE(&cnf), nil
 | 
			
		||||
		return NewSUSE(&cnf, constant.SUSEEnterpriseServer), nil
 | 
			
		||||
	case constant.SUSEEnterpriseDesktop:
 | 
			
		||||
		return NewSUSE(&cnf, constant.SUSEEnterpriseDesktop), nil
 | 
			
		||||
	case constant.Alpine:
 | 
			
		||||
		return NewAlpine(&cnf), nil
 | 
			
		||||
	case constant.Amazon:
 | 
			
		||||
@@ -535,9 +547,14 @@ func GetFamilyInOval(familyInScanResult string) (string, error) {
 | 
			
		||||
		return constant.Fedora, nil
 | 
			
		||||
	case constant.Oracle:
 | 
			
		||||
		return constant.Oracle, nil
 | 
			
		||||
	case constant.OpenSUSE:
 | 
			
		||||
		return constant.OpenSUSE, nil
 | 
			
		||||
	case constant.OpenSUSELeap:
 | 
			
		||||
		return constant.OpenSUSELeap, nil
 | 
			
		||||
	case constant.SUSEEnterpriseServer:
 | 
			
		||||
		// TODO other suse family
 | 
			
		||||
		return constant.SUSEEnterpriseServer, nil
 | 
			
		||||
	case constant.SUSEEnterpriseDesktop:
 | 
			
		||||
		return constant.SUSEEnterpriseDesktop, nil
 | 
			
		||||
	case constant.Alpine:
 | 
			
		||||
		return constant.Alpine, nil
 | 
			
		||||
	case constant.Amazon:
 | 
			
		||||
@@ -554,3 +571,36 @@ func GetFamilyInOval(familyInScanResult string) (string, error) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseCvss2 divide CVSSv2 string into score and vector
 | 
			
		||||
// 5/AV:N/AC:L/Au:N/C:N/I:N/A:P
 | 
			
		||||
func parseCvss2(scoreVector string) (score float64, vector string) {
 | 
			
		||||
	var err error
 | 
			
		||||
	ss := strings.Split(scoreVector, "/")
 | 
			
		||||
	if 1 < len(ss) {
 | 
			
		||||
		if score, err = strconv.ParseFloat(ss[0], 64); err != nil {
 | 
			
		||||
			return 0, ""
 | 
			
		||||
		}
 | 
			
		||||
		return score, strings.Join(ss[1:], "/")
 | 
			
		||||
	}
 | 
			
		||||
	return 0, ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseCvss3 divide CVSSv3 string into score and vector
 | 
			
		||||
// 5.6/CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L
 | 
			
		||||
func parseCvss3(scoreVector string) (score float64, vector string) {
 | 
			
		||||
	var err error
 | 
			
		||||
	for _, s := range []string{
 | 
			
		||||
		"/CVSS:3.0/",
 | 
			
		||||
		"/CVSS:3.1/",
 | 
			
		||||
	} {
 | 
			
		||||
		ss := strings.Split(scoreVector, s)
 | 
			
		||||
		if 1 < len(ss) {
 | 
			
		||||
			if score, err = strconv.ParseFloat(ss[0], 64); err != nil {
 | 
			
		||||
				return 0, ""
 | 
			
		||||
			}
 | 
			
		||||
			return score, strings.TrimPrefix(s, "/") + ss[1]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return 0, ""
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2049,3 +2049,76 @@ func Test_ovalResult_Sort(t *testing.T) {
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestParseCvss2(t *testing.T) {
 | 
			
		||||
	type out struct {
 | 
			
		||||
		score  float64
 | 
			
		||||
		vector string
 | 
			
		||||
	}
 | 
			
		||||
	var tests = []struct {
 | 
			
		||||
		in  string
 | 
			
		||||
		out out
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			in: "5/AV:N/AC:L/Au:N/C:N/I:N/A:P",
 | 
			
		||||
			out: out{
 | 
			
		||||
				score:  5.0,
 | 
			
		||||
				vector: "AV:N/AC:L/Au:N/C:N/I:N/A:P",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			in: "",
 | 
			
		||||
			out: out{
 | 
			
		||||
				score:  0,
 | 
			
		||||
				vector: "",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		s, v := parseCvss2(tt.in)
 | 
			
		||||
		if s != tt.out.score || v != tt.out.vector {
 | 
			
		||||
			t.Errorf("\nexpected: %f, %s\n  actual: %f, %s",
 | 
			
		||||
				tt.out.score, tt.out.vector, s, v)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestParseCvss3(t *testing.T) {
 | 
			
		||||
	type out struct {
 | 
			
		||||
		score  float64
 | 
			
		||||
		vector string
 | 
			
		||||
	}
 | 
			
		||||
	var tests = []struct {
 | 
			
		||||
		in  string
 | 
			
		||||
		out out
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			in: "5.6/CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
 | 
			
		||||
			out: out{
 | 
			
		||||
				score:  5.6,
 | 
			
		||||
				vector: "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			in: "6.1/CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
 | 
			
		||||
			out: out{
 | 
			
		||||
				score:  6.1,
 | 
			
		||||
				vector: "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			in: "",
 | 
			
		||||
			out: out{
 | 
			
		||||
				score:  0,
 | 
			
		||||
				vector: "",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	for _, tt := range tests {
 | 
			
		||||
		s, v := parseCvss3(tt.in)
 | 
			
		||||
		if s != tt.out.score || v != tt.out.vector {
 | 
			
		||||
			t.Errorf("\nexpected: %f, %s\n  actual: %f, %s",
 | 
			
		||||
				tt.out.score, tt.out.vector, s, v)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user