Skip to content

Commit

Permalink
Merge pull request #19 from jcchavezs/adds_support_for_host_mounting
Browse files Browse the repository at this point in the history
feat: adds support and example for mounting host FS into guest.
  • Loading branch information
jcchavezs authored Jul 4, 2024
2 parents f9d28cf + ed548cb commit cdd5ac8
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 21 deletions.
21 changes: 21 additions & 0 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import (
"net/http"

"github.com/http-wasm/http-wasm-host-go/handler"
nethttp "github.com/http-wasm/http-wasm-host-go/handler/nethttp"
wasm "github.com/http-wasm/http-wasm-host-go/handler/nethttp"
"github.com/tetratelabs/wazero"
)

//go:embed build/coraza-http-wasm.wasm
Expand Down Expand Up @@ -64,3 +66,22 @@ func ExampleMain() {

// Output: 403
}

func ExampleFS() {
moduleConfig := wazero.
NewModuleConfig().
// Mount the directory as read-only at the root of the guest filesystem.
WithFSConfig(wazero.NewFSConfig().WithReadOnlyDirMount("./testdata", "/"))

mw, err := nethttp.NewMiddleware(context.Background(), []byte(guest),
handler.ModuleConfig(moduleConfig),
handler.GuestConfig([]byte("{\"directives\": [ \"Include ./directives.conf\", \"Include @crs-setup.conf.example\" ]}")),
)
if err == nil {
mw.Close(context.Background())
} else {
fmt.Printf("failed to create middleware: %v\n", err)
}

// Output:
}
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ require (
github.com/corazawaf/coraza/v3 v3.1.0
github.com/http-wasm/http-wasm-guest-tinygo v0.4.0
github.com/http-wasm/http-wasm-host-go v0.6.0
github.com/jcchavezs/mergefs v0.0.0-20230503083351-07f27d256761
github.com/mccutchen/go-httpbin/v2 v2.13.4
github.com/stretchr/testify v1.8.4
github.com/tetratelabs/wabin v0.0.0-20230304001439-f6f874872834
github.com/tetratelabs/wazero v1.6.0
github.com/wasilibs/nottinygc v0.4.0
github.com/tetratelabs/wazero v1.7.2
github.com/wasilibs/nottinygc v0.7.1
)

require (
Expand Down
14 changes: 14 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ github.com/corazawaf/coraza/v3 v3.1.0 h1:CB6YxNXdbZjUJS/0FVFoFvS8eOVFbIvlNuHNC5d
github.com/corazawaf/coraza/v3 v3.1.0/go.mod h1:S0bhYQfTu1Ew3YKdI37X1WWu6t4En4Tvw28aKyQFJaU=
github.com/corazawaf/libinjection-go v0.1.3 h1:PUplAYho1BBl0tIVbhDsNRuVGIeUYSiCEc9oQpb2rJU=
github.com/corazawaf/libinjection-go v0.1.3/go.mod h1:OP4TM7xdJ2skyXqNX1AN1wN5nNZEmJNuWbNPOItn7aw=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI=
Expand All @@ -14,6 +15,8 @@ github.com/http-wasm/http-wasm-guest-tinygo v0.4.0 h1:sWd1hqOL8LF3DVRPXloVELTQIt
github.com/http-wasm/http-wasm-guest-tinygo v0.4.0/go.mod h1:zcKr7h/t5ha2ZWIMwV4iOqhfC/qno/tNPYgybVkn/MQ=
github.com/http-wasm/http-wasm-host-go v0.6.0 h1:Vd4XvcFB3NMgWp2VLCQaiqYgLneN2lChbyN9NGoNDro=
github.com/http-wasm/http-wasm-host-go v0.6.0/go.mod h1:zQB3w+df4hryDEqBorGyA1DwPJ86LfKIASNLFuj6CuI=
github.com/jcchavezs/mergefs v0.0.0-20230503083351-07f27d256761 h1:Wbw8wlehLICFiXFPmQjMnYkcC6qH4a0d1iNbp6md+tk=
github.com/jcchavezs/mergefs v0.0.0-20230503083351-07f27d256761/go.mod h1:BGD4X4tm4ZCbtShoISaG4Ama2L3NOq7y6cvuOxbYgzs=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
Expand All @@ -29,12 +32,20 @@ github.com/petar-dambovaliev/aho-corasick v0.0.0-20230725210150-fb29fc3c913e h1:
github.com/petar-dambovaliev/aho-corasick v0.0.0-20230725210150-fb29fc3c913e/go.mod h1:EHPiTAKtiFmrMldLUNswFwfZ2eJIYBHktdaUTZxYWRw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tetratelabs/wabin v0.0.0-20230304001439-f6f874872834 h1:ZF+QBjOI+tILZjBaFj3HgFonKXUcwgJ4djLb6i42S3Q=
github.com/tetratelabs/wabin v0.0.0-20230304001439-f6f874872834/go.mod h1:m9ymHTgNSEjuxvw8E7WWe4Pl4hZQHXONY8wE6dMLaRk=
github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g=
github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
github.com/tetratelabs/wazero v1.7.2 h1:1+z5nXJNwMLPAWaTePFi49SSTL0IMx/i3Fg8Yc25GDc=
github.com/tetratelabs/wazero v1.7.2/go.mod h1:ytl6Zuh20R/eROuyDaGPkp82O9C/DJfXAwJfQ3X6/7Y=
github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U=
github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
Expand All @@ -50,6 +61,8 @@ github.com/wasilibs/go-re2 v1.4.0 h1:Jp6BM8G/zajgY1BCQUm3i7oGMdR1gA5EBv87wGd2ysc
github.com/wasilibs/go-re2 v1.4.0/go.mod h1:hLzlKjEgON+17hWjikLx8hJBkikyjQH/lsqCy9t6tIY=
github.com/wasilibs/nottinygc v0.4.0 h1:h1TJMihMC4neN6Zq+WKpLxgd9xCFMw7O9ETLwY2exJQ=
github.com/wasilibs/nottinygc v0.4.0/go.mod h1:oDcIotskuYNMpqMF23l7Z8uzD4TC0WXHK8jetlB3HIo=
github.com/wasilibs/nottinygc v0.7.1 h1:rKu19+SFniRNuSo5NX7/wxpSpXmMUmkcyt/YiWLJg8w=
github.com/wasilibs/nottinygc v0.7.1/go.mod h1:oDcIotskuYNMpqMF23l7Z8uzD4TC0WXHK8jetlB3HIo=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
Expand All @@ -63,6 +76,7 @@ golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE=
Expand Down
5 changes: 5 additions & 0 deletions go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLf
github.com/projectdiscovery/yamldoc-go v1.0.4/go.mod h1:8PIPRcUD55UbtQdcfFR1hpIGRWG0P7alClXNGt1TBik=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
wait4x.dev/v2 v2.14.0/go.mod h1:Qvt5rGUgGVQoxTCYBbp6KMJG4QHDwsJP8BIRQdUe1TA=
2 changes: 1 addition & 1 deletion magefile.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func Test() error {

// E2e runs e2e tests
func E2e() error {
return sh.RunV("go", "test", "-run=^TestE2E", "-tags=e2e", "-v", ".")
return sh.RunV("go", "test", "-count=1", "-run=^TestE2E", "-tags=e2e", "-v", ".")
}

func copy(src, dst string) error {
Expand Down
40 changes: 29 additions & 11 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import (
"github.com/corazawaf/coraza/v3/types"
httpwasm "github.com/http-wasm/http-wasm-guest-tinygo/handler"
"github.com/http-wasm/http-wasm-guest-tinygo/handler/api"
"github.com/jcchavezs/mergefs"
fsio "github.com/jcchavezs/mergefs/io"
"github.com/tidwall/gjson"
)

Expand Down Expand Up @@ -64,20 +66,31 @@ func toHostLevel(lvl debuglog.Level) api.LogLevel {
}
}

func getDirectivesFromHost(host api.Host) (string, error) {
type config struct {
includeCRS bool
directives string
}

func getConfigFromHost(host api.Host) (config, error) {
cfg := config{includeCRS: true}

if len(host.GetConfig()) == 0 {
return "", nil
return cfg, nil
}

var directives = strings.Builder{}
cfgAsJSON := gjson.ParseBytes(host.GetConfig())
if !cfgAsJSON.Exists() {
return "", errors.New("invalid host config")
return config{}, errors.New("invalid host config")
}

if includeCRSRes := cfgAsJSON.Get("includeCRS"); includeCRSRes.Exists() {
cfg.includeCRS = includeCRSRes.Bool()
}

directivesResult := cfgAsJSON.Get("directives")
if !directivesResult.IsArray() {
return "", errors.New("invalid host config, array expected for field directives")
return config{}, errors.New("invalid host config, array expected for field directives")
}

isFirst := true
Expand All @@ -93,10 +106,11 @@ func getDirectivesFromHost(host api.Host) (string, error) {
})

if directives.Len() == 0 {
return "", errors.New("empty directives")
return config{}, errors.New("empty directives")
}

return directives.String(), nil
cfg.directives = directives.String()
return cfg, nil
}

func errorCb(host api.Host) func(types.MatchedRule) {
Expand All @@ -120,14 +134,18 @@ func errorCb(host api.Host) func(types.MatchedRule) {
}

func initializeWAF(host api.Host) (coraza.WAF, error) {
wafConfig := coraza.NewWAFConfig().WithRootFS(coreruleset.FS)
wafConfig := coraza.NewWAFConfig()

if cfg, err := getConfigFromHost(host); err == nil {
if cfg.includeCRS {
wafConfig = wafConfig.WithRootFS(mergefs.Merge(coreruleset.FS, fsio.OSFS))
}

if directives, err := getDirectivesFromHost(host); err == nil {
if directives == "" {
if cfg.directives == "" {
host.Log(api.LogLevelWarn, "Initializing WAF with no directives")
} else {
host.Log(api.LogLevelDebug, "Initializing WAF with directives:\n"+directives)
wafConfig = wafConfig.WithDirectives(directives)
host.Log(api.LogLevelDebug, "Initializing WAF with directives:\n"+cfg.directives)
wafConfig = wafConfig.WithDirectives(cfg.directives)
}
} else {
return nil, err
Expand Down
16 changes: 9 additions & 7 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,36 +27,37 @@ func (h mockAPIHost) Log(_ api.LogLevel, msg string) {

func TestGetDirectivesFromHost(t *testing.T) {
t.Run("empty config", func(t *testing.T) {
directives, err := getDirectivesFromHost(mockAPIHost{t: t, getConfig: func() []byte {
cfg, err := getConfigFromHost(mockAPIHost{t: t, getConfig: func() []byte {
return nil
}})
require.Empty(t, directives)
require.True(t, cfg.includeCRS)
require.Empty(t, cfg.directives)
require.NoError(t, err)
})

t.Run("invalid JSON", func(t *testing.T) {
_, err := getDirectivesFromHost(mockAPIHost{getConfig: func() []byte {
_, err := getConfigFromHost(mockAPIHost{getConfig: func() []byte {
return []byte("abcd")
}})
require.ErrorContains(t, err, "invalid host config")
})

t.Run("invalid directives value", func(t *testing.T) {
_, err := getDirectivesFromHost(mockAPIHost{getConfig: func() []byte {
_, err := getConfigFromHost(mockAPIHost{getConfig: func() []byte {
return []byte("{\"directives\": true}")
}})
require.ErrorContains(t, err, "invalid host config")
})

t.Run("empty directives", func(t *testing.T) {
_, err := getDirectivesFromHost(mockAPIHost{getConfig: func() []byte {
_, err := getConfigFromHost(mockAPIHost{getConfig: func() []byte {
return []byte("{\"directives\": []}")
}})
require.ErrorContains(t, err, "empty directives")
})

t.Run("valid directives", func(t *testing.T) {
directives, err := getDirectivesFromHost(mockAPIHost{getConfig: func() []byte {
cfg, err := getConfigFromHost(mockAPIHost{getConfig: func() []byte {
return []byte(`
{
"directives": [
Expand All @@ -66,8 +67,9 @@ func TestGetDirectivesFromHost(t *testing.T) {
}
`)
}})
require.True(t, cfg.includeCRS)
require.NoError(t, err)
require.Equal(t, "SecRuleEngine: On\nSecDebugLog /etc/var/logs/coraza.conf", directives)
require.Equal(t, "SecRuleEngine: On\nSecDebugLog /etc/var/logs/coraza.conf", cfg.directives)
})
}

Expand Down
1 change: 1 addition & 0 deletions testdata/directives.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SecRuleEngine On

0 comments on commit cdd5ac8

Please sign in to comment.