github.com/prysmaticlabs/prysm@v1.4.4/tools/analyzers/properpermissions/analyzer.go (about) 1 // Package properpermissions implements a static analyzer to ensure that Prysm does not 2 // use ioutil.MkdirAll or os.WriteFile as they are unsafe when it comes to guaranteeing 3 // file permissions and not overriding existing permissions. Instead, users are warned 4 // to utilize shared/fileutil as the canonical solution. 5 package properpermissions 6 7 import ( 8 "errors" 9 "fmt" 10 "go/ast" 11 12 "golang.org/x/tools/go/analysis" 13 "golang.org/x/tools/go/analysis/passes/inspect" 14 "golang.org/x/tools/go/ast/inspector" 15 ) 16 17 // Doc explaining the tool. 18 const Doc = "Tool to enforce usage of Prysm's internal file-writing utils instead of os.MkdirAll or ioutil.WriteFile" 19 20 var ( 21 errUnsafePackage = errors.New( 22 "os and ioutil dir and file writing functions are not permissions-safe, use shared/fileutil", 23 ) 24 disallowedFns = []string{"MkdirAll", "WriteFile"} 25 ) 26 27 // Analyzer runs static analysis. 28 var Analyzer = &analysis.Analyzer{ 29 Name: "properpermissions", 30 Doc: Doc, 31 Requires: []*analysis.Analyzer{inspect.Analyzer}, 32 Run: run, 33 } 34 35 func run(pass *analysis.Pass) (interface{}, error) { 36 inspection, ok := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) 37 if !ok { 38 return nil, errors.New("analyzer is not type *inspector.Inspector") 39 } 40 41 nodeFilter := []ast.Node{ 42 (*ast.File)(nil), 43 (*ast.ImportSpec)(nil), 44 (*ast.CallExpr)(nil), 45 } 46 47 aliases := make(map[string]string) 48 49 inspection.Preorder(nodeFilter, func(node ast.Node) { 50 switch stmt := node.(type) { 51 case *ast.File: 52 // Reset aliases (per file). 53 aliases = make(map[string]string) 54 case *ast.ImportSpec: 55 // Collect aliases. 56 pkg := stmt.Path.Value 57 if pkg == "\"os\"" { 58 if stmt.Name != nil { 59 aliases[stmt.Name.Name] = pkg 60 } else { 61 aliases["os"] = pkg 62 } 63 } 64 if pkg == "\"io/ioutil\"" { 65 if stmt.Name != nil { 66 aliases[stmt.Name.Name] = pkg 67 } else { 68 aliases["ioutil"] = pkg 69 } 70 } 71 case *ast.CallExpr: 72 // Check if any of disallowed functions have been used. 73 for alias, pkg := range aliases { 74 for _, fn := range disallowedFns { 75 if isPkgDot(stmt.Fun, alias, fn) { 76 pass.Reportf( 77 node.Pos(), 78 fmt.Sprintf( 79 "%v: %s.%s() (from %s)", 80 errUnsafePackage, 81 alias, 82 fn, 83 pkg, 84 ), 85 ) 86 } 87 } 88 } 89 } 90 }) 91 92 return nil, nil 93 } 94 95 func isPkgDot(expr ast.Expr, pkg, name string) bool { 96 sel, ok := expr.(*ast.SelectorExpr) 97 res := ok && isIdent(sel.X, pkg) && isIdent(sel.Sel, name) 98 return res 99 } 100 101 func isIdent(expr ast.Expr, ident string) bool { 102 id, ok := expr.(*ast.Ident) 103 return ok && id.Name == ident 104 }