Skip to content

Commit 5dc1352

Browse files
authored
feat: Better formatted output for detected events. (#573)
* feat: Better formatted output for detected events. Signed-off-by: Simarpreet Singh <[email protected]> * fix: Format time as UTC in RFC3339 Signed-off-by: Simarpreet Singh <[email protected]> * fix: Add a testcase for unsupport input event Signed-off-by: Simarpreet Singh <[email protected]> * feat: Include signature ID in detection output Signed-off-by: Simarpreet Singh <[email protected]> * feat: Rework fields for display Signed-off-by: Simarpreet Singh <[email protected]>
1 parent 28fbc66 commit 5dc1352

File tree

3 files changed

+125
-3
lines changed

3 files changed

+125
-3
lines changed

tracee-rules/main.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,23 @@ import (
77
"os"
88
"os/signal"
99
"syscall"
10+
"time"
1011

1112
"github.com/aquasecurity/tracee/tracee-rules/engine"
1213
"github.com/urfave/cli/v2"
1314
)
1415

16+
type Clock interface {
17+
Now() time.Time
18+
}
19+
20+
type realClock struct {
21+
}
22+
23+
func (realClock) Now() time.Time {
24+
return time.Now()
25+
}
26+
1527
func main() {
1628
app := &cli.App{
1729
Name: "tracee-rules",
@@ -56,7 +68,7 @@ func main() {
5668
if inputs == (engine.EventSources{}) {
5769
return err
5870
}
59-
output, err := setupOutput(c.String("webhook"))
71+
output, err := setupOutput(os.Stdout, realClock{}, c.String("webhook"))
6072
if err != nil {
6173
return err
6274
}

tracee-rules/output.go

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"encoding/json"
55
"fmt"
6+
"io"
67
"log"
78
"net/http"
89
"strings"
@@ -12,11 +13,36 @@ import (
1213
"github.com/aquasecurity/tracee/tracee-rules/types"
1314
)
1415

15-
func setupOutput(webhook string) (chan types.Finding, error) {
16+
const DetectionOutput string = `
17+
*** Detection ***
18+
Time: %s
19+
Signature ID: %s
20+
Signature: %s
21+
Data: %s
22+
Command: %s
23+
Hostname: %s
24+
`
25+
26+
func setupOutput(resultWriter io.Writer, clock Clock, webhook string) (chan types.Finding, error) {
1627
out := make(chan types.Finding)
1728
go func() {
1829
for res := range out {
19-
fmt.Printf("%+v\n", res)
30+
sigMetadata, err := res.Signature.GetMetadata()
31+
if err != nil {
32+
log.Println("invalid signature metadata: ", err)
33+
continue
34+
}
35+
36+
switch res.Context.(type) {
37+
case tracee.Event:
38+
command := res.Context.(tracee.Event).ProcessName
39+
hostName := res.Context.(tracee.Event).HostName
40+
fmt.Fprintf(resultWriter, DetectionOutput, clock.Now().UTC().Format(time.RFC3339), sigMetadata.ID, sigMetadata.Name, res.Data, command, hostName)
41+
default:
42+
log.Printf("unsupported event detected: %T\n", res.Context)
43+
continue
44+
}
45+
2046
if webhook != "" {
2147
payload, err := prepareJSONPayload(res)
2248
if err != nil {

tracee-rules/output_test.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"testing"
6+
"time"
7+
8+
"github.com/aquasecurity/tracee/tracee-ebpf/tracee/external"
9+
10+
"github.com/aquasecurity/tracee/tracee-rules/types"
11+
"github.com/stretchr/testify/assert"
12+
13+
"github.com/stretchr/testify/require"
14+
)
15+
16+
type fakeClock struct {
17+
}
18+
19+
func (fakeClock) Now() time.Time {
20+
return time.Unix(1614045297, 0)
21+
}
22+
23+
type fakeSignature struct {
24+
types.Signature
25+
}
26+
27+
func (f fakeSignature) GetMetadata() (types.SignatureMetadata, error) {
28+
return types.SignatureMetadata{
29+
ID: "FOO-666",
30+
Name: "foo bar signature",
31+
Description: "the most evil",
32+
}, nil
33+
}
34+
35+
func Test_setupOutput(t *testing.T) {
36+
var testCases = []struct {
37+
name string
38+
inputContext interface{}
39+
expectedOutput string
40+
}{
41+
{
42+
name: "happy path with tracee event",
43+
inputContext: external.Event{
44+
Timestamp: 12345678,
45+
ProcessName: "foobar.exe",
46+
HostName: "foobar.local",
47+
},
48+
expectedOutput: `
49+
*** Detection ***
50+
Time: 2021-02-23T01:54:57Z
51+
Signature ID: FOO-666
52+
Signature: foo bar signature
53+
Data: map[foo1:bar1, baz1 foo2:[bar2 baz2]]
54+
Command: foobar.exe
55+
Hostname: foobar.local
56+
`,
57+
},
58+
{
59+
name: "sad path with unknown context",
60+
inputContext: struct {
61+
foo string
62+
}{foo: "bad input context"},
63+
expectedOutput: ``,
64+
},
65+
}
66+
67+
for _, tc := range testCases {
68+
var actualOutput bytes.Buffer
69+
findingCh, err := setupOutput(&actualOutput, fakeClock{}, "")
70+
require.NoError(t, err, tc.name)
71+
72+
findingCh <- types.Finding{
73+
Data: map[string]interface{}{
74+
"foo1": "bar1, baz1",
75+
"foo2": []string{"bar2", "baz2"},
76+
},
77+
Context: tc.inputContext,
78+
Signature: fakeSignature{},
79+
}
80+
81+
time.Sleep(time.Millisecond)
82+
assert.Equal(t, tc.expectedOutput, actualOutput.String(), tc.name)
83+
}
84+
}

0 commit comments

Comments
 (0)