-
Notifications
You must be signed in to change notification settings - Fork 876
/
response.go
246 lines (201 loc) · 6.49 KB
/
response.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
package response
import (
"fmt"
"reflect"
"time"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/utils/wildcard"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
// EngineResponse engine response to the action
type EngineResponse struct {
// Resource patched with the engine action changes
PatchedResource unstructured.Unstructured
// Original policy
Policy kyvernov1.PolicyInterface
// Policy Response
PolicyResponse PolicyResponse
}
// PolicyResponse policy application response
type PolicyResponse struct {
// policy details
Policy PolicySpec `json:"policy"`
// resource details
Resource ResourceSpec `json:"resource"`
// policy statistics
PolicyStats `json:",inline"`
// rule response
Rules []RuleResponse `json:"rules"`
// ValidationFailureAction: audit (default) or enforce
ValidationFailureAction kyvernov1.ValidationFailureAction
ValidationFailureActionOverrides []ValidationFailureActionOverride
}
// PolicySpec policy
type PolicySpec struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
}
// ResourceSpec resource action applied on
type ResourceSpec struct {
Kind string `json:"kind"`
APIVersion string `json:"apiVersion"`
Namespace string `json:"namespace"`
Name string `json:"name"`
// UID is not used to build the unique identifier
// optional
UID string `json:"uid"`
}
// GetKey returns the key
func (rs ResourceSpec) GetKey() string {
return rs.Kind + "/" + rs.Namespace + "/" + rs.Name
}
// PolicyStats stores statistics for the single policy application
type PolicyStats struct {
// time required to process the policy rules on a resource
ProcessingTime time.Duration `json:"processingTime"`
// Count of rules that were applied successfully
RulesAppliedCount int `json:"rulesAppliedCount"`
// Count of rules that with execution errors
RulesErrorCount int `json:"rulesErrorCount"`
// Timestamp of the instant the Policy was triggered
PolicyExecutionTimestamp int64 `json:"policyExecutionTimestamp"`
}
type RuleType string
const (
// Mutation type for mutation rule
Mutation RuleType = "Mutation"
// Validation type for validation rule
Validation RuleType = "Validation"
// Generation type for generation rule
Generation RuleType = "Generation"
// ImageVerify type for image verification
ImageVerify RuleType = "ImageVerify"
)
// RuleResponse details for each rule application
type RuleResponse struct {
// rule name specified in policy
Name string `json:"name"`
// rule type (Mutation,Generation,Validation) for Kyverno Policy
Type RuleType `json:"type"`
// message response from the rule application
Message string `json:"message"`
// JSON patches, for mutation rules
Patches [][]byte `json:"patches,omitempty"`
// Resource generated by the generate rules of a policy
GeneratedResource unstructured.Unstructured `json:"generatedResource,omitempty"`
// rule status
Status RuleStatus `json:"status"`
// statistics
RuleStats `json:",inline"`
// PatchedTarget is the patched resource for mutate.targets
PatchedTarget *unstructured.Unstructured
}
// ToString ...
func (rr RuleResponse) ToString() string {
return fmt.Sprintf("rule %s (%s): %v", rr.Name, rr.Type, rr.Message)
}
// RuleStats stores the statistics for the single rule application
type RuleStats struct {
// time required to apply the rule on the resource
ProcessingTime time.Duration `json:"processingTime"`
// Timestamp of the instant the rule got triggered
RuleExecutionTimestamp int64 `json:"ruleExecutionTimestamp"`
}
// IsSuccessful checks if any rule has failed or produced an error during execution
func (er EngineResponse) IsSuccessful() bool {
for _, r := range er.PolicyResponse.Rules {
if r.Status == RuleStatusFail || r.Status == RuleStatusError {
return false
}
}
return true
}
// IsSkipped checks if any rule has skipped resource or not.
func (er EngineResponse) IsSkipped() bool {
for _, r := range er.PolicyResponse.Rules {
if r.Status == RuleStatusSkip {
return true
}
}
return false
}
// IsFailed checks if any rule created a policy violation
func (er EngineResponse) IsFailed() bool {
for _, r := range er.PolicyResponse.Rules {
if r.Status == RuleStatusFail {
return true
}
}
return false
}
// IsError checks if any rule resulted in a processing error
func (er EngineResponse) IsError() bool {
for _, r := range er.PolicyResponse.Rules {
if r.Status == RuleStatusError {
return true
}
}
return false
}
// IsEmpty checks if any rule results are present
func (er EngineResponse) IsEmpty() bool {
return len(er.PolicyResponse.Rules) == 0
}
// isNil checks if rule is an empty rule
func (er EngineResponse) IsNil() bool {
return reflect.DeepEqual(er, EngineResponse{})
}
// GetPatches returns all the patches joined
func (er EngineResponse) GetPatches() [][]byte {
var patches [][]byte
for _, r := range er.PolicyResponse.Rules {
if r.Patches != nil {
patches = append(patches, r.Patches...)
}
}
return patches
}
// GetFailedRules returns failed rules
func (er EngineResponse) GetFailedRules() []string {
return er.getRules(func(status RuleStatus) bool { return status == RuleStatusFail || status == RuleStatusError })
}
// GetSuccessRules returns success rules
func (er EngineResponse) GetSuccessRules() []string {
return er.getRules(func(status RuleStatus) bool { return status == RuleStatusPass })
}
// GetResourceSpec returns resourceSpec of er
func (er EngineResponse) GetResourceSpec() ResourceSpec {
return ResourceSpec{
Kind: er.PatchedResource.GetKind(),
APIVersion: er.PatchedResource.GetAPIVersion(),
Namespace: er.PatchedResource.GetNamespace(),
Name: er.PatchedResource.GetName(),
UID: string(er.PatchedResource.GetUID()),
}
}
func (er EngineResponse) getRules(predicate func(RuleStatus) bool) []string {
var rules []string
for _, r := range er.PolicyResponse.Rules {
if predicate(r.Status) {
rules = append(rules, r.Name)
}
}
return rules
}
func (er *EngineResponse) GetValidationFailureAction() kyvernov1.ValidationFailureAction {
for _, v := range er.PolicyResponse.ValidationFailureActionOverrides {
if v.Action != kyvernov1.Enforce && v.Action != kyvernov1.Audit {
continue
}
for _, ns := range v.Namespaces {
if wildcard.Match(ns, er.PatchedResource.GetNamespace()) {
return v.Action
}
}
}
return er.PolicyResponse.ValidationFailureAction
}
type ValidationFailureActionOverride struct {
Action kyvernov1.ValidationFailureAction `json:"action"`
Namespaces []string `json:"namespaces"`
}