Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package gokart for openSUSE:Factory checked 
in at 2021-09-14 21:14:19
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/gokart (Old)
 and      /work/SRC/openSUSE:Factory/.gokart.new.1899 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "gokart"

Tue Sep 14 21:14:19 2021 rev:2 rq:918787 version:0.2.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/gokart/gokart.changes    2021-08-20 
16:58:14.150840554 +0200
+++ /work/SRC/openSUSE:Factory/.gokart.new.1899/gokart.changes  2021-09-14 
21:14:25.780407387 +0200
@@ -1,0 +2,14 @@
+Thu Sep 02 14:03:52 UTC 2021 - alexandre.vice...@suse.com
+
+- Update to version 0.2.0:
+  * Add new flags usage to Getting Started (#31)
+  * Adding -r flag to automatically clone and test remote go modules, along 
with functionality to test the Scan cmd (#20)
+  * Making a minor change to error messages when packages aren't found in the 
directory (#28)
+  * Feature enhancement implementation for Issue #3 (Findings Output to File 
Flag) (#24)
+  * changed panic to log.Fatal (#22)
+  * removed non-user-controllable input sources (#23)
+  * typo fixes (#14)
+  * Improved config mgmt and fixed out of bounds panic (#5)
+  * add link to Praetorian blog post in README
+
+-------------------------------------------------------------------

Old:
----
  gokart-0.1.0.tar.gz

New:
----
  gokart-0.2.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ gokart.spec ++++++
--- /var/tmp/diff_new_pack.ysxNu4/_old  2021-09-14 21:14:26.576408169 +0200
+++ /var/tmp/diff_new_pack.ysxNu4/_new  2021-09-14 21:14:26.576408169 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           gokart
-Version:        0.1.0
+Version:        0.2.0
 Release:        0
 Summary:        Static analysis tool for securing Go code
 License:        Apache-2.0

++++++ _service ++++++
--- /var/tmp/diff_new_pack.ysxNu4/_old  2021-09-14 21:14:26.604408196 +0200
+++ /var/tmp/diff_new_pack.ysxNu4/_new  2021-09-14 21:14:26.604408196 +0200
@@ -3,7 +3,7 @@
     <param name="url">https://github.com/praetorian-inc/gokart.git</param>
     <param name="scm">git</param>
     <param name="exclude">.git</param>
-    <param name="revision">v0.1.0</param>
+    <param name="revision">v0.2.0</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="changesgenerate">enable</param>
     <param name="versionrewrite-pattern">v(.*)</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.ysxNu4/_old  2021-09-14 21:14:26.620408211 +0200
+++ /var/tmp/diff_new_pack.ysxNu4/_new  2021-09-14 21:14:26.620408211 +0200
@@ -1,4 +1,4 @@
 <servicedata>
 <service name="tar_scm">
                 <param 
name="url">https://github.com/praetorian-inc/gokart.git</param>
-              <param 
name="changesrevision">ab619765ff5e3963f1b504516490b3a4f328f08f</param></service></servicedata>
\ No newline at end of file
+              <param 
name="changesrevision">fecb3b0f40927e14053bbb6dfbce3160e8b388bb</param></service></servicedata>
\ No newline at end of file

++++++ gokart-0.1.0.tar.gz -> gokart-0.2.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gokart-0.1.0/README.md new/gokart-0.2.0/README.md
--- old/gokart-0.1.0/README.md  2021-08-18 15:59:31.000000000 +0200
+++ new/gokart-0.2.0/README.md  2021-08-27 20:22:38.000000000 +0200
@@ -28,7 +28,9 @@
 the answer is yes. By leveraging source-to-sink tracing and SSA, GoKart is 
capable
 of tracking variable taint between variable assignments, significantly 
improving the 
 accuracy of findings. Our focus is on usability: pragmatically, that means we 
-have optimized our approaches to reduce false alarms. 
+have optimized our approaches to reduce false alarms.
+
+For more information, please read [our blog 
post](https://www.praetorian.com/blog/introducing-gokart/).
 
 ## Install
 
@@ -132,6 +134,22 @@
 
 # Output results in sarif format
 gokart scan go-test-bench/ -s
+
+# Output results to file
+gokart scan go-test-bench/ -o gokart-go-test-bench.txt
+
+# Output scarif results to file
+gokart scan go-test-bench/ -o gokart-go-test-bench.txt -s
+
+# Scan remote repository (private repos require proper authentication)
+# Repository will be cloned locally, scanned and deleted afterwards
+gokart scan -r github.com/ShiftLeftSecurity/shiftleft-go-demo -v
+
+# Use remote scan and output flags together for seamless security reviews
+gokart scan -r github.com/ShiftLeftSecurity/shiftleft-go-demo -o 
gokart-shiftleft-go-demo.txt -v 
+
+# Use remote scan, output and sarif flags for frictionless integration into 
CI/CD
+gokart scan -r github.com/ShiftLeftSecurity/shiftleft-go-demo -o 
gokart-shiftleft-go-demo.txt -s
 ```
 
 To test out the extensibility of GoKart, you can modify the configuration file 
that GoKart uses to
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gokart-0.1.0/analyzers/cmdi.go 
new/gokart-0.2.0/analyzers/cmdi.go
--- old/gokart-0.1.0/analyzers/cmdi.go  2021-08-18 15:59:31.000000000 +0200
+++ new/gokart-0.2.0/analyzers/cmdi.go  2021-08-27 20:22:38.000000000 +0200
@@ -65,7 +65,7 @@
                        // Construct full name of function
                        current_function := pkg + "." + fn
 
-                       // Iterate over occurences of vulnerable function in 
call graph
+                       // Iterate over occurrences of vulnerable function in 
call graph
                        for _, vulnFunc := range call_graph[current_function] {
 
                                // Check if argument of vulnerable function is 
tainted by possibly user-controlled input
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gokart-0.1.0/analyzers/generic.go 
new/gokart-0.2.0/analyzers/generic.go
--- old/gokart-0.1.0/analyzers/generic.go       2021-08-18 15:59:31.000000000 
+0200
+++ new/gokart-0.2.0/analyzers/generic.go       2021-08-27 20:22:38.000000000 
+0200
@@ -15,13 +15,9 @@
 package analyzers
 
 import (
-       "io/ioutil"
-       "log"
-
        "github.com/praetorian-inc/gokart/util"
        "golang.org/x/tools/go/analysis"
        "golang.org/x/tools/go/analysis/passes/buildssa"
-       "gopkg.in/yaml.v3"
 )
 
 // Creates generic taint analyzer based on Sources and Sinks defined in 
analyzers.yaml file
@@ -46,7 +42,7 @@
                for _, fn := range funcs {
                        // Construct full name of function
                        currentFunc := pkg + "." + fn
-                       // Iterate over occurences of vulnerable function in 
call graph
+                       // Iterate over occurrences of vulnerable function in 
call graph
                        for _, vulnFunc := range cg[currentFunc] {
                                // Check if argument of vulnerable function is 
tainted by possibly user-controlled input
                                taintAnalyzer := util.CreateTaintAnalyzer(pass, 
vulnFunc.Fn.Pos())
@@ -63,56 +59,23 @@
        return results, nil
 }
 
-// LoadGenericAnalyzers creates generic taint anlalyzers from custom Sources 
and Sinks defined in analyzers.yaml
+// LoadGenericAnalyzers creates generic taint analyzers from custom Sources 
and Sinks defined in analyzers.yaml
 // converts all variables to SSA form to construct a call graph and performs
 // recursive taint analysis to search for input sources of user-controllable 
data
+func LoadGenericAnalyzers() []*analysis.Analyzer {
+       var analyzers []*analysis.Analyzer
 
-func LoadGenericAnalyzers(yaml_path string) []*analysis.Analyzer {
-       yfile, err := ioutil.ReadFile(yaml_path)
-       if err != nil {
-               log.Fatal(err)
-       }
-
-       data := 
make(map[interface{}]map[interface{}]map[interface{}]interface{})
-       err = yaml.Unmarshal(yfile, &data)
-       if err != nil {
-               log.Fatal(err)
-       }
-
-       // Load analyzers from the interface
-       analyzers := []*analysis.Analyzer{}
-       m := data["analyzers"]
-       for analyzerName, analyzerDict := range m {
-               // Get the vulnerability message
-               message := ""
-               if analyzerDict["message"] != nil {
-                       message = analyzerDict["message"].(string)
-               }
-
-               // Load the map of vulnerable functions
-               vulnCalls := make(map[string][]string)
-               yamlCallsMap := 
analyzerDict["vuln_calls"].(map[string]interface{})
-               for pkgName, packageVulnFuncs := range yamlCallsMap {
-                       var newList []string
-                       vulnCalls[pkgName] = newList
-                       packageVulnFuncsList := packageVulnFuncs.([]interface{})
-                       for _, val := range packageVulnFuncsList {
-                               vulnCalls[pkgName] = append(vulnCalls[pkgName], 
val.(string))
-                       }
-               }
-
-               // Wrap generic_function_run with a function that the analyze 
package can use
+       for analyzerName, analyzerDict := range util.ScanConfig.Analyzers {
                analyzerFunc := func(pass *analysis.Pass) (interface{}, error) {
-                       return genericFunctionRun(pass, vulnCalls, 
analyzerName.(string), message)
+                       return genericFunctionRun(pass, analyzerDict.VulnCalls, 
analyzerName, analyzerDict.Message)
                }
-
-               // Form the analyzer object and append to the analyzer list
-               analysisRun := new(analysis.Analyzer)
-               analysisRun.Name = "path_traversal"
-               analysisRun.Doc = analyzerDict["doc"].(string)
-               analysisRun.Run = analyzerFunc
-               analysisRun.Requires = []*analysis.Analyzer{buildssa.Analyzer}
-               analyzers = append(analyzers, analysisRun)
+               analysisRun := analysis.Analyzer{
+                       Name:     analyzerName,
+                       Doc:      analyzerDict.Doc,
+                       Run:      analyzerFunc,
+                       Requires: []*analysis.Analyzer{buildssa.Analyzer},
+               }
+               analyzers = append(analyzers, &analysisRun)
        }
 
        return analyzers
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gokart-0.1.0/analyzers/rsa.go 
new/gokart-0.2.0/analyzers/rsa.go
--- old/gokart-0.1.0/analyzers/rsa.go   2021-08-18 15:59:31.000000000 +0200
+++ new/gokart-0.2.0/analyzers/rsa.go   2021-08-27 20:22:38.000000000 +0200
@@ -28,7 +28,7 @@
 
 // RSAKeyLenAnalyzer is used to resolve constant values used for RSA key 
generation in order to more accurately
 // detect use of an insecure RSA key length constructed
-// all variables are converted to SSA form and a call graph is contructed
+// all variables are converted to SSA form and a call graph is constructed
 // recursive analysis is then used to resolve variables used as a key length 
to a final constant value at the callsite
 var RsaKeylenAnalyzer = &analysis.Analyzer{
        Name:     "rsa_keylen",
@@ -168,7 +168,7 @@
                        // Construct full name of function
                        current_function := pkg + "." + fn
 
-                       // Iterate over occurences of vulnerable function in 
call graph
+                       // Iterate over occurrences of vulnerable function in 
call graph
                        for _, vulnFunc := range call_graph[current_function] {
 
                                // Check if argument of vulnerable function has 
keylen that is less than RECOMMENDED_KEYLEN
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gokart-0.1.0/analyzers/scan.go 
new/gokart-0.2.0/analyzers/scan.go
--- old/gokart-0.1.0/analyzers/scan.go  2021-08-18 15:59:31.000000000 +0200
+++ new/gokart-0.2.0/analyzers/scan.go  2021-08-27 20:22:38.000000000 +0200
@@ -39,17 +39,73 @@
        SSRFAnalyzer,
 }
 
+func FilterResults(unfilteredResults []util.Finding, parent_dir string) 
([]util.Finding, error) {
+       filteredResults := []util.Finding{}
+
+       for _, finding := range unfilteredResults {
+               finding.Vulnerable_Function.SourceFilename = 
strings.TrimPrefix(finding.Vulnerable_Function.SourceFilename, parent_dir)
+               if finding.Untrusted_Source != nil {
+                       for i, source := range finding.Untrusted_Source {
+                               finding.Untrusted_Source[i].SourceFilename = 
strings.TrimPrefix(source.SourceFilename, parent_dir)
+                       }
+               }
+               if util.IsValidFinding(finding) {
+                       filteredResults = append(filteredResults, finding)
+               }
+       }
+
+       return filteredResults, nil
+}
+
+func OutputResults(results []util.Finding, success bool) error {
+       var stdOutPipe, outputFile *os.File
+
+       if util.Config.OutputPath != "" {
+               stdOutPipe = os.Stdout // keep backup of the real stdout
+               // open file read/write | create if not exist | clear file at 
open if exists
+               outputFile, err := os.OpenFile(util.Config.OutputPath, 
os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
+               if err != nil {
+                       return err
+               }
+               os.Stdout = outputFile
+       }
+
+       for _, finding := range results {
+               util.OutputFinding(finding)
+       }
+
+       // if packages were able to be scanned, print the correct output message
+       if util.Config.OutputSarif && success {
+               util.SarifPrintReport()
+               fmt.Println()
+       }
+
+       // if output was redirected for findings, change it back to the 
original stdout
+       if util.Config.OutputPath != "" {
+               outputFile.Close()
+               os.Stdout = stdOutPipe // restoring the real stdout
+       }
+
+       return nil
+}
+
 func Scan(args []string) {
+       //Get the current dir so we can reset it later.
+       current_dir, err := os.Getwd()
+       if err != nil {
+               fmt.Printf("Unable to get current dir.\n")
+       }
+
        if util.Config.OutputSarif {
                util.InitSarifReporting()
        } else {
                fmt.Printf("\nRevving engines VRMMM VRMMM\n3...2...1...Go!\n")
        }
-
        // If we're given a target path, we do some slight changes to make sure 
that
        // gokart will behave as expected. Specifically we turn the path into 
an absolute
        // path, and then we append /... to the end to make sure the package 
loading is recursive.
        // Finally we update the current working directory to the target
+       // In order to not cause issues we set the working directory back after 
we are done scanning.
        if len(args) > 0 {
                target_path := args[0]
                if !filepath.IsAbs(target_path) {
@@ -58,7 +114,7 @@
                }
 
                // Fix up the path to make sure it is pointed at a directory 
(even if given a file)
-               fileInfo, err := os.Stat(strings.TrimRight(target_path, "..."))
+               fileInfo, err := os.Stat(strings.TrimRight(target_path, "."))
                if err != nil {
                        log.Fatal(err)
                }
@@ -76,7 +132,7 @@
                        }
                }
 
-               err = os.Chdir(strings.TrimRight(target_path, "..."))
+               err = os.Chdir(strings.TrimRight(target_path, "."))
                if err != nil {
                        log.Fatal(err)
                }
@@ -86,7 +142,7 @@
                }
        }
 
-       generic_analyzers := LoadGenericAnalyzers(util.Config.YMLPath)
+       generic_analyzers := LoadGenericAnalyzers()
        Analyzers = append(Analyzers, generic_analyzers[:]...)
 
        // Begin timer
@@ -94,7 +150,7 @@
        // Run analyzers
        results, success, err := run.Run(Analyzers, args...)
        if err != nil {
-               panic(err)
+               log.Fatal(err)
        }
        // Calculate time taken
        scan_time := time.Since(run_begin_time)
@@ -117,24 +173,21 @@
                parent_dir += "/"
        }
 
-       count := 0
-       for _, finding := range results {
-               finding.Vulnerable_Function.SourceFilename = 
strings.TrimPrefix(finding.Vulnerable_Function.SourceFilename, parent_dir)
-               if finding.Untrusted_Source != nil {
-                       for i, source := range finding.Untrusted_Source {
-                               finding.Untrusted_Source[i].SourceFilename = 
strings.TrimPrefix(source.SourceFilename, parent_dir)
-                       }
-               }
-               if util.OutputFinding(finding) {
-                       count++
-               }
+       // fix-up our results to exclude invalid results + shorten long 
directory names
+       filteredResults, err := FilterResults(results, parent_dir)
+       if err != nil {
+               log.Fatal(err)
        }
-       // if packages were able to be scanned, print the correct output message
-       if util.Config.OutputSarif && success {
-               util.SarifPrintReport()
-               fmt.Println()
-       } else if success {
+
+       // output findings to stdout or specified output file
+       err = OutputResults(filteredResults, success)
+       if err != nil {
+               log.Fatalf("Error opening output file: %v", err)
+       }
+
+       if !util.Config.OutputSarif && success {
                fmt.Println("\nRace Complete! Analysis took", scan_time, "and", 
util.FilesFound, "Go files were scanned (including imported packages)")
-               fmt.Printf("GoKart found %d potentially vulnerable 
functions\n", count)
+               fmt.Printf("GoKart found %d potentially vulnerable 
functions\n", len(filteredResults))
        }
+       os.Chdir(current_dir)
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gokart-0.1.0/analyzers/sqli.go 
new/gokart-0.2.0/analyzers/sqli.go
--- old/gokart-0.1.0/analyzers/sqli.go  2021-08-18 15:59:31.000000000 +0200
+++ new/gokart-0.2.0/analyzers/sqli.go  2021-08-27 20:22:38.000000000 +0200
@@ -23,7 +23,7 @@
 )
 
 // SQLInjectionAnalyzer constructs Sinks from a set of functions known to be 
vulnerable to SQL injection
-// all variables are converted to SSA form and a call graph is contructed
+// all variables are converted to SSA form and a call graph is constructed
 // recursive taint analysis is then used to search from a given Sink up the 
callgraph for Sources of user-controllable data
 var SQLInjectionAnalyzer = &analysis.Analyzer{
        Name:     "sql_injection",
@@ -71,7 +71,7 @@
                                argIndex = 2
                        }
 
-                       // Iterate over occurences of vulnerable function in 
call graph
+                       // Iterate over occurrences of vulnerable function in 
call graph
                        for _, vulnFunc := range cg[current_function] {
 
                                // Check if argument of vulnerable function is 
tainted by possibly user-controlled input
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gokart-0.1.0/analyzers/ssrf.go 
new/gokart-0.2.0/analyzers/ssrf.go
--- old/gokart-0.1.0/analyzers/ssrf.go  2021-08-18 15:59:31.000000000 +0200
+++ new/gokart-0.2.0/analyzers/ssrf.go  2021-08-27 20:22:38.000000000 +0200
@@ -143,7 +143,7 @@
 
                        // Construct full name of function
                        curFunc := pkg + "." + fn
-                       // Iterate over occurences of vulnerable function in 
call graph
+                       // Iterate over occurrences of vulnerable function in 
call graph
                        for _, vulnFunc := range cg[curFunc] {
                                // Check if argument of vulnerable function is 
tainted by possibly user-controlled input
                                taintAnalyzer := util.CreateTaintAnalyzer(pass, 
vulnFunc.Fn.Pos())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gokart-0.1.0/analyzers/traversal.go 
new/gokart-0.2.0/analyzers/traversal.go
--- old/gokart-0.1.0/analyzers/traversal.go     2021-08-18 15:59:31.000000000 
+0200
+++ new/gokart-0.2.0/analyzers/traversal.go     2021-08-27 20:22:38.000000000 
+0200
@@ -21,12 +21,12 @@
 )
 
 // PathTraversalAnalyzer constructs Sinks from a set of functions known to be 
vulnerable to path injection
-// all variables are converted to SSA form and a call graph is contructed
+// all variables are converted to SSA form and a call graph is constructed
 // recursive taint analysis is then used to search from a given Sink up the 
callgraph for Sources of user-controllable data
 var PathTraversalAnalyzer = &analysis.Analyzer{
        Name:     "path_traversal",
        Doc:      "reports when path traversal can occur",
-       Run:      traveralRun,
+       Run:      traversalRun,
        Requires: []*analysis.Analyzer{buildssa.Analyzer},
 }
 
@@ -38,8 +38,8 @@
        }
 }
 
-// traveralRun runs the path traversal analyzer
-func traveralRun(pass *analysis.Pass) (interface{}, error) {
+// traversalRun runs the path traversal analyzer
+func traversalRun(pass *analysis.Pass) (interface{}, error) {
 
        results := []util.Finding{}
        // Builds SSA model of Go code
@@ -65,7 +65,7 @@
                        // Construct full name of function
                        curFunc := pkg + "." + fn
 
-                       // Iterate over occurences of vulnerable function in 
call graph
+                       // Iterate over occurrences of vulnerable function in 
call graph
                        for _, vulnFunc := range cg[curFunc] {
 
                                // Check if argument of vulnerable function is 
tainted by possibly user-controlled input
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gokart-0.1.0/cmd/scan.go new/gokart-0.2.0/cmd/scan.go
--- old/gokart-0.1.0/cmd/scan.go        2021-08-18 15:59:31.000000000 +0200
+++ new/gokart-0.2.0/cmd/scan.go        2021-08-27 20:22:38.000000000 +0200
@@ -18,12 +18,17 @@
 package cmd
 
 import (
+       "log"
+
        "github.com/praetorian-inc/gokart/analyzers"
        "github.com/praetorian-inc/gokart/util"
        "github.com/spf13/cobra"
+
 )
 
 var yml string
+var goModName string
+var outputPath string
 
 func init() {
        goKartCmd.AddCommand(scanCmd)
@@ -31,7 +36,9 @@
        scanCmd.Flags().BoolP("globalsTainted", "g", false, "marks global 
variables as dangerous")
        scanCmd.Flags().BoolP("verbose", "v", false, "outputs full trace of 
taint analysis")
        scanCmd.Flags().BoolP("debug", "d", false, "outputs debug logs")
-       scanCmd.Flags().StringVarP(&yml, "input", "i", "", "input path to 
custom yml file")
+       scanCmd.Flags().StringVarP(&goModName, "remoteModule", "r", "", "Remote 
gomodule to scan")
+  scanCmd.Flags().StringVarP(&yml, "input", "i", "", "input path to custom yml 
file")
+       scanCmd.Flags().StringVarP(&outputPath, "output", "o", "", "file path 
to write findings output instead of stdout")
        goKartCmd.MarkFlagRequired("scan")
 }
 
@@ -41,15 +48,32 @@
        Long: `
 Scans a Go module directory. To scan the current directory recursively, use 
gokart scan. To scan a specific directory, use gokart scan <directory>.`,
        Run: func(cmd *cobra.Command, args []string) {
-               if len(args) == 0 {
-                       // recursively scan the current directory if no 
arguments are passed in
-                       args = append(args, "./...")
-               }
                sarif, _ := cmd.Flags().GetBool("sarif")
                globals, _ := cmd.Flags().GetBool("globalsTainted")
                verbose, _ := cmd.Flags().GetBool("verbose")
                debug, _ := cmd.Flags().GetBool("debug")
-               util.InitConfig(globals, sarif, verbose, debug, yml)
+               util.InitConfig(globals, sarif, verbose, debug, outputPath, yml)
+               
+               // If gomodname flag is set to a non-empty value then clone the 
repo and scan it
+               if len(goModName) != 0 {
+                       modDirName, err := util.ParseModuleName(goModName)
+                       if err != nil {
+                               log.Fatal(err)
+                       }
+                       err = util.CloneModule(modDirName, "https://"+goModName)
+                       if err != nil {
+                               log.Fatal("GoKart was unable to get the new 
racetrack. Ensure track repository is open to the public or that your access 
tokens are configured correctly for Private ones.")
+                       }
+                       defer util.CleanupModule(modDirName)
+                       // If passing in a module - the other arguments are 
wiped out!
+                       args = append([]string{}, modDirName+"/...")
+               }
+
+               // recursively scan the current directory if no arguments are 
passed in
+               if len(args) == 0 {
+                       args = append(args, "./...")
+               }
+               
                analyzers.Scan(args)
        },
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gokart-0.1.0/cmd/scan_test.go 
new/gokart-0.2.0/cmd/scan_test.go
--- old/gokart-0.1.0/cmd/scan_test.go   1970-01-01 01:00:00.000000000 +0100
+++ new/gokart-0.2.0/cmd/scan_test.go   2021-08-27 20:22:38.000000000 +0200
@@ -0,0 +1,77 @@
+package cmd
+
+import (
+       "testing"
+       "strings"
+       "fmt"
+       "os"
+       "io/ioutil"
+       
+       "github.com/praetorian-inc/gokart/util"
+       "github.com/spf13/cobra"
+)
+
+func TestScanCommand(t *testing.T) {
+       // Tests the Scan command.
+       cur_dir, err := os.Getwd()
+       if err != nil {
+               fmt.Println(err)
+               os.Exit(1)
+       }
+       fmt.Printf("Current dir is: %s", cur_dir)
+       var tests = []struct {
+               args []string
+               expected_lastline string
+               moduledir string
+       }{
+               {[]string{"scan"},"GoKart found 0 potentially vulnerable 
functions", ""},
+               {[]string{"scan","-r", 
"github.com/Contrast-Security-OSS/go-test-bench"}, "GoKart found 8 potentially 
vulnerable functions", cur_dir+"/go-test-bench"},
+               {[]string{"scan","-r", "github.com/praetorian-inc/gokart"}, 
"GoKart found 0 potentially vulnerable functions", cur_dir+"/gokart"},
+               {[]string{"scan", "--help"}, "  -v, --verbose               
outputs full trace of taint analysis", ""},
+       }
+       for _, tt := range tests {
+               t.Run(strings.Join(tt.args, " "), func(t *testing.T) {
+                       
+                       if err != nil {
+                               t.Fatalf("Failed! %s",err)
+                       }
+
+                       // fetch last line of output from scan command
+                       lastline := ExecuteCommand(goKartCmd, tt.args)
+                       //if we tested with a remote module clean it up.
+                       if len(tt.moduledir) != 0 {
+                               err := util.CleanupModule(tt.moduledir)
+                               if err != nil {
+                                       fmt.Print(err)
+                               }
+                       }
+                       if lastline != tt.expected_lastline {
+                               t.Fatalf("Failed! Expected: %s\nGot: 
%s\n",tt.expected_lastline,lastline,)
+                       } 
+               })
+       }
+}
+
+func ExecuteCommand(cmd *cobra.Command,args []string) (string) {
+
+       // change stdout to something we can read from to capture command out
+       // Not sure if this could potentially cause issues if buffer gets too 
full
+       old := os.Stdout
+       r, w, _ := os.Pipe()
+       os.Stdout = w
+       os.Stderr = w
+
+       cmd.SetArgs(args)
+       Execute()
+
+       // reset stdout to normal stdout and read output from cmd
+       w.Close()
+       stdoutres, _ := ioutil.ReadAll(r)
+       os.Stdout = old
+
+       //get the last line of output for comparison with our tests
+       stdoutresslice := strings.Split(strings.ReplaceAll(string(stdoutres), 
"\r\n", "\n"), "\n")
+       lastline := stdoutresslice[len(stdoutresslice)-2]
+       return lastline
+
+}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gokart-0.1.0/go.mod new/gokart-0.2.0/go.mod
--- old/gokart-0.1.0/go.mod     2021-08-18 15:59:31.000000000 +0200
+++ new/gokart-0.2.0/go.mod     2021-08-27 20:22:38.000000000 +0200
@@ -4,6 +4,7 @@
 
 require (
        github.com/fatih/color v1.12.0
+       github.com/go-git/go-git/v5 v5.4.2 // indirect
        github.com/lithammer/dedent v1.1.0
        github.com/owenrumney/go-sarif v1.0.11
        github.com/segmentio/fasthash v1.0.3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gokart-0.1.0/go.sum new/gokart-0.2.0/go.sum
--- old/gokart-0.1.0/go.sum     2021-08-18 15:59:31.000000000 +0200
+++ new/gokart-0.2.0/go.sum     2021-08-27 20:22:38.000000000 +0200
@@ -39,11 +39,20 @@
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod 
h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 github.com/BurntSushi/toml v0.3.1/go.mod 
h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod 
h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/Microsoft/go-winio v0.4.14/go.mod 
h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
+github.com/Microsoft/go-winio v0.4.16 
h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk=
+github.com/Microsoft/go-winio v0.4.16/go.mod 
h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
+github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 
h1:YoJbenK9C67SkzkDfmQuVln04ygHj3vjZfd9FL+GmQQ=
+github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod 
h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
+github.com/acomagu/bufpipe v1.0.3 
h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk=
+github.com/acomagu/bufpipe v1.0.3/go.mod 
h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
+github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod 
h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
 github.com/antihax/optional v1.0.0/go.mod 
h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod 
h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod 
h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod 
h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod 
h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod 
h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
 github.com/bgentry/speakeasy v0.1.0/go.mod 
h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
 github.com/bketelsen/crypt v0.0.4/go.mod 
h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod 
h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -57,9 +66,12 @@
 github.com/coreos/go-semver v0.3.0/go.mod 
h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 github.com/coreos/go-systemd/v22 v22.3.2/go.mod 
h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
 github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod 
h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.9/go.mod 
h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/davecgh/go-spew v1.1.0/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 
h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/emirpasic/gods v1.12.0 
h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
+github.com/emirpasic/gods v1.12.0/go.mod 
h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod 
h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane 
v0.9.1-0.20191026205805-5f8ba28d4473/go.mod 
h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod 
h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -70,8 +82,18 @@
 github.com/fatih/color v1.7.0/go.mod 
h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
 github.com/fatih/color v1.12.0/go.mod 
h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
+github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod 
h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
 github.com/fsnotify/fsnotify v1.4.9/go.mod 
h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
 github.com/ghodss/yaml v1.0.0/go.mod 
h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/gliderlabs/ssh v0.2.2/go.mod 
h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
+github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
+github.com/go-git/gcfg v1.5.0/go.mod 
h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
+github.com/go-git/go-billy/v5 v5.2.0/go.mod 
h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
+github.com/go-git/go-billy/v5 v5.3.1 
h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34=
+github.com/go-git/go-billy/v5 v5.3.1/go.mod 
h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
+github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod 
h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0=
+github.com/go-git/go-git/v5 v5.4.2 
h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4=
+github.com/go-git/go-git/v5 v5.4.2/go.mod 
h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod 
h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod 
h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod 
h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -163,23 +185,34 @@
 github.com/hashicorp/serf v0.8.2/go.mod 
h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod 
h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod 
h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/imdario/mergo v0.3.12 
h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
+github.com/imdario/mergo v0.3.12/go.mod 
h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
 github.com/inconshreveable/mousetrap v1.0.0 
h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod 
h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 
h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod 
h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
+github.com/jessevdk/go-flags v1.5.0/go.mod 
h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
 github.com/json-iterator/go v1.1.11/go.mod 
h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod 
h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
 github.com/jstemmer/go-junit-report v0.9.1/go.mod 
h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod 
h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 
h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck=
+github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod 
h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
 github.com/kisielk/errcheck v1.5.0/go.mod 
h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod 
h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod 
h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
 github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 github.com/kr/pretty v0.1.0/go.mod 
h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.1/go.mod 
h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod 
h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0/go.mod 
h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/lithammer/dedent v1.1.0 
h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY=
 github.com/lithammer/dedent v1.1.0/go.mod 
h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
 github.com/magiconair/properties v1.8.5/go.mod 
h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
+github.com/matryer/is v1.2.0/go.mod 
h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
 github.com/mattn/go-colorable v0.0.9/go.mod 
h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
 github.com/mattn/go-colorable v0.1.8 
h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
 github.com/mattn/go-colorable v0.1.8/go.mod 
h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
@@ -189,6 +222,8 @@
 github.com/miekg/dns v1.0.14/go.mod 
h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
 github.com/mitchellh/cli v1.0.0/go.mod 
h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
 github.com/mitchellh/go-homedir v1.0.0/go.mod 
h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-homedir v1.1.0 
h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
+github.com/mitchellh/go-homedir v1.1.0/go.mod 
h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/go-testing-interface v1.0.0/go.mod 
h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
 github.com/mitchellh/gox v0.4.0/go.mod 
h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
 github.com/mitchellh/iochan v1.0.0/go.mod 
h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
@@ -198,11 +233,13 @@
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod 
h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod 
h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v1.0.1/go.mod 
h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod 
h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/owenrumney/go-sarif v1.0.11 
h1:7k4TLSi6h3vAozSECjO0arcQoeUNDMgvA7LDac95sJo=
 github.com/owenrumney/go-sarif v1.0.11/go.mod 
h1:hTBFbxU7GuVRUvwMx+eStp9M/Oun4xHCS3vqpPvket8=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod 
h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pelletier/go-toml v1.9.3/go.mod 
h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
 github.com/pkg/errors v0.8.1/go.mod 
h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1/go.mod 
h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/sftp v1.10.1/go.mod 
h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
 github.com/pmezard/go-difflib v1.0.0 
h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod 
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -215,7 +252,10 @@
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod 
h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
 github.com/segmentio/fasthash v1.0.3 
h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtrmhM=
 github.com/segmentio/fasthash v1.0.3/go.mod 
h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY=
+github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
+github.com/sergi/go-diff v1.1.0/go.mod 
h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod 
h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.4.1/go.mod 
h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod 
h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
 github.com/smartystreets/goconvey v1.6.4/go.mod 
h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
 github.com/spf13/afero v1.6.0/go.mod 
h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
@@ -227,6 +267,7 @@
 github.com/spf13/pflag v1.0.5/go.mod 
h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/spf13/viper v1.8.1/go.mod 
h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
 github.com/stretchr/objx v0.1.0/go.mod 
h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod 
h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.2.2/go.mod 
h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod 
h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod 
h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -237,6 +278,8 @@
 github.com/subosito/gotenv v1.2.0/go.mod 
h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod 
h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
 github.com/vmihailenco/tagparser v0.1.1/go.mod 
h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
+github.com/xanzy/ssh-agent v0.3.0 
h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI=
+github.com/xanzy/ssh-agent v0.3.0/go.mod 
h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
 github.com/yuin/goldmark v1.1.25/go.mod 
h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.27/go.mod 
h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.32/go.mod 
h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -258,12 +301,16 @@
 go.uber.org/multierr v1.6.0/go.mod 
h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
 go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
 golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod 
h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod 
h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod 
h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod 
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod 
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod 
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod 
h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod 
h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod 
h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b 
h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
+golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod 
h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod 
h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod 
h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod 
h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -335,6 +382,8 @@
 golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod 
h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod 
h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod 
h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
+golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod 
h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 
h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod 
h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod 
h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod 
h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -361,6 +410,7 @@
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -370,6 +420,7 @@
 golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -398,8 +449,10 @@
 golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007 
h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod 
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod 
h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -577,11 +630,18 @@
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod 
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 
h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod 
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod 
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod 
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod 
h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
+gopkg.in/warnings.v0 v0.1.2/go.mod 
h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod 
h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b 
h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gokart-0.1.0/run/run.go new/gokart-0.2.0/run/run.go
--- old/gokart-0.1.0/run/run.go 2021-08-18 15:59:31.000000000 +0200
+++ new/gokart-0.2.0/run/run.go 2021-08-27 20:22:38.000000000 +0200
@@ -88,7 +88,8 @@
        }
        // Print error mssage if no scannable packages are found
        if len(pkgs) == 0 {
-               fmt.Printf("CRASH! GoKart didn't find any files to scan! Make 
sure the usage is correct to get GoKart back on track. \n")
+               fmt.Printf("CRASH! GoKart didn't find any files to scan! Make 
sure the usage is correct to get GoKart back on track. \n" +
+                       "If the usage appears to be correct, try pointing 
gokart at the directory from where you would run 'go build'. \n")
                success = false
        }
        return pkgs, success, nil
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gokart-0.1.0/util/analyzers.yml 
new/gokart-0.2.0/util/analyzers.yml
--- old/gokart-0.1.0/util/analyzers.yml 2021-08-18 15:59:31.000000000 +0200
+++ new/gokart-0.2.0/util/analyzers.yml 2021-08-27 20:22:38.000000000 +0200
@@ -33,66 +33,61 @@
 #         - "Printf"
 
 
+
+# Each entry specifies a source that should be considered untrusted
+# If the package already exists in the sources section, add the 
variable/function/type underneath 
+# Each package can contain multiple vulnerable sources.
 sources:
-  # Each entry specifies a source that should be considered untrusted
-  # If the package already exists in the sources section, add the 
variable/function/type underneath 
-  # Each package can contain multiple vulnerable sources.
-  sources:
-    # Sources that are defined in Go documentation as a "variable" go here 
(note: these variables will have an SSA type of "Global").
-    variables:
-      "os":
-        - "Args"
-    # Sources that are defined in Go documentation as a "function" go here.
-    functions:
-      "flag":
-        - "Arg"
-        - "Args"
-      "os":
-        - "Environ"
-        - "File"
-        - "FileInfo"
-        - "FileMode"
-        - "Readdir"
-        - "Readdirnames"
-        - "OpenFile"
-      "crypto/tls":
-        - "LoadX509KeyPair"
-        - "X509KeyPair"
-      "os/user":
-        - "Lookup"
-        - "LookupId"
-        - "Current"
-      "crypto/x509":
-        - "Subjects"
-      "io":
-        - "ReadAtLeast"
-        - "ReadFull"
-      "database/sql":
-        - "Query"
-        - "QueryRow"
-      "bytes":
-        - "String"
-        - "ReadBytes"
-        - "ReadByte"
-      "bufio":
-        - "Text"
-        - "Bytes"
-        - "ReadString"
-        - "ReadSlice"
-        - "ReadRune"
-        - "ReadLine"
-        - "ReadBytes"
-        - "ReadByte"
-      "archive/tar":
-        - "Next"
-        - "FileInfo"
-        - "Header"
-      "net/url":
-        - "ParseQuery"
-        - "ParseUriRequest"
-        - "Parse"
-        - "Query"
-    # Sources that are defined in Go documentation as a "type" go here (note: 
adding types will consider all functions that use that type to be tainted).
-    types:
-      "net/http":
-        - "Request"
+  # Sources that are defined in Go documentation as a "variable" go here 
(note: these variables will have an SSA type of "Global").
+  variables:
+    "os":
+      - "Args"
+  # Sources that are defined in Go documentation as a "function" go here.
+  functions:
+    "flag":
+      - "Arg"
+      - "Args"
+    "os":
+      - "Environ"
+      - "File"
+    "crypto/tls":
+      - "LoadX509KeyPair"
+      - "X509KeyPair"
+    "os/user":
+      - "Lookup"
+      - "LookupId"
+      - "Current"
+    "crypto/x509":
+      - "Subjects"
+    "io":
+      - "ReadAtLeast"
+      - "ReadFull"
+    "database/sql":
+      - "Query"
+      - "QueryRow"
+    "bytes":
+      - "String"
+      - "ReadBytes"
+      - "ReadByte"
+    "bufio":
+      - "Text"
+      - "Bytes"
+      - "ReadString"
+      - "ReadSlice"
+      - "ReadRune"
+      - "ReadLine"
+      - "ReadBytes"
+      - "ReadByte"
+    "archive/tar":
+      - "Next"
+      - "FileInfo"
+      - "Header"
+    "net/url":
+      - "ParseQuery"
+      - "ParseUriRequest"
+      - "Parse"
+      - "Query"
+  # Sources that are defined in Go documentation as a "type" go here (note: 
adding types will consider all functions that use that type to be tainted).
+  types:
+    "net/http":
+      - "Request"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gokart-0.1.0/util/config.go 
new/gokart-0.2.0/util/config.go
--- old/gokart-0.1.0/util/config.go     2021-08-18 15:59:31.000000000 +0200
+++ new/gokart-0.2.0/util/config.go     2021-08-27 20:22:38.000000000 +0200
@@ -16,13 +16,12 @@
 
 import (
        _ "embed"
-       "flag"
        "fmt"
        "io/ioutil"
        "log"
        "os"
-       "path"
        "path/filepath"
+       "sync"
 
        "gopkg.in/yaml.v3"
 )
@@ -34,6 +33,29 @@
        Debug       bool
        Verbose     bool
        YMLPath     string
+       OutputPath  string
+}
+
+// ConfigFile stores the values parsed from the configuration file
+type ConfigFile struct {
+       Analyzers map[string]Analyzer `yaml:"analyzers"`
+       Sources   Sources             `yaml:"sources"`
+}
+
+// Analyzer stores an analyzer parsed from the configuration file
+type Analyzer struct {
+       Doc       string              `yaml:"doc"`
+       Message   string              `yaml:"message"`
+       VulnCalls map[string][]string `yaml:"vuln_calls"`
+}
+
+// Sources stores the untrusted sources parsed from the configuration file
+type Sources struct {
+       Variables map[string][]string `yaml:"variables"`
+       Functions map[string][]string `yaml:"functions"`
+       Types     map[string][]string `yaml:"types"`
+       // For compatibility with older analyzer.yml format
+       OldSrcs *Sources `yaml:"sources"`
 }
 
 var (
@@ -45,115 +67,113 @@
        DefaultAnalyzersContent []byte
 )
 
-var Config ConfigType
+var (
+       configDir string
+       once      sync.Once
+)
 
-func LoadVulnerableSources() {
-       // Load YAML
-       yamlPath := Config.YMLPath
-       // If not found in the working directory, use the one in the 
executable's directory
-       if _, err := os.Stat(yamlPath); os.IsNotExist(err) {
-               execPath, err := os.Executable()
-               if err != nil {
-                       log.Fatal(err)
-               }
-               yamlPath = path.Join(path.Dir(execPath), yamlPath)
-       }
-       yfile, err := ioutil.ReadFile(yamlPath)
+var (
+       Config     ConfigType
+       ScanConfig ConfigFile
+)
+
+func LoadScanConfig() {
+       configBytes, err := ioutil.ReadFile(Config.YMLPath)
        if err != nil {
                log.Fatal(err)
        }
-
-       data := 
make(map[interface{}]map[interface{}]map[interface{}]interface{})
-       err = yaml.Unmarshal(yfile, &data)
-       if err != nil {
+       if err := yaml.Unmarshal(configBytes, &ScanConfig); err != nil {
                log.Fatal(err)
        }
 
-       skeys := data["sources"]
-       if Config.Debug {
-               log.Println("Beginning list of sources defined in yml:")
+       // If OldSrcs isn't nil, then the config file is in the old format and 
we unnest the values
+       if ScanConfig.Sources.OldSrcs != nil {
+               ScanConfig.Sources.Functions = 
ScanConfig.Sources.OldSrcs.Functions
+               ScanConfig.Sources.Variables = 
ScanConfig.Sources.OldSrcs.Variables
+               ScanConfig.Sources.Types = ScanConfig.Sources.OldSrcs.Types
+               // Set OldSrcs to nil to let the garbage collector clean it up
+               ScanConfig.Sources.OldSrcs = nil
        }
-       for _, sdict := range skeys {
-               for stype, sTypeDict := range sdict {
-                       callsmap := sTypeDict.(map[string]interface{})
-                       vulnmap := make(map[string][]string)
-
-                       for package_name, package_vuln_funcs := range callsmap {
-                               // Initialize an empty array if the map key 
does not exist
-                               if _, ok := vulnmap[package_name]; !ok {
-                                       var empty_array []string
-                                       vulnmap[package_name] = empty_array
-                               }
-                               package_vuln_funcs_arr := 
package_vuln_funcs.([]interface{})
-                               for i, val := range package_vuln_funcs_arr {
-                                       if Config.Debug {
-                                               log.Println("Function", 
package_vuln_funcs_arr[i], "in package", package_name)
-                                       }
-                                       vulnmap[package_name] = 
append(vulnmap[package_name], val.(string))
-                               }
-                       }
 
-                       // Set the map of vulnerable sources of this type
-                       if stype == "variables" {
-                               VulnGlobalVars = vulnmap
-                       } else if stype == "functions" {
-                               VulnGlobalFuncs = vulnmap
-                       } else if stype == "types" {
-                               VulnTypes = vulnmap
+       if Config.Debug {
+               log.Println("Beginning list of default sources defined in yml:")
+               for pkg, fn := range ScanConfig.Sources.Functions {
+                       log.Printf("Functions %s in package %s\n", fn, pkg)
+               }
 
+               if len(ScanConfig.Analyzers) > 0 {
+                       log.Println("\nBeginning list of analyzers defined in 
yml:")
+                       for name, values := range ScanConfig.Analyzers {
+                               log.Printf("Name:    %s\n", name)
+                               log.Printf("Doc:     %s\n", values.Doc)
+                               log.Printf("Message: %s\n", values.Message)
+                               log.Println("Vuln Calls:")
+                               for pkg, fn := range values.VulnCalls {
+                                       log.Printf("Functions %s in package 
%s\n", fn, pkg)
+                               }
                        }
                }
+               log.Printf("\n\n")
        }
-       if Config.Debug {
-               log.Println("List of sources complete")
-       }
+       VulnGlobalVars = ScanConfig.Sources.Variables
+       VulnGlobalFuncs = ScanConfig.Sources.Functions
+       VulnTypes = ScanConfig.Sources.Types
 }
 
 // InitConfig() parses the flags and sets the corresponding Config variables
-func InitConfig(globals bool, sarif bool, verbose bool, debug bool, yml 
string) {
-
-       flag.Parse()
-
-       // If the YAML path provided is a relative path, convert it to absolute
-       if yml != "" && !filepath.IsAbs(yml) {
-               yml, _ = filepath.Abs(yml)
+func InitConfig(globals bool, sarif bool, verbose bool, debug bool, 
output_path string, yml string) {
+       if yml == "" {
+               yml = getDefaultConfigPath()
+       } else if _, err := os.Stat(yml); err != nil {
+               log.Fatalf("failed to find the provided config file at %s: %v", 
yml, err)
        }
+       fmt.Printf("Using config found at %s\n", yml)
 
-       // If the YAML path provided is empty or doesn't exist, then load from 
the default of ~/.gokart/analyzers.yml
-       if _, err := os.Stat(yml); os.IsNotExist(err) {
-               if yml != "" {
-                       fmt.Printf("Custom analyzers config file not found at 
%q. ", yml)
+       Config.GlobalsSafe = !globals
+       Config.OutputSarif = sarif
+       Config.Debug = debug
+       Config.Verbose = verbose
+       Config.OutputPath = ""
+       // get the absolute path of the output file to avoid issues when 
changing working directory for loading packages
+       if output_path != "" {
+               abs_output_path, err := filepath.Abs(output_path)
+               if err != nil {
+                       log.Fatal(err)
                }
-               fmt.Println("Using default analyzers config found at 
\"~/.gokart/analyzers.yml\".")
-
-               // Load YAML
-               config_path := os.ExpandEnv("$HOME/.gokart")
-               yaml_path := path.Join(config_path, "analyzers.yml")
-               yml = yaml_path
+               Config.OutputPath = abs_output_path
+       }
+       Config.YMLPath = yml
+       LoadScanConfig()
+}
 
-               // Create our config directory if it doesn't already exist
-               if _, err := os.Stat(config_path); os.IsNotExist(err) {
-                       err = os.Mkdir(config_path, 0744)
-                       if err != nil {
-                               log.Fatal(err)
-                       }
-               }
+// getDefaultConfigPath gets the path to the default configuration file and 
creates it if it doesn't yet exist.
+func getDefaultConfigPath() string {
+       setConfigDir()
+       yamlPath := filepath.Join(configDir, "analyzers.yml")
 
-               // If not found in the working directory, use the one in the 
executable's directory
-               if _, err := os.Stat(yaml_path); os.IsNotExist(err) {
-                       // default_analyzers_content is populated using the 
go:embed directive above
-                       err := ioutil.WriteFile(yaml_path, 
DefaultAnalyzersContent, 0744)
-                       if err != nil {
-                               log.Fatal(err)
-                       }
-                       fmt.Println("No existing analyzers.yml file found - 
writing default to ~/.gokart/analyzers.yml")
+       // If ~/.gokart/analyzers.yml doesn't exist, create it with the default 
config
+       if _, err := os.Stat(yamlPath); os.IsNotExist(err) {
+               fmt.Printf("Initializing default config at %s\n", yamlPath)
+               if err := ioutil.WriteFile(yamlPath, DefaultAnalyzersContent, 
0o744); err != nil {
+                       log.Fatalf("failed to write default config to %s: %v", 
yamlPath, err)
                }
+       } else if err != nil {
+               // If the error returned by os.Stat is not ErrNotExist
+               log.Fatalf("failed to initialize default config: %v", err)
        }
+       return yamlPath
+}
 
-       Config.GlobalsSafe = !globals
-       Config.OutputSarif = sarif
-       Config.Debug = debug
-       Config.Verbose = verbose
-       Config.YMLPath = yml
-       LoadVulnerableSources()
+// setConfigDir initializes the configDir variable upon its first invocation, 
does nothing otherwise.
+func setConfigDir() {
+       once.Do(func() {
+               userHomeDir, err := os.UserHomeDir()
+               if err != nil {
+                       log.Fatalf("failed to get home directory: %v", err)
+               }
+               configDir = filepath.Join(userHomeDir, ".gokart")
+               if err = os.MkdirAll(configDir, 0o744); err != nil {
+                       log.Fatalf("failed to create config directory %s: %v", 
configDir, err)
+               }
+       })
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gokart-0.1.0/util/finding.go 
new/gokart-0.2.0/util/finding.go
--- old/gokart-0.1.0/util/finding.go    2021-08-18 15:59:31.000000000 +0200
+++ new/gokart-0.2.0/util/finding.go    2021-08-27 20:22:38.000000000 +0200
@@ -48,12 +48,20 @@
        return strings.TrimSpace(functionName) + "(...)" + functionReturn
 }
 
-// prints out a finding; returns true if the finding was valid and false if 
the finding had the same source and sink
-func OutputFinding(finding Finding) bool {
-       // if the source and sink are the same, return false and do not print 
out the finding
+// returns true if the finding was valid and false if the finding had the same 
source and sink
+func IsValidFinding(finding Finding) bool {
+       if len(finding.Untrusted_Source) == 0 {
+               return false
+       }
        if finding.Vulnerable_Function.SourceCode == 
finding.Untrusted_Source[0].SourceCode {
+               // if the source and sink are the same, return false and do not 
print out the finding
                return false
        }
+       return true
+}
+
+// prints out a finding
+func OutputFinding(finding Finding) {
        if Config.OutputSarif {
                SarifRecordFinding(finding.Type, finding.message, 
finding.Vulnerable_Function.SourceFilename,
                        finding.Vulnerable_Function.SourceLineNum)
@@ -92,5 +100,4 @@
                }
                
fmt.Printf("------------------------------------------------------------------------------\n")
        }
-       return true
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gokart-0.1.0/util/module.go 
new/gokart-0.2.0/util/module.go
--- old/gokart-0.1.0/util/module.go     1970-01-01 01:00:00.000000000 +0100
+++ new/gokart-0.2.0/util/module.go     2021-08-27 20:22:38.000000000 +0200
@@ -0,0 +1,72 @@
+// Copyright 2021 Praetorian Security, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package util
+
+import (
+       "github.com/go-git/go-git/v5"
+       "fmt"
+       "strings"
+       "os"
+       "errors"
+)
+
+// CloneModule clones a remote git repository over HTTP.
+func CloneModule(dir string, url string) error {
+       // fmt.Printf("git clone %s\n", url)
+       fmt.Printf("Loading new racetrack: %s\n",url)
+
+       _, err := git.PlainClone(dir, false, &git.CloneOptions{
+               URL: url,
+               Progress: os.Stdout,
+       })
+       if err != nil {
+               return err
+       }
+
+       return nil
+}
+
+//CleanupModule attempts to delete a directory.
+func CleanupModule(dir string) error {
+       
+       err := os.RemoveAll(dir)
+       if err != nil{
+               return err
+       }
+       return nil
+}
+
+// ParseModuleName returns a directory from a module path 
+func ParseModuleName(mn string) (string, error) {
+
+       cur_dir, err := os.Getwd()
+       if err != nil {
+               return "", err
+       }
+
+       if len(mn) == 0 {
+               return "", errors.New("No module name provided")
+       }
+
+       modSlice := strings.Split(mn, "/")
+       if len(modSlice) <= 1 {
+               return "", errors.New("Invalid remote module name!\nMust be in 
format of: github.com/praetorian/gokart")
+       }
+
+       dirName := cur_dir + "/" + modSlice[len(modSlice)-1:][0]
+       return dirName, nil
+
+
+}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/gokart-0.1.0/util/sarif.go 
new/gokart-0.2.0/util/sarif.go
--- old/gokart-0.1.0/util/sarif.go      2021-08-18 15:59:31.000000000 +0200
+++ new/gokart-0.2.0/util/sarif.go      2021-08-27 20:22:38.000000000 +0200
@@ -15,6 +15,7 @@
 package util
 
 import (
+       "log"
        "os"
 
        "github.com/owenrumney/go-sarif/sarif"
@@ -27,7 +28,7 @@
        report, err := sarif.New(sarif.Version210)
        SarifReport = report
        if err != nil {
-               panic(err)
+               log.Fatal(err)
        }
        SarifRun = sarif.NewRun("GoKart", 
"https://github.com/praetorian-inc/gokart";)
 }

++++++ vendor.tar.gz ++++++
++++ 111814 lines of diff (skipped)

Reply via email to