From ce2daf24931140afd916e65df795f62fc55983e9 Mon Sep 17 00:00:00 2001 From: gleentea Date: Tue, 1 Nov 2016 16:06:02 +0900 Subject: [PATCH] add xml-report add struct tag for encoding/xml update README update glide.lock --- README.ja.md | 10 +++++---- README.md | 7 +++++-- commands/scan.go | 10 +++++++++ glide.lock | 2 +- models/models.go | 32 ++++++++++++++-------------- report/xml.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 92 insertions(+), 23 deletions(-) create mode 100644 report/xml.go diff --git a/README.ja.md b/README.ja.md index bc4b5da9ff..965f441dab 100644 --- a/README.ja.md +++ b/README.ja.md @@ -157,7 +157,7 @@ $ sudo chmod 700 /var/log/vuls $ $ mkdir -p $GOPATH/src/github.com/kotakanbe $ cd $GOPATH/src/github.com/kotakanbe -$ git https://github.com/kotakanbe/go-cve-dictionary.git +$ git clone https://github.com/kotakanbe/go-cve-dictionary.git $ cd go-cve-dictionary $ make install ``` @@ -620,6 +620,7 @@ scan: [-report-s3] [-report-slack] [-report-text] + [-report-xml] [-http-proxy=http://192.168.0.1:8080] [-ask-key-password] [-debug] @@ -681,6 +682,8 @@ scan: Send report via Slack -report-text Write report to text files ($PWD/results/current) + -report-xml + Write report to XML files ($PWDresults/current) -results-dir string /path/to/results (default "$PWD/results") -ssh-external @@ -708,11 +711,10 @@ Defaults:vuls !requiretty | empty password | - | | | with password | required | or use ssh-agent | -## -report-json , -report-text option +## -report-json , -report-text , -report-xml option 結果をファイルに出力したい場合に指定する。出力先は、`$PWD/result/current/` -`all.(json|txt)`には、全サーバのスキャン結果が出力される。 -`servername.(json|txt)`には、サーバごとのスキャン結果が出力される。 +`servername.(json|txt|xml)`には、サーバごとのスキャン結果が出力される。 ## Example: Scan all servers defined in config file ``` diff --git a/README.md b/README.md index 75eb206561..2f2e5abfcf 100644 --- a/README.md +++ b/README.md @@ -627,6 +627,7 @@ scan: [-report-s3] [-report-slack] [-report-text] + [-report-xml] [-http-proxy=http://192.168.0.1:8080] [-ask-key-password] [-debug] @@ -688,6 +689,8 @@ scan: Send report via Slack -report-text Write report to text files ($PWD/results/current) + -report-xml + Write report to XML files ($PWDresults/current) -results-dir string /path/to/results (default "$PWD/results") -ssh-external @@ -716,10 +719,10 @@ Defaults:vuls !requiretty | empty password | - | | | with password | required | or use ssh-agent | -## -report-json , -report-text option +## -report-json , -report-text , -report-xml option At the end of the scan, scan results will be available in the `$PWD/result/current/` directory. -`all.(json|txt)` includes the scan results of all servers and `servername.(json|txt)` includes the scan result of the server. +`servername.(json|txt|xml)` includes the scan result of the server. ## Example: Scan all servers defined in config file ``` diff --git a/commands/scan.go b/commands/scan.go index d902538d9b..c87d720c70 100644 --- a/commands/scan.go +++ b/commands/scan.go @@ -67,6 +67,7 @@ type ScanCmd struct { reportText bool reportS3 bool reportAzureBlob bool + reportXML bool awsProfile string awsS3Bucket string @@ -106,6 +107,7 @@ func (*ScanCmd) Usage() string { [-report-s3] [-report-slack] [-report-text] + [-report-xml] [-http-proxy=http://192.168.0.1:8080] [-ask-key-password] [-debug] @@ -204,6 +206,11 @@ func (p *ScanCmd) SetFlags(f *flag.FlagSet) { false, fmt.Sprintf("Write report to text files (%s/results/current)", wd), ) + f.BoolVar(&p.reportXML, + "report-xml", + false, + fmt.Sprintf("Write report to XML files (%s/results/current)", wd), + ) f.BoolVar(&p.reportS3, "report-s3", @@ -333,6 +340,9 @@ func (p *ScanCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) if p.reportText { reports = append(reports, report.TextFileWriter{ScannedAt: scannedAt}) } + if p.reportXML { + reports = append(reports, report.XMLWriter{ScannedAt: scannedAt}) + } if p.reportS3 { c.Conf.AwsRegion = p.awsRegion c.Conf.AwsProfile = p.awsProfile diff --git a/glide.lock b/glide.lock index 32a30e26b9..5ff706a9e5 100644 --- a/glide.lock +++ b/glide.lock @@ -69,7 +69,7 @@ imports: - name: github.com/k0kubun/pp version: f5dce6ed0ccf6c350f1679964ff6b61f3d6d2033 - name: github.com/kotakanbe/go-cve-dictionary - version: d0d8b0d3eee8022395d37edd95e88af7f5f970ad + version: 70989b6709c3102924ad8c8483e9bdc99bcb598b subpackages: - config - db diff --git a/models/models.go b/models/models.go index 3a1877748d..c1ae27bc6c 100644 --- a/models/models.go +++ b/models/models.go @@ -72,8 +72,8 @@ func (s ScanResults) FilterByCvssOver() (filtered ScanResults) { // ScanResult has the result of scanned CVE information. type ScanResult struct { - gorm.Model `json:"-"` - ScanHistoryID uint `json:"-"` + gorm.Model `json:"-" xml:"-"` + ScanHistoryID uint `json:"-" xml:"-"` ScannedAt time.Time ServerName string // TOML Section key @@ -167,8 +167,8 @@ func (r ScanResult) CveSummary() string { // NWLink has network link information. type NWLink struct { - gorm.Model `json:"-"` - ScanResultID uint `json:"-"` + gorm.Model `json:"-" xml:"-"` + ScanResultID uint `json:"-" xml:"-"` IPAddress string Netmask string @@ -197,8 +197,8 @@ func (c CveInfos) Less(i, j int) bool { // CveInfo has Cve Information. type CveInfo struct { - gorm.Model `json:"-"` - ScanResultID uint `json:"-"` + gorm.Model `json:"-" xml:"-"` + ScanResultID uint `json:"-" xml:"-"` CveDetail cve.CveDetail Packages []PackageInfo @@ -208,8 +208,8 @@ type CveInfo struct { // CpeName has CPE name type CpeName struct { - gorm.Model `json:"-"` - CveInfoID uint `json:"-"` + gorm.Model `json:"-" xml:"-"` + CveInfoID uint `json:"-" xml:"-"` Name string } @@ -274,8 +274,8 @@ func (ps PackageInfoList) FindByName(name string) (result PackageInfo, found boo // PackageInfo has installed packages. type PackageInfo struct { - gorm.Model `json:"-"` - CveInfoID uint `json:"-"` + gorm.Model `json:"-" xml:"-"` + CveInfoID uint `json:"-" xml:"-"` Name string Version string @@ -311,8 +311,8 @@ func (p PackageInfo) ToStringNewVersion() string { // DistroAdvisory has Amazon Linux, RHEL, FreeBSD Security Advisory information. type DistroAdvisory struct { - gorm.Model `json:"-"` - CveInfoID uint `json:"-"` + gorm.Model `json:"-" xml:"-"` + CveInfoID uint `json:"-" xml:"-"` AdvisoryID string Severity string @@ -322,8 +322,8 @@ type DistroAdvisory struct { // Container has Container information type Container struct { - gorm.Model `json:"-"` - ScanResultID uint `json:"-"` + gorm.Model `json:"-" xml:"-"` + ScanResultID uint `json:"-" xml:"-"` ContainerID string Name string @@ -331,8 +331,8 @@ type Container struct { // Platform has platform information type Platform struct { - gorm.Model `json:"-"` - ScanResultID uint `json:"-"` + gorm.Model `json:"-" xml:"-"` + ScanResultID uint `json:"-" xml:"-"` Name string // aws or azure or gcp or other... InstanceID string diff --git a/report/xml.go b/report/xml.go new file mode 100644 index 0000000000..5699e1714a --- /dev/null +++ b/report/xml.go @@ -0,0 +1,54 @@ +package report + +import ( + "bytes" + "encoding/xml" + "fmt" + "io/ioutil" + "path/filepath" + "time" + + "github.com/future-architect/vuls/models" +) + +const ( + vulsOpenTag = "" + vulsCloseTag = "" +) + +// XMLWriter writes results to file. +type XMLWriter struct { + ScannedAt time.Time +} + +func (w XMLWriter) Write(scanResults []models.ScanResult) (err error) { + var path string + if path, err = ensureResultDir(w.ScannedAt); err != nil { + return fmt.Errorf("Failed to make direcotory/symlink : %s", err) + } + + for _, scanResult := range scanResults { + scanResult.ScannedAt = w.ScannedAt + } + + var xmlBytes []byte + for _, r := range scanResults { + xmlPath := "" + if len(r.Container.ContainerID) == 0 { + xmlPath = filepath.Join(path, fmt.Sprintf("%s.xml", r.ServerName)) + } else { + xmlPath = filepath.Join(path, + fmt.Sprintf("%s_%s.xml", r.ServerName, r.Container.Name)) + } + + if xmlBytes, err = xml.Marshal(r); err != nil { + return fmt.Errorf("Failed to Marshal to XML: %s", err) + } + + allBytes := bytes.Join([][]byte{[]byte(xml.Header + vulsOpenTag), xmlBytes, []byte(vulsCloseTag)}, []byte{}) + if err := ioutil.WriteFile(xmlPath, allBytes, 0600); err != nil { + return fmt.Errorf("Failed to write XML. path: %s, err: %s", xmlPath, err) + } + } + return nil +}