gopkg.in/alecthomas/gometalinter.v3@v3.0.0/_linters/src/github.com/securego/gosec/cmd/gosecutil/tools.go (about) 1 // (c) Copyright 2016 Hewlett Packard Enterprise Development LP 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package main 16 17 import ( 18 "flag" 19 "fmt" 20 "go/ast" 21 "go/importer" 22 "go/parser" 23 "go/token" 24 "go/types" 25 "os" 26 "strings" 27 ) 28 29 type command func(args ...string) 30 type utilities struct { 31 commands map[string]command 32 call []string 33 } 34 35 // Custom commands / utilities to run instead of default analyzer 36 func newUtils() *utilities { 37 utils := make(map[string]command) 38 utils["ast"] = dumpAst 39 utils["callobj"] = dumpCallObj 40 utils["uses"] = dumpUses 41 utils["types"] = dumpTypes 42 utils["defs"] = dumpDefs 43 utils["comments"] = dumpComments 44 utils["imports"] = dumpImports 45 return &utilities{utils, make([]string, 0)} 46 } 47 48 func (u *utilities) String() string { 49 i := 0 50 keys := make([]string, len(u.commands)) 51 for k := range u.commands { 52 keys[i] = k 53 i++ 54 } 55 return strings.Join(keys, ", ") 56 } 57 58 func (u *utilities) Set(opt string) error { 59 if _, ok := u.commands[opt]; !ok { 60 return fmt.Errorf("valid tools are: %s", u.String()) 61 62 } 63 u.call = append(u.call, opt) 64 return nil 65 } 66 67 func (u *utilities) run(args ...string) { 68 for _, util := range u.call { 69 if cmd, ok := u.commands[util]; ok { 70 cmd(args...) 71 } 72 } 73 } 74 75 func shouldSkip(path string) bool { 76 st, e := os.Stat(path) 77 if e != nil { 78 // #nosec 79 fmt.Fprintf(os.Stderr, "Skipping: %s - %s\n", path, e) 80 return true 81 } 82 if st.IsDir() { 83 // #nosec 84 fmt.Fprintf(os.Stderr, "Skipping: %s - directory\n", path) 85 return true 86 } 87 return false 88 } 89 90 func dumpAst(files ...string) { 91 for _, arg := range files { 92 // Ensure file exists and not a directory 93 if shouldSkip(arg) { 94 continue 95 } 96 97 // Create the AST by parsing src. 98 fset := token.NewFileSet() // positions are relative to fset 99 f, err := parser.ParseFile(fset, arg, nil, 0) 100 if err != nil { 101 // #nosec 102 fmt.Fprintf(os.Stderr, "Unable to parse file %s\n", err) 103 continue 104 } 105 106 // Print the AST. #nosec 107 ast.Print(fset, f) 108 } 109 } 110 111 type context struct { 112 fileset *token.FileSet 113 comments ast.CommentMap 114 info *types.Info 115 pkg *types.Package 116 config *types.Config 117 root *ast.File 118 } 119 120 func createContext(filename string) *context { 121 fileset := token.NewFileSet() 122 root, e := parser.ParseFile(fileset, filename, nil, parser.ParseComments) 123 if e != nil { 124 // #nosec 125 fmt.Fprintf(os.Stderr, "Unable to parse file: %s. Reason: %s\n", filename, e) 126 return nil 127 } 128 comments := ast.NewCommentMap(fileset, root, root.Comments) 129 info := &types.Info{ 130 Types: make(map[ast.Expr]types.TypeAndValue), 131 Defs: make(map[*ast.Ident]types.Object), 132 Uses: make(map[*ast.Ident]types.Object), 133 Selections: make(map[*ast.SelectorExpr]*types.Selection), 134 Scopes: make(map[ast.Node]*types.Scope), 135 Implicits: make(map[ast.Node]types.Object), 136 } 137 config := types.Config{Importer: importer.Default()} 138 pkg, e := config.Check("main.go", fileset, []*ast.File{root}, info) 139 if e != nil { 140 // #nosec 141 fmt.Fprintf(os.Stderr, "Type check failed for file: %s. Reason: %s\n", filename, e) 142 return nil 143 } 144 return &context{fileset, comments, info, pkg, &config, root} 145 } 146 147 func printObject(obj types.Object) { 148 fmt.Println("OBJECT") 149 if obj == nil { 150 fmt.Println("object is nil") 151 return 152 } 153 fmt.Printf(" Package = %v\n", obj.Pkg()) 154 if obj.Pkg() != nil { 155 fmt.Println(" Path = ", obj.Pkg().Path()) 156 fmt.Println(" Name = ", obj.Pkg().Name()) 157 fmt.Println(" String = ", obj.Pkg().String()) 158 } 159 fmt.Printf(" Name = %v\n", obj.Name()) 160 fmt.Printf(" Type = %v\n", obj.Type()) 161 fmt.Printf(" Id = %v\n", obj.Id()) 162 } 163 164 func checkContext(ctx *context, file string) bool { 165 // #nosec 166 if ctx == nil { 167 fmt.Fprintln(os.Stderr, "Failed to create context for file: ", file) 168 return false 169 } 170 return true 171 } 172 173 func dumpCallObj(files ...string) { 174 175 for _, file := range files { 176 if shouldSkip(file) { 177 continue 178 } 179 context := createContext(file) 180 if !checkContext(context, file) { 181 return 182 } 183 ast.Inspect(context.root, func(n ast.Node) bool { 184 var obj types.Object 185 switch node := n.(type) { 186 case *ast.Ident: 187 obj = context.info.ObjectOf(node) //context.info.Uses[node] 188 case *ast.SelectorExpr: 189 obj = context.info.ObjectOf(node.Sel) //context.info.Uses[node.Sel] 190 default: 191 obj = nil 192 } 193 if obj != nil { 194 printObject(obj) 195 } 196 return true 197 }) 198 } 199 } 200 201 func dumpUses(files ...string) { 202 for _, file := range files { 203 if shouldSkip(file) { 204 continue 205 } 206 context := createContext(file) 207 if !checkContext(context, file) { 208 return 209 } 210 for ident, obj := range context.info.Uses { 211 fmt.Printf("IDENT: %v, OBJECT: %v\n", ident, obj) 212 } 213 } 214 } 215 216 func dumpTypes(files ...string) { 217 for _, file := range files { 218 if shouldSkip(file) { 219 continue 220 } 221 context := createContext(file) 222 if !checkContext(context, file) { 223 return 224 } 225 for expr, tv := range context.info.Types { 226 fmt.Printf("EXPR: %v, TYPE: %v\n", expr, tv) 227 } 228 } 229 } 230 231 func dumpDefs(files ...string) { 232 for _, file := range files { 233 if shouldSkip(file) { 234 continue 235 } 236 context := createContext(file) 237 if !checkContext(context, file) { 238 return 239 } 240 for ident, obj := range context.info.Defs { 241 fmt.Printf("IDENT: %v, OBJ: %v\n", ident, obj) 242 } 243 } 244 } 245 246 func dumpComments(files ...string) { 247 for _, file := range files { 248 if shouldSkip(file) { 249 continue 250 } 251 context := createContext(file) 252 if !checkContext(context, file) { 253 return 254 } 255 for _, group := range context.comments.Comments() { 256 fmt.Println(group.Text()) 257 } 258 } 259 } 260 261 func dumpImports(files ...string) { 262 for _, file := range files { 263 if shouldSkip(file) { 264 continue 265 } 266 context := createContext(file) 267 if !checkContext(context, file) { 268 return 269 } 270 for _, pkg := range context.pkg.Imports() { 271 fmt.Println(pkg.Path(), pkg.Name()) 272 for _, name := range pkg.Scope().Names() { 273 fmt.Println(" => ", name) 274 } 275 } 276 } 277 } 278 279 func main() { 280 tools := newUtils() 281 flag.Var(tools, "tool", "Utils to assist with rule development") 282 flag.Parse() 283 284 if len(tools.call) > 0 { 285 tools.run(flag.Args()...) 286 os.Exit(0) 287 } 288 }