feat(go): advance validation sidecar toward production
This commit is contained in:
parent
6a06eba255
commit
f85c2e831a
92 changed files with 8881 additions and 91 deletions
121
go-agent/internal/events/pipeline.go
Normal file
121
go-agent/internal/events/pipeline.go
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package events
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"codeberg.org/anassaeneroi/enodia-sentinal/go-agent/internal/model"
|
||||
)
|
||||
|
||||
type EventKind string
|
||||
|
||||
const (
|
||||
ExecKind EventKind = "exec"
|
||||
SyscallKind EventKind = "syscall"
|
||||
HostKind EventKind = "host"
|
||||
)
|
||||
|
||||
// RuleSet is the transport-independent destination for every live or replayed
|
||||
// kernel event. A cilium/ebpf source only needs to decode into these records;
|
||||
// it does not need to know rule details or alert schemas.
|
||||
type RuleSet struct {
|
||||
Exec ExecRuleEngine
|
||||
Syscall SyscallRuleEngine
|
||||
Host HostRuleEngine
|
||||
}
|
||||
|
||||
func NewRuleSet(exec ExecRuleEngine) RuleSet {
|
||||
return RuleSet{
|
||||
Exec: exec, Syscall: DefaultSyscallRuleEngine(), Host: DefaultHostRuleEngine(),
|
||||
}
|
||||
}
|
||||
|
||||
func (r RuleSet) MatchJSON(raw []byte) ([]model.Alert, error) {
|
||||
kind, err := eventKind(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch kind {
|
||||
case ExecKind:
|
||||
var event ExecEvent
|
||||
if err := json.Unmarshal(raw, &event); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r.Exec.Match(event), nil
|
||||
case SyscallKind:
|
||||
var event SyscallEvent
|
||||
if err := json.Unmarshal(raw, &event); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r.Syscall.Match(event), nil
|
||||
case HostKind:
|
||||
var event HostEvent
|
||||
if err := json.Unmarshal(raw, &event); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r.Host.Match(event), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("event JSON must be an exec, syscall, or host event")
|
||||
}
|
||||
}
|
||||
|
||||
func eventKind(raw []byte) (EventKind, error) {
|
||||
var values map[string]any
|
||||
if err := json.Unmarshal(raw, &values); err != nil {
|
||||
return "", err
|
||||
}
|
||||
explicit := strings.ToLower(stringValue(firstValue(values, "event", "type")))
|
||||
switch explicit {
|
||||
case "exec", "execve":
|
||||
return ExecKind, nil
|
||||
case "syscall", "sys":
|
||||
return SyscallKind, nil
|
||||
case "tcp_connect", "bind", "listen", "accept", "file_write",
|
||||
"chmod", "chown", "setuid", "setgid", "capset", "module_load":
|
||||
return HostKind, nil
|
||||
}
|
||||
if _, ok := values["filename"]; ok {
|
||||
return ExecKind, nil
|
||||
}
|
||||
if _, ok := values["argv"]; ok {
|
||||
return ExecKind, nil
|
||||
}
|
||||
if _, ok := values["parent_comm"]; ok {
|
||||
return ExecKind, nil
|
||||
}
|
||||
if _, ok := values["syscall"]; ok {
|
||||
return SyscallKind, nil
|
||||
}
|
||||
if _, ok := values["args"]; ok {
|
||||
return SyscallKind, nil
|
||||
}
|
||||
return "", fmt.Errorf("event JSON must be an exec, syscall, or host event")
|
||||
}
|
||||
|
||||
// ScanJSONL feeds non-empty lines to the matcher callback with line-numbered
|
||||
// errors. Scanner capacity is raised for long argv or future module metadata.
|
||||
func ScanJSONL(reader io.Reader, consume func([]byte) error) error {
|
||||
scanner := bufio.NewScanner(reader)
|
||||
scanner.Buffer(make([]byte, 64*1024), 1024*1024)
|
||||
line := 0
|
||||
for scanner.Scan() {
|
||||
line++
|
||||
raw := bytesTrimSpace(scanner.Bytes())
|
||||
if len(raw) == 0 {
|
||||
continue
|
||||
}
|
||||
if err := consume(raw); err != nil {
|
||||
return fmt.Errorf("event stream line %d: %w", line, err)
|
||||
}
|
||||
}
|
||||
return scanner.Err()
|
||||
}
|
||||
|
||||
func bytesTrimSpace(value []byte) []byte {
|
||||
return []byte(strings.TrimSpace(string(value)))
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue