Skip to content

Commit

Permalink
add api to lookup cloud compliance controls
Browse files Browse the repository at this point in the history
  • Loading branch information
gnmahanth committed Jul 9, 2024
1 parent ac4f165 commit 7e6a853
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 11 deletions.
8 changes: 6 additions & 2 deletions deepfence_server/apiDocs/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ func (d *OpenAPIDocs) AddLookupOperations() {
d.AddOperation("getCloudCompliances", http.MethodPost, "/deepfence/lookup/cloud-compliances",
"Retrieve Cloud Compliances data", "Retrieve all the data associated with cloud-compliances",
http.StatusOK, []string{tagLookup}, bearerToken, new(LookupFilter), new([]CloudCompliance))

d.AddOperation("getComplianceControls", http.MethodPost, "/deepfence/lookup/compliance-controls",
"Retrieve Cloud Compliances Control data", "Retrieve all the data associated with cloud compliance controls",
http.StatusOK, []string{tagLookup}, bearerToken, new(LookupFilter), new([]CloudComplianceControl))
}

func (d *OpenAPIDocs) AddSearchOperations() {
Expand Down Expand Up @@ -612,10 +616,10 @@ func (d *OpenAPIDocs) AddScansOperations() {
// compliance and cloud-compliance results count grouped by control_id
d.AddOperation("groupResultsCompliance", http.MethodPost, "/deepfence/scan/results/count/group/compliance",
"Count Compliance Results by Control ID", "Count Compliance Results grouped by Control ID",
http.StatusOK, []string{tagCompliance}, bearerToken, new(ComplinaceScanResultsGroupReq), new(ComplinaceScanResultsGroupResp))
http.StatusOK, []string{tagCompliance}, bearerToken, new(ComplinaceScanResultsGroupReq), new(ComplianceScanResultsGroupResp))
d.AddOperation("groupResultsCloudCompliance", http.MethodPost, "/deepfence/scan/results/count/group/cloud-compliance",
"Count Cloud Compliance Results by Control ID", "Count Cloud Compliance Results grouped by Control ID",
http.StatusOK, []string{tagCompliance}, bearerToken, new(ComplinaceScanResultsGroupReq), new(ComplinaceScanResultsGroupResp))
http.StatusOK, []string{tagCompliance}, bearerToken, new(ComplinaceScanResultsGroupReq), new(ComplianceScanResultsGroupResp))

d.AddOperation("getAllNodesInScanResults", http.MethodPost, "/deepfence/scan/nodes-in-result",
"Get all nodes in given scan result ids", "Get all nodes in given scan result ids",
Expand Down
4 changes: 4 additions & 0 deletions deepfence_server/handler/lookup_reports.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,7 @@ func (h *Handler) GetCompliances(w http.ResponseWriter, r *http.Request) {
func (h *Handler) GetCloudCompliances(w http.ResponseWriter, r *http.Request) {
getGeneric[model.CloudCompliance](h, w, r, reporters_lookup.GetCloudComplianceReport)
}

func (h *Handler) GetCloudComplianceControl(w http.ResponseWriter, r *http.Request) {
getGeneric[model.CloudComplianceControl](h, w, r, reporters_lookup.GetCloudComplianceControl)
}
12 changes: 6 additions & 6 deletions deepfence_server/handler/scan_reports.go
Original file line number Diff line number Diff line change
Expand Up @@ -1266,10 +1266,10 @@ func (h *Handler) CountComplianceScanResultsGroupHandler(w http.ResponseWriter,
h.respondError(err, w)
}

results := map[string]model.ComplinaceScanResultControlGroup{}
results := map[string]model.ComplianceScanResultControlGroup{}

for _, rec := range recs {
r := model.ComplinaceScanResultControlGroup{
r := model.ComplianceScanResultControlGroup{
Counts: groupArrayToMap(rec.Values[1].([]interface{})),
BenchmarkTypes: cast.ToStringSlice(rec.Values[2].(string)),
Title: rec.Values[3].(string),
Expand All @@ -1278,7 +1278,7 @@ func (h *Handler) CountComplianceScanResultsGroupHandler(w http.ResponseWriter,
}

err = httpext.JSON(w, http.StatusOK,
model.ComplinaceScanResultsGroupResp{Groups: results})
model.ComplianceScanResultsGroupResp{Groups: results})
if err != nil {
log.Error().Msgf("%v", err)
}
Expand Down Expand Up @@ -1352,10 +1352,10 @@ func (h *Handler) CountCloudComplianceScanResultsGroupHandler(w http.ResponseWri
h.respondError(err, w)
}

results := map[string]model.ComplinaceScanResultControlGroup{}
results := map[string]model.ComplianceScanResultControlGroup{}

for _, rec := range recs {
r := model.ComplinaceScanResultControlGroup{
r := model.ComplianceScanResultControlGroup{
Counts: groupArrayToMap(rec.Values[1].([]interface{})),
BenchmarkTypes: cast.ToStringSlice(rec.Values[2].([]interface{})),
Title: rec.Values[3].(string),
Expand All @@ -1364,7 +1364,7 @@ func (h *Handler) CountCloudComplianceScanResultsGroupHandler(w http.ResponseWri
}

err = httpext.JSON(w, http.StatusOK,
model.ComplinaceScanResultsGroupResp{Groups: results})
model.ComplianceScanResultsGroupResp{Groups: results})
if err != nil {
log.Error().Msgf("%v", err)
}
Expand Down
40 changes: 37 additions & 3 deletions deepfence_server/model/scans.go
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,40 @@ func (CloudCompliance) GetJSONCategory() string {
return "severity"
}

type CloudComplianceControl struct {
ControlID string `json:"control_id"`
Documentation string `json:"documentation"`
Active bool `json:"active"`
Description string `json:"description"`
CloudProvider string `json:"cloud_provider"`
Title string `json:"title"`
Executable bool `json:"executable"`
CategoryHierarchyShort string `json:"category_hierarchy_short"`
CategoryHierarchy []string `json:"category_hierarchy"`
Service string `json:"service"`
ParentControlHierarchy []string `json:"parent_control_hierarchy"`
ComplianceType string `json:"compliance_type"`
Disabled bool `json:"disabled"`
Category string `json:"category"`
NodeID string `json:"node_id"`
}

func (CloudComplianceControl) NodeType() string {
return "CloudComplianceControl"
}

func (CloudComplianceControl) ExtendedField() string {
return ""
}

func (v CloudComplianceControl) GetCategory() string {
return v.ComplianceType
}

func (CloudComplianceControl) GetJSONCategory() string {
return "compliance_type"
}

type ScanReportFieldsResponse struct {
Vulnerability []string `json:"vulnerability"`
Secret []string `json:"secret"`
Expand All @@ -615,11 +649,11 @@ type ComplinaceScanResultsGroupReq struct {
FieldsFilter reporters.FieldsFilters `json:"fields_filter" required:"true"`
}

type ComplinaceScanResultsGroupResp struct {
Groups map[string]ComplinaceScanResultControlGroup `json:"groups"`
type ComplianceScanResultsGroupResp struct {
Groups map[string]ComplianceScanResultControlGroup `json:"groups"`
}

type ComplinaceScanResultControlGroup struct {
type ComplianceScanResultControlGroup struct {
Title string `json:"title,omitempty"`
Counts map[string]int64 `json:"counts,omitempty"`
BenchmarkTypes []string `json:"benchmark_types,omitempty"`
Expand Down
84 changes: 84 additions & 0 deletions deepfence_server/reporters/lookup/lookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,86 @@ func getGenericDirectNodeReport[T reporters.Cypherable](ctx context.Context, fil
return res, nil
}

// whereIDLabel is not used if nodeID's in filter are not present
func getGenericNodeReport[T reporters.Cypherable](ctx context.Context, whereIDLabel string, filter LookupFilter) ([]T, error) {

ctx, span := telemetry.NewSpan(ctx, "lookup", "get-generic-node-report")
defer span.End()

res := []T{}
var dummy T

driver, err := directory.Neo4jClient(ctx)
if err != nil {
return res, err
}

session := driver.NewSession(ctx, neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead})
defer session.Close(ctx)

tx, err := session.BeginTransaction(ctx, neo4j.WithTxTimeout(30*time.Second))
if err != nil {
return res, err
}
defer tx.Close(ctx)

var r neo4j.ResultWithContext
var query string
if len(filter.NodeIds) == 0 {
query = `
MATCH (n:` + dummy.NodeType() + `)
RETURN ` + reporters.FieldFilterCypher("n", filter.InFieldFilter) +
filter.Window.FetchWindow2CypherQuery()
} else {
query = `
MATCH (n:` + dummy.NodeType() + `)
WHERE n.` + whereIDLabel + ` IN $ids
RETURN ` + reporters.FieldFilterCypher("n", filter.InFieldFilter) +
filter.Window.FetchWindow2CypherQuery()
}

log.Debug().Msgf("query: %s", query)

r, err = tx.Run(ctx, query, map[string]interface{}{"ids": filter.NodeIds})
if err != nil {
return res, err
}

recs, err := r.Collect(ctx)

if err != nil {
return res, err
}

for _, rec := range recs {
var nodeMap map[string]interface{}
if len(filter.InFieldFilter) == 0 {
data, has := rec.Get("n")
if !has {
log.Warn().Msgf("Missing neo4j entry")
continue
}
da, ok := data.(dbtype.Node)
if !ok {
log.Warn().Msgf("Missing neo4j entry")
continue
}
nodeMap = da.Props
} else {
nodeMap = map[string]interface{}{}
for i := range filter.InFieldFilter {
nodeMap[filter.InFieldFilter[i]] = rec.Values[i]
}
}

var node T
utils.FromMap(nodeMap, &node)
res = append(res, node)
}

return res, nil
}

func getNodeConnections[T reporters.Cypherable](ctx context.Context, ids []string) ([]model.ConnectionQueryResp, []model.ConnectionQueryResp, error) {
inbound := []model.ConnectionQueryResp{}
outbound := []model.ConnectionQueryResp{}
Expand Down Expand Up @@ -626,3 +706,7 @@ func GetComplianceReport(ctx context.Context, filter LookupFilter) ([]model.Comp
func GetCloudComplianceReport(ctx context.Context, filter LookupFilter) ([]model.CloudCompliance, error) {
return getGenericDirectNodeReport[model.CloudCompliance](ctx, filter)
}

func GetCloudComplianceControl(ctx context.Context, filter LookupFilter) ([]model.CloudComplianceControl, error) {
return getGenericNodeReport[model.CloudComplianceControl](ctx, "control_id", filter)
}
1 change: 1 addition & 0 deletions deepfence_server/router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ func SetupRoutes(r *chi.Mux, serverPort string, serveOpenapiDocs bool, ingestC c
r.Post("/malwares", dfHandler.GetMalwares)
r.Post("/compliances", dfHandler.GetCompliances)
r.Post("/cloud-compliances", dfHandler.GetCloudCompliances)
r.Post("/compliance-controls", dfHandler.GetCloudComplianceControl)
})

r.Route("/complete", func(r chi.Router) {
Expand Down

0 comments on commit 7e6a853

Please sign in to comment.