@@ -28,9 +28,37 @@ import (
2828//go:embed templates/*
2929var templateFS embed.FS
3030
31+ // PolicyType represents the type of policy to initialize
32+ type PolicyType string
33+
34+ const (
35+ PolicyTypeRego PolicyType = "rego"
36+ PolicyTypeWasmGo PolicyType = "wasm-go"
37+ PolicyTypeWasmJS PolicyType = "wasm-js"
38+ )
39+
3140const (
32- policyTemplateRegoPath = "templates/example-policy.rego"
33- policyTemplatePath = "templates/example-policy.yaml"
41+ // Rego templates
42+ regoTemplateDir = "templates/rego"
43+ regoPolicyFile = "example-policy.rego"
44+ regoYAMLFile = "example-policy.yaml"
45+
46+ // WASM Go templates
47+ wasmGoTemplateDir = "templates/wasm-go"
48+ wasmGoPolicyFile = "policy.go.tmpl"
49+ wasmGoModFile = "go.mod.tmpl"
50+ wasmGoYAMLFile = "policy.yaml"
51+ wasmGoMakefileFile = "Makefile"
52+
53+ // WASM JS templates
54+ wasmJSTemplateDir = "templates/wasm-js"
55+ wasmJSPolicyFile = "policy.js"
56+ wasmJSPackageFile = "package.json"
57+ wasmJSEsbuildFile = "esbuild.js"
58+ wasmJSDTSFile = "policy.d.ts"
59+ wasmJSYAMLFile = "policy.yaml"
60+
61+ // Defaults
3462 defaultPolicyName = "policy"
3563 defaultPolicyDescription = "Chainloop validation policy"
3664 defaultMaterialKind = "SBOM_CYCLONEDX_JSON"
@@ -45,90 +73,220 @@ type TemplateData struct {
4573 MaterialKind string
4674}
4775
48- type Content struct {
49- YAML string
50- Rego string
51- }
52-
5376type InitOptions struct {
5477 Directory string
78+ PolicyType PolicyType
5579 Embedded bool
5680 Force bool
5781 Name string
5882 Description string
5983}
6084
6185func Initialize (opts * InitOptions ) error {
62- content , err := loadAndProcessTemplates (opts )
86+ // Default to Rego if no type specified
87+ if opts .PolicyType == "" {
88+ opts .PolicyType = PolicyTypeRego
89+ }
90+
91+ // Route to appropriate initializer based on policy type
92+ switch opts .PolicyType {
93+ case PolicyTypeRego :
94+ return initializeRegoPolicy (opts )
95+ case PolicyTypeWasmGo :
96+ return initializeWasmGoPolicy (opts )
97+ case PolicyTypeWasmJS :
98+ return initializeWasmJSPolicy (opts )
99+ default :
100+ return fmt .Errorf ("unsupported policy type: %s" , opts .PolicyType )
101+ }
102+ }
103+
104+ // initializeRegoPolicy creates a Rego-based policy
105+ func initializeRegoPolicy (opts * InitOptions ) error {
106+ // Load templates
107+ regoContent , err := templateFS .ReadFile (filepath .Join (regoTemplateDir , regoPolicyFile ))
63108 if err != nil {
64- return fmt .Errorf ("failed to process templates : %w" , err )
109+ return fmt .Errorf ("failed to read Rego template : %w" , err )
65110 }
66111
112+ yamlContent , err := templateFS .ReadFile (filepath .Join (regoTemplateDir , regoYAMLFile ))
113+ if err != nil {
114+ return fmt .Errorf ("failed to read YAML template: %w" , err )
115+ }
116+
117+ // Prepare template data
118+ data := & TemplateData {
119+ Name : getPolicyName (opts .Name ),
120+ Description : getPolicyDescription (opts .Description ),
121+ RegoPath : sanitizeName (getPolicyName (opts .Name )) + ".rego" ,
122+ RegoContent : string (regoContent ),
123+ Embedded : opts .Embedded ,
124+ MaterialKind : defaultMaterialKind ,
125+ }
126+
127+ // Process YAML template
128+ yamlProcessed , err := executeTemplate (string (yamlContent ), data )
129+ if err != nil {
130+ return fmt .Errorf ("failed to process YAML template: %w" , err )
131+ }
132+
133+ // Prepare files to write
67134 files := make (map [string ]string )
68- fileNameBase := sanitizeName (getPolicyName ( opts .Name ) )
135+ fileNameBase := sanitizeName (data .Name )
69136
70- if opts .Embedded {
71- files [fileNameBase + ".yaml" ] = content .YAML
72- } else {
73- files [fileNameBase + ".yaml" ] = content .YAML
74- files [fileNameBase + ".rego" ] = content .Rego
137+ files [fileNameBase + ".yaml" ] = yamlProcessed
138+ if ! opts .Embedded {
139+ files [fileNameBase + ".rego" ] = data .RegoContent
75140 }
76141
77142 return writeFiles (opts .Directory , files , opts .Force )
78143}
79144
80- func getPolicyName (name string ) string {
81- if name == "" {
82- return defaultPolicyName
145+ // initializeWasmGoPolicy creates a WASM Go-based policy
146+ func initializeWasmGoPolicy (opts * InitOptions ) error {
147+ // Load templates
148+ policyContent , err := templateFS .ReadFile (filepath .Join (wasmGoTemplateDir , wasmGoPolicyFile ))
149+ if err != nil {
150+ return fmt .Errorf ("failed to read Go policy template: %w" , err )
83151 }
84- return name
85- }
86152
87- func getPolicyDescription ( description string ) string {
88- if description == "" {
89- return defaultPolicyDescription
153+ goModContent , err := templateFS . ReadFile ( filepath . Join ( wasmGoTemplateDir , wasmGoModFile ))
154+ if err != nil {
155+ return fmt . Errorf ( "failed to read go.mod template: %w" , err )
90156 }
91- return description
157+
158+ yamlContent , err := templateFS .ReadFile (filepath .Join (wasmGoTemplateDir , wasmGoYAMLFile ))
159+ if err != nil {
160+ return fmt .Errorf ("failed to read YAML template: %w" , err )
161+ }
162+
163+ makefileContent , err := templateFS .ReadFile (filepath .Join (wasmGoTemplateDir , wasmGoMakefileFile ))
164+ if err != nil {
165+ return fmt .Errorf ("failed to read Makefile template: %w" , err )
166+ }
167+
168+ // Prepare template data
169+ data := & TemplateData {
170+ Name : getPolicyName (opts .Name ),
171+ Description : getPolicyDescription (opts .Description ),
172+ MaterialKind : defaultMaterialKind ,
173+ }
174+
175+ // Process templates
176+ policyProcessed , err := executeTemplate (string (policyContent ), data )
177+ if err != nil {
178+ return fmt .Errorf ("failed to process policy template: %w" , err )
179+ }
180+
181+ goModProcessed , err := executeTemplate (string (goModContent ), data )
182+ if err != nil {
183+ return fmt .Errorf ("failed to process go.mod template: %w" , err )
184+ }
185+
186+ yamlProcessed , err := executeTemplate (string (yamlContent ), data )
187+ if err != nil {
188+ return fmt .Errorf ("failed to process YAML template: %w" , err )
189+ }
190+
191+ makefileProcessed , err := executeTemplate (string (makefileContent ), data )
192+ if err != nil {
193+ return fmt .Errorf ("failed to process Makefile template: %w" , err )
194+ }
195+
196+ // Prepare files to write
197+ files := map [string ]string {
198+ "policy.go" : policyProcessed ,
199+ "go.mod" : goModProcessed ,
200+ "policy.yaml" : yamlProcessed ,
201+ "Makefile" : makefileProcessed ,
202+ }
203+
204+ return writeFiles (opts .Directory , files , opts .Force )
92205}
93206
94- func loadAndProcessTemplates (opts * InitOptions ) (* Content , error ) {
95- regoContent , err := templateFS .ReadFile (policyTemplateRegoPath )
207+ // initializeWasmJSPolicy creates a WASM JavaScript-based policy
208+ func initializeWasmJSPolicy (opts * InitOptions ) error {
209+ // Load templates
210+ policyContent , err := templateFS .ReadFile (filepath .Join (wasmJSTemplateDir , wasmJSPolicyFile ))
96211 if err != nil {
97- return nil , fmt .Errorf ("failed to read Rego template: %w" , err )
212+ return fmt .Errorf ("failed to read JS policy template: %w" , err )
98213 }
99214
215+ packageContent , err := templateFS .ReadFile (filepath .Join (wasmJSTemplateDir , wasmJSPackageFile ))
216+ if err != nil {
217+ return fmt .Errorf ("failed to read package.json template: %w" , err )
218+ }
219+
220+ esbuildContent , err := templateFS .ReadFile (filepath .Join (wasmJSTemplateDir , wasmJSEsbuildFile ))
221+ if err != nil {
222+ return fmt .Errorf ("failed to read esbuild.js template: %w" , err )
223+ }
224+
225+ dtsContent , err := templateFS .ReadFile (filepath .Join (wasmJSTemplateDir , wasmJSDTSFile ))
226+ if err != nil {
227+ return fmt .Errorf ("failed to read policy.d.ts template: %w" , err )
228+ }
229+
230+ yamlContent , err := templateFS .ReadFile (filepath .Join (wasmJSTemplateDir , wasmJSYAMLFile ))
231+ if err != nil {
232+ return fmt .Errorf ("failed to read YAML template: %w" , err )
233+ }
234+
235+ // Prepare template data
100236 data := & TemplateData {
101237 Name : getPolicyName (opts .Name ),
102238 Description : getPolicyDescription (opts .Description ),
103- RegoPath : sanitizeName (getPolicyName (opts .Name )) + ".rego" ,
104- RegoContent : string (regoContent ),
105- Embedded : opts .Embedded ,
106239 MaterialKind : defaultMaterialKind ,
107240 }
108241
109- // Process main template
110- content , err := templateFS . ReadFile ( policyTemplatePath )
242+ // Process templates
243+ policyProcessed , err := executeTemplate ( string ( policyContent ), data )
111244 if err != nil {
112- return nil , fmt .Errorf ("failed to read policy template: %w" , err )
245+ return fmt .Errorf ("failed to process policy template: %w" , err )
113246 }
114247
115- yamlContent , err := executeTemplate (string (content ), data )
248+ packageProcessed , err := executeTemplate (string (packageContent ), data )
116249 if err != nil {
117- return nil , fmt .Errorf ("failed to execute template: %w" , err )
250+ return fmt .Errorf ("failed to process package.json template: %w" , err )
118251 }
119252
120- // For non-embedded case, we still need the Rego content to write to file
121- if ! opts .Embedded {
122- return & Content {
123- YAML : yamlContent ,
124- Rego : data .RegoContent ,
125- }, nil
253+ dtsProcessed , err := executeTemplate (string (dtsContent ), data )
254+ if err != nil {
255+ return fmt .Errorf ("failed to process policy.d.ts template: %w" , err )
256+ }
257+
258+ yamlProcessed , err := executeTemplate (string (yamlContent ), data )
259+ if err != nil {
260+ return fmt .Errorf ("failed to process YAML template: %w" , err )
261+ }
262+
263+ // Prepare files to write (esbuild.js doesn't need template processing)
264+ files := map [string ]string {
265+ "policy.js" : policyProcessed ,
266+ "package.json" : packageProcessed ,
267+ "esbuild.js" : string (esbuildContent ),
268+ "policy.d.ts" : dtsProcessed ,
269+ "policy.yaml" : yamlProcessed ,
270+ }
271+
272+ return writeFiles (opts .Directory , files , opts .Force )
273+ }
274+
275+ func getPolicyName (name string ) string {
276+ if name == "" {
277+ return defaultPolicyName
126278 }
279+ return name
280+ }
127281
128- return & Content {YAML : yamlContent }, nil
282+ func getPolicyDescription (description string ) string {
283+ if description == "" {
284+ return defaultPolicyDescription
285+ }
286+ return description
129287}
130288
131- // Add custom template functions
289+ // executeTemplate processes a template with the given data
132290func executeTemplate (content string , data * TemplateData ) (string , error ) {
133291 tmpl := template .New ("policy" ).Funcs (template.FuncMap {
134292 "sanitize" : sanitizeName ,
0 commit comments