Merge pull request #240 from gleentea/feature/report-xml
Add the XML output
This commit is contained in:
		
							
								
								
									
										10
									
								
								README.ja.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								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
 | 
			
		||||
```
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
```
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								glide.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								glide.lock
									
									
									
										generated
									
									
									
								
							@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										54
									
								
								report/xml.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								report/xml.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
package report
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/xml"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/future-architect/vuls/models"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	vulsOpenTag  = "<vulsreport>"
 | 
			
		||||
	vulsCloseTag = "</vulsreport>"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 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
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user