@@ -14,6 +14,8 @@ import (
1414 "strings"
1515 "testing"
1616
17+ minderv1 "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1"
18+ "github.com/mindersec/minder/pkg/fileconvert"
1719 "go.starlark.net/starlark"
1820 "go.starlark.net/starlarktest"
1921 "go.starlark.net/syntax"
@@ -26,23 +28,25 @@ type testCaseRunner struct {
2628 fs fs.FS
2729 predeclared starlark.StringDict
2830 failures []string
31+ ruleTypes map [string ]* minderv1.RuleType
2932}
3033
31- func (r * Runner ) newTestCaseRunner (name string , fileSystem fs.FS ) * testCaseRunner {
34+ func (r * Runner ) newTestCaseRunner (name string , fileSystem fs.FS , ruleTypes map [ string ] * minderv1. RuleType ) * testCaseRunner {
3235 if fileSystem == nil {
3336 panic ("fileSystem cannot be nil" )
3437 }
3538 tr := & testCaseRunner {
3639 fs : fileSystem ,
3740 predeclared : starlark.StringDict {},
41+ ruleTypes : ruleTypes ,
3842 }
3943 tr .thread = & starlark.Thread {
4044 Name : name ,
4145 Print : func (_ * starlark.Thread , msg string ) { fmt .Println (msg ) },
4246 }
4347 starlarktest .SetReporter (tr .thread , tr )
4448
45- tr .predeclared ["eval" ] = starlark .NewBuiltin ("eval" , builtinEval )
49+ tr .predeclared ["eval" ] = starlark .NewBuiltin ("eval" , tr . builtinEval )
4650 tr .predeclared ["read_file" ] = starlark .NewBuiltin ("read_file" , tr .builtinReadFile )
4751 tr .predeclared ["txtar" ] = starlark .NewBuiltin ("txtar" , builtinTxtar )
4852 tr .predeclared ["body" ] = starlark .NewBuiltin ("body" , builtinBody )
@@ -90,10 +94,13 @@ func NewRunner() *Runner {
9094 }
9195}
9296
93- // RunFile executes a single Starlark test file and returns the results
94- // for each test_* function found in it.
95- // src may be nil, or a string, []byte, or io.Reader containing the file source.
97+ // RunFile executes a single Starlark test file. If src is non-nil, it is
98+ // used as the file contents.
9699func (r * Runner ) RunFile (filename string , src any ) ([]TestResult , error ) {
100+ return r .runFileWithRules (filename , src , nil )
101+ }
102+
103+ func (r * Runner ) runFileWithRules (filename string , src any , ruleTypes map [string ]* minderv1.RuleType ) ([]TestResult , error ) {
97104 if filename == "" {
98105 return nil , errors .New ("filename cannot be empty" )
99106 }
@@ -102,11 +109,11 @@ func (r *Runner) RunFile(filename string, src any) ([]TestResult, error) {
102109 fileSystem := os .DirFS (baseDir )
103110
104111 name := filepath .Base (filename )
105- tr := r .newTestCaseRunner (name , fileSystem )
112+ tr := r .newTestCaseRunner (name , fileSystem , ruleTypes )
106113
107114 globals , err := tr .runFile (filename , src )
108115 if err != nil {
109- if evalErr , ok := errors. AsType [ * starlark.EvalError ]( err ); ok {
116+ if evalErr , ok := err .( * starlark.EvalError ); ok {
110117 return nil , fmt .Errorf ("loading %s: %w\n %s" , filename , err , evalErr .Backtrace ())
111118 }
112119 return nil , fmt .Errorf ("loading %s: %w" , filename , err )
@@ -129,15 +136,15 @@ func (r *Runner) RunFile(filename string, src any) ([]TestResult, error) {
129136
130137 var results []TestResult
131138 for name , fn := range testFns {
132- result := r .runOneTest (name , fn , fileSystem )
139+ result := r .runOneTest (name , fn , fileSystem , ruleTypes )
133140 results = append (results , result )
134141 }
135142
136143 return results , nil
137144}
138145
139- func (r * Runner ) runOneTest (name string , fn * starlark.Function , fileSystem fs.FS ) TestResult {
140- tr := r .newTestCaseRunner (name , fileSystem )
146+ func (r * Runner ) runOneTest (name string , fn * starlark.Function , fileSystem fs.FS , ruleTypes map [ string ] * minderv1. RuleType ) TestResult {
147+ tr := r .newTestCaseRunner (name , fileSystem , ruleTypes )
141148 result := TestResult {Name : name }
142149
143150 _ , err := starlark .Call (tr .thread , fn , nil , nil )
@@ -174,11 +181,63 @@ func DiscoverFiles(root string) ([]string, error) {
174181 return files , nil
175182}
176183
184+ // loadRulesFromDir finds and parses all *.yaml files in the given directory
185+ // into a map of RuleTypes keyed by rule name.
186+ func loadRulesFromDir (dir string ) (map [string ]* minderv1.RuleType , error ) {
187+ ruleTypes := make (map [string ]* minderv1.RuleType )
188+ yamlFiles , err := filepath .Glob (filepath .Join (dir , "*.yaml" ))
189+ if err != nil {
190+ return nil , fmt .Errorf ("globbing yaml files: %w" , err )
191+ }
192+ for _ , yf := range yamlFiles {
193+ decoder , closer := fileconvert .DecoderForFile (yf )
194+ if decoder == nil {
195+ return nil , fmt .Errorf ("error opening file: %s" , yf )
196+ }
197+ rt , err := fileconvert.ReadResourceTyped [* minderv1.RuleType ](decoder )
198+ closer .Close ()
199+ if err == nil && rt != nil && rt .Name != "" {
200+ ruleTypes [rt .Name ] = rt
201+ }
202+ }
203+ return ruleTypes , nil
204+ }
205+
177206// RunDir discovers and executes all *.star test files under the given
178- // directory, reporting results through t.
179- func (r * Runner ) RunDir (t * testing.T , dir string ) {
207+ // directory. It also discovers and loads any *.yaml rule files in the directory.
208+ func (r * Runner ) RunDir (dir string ) ([]TestResult , error ) {
209+ ruleTypes , err := loadRulesFromDir (dir )
210+ if err != nil {
211+ return nil , fmt .Errorf ("loading rules: %w" , err )
212+ }
213+
214+ files , err := DiscoverFiles (dir )
215+ if err != nil {
216+ return nil , fmt .Errorf ("discovering test files: %w" , err )
217+ }
218+
219+ var allResults []TestResult
220+ for _ , file := range files {
221+ results , err := r .runFileWithRules (file , nil , ruleTypes )
222+ if err != nil {
223+ return nil , err
224+ }
225+ allResults = append (allResults , results ... )
226+ }
227+
228+ return allResults , nil
229+ }
230+
231+ // TestDir discovers and executes all *.star test files under the given
232+ // directory, reporting results through t. It also loads *.yaml rules.
233+ func (r * Runner ) TestDir (t * testing.T , dir string ) {
180234 t .Helper ()
181235
236+ ruleTypes , err := loadRulesFromDir (dir )
237+ if err != nil {
238+ t .Fatalf ("loading rules: %v" , err )
239+ }
240+
182241 files , err := DiscoverFiles (dir )
183242 if err != nil {
184243 t .Fatalf ("discovering test files: %v" , err )
@@ -196,7 +255,7 @@ func (r *Runner) RunDir(t *testing.T, dir string) {
196255 }
197256
198257 t .Run (rel , func (t * testing.T ) {
199- results , err := r .RunFile (file , nil )
258+ results , err := r .runFileWithRules (file , nil , ruleTypes )
200259 if err != nil {
201260 t .Fatalf ("running %s: %v" , file , err )
202261 }
0 commit comments