vitess.io/vitess@v0.16.2/go/vt/vtadmin/testutil/authztestgen/main.go (about) 1 /* 2 Copyright 2022 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "io" 23 "os" 24 "text/template" 25 26 "github.com/spf13/pflag" 27 28 "vitess.io/vitess/go/vt/vtadmin/rbac" 29 30 vtadminpb "vitess.io/vitess/go/vt/proto/vtadmin" 31 ) 32 33 type Config struct { 34 Package string `json:"package"` 35 Clusters []*ClusterConfig `json:"clusters"` 36 Tests []*Test `json:"tests"` 37 } 38 39 type ClusterConfig struct { 40 ID string `json:"id"` 41 Name string `json:"name"` 42 FakeVtctldClientResults []*FakeVtctldClientResult `json:"vtctldclient_mock_data"` 43 DBTablets []*vtadminpb.Tablet `json:"db_tablet_list"` 44 } 45 46 type Test struct { 47 Method string `json:"method"` 48 Rules []*AuthzRules `json:"rules"` 49 Request string `json:"request"` 50 SerializeCases bool `json:"serialize_cases"` 51 Cases []*TestCase `json:"cases"` 52 } 53 54 type TestCase struct { 55 Name string `json:"name"` 56 Actor *rbac.Actor `json:"actor"` 57 IsPermitted bool `json:"is_permitted"` 58 IncludeErrorVar bool `json:"include_error_var"` 59 Assertions []string `json:"assertions"` 60 } 61 62 type AuthzRules struct { 63 Resource string `json:"resource"` 64 Actions []string `json:"actions"` 65 Subjects []string `json:"subjects"` 66 Clusters []string `json:"clusters"` 67 } 68 69 type FakeVtctldClientResult struct { 70 FieldName string `json:"field"` 71 Type string `json:"type"` 72 Value string `json:"value"` 73 } 74 75 type DocConfig struct { 76 Methods []*DocMethod 77 } 78 79 type DocMethod struct { 80 Name string 81 Rules []*struct { 82 Resource rbac.Resource 83 Action rbac.Action 84 } 85 } 86 87 func transformConfigForDocs(in Config) DocConfig { 88 cfg := DocConfig{} 89 90 for _, t := range in.Tests { 91 m := &DocMethod{ 92 Name: t.Method, 93 } 94 95 resourceActions := map[string]struct{}{} 96 for _, r := range t.Rules { 97 for _, a := range r.Actions { 98 k := fmt.Sprintf("%s.%s", r.Resource, a) 99 if _, ok := resourceActions[k]; ok { 100 continue 101 } 102 103 resourceActions[k] = struct{}{} 104 105 m.Rules = append(m.Rules, &struct { 106 Resource rbac.Resource 107 Action rbac.Action 108 }{ 109 Resource: rbac.Resource(r.Resource), 110 Action: rbac.Action(a), 111 }) 112 } 113 } 114 115 cfg.Methods = append(cfg.Methods, m) 116 } 117 118 return cfg 119 } 120 121 func panicIf(err error) { 122 if err != nil { 123 panic(err) 124 } 125 } 126 127 func open(path string) (output io.Writer, closer func()) { 128 output = os.Stdout 129 closer = func() {} 130 131 if path != "" { 132 f, err := os.Create(path) 133 panicIf(err) 134 135 closer = func() { f.Close() } 136 output = f 137 } 138 139 return output, closer 140 } 141 142 func main() { 143 path := pflag.StringP("config", "c", "config.json", "authztest configuration (see the Config type in this package for the spec)") 144 pflag.StringVarP(path, "config-path", "p", "config.json", "alias for --config") 145 outputPath := pflag.StringP("output", "o", "", "destination to write generated code. if empty, defaults to os.Stdout") 146 docgen := pflag.Bool("docgen", false, "generate docs table from authztest config instead of authz tests themselves") 147 148 pflag.Parse() 149 150 data, err := os.ReadFile(*path) 151 panicIf(err) 152 153 var cfg Config 154 err = json.Unmarshal(data, &cfg) 155 panicIf(err) 156 157 if *docgen { 158 cfg := transformConfigForDocs(cfg) 159 tmpl, err := template.New("docs").Funcs(map[string]any{ 160 "formatDocRow": formatDocRow, 161 }).Parse(_doct) 162 panicIf(err) 163 164 output, closer := open(*outputPath) 165 defer closer() 166 167 err = tmpl.Execute(output, &cfg) 168 panicIf(err) 169 170 return 171 } 172 173 tmpl, err := template.New("tests").Funcs(map[string]any{ 174 "getActor": getActor, 175 "writeAssertion": writeAssertion, 176 }).Parse(_t) 177 panicIf(err) 178 179 output, closer := open(*outputPath) 180 defer closer() 181 182 err = tmpl.Execute(output, &cfg) 183 panicIf(err) 184 }