-
Notifications
You must be signed in to change notification settings - Fork 10
feat: support including rules from the local filesystem #49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
e6d5abd
29ebea0
d3f3adb
a9aff20
ee3b17f
c949576
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,6 +37,88 @@ func TestWafIsConsistent(t *testing.T) { | |
| } | ||
|
|
||
| func TestAddRulesToWaf(t *testing.T) { | ||
| tests := []struct { | ||
| name string | ||
| rules string | ||
| canCreateWaf bool | ||
| }{ | ||
| { | ||
| name: "rule", | ||
| rules: `SecRule REMOTE_ADDR "127.0.0.1" "id:1,phase:1,deny,log,msg:'test 123',status:403"`, | ||
| canCreateWaf: true, | ||
| }, | ||
| { | ||
| name: "include local file", | ||
| rules: `Include testdata/test.conf`, | ||
| canCreateWaf: true, | ||
| }, | ||
| { | ||
| name: "include invalid rule", | ||
| rules: `foobar123`, | ||
| canCreateWaf: false, | ||
| }, | ||
| { | ||
| name: "include non-existent file", | ||
| rules: `Include testdata/nonexistent.conf`, | ||
| canCreateWaf: false, | ||
| }, | ||
| } | ||
| for _, test := range tests { | ||
| t.Run(test.name, func(t *testing.T) { | ||
| config := coraza_new_waf_config() | ||
| rv := coraza_rules_add(config, stringToC(test.rules)) | ||
| if rv != 0 { | ||
| t.Fatalf("Rules addition failed: %d", rv) | ||
| } | ||
|
|
||
| er := stringToC("") | ||
| waf := coraza_new_waf(config, &er) | ||
| if test.canCreateWaf && (waf == 0 || stringFromC(er) != "") { | ||
| t.Fatalf("Waf creation failed: %d", waf) | ||
| } else if !test.canCreateWaf && (waf != 0 || stringFromC(er) == "") { | ||
| t.Fatalf("Waf creation should have failed: %d", waf) | ||
| } | ||
|
Comment on lines
+64
to
+80
|
||
| if stringFromC(er) != "" { | ||
| t.Logf("Waf creation error: %s", stringFromC(er)) | ||
| } | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func TestAddRulesFromFileToWaf(t *testing.T) { | ||
| tests := []struct { | ||
| name string | ||
| file string | ||
| canCreateWaf bool | ||
| }{ | ||
| { | ||
| name: "test.conf", | ||
| file: "testdata/test.conf", | ||
| canCreateWaf: true, | ||
| }, | ||
| { | ||
| name: "nonexistent.conf", | ||
| file: "testdata/nonexistent.conf", | ||
| canCreateWaf: false, | ||
| }, | ||
| } | ||
| for _, test := range tests { | ||
| t.Run(test.name, func(t *testing.T) { | ||
| config := coraza_new_waf_config() | ||
| rv := coraza_rules_add_file(config, stringToC(test.file)) | ||
| if rv != 0 { | ||
| t.Fatalf("Rules addition failed: %d", rv) | ||
| } | ||
|
|
||
| er := stringToC("") | ||
| waf := coraza_new_waf(config, &er) | ||
| if test.canCreateWaf && (waf == 0 || stringFromC(er) != "") { | ||
| t.Fatalf("Waf creation failed: %d", waf) | ||
|
Comment on lines
+103
to
+116
|
||
| } else if !test.canCreateWaf && (waf != 0 || stringFromC(er) == "") { | ||
| t.Fatalf("Waf creation should have failed: %d", waf) | ||
| } | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func TestRulesCount(t *testing.T) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| package main | ||
|
|
||
| import "C" | ||
|
|
||
| import ( | ||
| "io/fs" | ||
| "os" | ||
| "path" | ||
| ) | ||
|
|
||
| // combinedFS is a filesystem that routes paths by checking both the local and root filesystems. | ||
| type combinedFS struct { | ||
| localFS fs.FS // local filesystem | ||
| rootFS fs.FS // root filesystem | ||
| } | ||
|
|
||
| func (c *combinedFS) Open(name string) (fs.File, error) { | ||
| if path.IsAbs(name) { | ||
| return c.rootFS.Open(name) | ||
| } else { | ||
| return c.localFS.Open(name) | ||
| } | ||
|
Comment on lines
+17
to
+22
|
||
| } | ||
|
|
||
| var rootFS fs.FS | ||
|
|
||
| func init() { | ||
| rootFS = &combinedFS{ | ||
| localFS: os.DirFS("."), | ||
| rootFS: os.DirFS("/"), | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| SecRule REMOTE_ADDR "127.0.0.1" "id:1,phase:1,deny,log,msg:'test 123',status:403" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting a default RootFS (
WithRootFS(rootFS)) changes the default security posture: configs/rules that containIncludedirectives (or other file-reading directives) can now read from the process filesystem. If rule sources can be influenced by untrusted input, this becomes a local file read primitive. Consider making filesystem access opt-in (expose a C API to set RootFS / allowed include dirs) or at least document the new behavior and restrict the default FS scope (e.g., only a dedicated rules directory).