From 0d1f8c74656c4e2043323b38cadde4e0456d6cfd Mon Sep 17 00:00:00 2001 From: Salim Afiune Date: Fri, 17 Jul 2020 16:18:05 -0600 Subject: [PATCH] =?UTF-8?q?feat(cli):=20Create=20Slack=20Channel=20Alerts?= =?UTF-8?q?=20=F0=9F=9A=A8=20(#165)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Users now can create Slack Channel Alert Integrations via the CLI: ``` $ lacework integration create ? Choose an integration type to create: Slack Channel Alert ▸ Name: #tech-ally-notify ▸ Slack URL: https://hooks.slack.com/services/1234/ABC/abc123 ▸ Alert Severity Level: Critical The integration was created. ``` Signed-off-by: Salim Afiune Maya --- api/integrations_slack_channel.go | 36 ++++++++-- api/integrations_slack_channel_test.go | 4 +- cli/cmd/integration.go | 3 + cli/cmd/integration_slack_channel.go | 96 ++++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 6 deletions(-) create mode 100644 cli/cmd/integration_slack_channel.go diff --git a/api/integrations_slack_channel.go b/api/integrations_slack_channel.go index 66b690001..f293700e6 100644 --- a/api/integrations_slack_channel.go +++ b/api/integrations_slack_channel.go @@ -49,6 +49,35 @@ func NewSlackChannelIntegration(name string, data SlackChannelData) SlackChanInt } } +type SlackAlertLevel int + +const ( + CriticalSlackAlertLevel SlackAlertLevel = 1 + HighSlackAlertLevel SlackAlertLevel = 2 + MediumSlackAlertLevel SlackAlertLevel = 3 + LowSlackAlertLevel SlackAlertLevel = 4 + AllSlackAlertLevel SlackAlertLevel = 5 +) + +// SlackAlertLevels is the list of available slack alert levels +var SlackAlertLevels = map[SlackAlertLevel]string{ + CriticalSlackAlertLevel: "Critical", + HighSlackAlertLevel: "High", + MediumSlackAlertLevel: "Medium", + LowSlackAlertLevel: "Low", + AllSlackAlertLevel: "All", +} + +// String returns the string representation of a slack alert level +func (i SlackAlertLevel) String() string { + return SlackAlertLevels[i] +} + +// Int returns the int representation of a slack alert level +func (i SlackAlertLevel) Int() int { + return int(i) +} + // CreateSlackChannel creates a slack channel alert integration on the Lacework Server func (svc *IntegrationsService) CreateSlackChannel(integration SlackChanIntegration) ( response SlackChanIntResponse, @@ -95,8 +124,7 @@ type SlackChanIntegration struct { } type SlackChannelData struct { - IssueGrouping string `json:"ISSUE_GROUPING,omitempty"` - SlackUrl string `json:"SLACK_URL"` - // TODO: @afiune to convert to an actual ENUM - MinAlertSeverity int `json:"MIN_ALERT_SEVERITY"` + IssueGrouping string `json:"ISSUE_GROUPING,omitempty"` + SlackUrl string `json:"SLACK_URL"` + MinAlertSeverity SlackAlertLevel `json:"MIN_ALERT_SEVERITY"` } diff --git a/api/integrations_slack_channel_test.go b/api/integrations_slack_channel_test.go index 7c6e6cd51..67dd26e39 100644 --- a/api/integrations_slack_channel_test.go +++ b/api/integrations_slack_channel_test.go @@ -88,7 +88,7 @@ func TestIntegrationsCreateSlackChannel(t *testing.T) { assert.Equal(t, "integration_name", resData.Name) assert.True(t, resData.State.Ok) assert.Equal(t, "https://hooks.slack.com/services/ABCD/12345/abcd1234", resData.Data.SlackUrl) - assert.Equal(t, 3, resData.Data.MinAlertSeverity) + assert.Equal(t, api.SlackAlertLevel(3), resData.Data.MinAlertSeverity) } } @@ -120,7 +120,7 @@ func TestIntegrationsGetSlackChannel(t *testing.T) { assert.Equal(t, "integration_name", resData.Name) assert.True(t, resData.State.Ok) assert.Equal(t, "https://hooks.slack.com/services/ABCD/12345/abcd1234", resData.Data.SlackUrl) - assert.Equal(t, 3, resData.Data.MinAlertSeverity) + assert.Equal(t, api.SlackAlertLevel(3), resData.Data.MinAlertSeverity) } } diff --git a/cli/cmd/integration.go b/cli/cmd/integration.go index a76d40488..59a596362 100644 --- a/cli/cmd/integration.go +++ b/cli/cmd/integration.go @@ -183,6 +183,7 @@ func promptCreateIntegration() error { prompt = &survey.Select{ Message: "Choose an integration type to create: ", Options: []string{ + "Slack Channel Alert", "Docker Hub", "AWS Config", "AWS CloudTrail", @@ -203,6 +204,8 @@ func promptCreateIntegration() error { } switch integration { + case "Slack Channel Alert": + return createSlackChannelIntegration() case "Docker Hub": return createDockerHubIntegration() case "AWS Config": diff --git a/cli/cmd/integration_slack_channel.go b/cli/cmd/integration_slack_channel.go new file mode 100644 index 000000000..17aea9d88 --- /dev/null +++ b/cli/cmd/integration_slack_channel.go @@ -0,0 +1,96 @@ +// +// Author:: Salim Afiune Maya () +// Copyright:: Copyright 2020, Lacework Inc. +// License:: Apache License, Version 2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package cmd + +import ( + "github.com/AlecAivazis/survey/v2" + + "github.com/lacework/go-sdk/api" +) + +func createSlackChannelIntegration() error { + questions := []*survey.Question{ + { + Name: "name", + Prompt: &survey.Input{Message: "Name: "}, + Validate: survey.Required, + }, + { + Name: "url", + Prompt: &survey.Input{Message: "Slack URL: "}, + Validate: survey.Required, + }, + { + Name: "alert_severity_level", + Prompt: &survey.Select{ + Message: "Alert Severity Level: ", + Options: []string{ + "Critical", + "High and above", + "Medium and above", + "Low and above", + "All", + }, + }, + Validate: survey.Required, + }, + } + + answers := struct { + Name string + Url string + AlertSeverity string `survey:"alert_severity_level"` + }{} + + err := survey.Ask(questions, &answers, + survey.WithIcons(promptIconsFunc), + ) + if err != nil { + return err + } + + slack := api.NewSlackChannelIntegration(answers.Name, + api.SlackChannelData{ + SlackUrl: answers.Url, + MinAlertSeverity: alertSeverityToEnum(answers.AlertSeverity), + }, + ) + + cli.StartProgress(" Creating integration...") + _, err = cli.LwApi.Integrations.CreateSlackChannel(slack) + cli.StopProgress() + return err +} + +func alertSeverityToEnum(level string) api.SlackAlertLevel { + switch level { + case "Critical": + return api.CriticalSlackAlertLevel + case "High and above": + return api.HighSlackAlertLevel + case "Medium and above": + return api.MediumSlackAlertLevel + case "Low and above": + return api.LowSlackAlertLevel + case "All": + return api.AllSlackAlertLevel + default: + return api.MediumSlackAlertLevel + } +}