From 6ec13ec16e8242c359d2b2e796a0588f20ad7f67 Mon Sep 17 00:00:00 2001 From: Dominik Richter Date: Thu, 4 Apr 2024 23:41:27 -0700 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20hard=20breakpoints=20for=20blastrad?= =?UTF-8?q?ius?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The indicator sometimes says something is large, despite the fact it is actually quite small. Example: if 1 out of 2 assets is affected, the indicator says blast radius is large. This new mechanism sets strict breakpoints before something is considered large in its effect. Signed-off-by: Dominik Richter --- policy/score_stats.go | 26 ++++++++++++++++++-------- policy/score_stats_test.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 8 deletions(-) create mode 100644 policy/score_stats_test.go diff --git a/policy/score_stats.go b/policy/score_stats.go index 19a7437e..f3dbf55c 100644 --- a/policy/score_stats.go +++ b/policy/score_stats.go @@ -13,26 +13,36 @@ const ( // BlastRadiusConfig for custom blast radius indicators type BlastRadiusConfig struct { - SmallPct float32 - MediumPct float32 - CategoryThreshold float32 + // Percentage of infrastructure in total weight that is considered small. + // eg. 5%. If something affects 3/100 assets, it is 3% and thus small. + SmallPct float32 + // Percentage of infrastructure in total weight that is considered medium. + // eg. 20%. If something affects 10/100 assets, it is 10% and thus medium. + MediumPct float32 + // Minimum number of assets for something to be considered medium. + // eg. 10. If something affects 2/4 assets, it is 50%, but still small. + MediumMinCnt float32 + // Minimum number of assets for something to be considered large. + // eg. 25. If something affects 20/40 assets, it is 50%, but still medium. + LargeMinCnt float32 } // DefaultBlastRadiusConfig var DefaultBlastRadiusConfig = BlastRadiusConfig{ - SmallPct: 0.05, - MediumPct: 0.20, - CategoryThreshold: 20, + SmallPct: 0.05, + MediumPct: 0.20, + MediumMinCnt: 10, + LargeMinCnt: 25, } // BlastRadius retrieves the blast radius indicator and assets in this category. // It requires a weight as input func (b *BlastRadiusConfig) Indicator(totalWeight float32, weight float32) BlastRadiusIndicator { rel := weight / totalWeight - if rel < b.SmallPct { + if rel < b.SmallPct || weight < b.MediumMinCnt { return BlastRadius_Small } - if rel < b.MediumPct { + if rel < b.MediumPct || weight < b.LargeMinCnt { return BlastRadius_Medium } return BlastRadius_Large diff --git a/policy/score_stats_test.go b/policy/score_stats_test.go new file mode 100644 index 00000000..933513c9 --- /dev/null +++ b/policy/score_stats_test.go @@ -0,0 +1,34 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package policy + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBlastRadius(t *testing.T) { + conf := DefaultBlastRadiusConfig + tests := []struct { + n float32 + max float32 + indicator string + }{ + {1, 100, "s"}, + {10, 100, "m"}, + {30, 100, "l"}, + {4, 5, "s"}, + {10, 20, "m"}, + {50, 100, "l"}, + } + + for i := range tests { + test := tests[i] + t.Run(fmt.Sprintf("%.2f / %.2f => %s", test.n, test.max, test.indicator), func(t *testing.T) { + assert.Equal(t, test.indicator, string(conf.Indicator(test.max, test.n))) + }) + } +}