diff --git a/gitregostore/gitstoremethods.go b/gitregostore/gitstoremethods.go index 33ae7951..eb44a697 100644 --- a/gitregostore/gitstoremethods.go +++ b/gitregostore/gitstoremethods.go @@ -7,6 +7,7 @@ import ( "github.com/armosec/armoapi-go/armotypes" "github.com/go-gota/gota/dataframe" "github.com/go-gota/gota/series" + "github.com/kubescape/opa-utils/reporthandling" opapolicy "github.com/kubescape/opa-utils/reporthandling" "github.com/kubescape/opa-utils/reporthandling/attacktrack/v1alpha1" "k8s.io/utils/strings/slices" @@ -301,6 +302,55 @@ func (gs *GitRegoStore) GetOpaFrameworkListByControlID(controlID string) []strin return frameworksNameList } +// GetControlFrameworkSubsections returns all subsections of a control in a framework +func (gs *GitRegoStore) GetControlFrameworkSubsections(controlID string, frameworkName string) ([]string, error) { + gs.frameworksLock.RLock() + defer gs.frameworksLock.RUnlock() + gs.controlsLock.RLock() + defer gs.controlsLock.RUnlock() + + fw, err := gs.getOPAFrameworkByName(frameworkName) // doesn't lock framework + if err != nil { + return nil, err + } + + control, err := gs.getOPAControlByID(controlID) // doesn't lock control + if err != nil { + return nil, err + } + + fwSubsectionIDs := make([]string, 0) + subsections := fw.SubSections + + for i := range subsections { + fwSubsectionIDs = gs.getControlFrameworkSubSections(fwSubsectionIDs, control.ControlID, subsections[i]) + } + + return fwSubsectionIDs, nil +} + +func (gs *GitRegoStore) getControlFrameworkSubSections(fwSubsectionIDs []string, controlID string, section *reporthandling.FrameworkSubSection) []string { + // Return the current list if the section is nil + if section == nil { + return fwSubsectionIDs + } + + // Recursively gather IDs from subsections + if section.SubSections != nil { + for _, subSection := range section.SubSections { + // Update fwSubsectionIDs with the result of the recursive call + fwSubsectionIDs = gs.getControlFrameworkSubSections(fwSubsectionIDs, controlID, subSection) + } + } + + // Append the current section ID if it contains the controlID + if section.ControlIDs != nil && slices.Contains(section.ControlIDs, controlID) { + fwSubsectionIDs = append(fwSubsectionIDs, section.ID) + } + + return fwSubsectionIDs +} + // =============================================================== // =========================== Frameworks ======================== // =============================================================== diff --git a/gitregostore/gitstoremethods_test.go b/gitregostore/gitstoremethods_test.go index b2579792..f22dc774 100644 --- a/gitregostore/gitstoremethods_test.go +++ b/gitregostore/gitstoremethods_test.go @@ -220,6 +220,28 @@ func gs_tests(t *testing.T, gs *GitRegoStore) { "wrong control for framework name 'NSA' and control name 'Allow privilege escalation' expected: 'C-0016', found %s", control.ControlID, ) }) + + t.Run("should retrieve list of fw subsections IDs", func(t *testing.T) { + t.Parallel() + + subsectionsIDs, err := gs.GetControlFrameworkSubsections("C-0067", "cis-eks-t1.2.0") + require.NoError(t, err) + require.NotEmptyf(t, subsectionsIDs, + "failed to get subsections ids list for control 'C-0067' in framework name 'cis-eks-t1.2.0' %v", err, + ) + assert.ElementsMatch(t, []string{"2.1"}, subsectionsIDs) + + t.Run("should retrieve fw subsection by ID", func(t *testing.T) { + t.Parallel() + + subsectionsIDs, err := gs.GetControlFrameworkSubsections("C-0167", "cis-aks-t1.2.0") + assert.NoError(t, err) + require.NotEmptyf(t, subsectionsIDs, + "failed to get subsections ids list for control 'C-0167' in framework name 'cis-aks-t1.2.0' %v", err, + ) + assert.ElementsMatch(t, []string{"3.1"}, subsectionsIDs) + }) + }) } func TestGetPoliciesMethodsNewV2(t *testing.T) {