mirror of
https://github.com/kubescape/kubescape.git
synced 2026-04-15 06:58:11 +00:00
410 lines
11 KiB
Go
410 lines
11 KiB
Go
package getter
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func MockNewLoadPolicy() *LoadPolicy {
|
|
return &LoadPolicy{
|
|
filePaths: []string{""},
|
|
}
|
|
}
|
|
|
|
func TestLoadPolicy(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const (
|
|
testFramework = "MITRE"
|
|
testControl = "C-0053"
|
|
)
|
|
|
|
t.Run("with GetFramework", func(t *testing.T) {
|
|
t.Run("should retrieve named framework", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
p := NewLoadPolicy([]string{testFrameworkFile(testFramework)})
|
|
fw, err := p.GetFramework(testFramework)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, fw)
|
|
|
|
require.Equal(t, testFramework, fw.Name)
|
|
})
|
|
|
|
t.Run("should fail to retrieve framework", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
p := NewLoadPolicy([]string{testFrameworkFile(testFramework)})
|
|
fw, err := p.GetFramework("wrong")
|
|
require.Error(t, err)
|
|
require.Nil(t, fw)
|
|
})
|
|
|
|
t.Run("edge case: should error on empty framework", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
p := NewLoadPolicy([]string{testFrameworkFile(testFramework)})
|
|
fw, err := p.GetFramework("")
|
|
require.ErrorIs(t, err, ErrNameRequired)
|
|
require.Nil(t, fw)
|
|
})
|
|
|
|
t.Run("edge case: corrupted json", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const invalidFramework = "invalid-fw"
|
|
p := NewLoadPolicy([]string{testFrameworkFile(invalidFramework)})
|
|
fw, err := p.GetFramework(invalidFramework)
|
|
require.Error(t, err)
|
|
require.Nil(t, fw)
|
|
})
|
|
|
|
t.Run("edge case: missing json", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const invalidFramework = "nowheretobefound"
|
|
p := NewLoadPolicy([]string{testFrameworkFile(invalidFramework)})
|
|
_, err := p.GetFramework(invalidFramework)
|
|
require.Error(t, err)
|
|
})
|
|
})
|
|
|
|
t.Run("with GetControl", func(t *testing.T) {
|
|
t.Run("should retrieve named control from framework", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const (
|
|
expectedControlName = "Access container service account"
|
|
)
|
|
p := NewLoadPolicy([]string{testFrameworkFile(testFramework)})
|
|
ctrl, err := p.GetControl(testControl)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, ctrl)
|
|
|
|
require.Equal(t, testControl, ctrl.ControlID)
|
|
require.Equal(t, expectedControlName, ctrl.Name)
|
|
})
|
|
|
|
t.Run("with single control descriptor", func(t *testing.T) {
|
|
const (
|
|
singleControl = "C-0001"
|
|
expectedControlName = "Forbidden Container Registries"
|
|
)
|
|
|
|
t.Run("should retrieve named control from control descriptor", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
p := NewLoadPolicy([]string{testFrameworkFile(singleControl)})
|
|
ctrl, err := p.GetControl(singleControl)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, ctrl)
|
|
|
|
require.Equal(t, singleControl, ctrl.ControlID)
|
|
require.Equal(t, expectedControlName, ctrl.Name)
|
|
})
|
|
|
|
t.Run("should fail to retrieve named control from control descriptor", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
p := NewLoadPolicy([]string{testFrameworkFile(singleControl)})
|
|
ctrl, err := p.GetControl("wrong")
|
|
require.Error(t, err)
|
|
require.Nil(t, ctrl)
|
|
})
|
|
})
|
|
|
|
t.Run("with framework descriptor", func(t *testing.T) {
|
|
t.Run("should fail to retrieve named control", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const testControl = "wrong"
|
|
p := NewLoadPolicy([]string{testFrameworkFile(testFramework)})
|
|
ctrl, err := p.GetControl(testControl)
|
|
require.ErrorIs(t, err, ErrControlNotMatching)
|
|
require.Nil(t, ctrl)
|
|
})
|
|
})
|
|
|
|
t.Run("edge case: corrupted json", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const invalidControl = "invalid-fw"
|
|
p := NewLoadPolicy([]string{testFrameworkFile(invalidControl)})
|
|
_, err := p.GetControl(invalidControl)
|
|
require.Error(t, err)
|
|
})
|
|
|
|
t.Run("edge case: missing json", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const invalidControl = "nowheretobefound"
|
|
p := NewLoadPolicy([]string{testFrameworkFile(invalidControl)})
|
|
_, err := p.GetControl(invalidControl)
|
|
require.Error(t, err)
|
|
})
|
|
|
|
t.Run("edge case: should error on empty control", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
p := NewLoadPolicy([]string{testFrameworkFile(testFramework)})
|
|
ctrl, err := p.GetControl("")
|
|
require.ErrorIs(t, err, ErrIDRequired)
|
|
require.Nil(t, ctrl)
|
|
})
|
|
})
|
|
|
|
t.Run("with ListFrameworks", func(t *testing.T) {
|
|
t.Run("should return all frameworks in the policy path", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const (
|
|
extraFramework = "NSA"
|
|
attackTracks = "attack-tracks"
|
|
)
|
|
p := NewLoadPolicy([]string{
|
|
testFrameworkFile(testFramework),
|
|
testFrameworkFile(extraFramework),
|
|
testFrameworkFile(extraFramework), // should be deduped
|
|
testFrameworkFile(attackTracks), // should be ignored
|
|
})
|
|
fws, err := p.ListFrameworks()
|
|
require.NoError(t, err)
|
|
require.Len(t, fws, 2)
|
|
|
|
require.Equal(t, testFramework, fws[0])
|
|
require.Equal(t, extraFramework, fws[1])
|
|
})
|
|
|
|
t.Run("should not return an empty framework", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const (
|
|
extraFramework = "NSA"
|
|
attackTracks = "attack-tracks"
|
|
controlsInputs = "controls-inputs"
|
|
)
|
|
p := NewLoadPolicy([]string{
|
|
testFrameworkFile(testFramework),
|
|
testFrameworkFile(extraFramework),
|
|
testFrameworkFile(attackTracks), // should be ignored
|
|
testFrameworkFile(controlsInputs), // should be ignored
|
|
})
|
|
fws, err := p.ListFrameworks()
|
|
require.NoError(t, err)
|
|
require.Len(t, fws, 2)
|
|
require.NotContains(t, fws, "")
|
|
|
|
require.Equal(t, testFramework, fws[0])
|
|
require.Equal(t, extraFramework, fws[1])
|
|
})
|
|
|
|
t.Run("should fail on file error", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const (
|
|
extraFramework = "NSA"
|
|
nowhere = "nowheretobeseen"
|
|
)
|
|
p := NewLoadPolicy([]string{
|
|
testFrameworkFile(testFramework),
|
|
testFrameworkFile(extraFramework),
|
|
testFrameworkFile(nowhere), // should raise an error
|
|
})
|
|
fws, err := p.ListFrameworks()
|
|
require.Error(t, err)
|
|
require.Nil(t, fws)
|
|
})
|
|
})
|
|
|
|
t.Run("edge case: policy without path", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
p := NewLoadPolicy([]string{})
|
|
require.Empty(t, p.filePath())
|
|
})
|
|
|
|
t.Run("with GetFrameworks", func(t *testing.T) {
|
|
const extraFramework = "NSA"
|
|
|
|
t.Run("should return all configured frameworks", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
p := NewLoadPolicy([]string{
|
|
testFrameworkFile(testFramework),
|
|
testFrameworkFile(extraFramework),
|
|
})
|
|
fws, err := p.GetFrameworks()
|
|
require.NoError(t, err)
|
|
require.Len(t, fws, 2)
|
|
|
|
require.Equal(t, testFramework, fws[0].Name)
|
|
require.Equal(t, extraFramework, fws[1].Name)
|
|
})
|
|
|
|
t.Run("should return dedupe configured frameworks", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const attackTracks = "attack-tracks"
|
|
p := NewLoadPolicy([]string{
|
|
testFrameworkFile(testFramework),
|
|
testFrameworkFile(extraFramework),
|
|
testFrameworkFile(extraFramework),
|
|
testFrameworkFile(attackTracks), // should be ignored
|
|
})
|
|
fws, err := p.GetFrameworks()
|
|
require.NoError(t, err)
|
|
require.Len(t, fws, 2)
|
|
|
|
require.Equal(t, testFramework, fws[0].Name)
|
|
require.Equal(t, extraFramework, fws[1].Name)
|
|
})
|
|
})
|
|
|
|
t.Run("with ListControls", func(t *testing.T) {
|
|
t.Run("should return controls", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
p := NewLoadPolicy([]string{testFrameworkFile(testFramework)})
|
|
controlIDs, err := p.ListControls()
|
|
require.NoError(t, err)
|
|
require.Greater(t, len(controlIDs), 0)
|
|
require.Equal(t, testControl, controlIDs[0])
|
|
})
|
|
})
|
|
|
|
t.Run("with GetAttackTracks", func(t *testing.T) {
|
|
t.Run("should return attack tracks", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const attackTracks = "attack-tracks"
|
|
p := NewLoadPolicy([]string{testFrameworkFile(attackTracks)})
|
|
tracks, err := p.GetAttackTracks()
|
|
require.NoError(t, err)
|
|
require.Greater(t, len(tracks), 0)
|
|
|
|
for _, track := range tracks {
|
|
require.Equal(t, "AttackTrack", track.Kind)
|
|
}
|
|
})
|
|
|
|
t.Run("edge case: corrupted json", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const invalidTracks = "invalid-fw"
|
|
p := NewLoadPolicy([]string{testFrameworkFile(invalidTracks)})
|
|
_, err := p.GetAttackTracks()
|
|
require.Error(t, err)
|
|
})
|
|
|
|
t.Run("edge case: missing json", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const invalidTracks = "nowheretobefound"
|
|
p := NewLoadPolicy([]string{testFrameworkFile(invalidTracks)})
|
|
_, err := p.GetAttackTracks()
|
|
require.Error(t, err)
|
|
})
|
|
})
|
|
|
|
t.Run("with GetControlsInputs", func(t *testing.T) {
|
|
const cluster = "dummy" // unused parameter at the moment
|
|
|
|
t.Run("should return control inputs for a cluster", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
fixture, expected := writeTempJSONControlInputs(t)
|
|
t.Cleanup(func() {
|
|
_ = os.Remove(fixture)
|
|
})
|
|
|
|
p := NewLoadPolicy([]string{fixture})
|
|
inputs, err := p.GetControlsInputs(cluster)
|
|
require.NoError(t, err)
|
|
require.EqualValues(t, expected, inputs)
|
|
})
|
|
|
|
t.Run("edge case: corrupted json", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const invalidInputs = "invalid-fw"
|
|
p := NewLoadPolicy([]string{testFrameworkFile(invalidInputs)})
|
|
_, err := p.GetControlsInputs(cluster)
|
|
require.Error(t, err)
|
|
})
|
|
|
|
t.Run("edge case: missing json", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const invalidInputs = "nowheretobefound"
|
|
p := NewLoadPolicy([]string{testFrameworkFile(invalidInputs)})
|
|
_, err := p.GetControlsInputs(cluster)
|
|
require.Error(t, err)
|
|
})
|
|
})
|
|
|
|
t.Run("with GetExceptions", func(t *testing.T) {
|
|
const cluster = "dummy" // unused parameter at the moment
|
|
|
|
t.Run("should return exceptions", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const exceptions = "exceptions"
|
|
|
|
p := NewLoadPolicy([]string{testFrameworkFile(exceptions)})
|
|
exceptionPolicies, err := p.GetExceptions(cluster)
|
|
require.NoError(t, err)
|
|
|
|
require.Greater(t, len(exceptionPolicies), 0)
|
|
t.Logf("len=%d", len(exceptionPolicies))
|
|
for _, policy := range exceptionPolicies {
|
|
require.NotEmpty(t, policy.Name)
|
|
}
|
|
})
|
|
|
|
t.Run("edge case: corrupted json", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const invalidInputs = "invalid-fw"
|
|
p := NewLoadPolicy([]string{testFrameworkFile(invalidInputs)})
|
|
_, err := p.GetExceptions(cluster)
|
|
require.Error(t, err)
|
|
})
|
|
|
|
t.Run("edge case: missing json", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const invalidInputs = "nowheretobefound"
|
|
p := NewLoadPolicy([]string{testFrameworkFile(invalidInputs)})
|
|
_, err := p.GetExceptions(cluster)
|
|
require.Error(t, err)
|
|
})
|
|
})
|
|
}
|
|
|
|
func testFrameworkFile(framework string) string {
|
|
return filepath.Join(".", "testdata", fmt.Sprintf("%s.json", framework))
|
|
}
|
|
|
|
func writeTempJSONControlInputs(t testing.TB) (string, map[string][]string) {
|
|
fileName := testFrameworkFile("control-inputs")
|
|
mock := map[string][]string{
|
|
"key1": {
|
|
"val1", "val2",
|
|
},
|
|
"key2": {
|
|
"val3", "val4",
|
|
},
|
|
}
|
|
|
|
buf, err := json.Marshal(mock)
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, os.WriteFile(fileName, buf, 0600))
|
|
|
|
return fileName, mock
|
|
}
|