1
1
package commands
2
2
3
3
import (
4
+ "bytes"
4
5
"encoding/json"
5
6
"fmt"
6
7
"os"
7
8
"path/filepath"
9
+ "text/template"
8
10
9
11
"github.com/plexsystems/konstraint/internal/rego"
10
12
13
+ "github.com/Masterminds/sprig/v3"
11
14
v1 "github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1"
12
15
"github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1beta1"
13
16
log "github.com/sirupsen/logrus"
@@ -50,10 +53,21 @@ Create constraints with the Gatekeeper enforcement action set to dryrun
50
53
if err := viper .BindPFlag ("constraint-template-version" , cmd .PersistentFlags ().Lookup ("constraint-template-version" )); err != nil {
51
54
return fmt .Errorf ("bind constraint-template-version flag: %w" , err )
52
55
}
56
+ if err := viper .BindPFlag ("constraint-template-custom-template-file" , cmd .PersistentFlags ().Lookup ("constraint-template-custom-template-file" )); err != nil {
57
+ return fmt .Errorf ("bind constraint-template-custom-template-file flag: %w" , err )
58
+ }
59
+ if err := viper .BindPFlag ("constraint-custom-template-file" , cmd .PersistentFlags ().Lookup ("constraint-custom-template-file" )); err != nil {
60
+ return fmt .Errorf ("bind constraint-custom-template-file flag: %w" , err )
61
+ }
62
+
53
63
if err := viper .BindPFlag ("partial-constraints" , cmd .PersistentFlags ().Lookup ("partial-constraints" )); err != nil {
54
64
return fmt .Errorf ("bind partial-constraints flag: %w" , err )
55
65
}
56
66
67
+ if cmd .PersistentFlags ().Lookup ("constraint-template-custom-template-file" ).Changed && cmd .PersistentFlags ().Lookup ("constraint-template-version" ).Changed {
68
+ return fmt .Errorf ("need to set either constraint-template-custom-template-file or constraint-template-version" )
69
+ }
70
+
57
71
path := "."
58
72
if len (args ) > 0 {
59
73
path = args [0 ]
@@ -68,6 +82,8 @@ Create constraints with the Gatekeeper enforcement action set to dryrun
68
82
cmd .PersistentFlags ().Bool ("skip-constraints" , false , "Skip generation of constraints" )
69
83
cmd .PersistentFlags ().String ("constraint-template-version" , "v1beta1" , "Set the version of ConstraintTemplates" )
70
84
cmd .PersistentFlags ().Bool ("partial-constraints" , false , "Generate partial Constraints for policies with parameters" )
85
+ cmd .PersistentFlags ().String ("constraint-template-custom-template-file" , "" , "Path to a custom template file to generate constraint templates" )
86
+ cmd .PersistentFlags ().String ("constraint-custom-template-file" , "" , "Path to a custom template file to generate constraints" )
71
87
72
88
return & cmd
73
89
}
@@ -107,21 +123,36 @@ func runCreateCommand(path string) error {
107
123
}
108
124
109
125
constraintTemplateVersion := viper .GetString ("constraint-template-version" )
126
+ constraintTemplateCustomTemplateFile := viper .GetString ("constraint-template-custom-template-file" )
127
+
110
128
var constraintTemplate any
111
- switch constraintTemplateVersion {
112
- case "v1" :
113
- constraintTemplate = getConstraintTemplatev1 (violation , logger )
114
- case "v1beta1" :
115
- constraintTemplate = getConstraintTemplatev1beta1 (violation , logger )
116
- default :
117
- return fmt .Errorf ("unsupported API version for constrainttemplate: %s" , constraintTemplateVersion )
118
- }
129
+ var constraintTemplateBytes []byte
119
130
120
- constraintTemplateBytes , err := yaml .Marshal (constraintTemplate )
121
- if err != nil {
122
- return fmt .Errorf ("marshal constrainttemplate: %w" , err )
123
- }
131
+ if constraintTemplateCustomTemplateFile != "" {
132
+ customTemplate , err := os .ReadFile (constraintTemplateCustomTemplateFile )
133
+ if err != nil {
134
+ return fmt .Errorf ("unable to open/read template file: %w" , err )
135
+ }
136
+ constraintTemplateBytes , err = renderTemplate (violation , customTemplate , logger )
137
+ if err != nil {
138
+ return fmt .Errorf ("unable to render custom template: %w" , err )
139
+ }
140
+ } else {
141
+ switch constraintTemplateVersion {
142
+ case "v1" :
143
+ constraintTemplate = getConstraintTemplatev1 (violation , logger )
144
+ case "v1beta1" :
145
+ constraintTemplate = getConstraintTemplatev1beta1 (violation , logger )
146
+ default :
147
+ return fmt .Errorf ("unsupported API version for constrainttemplate: %s" , constraintTemplateVersion )
148
+ }
149
+ constraintTemplateBytes , err = yaml .Marshal (constraintTemplate )
124
150
151
+ if err != nil {
152
+ return fmt .Errorf ("marshal constrainttemplate: %w" , err )
153
+ }
154
+
155
+ }
125
156
if err := os .WriteFile (filepath .Join (outputDir , templateFileName ), constraintTemplateBytes , 0644 ); err != nil {
126
157
return fmt .Errorf ("writing template: %w" , err )
127
158
}
@@ -137,16 +168,28 @@ func runCreateCommand(path string) error {
137
168
continue
138
169
}
139
170
140
- constraint , err := getConstraint (violation , logger )
141
- if err != nil {
142
- return fmt .Errorf ("get constraint: %w" , err )
143
- }
171
+ constraintCustomTemplateFile := viper .GetString ("constraint-custom-template-file" )
172
+ var constraintBytes []byte
173
+ if constraintCustomTemplateFile != "" {
174
+ customTemplate , err := os .ReadFile (constraintCustomTemplateFile )
175
+ if err != nil {
176
+ return fmt .Errorf ("unable to open/read template file: %w" , err )
177
+ }
178
+ constraintBytes , err = renderTemplate (violation , customTemplate , logger )
179
+ if err != nil {
180
+ return fmt .Errorf ("unable to render custom constraint: %w" , err )
181
+ }
182
+ } else {
183
+ constraint , err := getConstraint (violation , logger )
184
+ if err != nil {
185
+ return fmt .Errorf ("get constraint: %w" , err )
186
+ }
144
187
145
- constraintBytes , err := yaml .Marshal (constraint )
146
- if err != nil {
147
- return fmt .Errorf ("marshal constraint: %w" , err )
188
+ constraintBytes , err = yaml .Marshal (constraint )
189
+ if err != nil {
190
+ return fmt .Errorf ("marshal constraint: %w" , err )
191
+ }
148
192
}
149
-
150
193
if err := os .WriteFile (filepath .Join (outputDir , constraintFileName ), constraintBytes , 0644 ); err != nil {
151
194
return fmt .Errorf ("writing constraint: %w" , err )
152
195
}
@@ -157,6 +200,20 @@ func runCreateCommand(path string) error {
157
200
return nil
158
201
}
159
202
203
+ func renderTemplate (violation rego.Rego , appliedTemplate []byte , _ * log.Entry ) ([]byte , error ) {
204
+ t , err := template .New ("template" ).Funcs (sprig .FuncMap ()).Parse (string (appliedTemplate ))
205
+ if err != nil {
206
+ return nil , fmt .Errorf ("parsing template: %w" , err )
207
+ }
208
+ buf := new (bytes.Buffer )
209
+
210
+ if err := t .Execute (buf , violation ); err != nil {
211
+ return nil , fmt .Errorf ("executing template: %w" , err )
212
+ }
213
+
214
+ return buf .Bytes (), nil
215
+ }
216
+
160
217
func getConstraintTemplatev1 (violation rego.Rego , logger * log.Entry ) * v1.ConstraintTemplate {
161
218
constraintTemplate := v1.ConstraintTemplate {
162
219
TypeMeta : metav1.TypeMeta {
0 commit comments