• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kubescape / opa-utils / 13414848544

19 Feb 2025 02:23PM UTC coverage: 69.506% (+0.009%) from 69.497%
13414848544

push

github

web-flow
deprecate control name in posture exception policies (#157)

* deprecate control name in posture exception policies

Signed-off-by: Amir Malka <amirm@armosec.io>

* deprecate control name in posture exception policies

Signed-off-by: Amir Malka <amirm@armosec.io>

---------

Signed-off-by: Amir Malka <amirm@armosec.io>

6 of 9 new or added lines in 2 files covered. (66.67%)

1 existing line in 1 file now uncovered.

3109 of 4473 relevant lines covered (69.51%)

126.47 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

66.92
/exceptions/exceptionprocessor.go
1
package exceptions
2

3
import (
4
        "strings"
5

6
        "github.com/armosec/armoapi-go/identifiers"
7

8
        "github.com/kubescape/k8s-interface/workloadinterface"
9
        "github.com/kubescape/opa-utils/objectsenvelopes"
10
        "github.com/kubescape/opa-utils/reporthandling"
11

12
        "github.com/armosec/armoapi-go/armotypes"
13
)
14

15
// Processor processes exceptions.
16
type Processor struct {
17
        *comparator
18
        designatorCache *designatorCache
19
}
20

21
func NewProcessor() *Processor {
5✔
22
        return &Processor{
5✔
23
                comparator:      newComparator(),
5✔
24
                designatorCache: newDesignatorCache(),
5✔
25
        }
5✔
26
}
5✔
27

28
// SetFrameworkExceptions add exceptions to framework report
29
func (p *Processor) SetFrameworkExceptions(frameworkReport *reporthandling.FrameworkReport, exceptionsPolicies []armotypes.PostureExceptionPolicy, clusterName string) {
×
30
        for c := range frameworkReport.ControlReports {
×
31
                p.SetControlExceptions(&frameworkReport.ControlReports[c], exceptionsPolicies, clusterName, frameworkReport.Name)
×
32
        }
×
33
}
34

35
// SetControlExceptions add exceptions to control report
36
func (p *Processor) SetControlExceptions(controlReport *reporthandling.ControlReport, exceptionsPolicies []armotypes.PostureExceptionPolicy, clusterName, frameworkName string) {
×
37
        for r := range controlReport.RuleReports {
×
NEW
38
                p.SetRuleExceptions(&controlReport.RuleReports[r], exceptionsPolicies, clusterName, frameworkName, controlReport.ControlID)
×
39
        }
×
40
}
41

42
// SetRuleExceptions add exceptions to rule report
NEW
43
func (p *Processor) SetRuleExceptions(ruleReport *reporthandling.RuleReport, exceptionsPolicies []armotypes.PostureExceptionPolicy, clusterName, frameworkName, controlID string) {
×
44
        // adding exceptions to the rules
×
NEW
45
        ruleExceptions := p.ListRuleExceptions(exceptionsPolicies, frameworkName, controlID, ruleReport.Name)
×
46
        p.SetRuleResponsExceptions(ruleReport.RuleResponses, ruleExceptions, clusterName)
×
47
}
×
48

49
// SetRuleExceptions add exceptions to rule respons structure
50
func (p *Processor) SetRuleResponsExceptions(results []reporthandling.RuleResponse, ruleExceptions []armotypes.PostureExceptionPolicy, clusterName string) {
×
51
        if len(ruleExceptions) == 0 {
×
52
                return
×
53
        }
×
54

55
        for i := range results {
×
56
                workloads := alertObjectToWorkloads(&results[i].AlertObject)
×
57
                if len(workloads) == 0 {
×
58
                        continue
×
59
                }
60

61
                for w := range workloads {
×
62
                        if exceptions := p.GetResourceExceptions(ruleExceptions, workloads[w], clusterName); len(exceptions) > 0 {
×
63
                                results[i].Exception = &exceptions[0]
×
64
                        }
×
65
                }
66

67
                results[i].RuleStatus = results[i].GetStatus()
×
68
        }
69
}
70

71
func (p *Processor) ListRuleExceptions(exceptionPolicies []armotypes.PostureExceptionPolicy, frameworkName, controlID, ruleName string) []armotypes.PostureExceptionPolicy {
11✔
72
        ruleExceptions := make([]armotypes.PostureExceptionPolicy, 0, len(exceptionPolicies))
11✔
73

11✔
74
        for i := range exceptionPolicies {
22✔
75
                if p.ruleHasExceptions(&exceptionPolicies[i], frameworkName, controlID, ruleName) {
19✔
76
                        ruleExceptions = append(ruleExceptions, exceptionPolicies[i])
8✔
77
                }
8✔
78
        }
79

80
        return ruleExceptions[:len(ruleExceptions):len(ruleExceptions)]
11✔
81

82
}
83

84
func (p *Processor) ruleHasExceptions(exceptionPolicy *armotypes.PostureExceptionPolicy, frameworkName, controlID, ruleName string) bool {
11✔
85
        if len(exceptionPolicy.PosturePolicies) == 0 {
12✔
86
                return true // empty policy -> apply all
1✔
87
        }
1✔
88

89
        for _, posturePolicy := range exceptionPolicy.PosturePolicies {
20✔
90
                if posturePolicy.FrameworkName == "" && posturePolicy.ControlID == "" && posturePolicy.RuleName == "" {
10✔
91
                        return true // empty policy -> apply all
×
92
                }
×
93
                if posturePolicy.FrameworkName != "" && frameworkName != "" && !(strings.EqualFold(posturePolicy.FrameworkName, frameworkName) || p.regexCompareI(posturePolicy.FrameworkName, frameworkName)) {
12✔
94
                        continue // policy does not match
2✔
95
                }
96
                if posturePolicy.ControlID != "" && controlID != "" && !(strings.EqualFold(posturePolicy.ControlID, controlID) || p.regexCompareI(posturePolicy.ControlID, controlID)) {
8✔
UNCOV
97
                        continue // policy does not match
×
98
                }
99
                if posturePolicy.RuleName != "" && ruleName != "" && !(strings.EqualFold(posturePolicy.RuleName, ruleName) || p.regexCompareI(posturePolicy.RuleName, ruleName)) {
9✔
100
                        continue // policy does not match
1✔
101
                }
102

103
                return true // policies match
7✔
104
        }
105

106
        return false
3✔
107

108
}
109

110
func alertObjectToWorkloads(obj *reporthandling.AlertObject) []workloadinterface.IMetadata {
×
111
        resources := make([]workloadinterface.IMetadata, 0, len(obj.K8SApiObjects)+1)
×
112

×
113
        for i := range obj.K8SApiObjects {
×
114
                r := objectsenvelopes.NewObject(obj.K8SApiObjects[i])
×
115
                if r == nil {
×
116
                        continue
×
117
                }
118

119
                resources = append(resources, r)
×
120
                /*
121
                        ns : = r.GetNamespace()
122
                        if ns != "" {
123
                                // TODO - handle empty namespace
124
                        }
125
                */
126
        }
127

128
        if obj.ExternalObjects != nil {
×
129
                if r := objectsenvelopes.NewObject(obj.ExternalObjects); r != nil {
×
130
                        // TODO - What about linked objects?
×
131
                        resources = append(resources, r)
×
132
                }
×
133
        }
134

135
        return resources[:len(resources):len(resources)]
×
136
}
137

138
// GetResourceException get exceptions of single resource
139
func (p *Processor) GetResourceExceptions(ruleExceptions []armotypes.PostureExceptionPolicy, workload workloadinterface.IMetadata, clusterName string) []armotypes.PostureExceptionPolicy {
9✔
140
        // no pre-allocation since most of the time it's empty or has only one element
9✔
141
        var postureExceptionPolicy []armotypes.PostureExceptionPolicy
9✔
142

9✔
143
        for _, ruleException := range ruleExceptions {
18✔
144
                for _, resourceToPin := range ruleException.Resources {
18✔
145
                        resource := resourceToPin
9✔
146
                        if p.hasException(clusterName, &resource, workload) {
15✔
147
                                postureExceptionPolicy = append(postureExceptionPolicy, ruleException)
6✔
148
                        }
6✔
149
                }
150
        }
151

152
        return postureExceptionPolicy
9✔
153
}
154

155
// compareMetadata - compare namespace and kind
156
func (p *Processor) hasException(clusterName string, designator *identifiers.PortalDesignator, workload workloadinterface.IMetadata) bool {
40✔
157
        var attributes identifiers.AttributesDesignators
40✔
158
        if attrs, ok := p.designatorCache.Get(designator); ok {
54✔
159
                attributes = attrs
14✔
160
        } else {
40✔
161
                attrs := designator.DigestPortalDesignator()
26✔
162
                attributes = attrs
26✔
163
                p.designatorCache.Set(designator, attributes)
26✔
164
        }
26✔
165

166
        if attributes.GetCluster() == "" && attributes.GetNamespace() == "" && attributes.GetKind() == "" && attributes.GetName() == "" && attributes.GetResourceID() == "" && attributes.GetPath() == "" && len(attributes.GetLabels()) == 0 {
41✔
167
                return false // if designators are empty
1✔
168
        }
1✔
169

170
        if attributes.GetCluster() != "" && !p.compareCluster(attributes.GetCluster(), clusterName) { // TODO - where do we receive cluster name from?
40✔
171
                return false // cluster name does not match
1✔
172
        }
1✔
173

174
        if isTypeRegoResponseVector(workload) {
43✔
175
                if p.iterateRegoResponseVector(workload, attributes) {
6✔
176
                        return true
1✔
177
                }
1✔
178
                // otherwise, continue to check the base object
179
        }
180
        return p.metadataHasException(workload, attributes)
37✔
181

182
}
183

184
func (p *Processor) metadataHasException(workload workloadinterface.IMetadata, attributes identifiers.AttributesDesignators) bool {
56✔
185

56✔
186
        if attributes.GetNamespace() != "" && !p.compareNamespace(workload, attributes.GetNamespace()) {
57✔
187
                return false // namespaces do not match
1✔
188
        }
1✔
189

190
        if attributes.GetKind() != "" && !p.compareKind(workload, attributes.GetKind()) {
61✔
191
                return false // kinds do not match
6✔
192
        }
6✔
193

194
        if attributes.GetName() != "" && !p.compareName(workload, attributes.GetName()) {
55✔
195
                return false // names do not match
6✔
196
        }
6✔
197

198
        if attributes.GetResourceID() != "" && !p.compareResourceID(workload, attributes.GetResourceID()) {
44✔
199
                return false // names do not match
1✔
200
        }
1✔
201

202
        if attributes.GetPath() != "" && !p.comparePath(workload, attributes.GetPath()) {
43✔
203
                return false // paths do not match
1✔
204
        }
1✔
205

206
        if isTypeWorkload(workload) && len(attributes.GetLabels()) > 0 {
68✔
207
                if !p.compareLabels(workload, attributes.GetLabels()) && !p.compareAnnotations(workload, attributes.GetLabels()) {
41✔
208
                        return false // labels nor annotations do not match
14✔
209
                }
14✔
210
        }
211
        return true
27✔
212
}
213

214
func (p *Processor) iterateRegoResponseVector(workload workloadinterface.IMetadata, attributes identifiers.AttributesDesignators) bool {
11✔
215
        v := objectsenvelopes.NewRegoResponseVectorObject(workload.GetObject())
11✔
216
        for _, r := range v.GetRelatedObjects() {
30✔
217
                if p.metadataHasException(r, attributes) {
24✔
218
                        return true
5✔
219
                }
5✔
220
        }
221
        return false
6✔
222
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc