Skip to content

Commit

Permalink
Fix integration test for AppSec
Browse files Browse the repository at this point in the history
  • Loading branch information
hslatman committed Nov 19, 2024
1 parent 4d95de7 commit 5ecdc9e
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 22 deletions.
89 changes: 68 additions & 21 deletions internal/testutils/testutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"time"

"github.com/caddyserver/caddy/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/exec"
Expand Down Expand Up @@ -51,7 +52,7 @@ func NewCrowdSecContainer(t *testing.T, ctx context.Context) *container {

return &container{
c: c,
endpoint: fmt.Sprintf("http://localhost:%d", endpointPort.Int()),
endpoint: fmt.Sprintf("http://127.0.0.1:%d", endpointPort.Int()),
}
}

Expand Down Expand Up @@ -81,11 +82,70 @@ labels:

func NewAppSecContainer(t *testing.T, ctx context.Context) *container {
t.Helper()

// shared data between initialization and actual AppSec container
mounts := testcontainers.ContainerMounts{
{
Source: testcontainers.GenericVolumeMountSource{
Name: "crowdsec-etc",
},
Target: "/etc/crowdsec",
},
{
Source: testcontainers.GenericVolumeMountSource{
Name: "crowdsec-data",
},
Target: "/var/lib/crowdsec/data",
},
}

// AppSec requires some WAF rules to be present, so we start by initializing
// a container, installing the required collections, and then stopping it again.
initContainer, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: testcontainers.ContainerRequest{
Image: "crowdsecurity/crowdsec:latest",
Mounts: mounts,
ExposedPorts: []string{"8080/tcp"},
WaitingFor: wait.ForLog("CrowdSec Local API listening on 0.0.0.0:8080"),
Env: map[string]string{
"BOUNCER_KEY_testbouncer1": testAPIKey,
"DISABLE_ONLINE_API": "true",
},
},
Started: true,
Logger: testcontainers.TestLogger(t),
})
require.NoError(t, err)
require.NotNil(t, initContainer)

// install some AppSec rule collections
code, reader, err := initContainer.Exec(ctx, []string{"cscli", "collections", "install", "crowdsecurity/appsec-virtual-patching"})
assert.NoError(t, err)
assert.Equal(t, 0, code)
LogContainerOutput(t, reader)

code, reader, err = initContainer.Exec(ctx, []string{"cscli", "collections", "install", "crowdsecurity/appsec-generic-rules"})
assert.NoError(t, err)
assert.Equal(t, 0, code)
LogContainerOutput(t, reader)

// allow container some slack
time.Sleep(1 * time.Second)

// cleanly stop the initialization container
duration := 3 * time.Second
err = initContainer.Stop(ctx, &duration)
require.NoError(t, err)
err = initContainer.Terminate(ctx)
require.NoError(t, err)

// create the actual AppSec container
c, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: testcontainers.ContainerRequest{
Image: "crowdsecurity/crowdsec:latest",
Mounts: mounts,
ExposedPorts: []string{"8080/tcp", "7422/tcp"},
WaitingFor: wait.ForLog("CrowdSec Local API listening on 0.0.0.0:8080"),
WaitingFor: wait.ForLog("Appsec Runner ready to process event"),
Env: map[string]string{
"BOUNCER_KEY_testbouncer1": testAPIKey,
"DISABLE_ONLINE_API": "true",
Expand All @@ -104,23 +164,6 @@ func NewAppSecContainer(t *testing.T, ctx context.Context) *container {
require.NotNil(t, c)
t.Cleanup(func() { _ = c.Terminate(ctx) })

code, reader, err := c.Exec(ctx, []string{"cscli", "collections", "install", "crowdsecurity/appsec-virtual-patching"})
require.NoError(t, err)
require.Equal(t, 0, code)
LogContainerOutput(t, reader)

code, reader, err = c.Exec(ctx, []string{"cscli", "collections", "install", "crowdsecurity/appsec-generic-rules"})
require.NoError(t, err)
require.Equal(t, 0, code)
LogContainerOutput(t, reader)

time.Sleep(2 * time.Second)

err = c.Stop(ctx, nil)
require.NoError(t, err)
err = c.Start(ctx)
require.NoError(t, err)

endpointPort, err := c.MappedPort(ctx, "8080/tcp")
require.NoError(t, err)

Expand All @@ -129,8 +172,8 @@ func NewAppSecContainer(t *testing.T, ctx context.Context) *container {

return &container{
c: c,
endpoint: fmt.Sprintf("http://localhost:%d", endpointPort.Int()),
appsec: fmt.Sprintf("http://localhost:%d", appsecPort.Int()),
endpoint: fmt.Sprintf("http://127.0.0.1:%d", endpointPort.Int()),
appsec: fmt.Sprintf("http://127.0.0.1:%d", appsecPort.Int()),
}
}

Expand All @@ -156,6 +199,10 @@ func NewCrowdSecModule(t *testing.T, ctx context.Context, config string) *crowds
func LogContainerOutput(t *testing.T, reader io.Reader) {
t.Helper()

if reader == nil {
return
}

buf := new(strings.Builder)
_, err := io.Copy(buf, reader)
require.NoError(t, err)
Expand Down
2 changes: 1 addition & 1 deletion test/appsec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func TestAppSec(t *testing.T) {

// wait a little bit of time to let the go-cs-bouncer do _some_ work,
// before it properly returns; seems to hang otherwise on b.wg.Wait().
time.Sleep(1 * time.Second)
time.Sleep(100 * time.Millisecond)

r := httptest.NewRequest(http.MethodGet, "http://www.example.com", http.NoBody)
r = r.WithContext(ctx)
Expand Down

0 comments on commit 5ecdc9e

Please sign in to comment.