Skip to content

Commit 42e0309

Browse files
authored
feat(cli): new open event command (#197)
Users can now use this new command to do further investigation on an event: ``` $ lacework event open 123 ``` Additionally, we now display a URL at the end of the command: ``` $ lacework event show 123 ... For further investigation of this event navigate to https://account.lacework.net/ui/investigation/recents/EventDossier-123 ``` Closes #194 Signed-off-by: Salim Afiune Maya <[email protected]>
1 parent 00de7f7 commit 42e0309

File tree

2 files changed

+65
-3
lines changed

2 files changed

+65
-3
lines changed

cli/cmd/event.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ package cmd
2020

2121
import (
2222
"fmt"
23+
"os/exec"
24+
"runtime"
2325
"sort"
26+
"strconv"
2427
"strings"
2528
"time"
2629

@@ -175,6 +178,46 @@ For example, to list all events from the last day with severity medium and above
175178
cli.OutputHuman("\n")
176179
cli.OutputHuman(entityTable)
177180
}
181+
182+
cli.OutputHuman(
183+
"\nFor further investigation of this event navigate to %s\n",
184+
eventLinkBuilder(args[0]),
185+
)
186+
return nil
187+
},
188+
}
189+
190+
// eventOpenCmd represents the open sub-command inside the event command
191+
eventOpenCmd = &cobra.Command{
192+
Use: "open <event_id>",
193+
Short: "open a specified event in a web browser",
194+
Long: "Open a specified event in a web browser.",
195+
Args: cobra.ExactArgs(1),
196+
RunE: func(_ *cobra.Command, args []string) error {
197+
// Event IDs should be only numeric values
198+
if _, err := strconv.Atoi(args[0]); err != nil {
199+
return errors.Errorf("invalid event id %s. Event id should be a numeric value", args[0])
200+
}
201+
202+
var (
203+
err error
204+
url = eventLinkBuilder(args[0])
205+
)
206+
207+
switch runtime.GOOS {
208+
case "linux":
209+
err = exec.Command("xdg-open", url).Start()
210+
case "windows":
211+
err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
212+
case "darwin":
213+
err = exec.Command("open", url).Start()
214+
default:
215+
err = fmt.Errorf("unsupported platform\n\nNavigate to %s", url)
216+
}
217+
if err != nil {
218+
return errors.Wrap(err, "unable to open web browser")
219+
}
220+
178221
return nil
179222
},
180223
}
@@ -209,6 +252,13 @@ func init() {
209252
)
210253

211254
eventCmd.AddCommand(eventShowCmd)
255+
eventCmd.AddCommand(eventOpenCmd)
256+
}
257+
258+
// Generates a URL similar to:
259+
// => https://account.lacework.net/ui/investigate/recents/EventDossier-123
260+
func eventLinkBuilder(id string) string {
261+
return fmt.Sprintf("https://%s.lacework.net/ui/investigation/recents/EventDossier-%s", cli.Account, id)
212262
}
213263

214264
func eventsToTableReport(events []api.Event) string {

integration/event_test.go

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

61-
func TestEventCommandListDays(t *testing.T) {
61+
func TestEventCommandList3Days(t *testing.T) {
6262
// @afiune could we find a way to generate a consistent event? but if we do
6363
// wouldn't the ML learn it and then become a known behavior? uhmmm
6464
// for now we will just check that we have the headers :wink:
65-
out, err, exitcode := LaceworkCLIWithTOMLConfig("event", "list", "--days", "1")
65+
out, err, exitcode := LaceworkCLIWithTOMLConfig("event", "list", "--days", "3")
6666
assert.Contains(t, out.String(), "EVENT ID",
6767
"STDOUT table headers changed, please check")
6868
assert.Contains(t, out.String(), "TYPE",
@@ -94,7 +94,7 @@ func TestEventCommandListSeverityError(t *testing.T) {
9494
func TestEventCommandListTimeRange(t *testing.T) {
9595
var (
9696
now = time.Now().UTC()
97-
from = now.AddDate(0, 0, -1) // 1 days from now
97+
from = now.AddDate(0, 0, -2) // 2 days from now
9898
)
9999

100100
out, err, exitcode := LaceworkCLIWithTOMLConfig("event", "list", "--start", from.Format(time.RFC3339), "--end", now.Format(time.RFC3339))
@@ -114,3 +114,15 @@ func TestEventCommandListTimeRange(t *testing.T) {
114114
assert.Equal(t, 0, exitcode,
115115
"EXITCODE is not the expected one")
116116
}
117+
118+
func TestEventCommandOpenError(t *testing.T) {
119+
out, err, exitcode := LaceworkCLIWithTOMLConfig("event", "open", "123abc")
120+
assert.Contains(t, err.String(),
121+
"ERROR invalid event id 123abc. Event id should be a numeric value",
122+
"STDERR the error message changed, update")
123+
assert.Empty(t,
124+
out.String(),
125+
"STDOUT should be empty")
126+
assert.Equal(t, 1, exitcode,
127+
"EXITCODE is not the expected one")
128+
}

0 commit comments

Comments
 (0)