@@ -28,6 +28,7 @@ import (
2828 "github.com/bufbuild/protoyaml-go"
2929 v1 "github.com/chainloop-dev/chainloop/app/controlplane/api/workflowcontract/v1"
3030 "github.com/chainloop-dev/chainloop/app/controlplane/pkg/unmarshal"
31+ "github.com/chainloop-dev/chainloop/pkg/resourceloader"
3132 "github.com/open-policy-agent/opa/v1/format"
3233 "github.com/styrainc/regal/pkg/config"
3334 "github.com/styrainc/regal/pkg/linter"
@@ -79,30 +80,37 @@ func (p *PolicyToLint) AddError(path, message string, line int) {
7980 })
8081}
8182
82- // Read policy files from the given directory or file
83+ // Read policy files
8384func Lookup (absPath , config string , format bool ) (* PolicyToLint , error ) {
84- fileInfo , err := os .Stat (absPath )
85+ resolvedPath , err := resourceloader .GetPathForResource (absPath )
86+ if err != nil {
87+ return nil , fmt .Errorf ("failed to resolve policy file: %w" , err )
88+ }
89+
90+ fileInfo , err := os .Stat (resolvedPath )
8591 if err != nil {
8692 if os .IsNotExist (err ) {
87- return nil , fmt .Errorf ("path does not exist: %s" , absPath )
93+ return nil , fmt .Errorf ("policy file does not exist: %s" , resolvedPath )
8894 }
89- return nil , fmt .Errorf ("failed to stat path %q: %w" , absPath , err )
95+ return nil , fmt .Errorf ("failed to stat file %q: %w" , resolvedPath , err )
96+ }
97+ if fileInfo .IsDir () {
98+ return nil , fmt .Errorf ("expected a file but got a directory: %s" , resolvedPath )
9099 }
91100
92101 policy := & PolicyToLint {
93- Path : absPath ,
102+ Path : resolvedPath ,
94103 Format : format ,
95104 Config : config ,
96105 }
97106
98- if fileInfo .IsDir () {
99- if err := scanDirectory (policy , absPath ); err != nil {
100- return nil , err
101- }
102- } else {
103- if err := processFile (policy , absPath ); err != nil {
104- return nil , err
105- }
107+ if err := policy .processFile (resolvedPath ); err != nil {
108+ return nil , err
109+ }
110+
111+ // Load referenced rego files from all YAML files
112+ if err := policy .loadReferencedRegoFiles (filepath .Dir (resolvedPath )); err != nil {
113+ return nil , err
106114 }
107115
108116 // Verify we found at least one valid file
@@ -113,35 +121,42 @@ func Lookup(absPath, config string, format bool) (*PolicyToLint, error) {
113121 return policy , nil
114122}
115123
116- // Performs a one-level directory lookup to find .yaml/.yml or .rego files.
117- func scanDirectory (policy * PolicyToLint , dirPath string ) error {
118- files , err := os .ReadDir (dirPath )
119- if err != nil {
120- return fmt .Errorf ("reading directory: %w" , err )
121- }
122-
123- var foundValidFile bool
124- for _ , file := range files {
125- if file .IsDir () {
124+ // Loads referenced rego files from all YAML files in the policy
125+ // Loads referenced rego files from all YAML files in the policy
126+ func (p * PolicyToLint ) loadReferencedRegoFiles (baseDir string ) error {
127+ seen := make (map [string ]struct {})
128+ for _ , yamlFile := range p .YAMLFiles {
129+ var parsed v1.Policy
130+ if err := unmarshal .FromRaw (yamlFile .Content , unmarshal .RawFormatYAML , & parsed , true ); err != nil {
131+ // Ignore parse errors here; they'll be caught in validation
126132 continue
127133 }
128-
129- filePath := filepath .Join (dirPath , file .Name ())
130- if err := processFile (policy , filePath ); err != nil {
131- // Skip unsupported files but continue processing others
132- continue
134+ for _ , spec := range parsed .Spec .Policies {
135+ regoPath := spec .GetPath ()
136+ if regoPath != "" {
137+ // If path is relative, make it relative to the YAML file's directory
138+ if ! filepath .IsAbs (regoPath ) {
139+ regoPath = filepath .Join (baseDir , regoPath )
140+ }
141+
142+ resolvedPath , err := resourceloader .GetPathForResource (regoPath )
143+ if err != nil {
144+ return fmt .Errorf ("failed to resolve rego file %q: %w" , regoPath , err )
145+ }
146+ if _ , ok := seen [resolvedPath ]; ok {
147+ continue // avoid duplicates
148+ }
149+ seen [resolvedPath ] = struct {}{}
150+ if err := p .processFile (resolvedPath ); err != nil {
151+ return fmt .Errorf ("failed to load referenced rego file %q: %w" , resolvedPath , err )
152+ }
153+ }
133154 }
134- foundValidFile = true
135155 }
136-
137- if ! foundValidFile {
138- return fmt .Errorf ("no valid .yaml/.yml or .rego files found in directory" )
139- }
140-
141156 return nil
142157}
143158
144- func processFile ( policy * PolicyToLint , filePath string ) error {
159+ func ( p * PolicyToLint ) processFile ( filePath string ) error {
145160 content , err := os .ReadFile (filePath )
146161 if err != nil {
147162 return fmt .Errorf ("reading %s: %w" , filepath .Base (filePath ), err )
@@ -150,12 +165,12 @@ func processFile(policy *PolicyToLint, filePath string) error {
150165 ext := strings .ToLower (filepath .Ext (filePath ))
151166 switch ext {
152167 case ".yaml" , ".yml" :
153- policy .YAMLFiles = append (policy .YAMLFiles , & File {
168+ p .YAMLFiles = append (p .YAMLFiles , & File {
154169 Path : filePath ,
155170 Content : content ,
156171 })
157172 case ".rego" :
158- policy .RegoFiles = append (policy .RegoFiles , & File {
173+ p .RegoFiles = append (p .RegoFiles , & File {
159174 Path : filePath ,
160175 Content : content ,
161176 })
0 commit comments