Skip to content

Commit 00de7f7

Browse files
authored
Merge pull request #196 from lacework/afiune/195/events-flags
feat: add event flags --severity and --days
2 parents c28ca2d + 2d8fdf4 commit 00de7f7

File tree

4 files changed

+140
-12
lines changed

4 files changed

+140
-12
lines changed

api/events.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ type EventsService struct {
3131
client *Client
3232
}
3333

34+
// ValidEventSeverities is a list of all valid event severities
35+
var ValidEventSeverities = []string{"critical", "high", "medium", "low", "info"}
36+
3437
// List leverages ListDateRange and returns a list of events from the last 7 days
3538
func (svc *EventsService) List() (EventsResponse, error) {
3639
var (

cli/cmd/event.go

Lines changed: 102 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ var (
3939

4040
// end time for listing events
4141
End string
42+
43+
// list events from an specific number of days
44+
Days int
45+
46+
// list events with a specific severity
47+
Severity string
4248
}{}
4349

4450
// easily add or remove borders to all event details tables
@@ -55,18 +61,33 @@ var (
5561
// eventListCmd represents the list sub-command inside the event command
5662
eventListCmd = &cobra.Command{
5763
Use: "list",
58-
Short: "list all events from a date range (default last 7 days)",
59-
Long: `
60-
List all events from a time range, by default this command displays the
61-
events from the last 7 days, but it is possible to specify a different
62-
time range.`,
64+
Short: "list all events (default last 7 days)",
65+
Long: `List all events for the last 7 days by default, or pass --start and --end to
66+
specify a custom time period. You can also pass --serverity to filter by a
67+
severity threshold.
68+
69+
Additionally, pass --days to list events for a specified number of days.
70+
71+
For example, to list all events from the last day with severity medium and above
72+
(Critical, High and Medium) run:
73+
74+
$ lacework events list --severity medium --days 1`,
6375
Args: cobra.NoArgs,
6476
RunE: func(_ *cobra.Command, _ []string) error {
6577

6678
var (
6779
response api.EventsResponse
6880
err error
6981
)
82+
83+
if eventsCmdState.Severity != "" {
84+
if !array.ContainsStr(api.ValidEventSeverities, eventsCmdState.Severity) {
85+
return errors.Errorf("the severity %s is not valid, use one of %s",
86+
eventsCmdState.Severity, strings.Join(api.ValidEventSeverities, ", "),
87+
)
88+
}
89+
}
90+
7091
if eventsCmdState.Start != "" || eventsCmdState.End != "" {
7192
start, end, errT := parseStartAndEndTime(eventsCmdState.Start, eventsCmdState.End)
7293
if errT != nil {
@@ -77,6 +98,14 @@ time range.`,
7798
"start_time", start, "end_time", end,
7899
)
79100
response, err = cli.LwApi.Events.ListDateRange(start, end)
101+
} else if eventsCmdState.Days != 0 {
102+
end := time.Now()
103+
start := end.Add(time.Hour * 24 * time.Duration(eventsCmdState.Days) * -1)
104+
105+
cli.Log.Infow("requesting list of events from specific days",
106+
"days", eventsCmdState.Days, "start_time", start, "end_time", end,
107+
)
108+
response, err = cli.LwApi.Events.ListDateRange(start, end)
80109
} else {
81110
cli.Log.Info("requesting list of events from the last 7 days")
82111
response, err = cli.LwApi.Events.List()
@@ -87,16 +116,30 @@ time range.`,
87116
}
88117

89118
cli.Log.Debugw("events", "raw", response)
90-
// Sort the events from the response by severity
91-
sort.Slice(response.Events, func(i, j int) bool {
92-
return response.Events[i].Severity < response.Events[j].Severity
119+
120+
// filter events by severity, if the user didn't specify a severity
121+
// the funtion will return it back without modifications
122+
events := filterEventsWithSeverity(response.Events)
123+
124+
// Sort the events by severity
125+
sort.Slice(events, func(i, j int) bool {
126+
return events[i].Severity < events[j].Severity
93127
})
94128

95129
if cli.JSONOutput() {
96-
return cli.OutputJSON(response.Events)
130+
return cli.OutputJSON(events)
97131
}
98132

99-
cli.OutputHuman(eventsToTableReport(response.Events))
133+
if len(events) == 0 {
134+
if eventsCmdState.Severity != "" {
135+
cli.OutputHuman("There are no events with the specified severity.\n")
136+
} else {
137+
cli.OutputHuman("There are no events in your account in the specified time range.\n")
138+
}
139+
return nil
140+
}
141+
142+
cli.OutputHuman(eventsToTableReport(events))
100143
return nil
101144
},
102145
}
@@ -152,6 +195,18 @@ func init() {
152195
eventListCmd.Flags().StringVar(&eventsCmdState.End,
153196
"end", "", "end of the time range in UTC (format: yyyy-MM-ddTHH:mm:ssZ)",
154197
)
198+
// add days flag to events list command
199+
eventListCmd.Flags().IntVar(&eventsCmdState.Days,
200+
"days", 0, "list events for specified number of days (max: 7 days)",
201+
)
202+
// add severity flag to events list command
203+
eventListCmd.Flags().StringVar(&eventsCmdState.Severity,
204+
"severity", "",
205+
fmt.Sprintf(
206+
"filter events by severity threshold (%s)",
207+
strings.Join(api.ValidEventSeverities, ", "),
208+
),
209+
)
155210

156211
eventCmd.AddCommand(eventShowCmd)
157212
}
@@ -899,3 +954,40 @@ func eventMachineEntitiesTable(machines []api.EventMachineEntity) string {
899954

900955
return r.String()
901956
}
957+
958+
func filterEventsWithSeverity(events []api.Event) []api.Event {
959+
if eventsCmdState.Severity == "" {
960+
return events
961+
}
962+
963+
sevThreshold, sevString := eventSeverityToProperTypes(eventsCmdState.Severity)
964+
cli.Log.Debugw("filtering events", "threshold", sevThreshold, "severity", sevString)
965+
eFiltered := []api.Event{}
966+
for _, event := range events {
967+
eventSeverity, _ := eventSeverityToProperTypes(event.Severity)
968+
if eventSeverity <= sevThreshold {
969+
eFiltered = append(eFiltered, event)
970+
}
971+
}
972+
973+
cli.Log.Debugw("filtered events", "events", eFiltered)
974+
975+
return eFiltered
976+
}
977+
978+
func eventSeverityToProperTypes(severity string) (int, string) {
979+
switch strings.ToLower(severity) {
980+
case "1", "critical":
981+
return 1, "Critical"
982+
case "2", "high":
983+
return 2, "High"
984+
case "3", "medium":
985+
return 3, "Medium"
986+
case "4", "low":
987+
return 4, "Low"
988+
case "5", "info":
989+
return 5, "Info"
990+
default:
991+
return 6, "Unknown"
992+
}
993+
}

cli/cmd/integration.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,8 +294,8 @@ func buildIntDetailsTable(integrations []api.RawIntegration) string {
294294
if len(integrations) != 0 {
295295
integration := integrations[0]
296296
t.AppendBulk(reflectIntegrationData(integration))
297-
t.Append([]string{"UPDATE AT", integration.CreatedOrUpdatedTime})
298-
t.Append([]string{"UPDATE BY", integration.CreatedOrUpdatedBy})
297+
t.Append([]string{"UPDATED AT", integration.CreatedOrUpdatedTime})
298+
t.Append([]string{"UPDATED BY", integration.CreatedOrUpdatedBy})
299299
t.AppendBulk(buildIntegrationState(integration.State))
300300
}
301301
t.Render()

integration/event_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,39 @@ func TestEventCommandList(t *testing.T) {
5858
"EXITCODE is not the expected one")
5959
}
6060

61+
func TestEventCommandListDays(t *testing.T) {
62+
// @afiune could we find a way to generate a consistent event? but if we do
63+
// wouldn't the ML learn it and then become a known behavior? uhmmm
64+
// for now we will just check that we have the headers :wink:
65+
out, err, exitcode := LaceworkCLIWithTOMLConfig("event", "list", "--days", "1")
66+
assert.Contains(t, out.String(), "EVENT ID",
67+
"STDOUT table headers changed, please check")
68+
assert.Contains(t, out.String(), "TYPE",
69+
"STDOUT table headers changed, please check")
70+
assert.Contains(t, out.String(), "SEVERITY",
71+
"STDOUT table headers changed, please check")
72+
assert.Contains(t, out.String(), "START TIME",
73+
"STDOUT table headers changed, please check")
74+
assert.Contains(t, out.String(), "END TIME",
75+
"STDOUT table headers changed, please check")
76+
assert.Empty(t,
77+
err.String(),
78+
"STDERR should be empty")
79+
assert.Equal(t, 0, exitcode,
80+
"EXITCODE is not the expected one")
81+
}
82+
83+
func TestEventCommandListSeverityError(t *testing.T) {
84+
out, err, exitcode := LaceworkCLIWithTOMLConfig("event", "list", "--severity", "foo")
85+
assert.Contains(t, err.String(), "ERROR the severity foo is not valid, use one of critical, high, medium, low, info",
86+
"STDERR the message to the user has changed, update please")
87+
assert.Empty(t,
88+
out.String(),
89+
"STDOUT should be empty")
90+
assert.Equal(t, 1, exitcode,
91+
"EXITCODE is not the expected one")
92+
}
93+
6194
func TestEventCommandListTimeRange(t *testing.T) {
6295
var (
6396
now = time.Now().UTC()

0 commit comments

Comments
 (0)