Skip to content

Commit 7a32c94

Browse files
committed
Simplify threshold calculation
1 parent 04fe074 commit 7a32c94

File tree

3 files changed

+62
-53
lines changed

3 files changed

+62
-53
lines changed

main.go

+12-3
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,8 @@ type scanDeduplicatorValidator struct {
2727
}
2828

2929
func (v *scanDeduplicatorValidator) Validate(_ context.Context, _ *kwhmodel.AdmissionReview, obj metav1.Object) (*kwhvalidating.ValidatorResult, error) {
30-
scan, ok := obj.(*executionv1.Scan)
31-
3230
v.logger.Infof("Validating Scan.")
31+
scan, ok := obj.(*executionv1.Scan)
3332

3433
if !ok {
3534
return nil, fmt.Errorf("not an scan")
@@ -56,7 +55,17 @@ func (v *scanDeduplicatorValidator) Validate(_ context.Context, _ *kwhmodel.Admi
5655

5756
if lastExecution, ok := recentHashes[hash]; ok {
5857
now := time.Now()
59-
threshhold := thresholds.GetThreshholdForScan(*scan)
58+
threshhold, err := thresholds.GetThreshholdForScan(*scan)
59+
60+
if err != nil {
61+
v.logger.Errorf("Failed to get threshold for scan!", err)
62+
return &kwhvalidating.ValidatorResult{
63+
Valid: true,
64+
Message: fmt.Sprintf("Failed to check for duplicated scan. Failed to get threshold: %s", err),
65+
Warnings: []string{"Failed to get threshold.", "Deduplication wasn't performed."},
66+
}, err
67+
}
68+
6069
if lastExecution.Before(now.Add(-threshhold)) {
6170
v.logger.Infof("Scan was executed before (%v ago), but it was longer than %v. Starting it normally.", now.Sub(lastExecution), threshhold)
6271
recentHashes[hash] = now

thresholds/thesholds_test.go

+37-11
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,55 @@ import (
1010
)
1111

1212
func TestGetThreshholdForScan(t *testing.T) {
13-
t.Run("returns zero threshold for scans without matching labels", func(t *testing.T) {
13+
t.Run("returns zero threshold for scans without deduplication annotation", func(t *testing.T) {
1414
scan := executionv1.Scan{
1515
ObjectMeta: metav1.ObjectMeta{
16-
Labels: map[string]string{
17-
"foo": "bar",
16+
Annotations: map[string]string{
17+
"irrelevant annotation": "...",
1818
},
1919
},
2020
}
21-
threshold := GetThreshholdForScan(scan)
21+
threshold, err := GetThreshholdForScan(scan)
22+
assert.Nil(t, err)
2223
assert.Equal(t, 0*time.Second, threshold)
2324
})
2425

25-
t.Run("returns matchign thresholds for scnas with matching rules threshold for scans without matching labels", func(t *testing.T) {
26+
t.Run("returns parsed threshold for scans with matching annotation", func(t *testing.T) {
2627
scan := executionv1.Scan{
2728
ObjectMeta: metav1.ObjectMeta{
28-
Labels: map[string]string{
29-
"securecodebox.io/hook": "cascading-scans",
30-
"cascading.securecodebox.io/cascading-rule": "nmap-portscan",
31-
"foo": "bar",
29+
Annotations: map[string]string{
30+
"scan-deduplicator.securecodebox.io/min-time-interval": "24h",
3231
},
3332
},
3433
}
35-
threshold := GetThreshholdForScan(scan)
36-
assert.Equal(t, 4*time.Hour, threshold)
34+
threshold, err := GetThreshholdForScan(scan)
35+
assert.Nil(t, err)
36+
assert.Equal(t, 24*time.Hour, threshold)
37+
})
38+
39+
t.Run("returns an error if the threshold is wrongly formatted", func(t *testing.T) {
40+
scan := executionv1.Scan{
41+
ObjectMeta: metav1.ObjectMeta{
42+
Annotations: map[string]string{
43+
"scan-deduplicator.securecodebox.io/min-time-interval": "invalid-time-format",
44+
},
45+
},
46+
}
47+
threshold, err := GetThreshholdForScan(scan)
48+
assert.EqualError(t, err, "error parsing duration: time: invalid duration \"invalid-time-format\"")
49+
assert.Equal(t, 0*time.Second, threshold)
50+
})
51+
52+
t.Run("returns an error if the threshold is negative", func(t *testing.T) {
53+
scan := executionv1.Scan{
54+
ObjectMeta: metav1.ObjectMeta{
55+
Annotations: map[string]string{
56+
"scan-deduplicator.securecodebox.io/min-time-interval": "-24h",
57+
},
58+
},
59+
}
60+
threshold, err := GetThreshholdForScan(scan)
61+
assert.EqualError(t, err, "threshold must be a positive duration")
62+
assert.Equal(t, 0*time.Second, threshold)
3763
})
3864
}

thresholds/thresholds.go

+13-39
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,26 @@
11
package thresholds
22

33
import (
4-
"math"
4+
"fmt"
55
"time"
66

77
executionv1 "github.com/secureCodeBox/secureCodeBox/operator/apis/execution/v1"
88
)
99

10-
type ThreshholdRule struct {
11-
MatchLabels map[string]string
12-
Threshold time.Duration
13-
}
14-
15-
var rules []ThreshholdRule = []ThreshholdRule{
16-
// default fallback, no limitation
17-
{
18-
MatchLabels: map[string]string{},
19-
Threshold: 0 * time.Second,
20-
},
21-
{
22-
MatchLabels: map[string]string{
23-
"securecodebox.io/hook": "cascading-scans",
24-
"cascading.securecodebox.io/cascading-rule": "nmap-portscan",
25-
},
26-
Threshold: 4 * time.Hour,
27-
},
28-
}
29-
30-
func GetThreshholdForScan(scan executionv1.Scan) time.Duration {
31-
highestMatchingThreshold := time.Duration(math.MinInt64)
32-
for _, rule := range rules {
33-
if isMapSubset(scan.Labels, rule.MatchLabels) {
34-
if highestMatchingThreshold < rule.Threshold {
35-
highestMatchingThreshold = rule.Threshold
36-
}
37-
}
10+
func GetThreshholdForScan(scan executionv1.Scan) (time.Duration, error) {
11+
thresholdStr, ok := scan.Annotations["scan-deduplicator.securecodebox.io/min-time-interval"]
12+
if !ok {
13+
return 0 * time.Second, nil
3814
}
39-
return highestMatchingThreshold
40-
}
4115

42-
func isMapSubset[K, V comparable](m, sub map[K]V) bool {
43-
if len(sub) > len(m) {
44-
return false
16+
threshold, err := time.ParseDuration(thresholdStr)
17+
if err != nil {
18+
return 0, fmt.Errorf("error parsing duration: %w", err)
4519
}
46-
for k, vsub := range sub {
47-
if vm, found := m[k]; !found || vm != vsub {
48-
return false
49-
}
20+
21+
if threshold < 0 {
22+
return 0, fmt.Errorf("threshold must be a positive duration")
5023
}
51-
return true
24+
25+
return threshold, nil
5226
}

0 commit comments

Comments
 (0)