mirror of
https://github.com/mariocandela/beelzebub.git
synced 2025-07-01 18:47:26 -04:00
Feature: Enhance Performance, Logging & Stability: Precompile Regex, Command Matching, Golang 1.24, History Cleanup & memLimitMiB Flag. (#182)
* Feat: Add support for logging which "command" was matched for SSH and HTTP strategies. * Feat: Convert to precompiling regexp at config load time. This allows for errors to be presented to the user during startup, and provides better performance for complex regexp. * Feat:Bump Golang version to latest stable 1.24 * Feat: Add a cleanup routine for HistoryStore, default TTL for events is 1 hour since last interaction. * Feat: Add new command line flag "memLimitMiB" with a default value of 100. --------- Signed-off-by: Bryan Nolen <bryan@arc.net.au> Signed-off-by: Mario Candela <mario.candela.personal@gmail.com> Co-authored-by: Mario Candela <mario.candela.personal@gmail.com>
This commit is contained in:
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
@ -76,11 +77,13 @@ type BeelzebubServiceConfiguration struct {
|
||||
|
||||
// Command is the struct that contains the configurations of the commands
|
||||
type Command struct {
|
||||
Regex string `yaml:"regex"`
|
||||
Handler string `yaml:"handler"`
|
||||
Headers []string `yaml:"headers"`
|
||||
StatusCode int `yaml:"statusCode"`
|
||||
Plugin string `yaml:"plugin"`
|
||||
RegexStr string `yaml:"regex"`
|
||||
Regex *regexp.Regexp `yaml:"-"` // This field is parsed, not stored in the config itself.
|
||||
Handler string `yaml:"handler"`
|
||||
Headers []string `yaml:"headers"`
|
||||
StatusCode int `yaml:"statusCode"`
|
||||
Plugin string `yaml:"plugin"`
|
||||
Name string `yaml:"name"`
|
||||
}
|
||||
|
||||
type configurationsParser struct {
|
||||
@ -140,12 +143,29 @@ func (bp configurationsParser) ReadConfigurationsServices() ([]BeelzebubServiceC
|
||||
return nil, fmt.Errorf("in file %s: %v", filePath, err)
|
||||
}
|
||||
log.Debug(beelzebubServiceConfiguration)
|
||||
if err := beelzebubServiceConfiguration.CompileCommandRegex(); err != nil {
|
||||
return nil, fmt.Errorf("in file %s: invalid regex: %v", filePath, err)
|
||||
}
|
||||
servicesConfiguration = append(servicesConfiguration, *beelzebubServiceConfiguration)
|
||||
}
|
||||
|
||||
return servicesConfiguration, nil
|
||||
}
|
||||
|
||||
// CompileCommandRegex is the method that compiles the regular expression for each configured Command.
|
||||
func (c *BeelzebubServiceConfiguration) CompileCommandRegex() error {
|
||||
for i, command := range c.Commands {
|
||||
if command.RegexStr != "" {
|
||||
rex, err := regexp.Compile(command.RegexStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Commands[i].Regex = rex
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func gelAllFilesNameByDirName(dirName string) ([]string, error) {
|
||||
files, err := os.ReadDir(dirName)
|
||||
if err != nil {
|
||||
|
@ -3,6 +3,7 @@ package parser
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -56,6 +57,11 @@ commands:
|
||||
handler: "login"
|
||||
headers:
|
||||
- "Content-Type: text/html"
|
||||
- name: "wp-admin"
|
||||
regex: "wp-admin"
|
||||
handler: "login"
|
||||
headers:
|
||||
- "Content-Type: text/html"
|
||||
fallbackCommand:
|
||||
handler: "404 Not Found!"
|
||||
statusCode: 404
|
||||
@ -131,12 +137,14 @@ func TestReadConfigurationsServicesValid(t *testing.T) {
|
||||
assert.Equal(t, firstBeelzebubServiceConfiguration.Protocol, "http")
|
||||
assert.Equal(t, firstBeelzebubServiceConfiguration.ApiVersion, "v1")
|
||||
assert.Equal(t, firstBeelzebubServiceConfiguration.Address, ":8080")
|
||||
assert.Equal(t, len(firstBeelzebubServiceConfiguration.Commands), 1)
|
||||
assert.Equal(t, len(firstBeelzebubServiceConfiguration.Commands), 1)
|
||||
assert.Equal(t, firstBeelzebubServiceConfiguration.Commands[0].Regex, "wp-admin")
|
||||
assert.Equal(t, len(firstBeelzebubServiceConfiguration.Commands), 2)
|
||||
assert.Equal(t, len(firstBeelzebubServiceConfiguration.Commands), 2)
|
||||
assert.Equal(t, firstBeelzebubServiceConfiguration.Commands[0].RegexStr, "wp-admin")
|
||||
assert.Equal(t, firstBeelzebubServiceConfiguration.Commands[0].Regex.String(), "wp-admin")
|
||||
assert.Equal(t, firstBeelzebubServiceConfiguration.Commands[0].Handler, "login")
|
||||
assert.Equal(t, len(firstBeelzebubServiceConfiguration.Commands[0].Headers), 1)
|
||||
assert.Equal(t, firstBeelzebubServiceConfiguration.Commands[0].Headers[0], "Content-Type: text/html")
|
||||
assert.Equal(t, firstBeelzebubServiceConfiguration.Commands[1].Name, "wp-admin")
|
||||
assert.Equal(t, firstBeelzebubServiceConfiguration.FallbackCommand.Handler, "404 Not Found!")
|
||||
assert.Equal(t, firstBeelzebubServiceConfiguration.FallbackCommand.StatusCode, 404)
|
||||
assert.Equal(t, firstBeelzebubServiceConfiguration.Plugin.OpenAISecretKey, "qwerty")
|
||||
@ -199,3 +207,79 @@ func TestReadFileBytesByFilePath(t *testing.T) {
|
||||
|
||||
assert.Equal(t, "", string(bytes))
|
||||
}
|
||||
|
||||
func TestCompileCommandRegex(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
config BeelzebubServiceConfiguration
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
name: "Valid Regex",
|
||||
config: BeelzebubServiceConfiguration{
|
||||
Commands: []Command{
|
||||
{RegexStr: "^/api/v1/.*$"},
|
||||
{RegexStr: "wp-admin"},
|
||||
},
|
||||
},
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
name: "Empty Regex",
|
||||
config: BeelzebubServiceConfiguration{
|
||||
Commands: []Command{
|
||||
{RegexStr: ""},
|
||||
{RegexStr: ""},
|
||||
},
|
||||
},
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
name: "Invalid Regex",
|
||||
config: BeelzebubServiceConfiguration{
|
||||
Commands: []Command{
|
||||
{RegexStr: "["},
|
||||
},
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "Mixed valid and Invalid Regex",
|
||||
config: BeelzebubServiceConfiguration{
|
||||
Commands: []Command{
|
||||
{RegexStr: "^/api/v1/.*$"},
|
||||
{RegexStr: "["},
|
||||
{RegexStr: "test"},
|
||||
},
|
||||
},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "No commands",
|
||||
config: BeelzebubServiceConfiguration{},
|
||||
expectedError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.config.CompileCommandRegex()
|
||||
|
||||
if tt.expectedError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
for _, command := range tt.config.Commands {
|
||||
if command.RegexStr != "" {
|
||||
assert.NotNil(t, command.Regex)
|
||||
_, err := regexp.Compile(command.RegexStr)
|
||||
assert.NoError(t, err)
|
||||
|
||||
} else {
|
||||
assert.Nil(t, command.Regex)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user