diff --git a/internal/seclang/parser.go b/internal/seclang/parser.go index 2cd6d62fe..e1fbf3a70 100644 --- a/internal/seclang/parser.go +++ b/internal/seclang/parser.go @@ -46,12 +46,14 @@ func (p *Parser) FromFile(profilePath string) error { if err != nil { return fmt.Errorf("failed to glob: %s", err.Error()) } + if len(files) == 0 { - return fmt.Errorf("empty glob: %s does not match any file", profilePath) + p.options.WAF.Logger.Warn().Int("line", p.currentLine).Msg("empty glob result") } } else { files = append(files, profilePath) } + for _, profilePath := range files { profilePath = strings.TrimSpace(profilePath) if !strings.HasPrefix(profilePath, "/") { @@ -157,20 +159,22 @@ func (p *Parser) evaluateLine(l string) error { if len(opts) >= 3 && opts[0] == '"' && opts[len(opts)-1] == '"' { opts = strings.Trim(opts, `"`) } + if directive == "include" { // this is a special hardcoded case // we cannot add it as a directive type because there are recursion issues // note a user might still include another file that includes the original file // generating a DDOS attack if p.includeCount >= maxIncludeRecursion { - return p.log(fmt.Sprintf("cannot include more than %d files", maxIncludeRecursion)) + return p.logAndReturnErr(fmt.Sprintf("cannot include more than %d files", maxIncludeRecursion)) } p.includeCount++ return p.FromFile(opts) } + d, ok := directivesMap[directive] if !ok || d == nil { - return p.log(fmt.Sprintf("unknown directive %q", directive)) + return p.logAndReturnErr(fmt.Sprintf("unknown directive %q", directive)) } p.options.Raw = l @@ -194,7 +198,7 @@ func (p *Parser) evaluateLine(l string) error { return nil } -func (p *Parser) log(msg string) error { +func (p *Parser) logAndReturnErr(msg string) error { p.options.WAF.Logger.Error().Int("line", p.currentLine).Msg(msg) return errors.New(msg) } diff --git a/internal/seclang/parser_test.go b/internal/seclang/parser_test.go index ad701cd84..0865b8df8 100644 --- a/internal/seclang/parser_test.go +++ b/internal/seclang/parser_test.go @@ -89,25 +89,34 @@ func TestErrorWithBackticks(t *testing.T) { func TestLoadConfigurationFile(t *testing.T) { waf := coraza.NewWAF() p := NewParser(waf) - err := p.FromFile("../../coraza.conf-recommended") - if err != nil { - t.Errorf("unexpected error: %s", err.Error()) - } - err = p.FromFile("../doesnotexist.conf") - if err == nil { - t.Error("expected not found error") - } + t.Run("existing file", func(t *testing.T) { + err := p.FromFile("../../coraza.conf-recommended") + if err != nil { + t.Errorf("unexpected error: %s", err.Error()) + } + }) - err = p.FromFile("./testdata/glob/*.conf") - if err != nil { - t.Errorf("unexpected error: %s", err.Error()) - } + t.Run("unexisting file", func(t *testing.T) { + err := p.FromFile("../doesnotexist.conf") + if err == nil { + t.Error("expected not found error") + } + }) - err = p.FromFile("./testdata/glob/*.comf") - if err == nil { - t.Errorf("expected an error as glob does not match any file") - } + t.Run("successful glob", func(t *testing.T) { + err := p.FromFile("./testdata/glob/*.conf") + if err != nil { + t.Errorf("unexpected error: %s", err.Error()) + } + }) + + t.Run("empty glob result", func(t *testing.T) { + err := p.FromFile("./testdata/glob/*.comf") + if err != nil { + t.Errorf("unexpected error despite glob not matching any file") + } + }) } // Connectors are supporting embedding github.com/corazawaf/coraza-coreruleset to ease CRS integration