Refactoring

This commit is contained in:
Kota Kanbe
2017-05-21 11:45:21 +09:00
committed by kota kanbe
parent 9128e2748b
commit d9bc4499a4
23 changed files with 2086 additions and 1885 deletions

View File

@@ -27,6 +27,7 @@ import (
"strings"
c "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/report"
"github.com/google/subcommands"
)
@@ -68,9 +69,8 @@ func (p *HistoryCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{
c.Conf.DebugSQL = p.debugSQL
c.Conf.ResultsDir = p.resultsDir
var err error
var dirs jsonDirs
if dirs, err = lsValidJSONDirs(); err != nil {
dirs, err := report.ListValidJSONDirs()
if err != nil {
return subcommands.ExitFailure
}
for _, d := range dirs {

View File

@@ -25,9 +25,7 @@ import (
"path/filepath"
c "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/cveapi"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/oval"
"github.com/future-architect/vuls/report"
"github.com/future-architect/vuls/util"
"github.com/google/subcommands"
@@ -290,6 +288,8 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
c.Conf.Lang = p.lang
c.Conf.ResultsDir = p.resultsDir
c.Conf.RefreshCve = p.refreshCve
c.Conf.Diff = p.diff
c.Conf.CveDBType = p.cvedbtype
c.Conf.CveDBPath = p.cvedbpath
c.Conf.CveDBURL = p.cvedbURL
@@ -314,9 +314,9 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
var dir string
var err error
if p.diff {
dir, err = jsonDir([]string{})
dir, err = report.JSONDir([]string{})
} else {
dir, err = jsonDir(f.Args())
dir, err = report.JSONDir(f.Args())
}
if err != nil {
util.Log.Errorf("Failed to read from JSON: %s", err)
@@ -385,7 +385,7 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
if !c.Conf.ValidateOnReport() {
return subcommands.ExitUsageError
}
if ok, err := cveapi.CveClient.CheckHealth(); !ok {
if ok, err := report.CveClient.CheckHealth(); !ok {
util.Log.Errorf("CVE HTTP server is not running. err: %s", err)
util.Log.Errorf("Run go-cve-dictionary as server mode before reporting or run with --cvedb-path option")
return subcommands.ExitFailure
@@ -398,90 +398,36 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
}
}
rs, err := loadScanResults(dir)
if err != nil {
var res models.ScanResults
if res, err = report.LoadScanResults(dir); err != nil {
util.Log.Error(err)
return subcommands.ExitFailure
}
util.Log.Infof("Loaded: %s", dir)
var results []models.ScanResult
for _, r := range rs {
if p.refreshCve || needToRefreshCve(r) {
util.Log.Debugf("need to refresh")
if c.Conf.CveDBType == "sqlite3" && c.Conf.CveDBURL == "" {
if _, err := os.Stat(c.Conf.CveDBPath); os.IsNotExist(err) {
util.Log.Errorf("SQLite3 DB(CVE-Dictionary) is not exist: %s",
c.Conf.CveDBPath)
return subcommands.ExitFailure
}
}
if err := fillCveInfoFromOvalDB(&r); err != nil {
util.Log.Errorf("Failed to fill OVAL information: %s", err)
return subcommands.ExitFailure
}
if err := fillCveInfoFromCveDB(&r); err != nil {
util.Log.Errorf("Failed to fill CVE information: %s", err)
return subcommands.ExitFailure
}
r.Lang = c.Conf.Lang
if err := overwriteJSONFile(dir, r); err != nil {
util.Log.Errorf("Failed to write JSON: %s", err)
return subcommands.ExitFailure
}
results = append(results, r)
} else {
util.Log.Debugf("no need to refresh")
results = append(results, r)
}
//TODO dir
if res, err = report.FillCveInfos(res, dir); err != nil {
util.Log.Error(err)
return subcommands.ExitFailure
}
if p.diff {
previous, err := loadPrevious(results)
if err != nil {
util.Log.Error(err)
return subcommands.ExitFailure
}
diff, err := diff(results, previous)
if err != nil {
util.Log.Error(err)
return subcommands.ExitFailure
}
results = []models.ScanResult{}
for _, r := range diff {
if err := fillCveDetail(&r); err != nil {
util.Log.Error(err)
return subcommands.ExitFailure
}
results = append(results, r)
}
}
var res models.ScanResults
for _, r := range results {
res = append(res, r.FilterByCvssOver(c.Conf.CvssScoreOver))
// TODO Add sort function to ScanResults
//remove
// for _, vuln := range r.ScannedCves {
// // if _, ok := vuln.CveContents.Get(models.NewCveContentType(r.Family)); !ok {
// // pp.Printf("not in oval: %s %f\n%v\n",
// // vuln.CveID, vuln.CveContents.CvssV2Score(), vuln.Packages)
// // } else {
// // fmt.Printf(" in oval: %s %f\n",
// // vuln.CveID, vuln.CveContents.CvssV2Score())
// // }
// // if vuln.CveContents.CvssV2Score() < 0.1 &&
// // vuln.CveContents.CvssV3Score() < 0.1 {
// // pp.Println(vuln)
// // }
// }
}
// TODO Filter, Sort
// TODO Add sort function to ScanResults
//remove
// for _, vuln := range r.ScannedCves {
// // if _, ok := vuln.CveContents.Get(models.NewCveContentType(r.Family)); !ok {
// // pp.Printf("not in oval: %s %f\n%v\n",
// // vuln.CveID, vuln.CveContents.CvssV2Score(), vuln.Packages)
// // } else {
// // fmt.Printf(" in oval: %s %f\n",
// // vuln.CveID, vuln.CveContents.CvssV2Score())
// // }
// // if vuln.CveContents.CvssV2Score() < 0.1 &&
// // vuln.CveContents.CvssV3Score() < 0.1 {
// // pp.Println(vuln)
// // }
// }
// }
for _, w := range reports {
if err := w.Write(res...); err != nil {
@@ -491,76 +437,3 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
}
return subcommands.ExitSuccess
}
// fillCveDetail fetches NVD, JVN from CVE Database, and then set to fields.
func fillCveDetail(r *models.ScanResult) error {
var cveIDs []string
for _, v := range r.ScannedCves {
cveIDs = append(cveIDs, v.CveID)
}
ds, err := cveapi.CveClient.FetchCveDetails(cveIDs)
if err != nil {
return err
}
for _, d := range ds {
nvd := r.ConvertNvdToModel(d.CveID, d.Nvd)
jvn := r.ConvertJvnToModel(d.CveID, d.Jvn)
for cveID, vinfo := range r.ScannedCves {
if vinfo.CveID == d.CveID {
if vinfo.CveContents == nil {
vinfo.CveContents = models.CveContents{}
}
for _, con := range []models.CveContent{*nvd, *jvn} {
if !con.Empty() {
vinfo.CveContents[con.Type] = con
}
}
r.ScannedCves[cveID] = vinfo
break
}
}
}
//TODO Remove
// sort.Slice(r.ScannedCves, func(i, j int) bool {
// if r.ScannedCves[j].CveContents.CvssV2Score() == r.ScannedCves[i].CveContents.CvssV2Score() {
// return r.ScannedCves[j].CveContents.CvssV2Score() < r.ScannedCves[i].CveContents.CvssV2Score()
// }
// return r.ScannedCves[j].CveContents.CvssV2Score() < r.ScannedCves[i].CveContents.CvssV2Score()
// })
return nil
}
func fillCveInfoFromCveDB(r *models.ScanResult) error {
sInfo := c.Conf.Servers[r.ServerName]
if err := fillVulnByCpeNames(sInfo.CpeNames, r.ScannedCves); err != nil {
return err
}
if err := fillCveDetail(r); err != nil {
return err
}
return nil
}
func fillCveInfoFromOvalDB(r *models.ScanResult) error {
var ovalClient oval.Client
switch r.Family {
case "debian":
ovalClient = oval.NewDebian()
case "ubuntu":
ovalClient = oval.NewUbuntu()
case "rhel":
ovalClient = oval.NewRedhat()
case "centos":
ovalClient = oval.NewCentOS()
case "amazon", "oraclelinux", "Raspbian", "FreeBSD":
//TODO implement OracleLinux
return nil
default:
return fmt.Errorf("Oval %s is not implemented yet", r.Family)
}
if err := ovalClient.FillCveInfoFromOvalDB(r); err != nil {
return err
}
return nil
}

View File

@@ -24,8 +24,6 @@ import (
"path/filepath"
c "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/report"
"github.com/future-architect/vuls/util"
"github.com/google/subcommands"
)
@@ -146,40 +144,41 @@ func (p *TuiCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) s
}
c.Conf.Pipe = p.pipe
jsonDir, err := jsonDir(f.Args())
if err != nil {
log.Errorf("Failed to read json dir under results: %s", err)
return subcommands.ExitFailure
}
// jsonDir, err := report.JSONDir(f.Args())
// if err != nil {
// log.Errorf("Failed to read json dir under results: %s", err)
// return subcommands.ExitFailure
// }
results, err := loadScanResults(jsonDir)
if err != nil {
log.Errorf("Failed to read from JSON: %s", err)
return subcommands.ExitFailure
}
// results, err := report.LoadScanResults(jsonDir)
// if err != nil {
// log.Errorf("Failed to read from JSON: %s", err)
// return subcommands.ExitFailure
// }
var filledResults []models.ScanResult
for _, r := range results {
if p.refreshCve || needToRefreshCve(r) {
if c.Conf.CveDBType == "sqlite3" {
if _, err := os.Stat(c.Conf.CveDBPath); os.IsNotExist(err) {
log.Errorf("SQLite3 DB(CVE-Dictionary) is not exist: %s",
c.Conf.CveDBPath)
return subcommands.ExitFailure
}
}
// var filledResults []models.ScanResult
// for _, r := range results {
// if p.refreshCve || needToRefreshCve(r) {
// if c.Conf.CveDBType == "sqlite3" {
// if _, err := os.Stat(c.Conf.CveDBPath); os.IsNotExist(err) {
// log.Errorf("SQLite3 DB(CVE-Dictionary) is not exist: %s",
// c.Conf.CveDBPath)
// return subcommands.ExitFailure
// }
// }
if err := fillCveInfoFromCveDB(&r); err != nil {
log.Errorf("Failed to fill CVE information: %s", err)
return subcommands.ExitFailure
}
// if err := fillCveInfoFromCveDB(&r); err != nil {
// log.Errorf("Failed to fill CVE information: %s", err)
// return subcommands.ExitFailure
// }
if err := overwriteJSONFile(jsonDir, r); err != nil {
log.Errorf("Failed to write JSON: %s", err)
return subcommands.ExitFailure
}
}
filledResults = append(filledResults, r)
}
return report.RunTui(filledResults)
// if err := overwriteJSONFile(jsonDir, r); err != nil {
// log.Errorf("Failed to write JSON: %s", err)
// return subcommands.ExitFailure
// }
// }
// filledResults = append(filledResults, r)
// }
// return report.RunTui(filledResults)
return subcommands.ExitFailure
}

View File

@@ -18,307 +18,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
package commands
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"sort"
"strings"
"time"
c "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/cveapi"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/report"
"github.com/future-architect/vuls/util"
"github.com/howeyc/gopass"
)
// jsonDirPattern is file name pattern of JSON directory
// 2016-11-16T10:43:28+09:00
// 2016-11-16T10:43:28Z
var jsonDirPattern = regexp.MustCompile(
`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:Z|[+-]\d{2}:\d{2})$`)
// JSONDirs is array of json files path.
type jsonDirs []string
// getValidJSONDirs return valid json directory as array
// Returned array is sorted so that recent directories are at the head
func lsValidJSONDirs() (dirs jsonDirs, err error) {
var dirInfo []os.FileInfo
if dirInfo, err = ioutil.ReadDir(c.Conf.ResultsDir); err != nil {
err = fmt.Errorf("Failed to read %s: %s", c.Conf.ResultsDir, err)
return
}
for _, d := range dirInfo {
if d.IsDir() && jsonDirPattern.MatchString(d.Name()) {
jsonDir := filepath.Join(c.Conf.ResultsDir, d.Name())
dirs = append(dirs, jsonDir)
}
}
sort.Slice(dirs, func(i, j int) bool {
return dirs[j] < dirs[i]
})
return
}
// jsonDir returns
// If there is an arg, check if it is a valid format and return the corresponding path under results.
// If arg passed via PIPE (such as history subcommand), return that path.
// Otherwise, returns the path of the latest directory
func jsonDir(args []string) (string, error) {
var err error
var dirs jsonDirs
if 0 < len(args) {
if dirs, err = lsValidJSONDirs(); err != nil {
return "", err
}
path := filepath.Join(c.Conf.ResultsDir, args[0])
for _, d := range dirs {
ss := strings.Split(d, string(os.PathSeparator))
timedir := ss[len(ss)-1]
if timedir == args[0] {
return path, nil
}
}
return "", fmt.Errorf("Invalid path: %s", path)
}
// PIPE
if c.Conf.Pipe {
bytes, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return "", fmt.Errorf("Failed to read stdin: %s", err)
}
fields := strings.Fields(string(bytes))
if 0 < len(fields) {
return filepath.Join(c.Conf.ResultsDir, fields[0]), nil
}
return "", fmt.Errorf("Stdin is invalid: %s", string(bytes))
}
// returns latest dir when no args or no PIPE
if dirs, err = lsValidJSONDirs(); err != nil {
return "", err
}
if len(dirs) == 0 {
return "", fmt.Errorf("No results under %s",
c.Conf.ResultsDir)
}
return dirs[0], nil
}
// loadOneServerScanResult read JSON data of one server
func loadOneServerScanResult(jsonFile string) (result models.ScanResult, err error) {
var data []byte
if data, err = ioutil.ReadFile(jsonFile); err != nil {
err = fmt.Errorf("Failed to read %s: %s", jsonFile, err)
return
}
if json.Unmarshal(data, &result) != nil {
err = fmt.Errorf("Failed to parse %s: %s", jsonFile, err)
}
return
}
// loadScanResults read JSON data
func loadScanResults(jsonDir string) (results models.ScanResults, err error) {
var files []os.FileInfo
if files, err = ioutil.ReadDir(jsonDir); err != nil {
return nil, fmt.Errorf("Failed to read %s: %s", jsonDir, err)
}
for _, f := range files {
if filepath.Ext(f.Name()) != ".json" || strings.HasSuffix(f.Name(), "_diff.json") {
continue
}
var r models.ScanResult
path := filepath.Join(jsonDir, f.Name())
if r, err = loadOneServerScanResult(path); err != nil {
return nil, err
}
results = append(results, r)
}
if len(results) == 0 {
return nil, fmt.Errorf("There is no json file under %s", jsonDir)
}
return
}
func loadPrevious(current models.ScanResults) (previous models.ScanResults, err error) {
var dirs jsonDirs
if dirs, err = lsValidJSONDirs(); err != nil {
return
}
for _, result := range current {
for _, dir := range dirs[1:] {
var r models.ScanResult
path := filepath.Join(dir, result.ServerName+".json")
if r, err = loadOneServerScanResult(path); err != nil {
continue
}
if r.Family == result.Family && r.Release == result.Release {
previous = append(previous, r)
util.Log.Infof("Privious json found: %s", path)
break
}
}
}
return previous, nil
}
func diff(curResults, preResults models.ScanResults) (diffed models.ScanResults, err error) {
for _, current := range curResults {
found := false
var previous models.ScanResult
for _, r := range preResults {
if current.ServerName == r.ServerName {
found = true
previous = r
break
}
}
if found {
current.ScannedCves = getDiffCves(previous, current)
packages := models.Packages{}
for _, s := range current.ScannedCves {
for _, name := range s.PackageNames {
p := current.Packages[name]
packages[name] = p
}
}
current.Packages = packages
}
diffed = append(diffed, current)
}
return diffed, err
}
func getDiffCves(previous, current models.ScanResult) models.VulnInfos {
previousCveIDsSet := map[string]bool{}
for _, previousVulnInfo := range previous.ScannedCves {
previousCveIDsSet[previousVulnInfo.CveID] = true
}
new := models.VulnInfos{}
updated := models.VulnInfos{}
for _, v := range current.ScannedCves {
if previousCveIDsSet[v.CveID] {
if isCveInfoUpdated(v.CveID, previous, current) {
updated[v.CveID] = v
}
} else {
new[v.CveID] = v
}
}
for cveID, vuln := range new {
updated[cveID] = vuln
}
return updated
}
func isCveInfoUpdated(cveID string, previous, current models.ScanResult) bool {
cTypes := []models.CveContentType{
models.NVD,
models.JVN,
models.NewCveContentType(current.Family),
}
prevLastModified := map[models.CveContentType]time.Time{}
for _, c := range previous.ScannedCves {
if cveID == c.CveID {
for _, cType := range cTypes {
content, _ := c.CveContents[cType]
prevLastModified[cType] = content.LastModified
}
break
}
}
curLastModified := map[models.CveContentType]time.Time{}
for _, c := range current.ScannedCves {
if cveID == c.CveID {
for _, cType := range cTypes {
content, _ := c.CveContents[cType]
curLastModified[cType] = content.LastModified
}
break
}
}
for _, cType := range cTypes {
if equal := prevLastModified[cType].Equal(curLastModified[cType]); !equal {
return true
}
}
return false
}
func overwriteJSONFile(dir string, r models.ScanResult) error {
before := c.Conf.FormatJSON
beforeDiff := c.Conf.Diff
c.Conf.FormatJSON = true
c.Conf.Diff = false
w := report.LocalFileWriter{CurrentDir: dir}
if err := w.Write(r); err != nil {
return fmt.Errorf("Failed to write summary report: %s", err)
}
c.Conf.FormatJSON = before
c.Conf.Diff = beforeDiff
return nil
}
func fillVulnByCpeNames(cpeNames []string, scannedVulns models.VulnInfos) error {
for _, name := range cpeNames {
details, err := cveapi.CveClient.FetchCveDetailsByCpeName(name)
if err != nil {
return err
}
for _, detail := range details {
if val, ok := scannedVulns[detail.CveID]; ok {
names := val.CpeNames
names = util.AppendIfMissing(names, name)
val.CpeNames = names
val.Confidence = models.CpeNameMatch
scannedVulns[detail.CveID] = val
} else {
v := models.VulnInfo{
CveID: detail.CveID,
CpeNames: []string{name},
Confidence: models.CpeNameMatch,
}
//TODO
// v.NilToEmpty()
scannedVulns[detail.CveID] = v
}
}
}
return nil
}
func needToRefreshCve(r models.ScanResult) bool {
if r.Lang != c.Conf.Lang {
return true
}
for _, cve := range r.ScannedCves {
if 0 < len(cve.CveContents) {
return false
}
}
return true
}
func getPasswd(prompt string) (string, error) {
for {
fmt.Print(prompt)

View File

@@ -16,329 +16,3 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package commands
import (
"reflect"
"testing"
"time"
"github.com/future-architect/vuls/models"
"github.com/k0kubun/pp"
)
func TestIsCveInfoUpdated(t *testing.T) {
f := "2006-01-02"
old, _ := time.Parse(f, "2015-12-15")
new, _ := time.Parse(f, "2015-12-16")
type In struct {
cveID string
cur models.ScanResult
prev models.ScanResult
}
var tests = []struct {
in In
expected bool
}{
// NVD compare non-initialized times
{
in: In{
cveID: "CVE-2017-0001",
cur: models.ScanResult{
ScannedCves: models.VulnInfos{
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
CveContents: models.NewCveContents(
models.CveContent{
Type: models.NVD,
CveID: "CVE-2017-0001",
LastModified: time.Time{},
},
),
},
},
},
prev: models.ScanResult{
ScannedCves: models.VulnInfos{
"CVE-2017-0001": {
CveID: "CVE-2017-0001",
CveContents: models.NewCveContents(
models.CveContent{
Type: models.NVD,
CveID: "CVE-2017-0001",
LastModified: time.Time{},
},
),
},
},
},
},
expected: false,
},
// JVN not updated
{
in: In{
cveID: "CVE-2017-0002",
cur: models.ScanResult{
ScannedCves: models.VulnInfos{
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
CveContents: models.NewCveContents(
models.CveContent{
Type: models.NVD,
CveID: "CVE-2017-0002",
LastModified: old,
},
),
},
},
},
prev: models.ScanResult{
ScannedCves: models.VulnInfos{
"CVE-2017-0002": {
CveID: "CVE-2017-0002",
CveContents: models.NewCveContents(
models.CveContent{
Type: models.NVD,
CveID: "CVE-2017-0002",
LastModified: old,
},
),
},
},
},
},
expected: false,
},
// OVAL updated
{
in: In{
cveID: "CVE-2017-0003",
cur: models.ScanResult{
Family: "ubuntu",
ScannedCves: models.VulnInfos{
"CVE-2017-0003": {
CveID: "CVE-2017-0003",
CveContents: models.NewCveContents(
models.CveContent{
Type: models.NVD,
CveID: "CVE-2017-0002",
LastModified: new,
},
),
},
},
},
prev: models.ScanResult{
Family: "ubuntu",
ScannedCves: models.VulnInfos{
"CVE-2017-0003": {
CveID: "CVE-2017-0003",
CveContents: models.NewCveContents(
models.CveContent{
Type: models.NVD,
CveID: "CVE-2017-0002",
LastModified: old,
},
),
},
},
},
},
expected: true,
},
// OVAL newly detected
{
in: In{
cveID: "CVE-2017-0004",
cur: models.ScanResult{
Family: "redhat",
ScannedCves: models.VulnInfos{
"CVE-2017-0004": {
CveID: "CVE-2017-0004",
CveContents: models.NewCveContents(
models.CveContent{
Type: models.NVD,
CveID: "CVE-2017-0002",
LastModified: old,
},
),
},
},
},
prev: models.ScanResult{
Family: "redhat",
ScannedCves: models.VulnInfos{},
},
},
expected: true,
},
}
for i, tt := range tests {
actual := isCveInfoUpdated(tt.in.cveID, tt.in.prev, tt.in.cur)
if actual != tt.expected {
t.Errorf("[%d] actual: %t, expected: %t", i, actual, tt.expected)
}
}
}
func TestDiff(t *testing.T) {
atCurrent, _ := time.Parse("2006-01-02", "2014-12-31")
atPrevious, _ := time.Parse("2006-01-02", "2014-11-31")
var tests = []struct {
inCurrent models.ScanResults
inPrevious models.ScanResults
out models.ScanResult
}{
{
inCurrent: models.ScanResults{
{
ScannedAt: atCurrent,
ServerName: "u16",
Family: "ubuntu",
Release: "16.04",
ScannedCves: models.VulnInfos{
"CVE-2012-6702": {
CveID: "CVE-2012-6702",
PackageNames: []string{"libexpat1"},
DistroAdvisories: []models.DistroAdvisory{},
CpeNames: []string{},
},
"CVE-2014-9761": {
CveID: "CVE-2014-9761",
PackageNames: []string{"libc-bin"},
DistroAdvisories: []models.DistroAdvisory{},
CpeNames: []string{},
},
},
Packages: models.Packages{},
Errors: []string{},
Optional: [][]interface{}{},
},
},
inPrevious: models.ScanResults{
{
ScannedAt: atPrevious,
ServerName: "u16",
Family: "ubuntu",
Release: "16.04",
ScannedCves: models.VulnInfos{
"CVE-2012-6702": {
CveID: "CVE-2012-6702",
PackageNames: []string{"libexpat1"},
DistroAdvisories: []models.DistroAdvisory{},
CpeNames: []string{},
},
"CVE-2014-9761": {
CveID: "CVE-2014-9761",
PackageNames: []string{"libc-bin"},
DistroAdvisories: []models.DistroAdvisory{},
CpeNames: []string{},
},
},
Packages: models.Packages{},
Errors: []string{},
Optional: [][]interface{}{},
},
},
out: models.ScanResult{
ScannedAt: atCurrent,
ServerName: "u16",
Family: "ubuntu",
Release: "16.04",
Packages: models.Packages{},
ScannedCves: models.VulnInfos{},
Errors: []string{},
Optional: [][]interface{}{},
},
},
{
inCurrent: models.ScanResults{
{
ScannedAt: atCurrent,
ServerName: "u16",
Family: "ubuntu",
Release: "16.04",
ScannedCves: models.VulnInfos{
"CVE-2016-6662": {
CveID: "CVE-2016-6662",
PackageNames: []string{"mysql-libs"},
DistroAdvisories: []models.DistroAdvisory{},
CpeNames: []string{},
},
},
Packages: models.Packages{
"mysql-libs": {
Name: "mysql-libs",
Version: "5.1.73",
Release: "7.el6",
NewVersion: "5.1.73",
NewRelease: "8.el6_8",
Repository: "",
Changelog: models.Changelog{
Contents: "",
Method: "",
},
},
},
},
},
inPrevious: models.ScanResults{
{
ScannedAt: atPrevious,
ServerName: "u16",
Family: "ubuntu",
Release: "16.04",
ScannedCves: models.VulnInfos{},
},
},
out: models.ScanResult{
ScannedAt: atCurrent,
ServerName: "u16",
Family: "ubuntu",
Release: "16.04",
ScannedCves: models.VulnInfos{
"CVE-2016-6662": {
CveID: "CVE-2016-6662",
PackageNames: []string{"mysql-libs"},
DistroAdvisories: []models.DistroAdvisory{},
CpeNames: []string{},
},
},
Packages: models.Packages{
"mysql-libs": {
Name: "mysql-libs",
Version: "5.1.73",
Release: "7.el6",
NewVersion: "5.1.73",
NewRelease: "8.el6_8",
Repository: "",
Changelog: models.Changelog{
Contents: "",
Method: "",
},
},
},
},
},
}
for i, tt := range tests {
diff, _ := diff(tt.inCurrent, tt.inPrevious)
for _, actual := range diff {
if !reflect.DeepEqual(actual.ScannedCves, tt.out.ScannedCves) {
h := pp.Sprint(actual.ScannedCves)
x := pp.Sprint(tt.out.ScannedCves)
t.Errorf("[%d] cves actual: \n %s \n expected: \n %s", i, h, x)
}
for j := range tt.out.Packages {
if !reflect.DeepEqual(tt.out.Packages[j], actual.Packages[j]) {
h := pp.Sprint(tt.out.Packages[j])
x := pp.Sprint(actual.Packages[j])
t.Errorf("[%d] packages actual: \n %s \n expected: \n %s", i, x, h)
}
}
}
}
}