Skip to content

Commit e89fc33

Browse files
shinoMaineK00n
andauthored
feat(detector): use vuls2 for RedHat, CentOS, Alma and Rocky (#2106)
* feat!(detector): use vuls2 for redhat/alma/rocky (#2075) Co-authored-by: MaineK00n <[email protected]> * chore(detector/vuls2): check downloaded time before updating db (#2077) * chore(detector/vuls2): check downloaded time before updating db Co-authored-by: MaineK00n <[email protected]> * fix(detector/vuls2): fix post convert bugs (#2082) * fix(detector/vuls2): use tag for selection logic (#2086) * fix(models/cvecontents): use cve content type Alma, Rocky (#2087) * fix(detector/vuls2): lower stauts string and compare (#2095) * chore(deps): update vuls2 (#2096) * feat(detector/vuls2): fill title and summary (#2097) * chore(deps): update vuls2 (#2099) * chore(deps): update vuls2 incorporate MaineK00n/vuls2#139 * Vuls2Conf instead of Vuls2DictConf * Update detector/vuls2/db.go Co-authored-by: MaineK00n <[email protected]> * Update detector/vuls2/vendor.go Co-authored-by: MaineK00n <[email protected]> * Refactor * more refactor --------- Co-authored-by: MaineK00n <[email protected]>
1 parent 40e36cc commit e89fc33

File tree

13 files changed

+1243
-15
lines changed

13 files changed

+1243
-15
lines changed

config/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ type Config struct {
4747
Metasploit MetasploitConf `json:"metasploit,omitempty"`
4848
KEVuln KEVulnConf `json:"kevuln,omitempty"`
4949
Cti CtiConf `json:"cti,omitempty"`
50+
Vuls2 Vuls2Conf `json:"vuls2,omitempty"`
5051

5152
Slack SlackConf `json:"-"`
5253
EMail SMTPConf `json:"-"`

config/vulnDictConf.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,3 +328,10 @@ func (cnf *CtiConf) Init() {
328328
cnf.setDefault("go-cti.sqlite3")
329329
cnf.DebugSQL = Conf.DebugSQL
330330
}
331+
332+
// Vuls2Conf is configuration items for vuls2
333+
type Vuls2Conf struct {
334+
Repository string
335+
Path string
336+
SkipUpdate bool
337+
}

detector/detector.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/future-architect/vuls/constant"
1616
"github.com/future-architect/vuls/contrib/owasp-dependency-check/parser"
1717
"github.com/future-architect/vuls/cwe"
18+
"github.com/future-architect/vuls/detector/vuls2"
1819
"github.com/future-architect/vuls/gost"
1920
"github.com/future-architect/vuls/logging"
2021
"github.com/future-architect/vuls/models"
@@ -49,7 +50,7 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
4950
return nil, xerrors.Errorf("Failed to fill with Library dependency: %w", err)
5051
}
5152

52-
if err := DetectPkgCves(&r, config.Conf.OvalDict, config.Conf.Gost, config.Conf.LogOpts); err != nil {
53+
if err := DetectPkgCves(&r, config.Conf.OvalDict, config.Conf.Gost, config.Conf.Vuls2, config.Conf.LogOpts, config.Conf.NoProgress); err != nil {
5354
return nil, xerrors.Errorf("Failed to detect Pkg CVE: %w", err)
5455
}
5556

@@ -317,14 +318,19 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
317318

318319
// DetectPkgCves detects OS pkg cves
319320
// pass 2 configs
320-
func DetectPkgCves(r *models.ScanResult, ovalCnf config.GovalDictConf, gostCnf config.GostConf, logOpts logging.LogOpts) error {
321+
func DetectPkgCves(r *models.ScanResult, ovalCnf config.GovalDictConf, gostCnf config.GostConf, vuls2Conf config.Vuls2Conf, logOpts logging.LogOpts, noProgress bool) error {
321322
// Pkg Scan
322323
if isPkgCvesDetactable(r) {
323324
// OVAL, gost(Debian Security Tracker) does not support Package for Raspbian, so skip it.
324325
if r.Family == constant.Raspbian {
325326
r = r.RemoveRaspbianPackFromResult()
326327
}
327328

329+
// Vuls2
330+
if err := vuls2.Detect(r, vuls2Conf, noProgress); err != nil {
331+
return xerrors.Errorf("Failed to detect CVE with Vuls2: %w", err)
332+
}
333+
328334
// OVAL
329335
if err := detectPkgsCvesWithOval(ovalCnf, r, logOpts); err != nil {
330336
return xerrors.Errorf("Failed to detect CVE with OVAL: %w", err)
@@ -537,6 +543,9 @@ func detectPkgsCvesWithOval(cnf config.GovalDictConf, r *models.ScanResult, logO
537543
logging.Log.Infof("Skip OVAL and Scan with gost alone.")
538544
logging.Log.Infof("%s: %d CVEs are detected with OVAL", r.FormatServerName(), 0)
539545
return nil
546+
case constant.RedHat, constant.CentOS, constant.Alma, constant.Rocky:
547+
logging.Log.Debugf("Skip OVAL and Scan by Vuls2")
548+
return nil
540549
case constant.Windows, constant.MacOSX, constant.MacOSXServer, constant.MacOS, constant.MacOSServer, constant.FreeBSD, constant.ServerTypePseudo:
541550
return nil
542551
default:

detector/vuls2/db.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package vuls2
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path/filepath"
7+
"time"
8+
9+
"github.com/future-architect/vuls/config"
10+
"github.com/future-architect/vuls/logging"
11+
"github.com/pkg/errors"
12+
"golang.org/x/xerrors"
13+
14+
db "github.com/MaineK00n/vuls2/pkg/db/common"
15+
"github.com/MaineK00n/vuls2/pkg/db/fetch"
16+
)
17+
18+
var (
19+
// DefaultGHCRRepository is GitHub Container Registry for vuls2 db
20+
DefaultGHCRRepository = fmt.Sprintf("%s:%d", "ghcr.io/vulsio/vuls-nightly-db", db.SchemaVersion)
21+
22+
// DefaultPath is the path for vuls2 db file
23+
DefaultPath = func() string {
24+
wd, _ := os.Getwd()
25+
return filepath.Join(wd, "vuls.db")
26+
}()
27+
)
28+
29+
func newDBConnection(vuls2Conf config.Vuls2Conf, noProgress bool) (db.DB, error) {
30+
willDownload, err := shouldDownload(vuls2Conf, time.Now())
31+
if err != nil {
32+
return nil, xerrors.Errorf("Failed to check whether to download vuls2 db. err: %w", err)
33+
}
34+
35+
if willDownload {
36+
logging.Log.Infof("Fetching vuls2 db. repository: %s", vuls2Conf.Repository)
37+
if err := fetch.Fetch(fetch.WithRepository(vuls2Conf.Repository), fetch.WithDBPath(vuls2Conf.Path), fetch.WithNoProgress(noProgress)); err != nil {
38+
return nil, xerrors.Errorf("Failed to fetch vuls2 db. err: %w", err)
39+
}
40+
}
41+
42+
dbc, err := (&db.Config{
43+
Type: "boltdb",
44+
Path: vuls2Conf.Path,
45+
}).New()
46+
if err != nil {
47+
return nil, xerrors.Errorf("Failed to new vuls2 db connection. err: %w", err)
48+
}
49+
50+
return dbc, nil
51+
}
52+
53+
func shouldDownload(vuls2Conf config.Vuls2Conf, now time.Time) (bool, error) {
54+
if _, err := os.Stat(vuls2Conf.Path); err != nil {
55+
if errors.Is(err, os.ErrNotExist) {
56+
if vuls2Conf.SkipUpdate {
57+
return false, xerrors.Errorf("%s not found, cannot skip update", vuls2Conf.Path)
58+
}
59+
return true, nil
60+
}
61+
return false, xerrors.Errorf("Failed to stat vuls2 db file. err: %w", err)
62+
}
63+
64+
if vuls2Conf.SkipUpdate {
65+
return false, nil
66+
}
67+
68+
dbc, err := (&db.Config{
69+
Type: "boltdb",
70+
Path: vuls2Conf.Path,
71+
}).New()
72+
if err != nil {
73+
return false, xerrors.Errorf("Failed to new vuls2 db connection. path: %s, err: %w", vuls2Conf.Path, err)
74+
}
75+
76+
if err := dbc.Open(); err != nil {
77+
return false, xerrors.Errorf("Failed to open vuls2 db. path: %s, err: %w", vuls2Conf.Path, err)
78+
}
79+
defer dbc.Close()
80+
81+
metadata, err := dbc.GetMetadata()
82+
if err != nil {
83+
return false, xerrors.Errorf("Failed to get vuls2 db metadata. path: %s, err: %w", vuls2Conf.Path, err)
84+
}
85+
if metadata == nil {
86+
return false, xerrors.Errorf("Unexpected Vuls2 db metadata. metadata: nil,. path: %s", vuls2Conf.Path)
87+
}
88+
89+
if metadata.Downloaded != nil && now.Before((*metadata.Downloaded).Add(1*time.Hour)) {
90+
return false, nil
91+
}
92+
return metadata.LastModified.Add(6 * time.Hour).Before(now), nil
93+
}

detector/vuls2/db_test.go

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package vuls2
2+
3+
import (
4+
"path/filepath"
5+
"reflect"
6+
"testing"
7+
"time"
8+
9+
"golang.org/x/xerrors"
10+
11+
"github.com/MaineK00n/vuls2/pkg/db/common"
12+
"github.com/MaineK00n/vuls2/pkg/db/common/types"
13+
"github.com/future-architect/vuls/config"
14+
)
15+
16+
func Test_shouldDownload(t *testing.T) {
17+
type args struct {
18+
vuls2Conf config.Vuls2Conf
19+
now time.Time
20+
}
21+
tests := []struct {
22+
name string
23+
args args
24+
metadata *types.Metadata
25+
want bool
26+
wantErr bool
27+
}{
28+
{
29+
name: "no db file",
30+
args: args{
31+
vuls2Conf: config.Vuls2Conf{},
32+
now: *parse("2024-01-02T00:00:00Z"),
33+
},
34+
want: true,
35+
},
36+
{
37+
name: "no db file, but skip update",
38+
args: args{
39+
vuls2Conf: config.Vuls2Conf{
40+
SkipUpdate: true,
41+
},
42+
now: *parse("2024-01-02T00:00:00Z"),
43+
},
44+
wantErr: true,
45+
},
46+
{
47+
name: "just created",
48+
args: args{
49+
vuls2Conf: config.Vuls2Conf{},
50+
now: *parse("2024-01-02T00:00:00Z"),
51+
},
52+
metadata: &types.Metadata{
53+
LastModified: *parse("2024-01-02T00:00:00Z"),
54+
Downloaded: parse("2024-01-02T00:00:00Z"),
55+
SchemaVersion: common.SchemaVersion,
56+
},
57+
want: false,
58+
},
59+
{
60+
name: "8 hours old",
61+
args: args{
62+
vuls2Conf: config.Vuls2Conf{},
63+
now: *parse("2024-01-02T08:00:00Z"),
64+
},
65+
metadata: &types.Metadata{
66+
LastModified: *parse("2024-01-02T00:00:00Z"),
67+
Downloaded: parse("2024-01-02T00:00:00Z"),
68+
SchemaVersion: common.SchemaVersion,
69+
},
70+
want: true,
71+
},
72+
{
73+
name: "8 hours old, but skip update",
74+
args: args{
75+
vuls2Conf: config.Vuls2Conf{
76+
SkipUpdate: true,
77+
},
78+
now: *parse("2024-01-02T08:00:00Z"),
79+
},
80+
metadata: &types.Metadata{
81+
LastModified: *parse("2024-01-02T00:00:00Z"),
82+
Downloaded: parse("2024-01-02T00:00:00Z"),
83+
SchemaVersion: common.SchemaVersion,
84+
},
85+
want: false,
86+
},
87+
{
88+
name: "8 hours old, but download recently",
89+
args: args{
90+
vuls2Conf: config.Vuls2Conf{},
91+
now: *parse("2024-01-02T08:00:00Z"),
92+
},
93+
metadata: &types.Metadata{
94+
LastModified: *parse("2024-01-02T00:00:00Z"),
95+
Downloaded: parse("2024-01-02T07:30:00Z"),
96+
SchemaVersion: common.SchemaVersion,
97+
},
98+
want: false,
99+
},
100+
}
101+
for _, tt := range tests {
102+
t.Run(tt.name, func(t *testing.T) {
103+
d := t.TempDir()
104+
tt.args.vuls2Conf.Path = filepath.Join(d, "vuls.db")
105+
if tt.metadata != nil {
106+
if err := putMetadata(*tt.metadata, tt.args.vuls2Conf.Path); err != nil {
107+
t.Errorf("putMetadata err = %v", err)
108+
return
109+
}
110+
}
111+
got, err := shouldDownload(tt.args.vuls2Conf, tt.args.now)
112+
if (err != nil) != tt.wantErr {
113+
t.Errorf("shouldDownload() error = %v, wantErr %v", err, tt.wantErr)
114+
return
115+
}
116+
if !reflect.DeepEqual(got, tt.want) {
117+
t.Errorf("shouldDownload() = %v, want %v", got, tt.want)
118+
}
119+
})
120+
}
121+
122+
}
123+
124+
func putMetadata(metadata types.Metadata, path string) error {
125+
c := common.Config{
126+
Type: "boltdb",
127+
Path: path,
128+
}
129+
dbc, err := c.New()
130+
if err != nil {
131+
return xerrors.Errorf("c.New(). err: %w", err)
132+
}
133+
if err := dbc.Open(); err != nil {
134+
return xerrors.Errorf("dbc.Open(). err: %w", err)
135+
}
136+
defer dbc.Close()
137+
if err := dbc.Initialize(); err != nil {
138+
return xerrors.Errorf("dbc.Initialize(). err: %w", err)
139+
}
140+
if err := dbc.PutMetadata(metadata); err != nil {
141+
return xerrors.Errorf("dbc.PutMetadata(). err: %w", err)
142+
}
143+
return nil
144+
}
145+
146+
func parse(date string) *time.Time {
147+
t, _ := time.Parse(time.RFC3339, date)
148+
return &t
149+
}

0 commit comments

Comments
 (0)