diff --git a/cache/bolt.go b/cache/bolt.go index 400ac80a..ad46ac1f 100644 --- a/cache/bolt.go +++ b/cache/bolt.go @@ -5,8 +5,8 @@ import ( "time" "github.com/boltdb/bolt" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/util" - "github.com/sirupsen/logrus" "golang.org/x/xerrors" ) @@ -14,12 +14,12 @@ import ( // boltdb is used to store a cache of Changelogs of Ubuntu/Debian type Bolt struct { Path string - Log *logrus.Entry + Log logging.Logger db *bolt.DB } // SetupBolt opens a boltdb and creates a meta bucket if not exists. -func SetupBolt(path string, l *logrus.Entry) error { +func SetupBolt(path string, l logging.Logger) error { l.Infof("Open boltDB: %s", path) db, err := bolt.Open(path, 0600, nil) if err != nil { @@ -47,7 +47,7 @@ func (b Bolt) Close() error { return b.db.Close() } -// CreateBucketIfNotExists creates a buket that is specified by arg. +// CreateBucketIfNotExists creates a bucket that is specified by arg. func (b *Bolt) createBucketIfNotExists(name string) error { return b.db.Update(func(tx *bolt.Tx) error { _, err := tx.CreateBucketIfNotExists([]byte(name)) @@ -93,7 +93,7 @@ func (b Bolt) RefreshMeta(meta Meta) error { }) } -// EnsureBuckets puts a Meta information and create a buket that holds changelogs. +// EnsureBuckets puts a Meta information and create a bucket that holds changelogs. func (b Bolt) EnsureBuckets(meta Meta) error { jsonBytes, err := json.Marshal(meta) if err != nil { @@ -159,7 +159,7 @@ func (b Bolt) GetChangelog(servername, packName string) (changelog string, err e return } -// PutChangelog put the changelgo of specified packName into the Bucket +// PutChangelog put the changelog of specified packName into the Bucket func (b Bolt) PutChangelog(servername, packName, changelog string) error { return b.db.Update(func(tx *bolt.Tx) error { bkt := tx.Bucket([]byte(servername)) diff --git a/cache/bolt_test.go b/cache/bolt_test.go index dd78024a..97413d75 100644 --- a/cache/bolt_test.go +++ b/cache/bolt_test.go @@ -7,8 +7,8 @@ import ( "github.com/boltdb/bolt" "github.com/future-architect/vuls/config" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" - "github.com/sirupsen/logrus" ) const path = "/tmp/vuls-test-cache-11111111.db" @@ -29,7 +29,7 @@ var meta = Meta{ } func TestSetupBolt(t *testing.T) { - log := logrus.NewEntry(&logrus.Logger{}) + log := logging.NewNormalLogger() err := SetupBolt(path, log) if err != nil { t.Errorf("Failed to setup bolt: %s", err) @@ -57,7 +57,7 @@ func TestSetupBolt(t *testing.T) { } func TestEnsureBuckets(t *testing.T) { - log := logrus.NewEntry(&logrus.Logger{}) + log := logging.NewNormalLogger() if err := SetupBolt(path, log); err != nil { t.Errorf("Failed to setup bolt: %s", err) } @@ -98,7 +98,7 @@ func TestEnsureBuckets(t *testing.T) { func TestPutGetChangelog(t *testing.T) { clog := "changelog-text" - log := logrus.NewEntry(&logrus.Logger{}) + log := logging.NewNormalLogger() if err := SetupBolt(path, log); err != nil { t.Errorf("Failed to setup bolt: %s", err) } diff --git a/config/config.go b/config/config.go index 7be8974d..d21987ae 100644 --- a/config/config.go +++ b/config/config.go @@ -8,7 +8,7 @@ import ( "github.com/asaskevich/govalidator" "github.com/future-architect/vuls/constant" - log "github.com/sirupsen/logrus" + "github.com/future-architect/vuls/logging" "golang.org/x/xerrors" ) @@ -26,11 +26,11 @@ type Config struct { // scan, report Debug bool `json:"debug,omitempty"` DebugSQL bool `json:"debugSQL,omitempty"` - HTTPProxy string `valid:"url" json:"httpProxy,omitempty"` LogDir string `json:"logDir,omitempty"` + Quiet bool `json:"quiet,omitempty"` + HTTPProxy string `valid:"url" json:"httpProxy,omitempty"` ResultsDir string `json:"resultsDir,omitempty"` Pipe bool `json:"pipe,omitempty"` - Quiet bool `json:"quiet,omitempty"` Default ServerInfo `json:"default,omitempty"` Servers map[string]ServerInfo `json:"servers,omitempty"` @@ -94,7 +94,7 @@ func (c Config) ValidateOnConfigtest() bool { errs = append(errs, err) } for _, err := range errs { - log.Error(err) + logging.Log.Error(err) } return len(errs) == 0 } @@ -113,7 +113,7 @@ func (c Config) ValidateOnScan() bool { errs = append(errs, err) } for _, err := range errs { - log.Error(err) + logging.Log.Error(err) } return len(errs) == 0 } @@ -165,7 +165,7 @@ func (c Config) ValidateOnReport() bool { } for _, err := range errs { - log.Error(err) + logging.Log.Error(err) } return len(errs) == 0 @@ -181,7 +181,7 @@ func (c Config) ValidateOnTui() bool { } } for _, err := range errs { - log.Error(err) + logging.Log.Error(err) } return len(errs) == 0 } @@ -190,7 +190,7 @@ func (c Config) ValidateOnTui() bool { func (c Config) ValidateOnSaaS() bool { saaserrs := c.Saas.Validate() for _, err := range saaserrs { - log.Error("Failed to validate SaaS conf: %+w", err) + logging.Log.Error("Failed to validate SaaS conf: %+w", err) } return len(saaserrs) == 0 } diff --git a/config/vulnDictConf.go b/config/vulnDictConf.go index 3d26a61a..2f427e7b 100644 --- a/config/vulnDictConf.go +++ b/config/vulnDictConf.go @@ -7,8 +7,8 @@ import ( "time" "github.com/asaskevich/govalidator" + "github.com/future-architect/vuls/logging" "github.com/parnurzeal/gorequest" - log "github.com/sirupsen/logrus" "golang.org/x/xerrors" ) @@ -35,7 +35,7 @@ type VulnDict struct { // Validate settings func (cnf *VulnDict) Validate() error { - log.Infof("%s.type=%s, %s.url=%s, %s.SQLite3Path=%s", + logging.Log.Infof("%s.type=%s, %s.url=%s, %s.SQLite3Path=%s", cnf.Name, cnf.Type, cnf.Name, cnf.URL, cnf.Name, cnf.SQLite3Path) switch cnf.Type { diff --git a/detector/cve_client.go b/detector/cve_client.go index 0570ca38..30c08004 100644 --- a/detector/cve_client.go +++ b/detector/cve_client.go @@ -13,6 +13,7 @@ import ( "golang.org/x/xerrors" "github.com/future-architect/vuls/config" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/util" cvedb "github.com/kotakanbe/go-cve-dictionary/db" cvemodels "github.com/kotakanbe/go-cve-dictionary/models" @@ -76,7 +77,7 @@ func (api cvedictClient) FetchCveDetails(driver cvedb.DB, cveIDs []string) (cveD if err != nil { errChan <- err } else { - util.Log.Debugf("HTTP Request to %s", url) + logging.Log.Debugf("HTTP Request to %s", url) api.httpGet(cveID, url, resChan, errChan) } } @@ -116,13 +117,13 @@ func (api cvedictClient) httpGet(key, url string, resChan chan<- response, errCh // resp, body, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End() resp, body, errs = gorequest.New().Timeout(10 * time.Second).Get(url).End() if 0 < len(errs) || resp == nil || resp.StatusCode != 200 { - return xerrors.Errorf("HTTP GET Error, url: %s, resp: %v, err: %s", + return xerrors.Errorf("HTTP GET Error, url: %s, resp: %v, err: %+v", url, resp, errs) } return nil } notify := func(err error, t time.Duration) { - util.Log.Warnf("Failed to HTTP GET. retrying in %s seconds. err: %s", + logging.Log.Warnf("Failed to HTTP GET. retrying in %s seconds. err: %+v", t, err) } err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify) @@ -150,7 +151,7 @@ func (api cvedictClient) FetchCveDetailsByCpeName(driver cvedb.DB, cpeName strin } query := map[string]string{"name": cpeName} - util.Log.Debugf("HTTP Request to %s, query: %#v", url, query) + logging.Log.Debugf("HTTP Request to %s, query: %#v", url, query) return api.httpPost(cpeName, url, query) } return driver.GetByCpeURI(cpeName) @@ -168,12 +169,12 @@ func (api cvedictClient) httpPost(key, url string, query map[string]string) ([]c } resp, body, errs = req.End() if 0 < len(errs) || resp == nil || resp.StatusCode != 200 { - return xerrors.Errorf("HTTP POST error. url: %s, resp: %v, err: %s", url, resp, errs) + return xerrors.Errorf("HTTP POST error. url: %s, resp: %v, err: %+v", url, resp, errs) } return nil } notify := func(err error, t time.Duration) { - util.Log.Warnf("Failed to HTTP POST. retrying in %s seconds. err: %s", t, err) + logging.Log.Warnf("Failed to HTTP POST. retrying in %s seconds. err: %+v", t, err) } err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify) if err != nil { diff --git a/detector/db_client.go b/detector/db_client.go index 4abb437b..583b6fb1 100644 --- a/detector/db_client.go +++ b/detector/db_client.go @@ -6,7 +6,7 @@ import ( "os" "github.com/future-architect/vuls/config" - "github.com/future-architect/vuls/util" + "github.com/future-architect/vuls/logging" gostdb "github.com/knqyf263/gost/db" cvedb "github.com/kotakanbe/go-cve-dictionary/db" ovaldb "github.com/kotakanbe/goval-dictionary/db" @@ -49,7 +49,7 @@ func NewDBClient(cnf DBClientConf) (dbclient *DBClient, locked bool, err error) return nil, true, xerrors.Errorf("OvalDB is locked: %s", cnf.OvalDictCnf.SQLite3Path) } else if err != nil { - util.Log.Warnf("Unable to use OvalDB: %s, err: %s", + logging.Log.Warnf("Unable to use OvalDB: %s, err: %+v", cnf.OvalDictCnf.SQLite3Path, err) } @@ -58,7 +58,7 @@ func NewDBClient(cnf DBClientConf) (dbclient *DBClient, locked bool, err error) return nil, true, xerrors.Errorf("gostDB is locked: %s", cnf.GostCnf.SQLite3Path) } else if err != nil { - util.Log.Warnf("Unable to use gostDB: %s, err: %s", + logging.Log.Warnf("Unable to use gostDB: %s, err: %+v", cnf.GostCnf.SQLite3Path, err) } @@ -67,7 +67,7 @@ func NewDBClient(cnf DBClientConf) (dbclient *DBClient, locked bool, err error) return nil, true, xerrors.Errorf("exploitDB is locked: %s", cnf.ExploitCnf.SQLite3Path) } else if err != nil { - util.Log.Warnf("Unable to use exploitDB: %s, err: %s", + logging.Log.Warnf("Unable to use exploitDB: %s, err: %+v", cnf.ExploitCnf.SQLite3Path, err) } @@ -76,7 +76,7 @@ func NewDBClient(cnf DBClientConf) (dbclient *DBClient, locked bool, err error) return nil, true, xerrors.Errorf("metasploitDB is locked: %s", cnf.MetasploitCnf.SQLite3Path) } else if err != nil { - util.Log.Warnf("Unable to use metasploitDB: %s, err: %s", + logging.Log.Warnf("Unable to use metasploitDB: %s, err: %+v", cnf.MetasploitCnf.SQLite3Path, err) } @@ -94,17 +94,17 @@ func NewCveDB(cnf DBClientConf) (driver cvedb.DB, locked bool, err error) { if cnf.CveDictCnf.IsFetchViaHTTP() { return nil, false, nil } - util.Log.Debugf("open cve-dictionary db (%s)", cnf.CveDictCnf.Type) + logging.Log.Debugf("open cve-dictionary db (%s)", cnf.CveDictCnf.Type) path := cnf.CveDictCnf.URL if cnf.CveDictCnf.Type == "sqlite3" { path = cnf.CveDictCnf.SQLite3Path if _, err := os.Stat(path); os.IsNotExist(err) { - util.Log.Warnf("--cvedb-path=%s file not found. [CPE-scan](https://vuls.io/docs/en/usage-scan-non-os-packages.html#cpe-scan) needs cve-dictionary. if you specify cpe in config.toml, fetch cve-dictionary before reporting. For details, see `https://github.com/kotakanbe/go-cve-dictionary#deploy-go-cve-dictionary`", path) + logging.Log.Warnf("--cvedb-path=%s file not found. [CPE-scan](https://vuls.io/docs/en/usage-scan-non-os-packages.html#cpe-scan) needs cve-dictionary. if you specify cpe in config.toml, fetch cve-dictionary before reporting. For details, see `https://github.com/kotakanbe/go-cve-dictionary#deploy-go-cve-dictionary`", path) return nil, false, nil } } - util.Log.Debugf("Open cve-dictionary db (%s): %s", cnf.CveDictCnf.Type, path) + logging.Log.Debugf("Open cve-dictionary db (%s): %s", cnf.CveDictCnf.Type, path) driver, locked, err = cvedb.NewDB(cnf.CveDictCnf.Type, path, cnf.DebugSQL) if err != nil { err = xerrors.Errorf("Failed to init CVE DB. err: %w, path: %s", err, path) @@ -123,12 +123,12 @@ func NewOvalDB(cnf DBClientConf) (driver ovaldb.DB, locked bool, err error) { path = cnf.OvalDictCnf.SQLite3Path if _, err := os.Stat(path); os.IsNotExist(err) { - util.Log.Warnf("--ovaldb-path=%s file not found", path) + logging.Log.Warnf("--ovaldb-path=%s file not found", path) return nil, false, nil } } - util.Log.Debugf("Open oval-dictionary db (%s): %s", cnf.OvalDictCnf.Type, path) + logging.Log.Debugf("Open oval-dictionary db (%s): %s", cnf.OvalDictCnf.Type, path) driver, locked, err = ovaldb.NewDB("", cnf.OvalDictCnf.Type, path, cnf.DebugSQL) if err != nil { err = xerrors.Errorf("Failed to new OVAL DB. err: %w", err) @@ -150,16 +150,15 @@ func NewGostDB(cnf DBClientConf) (driver gostdb.DB, locked bool, err error) { path = cnf.GostCnf.SQLite3Path if _, err := os.Stat(path); os.IsNotExist(err) { - util.Log.Warnf("--gostdb-path=%s file not found. Vuls can detect `patch-not-released-CVE-ID` using gost if the scan target server is Debian, RHEL or CentOS, For details, see `https://github.com/knqyf263/gost#fetch-redhat`", path) + logging.Log.Warnf("--gostdb-path=%s file not found. Vuls can detect `patch-not-released-CVE-ID` using gost if the scan target server is Debian, RHEL or CentOS, For details, see `https://github.com/knqyf263/gost#fetch-redhat`", path) return nil, false, nil } } - util.Log.Debugf("Open gost db (%s): %s", cnf.GostCnf.Type, path) + logging.Log.Debugf("Open gost db (%s): %s", cnf.GostCnf.Type, path) if driver, locked, err = gostdb.NewDB(cnf.GostCnf.Type, path, cnf.DebugSQL); err != nil { if locked { - util.Log.Errorf("gostDB is locked. err: %+v", err) - return nil, true, err + return nil, true, xerrors.Errorf("gostDB is locked. err: %w", err) } return nil, false, err } @@ -176,16 +175,15 @@ func NewExploitDB(cnf DBClientConf) (driver exploitdb.DB, locked bool, err error path = cnf.ExploitCnf.SQLite3Path if _, err := os.Stat(path); os.IsNotExist(err) { - util.Log.Warnf("--exploitdb-path=%s file not found. Fetch go-exploit-db before reporting if you want to display exploit codes of detected CVE-IDs. For details, see `https://github.com/vulsio/go-exploitdb`", path) + logging.Log.Warnf("--exploitdb-path=%s file not found. Fetch go-exploit-db before reporting if you want to display exploit codes of detected CVE-IDs. For details, see `https://github.com/vulsio/go-exploitdb`", path) return nil, false, nil } } - util.Log.Debugf("Open exploit db (%s): %s", cnf.ExploitCnf.Type, path) + logging.Log.Debugf("Open exploit db (%s): %s", cnf.ExploitCnf.Type, path) if driver, locked, err = exploitdb.NewDB(cnf.ExploitCnf.Type, path, cnf.DebugSQL); err != nil { if locked { - util.Log.Errorf("exploitDB is locked. err: %+v", err) - return nil, true, err + return nil, true, xerrors.Errorf("exploitDB is locked. err: %w", err) } return nil, false, err } @@ -202,16 +200,15 @@ func NewMetasploitDB(cnf DBClientConf) (driver metasploitdb.DB, locked bool, err path = cnf.MetasploitCnf.SQLite3Path if _, err := os.Stat(path); os.IsNotExist(err) { - util.Log.Warnf("--msfdb-path=%s file not found. Fetch go-msfdb before reporting if you want to display metasploit modules of detected CVE-IDs. For details, see `https://github.com/takuzoo3868/go-msfdb`", path) + logging.Log.Warnf("--msfdb-path=%s file not found. Fetch go-msfdb before reporting if you want to display metasploit modules of detected CVE-IDs. For details, see `https://github.com/takuzoo3868/go-msfdb`", path) return nil, false, nil } } - util.Log.Debugf("Open metasploit db (%s): %s", cnf.MetasploitCnf.Type, path) + logging.Log.Debugf("Open metasploit db (%s): %s", cnf.MetasploitCnf.Type, path) if driver, locked, err = metasploitdb.NewDB(cnf.MetasploitCnf.Type, path, cnf.DebugSQL, false); err != nil { if locked { - util.Log.Errorf("metasploitDB is locked. err: %+v", err) - return nil, true, err + return nil, true, xerrors.Errorf("metasploitDB is locked. err: %w", err) } return nil, false, err } @@ -219,15 +216,17 @@ func NewMetasploitDB(cnf DBClientConf) (driver metasploitdb.DB, locked bool, err } // CloseDB close dbs -func (d DBClient) CloseDB() { +func (d DBClient) CloseDB() (errs []error) { if d.CveDB != nil { if err := d.CveDB.CloseDB(); err != nil { - util.Log.Errorf("Failed to close DB. err: %+v", err) + errs = append(errs, xerrors.Errorf("Failed to close cveDB. err: %+v", err)) } } if d.OvalDB != nil { if err := d.OvalDB.CloseDB(); err != nil { - util.Log.Errorf("Failed to close DB. err: %+v", err) + errs = append(errs, xerrors.Errorf("Failed to close ovalDB. err: %+v", err)) } } + //TODO CloseDB gost, exploitdb, metasploit + return errs } diff --git a/detector/detector.go b/detector/detector.go index 8666de90..0da7994f 100644 --- a/detector/detector.go +++ b/detector/detector.go @@ -7,13 +7,13 @@ import ( "strings" "time" - "github.com/future-architect/vuls/config" c "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/constant" "github.com/future-architect/vuls/contrib/owasp-dependency-check/parser" "github.com/future-architect/vuls/cwe" "github.com/future-architect/vuls/exploit" "github.com/future-architect/vuls/gost" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/future-architect/vuls/msf" "github.com/future-architect/vuls/oval" @@ -29,7 +29,7 @@ import ( ) // type Detector struct { -// Targets map[string]config.ServerInfo +// Targets map[string]c.ServerInfo // } // Detect vulns and fill CVE detailed information @@ -39,7 +39,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca reportedAt := time.Now() for i, r := range rs { if !c.Conf.RefreshCve && !needToRefreshCve(r) { - util.Log.Info("No need to refresh") + logging.Log.Info("No need to refresh") continue } @@ -94,7 +94,7 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca return nil, xerrors.Errorf("Failed to detect GitHub Cves: %w", err) } - if err := DetectWordPressCves(&r, &config.Conf.WpScan); err != nil { + if err := DetectWordPressCves(&r, &c.Conf.WpScan); err != nil { return nil, xerrors.Errorf("Failed to detect WordPress Cves: %w", err) } @@ -150,8 +150,8 @@ func Detect(dbclient DBClient, rs []models.ScanResult, dir string) ([]models.Sca // ignorePkgs ignorePkgsRegexps := []string{} if r.Container.Name == "" { - ignorePkgsRegexps = config.Conf.Servers[r.ServerName].IgnorePkgsRegexp - } else if s, ok := config.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok { + ignorePkgsRegexps = c.Conf.Servers[r.ServerName].IgnorePkgsRegexp + } else if s, ok := c.Conf.Servers[r.ServerName].Containers[r.Container.Name]; ok { ignorePkgsRegexps = s.IgnorePkgsRegexp } r = r.FilterIgnorePkgs(ignorePkgsRegexps) @@ -180,9 +180,9 @@ func DetectPkgCves(dbclient DBClient, r *models.ScanResult) error { return xerrors.Errorf("Failed to detect CVE with gost: %w", err) } } else if reuseScannedCves(r) { - util.Log.Infof("r.Release is empty. Use CVEs as it as.") + logging.Log.Infof("r.Release is empty. Use CVEs as it as.") } else if r.Family == constant.ServerTypePseudo { - util.Log.Infof("pseudo type. Skip OVAL and gost detection") + logging.Log.Infof("pseudo type. Skip OVAL and gost detection") } else { return xerrors.Errorf("Failed to fill CVEs. r.Release is empty") } @@ -205,7 +205,7 @@ func DetectPkgCves(dbclient DBClient, r *models.ScanResult) error { for _, ipPort := range proc.ListenPorts { ps, err := models.NewPortStat(ipPort) if err != nil { - util.Log.Warnf("Failed to parse ip:port: %s, err:%+v", ipPort, err) + logging.Log.Warnf("Failed to parse ip:port: %s, err:%+v", ipPort, err) continue } r.Packages[i].AffectedProcs[j].ListenPortStats = append( @@ -232,7 +232,7 @@ func DetectGitHubCves(r *models.ScanResult, githubConfs map[string]c.GitHubConf, if err != nil { return xerrors.Errorf("Failed to access GitHub Security Alerts: %w", err) } - util.Log.Infof("%s: %d CVEs detected with GHSA %s/%s", + logging.Log.Infof("%s: %d CVEs detected with GHSA %s/%s", r.FormatServerName(), n, owner, repo) } return nil @@ -243,44 +243,44 @@ func DetectWordPressCves(r *models.ScanResult, wpCnf *c.WpScanConf) error { if len(r.WordPressPackages) == 0 { return nil } - util.Log.Infof("Detect WordPress CVE. pkgs: %d ", len(r.WordPressPackages)) + logging.Log.Infof("Detect WordPress CVE. pkgs: %d ", len(r.WordPressPackages)) n, err := detectWordPressCves(r, wpCnf) if err != nil { return xerrors.Errorf("Failed to detect WordPress CVE: %w", err) } - util.Log.Infof("%s: found %d WordPress CVEs", r.FormatServerName(), n) + logging.Log.Infof("%s: found %d WordPress CVEs", r.FormatServerName(), n) return nil } // FillCveInfo fill scanResult with cve info. func FillCveInfo(dbclient DBClient, r *models.ScanResult) error { - util.Log.Infof("Fill CVE detailed with gost") + logging.Log.Infof("Fill CVE detailed with gost") if err := gost.NewClient(r.Family).FillCVEsWithRedHat(dbclient.GostDB, r); err != nil { return xerrors.Errorf("Failed to fill with gost: %w", err) } - util.Log.Infof("Fill CVE detailed with CVE-DB") + logging.Log.Infof("Fill CVE detailed with CVE-DB") if err := fillCvesWithNvdJvn(dbclient.CveDB, r); err != nil { return xerrors.Errorf("Failed to fill with CVE: %w", err) } - util.Log.Infof("Fill exploit with Exploit-DB") + logging.Log.Infof("Fill exploit with Exploit-DB") nExploitCve, err := fillWithExploitDB(dbclient.ExploitDB, r) if err != nil { return xerrors.Errorf("Failed to fill with exploit: %w", err) } - util.Log.Infof("%s: %d exploits are detected", + logging.Log.Infof("%s: %d exploits are detected", r.FormatServerName(), nExploitCve) - util.Log.Infof("Fill metasploit module with Metasploit-DB") + logging.Log.Infof("Fill metasploit module with Metasploit-DB") nMetasploitCve, err := fillWithMetasploit(dbclient.MetasploitDB, r) if err != nil { return xerrors.Errorf("Failed to fill with metasploit: %w", err) } - util.Log.Infof("%s: %d modules are detected", + logging.Log.Infof("%s: %d modules are detected", r.FormatServerName(), nMetasploitCve) - util.Log.Infof("Fill CWE with NVD") + logging.Log.Infof("Fill CWE with NVD") fillCweDict(r) return nil @@ -397,7 +397,7 @@ func detectPkgsCvesWithOval(driver ovaldb.DB, r *models.ScanResult) error { } } - util.Log.Debugf("Check whether oval fetched: %s %s", ovalFamily, r.Release) + logging.Log.Debugf("Check whether oval fetched: %s %s", ovalFamily, r.Release) ok, err := ovalClient.CheckIfOvalFetched(driver, ovalFamily, r.Release) if err != nil { return err @@ -416,14 +416,14 @@ func detectPkgsCvesWithOval(driver ovaldb.DB, r *models.ScanResult) error { return err } - util.Log.Infof("%s: %d CVEs are detected with OVAL", r.FormatServerName(), nCVEs) + logging.Log.Infof("%s: %d CVEs are detected with OVAL", r.FormatServerName(), nCVEs) return nil } func detectPkgsCvesWithGost(driver gostdb.DB, r *models.ScanResult) error { nCVEs, err := gost.NewClient(r.Family).DetectUnfixed(driver, r, true) - util.Log.Infof("%s: %d unfixed CVEs are detected with gost", + logging.Log.Infof("%s: %d unfixed CVEs are detected with gost", r.FormatServerName(), nCVEs) return err } @@ -431,7 +431,7 @@ func detectPkgsCvesWithGost(driver gostdb.DB, r *models.ScanResult) error { // fillWithExploitDB fills Exploits with exploit dataabase // https://github.com/vulsio/go-exploitdb func fillWithExploitDB(driver exploitdb.DB, r *models.ScanResult) (nExploitCve int, err error) { - return exploit.FillWithExploit(driver, r, &config.Conf.Exploit) + return exploit.FillWithExploit(driver, r, &c.Conf.Exploit) } // fillWithMetasploit fills metasploit modules with metasploit database @@ -471,7 +471,7 @@ func DetectCpeURIsCves(driver cvedb.DB, r *models.ScanResult, cpeURIs []string) } } } - util.Log.Infof("%s: %d CVEs are detected with CPE", r.FormatServerName(), nCVEs) + logging.Log.Infof("%s: %d CVEs are detected with CPE", r.FormatServerName(), nCVEs) return nil } @@ -503,7 +503,7 @@ func fillCweDict(r *models.ScanResult) { } entry.En = &e } else { - util.Log.Debugf("CWE-ID %s is not found in English CWE Dict", id) + logging.Log.Debugf("CWE-ID %s is not found in English CWE Dict", id) entry.En = &cwe.Cwe{CweID: id} } @@ -520,7 +520,7 @@ func fillCweDict(r *models.ScanResult) { } entry.Ja = &e } else { - util.Log.Debugf("CWE-ID %s is not found in Japanese CWE Dict", id) + logging.Log.Debugf("CWE-ID %s is not found in Japanese CWE Dict", id) entry.Ja = &cwe.Cwe{CweID: id} } } diff --git a/detector/library.go b/detector/library.go index 05f39896..273b9aae 100644 --- a/detector/library.go +++ b/detector/library.go @@ -12,8 +12,8 @@ import ( "golang.org/x/xerrors" "k8s.io/utils/clock" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" - "github.com/future-architect/vuls/util" ) // DetectLibsCves fills LibraryScanner information @@ -29,7 +29,7 @@ func DetectLibsCves(r *models.ScanResult, cacheDir string, noProgress bool) (err return err } - util.Log.Info("Updating library db...") + logging.Log.Info("Updating library db...") if err := downloadDB("", cacheDir, noProgress, false, false); err != nil { return err } @@ -56,7 +56,7 @@ func DetectLibsCves(r *models.ScanResult, cacheDir string, noProgress bool) (err totalCnt += len(vinfos) } - util.Log.Infof("%s: %d CVEs are detected with Library", + logging.Log.Infof("%s: %d CVEs are detected with Library", r.FormatServerName(), totalCnt) return nil @@ -71,8 +71,8 @@ func downloadDB(appVersion, cacheDir string, quiet, light, skipUpdate bool) erro } if needsUpdate { - util.Log.Info("Need to update DB") - util.Log.Info("Downloading DB...") + logging.Log.Info("Need to update DB") + logging.Log.Info("Downloading DB...") if err := client.Download(ctx, cacheDir, light); err != nil { return xerrors.Errorf("failed to download vulnerability DB: %w", err) } @@ -105,7 +105,7 @@ func showDBInfo(cacheDir string) error { if err != nil { return xerrors.Errorf("something wrong with DB: %w", err) } - util.Log.Debugf("DB Schema: %d, Type: %d, UpdatedAt: %s, NextUpdate: %s", + logging.Log.Debugf("DB Schema: %d, Type: %d, UpdatedAt: %s, NextUpdate: %s", metadata.Version, metadata.Type, metadata.UpdatedAt, metadata.NextUpdate) return nil } diff --git a/detector/util.go b/detector/util.go index 550e4fb2..d723967d 100644 --- a/detector/util.go +++ b/detector/util.go @@ -12,8 +12,8 @@ import ( "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/constant" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" - "github.com/future-architect/vuls/util" "golang.org/x/xerrors" ) @@ -57,15 +57,15 @@ func loadPrevious(currs models.ScanResults) (prevs models.ScanResults, err error path := filepath.Join(dir, filename) r, err := loadOneServerScanResult(path) if err != nil { - util.Log.Debugf("%+v", err) + logging.Log.Debugf("%+v", err) continue } if r.Family == result.Family && r.Release == result.Release { prevs = append(prevs, *r) - util.Log.Infof("Previous json found: %s", path) + logging.Log.Infof("Previous json found: %s", path) break } else { - util.Log.Infof("Previous json is different family.Release: %s, pre: %s.%s cur: %s.%s", + logging.Log.Infof("Previous json is different family.Release: %s, pre: %s.%s cur: %s.%s", path, r.Family, r.Release, result.Family, result.Release) } } @@ -137,27 +137,27 @@ func getPlusDiffCves(previous, current models.ScanResult) models.VulnInfos { if isCveInfoUpdated(v.CveID, previous, current) { v.DiffStatus = models.DiffPlus updated[v.CveID] = v - util.Log.Debugf("updated: %s", v.CveID) + logging.Log.Debugf("updated: %s", v.CveID) // TODO commented out because a bug of diff logic when multiple oval defs found for a certain CVE-ID and same updated_at // if these OVAL defs have different affected packages, this logic detects as updated. // This logic will be uncomented after integration with gost https://github.com/knqyf263/gost // } else if isCveFixed(v, previous) { // updated[v.CveID] = v - // util.Log.Debugf("fixed: %s", v.CveID) + // logging.Log.Debugf("fixed: %s", v.CveID) } else { - util.Log.Debugf("same: %s", v.CveID) + logging.Log.Debugf("same: %s", v.CveID) } } else { - util.Log.Debugf("new: %s", v.CveID) + logging.Log.Debugf("new: %s", v.CveID) v.DiffStatus = models.DiffPlus new[v.CveID] = v } } if len(updated) == 0 && len(new) == 0 { - util.Log.Infof("%s: There are %d vulnerabilities, but no difference between current result and previous one.", current.FormatServerName(), len(current.ScannedCves)) + logging.Log.Infof("%s: There are %d vulnerabilities, but no difference between current result and previous one.", current.FormatServerName(), len(current.ScannedCves)) } for cveID, vuln := range new { @@ -177,11 +177,11 @@ func getMinusDiffCves(previous, current models.ScanResult) models.VulnInfos { if !currentCveIDsSet[v.CveID] { v.DiffStatus = models.DiffMinus clear[v.CveID] = v - util.Log.Debugf("clear: %s", v.CveID) + logging.Log.Debugf("clear: %s", v.CveID) } } if len(clear) == 0 { - util.Log.Infof("%s: There are %d vulnerabilities, but no difference between current result and previous one.", current.FormatServerName(), len(current.ScannedCves)) + logging.Log.Infof("%s: There are %d vulnerabilities, but no difference between current result and previous one.", current.FormatServerName(), len(current.ScannedCves)) } return clear @@ -218,7 +218,7 @@ func isCveInfoUpdated(cveID string, previous, current models.ScanResult) bool { for _, t := range cTypes { if !curLastModified[t].Equal(prevLastModified[t]) { - util.Log.Debugf("%s LastModified not equal: \n%s\n%s", + logging.Log.Debugf("%s LastModified not equal: \n%s\n%s", cveID, curLastModified[t], prevLastModified[t]) return true } diff --git a/detector/wordpress.go b/detector/wordpress.go index ceabc9ce..0aabcdbc 100644 --- a/detector/wordpress.go +++ b/detector/wordpress.go @@ -9,9 +9,9 @@ import ( "strings" "time" - "github.com/future-architect/vuls/config" c "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/errof" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/future-architect/vuls/util" version "github.com/hashicorp/go-version" @@ -116,7 +116,7 @@ func wpscan(url, name, token string) (vinfos []models.VulnInfo, err error) { return nil, err } if body == "" { - util.Log.Debugf("wpscan.com response body is empty. URL: %s", url) + logging.Log.Debugf("wpscan.com response body is empty. URL: %s", url) } return convertToVinfos(name, body) } @@ -126,17 +126,17 @@ func detect(installed models.WpPackage, candidates []models.VulnInfo) (vulns []m for _, fixstat := range v.WpPackageFixStats { ok, err := match(installed.Version, fixstat.FixedIn) if err != nil { - util.Log.Errorf("Failed to compare versions %s installed: %s, fixedIn: %s, v: %+v", + logging.Log.Warnf("Failed to compare versions %s installed: %s, fixedIn: %s, v: %+v", installed.Name, installed.Version, fixstat.FixedIn, v) // continue scanning continue } if ok { vulns = append(vulns, v) - util.Log.Debugf("Affected: %s installed: %s, fixedIn: %s", + logging.Log.Debugf("Affected: %s installed: %s, fixedIn: %s", installed.Name, installed.Version, fixstat.FixedIn) } else { - util.Log.Debugf("Not affected: %s : %s, fixedIn: %s", + logging.Log.Debugf("Not affected: %s : %s, fixedIn: %s", installed.Name, installed.Version, fixstat.FixedIn) } } @@ -227,7 +227,7 @@ func httpRequest(url, token string) (string, error) { fmt.Sprintf("Failed to access to wpscan.com. err: %s", err)) } req.Header.Set("Authorization", fmt.Sprintf("Token token=%s", token)) - client, err := util.GetHTTPClient(config.Conf.HTTPProxy) + client, err := util.GetHTTPClient(c.Conf.HTTPProxy) if err != nil { return "", err } @@ -251,7 +251,7 @@ func httpRequest(url, token string) (string, error) { return "", errof.New(errof.ErrWpScanAPILimitExceeded, fmt.Sprintf("wpscan.com API limit exceeded: %+v", resp.Status)) } else { - util.Log.Warnf("wpscan.com unknown status code: %+v", resp.Status) + logging.Log.Warnf("wpscan.com unknown status code: %+v", resp.Status) return "", nil } } diff --git a/exploit/util.go b/exploit/util.go index e653c9aa..60c3970c 100644 --- a/exploit/util.go +++ b/exploit/util.go @@ -5,6 +5,7 @@ import ( "time" "github.com/cenkalti/backoff" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/util" "github.com/parnurzeal/gorequest" "golang.org/x/xerrors" @@ -46,7 +47,7 @@ func getCvesViaHTTP(cveIDs []string, urlPrefix string) ( if err != nil { errChan <- err } else { - util.Log.Debugf("HTTP Request to %s", url) + logging.Log.Debugf("HTTP Request to %s", url) httpGet(url, req, resChan, errChan) } } @@ -91,12 +92,12 @@ func httpGet(url string, req request, resChan chan<- response, errChan chan<- er if count == retryMax { return nil } - return xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %s", url, resp, errs) + return xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %+v", url, resp, errs) } return nil } notify := func(err error, t time.Duration) { - util.Log.Warnf("Failed to HTTP GET. retrying in %s seconds. err: %s", t, err) + logging.Log.Warnf("Failed to HTTP GET. retrying in %s seconds. err: %+v", t, err) } err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify) if err != nil { diff --git a/gost/debian.go b/gost/debian.go index 94fc1c42..e3affd11 100644 --- a/gost/debian.go +++ b/gost/debian.go @@ -7,6 +7,7 @@ import ( "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/constant" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/future-architect/vuls/util" "github.com/knqyf263/gost/db" @@ -37,7 +38,7 @@ func (deb Debian) supported(major string) bool { func (deb Debian) DetectUnfixed(driver db.DB, r *models.ScanResult, _ bool) (nCVEs int, err error) { if !deb.supported(major(r.Release)) { // only logging - util.Log.Warnf("Debian %s is not supported yet", r.Release) + logging.Log.Warnf("Debian %s is not supported yet", r.Release) return 0, nil } diff --git a/gost/util.go b/gost/util.go index 3dbf90f5..a3149b24 100644 --- a/gost/util.go +++ b/gost/util.go @@ -6,6 +6,7 @@ import ( "time" "github.com/cenkalti/backoff" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/future-architect/vuls/util" "github.com/parnurzeal/gorequest" @@ -48,7 +49,7 @@ func getCvesViaHTTP(cveIDs []string, urlPrefix string) ( if err != nil { errChan <- err } else { - util.Log.Debugf("HTTP Request to %s", url) + logging.Log.Debugf("HTTP Request to %s", url) httpGet(url, req, resChan, errChan) } } @@ -122,7 +123,7 @@ func getAllUnfixedCvesViaHTTP(r *models.ScanResult, urlPrefix string) ( if err != nil { errChan <- err } else { - util.Log.Debugf("HTTP Request to %s", url) + logging.Log.Debugf("HTTP Request to %s", url) httpGet(url, req, resChan, errChan) } } @@ -160,12 +161,12 @@ func httpGet(url string, req request, resChan chan<- response, errChan chan<- er if count == retryMax { return nil } - return xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %s", url, resp, errs) + return xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %+v", url, resp, errs) } return nil } notify := func(err error, t time.Duration) { - util.Log.Warnf("Failed to HTTP GET. retrying in %s seconds. err: %s", t, err) + logging.Log.Warnf("Failed to HTTP GET. retrying in %s seconds. err: %+v", t, err) } err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify) if err != nil { diff --git a/util/logutil.go b/logging/logutil.go similarity index 58% rename from util/logutil.go rename to logging/logutil.go index 1fb04789..d9af74b2 100644 --- a/util/logutil.go +++ b/logging/logutil.go @@ -1,4 +1,4 @@ -package util +package logging import ( "flag" @@ -12,66 +12,75 @@ import ( "github.com/rifflock/lfshook" "github.com/sirupsen/logrus" - "github.com/future-architect/vuls/config" formatter "github.com/kotakanbe/logrus-prefixed-formatter" ) // Log for localhost -var Log *logrus.Entry +var Log Logger + +// Logger has logrus entry +type Logger struct { + logrus.Entry +} func init() { log := logrus.New() log.Out = ioutil.Discard fields := logrus.Fields{"prefix": ""} - Log = log.WithFields(fields) + Log = Logger{Entry: *log.WithFields(fields)} +} + +// NewNormalLogger creates normal logger +func NewNormalLogger() Logger { + return Logger{Entry: logrus.Entry{Logger: logrus.New()}} } // NewCustomLogger creates logrus -func NewCustomLogger(server config.ServerInfo) *logrus.Entry { +func NewCustomLogger(debug, quiet bool, logDir, logMsgAnsiColor, serverName string) Logger { log := logrus.New() - log.Formatter = &formatter.TextFormatter{MsgAnsiColor: server.LogMsgAnsiColor} + log.Formatter = &formatter.TextFormatter{MsgAnsiColor: logMsgAnsiColor} log.Level = logrus.InfoLevel - if config.Conf.Debug { + if debug { log.Level = logrus.DebugLevel pp.ColoringEnabled = false } if flag.Lookup("test.v") != nil { - return logrus.NewEntry(log) + return Logger{Entry: *logrus.NewEntry(log)} } // File output - logDir := GetDefaultLogDir() - if 0 < len(config.Conf.LogDir) { - logDir = config.Conf.LogDir + dir := GetDefaultLogDir() + if logDir != "" { + dir = logDir } // Only log to a file if quiet mode enabled - if config.Conf.Quiet && flag.Lookup("test.v") == nil { - if _, err := os.Stat(logDir); os.IsNotExist(err) { - if err := os.Mkdir(logDir, 0700); err != nil { - log.Errorf("Failed to create log directory. path: %s, err: %s", logDir, err) + if quiet && flag.Lookup("test.v") == nil { + if _, err := os.Stat(dir); os.IsNotExist(err) { + if err := os.Mkdir(dir, 0700); err != nil { + log.Errorf("Failed to create log directory. path: %s, err: %+v", dir, err) } } - logFile := logDir + "/vuls.log" + logFile := dir + "/vuls.log" if file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644); err == nil { log.Out = file } else { log.Out = os.Stderr - log.Errorf("Failed to create log file. path: %s, err: %s", logFile, err) + log.Errorf("Failed to create log file. path: %s, err: %+v", logFile, err) } } else { log.Out = os.Stderr } whereami := "localhost" - if 0 < len(server.ServerName) { - whereami = server.GetServerName() + if 0 < len(serverName) { + whereami = serverName } - if _, err := os.Stat(logDir); err == nil { - path := filepath.Join(logDir, fmt.Sprintf("%s.log", whereami)) + if _, err := os.Stat(dir); err == nil { + path := filepath.Join(dir, fmt.Sprintf("%s.log", whereami)) if _, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644); err == nil { log.Hooks.Add(lfshook.NewHook(lfshook.PathMap{ logrus.DebugLevel: path, @@ -82,13 +91,12 @@ func NewCustomLogger(server config.ServerInfo) *logrus.Entry { logrus.PanicLevel: path, }, nil)) } else { - log.Errorf("Failed to create log file. path: %s, err: %s", path, err) + log.Errorf("Failed to create log file. path: %s, err: %+v", path, err) } } entry := log.WithFields(logrus.Fields{"prefix": whereami}) - entry.Infof("vuls-%s-%s", config.Version, config.Revision) - return entry + return Logger{Entry: *entry} } // GetDefaultLogDir returns default log directory diff --git a/models/library.go b/models/library.go index fdda9f58..b7c61d09 100644 --- a/models/library.go +++ b/models/library.go @@ -6,9 +6,9 @@ import ( "github.com/aquasecurity/trivy-db/pkg/db" trivyDBTypes "github.com/aquasecurity/trivy-db/pkg/types" "github.com/aquasecurity/trivy/pkg/detector/library" + "github.com/future-architect/vuls/logging" "github.com/aquasecurity/trivy/pkg/types" - "github.com/future-architect/vuls/util" "golang.org/x/xerrors" // "github.com/aquasecurity/go-dep-parser/pkg/types" ) @@ -71,7 +71,7 @@ func (s LibraryScanner) convertFanalToVuln(tvulns []types.DetectedVulnerability) for _, tvuln := range tvulns { vinfo, err := s.getVulnDetail(tvuln) if err != nil { - util.Log.Debugf("failed to getVulnDetail. err: %s, tvuln: %#v", err, tvuln) + logging.Log.Debugf("failed to getVulnDetail. err: %+v, tvuln: %#v", err, tvuln) continue } vulns = append(vulns, vinfo) diff --git a/models/scanresults.go b/models/scanresults.go index c83beb41..f22c1bb6 100644 --- a/models/scanresults.go +++ b/models/scanresults.go @@ -11,7 +11,7 @@ import ( "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/constant" "github.com/future-architect/vuls/cwe" - "github.com/future-architect/vuls/util" + "github.com/future-architect/vuls/logging" ) // ScanResults is a slide of ScanResult @@ -134,7 +134,7 @@ func (r ScanResult) FilterIgnorePkgs(ignorePkgsRegexps []string) ScanResult { for _, pkgRegexp := range ignorePkgsRegexps { re, err := regexp.Compile(pkgRegexp) if err != nil { - util.Log.Errorf("Failed to parse %s. err: %+v", pkgRegexp, err) + logging.Log.Warnf("Failed to parse %s. err: %+v", pkgRegexp, err) continue } else { regexps = append(regexps, re) diff --git a/oval/alpine.go b/oval/alpine.go index e2e3001c..d5053c3e 100644 --- a/oval/alpine.go +++ b/oval/alpine.go @@ -5,8 +5,8 @@ package oval import ( "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/constant" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" - "github.com/future-architect/vuls/util" "github.com/kotakanbe/goval-dictionary/db" ) @@ -47,7 +47,7 @@ func (o Alpine) update(r *models.ScanResult, defPacks defPacks) { cveID := defPacks.def.Advisory.Cves[0].CveID vinfo, ok := r.ScannedCves[cveID] if !ok { - util.Log.Debugf("%s is newly detected by OVAL", cveID) + logging.Log.Debugf("%s is newly detected by OVAL", cveID) vinfo = models.VulnInfo{ CveID: cveID, Confidences: []models.Confidence{models.OvalMatch}, diff --git a/oval/debian.go b/oval/debian.go index fe7b4557..abc9851f 100644 --- a/oval/debian.go +++ b/oval/debian.go @@ -8,6 +8,7 @@ import ( "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/constant" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/future-architect/vuls/util" "github.com/kotakanbe/goval-dictionary/db" @@ -24,7 +25,7 @@ func (o DebianBase) update(r *models.ScanResult, defPacks defPacks) { ovalContent.Type = models.NewCveContentType(o.family) vinfo, ok := r.ScannedCves[defPacks.def.Debian.CveID] if !ok { - util.Log.Debugf("%s is newly detected by OVAL", defPacks.def.Debian.CveID) + logging.Log.Debugf("%s is newly detected by OVAL", defPacks.def.Debian.CveID) vinfo = models.VulnInfo{ CveID: defPacks.def.Debian.CveID, Confidences: []models.Confidence{models.OvalMatch}, @@ -34,10 +35,10 @@ func (o DebianBase) update(r *models.ScanResult, defPacks defPacks) { cveContents := vinfo.CveContents ctype := models.NewCveContentType(o.family) if _, ok := vinfo.CveContents[ctype]; ok { - util.Log.Debugf("%s OVAL will be overwritten", + logging.Log.Debugf("%s OVAL will be overwritten", defPacks.def.Debian.CveID) } else { - util.Log.Debugf("%s is also detected by OVAL", + logging.Log.Debugf("%s is also detected by OVAL", defPacks.def.Debian.CveID) cveContents = models.CveContents{} } @@ -362,7 +363,7 @@ func (o Ubuntu) fillWithOval(driver db.DB, r *models.ScanResult, kernelNamesInOv if v, ok := r.Packages[linuxImage]; ok { runningKernelVersion = v.Version } else { - util.Log.Warnf("Unable to detect vulns of running kernel because the version of the running kernel is unknown. server: %s", + logging.Log.Warnf("Unable to detect vulns of running kernel because the version of the running kernel is unknown. server: %s", r.ServerName) } @@ -401,7 +402,7 @@ func (o Ubuntu) fillWithOval(driver db.DB, r *models.ScanResult, kernelNamesInOv } if kernelPkgInOVAL == "" { - util.Log.Warnf("The OVAL name of the running kernel image %+v is not found. So vulns of `linux` wll be detected. server: %s", + logging.Log.Warnf("The OVAL name of the running kernel image %+v is not found. So vulns of `linux` wll be detected. server: %s", r.RunningKernel, r.ServerName) kernelPkgInOVAL = "linux" isOVALKernelPkgAdded = true diff --git a/oval/debian_test.go b/oval/debian_test.go index 51fa5a67..431f90d7 100644 --- a/oval/debian_test.go +++ b/oval/debian_test.go @@ -6,9 +6,7 @@ import ( "reflect" "testing" - "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/models" - "github.com/future-architect/vuls/util" ovalmodels "github.com/kotakanbe/goval-dictionary/models" ) @@ -56,7 +54,7 @@ func TestPackNamesOfUpdateDebian(t *testing.T) { }, } - util.Log = util.NewCustomLogger(config.ServerInfo{}) + // util.Log = util.NewCustomLogger() for i, tt := range tests { Debian{}.update(&tt.in, tt.defPacks) e := tt.out.ScannedCves["CVE-2000-1000"].AffectedPackages diff --git a/oval/oval.go b/oval/oval.go index 44a4127b..f3ed4fb7 100644 --- a/oval/oval.go +++ b/oval/oval.go @@ -7,6 +7,7 @@ import ( "time" cnf "github.com/future-architect/vuls/config" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/future-architect/vuls/util" "github.com/kotakanbe/goval-dictionary/db" @@ -41,7 +42,7 @@ func (b Base) CheckIfOvalFetched(driver db.DB, osFamily, release string) (fetche url, _ := util.URLPathJoin(cnf.Conf.OvalDict.URL, "count", osFamily, release) resp, body, errs := gorequest.New().Timeout(10 * time.Second).Get(url).End() if 0 < len(errs) || resp == nil || resp.StatusCode != 200 { - return false, xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %s", url, resp, errs) + return false, xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %+v", url, resp, errs) } count := 0 if err := json.Unmarshal([]byte(body), &count); err != nil { @@ -59,7 +60,7 @@ func (b Base) CheckIfOvalFresh(driver db.DB, osFamily, release string) (ok bool, url, _ := util.URLPathJoin(cnf.Conf.OvalDict.URL, "lastmodified", osFamily, release) resp, body, errs := gorequest.New().Timeout(10 * time.Second).Get(url).End() if 0 < len(errs) || resp == nil || resp.StatusCode != 200 { - return false, xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %s", url, resp, errs) + return false, xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %+v", url, resp, errs) } if err := json.Unmarshal([]byte(body), &lastModified); err != nil { @@ -70,10 +71,10 @@ func (b Base) CheckIfOvalFresh(driver db.DB, osFamily, release string) (ok bool, since := time.Now() since = since.AddDate(0, 0, -3) if lastModified.Before(since) { - util.Log.Warnf("OVAL for %s %s is old, last modified is %s. It's recommended to update OVAL to improve scanning accuracy. How to update OVAL database, see https://github.com/kotakanbe/goval-dictionary#usage", + logging.Log.Warnf("OVAL for %s %s is old, last modified is %s. It's recommended to update OVAL to improve scanning accuracy. How to update OVAL database, see https://github.com/kotakanbe/goval-dictionary#usage", osFamily, release, lastModified) return false, nil } - util.Log.Infof("OVAL is fresh: %s %s ", osFamily, release) + logging.Log.Infof("OVAL is fresh: %s %s ", osFamily, release) return true, nil } diff --git a/oval/redhat.go b/oval/redhat.go index a034099b..688d2f8c 100644 --- a/oval/redhat.go +++ b/oval/redhat.go @@ -9,8 +9,8 @@ import ( "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/constant" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" - "github.com/future-architect/vuls/util" "github.com/kotakanbe/goval-dictionary/db" ovalmodels "github.com/kotakanbe/goval-dictionary/models" ) @@ -92,7 +92,7 @@ func (o RedHatBase) update(r *models.ScanResult, defPacks defPacks) (nCVEs int) ovalContent := *o.convertToModel(cve.CveID, &defPacks.def) vinfo, ok := r.ScannedCves[cve.CveID] if !ok { - util.Log.Debugf("%s is newly detected by OVAL", cve.CveID) + logging.Log.Debugf("%s is newly detected by OVAL", cve.CveID) vinfo = models.VulnInfo{ CveID: cve.CveID, Confidences: models.Confidences{models.OvalMatch}, @@ -103,13 +103,13 @@ func (o RedHatBase) update(r *models.ScanResult, defPacks defPacks) (nCVEs int) cveContents := vinfo.CveContents if v, ok := vinfo.CveContents[ctype]; ok { if v.LastModified.After(ovalContent.LastModified) { - util.Log.Debugf("%s, OvalID: %d ignored: ", + logging.Log.Debugf("%s, OvalID: %d ignored: ", cve.CveID, defPacks.def.ID) } else { - util.Log.Debugf("%s OVAL will be overwritten", cve.CveID) + logging.Log.Debugf("%s OVAL will be overwritten", cve.CveID) } } else { - util.Log.Debugf("%s also detected by OVAL", cve.CveID) + logging.Log.Debugf("%s also detected by OVAL", cve.CveID) cveContents = models.CveContents{} } diff --git a/oval/redhat_test.go b/oval/redhat_test.go index fdf8fe9f..8172f6e3 100644 --- a/oval/redhat_test.go +++ b/oval/redhat_test.go @@ -6,9 +6,7 @@ import ( "reflect" "testing" - "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/models" - "github.com/future-architect/vuls/util" ovalmodels "github.com/kotakanbe/goval-dictionary/models" ) @@ -132,7 +130,7 @@ func TestPackNamesOfUpdate(t *testing.T) { }, } - util.Log = util.NewCustomLogger(config.ServerInfo{}) + // util.Log = util.Logger{}.NewCustomLogger() for i, tt := range tests { RedHat{}.update(&tt.in, tt.defPacks) e := tt.out.ScannedCves["CVE-2000-1000"].AffectedPackages diff --git a/oval/suse.go b/oval/suse.go index a5a138d6..d2c8c428 100644 --- a/oval/suse.go +++ b/oval/suse.go @@ -5,8 +5,8 @@ package oval import ( "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/constant" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" - "github.com/future-architect/vuls/util" "github.com/kotakanbe/goval-dictionary/db" ovalmodels "github.com/kotakanbe/goval-dictionary/models" ) @@ -56,7 +56,7 @@ func (o SUSE) update(r *models.ScanResult, defPacks defPacks) { ovalContent.Type = models.NewCveContentType(o.family) vinfo, ok := r.ScannedCves[defPacks.def.Title] if !ok { - util.Log.Debugf("%s is newly detected by OVAL", defPacks.def.Title) + logging.Log.Debugf("%s is newly detected by OVAL", defPacks.def.Title) vinfo = models.VulnInfo{ CveID: defPacks.def.Title, Confidences: models.Confidences{models.OvalMatch}, @@ -66,9 +66,9 @@ func (o SUSE) update(r *models.ScanResult, defPacks defPacks) { cveContents := vinfo.CveContents ctype := models.NewCveContentType(o.family) if _, ok := vinfo.CveContents[ctype]; ok { - util.Log.Debugf("%s OVAL will be overwritten", defPacks.def.Title) + logging.Log.Debugf("%s OVAL will be overwritten", defPacks.def.Title) } else { - util.Log.Debugf("%s is also detected by OVAL", defPacks.def.Title) + logging.Log.Debugf("%s is also detected by OVAL", defPacks.def.Title) cveContents = models.CveContents{} } vinfo.Confidences.AppendIfMissing(models.OvalMatch) diff --git a/oval/util.go b/oval/util.go index 35fcf5aa..1c152cd0 100644 --- a/oval/util.go +++ b/oval/util.go @@ -11,6 +11,7 @@ import ( "github.com/cenkalti/backoff" "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/constant" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/future-architect/vuls/util" apkver "github.com/knqyf263/go-apk-version" @@ -135,7 +136,7 @@ func getDefsByPackNameViaHTTP(r *models.ScanResult) ( if err != nil { errChan <- err } else { - util.Log.Debugf("HTTP Request to %s", url) + logging.Log.Debugf("HTTP Request to %s", url) httpGet(url, req, resChan, errChan) } } @@ -196,12 +197,12 @@ func httpGet(url string, req request, resChan chan<- response, errChan chan<- er if count == retryMax { return nil } - return xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %s", url, resp, errs) + return xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %+v", url, resp, errs) } return nil } notify := func(err error, t time.Duration) { - util.Log.Warnf("Failed to HTTP GET. retrying in %s seconds. err: %s", t, err) + logging.Log.Warnf("Failed to HTTP GET. retrying in %s seconds. err: %+v", t, err) } err := backoff.RetryNotify(f, backoff.NewExponentialBackOff(), notify) if err != nil { @@ -318,7 +319,7 @@ func isOvalDefAffected(def ovalmodels.Definition, req request, family string, ru // Compare between the installed version vs the version in OVAL less, err := lessThan(family, req.versionRelease, ovalPack) if err != nil { - util.Log.Debugf("Failed to parse versions: %s, Ver: %#v, OVAL: %#v, DefID: %s", + logging.Log.Debugf("Failed to parse versions: %s, Ver: %#v, OVAL: %#v, DefID: %s", err, req.versionRelease, ovalPack, def.DefinitionID) return false, false, ovalPack.Version } @@ -354,7 +355,7 @@ func isOvalDefAffected(def ovalmodels.Definition, req request, family string, ru // compare version: newVer vs oval less, err := lessThan(family, req.newVersionRelease, ovalPack) if err != nil { - util.Log.Debugf("Failed to parse versions: %s, NewVer: %#v, OVAL: %#v, DefID: %s", + logging.Log.Debugf("Failed to parse versions: %s, NewVer: %#v, OVAL: %#v, DefID: %s", err, req.newVersionRelease, ovalPack, def.DefinitionID) return false, false, ovalPack.Version } @@ -404,9 +405,8 @@ func lessThan(family, newVer string, packInOVAL ovalmodels.Package) (bool, error return vera.LessThan(verb), nil default: - util.Log.Errorf("Not implemented yet: %s", family) + return false, xerrors.Errorf("Not implemented yet: %s", family) } - return false, xerrors.Errorf("Package version comparison not supported: %s", family) } var centosVerPattern = regexp.MustCompile(`\.[es]l(\d+)(?:_\d+)?(?:\.centos)?`) diff --git a/reporter/slack.go b/reporter/slack.go index 230d11ca..0c6a7541 100644 --- a/reporter/slack.go +++ b/reporter/slack.go @@ -9,10 +9,10 @@ import ( "github.com/cenkalti/backoff" "github.com/future-architect/vuls/config" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/nlopes/slack" "github.com/parnurzeal/gorequest" - log "github.com/sirupsen/logrus" "golang.org/x/xerrors" ) @@ -148,14 +148,14 @@ func (w SlackWriter) send(msg message) error { return nil } return xerrors.Errorf( - "HTTP POST error. url: %s, resp: %v, body: %s, err: %s", + "HTTP POST error. url: %s, resp: %v, body: %s, err: %+v", conf.HookURL, resp, body, errs) } return nil } notify := func(err error, t time.Duration) { - log.Warnf("Error %s", err) - log.Warn("Retrying in ", t) + logging.Log.Warnf("Error %s", err) + logging.Log.Warn("Retrying in ", t) } boff := backoff.NewExponentialBackOff() if err := backoff.RetryNotify(f, boff, notify); err != nil { diff --git a/reporter/util.go b/reporter/util.go index 2c34e69b..e4d96da2 100644 --- a/reporter/util.go +++ b/reporter/util.go @@ -14,8 +14,8 @@ import ( "time" "github.com/future-architect/vuls/config" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" - "github.com/future-architect/vuls/util" "github.com/gosuri/uitable" "github.com/olekukonko/tablewriter" "golang.org/x/xerrors" @@ -620,27 +620,27 @@ func getPlusDiffCves(previous, current models.ScanResult) models.VulnInfos { if isCveInfoUpdated(v.CveID, previous, current) { v.DiffStatus = models.DiffPlus updated[v.CveID] = v - util.Log.Debugf("updated: %s", v.CveID) + logging.Log.Debugf("updated: %s", v.CveID) // TODO commented out because a bug of diff logic when multiple oval defs found for a certain CVE-ID and same updated_at // if these OVAL defs have different affected packages, this logic detects as updated. // This logic will be uncomented after integration with gost https://github.com/knqyf263/gost // } else if isCveFixed(v, previous) { // updated[v.CveID] = v - // util.Log.Debugf("fixed: %s", v.CveID) + // logging.Log.Debugf("fixed: %s", v.CveID) } else { - util.Log.Debugf("same: %s", v.CveID) + logging.Log.Debugf("same: %s", v.CveID) } } else { - util.Log.Debugf("new: %s", v.CveID) + logging.Log.Debugf("new: %s", v.CveID) v.DiffStatus = models.DiffPlus new[v.CveID] = v } } if len(updated) == 0 && len(new) == 0 { - util.Log.Infof("%s: There are %d vulnerabilities, but no difference between current result and previous one.", current.FormatServerName(), len(current.ScannedCves)) + logging.Log.Infof("%s: There are %d vulnerabilities, but no difference between current result and previous one.", current.FormatServerName(), len(current.ScannedCves)) } for cveID, vuln := range new { @@ -660,11 +660,11 @@ func getMinusDiffCves(previous, current models.ScanResult) models.VulnInfos { if !currentCveIDsSet[v.CveID] { v.DiffStatus = models.DiffMinus clear[v.CveID] = v - util.Log.Debugf("clear: %s", v.CveID) + logging.Log.Debugf("clear: %s", v.CveID) } } if len(clear) == 0 { - util.Log.Infof("%s: There are %d vulnerabilities, but no difference between current result and previous one.", current.FormatServerName(), len(current.ScannedCves)) + logging.Log.Infof("%s: There are %d vulnerabilities, but no difference between current result and previous one.", current.FormatServerName(), len(current.ScannedCves)) } return clear @@ -701,7 +701,7 @@ func isCveInfoUpdated(cveID string, previous, current models.ScanResult) bool { for _, t := range cTypes { if !curLastModified[t].Equal(prevLastModified[t]) { - util.Log.Debugf("%s LastModified not equal: \n%s\n%s", + logging.Log.Debugf("%s LastModified not equal: \n%s\n%s", cveID, curLastModified[t], prevLastModified[t]) return true } diff --git a/reporter/util_test.go b/reporter/util_test.go index 600d54e3..aba3b74c 100644 --- a/reporter/util_test.go +++ b/reporter/util_test.go @@ -6,14 +6,12 @@ import ( "testing" "time" - "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/models" - "github.com/future-architect/vuls/util" "github.com/k0kubun/pp" ) func TestMain(m *testing.M) { - util.Log = util.NewCustomLogger(config.ServerInfo{}) + // util.Log = util.Logger{}.NewCustomLogger() pp.ColoringEnabled = false code := m.Run() os.Exit(code) diff --git a/saas/saas.go b/saas/saas.go index c553caeb..67b21b32 100644 --- a/saas/saas.go +++ b/saas/saas.go @@ -19,6 +19,7 @@ import ( "github.com/aws/aws-sdk-go/service/sts" "github.com/future-architect/vuls/config" c "github.com/future-architect/vuls/config" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/future-architect/vuls/util" "golang.org/x/xerrors" @@ -50,7 +51,7 @@ func (w Writer) Write(rs ...models.ScanResult) error { ipv4s, ipv6s, err := util.IP() if err != nil { - util.Log.Errorf("Failed to fetch scannedIPs. err: %+v", err) + logging.Log.Warnf("Failed to get scannedIPs. err: %+v", err) } hostname, _ := os.Hostname() @@ -114,7 +115,7 @@ func (w Writer) Write(rs ...models.ScanResult) error { if err != nil { return xerrors.Errorf("Failed to Marshal to JSON: %w", err) } - util.Log.Infof("Uploading... %s", r.FormatServerName()) + logging.Log.Infof("Uploading... %s", r.FormatServerName()) s3Key := renameKeyName(r.ServerUUID, r.Container) putObjectInput := &s3.PutObjectInput{ Bucket: aws.String(tempCredential.S3Bucket), @@ -126,7 +127,7 @@ func (w Writer) Write(rs ...models.ScanResult) error { tempCredential.S3Bucket, s3Key, err) } } - util.Log.Infof("done") + logging.Log.Infof("done") return nil } diff --git a/saas/uuid.go b/saas/uuid.go index 1daee6f9..29150caa 100644 --- a/saas/uuid.go +++ b/saas/uuid.go @@ -10,8 +10,8 @@ import ( "github.com/BurntSushi/toml" c "github.com/future-architect/vuls/config" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" - "github.com/future-architect/vuls/util" "github.com/hashicorp/go-uuid" "golang.org/x/xerrors" ) @@ -48,7 +48,7 @@ func ensure(servers map[string]c.ServerInfo, path string, scanResults models.Sca needsOverwrite = true } else if _, err := uuid.ParseUUID(id); err != nil { // if the UUID of the host is invalid, re-generate it - util.Log.Warnf("UUID `%s` is invalid. Re-generate and overwrite", id) + logging.Log.Warnf("UUID `%s` is invalid. Re-generate and overwrite", id) serverInfo.UUIDs[r.ServerName], err = generateFunc() if err != nil { return false, err @@ -74,7 +74,7 @@ func ensure(servers map[string]c.ServerInfo, path string, scanResults models.Sca continue } // re-generate - util.Log.Warnf("UUID `%s` is invalid. Re-generate and overwrite", id) + logging.Log.Warnf("UUID `%s` is invalid. Re-generate and overwrite", id) } // Generate a new UUID and set to config and scanResult diff --git a/scanner/alpine.go b/scanner/alpine.go index 0ad06bb1..9c8a0301 100644 --- a/scanner/alpine.go +++ b/scanner/alpine.go @@ -6,6 +6,7 @@ import ( "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/constant" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/future-architect/vuls/util" "golang.org/x/xerrors" @@ -26,7 +27,7 @@ func newAlpine(c config.ServerInfo) *alpine { }, }, } - d.log = util.NewCustomLogger(c) + d.log = logging.NewNormalLogger() d.setServerInfo(c) return d } diff --git a/scanner/amazon.go b/scanner/amazon.go index 3f0d1b70..a7349f4d 100644 --- a/scanner/amazon.go +++ b/scanner/amazon.go @@ -2,8 +2,8 @@ package scanner import ( "github.com/future-architect/vuls/config" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" - "github.com/future-architect/vuls/util" "golang.org/x/xerrors" ) @@ -25,7 +25,7 @@ func newAmazon(c config.ServerInfo) *amazon { sudo: rootPrivAmazon{}, }, } - r.log = util.NewCustomLogger(c) + r.log = logging.NewNormalLogger() r.setServerInfo(c) return r } diff --git a/scanner/base.go b/scanner/base.go index bad1a488..631c6aae 100644 --- a/scanner/base.go +++ b/scanner/base.go @@ -15,9 +15,9 @@ import ( "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/constant" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/future-architect/vuls/util" - "github.com/sirupsen/logrus" "golang.org/x/xerrors" // Import library scanner @@ -38,7 +38,7 @@ type base struct { LibraryScanners []models.LibraryScanner WordPress models.WordPressPackages - log *logrus.Entry + log logging.Logger errs []error warns []error } @@ -484,6 +484,10 @@ func (l *base) getErrs() []error { return l.errs } +func (l *base) setLogger(logger logging.Logger) { + l.log = logger +} + const ( systemd = "systemd" upstart = "upstart" @@ -950,19 +954,19 @@ func (l *base) pkgPs(getOwnerPkgs func([]string) ([]string, error)) error { stdout := "" stdout, err = l.lsProcExe(pid) if err != nil { - l.log.Debugf("Failed to exec ls -l /proc/%s/exe err: %s", pid, err) + l.log.Debugf("Failed to exec ls -l /proc/%s/exe err: %+v", pid, err) continue } s, err := l.parseLsProcExe(stdout) if err != nil { - l.log.Debugf("Failed to parse /proc/%s/exe: %s", pid, err) + l.log.Debugf("Failed to parse /proc/%s/exe: %+v", pid, err) continue } pidLoadedFiles[pid] = append(pidLoadedFiles[pid], s) stdout, err = l.grepProcMap(pid) if err != nil { - l.log.Debugf("Failed to exec /proc/%s/maps: %s", pid, err) + l.log.Debugf("Failed to exec /proc/%s/maps: %+v", pid, err) continue } ss := l.parseGrepProcMap(stdout) diff --git a/scanner/base_test.go b/scanner/base_test.go index e8790a5c..72a81037 100644 --- a/scanner/base_test.go +++ b/scanner/base_test.go @@ -39,7 +39,7 @@ f570ae647edc agitated_lovelace centos:latest`, r := newRHEL(config.ServerInfo{}) actual, err := r.parseDockerPs(test.in) if err != nil { - t.Errorf("Error occurred. in: %s, err: %s", test.in, err) + t.Errorf("Error occurred. in: %s, err: %+v", test.in, err) return } for i, e := range test.expected { @@ -76,7 +76,7 @@ func TestParseLxdPs(t *testing.T) { r := newRHEL(config.ServerInfo{}) actual, err := r.parseLxdPs(test.in) if err != nil { - t.Errorf("Error occurred. in: %s, err: %s", test.in, err) + t.Errorf("Error occurred. in: %s, err: %+v", test.in, err) return } for i, e := range test.expected { diff --git a/scanner/centos.go b/scanner/centos.go index 159545ec..e65955e1 100644 --- a/scanner/centos.go +++ b/scanner/centos.go @@ -2,8 +2,8 @@ package scanner import ( "github.com/future-architect/vuls/config" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" - "github.com/future-architect/vuls/util" ) // inherit OsTypeInterface @@ -24,7 +24,7 @@ func newCentOS(c config.ServerInfo) *centos { sudo: rootPrivCentos{}, }, } - r.log = util.NewCustomLogger(c) + r.log = logging.NewNormalLogger() r.setServerInfo(c) return r } diff --git a/scanner/debian.go b/scanner/debian.go index ed14d4c7..ea6d9fc2 100644 --- a/scanner/debian.go +++ b/scanner/debian.go @@ -13,6 +13,7 @@ import ( "github.com/future-architect/vuls/cache" "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/constant" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/future-architect/vuls/util" version "github.com/knqyf263/go-deb-version" @@ -34,7 +35,7 @@ func newDebian(c config.ServerInfo) *debian { }, }, } - d.log = util.NewCustomLogger(c) + d.log = logging.NewNormalLogger() d.setServerInfo(c) return d } @@ -49,7 +50,7 @@ func detectDebian(c config.ServerInfo) (bool, osTypeInterface, error) { if r.ExitStatus == 255 { return false, nil, xerrors.Errorf("Unable to connect via SSH. Scan with -vvv option to print SSH debugging messages and check SSH settings. If you have never SSH to the host to be scanned, SSH to the host before scanning in order to add the HostKey. %s@%s port: %s\n%s", c.User, c.Host, c.Port, r) } - util.Log.Debugf("Not Debian like Linux. %s", r) + logging.Log.Debugf("Not Debian like Linux. %s", r) return false, nil, nil } @@ -78,7 +79,7 @@ func detectDebian(c config.ServerInfo) (bool, osTypeInterface, error) { deb := newDebian(c) if len(result) == 0 { deb.setDistro("debian/ubuntu", "unknown") - util.Log.Warnf("Unknown Debian/Ubuntu version. lsb_release -ir: %s", r) + logging.Log.Warnf("Unknown Debian/Ubuntu version. lsb_release -ir: %s", r) } else { distro := strings.ToLower(trim(result[1])) deb.setDistro(distro, trim(result[2])) @@ -96,7 +97,7 @@ func detectDebian(c config.ServerInfo) (bool, osTypeInterface, error) { result := re.FindStringSubmatch(trim(r.Stdout)) deb := newDebian(c) if len(result) == 0 { - util.Log.Warnf( + logging.Log.Warnf( "Unknown Debian/Ubuntu. cat /etc/lsb-release: %s", r) deb.setDistro("debian/ubuntu", "unknown") } else { @@ -114,7 +115,7 @@ func detectDebian(c config.ServerInfo) (bool, osTypeInterface, error) { return true, deb, nil } - util.Log.Debugf("Not Debian like Linux: %s", c.ServerName) + logging.Log.Debugf("Not Debian like Linux: %s", c.ServerName) return false, nil, nil } @@ -380,7 +381,7 @@ func (o *debian) scanInstalledPackages() (models.Packages, models.Packages, mode // Fill the candidate versions of upgradable packages err = o.fillCandidateVersion(updatable) if err != nil { - return nil, nil, nil, xerrors.Errorf("Failed to fill candidate versions. err: %s", err) + return nil, nil, nil, xerrors.Errorf("Failed to fill candidate versions. err: %w", err) } installed.MergeNewVersion(updatable) @@ -513,14 +514,14 @@ func (o *debian) scanUnsecurePackages(updatable models.Packages) (models.VulnInf // Collect CVE information of upgradable packages vulnInfos, err := o.scanChangelogs(updatable, meta, tmpClogPath) if err != nil { - return nil, xerrors.Errorf("Failed to scan unsecure packages. err: %s", err) + return nil, xerrors.Errorf("Failed to scan unsecure packages. err: %w", err) } // Delete a directory for saving changelog to get changelog in Raspbian if o.Distro.Family == constant.Raspbian { err := o.deleteTempChangelogDir(tmpClogPath) if err != nil { - return nil, xerrors.Errorf("Failed to delete directory to save changelog for Raspbian. err: %s", err) + return nil, xerrors.Errorf("Failed to delete directory to save changelog for Raspbian. err: %w", err) } } @@ -532,14 +533,14 @@ func (o *debian) ensureChangelogCache(current cache.Meta) (*cache.Meta, error) { cached, found, err := cache.DB.GetMeta(current.Name) if err != nil { return nil, xerrors.Errorf( - "Failed to get meta. Please remove cache.db and then try again. err: %s", err) + "Failed to get meta. Please remove cache.db and then try again. err: %w", err) } if !found { o.log.Debugf("Not found in meta: %s", current.Name) err = cache.DB.EnsureBuckets(current) if err != nil { - return nil, xerrors.Errorf("Failed to ensure buckets. err: %s", err) + return nil, xerrors.Errorf("Failed to ensure buckets. err: %w", err) } return ¤t, nil } @@ -549,7 +550,7 @@ func (o *debian) ensureChangelogCache(current cache.Meta) (*cache.Meta, error) { o.log.Debugf("Need to refresh meta: %s", current.Name) err = cache.DB.EnsureBuckets(current) if err != nil { - return nil, xerrors.Errorf("Failed to ensure buckets. err: %s", err) + return nil, xerrors.Errorf("Failed to ensure buckets. err: %w", err) } return ¤t, nil @@ -626,7 +627,6 @@ func (o *debian) parseAptGetUpgrade(stdout string) (updatableNames []string, err result[1], len(updatableNames)) } stopLineFound = true - o.log.Debugf("Found the stop line. line: %s", line) break } updatableNames = append(updatableNames, strings.Fields(line)...) @@ -660,7 +660,7 @@ func (o *debian) makeTempChangelogDir() (string, error) { func generateSuffix() (string, error) { var n uint64 if err := binary.Read(rand.Reader, binary.LittleEndian, &n); err != nil { - return "", xerrors.Errorf("Failed to generate Suffix. err: %s", err) + return "", xerrors.Errorf("Failed to generate Suffix. err: %w", err) } return strconv.FormatUint(n, 36), nil } @@ -803,7 +803,7 @@ func (o *debian) getChangelogCache(meta *cache.Meta, pack models.Package) string } changelog, err := cache.DB.GetChangelog(meta.Name, pack.Name) if err != nil { - o.log.Warnf("Failed to get changelog. bucket: %s, key:%s, err: %s", + o.log.Warnf("Failed to get changelog. bucket: %s, key:%s, err: %+v", meta.Name, pack.Name, err) return "" } @@ -829,7 +829,7 @@ func (o *debian) fetchParseChangelog(pack models.Package, tmpClogPath string) ([ changelogPath, err := o.getChangelogPath(pack.Name, tmpClogPath) if err != nil { // Ignore this Error. - o.log.Warnf("Failed to get Path to Changelog for Package: %s, err: %s", pack.Name, err) + o.log.Warnf("Failed to get Path to Changelog for Package: %s, err: %+v", pack.Name, err) return nil, nil, nil } cmd = fmt.Sprintf(`gzip -cd %s | cat`, changelogPath) diff --git a/scanner/debian_test.go b/scanner/debian_test.go index f02a4ba7..b4c34f96 100644 --- a/scanner/debian_test.go +++ b/scanner/debian_test.go @@ -9,9 +9,9 @@ import ( "github.com/future-architect/vuls/cache" "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/constant" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/k0kubun/pp" - "github.com/sirupsen/logrus" ) func TestGetCveIDsFromChangelog(t *testing.T) { @@ -421,7 +421,7 @@ func TestGetChangelogCache(t *testing.T) { } const path = "/tmp/vuls-test-cache-11111111.db" - log := logrus.NewEntry(&logrus.Logger{}) + log := logging.NewNormalLogger() if err := cache.SetupBolt(path, log); err != nil { t.Errorf("Failed to setup bolt: %s", err) } diff --git a/scanner/executil.go b/scanner/executil.go index 9cfac34b..b54b5ab9 100644 --- a/scanner/executil.go +++ b/scanner/executil.go @@ -12,9 +12,8 @@ import ( "golang.org/x/xerrors" conf "github.com/future-architect/vuls/config" - "github.com/future-architect/vuls/util" + "github.com/future-architect/vuls/logging" homedir "github.com/mitchellh/go-homedir" - "github.com/sirupsen/logrus" ) type execResult struct { @@ -72,7 +71,7 @@ func parallelExec(fn func(osTypeInterface) error, timeoutSec ...int) { go func(s osTypeInterface) { defer func() { if p := recover(); p != nil { - util.Log.Debugf("Panic: %s on %s", + logging.Log.Debugf("Panic: %s on %s", p, s.getServerInfo().GetServerName()) } }() @@ -100,7 +99,7 @@ func parallelExec(fn func(osTypeInterface) error, timeoutSec ...int) { if len(s.getErrs()) == 0 { successes = append(successes, s) } else { - util.Log.Errorf("Error on %s, err: %+v", + logging.Log.Errorf("Error on %s, err: %+v", s.getServerInfo().GetServerName(), s.getErrs()) errServers = append(errServers, s) } @@ -121,9 +120,8 @@ func parallelExec(fn func(osTypeInterface) error, timeoutSec ...int) { } } if !found { - err := xerrors.Errorf("Timed out: %s", - s.getServerInfo().GetServerName()) - util.Log.Errorf("%+v", err) + err := xerrors.Errorf("Timed out: %s", s.getServerInfo().GetServerName()) + logging.Log.Errorf("%+v", err) s.setErrs([]error{err}) errServers = append(errServers, s) } @@ -133,7 +131,7 @@ func parallelExec(fn func(osTypeInterface) error, timeoutSec ...int) { return } -func exec(c conf.ServerInfo, cmd string, sudo bool, log ...*logrus.Entry) (result execResult) { +func exec(c conf.ServerInfo, cmd string, sudo bool, log ...logging.Logger) (result execResult) { logger := getSSHLogger(log...) logger.Debugf("Executing... %s", strings.Replace(cmd, "\n", "", -1)) @@ -143,7 +141,7 @@ func exec(c conf.ServerInfo, cmd string, sudo bool, log ...*logrus.Entry) (resul result = sshExecExternal(c, cmd, sudo) } - logger.Debug(result) + logger.Debugf("%+v", result) return } @@ -261,9 +259,9 @@ func sshExecExternal(c conf.ServerInfo, cmd string, sudo bool) (result execResul return } -func getSSHLogger(log ...*logrus.Entry) *logrus.Entry { +func getSSHLogger(log ...logging.Logger) logging.Logger { if len(log) == 0 { - return util.Log + return logging.Log } return log[0] } diff --git a/scanner/freebsd.go b/scanner/freebsd.go index 86d1a281..9299272d 100644 --- a/scanner/freebsd.go +++ b/scanner/freebsd.go @@ -6,6 +6,7 @@ import ( "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/constant" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/future-architect/vuls/util" "golang.org/x/xerrors" @@ -26,7 +27,7 @@ func newBsd(c config.ServerInfo) *bsd { }, }, } - d.log = util.NewCustomLogger(c) + d.log = logging.NewNormalLogger() d.setServerInfo(c) return d } @@ -46,7 +47,7 @@ func detectFreebsd(c config.ServerInfo) (bool, osTypeInterface) { } } } - util.Log.Debugf("Not FreeBSD. servernam: %s", c.ServerName) + logging.Log.Debugf("Not FreeBSD. servernam: %s", c.ServerName) return false, nil } diff --git a/scanner/oracle.go b/scanner/oracle.go index f02a5ddd..60965a99 100644 --- a/scanner/oracle.go +++ b/scanner/oracle.go @@ -2,8 +2,8 @@ package scanner import ( "github.com/future-architect/vuls/config" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" - "github.com/future-architect/vuls/util" ) // inherit OsTypeInterface @@ -24,7 +24,7 @@ func newOracle(c config.ServerInfo) *oracle { sudo: rootPrivOracle{}, }, } - r.log = util.NewCustomLogger(c) + r.log = logging.NewNormalLogger() r.setServerInfo(c) return r } diff --git a/scanner/pseudo.go b/scanner/pseudo.go index 12600401..8d63b219 100644 --- a/scanner/pseudo.go +++ b/scanner/pseudo.go @@ -3,8 +3,8 @@ package scanner import ( "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/constant" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" - "github.com/future-architect/vuls/util" ) // inherit OsTypeInterface @@ -30,7 +30,7 @@ func newPseudo(c config.ServerInfo) *pseudo { }, }, } - d.log = util.NewCustomLogger(c) + d.log = logging.NewNormalLogger() d.setServerInfo(c) return d } diff --git a/scanner/redhatbase.go b/scanner/redhatbase.go index c97c446a..376afc8e 100644 --- a/scanner/redhatbase.go +++ b/scanner/redhatbase.go @@ -8,6 +8,7 @@ import ( "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/constant" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/future-architect/vuls/util" "golang.org/x/xerrors" @@ -18,7 +19,7 @@ import ( // https://github.com/serverspec/specinfra/blob/master/lib/specinfra/helper/detect_os/redhat.rb func detectRedhat(c config.ServerInfo) (bool, osTypeInterface) { if r := exec(c, "ls /etc/fedora-release", noSudo); r.isSuccess() { - util.Log.Warnf("Fedora not tested yet: %s", r) + logging.Log.Warnf("Fedora not tested yet: %s", r) return true, &unknown{} } @@ -29,7 +30,7 @@ func detectRedhat(c config.ServerInfo) (bool, osTypeInterface) { re := regexp.MustCompile(`(.*) release (\d[\d\.]*)`) result := re.FindStringSubmatch(strings.TrimSpace(r.Stdout)) if len(result) != 3 { - util.Log.Warnf("Failed to parse Oracle Linux version: %s", r) + logging.Log.Warnf("Failed to parse Oracle Linux version: %s", r) return true, newOracle(c) } @@ -47,7 +48,7 @@ func detectRedhat(c config.ServerInfo) (bool, osTypeInterface) { re := regexp.MustCompile(`(.*) release (\d[\d\.]*)`) result := re.FindStringSubmatch(strings.TrimSpace(r.Stdout)) if len(result) != 3 { - util.Log.Warnf("Failed to parse CentOS version: %s", r) + logging.Log.Warnf("Failed to parse CentOS version: %s", r) return true, newCentOS(c) } @@ -58,7 +59,7 @@ func detectRedhat(c config.ServerInfo) (bool, osTypeInterface) { cent.setDistro(constant.CentOS, release) return true, cent default: - util.Log.Warnf("Failed to parse CentOS: %s", r) + logging.Log.Warnf("Failed to parse CentOS: %s", r) } } } @@ -72,7 +73,7 @@ func detectRedhat(c config.ServerInfo) (bool, osTypeInterface) { re := regexp.MustCompile(`(.*) release (\d[\d\.]*)`) result := re.FindStringSubmatch(strings.TrimSpace(r.Stdout)) if len(result) != 3 { - util.Log.Warnf("Failed to parse RedHat/CentOS version: %s", r) + logging.Log.Warnf("Failed to parse RedHat/CentOS version: %s", r) return true, newCentOS(c) } @@ -113,7 +114,7 @@ func detectRedhat(c config.ServerInfo) (bool, osTypeInterface) { return true, amazon } - util.Log.Debugf("Not RedHat like Linux. servername: %s", c.ServerName) + logging.Log.Debugf("Not RedHat like Linux. servername: %s", c.ServerName) return false, &unknown{} } @@ -451,7 +452,7 @@ func (o *redhatBase) isExecNeedsRestarting() bool { case constant.RedHat, constant.CentOS, constant.Oracle: majorVersion, err := o.Distro.MajorVersion() if err != nil || majorVersion < 6 { - o.log.Errorf("Not implemented yet: %s, err: %s", o.Distro, err) + o.log.Errorf("Not implemented yet: %s, err: %+v", o.Distro, err) return false } diff --git a/scanner/redhatbase_test.go b/scanner/redhatbase_test.go index 0b5d0f18..4c744375 100644 --- a/scanner/redhatbase_test.go +++ b/scanner/redhatbase_test.go @@ -217,7 +217,7 @@ func TestParseYumCheckUpdateLine(t *testing.T) { for _, tt := range tests { aPack, err := r.parseUpdatablePacksLine(tt.in) if err != nil { - t.Errorf("Error has occurred, err: %s\ntt.in: %v", err, tt.in) + t.Errorf("Error has occurred, err: %+v\ntt.in: %v", err, tt.in) return } if !reflect.DeepEqual(tt.out, aPack) { @@ -296,7 +296,7 @@ pytalloc 0 2.0.7 2.el6 @CentOS 6.5/6.5` for _, tt := range tests { packages, err := r.parseUpdatablePacksLines(tt.in) if err != nil { - t.Errorf("Error has occurred, err: %s\ntt.in: %v", err, tt.in) + t.Errorf("Error has occurred, err: %+v\ntt.in: %v", err, tt.in) return } for name, ePack := range tt.out { @@ -352,7 +352,7 @@ if-not-architecture 0 100 200 amzn-main` for _, tt := range tests { packages, err := r.parseUpdatablePacksLines(tt.in) if err != nil { - t.Errorf("Error has occurred, err: %s\ntt.in: %v", err, tt.in) + t.Errorf("Error has occurred, err: %+v\ntt.in: %v", err, tt.in) return } for name, ePack := range tt.out { diff --git a/scanner/rhel.go b/scanner/rhel.go index 926e789c..22afdfd0 100644 --- a/scanner/rhel.go +++ b/scanner/rhel.go @@ -2,8 +2,8 @@ package scanner import ( "github.com/future-architect/vuls/config" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" - "github.com/future-architect/vuls/util" "golang.org/x/xerrors" ) @@ -25,7 +25,7 @@ func newRHEL(c config.ServerInfo) *rhel { sudo: rootPrivRHEL{}, }, } - r.log = util.NewCustomLogger(c) + r.log = logging.NewNormalLogger() r.setServerInfo(c) return r } diff --git a/scanner/serverapi.go b/scanner/serverapi.go index 0ef63d7a..621ad567 100644 --- a/scanner/serverapi.go +++ b/scanner/serverapi.go @@ -2,6 +2,7 @@ package scanner import ( "fmt" + "math/rand" "net/http" "os" "time" @@ -9,6 +10,7 @@ import ( "github.com/future-architect/vuls/cache" "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/constant" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/future-architect/vuls/util" "golang.org/x/xerrors" @@ -57,6 +59,7 @@ type osTypeInterface interface { exitedContainers() ([]config.Container, error) allContainers() ([]config.Container, error) + setLogger(logging.Logger) getErrs() []error setErrs([]error) } @@ -66,26 +69,29 @@ type Scanner struct { TimeoutSec int ScanTimeoutSec int CacheDBPath string + Debug bool + LogDir string + Quiet bool Targets map[string]config.ServerInfo } // Scan execute scan func (s Scanner) Scan() error { - util.Log.Info("Detecting Server/Container OS... ") + logging.Log.Info("Detecting Server/Container OS... ") if err := s.initServers(); err != nil { return xerrors.Errorf("Failed to init servers. err: %w", err) } - util.Log.Info("Checking Scan Modes... ") + logging.Log.Info("Checking Scan Modes... ") if err := s.checkScanModes(); err != nil { return xerrors.Errorf("Fix config.toml. err: %w", err) } - util.Log.Info("Detecting Platforms... ") + logging.Log.Info("Detecting Platforms... ") s.detectPlatform() - util.Log.Info("Detecting IPS identifiers... ") + logging.Log.Info("Detecting IPS identifiers... ") s.detectIPS() if err := s.execScan(); err != nil { @@ -96,29 +102,29 @@ func (s Scanner) Scan() error { // Configtest checks if the server is scannable. func (s Scanner) Configtest() error { - util.Log.Info("Detecting Server/Container OS... ") + logging.Log.Info("Detecting Server/Container OS... ") if err := s.initServers(); err != nil { return xerrors.Errorf("Failed to init servers. err: %w", err) } - util.Log.Info("Checking Scan Modes...") + logging.Log.Info("Checking Scan Modes...") if err := s.checkScanModes(); err != nil { return xerrors.Errorf("Fix config.toml. err: %w", err) } - util.Log.Info("Checking dependencies...") + logging.Log.Info("Checking dependencies...") s.checkDependencies() - util.Log.Info("Checking sudo settings...") + logging.Log.Info("Checking sudo settings...") s.checkIfSudoNoPasswd() - util.Log.Info("It can be scanned with fast scan mode even if warn or err messages are displayed due to lack of dependent packages or sudo settings in fast-root or deep scan mode") + logging.Log.Info("It can be scanned with fast scan mode even if warn or err messages are displayed due to lack of dependent packages or sudo settings in fast-root or deep scan mode") if len(servers) == 0 { return xerrors.Errorf("No scannable servers") } - util.Log.Info("Scannable servers are below...") + logging.Log.Info("Scannable servers are below...") for _, s := range servers { if s.getServerInfo().IsContainer() { fmt.Printf("%s@%s ", @@ -147,7 +153,7 @@ func ViaHTTP(header http.Header, body string, toLocalFile bool) (models.ScanResu kernelRelease := header.Get("X-Vuls-Kernel-Release") if kernelRelease == "" { - util.Log.Warn("If X-Vuls-Kernel-Release is not specified, there is a possibility of false detection") + logging.Log.Warn("If X-Vuls-Kernel-Release is not specified, there is a possibility of false detection") } kernelVersion := header.Get("X-Vuls-Kernel-Version") @@ -174,7 +180,7 @@ func ViaHTTP(header http.Header, body string, toLocalFile bool) (models.ScanResu osPackages: osPackages{ Kernel: kernel, }, - log: util.Log, + log: logging.Log, } var osType osTypeInterface @@ -228,7 +234,17 @@ func (s Scanner) initServers() error { if len(hosts) == 0 { return xerrors.New("No scannable host OS") } + + // to generate random color for logging + rand.Seed(time.Now().UnixNano()) + for _, srv := range hosts { + srv.setLogger(logging.NewCustomLogger(s.Debug, s.Quiet, s.LogDir, config.Colors[rand.Intn(len(config.Colors))], srv.getServerInfo().GetServerName())) + } + containers, errContainers := s.detectContainerOSes(hosts) + for _, srv := range containers { + srv.setLogger(logging.NewCustomLogger(s.Debug, s.Quiet, s.LogDir, config.Colors[rand.Intn(len(config.Colors))], srv.getServerInfo().GetServerName())) + } // set to pkg global variable for _, host := range hosts { @@ -246,14 +262,14 @@ func (s Scanner) initServers() error { } func (s Scanner) detectServerOSes() (servers, errServers []osTypeInterface) { - util.Log.Info("Detecting OS of servers... ") + logging.Log.Info("Detecting OS of servers... ") osTypeChan := make(chan osTypeInterface, len(s.Targets)) defer close(osTypeChan) for _, target := range s.Targets { go func(srv config.ServerInfo) { defer func() { if p := recover(); p != nil { - util.Log.Debugf("Panic: %s on %s", p, srv.ServerName) + logging.Log.Debugf("Panic: %s on %s", p, srv.ServerName) } }() osTypeChan <- s.detectOS(srv) @@ -266,16 +282,16 @@ func (s Scanner) detectServerOSes() (servers, errServers []osTypeInterface) { case res := <-osTypeChan: if 0 < len(res.getErrs()) { errServers = append(errServers, res) - util.Log.Errorf("(%d/%d) Failed: %s, err: %+v", + logging.Log.Errorf("(%d/%d) Failed: %s, err: %+v", i+1, len(s.Targets), res.getServerInfo().ServerName, res.getErrs()) } else { servers = append(servers, res) - util.Log.Infof("(%d/%d) Detected: %s: %s", + logging.Log.Infof("(%d/%d) Detected: %s: %s", i+1, len(s.Targets), res.getServerInfo().ServerName, res.getDistro()) } case <-timeout: msg := "Timed out while detecting servers" - util.Log.Error(msg) + logging.Log.Error(msg) for servername, sInfo := range s.Targets { found := false for _, o := range append(servers, errServers...) { @@ -289,7 +305,7 @@ func (s Scanner) detectServerOSes() (servers, errServers []osTypeInterface) { u.setServerInfo(sInfo) u.setErrs([]error{xerrors.New("Timed out")}) errServers = append(errServers, u) - util.Log.Errorf("(%d/%d) Timed out: %s", i+1, len(s.Targets), servername) + logging.Log.Errorf("(%d/%d) Timed out: %s", i+1, len(s.Targets), servername) } } } @@ -298,14 +314,14 @@ func (s Scanner) detectServerOSes() (servers, errServers []osTypeInterface) { } func (s Scanner) detectContainerOSes(hosts []osTypeInterface) (actives, inactives []osTypeInterface) { - util.Log.Info("Detecting OS of containers... ") + logging.Log.Info("Detecting OS of containers... ") osTypesChan := make(chan []osTypeInterface, len(hosts)) defer close(osTypesChan) for _, host := range hosts { go func(h osTypeInterface) { defer func() { if p := recover(); p != nil { - util.Log.Debugf("Panic: %s on %s", + logging.Log.Debugf("Panic: %s on %s", p, h.getServerInfo().GetServerName()) } }() @@ -321,15 +337,15 @@ func (s Scanner) detectContainerOSes(hosts []osTypeInterface) (actives, inactive sinfo := osi.getServerInfo() if 0 < len(osi.getErrs()) { inactives = append(inactives, osi) - util.Log.Errorf("Failed: %s err: %+v", sinfo.ServerName, osi.getErrs()) + logging.Log.Errorf("Failed: %s err: %+v", sinfo.ServerName, osi.getErrs()) continue } actives = append(actives, osi) - util.Log.Infof("Detected: %s@%s: %s", + logging.Log.Infof("Detected: %s@%s: %s", sinfo.Container.Name, sinfo.ServerName, osi.getDistro()) } case <-timeout: - util.Log.Error("Some containers timed out") + logging.Log.Error("Some containers timed out") } } return @@ -434,27 +450,27 @@ func (s Scanner) detectOS(c config.ServerInfo) (osType osTypeInterface) { } if itsMe { - util.Log.Debugf("Debian like Linux. Host: %s:%s", c.Host, c.Port) + logging.Log.Debugf("Debian like Linux. Host: %s:%s", c.Host, c.Port) return } if itsMe, osType = detectRedhat(c); itsMe { - util.Log.Debugf("Redhat like Linux. Host: %s:%s", c.Host, c.Port) + logging.Log.Debugf("Redhat like Linux. Host: %s:%s", c.Host, c.Port) return } if itsMe, osType = detectSUSE(c); itsMe { - util.Log.Debugf("SUSE Linux. Host: %s:%s", c.Host, c.Port) + logging.Log.Debugf("SUSE Linux. Host: %s:%s", c.Host, c.Port) return } if itsMe, osType = detectFreebsd(c); itsMe { - util.Log.Debugf("FreeBSD. Host: %s:%s", c.Host, c.Port) + logging.Log.Debugf("FreeBSD. Host: %s:%s", c.Host, c.Port) return } if itsMe, osType = detectAlpine(c); itsMe { - util.Log.Debugf("Alpine. Host: %s:%s", c.Host, c.Port) + logging.Log.Debugf("Alpine. Host: %s:%s", c.Host, c.Port) return } @@ -524,7 +540,7 @@ func (s Scanner) detectPlatform() { for i, s := range servers { if s.getServerInfo().IsContainer() { - util.Log.Infof("(%d/%d) %s on %s is running on %s", + logging.Log.Infof("(%d/%d) %s on %s is running on %s", i+1, len(servers), s.getServerInfo().Container.Name, s.getServerInfo().ServerName, @@ -532,7 +548,7 @@ func (s Scanner) detectPlatform() { ) } else { - util.Log.Infof("(%d/%d) %s is running on %s", + logging.Log.Infof("(%d/%d) %s is running on %s", i+1, len(servers), s.getServerInfo().ServerName, s.getPlatform().Name, @@ -552,7 +568,7 @@ func (s Scanner) detectIPS() { for i, s := range servers { if !s.getServerInfo().IsContainer() { - util.Log.Infof("(%d/%d) %s has %d IPS integration", + logging.Log.Infof("(%d/%d) %s has %d IPS integration", i+1, len(servers), s.getServerInfo().ServerName, len(s.getServerInfo().IPSIdentifiers), @@ -612,7 +628,7 @@ func (s Scanner) setupChangelogCache() error { } } if needToSetupCache { - if err := cache.SetupBolt(s.CacheDBPath, util.Log); err != nil { + if err := cache.SetupBolt(s.CacheDBPath, logging.Log); err != nil { return err } } @@ -654,7 +670,7 @@ func (s Scanner) getScanResults(scannedAt time.Time) (results models.ScanResults hostname, _ := os.Hostname() ipv4s, ipv6s, err := util.IP() if err != nil { - util.Log.Errorf("Failed to fetch scannedIPs. err: %+v", err) + logging.Log.Warnf("Failed to get scannedIPs. err: %+v", err) } for _, s := range append(servers, errServers...) { @@ -670,7 +686,7 @@ func (s Scanner) getScanResults(scannedAt time.Time) (results models.ScanResults results = append(results, r) if 0 < len(r.Warnings) { - util.Log.Warnf("Some warnings occurred during scanning on %s. Please fix the warnings to get a useful information. Execute configtest subcommand before scanning to know the cause of the warnings. warnings: %v", + logging.Log.Warnf("Some warnings occurred during scanning on %s. Please fix the warnings to get a useful information. Execute configtest subcommand before scanning to know the cause of the warnings. warnings: %v", r.ServerName, r.Warnings) } } diff --git a/scanner/suse.go b/scanner/suse.go index 816f526d..71676d21 100644 --- a/scanner/suse.go +++ b/scanner/suse.go @@ -8,6 +8,7 @@ import ( "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/constant" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/future-architect/vuls/util" "golang.org/x/xerrors" @@ -30,7 +31,7 @@ func newSUSE(c config.ServerInfo) *suse { }, }, } - r.log = util.NewCustomLogger(c) + r.log = logging.NewNormalLogger() r.setServerInfo(c) return r } @@ -71,12 +72,12 @@ func detectSUSE(c config.ServerInfo) (bool, osTypeInterface) { return true, s } } - util.Log.Warnf("Failed to parse SUSE Linux version: %s", r) + logging.Log.Warnf("Failed to parse SUSE Linux version: %s", r) return true, newSUSE(c) } } } - util.Log.Debugf("Not SUSE Linux. servername: %s", c.ServerName) + logging.Log.Debugf("Not SUSE Linux. servername: %s", c.ServerName) return false, nil } @@ -89,14 +90,14 @@ func (o *suse) parseOSRelease(content string) (name string, ver string) { } else if strings.Contains(content, `NAME="SLES_SAP"`) { name = constant.SUSEEnterpriseServer } else { - util.Log.Warnf("Failed to parse SUSE edition: %s", content) + logging.Log.Warnf("Failed to parse SUSE edition: %s", content) return "unknown", "unknown" } re := regexp.MustCompile(`VERSION_ID=\"(.+)\"`) result := re.FindStringSubmatch(strings.TrimSpace(content)) if len(result) != 2 { - util.Log.Warnf("Failed to parse SUSE Linux version: %s", content) + logging.Log.Warnf("Failed to parse SUSE Linux version: %s", content) return "unknown", "unknown" } return name, result[1] diff --git a/scanner/suse_test.go b/scanner/suse_test.go index cbdb5dbe..ca5ecd69 100644 --- a/scanner/suse_test.go +++ b/scanner/suse_test.go @@ -51,7 +51,7 @@ v | Clone of SLES11-SP3-Updates for x86_64 | ConsoleKit | 0.2.10-64.65.1 | 0.2.1 for _, tt := range tests { packages, err := r.parseZypperLULines(tt.in) if err != nil { - t.Errorf("Error has occurred, err: %s\ntt.in: %v", err, tt.in) + t.Errorf("Error has occurred, err: %+v\ntt.in: %v", err, tt.in) return } for name, ePack := range tt.out { @@ -87,7 +87,7 @@ func TestScanUpdatablePackage(t *testing.T) { for _, tt := range tests { pack, err := r.parseZypperLUOneLine(tt.in) if err != nil { - t.Errorf("Error has occurred, err: %s\ntt.in: %v", err, tt.in) + t.Errorf("Error has occurred, err: %+v\ntt.in: %v", err, tt.in) return } if !reflect.DeepEqual(*pack, tt.out) { diff --git a/scanner/utils.go b/scanner/utils.go index 91512f15..6cf4c255 100644 --- a/scanner/utils.go +++ b/scanner/utils.go @@ -9,9 +9,9 @@ import ( "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/constant" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/future-architect/vuls/reporter" - "github.com/future-architect/vuls/util" "golang.org/x/xerrors" ) @@ -36,7 +36,7 @@ func isRunningKernel(pack models.Package, family string, kernel models.Kernel) ( return false, false default: - util.Log.Warnf("Reboot required is not implemented yet: %s, %v", family, kernel) + logging.Log.Warnf("Reboot required is not implemented yet: %s, %v", family, kernel) } return false, false } diff --git a/server/server.go b/server/server.go index 34115fb5..2112b73d 100644 --- a/server/server.go +++ b/server/server.go @@ -12,10 +12,10 @@ import ( "time" "github.com/future-architect/vuls/detector" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/future-architect/vuls/reporter" "github.com/future-architect/vuls/scanner" - "github.com/future-architect/vuls/util" ) // VulsHandler is used for vuls server mode @@ -32,14 +32,14 @@ func (h VulsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { contentType := req.Header.Get("Content-Type") mediatype, _, err := mime.ParseMediaType(contentType) if err != nil { - util.Log.Error(err) + logging.Log.Error(err) http.Error(w, err.Error(), http.StatusBadRequest) return } if mediatype == "application/json" { if err = json.NewDecoder(req.Body).Decode(&result); err != nil { - util.Log.Error(err) + logging.Log.Error(err) http.Error(w, "Invalid JSON", http.StatusBadRequest) return } @@ -50,24 +50,24 @@ func (h VulsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } if result, err = scanner.ViaHTTP(req.Header, buf.String(), h.ToLocalFile); err != nil { - util.Log.Error(err) + logging.Log.Error(err) http.Error(w, err.Error(), http.StatusBadRequest) return } } else { - util.Log.Error(mediatype) + logging.Log.Error(mediatype) http.Error(w, fmt.Sprintf("Invalid Content-Type: %s", contentType), http.StatusUnsupportedMediaType) return } if err := detector.DetectPkgCves(h.DBclient, &result); err != nil { - util.Log.Errorf("Failed to detect Pkg CVE: %+v", err) + logging.Log.Errorf("Failed to detect Pkg CVE: %+v", err) http.Error(w, err.Error(), http.StatusServiceUnavailable) return } if err := detector.FillCveInfo(h.DBclient, &result); err != nil { - util.Log.Errorf("Failed to fill CVE detailed info: %+v", err) + logging.Log.Errorf("Failed to fill CVE detailed info: %+v", err) http.Error(w, err.Error(), http.StatusServiceUnavailable) return } @@ -90,7 +90,7 @@ func (h VulsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { } dir, err := scanner.EnsureResultDir(scannedAt) if err != nil { - util.Log.Errorf("Failed to ensure the result directory: %+v", err) + logging.Log.Errorf("Failed to ensure the result directory: %+v", err) http.Error(w, err.Error(), http.StatusServiceUnavailable) return } @@ -104,7 +104,7 @@ func (h VulsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { for _, w := range reports { if err := w.Write(result); err != nil { - util.Log.Errorf("Failed to report. err: %+v", err) + logging.Log.Errorf("Failed to report. err: %+v", err) return } } diff --git a/subcmds/configtest.go b/subcmds/configtest.go index 1064a3f1..c451337e 100644 --- a/subcmds/configtest.go +++ b/subcmds/configtest.go @@ -11,8 +11,8 @@ import ( "github.com/google/subcommands" c "github.com/future-architect/vuls/config" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/scanner" - "github.com/future-architect/vuls/util" ) // ConfigtestCmd is Subcommand @@ -51,7 +51,7 @@ func (p *ConfigtestCmd) SetFlags(f *flag.FlagSet) { defaultConfPath := filepath.Join(wd, "config.toml") f.StringVar(&p.configPath, "config", defaultConfPath, "/path/to/toml") - defaultLogDir := util.GetDefaultLogDir() + defaultLogDir := logging.GetDefaultLogDir() f.StringVar(&c.Conf.LogDir, "log-dir", defaultLogDir, "/path/to/log") f.BoolVar(&c.Conf.Debug, "debug", false, "debug mode") @@ -69,10 +69,11 @@ func (p *ConfigtestCmd) SetFlags(f *flag.FlagSet) { // Execute execute func (p *ConfigtestCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { - util.Log = util.NewCustomLogger(c.ServerInfo{}) + logging.Log = logging.NewCustomLogger(c.Conf.Debug, c.Conf.Quiet, c.Conf.LogDir, "", "") + logging.Log.Infof("vuls-%s-%s", c.Version, c.Revision) if err := mkdirDotVuls(); err != nil { - util.Log.Errorf("Failed to create .vuls. err: %+v", err) + logging.Log.Errorf("Failed to create $HOME/.vuls: %+v", err) return subcommands.ExitUsageError } @@ -81,7 +82,7 @@ func (p *ConfigtestCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interfa if p.askKeyPassword { prompt := "SSH key password: " if keyPass, err = getPasswd(prompt); err != nil { - util.Log.Error(err) + logging.Log.Error(err) return subcommands.ExitFailure } } @@ -93,7 +94,7 @@ func (p *ConfigtestCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interfa "If you update Vuls and get this error, there may be incompatible changes in config.toml", "Please check config.toml template : https://vuls.io/docs/en/usage-settings.html", } - util.Log.Errorf("%s\n%+v", strings.Join(msg, "\n"), err) + logging.Log.Errorf("%s\n%+v", strings.Join(msg, "\n"), err) return subcommands.ExitUsageError } @@ -113,7 +114,7 @@ func (p *ConfigtestCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interfa } } if !found { - util.Log.Errorf("%s is not in config", arg) + logging.Log.Errorf("%s is not in config", arg) return subcommands.ExitUsageError } } @@ -121,7 +122,7 @@ func (p *ConfigtestCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interfa c.Conf.Servers = targets } - util.Log.Info("Validating config...") + logging.Log.Info("Validating config...") if !c.Conf.ValidateOnConfigtest() { return subcommands.ExitUsageError } @@ -132,7 +133,7 @@ func (p *ConfigtestCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interfa } if err := s.Configtest(); err != nil { - util.Log.Errorf("Failed to configtest: %+v", err) + logging.Log.Errorf("Failed to configtest: %+v", err) return subcommands.ExitFailure } diff --git a/subcmds/discover.go b/subcmds/discover.go index dac8d5ea..eead4f5f 100644 --- a/subcmds/discover.go +++ b/subcmds/discover.go @@ -8,10 +8,11 @@ import ( "strings" "text/template" + "github.com/future-architect/vuls/config" + "github.com/future-architect/vuls/logging" "github.com/google/subcommands" ps "github.com/kotakanbe/go-pingscanner" - "github.com/sirupsen/logrus" ) // DiscoverCmd is Subcommand of host discovery mode @@ -38,9 +39,11 @@ func (p *DiscoverCmd) SetFlags(f *flag.FlagSet) { // Execute execute func (p *DiscoverCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { + logging.Log = logging.NewCustomLogger(config.Conf.Debug, config.Conf.Quiet, config.Conf.LogDir, "", "") + logging.Log.Infof("vuls-%s-%s", config.Version, config.Revision) // validate if len(f.Args()) == 0 { - logrus.Errorf("Usage: " + p.Usage()) + logging.Log.Errorf("Usage: " + p.Usage()) return subcommands.ExitUsageError } @@ -55,15 +58,15 @@ func (p *DiscoverCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface hosts, err := scanner.Scan() if err != nil { - logrus.Errorf("Host Discovery failed. err: %s", err) + logging.Log.Errorf("Host Discovery failed. err: %+v", err) return subcommands.ExitFailure } if len(hosts) < 1 { - logrus.Errorf("Active hosts not found in %s", cidr) + logging.Log.Errorf("Active hosts not found in %s", cidr) return subcommands.ExitSuccess } else if err := printConfigToml(hosts); err != nil { - logrus.Errorf("Failed to parse template. err: %s", err) + logging.Log.Errorf("Failed to parse template. err: %+v", err) return subcommands.ExitFailure } } diff --git a/subcmds/report.go b/subcmds/report.go index 0fec1571..644fbfbc 100644 --- a/subcmds/report.go +++ b/subcmds/report.go @@ -9,12 +9,11 @@ import ( "path/filepath" "github.com/aquasecurity/trivy/pkg/utils" - "github.com/future-architect/vuls/config" c "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/detector" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/future-architect/vuls/reporter" - "github.com/future-architect/vuls/util" "github.com/google/subcommands" "github.com/k0kubun/pp" ) @@ -108,7 +107,7 @@ func (p *ReportCmd) SetFlags(f *flag.FlagSet) { defaultResultsDir := filepath.Join(wd, "results") f.StringVar(&c.Conf.ResultsDir, "results-dir", defaultResultsDir, "/path/to/results") - defaultLogDir := util.GetDefaultLogDir() + defaultLogDir := logging.GetDefaultLogDir() f.StringVar(&c.Conf.LogDir, "log-dir", defaultLogDir, "/path/to/log") f.BoolVar(&c.Conf.RefreshCve, "refresh-cve", false, @@ -171,10 +170,11 @@ func (p *ReportCmd) SetFlags(f *flag.FlagSet) { // Execute execute func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { - util.Log = util.NewCustomLogger(c.ServerInfo{}) + logging.Log = logging.NewCustomLogger(c.Conf.Debug, c.Conf.Quiet, c.Conf.LogDir, "", "") + logging.Log.Infof("vuls-%s-%s", c.Version, c.Revision) if err := c.Load(p.configPath, ""); err != nil { - util.Log.Errorf("Error loading %s, %+v", p.configPath, err) + logging.Log.Errorf("Error loading %s, %+v", p.configPath, err) return subcommands.ExitUsageError } c.Conf.Slack.Enabled = p.toSlack @@ -201,11 +201,11 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{} dir, err = reporter.JSONDir(f.Args()) } if err != nil { - util.Log.Errorf("Failed to read from JSON: %+v", err) + logging.Log.Errorf("Failed to read from JSON: %+v", err) return subcommands.ExitFailure } - util.Log.Info("Validating config...") + logging.Log.Info("Validating config...") if !c.Conf.ValidateOnReport() { return subcommands.ExitUsageError } @@ -217,10 +217,10 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{} var loaded models.ScanResults if loaded, err = reporter.LoadScanResults(dir); err != nil { - util.Log.Error(err) + logging.Log.Error(err) return subcommands.ExitFailure } - util.Log.Infof("Loaded: %s", dir) + logging.Log.Infof("Loaded: %s", dir) var res models.ScanResults hasError := false @@ -228,7 +228,7 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{} if len(r.Errors) == 0 { res = append(res, r) } else { - util.Log.Errorf("Ignored since errors occurred during scanning: %s, err: %v", + logging.Log.Errorf("Ignored since errors occurred during scanning: %s, err: %v", r.ServerName, r.Errors) hasError = true } @@ -239,11 +239,11 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{} } for _, r := range res { - util.Log.Debugf("%s: %s", + logging.Log.Debugf("%s: %s", r.ServerInfo(), pp.Sprintf("%s", c.Conf.Servers[r.ServerName])) } - for _, cnf := range []config.VulnDictInterface{ + for _, cnf := range []c.VulnDictInterface{ &c.Conf.CveDict, &c.Conf.OvalDict, &c.Conf.Gost, @@ -251,12 +251,12 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{} &c.Conf.Metasploit, } { if err := cnf.Validate(); err != nil { - util.Log.Errorf("Failed to validate VulnDict: %+v", err) + logging.Log.Errorf("Failed to validate VulnDict: %+v", err) return subcommands.ExitFailure } if err := cnf.CheckHTTPHealth(); err != nil { - util.Log.Errorf("Run as server mode before reporting: %+v", err) + logging.Log.Errorf("Run as server mode before reporting: %+v", err) return subcommands.ExitFailure } } @@ -271,18 +271,22 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{} DebugSQL: c.Conf.DebugSQL, }) if locked { - util.Log.Errorf("SQLite3 is locked. Close other DB connections and try again. err: %+v", err) + logging.Log.Errorf("SQLite3 is locked. Close other DB connections and try again. err: %+v", err) return subcommands.ExitFailure } if err != nil { - util.Log.Errorf("Failed to init DB Clients. err: %+v", err) + logging.Log.Errorf("Failed to init DB Clients. err: %+v", err) return subcommands.ExitFailure } - defer dbclient.CloseDB() + defer func() { + for _, err := range dbclient.CloseDB() { + logging.Log.Errorf("Failed to CloseDB. err: %+v", err) + } + }() // TODO pass conf by arg if res, err = detector.Detect(*dbclient, res, dir); err != nil { - util.Log.Errorf("%+v", err) + logging.Log.Errorf("%+v", err) return subcommands.ExitFailure } @@ -342,7 +346,7 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{} if p.toS3 { if err := reporter.CheckIfBucketExists(); err != nil { - util.Log.Errorf("Check if there is a bucket beforehand: %s, err: %+v", + logging.Log.Errorf("Check if there is a bucket beforehand: %s, err: %+v", c.Conf.AWS.S3Bucket, err) return subcommands.ExitUsageError } @@ -366,11 +370,11 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{} } if c.Conf.Azure.ContainerName == "" { - util.Log.Error("Azure storage container name is required with -azure-container option") + logging.Log.Error("Azure storage container name is required with -azure-container option") return subcommands.ExitUsageError } if err := reporter.CheckIfAzureContainerExists(); err != nil { - util.Log.Errorf("Check if there is a container beforehand: %s, err: %+v", + logging.Log.Errorf("Check if there is a container beforehand: %s, err: %+v", c.Conf.Azure.ContainerName, err) return subcommands.ExitUsageError } @@ -385,7 +389,7 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{} for _, w := range reports { if err := w.Write(res...); err != nil { - util.Log.Errorf("Failed to report. err: %+v", err) + logging.Log.Errorf("Failed to report. err: %+v", err) return subcommands.ExitFailure } } diff --git a/subcmds/saas.go b/subcmds/saas.go index 2139b0c4..fa9dd68e 100644 --- a/subcmds/saas.go +++ b/subcmds/saas.go @@ -7,10 +7,10 @@ import ( "path/filepath" c "github.com/future-architect/vuls/config" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/future-architect/vuls/reporter" "github.com/future-architect/vuls/saas" - "github.com/future-architect/vuls/util" "github.com/google/subcommands" "github.com/k0kubun/pp" ) @@ -51,7 +51,7 @@ func (p *SaaSCmd) SetFlags(f *flag.FlagSet) { defaultResultsDir := filepath.Join(wd, "results") f.StringVar(&c.Conf.ResultsDir, "results-dir", defaultResultsDir, "/path/to/results") - defaultLogDir := util.GetDefaultLogDir() + defaultLogDir := logging.GetDefaultLogDir() f.StringVar(&c.Conf.LogDir, "log-dir", defaultLogDir, "/path/to/log") f.StringVar( @@ -61,29 +61,30 @@ func (p *SaaSCmd) SetFlags(f *flag.FlagSet) { // Execute execute func (p *SaaSCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { - util.Log = util.NewCustomLogger(c.ServerInfo{}) + logging.Log = logging.NewCustomLogger(c.Conf.Debug, c.Conf.Quiet, c.Conf.LogDir, "", "") + logging.Log.Infof("vuls-%s-%s", c.Version, c.Revision) if err := c.Load(p.configPath, ""); err != nil { - util.Log.Errorf("Error loading %s, %+v", p.configPath, err) + logging.Log.Errorf("Error loading %s, %+v", p.configPath, err) return subcommands.ExitUsageError } dir, err := reporter.JSONDir(f.Args()) if err != nil { - util.Log.Errorf("Failed to read from JSON: %+v", err) + logging.Log.Errorf("Failed to read from JSON: %+v", err) return subcommands.ExitFailure } - util.Log.Info("Validating config...") + logging.Log.Info("Validating config...") if !c.Conf.ValidateOnSaaS() { return subcommands.ExitUsageError } var loaded models.ScanResults if loaded, err = reporter.LoadScanResults(dir); err != nil { - util.Log.Error(err) + logging.Log.Error(err) return subcommands.ExitFailure } - util.Log.Infof("Loaded: %s", dir) + logging.Log.Infof("Loaded: %s", dir) var res models.ScanResults hasError := false @@ -91,7 +92,7 @@ func (p *SaaSCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) if len(r.Errors) == 0 { res = append(res, r) } else { - util.Log.Errorf("Ignored since errors occurred during scanning: %s, err: %v", + logging.Log.Errorf("Ignored since errors occurred during scanning: %s, err: %v", r.ServerName, r.Errors) hasError = true } @@ -102,19 +103,19 @@ func (p *SaaSCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) } for _, r := range res { - util.Log.Debugf("%s: %s", + logging.Log.Debugf("%s: %s", r.ServerInfo(), pp.Sprintf("%s", c.Conf.Servers[r.ServerName])) } // Ensure UUIDs of scan target servers in config.toml if err := saas.EnsureUUIDs(c.Conf.Servers, p.configPath, res); err != nil { - util.Log.Errorf("Failed to ensure UUIDs. err: %+v", err) + logging.Log.Errorf("Failed to ensure UUIDs. err: %+v", err) return subcommands.ExitFailure } var w reporter.ResultWriter = saas.Writer{} if err := w.Write(res...); err != nil { - util.Log.Errorf("Failed to upload. err: %+v", err) + logging.Log.Errorf("Failed to upload. err: %+v", err) return subcommands.ExitFailure } diff --git a/subcmds/scan.go b/subcmds/scan.go index e5b48a4d..ff6345dc 100644 --- a/subcmds/scan.go +++ b/subcmds/scan.go @@ -11,8 +11,8 @@ import ( "github.com/asaskevich/govalidator" c "github.com/future-architect/vuls/config" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/scanner" - "github.com/future-architect/vuls/util" "github.com/google/subcommands" "github.com/k0kubun/pp" ) @@ -67,7 +67,7 @@ func (p *ScanCmd) SetFlags(f *flag.FlagSet) { defaultResultsDir := filepath.Join(wd, "results") f.StringVar(&c.Conf.ResultsDir, "results-dir", defaultResultsDir, "/path/to/results") - defaultLogDir := util.GetDefaultLogDir() + defaultLogDir := logging.GetDefaultLogDir() f.StringVar(&c.Conf.LogDir, "log-dir", defaultLogDir, "/path/to/log") defaultCacheDBPath := filepath.Join(wd, "cache.db") @@ -97,17 +97,17 @@ func (p *ScanCmd) SetFlags(f *flag.FlagSet) { // Execute execute func (p *ScanCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { - // Setup Logger - util.Log = util.NewCustomLogger(c.ServerInfo{}) + logging.Log = logging.NewCustomLogger(c.Conf.Debug, c.Conf.Quiet, c.Conf.LogDir, "", "") + logging.Log.Infof("vuls-%s-%s", c.Version, c.Revision) if err := mkdirDotVuls(); err != nil { - util.Log.Errorf("Failed to create $HOME/.vuls err: %+v", err) + logging.Log.Errorf("Failed to create $HOME/.vuls err: %+v", err) return subcommands.ExitUsageError } if len(p.cacheDBPath) != 0 { if ok, _ := govalidator.IsFilePath(p.cacheDBPath); !ok { - util.Log.Errorf("Cache DB path must be a *Absolute* file path. -cache-dbpath: %s", + logging.Log.Errorf("Cache DB path must be a *Absolute* file path. -cache-dbpath: %s", p.cacheDBPath) return subcommands.ExitUsageError } @@ -118,7 +118,7 @@ func (p *ScanCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) if p.askKeyPassword { prompt := "SSH key password: " if keyPass, err = getPasswd(prompt); err != nil { - util.Log.Error(err) + logging.Log.Error(err) return subcommands.ExitFailure } } @@ -130,12 +130,12 @@ func (p *ScanCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) "If you update Vuls and get this error, there may be incompatible changes in config.toml", "Please check config.toml template : https://vuls.io/docs/en/usage-settings.html", } - util.Log.Errorf("%s\n%+v", strings.Join(msg, "\n"), err) + logging.Log.Errorf("%s\n%+v", strings.Join(msg, "\n"), err) return subcommands.ExitUsageError } - util.Log.Info("Start scanning") - util.Log.Infof("config: %s", p.configPath) + logging.Log.Info("Start scanning") + logging.Log.Infof("config: %s", p.configPath) var servernames []string if 0 < len(f.Args()) { @@ -143,7 +143,7 @@ func (p *ScanCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) } else if c.Conf.Pipe { bytes, err := ioutil.ReadAll(os.Stdin) if err != nil { - util.Log.Errorf("Failed to read stdin. err: %+v", err) + logging.Log.Errorf("Failed to read stdin. err: %+v", err) return subcommands.ExitFailure } fields := strings.Fields(string(bytes)) @@ -163,7 +163,7 @@ func (p *ScanCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) } } if !found { - util.Log.Errorf("%s is not in config", arg) + logging.Log.Errorf("%s is not in config", arg) return subcommands.ExitUsageError } } @@ -171,9 +171,9 @@ func (p *ScanCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) if 0 < len(servernames) { c.Conf.Servers = target } - util.Log.Debugf("%s", pp.Sprintf("%v", target)) + logging.Log.Debugf("%s", pp.Sprintf("%v", target)) - util.Log.Info("Validating config...") + logging.Log.Info("Validating config...") if !c.Conf.ValidateOnScan() { return subcommands.ExitUsageError } @@ -183,10 +183,13 @@ func (p *ScanCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) ScanTimeoutSec: p.scanTimeoutSec, CacheDBPath: p.cacheDBPath, Targets: target, + Debug: c.Conf.Debug, + Quiet: c.Conf.Quiet, + LogDir: c.Conf.LogDir, } if err := s.Scan(); err != nil { - util.Log.Errorf("Failed to scan: %+v", err) + logging.Log.Errorf("Failed to scan: %+v", err) return subcommands.ExitFailure } diff --git a/subcmds/server.go b/subcmds/server.go index 3cae21ce..de609509 100644 --- a/subcmds/server.go +++ b/subcmds/server.go @@ -12,11 +12,10 @@ import ( // "github.com/future-architect/vuls/Server" - "github.com/future-architect/vuls/config" c "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/detector" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/server" - "github.com/future-architect/vuls/util" "github.com/google/subcommands" ) @@ -66,7 +65,7 @@ func (p *ServerCmd) SetFlags(f *flag.FlagSet) { defaultResultsDir := filepath.Join(wd, "results") f.StringVar(&c.Conf.ResultsDir, "results-dir", defaultResultsDir, "/path/to/results") - defaultLogDir := util.GetDefaultLogDir() + defaultLogDir := logging.GetDefaultLogDir() f.StringVar(&c.Conf.LogDir, "log-dir", defaultLogDir, "/path/to/log") f.Float64Var(&c.Conf.CvssScoreOver, "cvss-over", 0, @@ -88,18 +87,19 @@ func (p *ServerCmd) SetFlags(f *flag.FlagSet) { // Execute execute func (p *ServerCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { - util.Log = util.NewCustomLogger(c.ServerInfo{}) + logging.Log = logging.NewCustomLogger(c.Conf.Debug, c.Conf.Quiet, c.Conf.LogDir, "", "") + logging.Log.Infof("vuls-%s-%s", c.Version, c.Revision) if err := c.Load(p.configPath, ""); err != nil { - util.Log.Errorf("Error loading %s. err: %+v", p.configPath, err) + logging.Log.Errorf("Error loading %s. err: %+v", p.configPath, err) return subcommands.ExitUsageError } - util.Log.Info("Validating config...") + logging.Log.Info("Validating config...") if !c.Conf.ValidateOnReport() { return subcommands.ExitUsageError } - for _, cnf := range []config.VulnDictInterface{ + for _, cnf := range []c.VulnDictInterface{ &c.Conf.CveDict, &c.Conf.OvalDict, &c.Conf.Gost, @@ -107,12 +107,12 @@ func (p *ServerCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{} &c.Conf.Metasploit, } { if err := cnf.Validate(); err != nil { - util.Log.Errorf("Failed to validate VulnDict: %+v", err) + logging.Log.Errorf("Failed to validate VulnDict: %+v", err) return subcommands.ExitFailure } if err := cnf.CheckHTTPHealth(); err != nil { - util.Log.Errorf("Run as server mode before reporting: %+v", err) + logging.Log.Errorf("Run as server mode before reporting: %+v", err) return subcommands.ExitFailure } } @@ -126,16 +126,18 @@ func (p *ServerCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{} DebugSQL: c.Conf.DebugSQL, }) if locked { - util.Log.Errorf("SQLite3 is locked. Close other DB connections and try again: %+v", err) + logging.Log.Errorf("SQLite3 is locked. Close other DB connections and try again: %+v", err) return subcommands.ExitFailure } - if err != nil { - util.Log.Errorf("Failed to init DB Clients. err: %+v", err) + logging.Log.Errorf("Failed to init DB Clients. err: %+v", err) return subcommands.ExitFailure } - - defer dbclient.CloseDB() + defer func() { + for _, err := range dbclient.CloseDB() { + logging.Log.Errorf("Failed to CloseDB. err: %+v", err) + } + }() http.Handle("/vuls", server.VulsHandler{ DBclient: *dbclient, @@ -144,9 +146,9 @@ func (p *ServerCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{} http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "ok") }) - util.Log.Infof("Listening on %s", p.listen) + logging.Log.Infof("Listening on %s", p.listen) if err := http.ListenAndServe(p.listen, nil); err != nil { - util.Log.Errorf("Failed to start server. err: %+v", err) + logging.Log.Errorf("Failed to start server. err: %+v", err) return subcommands.ExitFailure } return subcommands.ExitSuccess diff --git a/subcmds/tui.go b/subcmds/tui.go index 40df1376..6e0d8d53 100644 --- a/subcmds/tui.go +++ b/subcmds/tui.go @@ -9,13 +9,12 @@ import ( "path/filepath" "github.com/aquasecurity/trivy/pkg/utils" - "github.com/future-architect/vuls/config" c "github.com/future-architect/vuls/config" "github.com/future-architect/vuls/detector" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/future-architect/vuls/reporter" "github.com/future-architect/vuls/tui" - "github.com/future-architect/vuls/util" "github.com/google/subcommands" ) @@ -62,7 +61,7 @@ func (p *TuiCmd) SetFlags(f *flag.FlagSet) { f.BoolVar(&c.Conf.Quiet, "quiet", false, "Quiet mode. No output on stdout") f.BoolVar(&c.Conf.NoProgress, "no-progress", false, "Suppress progress bar") - defaultLogDir := util.GetDefaultLogDir() + defaultLogDir := logging.GetDefaultLogDir() f.StringVar(&c.Conf.LogDir, "log-dir", defaultLogDir, "/path/to/log") wd, _ := os.Getwd() @@ -102,9 +101,10 @@ func (p *TuiCmd) SetFlags(f *flag.FlagSet) { // Execute execute func (p *TuiCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { - util.Log = util.NewCustomLogger(c.ServerInfo{}) + logging.Log = logging.NewCustomLogger(c.Conf.Debug, c.Conf.Quiet, c.Conf.LogDir, "", "") + logging.Log.Infof("vuls-%s-%s", c.Version, c.Revision) if err := c.Load(p.configPath, ""); err != nil { - util.Log.Errorf("Error loading %s, err: %+v", p.configPath, err) + logging.Log.Errorf("Error loading %s, err: %+v", p.configPath, err) return subcommands.ExitUsageError } @@ -122,23 +122,23 @@ func (p *TuiCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) s dir, err = reporter.JSONDir(f.Args()) } if err != nil { - util.Log.Errorf("Failed to read from JSON. err: %+v", err) + logging.Log.Errorf("Failed to read from JSON. err: %+v", err) return subcommands.ExitFailure } - util.Log.Info("Validating config...") + logging.Log.Info("Validating config...") if !c.Conf.ValidateOnTui() { return subcommands.ExitUsageError } var res models.ScanResults if res, err = reporter.LoadScanResults(dir); err != nil { - util.Log.Error(err) + logging.Log.Error(err) return subcommands.ExitFailure } - util.Log.Infof("Loaded: %s", dir) + logging.Log.Infof("Loaded: %s", dir) - for _, cnf := range []config.VulnDictInterface{ + for _, cnf := range []c.VulnDictInterface{ &c.Conf.CveDict, &c.Conf.OvalDict, &c.Conf.Gost, @@ -146,12 +146,12 @@ func (p *TuiCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) s &c.Conf.Metasploit, } { if err := cnf.Validate(); err != nil { - util.Log.Errorf("Failed to validate VulnDict: %+v", err) + logging.Log.Errorf("Failed to validate VulnDict: %+v", err) return subcommands.ExitFailure } if err := cnf.CheckHTTPHealth(); err != nil { - util.Log.Errorf("Run as server mode before reporting: %+v", err) + logging.Log.Errorf("Run as server mode before reporting: %+v", err) return subcommands.ExitFailure } } @@ -165,25 +165,27 @@ func (p *TuiCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) s DebugSQL: c.Conf.DebugSQL, }) if locked { - util.Log.Errorf("SQLite3 is locked. Close other DB connections and try again: %+v", err) + logging.Log.Errorf("SQLite3 is locked. Close other DB connections and try again: %+v", err) return subcommands.ExitFailure } - if err != nil { - util.Log.Errorf("Failed to init DB Clients. err: %+v", err) + logging.Log.Errorf("Failed to init DB Clients. err: %+v", err) return subcommands.ExitFailure } - - defer dbclient.CloseDB() + defer func() { + for _, err := range dbclient.CloseDB() { + logging.Log.Errorf("Failed to CloseDB. err: %+v", err) + } + }() if res, err = detector.Detect(*dbclient, res, dir); err != nil { - util.Log.Error(err) + logging.Log.Error(err) return subcommands.ExitFailure } for _, r := range res { if len(r.Warnings) != 0 { - util.Log.Warnf("Warning: Some warnings occurred while scanning on %s: %s", + logging.Log.Warnf("Warning: Some warnings occurred while scanning on %s: %s", r.FormatServerName(), r.Warnings) } } diff --git a/tui/tui.go b/tui/tui.go index 1d87331f..684157e5 100644 --- a/tui/tui.go +++ b/tui/tui.go @@ -12,6 +12,7 @@ import ( "golang.org/x/xerrors" "github.com/future-architect/vuls/config" + "github.com/future-architect/vuls/logging" "github.com/future-architect/vuls/models" "github.com/future-architect/vuls/util" "github.com/google/subcommands" @@ -39,14 +40,14 @@ func RunTui(results models.ScanResults) subcommands.ExitStatus { g := gocui.NewGui() err := g.Init() if err != nil { - util.Log.Errorf("%+v", err) + logging.Log.Errorf("%+v", err) return subcommands.ExitFailure } defer g.Close() g.SetLayout(layout) if err := keybindings(g); err != nil { - util.Log.Errorf("%+v", err) + logging.Log.Errorf("%+v", err) return subcommands.ExitFailure } g.SelBgColor = gocui.ColorGreen @@ -55,7 +56,7 @@ func RunTui(results models.ScanResults) subcommands.ExitStatus { if err := g.MainLoop(); err != nil { g.Close() - util.Log.Errorf("%+v", err) + logging.Log.Errorf("%+v", err) os.Exit(1) } return subcommands.ExitSuccess @@ -929,7 +930,7 @@ func detailLines() (string, error) { mitigations = append(mitigations, fmt.Sprintf("* %s (%s)", m.URL, m.CveContentType)) default: - util.Log.Errorf("Unknown CveContentType: %s", m) + logging.Log.Errorf("Unknown CveContentType: %s", m) } } diff --git a/util/util.go b/util/util.go index 35782a08..0985cc77 100644 --- a/util/util.go +++ b/util/util.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/future-architect/vuls/config" + "github.com/future-architect/vuls/logging" ) // GenWorkers generates goroutine @@ -18,8 +19,7 @@ func GenWorkers(num int) chan<- func() { go func() { defer func() { if p := recover(); p != nil { - log := NewCustomLogger(config.ServerInfo{}) - log.Errorf("run time panic: %v", p) + logging.Log.Errorf("run time panic: %+v", p) } }() for f := range tasks { diff --git a/util/util_test.go b/util/util_test.go index 256af03c..a3564db4 100644 --- a/util/util_test.go +++ b/util/util_test.go @@ -69,7 +69,7 @@ func TestUrlJoin(t *testing.T) { paths := tt.in[1:] actual, err := URLPathJoin(baseurl, paths...) if err != nil { - t.Errorf("\nunexpected error occurred, err: %s,\ninput:%#v\nexpected: %s\n actual: %s", err, tt.in, tt.out, actual) + t.Errorf("\nunexpected error occurred, err: %+v,\ninput:%#v\nexpected: %s\n actual: %s", err, tt.in, tt.out, actual) } if actual != tt.out { t.Errorf("\ninput:%#v\nexpected: %s\n actual: %s", tt.in, tt.out, actual)