From 2d854cd64d2c701762c7a5054709cb23d259535a Mon Sep 17 00:00:00 2001 From: Kota Kanbe Date: Tue, 24 Jan 2017 00:21:56 +0900 Subject: [PATCH] Add -pipe flag #294 Solved the problem of trying to read from STDIN and stopping on the way when running from CRON or AWS Lambda. --- README.ja.md | 12 +++++++++++- README.md | 12 +++++++++++- commands/configtest.go | 15 --------------- commands/report.go | 15 ++++++++++++--- commands/scan.go | 30 ++++++++++++++++++------------ commands/tui.go | 10 ++++++++++ commands/util.go | 5 ++--- config/config.go | 2 ++ scan/redhat.go | 11 +++++------ 9 files changed, 71 insertions(+), 41 deletions(-) diff --git a/README.ja.md b/README.ja.md index 0a99ba2e6a..8e3b0c5a79 100644 --- a/README.ja.md +++ b/README.ja.md @@ -667,6 +667,7 @@ scan: [-http-proxy=http://192.168.0.1:8080] [-ask-key-password] [-debug] + [-pipe] [SERVER]... -ask-key-password @@ -681,6 +682,8 @@ scan: debug mode -http-proxy string http://proxy-url:port (default: empty) + -pipe + Use stdin via PIPE -results-dir string /path/to/results -skip-broken @@ -831,6 +834,7 @@ report: [-http-proxy=http://192.168.0.1:8080] [-debug] [-debug-sql] + [-pipe] [SERVER]... -aws-profile string @@ -877,6 +881,8 @@ report: Don't report the unscored CVEs -lang string [en|ja] (default "en") + -pipe + Use stdin via PIPE -refresh-cve Refresh CVE information in JSON file under results dir -results-dir string @@ -904,6 +910,7 @@ With this sample command, it will .. - Slack通知 - CVSS score が 7.0以上のもののみ通知 + ## Example: Put results in S3 bucket 事前にAWS関連の設定を行う @@ -1108,6 +1115,7 @@ tui: [-results-dir=/path/to/results] [-refresh-cve] [-debug-sql] + [-pipe] -cvedb-path string /path/to/sqlite3 (For get cve detail from cve.sqlite3) @@ -1117,6 +1125,8 @@ tui: http://cve-dictionary.com:8080 or mysql connection string -debug-sql debug SQL + -pipe + Use stdin via PIPE -refresh-cve Refresh CVE information in JSON file under results dir -results-dir string @@ -1156,7 +1166,7 @@ $ vuls tui 20160524_1940 # Display the previous scan results using peco ``` -$ vuls history | peco | vuls tui +$ vuls history | peco | vuls tui -pipe ``` [![asciicast](https://asciinema.org/a/emi7y7docxr60bq080z10t7v8.png)](https://asciinema.org/a/emi7y7docxr60bq080z10t7v8) diff --git a/README.md b/README.md index b0786fefa3..7c5efad26e 100644 --- a/README.md +++ b/README.md @@ -676,6 +676,7 @@ scan: [-http-proxy=http://192.168.0.1:8080] [-ask-key-password] [-debug] + [-pipe] [SERVER]... -ask-key-password @@ -690,6 +691,8 @@ scan: debug mode -http-proxy string http://proxy-url:port (default: empty) + -pipe + Use stdin via PIPE -results-dir string /path/to/results -skip-broken @@ -840,6 +843,7 @@ report: [-http-proxy=http://192.168.0.1:8080] [-debug] [-debug-sql] + [-pipe] [SERVER]... -aws-profile string @@ -886,6 +890,8 @@ report: Don't report the unscored CVEs -lang string [en|ja] (default "en") + -pipe + Use stdin via PIPE -refresh-cve Refresh CVE information in JSON file under results dir -results-dir string @@ -913,6 +919,7 @@ With this sample command, it will .. - Send scan results to slack - Only Report CVEs that CVSS score is over 7 + ## Example: Put results in S3 bucket To put results in S3 bucket, configure following settings in AWS before reporting. - Create S3 bucket. see [Creating a Bucket](http://docs.aws.amazon.com/AmazonS3/latest/UG/CreatingaBucket.html) @@ -1108,6 +1115,7 @@ tui: [-results-dir=/path/to/results] [-refresh-cve] [-debug-sql] + [-pipe] -cvedb-path string /path/to/sqlite3 (For get cve detail from cve.sqlite3) (default "/Users/kotakanbe/go/src/github.com/future-architect/vuls/cve.sqlite3") @@ -1117,6 +1125,8 @@ tui: http://cve-dictionary.com:8080 or mysql connection string -debug-sql debug SQL + -pipe + Use stdin via PIPE -refresh-cve Refresh CVE information in JSON file under results dir -results-dir string @@ -1152,7 +1162,7 @@ $ vuls tui 2016-12-30T10:34:38+09:00 # Display the previous scan results using peco ``` -$ vuls history | peco | vuls tui +$ vuls history | peco | vuls tui -pipe ``` [![asciicast](https://asciinema.org/a/emi7y7docxr60bq080z10t7v8.png)](https://asciinema.org/a/emi7y7docxr60bq080z10t7v8) diff --git a/commands/configtest.go b/commands/configtest.go index 2bcda75089..7c3ffbd93d 100644 --- a/commands/configtest.go +++ b/commands/configtest.go @@ -20,10 +20,8 @@ package commands import ( "context" "flag" - "io/ioutil" "os" "path/filepath" - "strings" "github.com/Sirupsen/logrus" "github.com/google/subcommands" @@ -108,19 +106,6 @@ func (p *ConfigtestCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interfa var servernames []string if 0 < len(f.Args()) { servernames = f.Args() - } else { - stat, _ := os.Stdin.Stat() - if (stat.Mode() & os.ModeCharDevice) == 0 { - bytes, err := ioutil.ReadAll(os.Stdin) - if err != nil { - logrus.Errorf("Failed to read stdin: %s", err) - return subcommands.ExitFailure - } - fields := strings.Fields(string(bytes)) - if 0 < len(fields) { - servernames = fields - } - } } target := make(map[string]c.ServerInfo) diff --git a/commands/report.go b/commands/report.go index 17095dccf5..a091797491 100644 --- a/commands/report.go +++ b/commands/report.go @@ -30,7 +30,6 @@ import ( "github.com/future-architect/vuls/report" "github.com/future-architect/vuls/util" "github.com/google/subcommands" - "github.com/kotakanbe/go-cve-dictionary/log" ) // ReportCmd is subcommand for reporting @@ -71,6 +70,8 @@ type ReportCmd struct { azureAccount string azureKey string azureContainer string + + pipe bool } // Name return subcommand name @@ -112,6 +113,7 @@ func (*ReportCmd) Usage() string { [-http-proxy=http://192.168.0.1:8080] [-debug] [-debug-sql] + [-pipe] [SERVER]... ` @@ -229,6 +231,12 @@ func (p *ReportCmd) SetFlags(f *flag.FlagSet) { "", "Azure account key to use. AZURE_STORAGE_ACCESS_KEY environment variable is used if not specified") f.StringVar(&p.azureContainer, "azure-container", "", "Azure storage container name") + + f.BoolVar( + &p.pipe, + "pipe", + false, + "Use args passed via PIPE") } // Execute execute @@ -251,9 +259,10 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{} c.Conf.IgnoreUnscoredCves = p.ignoreUnscoredCves c.Conf.HTTPProxy = p.httpProxy + c.Conf.Pipe = p.pipe jsonDir, err := jsonDir(f.Args()) if err != nil { - log.Errorf("Failed to read from JSON: %s", err) + Log.Errorf("Failed to read from JSON: %s", err) return subcommands.ExitFailure } @@ -348,7 +357,7 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{} Log.Debugf("need to refresh") if c.Conf.CveDBType == "sqlite3" { if _, err := os.Stat(c.Conf.CveDBPath); os.IsNotExist(err) { - log.Errorf("SQLite3 DB(CVE-Dictionary) is not exist: %s", + Log.Errorf("SQLite3 DB(CVE-Dictionary) is not exist: %s", c.Conf.CveDBPath) return subcommands.ExitFailure } diff --git a/commands/scan.go b/commands/scan.go index f06316bbdd..8bade889d5 100644 --- a/commands/scan.go +++ b/commands/scan.go @@ -45,6 +45,7 @@ type ScanCmd struct { containersOnly bool skipBroken bool sshExternal bool + pipe bool } // Name return subcommand name @@ -66,6 +67,7 @@ func (*ScanCmd) Usage() string { [-http-proxy=http://192.168.0.1:8080] [-ask-key-password] [-debug] + [-pipe] [SERVER]... ` @@ -121,6 +123,12 @@ func (p *ScanCmd) SetFlags(f *flag.FlagSet) { false, "Ask ssh privatekey password before scanning", ) + + f.BoolVar( + &p.pipe, + "pipe", + false, + "Use stdin via PIPE") } // Execute execute @@ -145,21 +153,19 @@ func (p *ScanCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) logrus.Info("Start scanning") logrus.Infof("config: %s", p.configPath) + c.Conf.Pipe = p.pipe var servernames []string if 0 < len(f.Args()) { servernames = f.Args() - } else { - stat, _ := os.Stdin.Stat() - if (stat.Mode() & os.ModeCharDevice) == 0 { - bytes, err := ioutil.ReadAll(os.Stdin) - if err != nil { - logrus.Errorf("Failed to read stdin: %s", err) - return subcommands.ExitFailure - } - fields := strings.Fields(string(bytes)) - if 0 < len(fields) { - servernames = fields - } + } else if c.Conf.Pipe { + bytes, err := ioutil.ReadAll(os.Stdin) + if err != nil { + logrus.Errorf("Failed to read stdin: %s", err) + return subcommands.ExitFailure + } + fields := strings.Fields(string(bytes)) + if 0 < len(fields) { + servernames = fields } } diff --git a/commands/tui.go b/commands/tui.go index 19a4d74041..55b4abb084 100644 --- a/commands/tui.go +++ b/commands/tui.go @@ -40,6 +40,8 @@ type TuiCmd struct { cvedbtype string cvedbpath string cveDictionaryURL string + + pipe bool } // Name return subcommand name @@ -58,6 +60,7 @@ func (*TuiCmd) Usage() string { [-results-dir=/path/to/results] [-refresh-cve] [-debug-sql] + [-pipe] ` } @@ -95,6 +98,12 @@ func (p *TuiCmd) SetFlags(f *flag.FlagSet) { "cvedb-url", "", "http://cve-dictionary.com:8080 or mysql connection string") + + f.BoolVar( + &p.pipe, + "pipe", + false, + "Use stdin via PIPE") } // Execute execute @@ -111,6 +120,7 @@ func (p *TuiCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) s return subcommands.ExitUsageError } + c.Conf.Pipe = p.pipe jsonDir, err := jsonDir(f.Args()) if err != nil { log.Errorf("Failed to read json dir under results: %s", err) diff --git a/commands/util.go b/commands/util.go index 6a7f345108..bd4b524918 100644 --- a/commands/util.go +++ b/commands/util.go @@ -74,7 +74,7 @@ func lsValidJSONDirs() (dirs jsonDirs, err error) { // jsonDir returns // If there is an arg, check if it is a valid format and return the corresponding path under results. -// If passed via PIPE (such as history subcommand), return that path. +// If arg passed via PIPE (such as history subcommand), return that path. // Otherwise, returns the path of the latest directory func jsonDir(args []string) (string, error) { var err error @@ -98,8 +98,7 @@ func jsonDir(args []string) (string, error) { } // PIPE - stat, _ := os.Stdin.Stat() - if (stat.Mode() & os.ModeCharDevice) == 0 { + if c.Conf.Pipe { bytes, err := ioutil.ReadAll(os.Stdin) if err != nil { return "", fmt.Errorf("Failed to read stdin: %s", err) diff --git a/config/config.go b/config/config.go index 3d0322fffb..e8a15deb30 100644 --- a/config/config.go +++ b/config/config.go @@ -72,6 +72,8 @@ type Config struct { AzureAccount string AzureKey string AzureContainer string + + Pipe bool } // ValidateOnConfigtest validates diff --git a/scan/redhat.go b/scan/redhat.go index 9778485052..5b38127c76 100644 --- a/scan/redhat.go +++ b/scan/redhat.go @@ -97,11 +97,11 @@ func detectRedhat(c config.ServerInfo) (itsMe bool, red osTypeInterface) { } func (o *redhat) checkIfSudoNoPasswd() error { - cmd := "yum --version" - if o.Distro.Family == "centos" { - cmd = "echo N | " + cmd - } - r := o.exec(cmd, o.sudo()) + cmd := "yum --version" + if o.Distro.Family == "centos" { + cmd = "echo N | " + cmd + } + r := o.exec(cmd, o.sudo()) if !r.isSuccess() { o.log.Errorf("sudo error on %s", r) return fmt.Errorf("Failed to sudo: %s", r) @@ -644,7 +644,6 @@ func (o *redhat) scanUnsecurePackagesUsingYumPluginSecurity() (models.VulnInfos, // All information collected. // Convert to VulnInfos. - o.log.Info("Fetching CVE details...") vinfos := models.VulnInfos{} for _, advIDCveIDs := range advisoryCveIDsList { for _, cveID := range advIDCveIDs.CveIDs {