From 1e8598e2a24bd8484930c8d9114a194034405a9f Mon Sep 17 00:00:00 2001 From: Ramanan Ravikumar <38394463+ramanan-ravi@users.noreply.github.com> Date: Fri, 5 Apr 2024 16:11:47 +0530 Subject: [PATCH] Set date range when generate report (#2063) #2062 --- deepfence_server/handler/export_reports.go | 79 +++++++++++++++++++--- deepfence_server/model/reports.go | 28 ++++---- deepfence_utils/utils/structs.go | 12 ++-- deepfence_worker/tasks/reports/data.go | 35 ++++------ 4 files changed, 106 insertions(+), 48 deletions(-) diff --git a/deepfence_server/handler/export_reports.go b/deepfence_server/handler/export_reports.go index 954e600cd4..aa235e58ba 100644 --- a/deepfence_server/handler/export_reports.go +++ b/deepfence_server/handler/export_reports.go @@ -2,6 +2,7 @@ package handler import ( "encoding/json" + "errors" "fmt" "net/http" "sort" @@ -379,6 +380,33 @@ func (h *Handler) ListReports(w http.ResponseWriter, r *http.Request) { } } +const ( + fromDateToDateMaxDifference = 180 * 24 // 180 days in hours +) + +var ( + errFromDateRequired = ValidatorError{ + err: errors.New("from_timestamp:required if 'to date' is set"), + skipOverwriteErrorMessage: true, + } + errToDateRequired = ValidatorError{ + err: errors.New("to_timestamp:required if 'from date' is set"), + skipOverwriteErrorMessage: true, + } + errFromDateLessThanToDate = ValidatorError{ + err: errors.New("to_timestamp:should be greater than from date"), + skipOverwriteErrorMessage: true, + } + errToDateGreaterThanToday = ValidatorError{ + err: errors.New("to_timestamp:should not be greater than today"), + skipOverwriteErrorMessage: true, + } + errFromAndToDateDifference = ValidatorError{ + err: fmt.Errorf("from_timestamp:difference cannot be more than %d days", fromDateToDateMaxDifference/24), + skipOverwriteErrorMessage: true, + } +) + func (h *Handler) GenerateReport(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() var req model.GenerateReportReq @@ -393,12 +421,41 @@ func (h *Handler) GenerateReport(w http.ResponseWriter, r *http.Request) { return } + var fromTimestamp time.Time + var toTimestamp time.Time + if req.FromTimestamp > 0 && req.ToTimestamp > 0 { + fromTimestamp = time.UnixMilli(req.FromTimestamp).UTC() + toTimestamp = time.UnixMilli(req.ToTimestamp).UTC() + + now := time.Now().UTC() + tomorrowDate := time.Date(now.Year(), now.Month(), now.Day()+1, 0, 0, 1, 0, time.UTC) + if tomorrowDate.Before(toTimestamp) { + h.respondError(&errToDateGreaterThanToday, w) + return + } + if fromTimestamp.After(toTimestamp) { + h.respondError(&errFromDateLessThanToDate, w) + return + } + if toTimestamp.Sub(fromTimestamp).Hours() > fromDateToDateMaxDifference { + h.respondError(&errFromAndToDateDifference, w) + return + } + } else if req.FromTimestamp > 0 { + h.respondError(&errToDateRequired, w) + return + } else if req.ToTimestamp > 0 { + h.respondError(&errFromDateRequired, w) + return + } + // report task params params := utils.ReportParams{ - ReportType: req.ReportType, - Duration: req.Duration, - Filters: req.Filters, - Options: req.Options, + ReportType: req.ReportType, + FromTimestamp: fromTimestamp, + ToTimestamp: toTimestamp, + Filters: req.Filters, + Options: req.Options, } // scan id can only be sent while downloading individual scans @@ -485,14 +542,16 @@ func (h *Handler) GenerateReport(w http.ResponseWriter, r *http.Request) { SET n.type=$type SET n.status=$status SET n.filters=$filters - SET n.duration=$duration + SET n.from_timestamp=$from_timestamp + SET n.to_timestamp=$to_timestamp RETURN n` createVars := map[string]interface{}{ - "type": req.ReportType, - "uid": params.ReportID, - "status": utils.ScanStatusStarting, - "filters": req.Filters.String(), - "duration": req.Duration, + "type": req.ReportType, + "uid": params.ReportID, + "status": utils.ScanStatusStarting, + "filters": req.Filters.String(), + "from_timestamp": req.FromTimestamp, + "to_timestamp": req.ToTimestamp, } _, err = tx.Run(ctx, createQuery, createVars) diff --git a/deepfence_server/model/reports.go b/deepfence_server/model/reports.go index a90e9ddd44..ba758675d5 100644 --- a/deepfence_server/model/reports.go +++ b/deepfence_server/model/reports.go @@ -5,10 +5,11 @@ import ( ) type GenerateReportReq struct { - ReportType string `json:"report_type" validate:"required" required:"true" enum:"pdf,xlsx,sbom"` - Duration int `json:"duration" enum:"0,1,7,30,60,90,180"` - Filters utils.ReportFilters `json:"filters"` - Options utils.ReportOptions `json:"options" validate:"omitempty"` + ReportType string `json:"report_type" validate:"required" required:"true" enum:"pdf,xlsx,sbom"` + FromTimestamp int64 `json:"from_timestamp"` // timestamp in milliseconds + ToTimestamp int64 `json:"to_timestamp"` // timestamp in milliseconds + Filters utils.ReportFilters `json:"filters"` + Options utils.ReportOptions `json:"options" validate:"omitempty"` } type GenerateReportResp struct { @@ -24,13 +25,14 @@ type BulkDeleteReportReq struct { } type ExportReport struct { - Duration int `json:"duration"` - UpdatedAt int64 `json:"updated_at"` - ReportID string `json:"report_id"` - CreatedAt int64 `json:"created_at"` - Filters string `json:"filters"` - Type string `json:"type"` - URL string `json:"url"` - Status string `json:"status"` - StoragePath string `json:"storage_path"` + UpdatedAt int64 `json:"updated_at"` + ReportID string `json:"report_id"` + CreatedAt int64 `json:"created_at"` + Filters string `json:"filters"` + Type string `json:"type"` + URL string `json:"url"` + Status string `json:"status"` + StoragePath string `json:"storage_path"` + FromTimestamp int64 `json:"from_timestamp"` // timestamp in milliseconds + ToTimestamp int64 `json:"to_timestamp"` // timestamp in milliseconds } diff --git a/deepfence_utils/utils/structs.go b/deepfence_utils/utils/structs.go index 9e5c8f6afb..a96a78a4a0 100644 --- a/deepfence_utils/utils/structs.go +++ b/deepfence_utils/utils/structs.go @@ -3,6 +3,7 @@ package utils import ( "encoding/json" "encoding/xml" + "time" ) type MinioError struct { @@ -76,11 +77,12 @@ type MalwareScanParameters struct { } type ReportParams struct { - ReportID string `json:"report_id"` - ReportType string `json:"report_type"` - Duration int `json:"duration"` - Filters ReportFilters `json:"filters"` - Options ReportOptions `json:"options,omitempty"` + ReportID string `json:"report_id"` + ReportType string `json:"report_type"` + FromTimestamp time.Time `json:"from_timestamp"` + ToTimestamp time.Time `json:"to_timestamp"` + Filters ReportFilters `json:"filters"` + Options ReportOptions `json:"options,omitempty"` } type ReportOptions struct { diff --git a/deepfence_worker/tasks/reports/data.go b/deepfence_worker/tasks/reports/data.go index f666eb1b59..1749ef40ed 100644 --- a/deepfence_worker/tasks/reports/data.go +++ b/deepfence_worker/tasks/reports/data.go @@ -141,12 +141,11 @@ func getVulnerabilityData(ctx context.Context, params sdkUtils.ReportParams) (*I searchFilter := searchScansFilter(params) var ( - end = time.Now() - start = time.Now() + start = params.FromTimestamp + end = params.ToTimestamp ) - if params.Duration > 0 && len(params.Filters.ScanID) == 0 { - start = end.AddDate(0, 0, -params.Duration) + if !params.FromTimestamp.IsZero() && len(params.Filters.ScanID) == 0 { searchFilter.ScanFilter = rptSearch.SearchFilter{ Filters: reporters.FieldsFilters{ CompareFilters: utils.TimeRangeFilter("updated_at", start, end), @@ -249,12 +248,11 @@ func getSecretData(ctx context.Context, params sdkUtils.ReportParams) (*Info[mod searchFilter := searchScansFilter(params) var ( - end = time.Now() - start = time.Now() + start = params.FromTimestamp + end = params.ToTimestamp ) - if params.Duration > 0 && len(params.Filters.ScanID) == 0 { - start = end.AddDate(0, 0, -params.Duration) + if !params.FromTimestamp.IsZero() && len(params.Filters.ScanID) == 0 { searchFilter.ScanFilter = rptSearch.SearchFilter{ Filters: reporters.FieldsFilters{ CompareFilters: utils.TimeRangeFilter("updated_at", start, end), @@ -311,12 +309,11 @@ func getMalwareData(ctx context.Context, params sdkUtils.ReportParams) (*Info[mo searchFilter := searchScansFilter(params) var ( - end = time.Now() - start = time.Now() + start = params.FromTimestamp + end = params.ToTimestamp ) - if params.Duration > 0 && len(params.Filters.ScanID) == 0 { - start = end.AddDate(0, 0, -params.Duration) + if !params.FromTimestamp.IsZero() && len(params.Filters.ScanID) == 0 { searchFilter.ScanFilter = rptSearch.SearchFilter{ Filters: reporters.FieldsFilters{ CompareFilters: utils.TimeRangeFilter("updated_at", start, end), @@ -372,12 +369,11 @@ func getComplianceData(ctx context.Context, params sdkUtils.ReportParams) (*Info searchFilter := searchScansFilter(params) var ( - end = time.Now() - start = time.Now() + start = params.FromTimestamp + end = params.ToTimestamp ) - if params.Duration > 0 && len(params.Filters.ScanID) == 0 { - start = end.AddDate(0, 0, -params.Duration) + if !params.FromTimestamp.IsZero() && len(params.Filters.ScanID) == 0 { searchFilter.ScanFilter = rptSearch.SearchFilter{ Filters: reporters.FieldsFilters{ CompareFilters: utils.TimeRangeFilter("updated_at", start, end), @@ -433,12 +429,11 @@ func getCloudComplianceData(ctx context.Context, params sdkUtils.ReportParams) ( searchFilter := searchScansFilter(params) var ( - end = time.Now() - start = time.Now() + start = params.FromTimestamp + end = params.ToTimestamp ) - if params.Duration > 0 && len(params.Filters.ScanID) == 0 { - start = end.AddDate(0, 0, -params.Duration) + if !params.FromTimestamp.IsZero() && len(params.Filters.ScanID) == 0 { searchFilter.ScanFilter = rptSearch.SearchFilter{ Filters: reporters.FieldsFilters{ CompareFilters: utils.TimeRangeFilter("updated_at", start, end),