Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support sending scan summary & link #2229

Merged
merged 7 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions deepfence_server/constants/api-messages/success.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ const (
ErrIntegrationTypeCannotBeUpdated = "integration type cannot be updated"
ErrIntegrationTypeEmpty = "integration type cannot be empty"
ErrNotificationTypeEmpty = "notification type cannot be empty"
ErrSendSummaryNotSupported = "notification type does not support sending summary links"
)
2 changes: 1 addition & 1 deletion deepfence_server/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ require (
github.com/segmentio/asm v1.2.0 // indirect
github.com/sendgrid/sendgrid-go v3.14.0+incompatible
github.com/shopspring/decimal v1.2.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/cast v1.6.0
github.com/spf13/pflag v1.0.5 // indirect
github.com/swaggest/jsonschema-go v0.3.64 // indirect
github.com/swaggest/refl v1.3.0 // indirect
Expand Down
12 changes: 12 additions & 0 deletions deepfence_server/handler/integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ func (h *Handler) AddIntegration(w http.ResponseWriter, r *http.Request) {
return
}

if req.SendSummary {
if integration.SupportsSummaryLink(req.IntegrationType) {
req.Config["send_summary"] = True
ibreakthecloud marked this conversation as resolved.
Show resolved Hide resolved
} else {
err = httpext.JSON(w, http.StatusBadRequest, model.ErrorResponse{Message: api_messages.ErrSendSummaryNotSupported})
if err != nil {
log.Error().Msg(err.Error())
}
return
}
}

req.Config["filter_hash"], err = GetFilterHash(req.Filters)
if err != nil {
log.Error().Msgf("%v", err)
Expand Down
1 change: 1 addition & 0 deletions deepfence_server/model/integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type IntegrationAddReq struct {
IntegrationType string `json:"integration_type" required:"true"`
NotificationType string `json:"notification_type" required:"true"`
Filters IntegrationFilters `json:"filters"`
SendSummary bool `json:"send_summary"`
}

type IntegrationFilters struct {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,3 +433,7 @@ func (a AwsSecurityHub) mapPayloadToFindings(msg []map[string]interface{}, resou
func (a AwsSecurityHub) IsValidCredential(ctx context.Context) (bool, error) {
return true, nil
}

func (a AwsSecurityHub) SendSummaryLink() bool {
return false
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,7 @@ func (e ElasticSearch) IsValidCredential(ctx context.Context) (bool, error) {

return true, nil
}

func (e ElasticSearch) SendSummaryLink() bool {
return false
}
78 changes: 30 additions & 48 deletions deepfence_server/pkg/integration/email/email.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (
"encoding/json"
"errors"
"fmt"
"sort"
"strconv"
"strings"

"github.com/deepfence/ThreatMapper/deepfence_server/model"
Expand Down Expand Up @@ -35,69 +33,49 @@ func New(ctx context.Context, b []byte) (*Email, error) {
return &h, nil
}

func (e Email) FormatMessage(message []map[string]interface{}) string {
var entiremsg strings.Builder
entiremsg.WriteString("*")
entiremsg.WriteString(e.Resource)
entiremsg.WriteString("*\n\n")

// Prepare the sorted keys so that the output has the records in same order
var keys []string
if len(message) > 0 {
keys = make([]string, 0, len(message[0]))
for key := range message[0] {
keys = append(keys, key)
}
func (e Email) FormatMessage(message []map[string]interface{},
extras map[string]interface{}) (string, map[string][]byte) {

sort.Strings(keys)
}
var msg strings.Builder
var attachments = map[string][]byte{}

for k, v := range message {
entiremsg.WriteString("#")
entiremsg.WriteString(strconv.Itoa(k + 1))
entiremsg.WriteString("\n")
for _, key := range keys {
if val, ok := v[key]; ok {
fmtVal := ""
if val != nil {
fmtVal = fmt.Sprintf("%v", val)
for k, v := range extras {
if v != "" {
if k == "severity_counts" {
s := ""
for i, j := range v.(map[string]int32) {
s = fmt.Sprintf(" %s: %d\r\n", i, j)
}
entiremsg.WriteString(key)
entiremsg.WriteString(": ")
entiremsg.WriteString(fmtVal)
entiremsg.WriteString("\n")
delete(v, key)
msg.WriteString(fmt.Sprintf("%s:\r\n%s", k, s))
} else {
msg.WriteString(fmt.Sprintf("%s: %v\r\n", k, v))
}
}
}

// This is to handle if we have unprocessed data in the map
// Possilbe if all the records are not uniform
for key, val := range v {
fmtVal := ""
if val != nil {
fmtVal = fmt.Sprintf("%v", val)
}
entiremsg.WriteString(key)
entiremsg.WriteString(": ")
entiremsg.WriteString(fmtVal)
entiremsg.WriteString("\n")
}
entiremsg.WriteString("\n")
r, err := json.Marshal(message)
if err != nil {
log.Error().Err(err).Msg("failed to marshal results")
}
return entiremsg.String()

attachments["scan-results.json"] = r

return msg.String(), attachments
}

func (e Email) SendNotification(ctx context.Context, message []map[string]interface{}, extras map[string]interface{}) error {
func (e Email) SendNotification(ctx context.Context,
message []map[string]interface{}, extras map[string]interface{}) error {

_, span := telemetry.NewSpan(ctx, "integrations", "email-send-notification")
defer span.End()

m := e.FormatMessage(message)
m, a := e.FormatMessage(message, extras)
emailSender, err := sendemail.NewEmailSender(ctx)
if err != nil {
return err
}
return emailSender.Send([]string{e.Config.EmailID}, "Deepfence Subscription", m, "", nil)
return emailSender.Send([]string{e.Config.EmailID},
fmt.Sprintf("Deepfence %s Subscription", e.Resource), m, "", a)
}

func (e Email) IsEmailConfigured(ctx context.Context) bool {
Expand Down Expand Up @@ -127,3 +105,7 @@ func (e Email) IsEmailConfigured(ctx context.Context) bool {
func (e Email) IsValidCredential(ctx context.Context) (bool, error) {
return true, nil
}

func (e Email) SendSummaryLink() bool {
return e.Config.SendSummary
}
3 changes: 2 additions & 1 deletion deepfence_server/pkg/integration/email/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ type Email struct {
}

type Config struct {
EmailID string `json:"email_id" validate:"required,email" required:"true"`
EmailID string `json:"email_id" validate:"required,email" required:"true"`
SendSummary bool `json:"send_summary"`
}

func (e Email) ValidateConfig(validate *validator.Validate) error {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,7 @@ func (g GoogleChronicle) SendNotification(ctx context.Context, message []map[str
func (g GoogleChronicle) IsValidCredential(ctx context.Context) (bool, error) {
return true, nil
}

func (g GoogleChronicle) SendSummaryLink() bool {
return false
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,7 @@ func (h HTTPEndpoint) IsValidCredential(ctx context.Context) (bool, error) {
// Check the response status code.
return resp.StatusCode == http.StatusOK, nil
}

func (h HTTPEndpoint) SendSummaryLink() bool {
return false
}
18 changes: 16 additions & 2 deletions deepfence_server/pkg/integration/integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,31 @@ func GetIntegration(ctx context.Context, integrationType string, b []byte) (Inte
func IsMessagingFormat(integrationType string) bool {
retVal := false
switch integrationType {
case constants.Slack, constants.Teams, constants.PagerDuty,
constants.Email, constants.Jira:
case constants.Slack,
constants.Teams,
constants.PagerDuty,
constants.Email,
constants.Jira:
retVal = true
}
return retVal
}

func SupportsSummaryLink(integrationType string) bool {
switch integrationType {
case constants.Slack,
constants.Teams:
return true
}
return false
}

// Integration is the interface for all integrations
type Integration interface {
// extras are additional fields that are not part of the message
// if SendSummaryLink is true then message array is expected to be scan summay
SendNotification(ctx context.Context, message []map[string]interface{}, extras map[string]interface{}) error
ValidateConfig(*validator.Validate) error
IsValidCredential(ctx context.Context) (bool, error)
SendSummaryLink() bool
}
14 changes: 13 additions & 1 deletion deepfence_server/pkg/integration/jira/jira.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,15 @@ func (j Jira) SendNotification(ctx context.Context, message []map[string]interfa
extraStr := []string{}
for k, v := range extras {
if v != "" {
extraStr = append(extraStr, fmt.Sprintf("%s: %v", k, v))
if k == "severity_counts" {
s := ""
for i, j := range v.(map[string]int32) {
s = fmt.Sprintf(" %s: %d\n", i, j)
}
extraStr = append(extraStr, fmt.Sprintf("%s:\n%s", k, s))
} else {
extraStr = append(extraStr, fmt.Sprintf("%s: %v\n", k, v))
}
}
}

Expand Down Expand Up @@ -168,3 +176,7 @@ func (j Jira) IsValidCredential(ctx context.Context) (bool, error) {

return true, nil
}

func (j Jira) SendSummaryLink() bool {
return false
}
4 changes: 4 additions & 0 deletions deepfence_server/pkg/integration/pagerduty/pagerduty.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,7 @@ func IsValidCreds(p PagerDuty) (bool, error) {
func (p PagerDuty) IsValidCredential(ctx context.Context) (bool, error) {
return true, nil
}

func (p PagerDuty) SendSummaryLink() bool {
return false
}
4 changes: 4 additions & 0 deletions deepfence_server/pkg/integration/s3/s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,7 @@ func (s S3) IsValidCredential(ctx context.Context) (bool, error) {

return true, nil
}

func (s S3) SendSummaryLink() bool {
return false
}
Loading
Loading