Files
Charon/backend/internal/caddy/config_crowdsec_test.go
GitHub Actions 72ff6313de Implement CrowdSec integration with API endpoints for managing IP bans and decisions
- Added unit tests for CrowdSec handler, including listing, banning, and unbanning IPs.
- Implemented mock command executor for testing command execution.
- Created tests for various scenarios including successful operations, error handling, and invalid inputs.
- Developed CrowdSec configuration tests to ensure proper handler setup and JSON output.
- Documented security features and identified gaps in CrowdSec, WAF, and Rate Limiting implementations.
- Established acceptance criteria for feature completeness and outlined implementation phases for future work.
2025-12-05 17:23:26 +00:00

165 lines
4.7 KiB
Go

package caddy
import (
"encoding/json"
"testing"
"github.com/Wikid82/charon/backend/internal/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestBuildCrowdSecHandler_Disabled(t *testing.T) {
// When crowdsecEnabled is false, should return nil
h, err := buildCrowdSecHandler(nil, nil, false)
require.NoError(t, err)
assert.Nil(t, h)
}
func TestBuildCrowdSecHandler_EnabledWithoutConfig(t *testing.T) {
// When crowdsecEnabled is true but no secCfg, should use default localhost URL
h, err := buildCrowdSecHandler(nil, nil, true)
require.NoError(t, err)
require.NotNil(t, h)
assert.Equal(t, "crowdsec", h["handler"])
assert.Equal(t, "http://localhost:8080", h["api_url"])
}
func TestBuildCrowdSecHandler_EnabledWithEmptyAPIURL(t *testing.T) {
// When crowdsecEnabled is true but CrowdSecAPIURL is empty, should use default
secCfg := &models.SecurityConfig{
CrowdSecAPIURL: "",
}
h, err := buildCrowdSecHandler(nil, secCfg, true)
require.NoError(t, err)
require.NotNil(t, h)
assert.Equal(t, "crowdsec", h["handler"])
assert.Equal(t, "http://localhost:8080", h["api_url"])
}
func TestBuildCrowdSecHandler_EnabledWithCustomAPIURL(t *testing.T) {
// When crowdsecEnabled is true and CrowdSecAPIURL is set, should use custom URL
secCfg := &models.SecurityConfig{
CrowdSecAPIURL: "http://crowdsec-lapi:8081",
}
h, err := buildCrowdSecHandler(nil, secCfg, true)
require.NoError(t, err)
require.NotNil(t, h)
assert.Equal(t, "crowdsec", h["handler"])
assert.Equal(t, "http://crowdsec-lapi:8081", h["api_url"])
}
func TestBuildCrowdSecHandler_JSONFormat(t *testing.T) {
// Test that the handler produces valid JSON matching caddy-crowdsec-bouncer schema
secCfg := &models.SecurityConfig{
CrowdSecAPIURL: "http://localhost:8080",
}
h, err := buildCrowdSecHandler(nil, secCfg, true)
require.NoError(t, err)
require.NotNil(t, h)
// Marshal to JSON and verify structure
b, err := json.Marshal(h)
require.NoError(t, err)
s := string(b)
// Verify expected JSON content
assert.Contains(t, s, `"handler":"crowdsec"`)
assert.Contains(t, s, `"api_url":"http://localhost:8080"`)
// Should NOT contain old "mode" field
assert.NotContains(t, s, `"mode"`)
}
func TestBuildCrowdSecHandler_WithHost(t *testing.T) {
// Test that host parameter is accepted (even if not currently used)
host := &models.ProxyHost{
UUID: "test-uuid",
DomainNames: "example.com",
}
secCfg := &models.SecurityConfig{
CrowdSecAPIURL: "http://custom-crowdsec:8080",
}
h, err := buildCrowdSecHandler(host, secCfg, true)
require.NoError(t, err)
require.NotNil(t, h)
assert.Equal(t, "crowdsec", h["handler"])
assert.Equal(t, "http://custom-crowdsec:8080", h["api_url"])
}
func TestGenerateConfig_WithCrowdSec(t *testing.T) {
// Test that CrowdSec handler is included in generated config when enabled
hosts := []models.ProxyHost{
{
UUID: "test-uuid",
DomainNames: "example.com",
ForwardHost: "app",
ForwardPort: 8080,
Enabled: true,
},
}
secCfg := &models.SecurityConfig{
CrowdSecMode: "local",
CrowdSecAPIURL: "http://localhost:8080",
}
// crowdsecEnabled=true should include the handler
config, err := GenerateConfig(hosts, "/tmp/caddy-data", "admin@example.com", "", "", false, true, false, false, false, "", nil, nil, nil, secCfg)
require.NoError(t, err)
require.NotNil(t, config.Apps.HTTP)
server := config.Apps.HTTP.Servers["charon_server"]
require.NotNil(t, server)
require.Len(t, server.Routes, 1)
route := server.Routes[0]
// Handlers should include crowdsec + reverse_proxy
require.GreaterOrEqual(t, len(route.Handle), 2)
// Find the crowdsec handler
var foundCrowdSec bool
for _, h := range route.Handle {
if h["handler"] == "crowdsec" {
foundCrowdSec = true
// Verify it has api_url
assert.Equal(t, "http://localhost:8080", h["api_url"])
break
}
}
require.True(t, foundCrowdSec, "crowdsec handler should be present")
}
func TestGenerateConfig_CrowdSecDisabled(t *testing.T) {
// Test that CrowdSec handler is NOT included when disabled
hosts := []models.ProxyHost{
{
UUID: "test-uuid",
DomainNames: "example.com",
ForwardHost: "app",
ForwardPort: 8080,
Enabled: true,
},
}
// crowdsecEnabled=false should NOT include the handler
config, err := GenerateConfig(hosts, "/tmp/caddy-data", "admin@example.com", "", "", false, false, false, false, false, "", nil, nil, nil, nil)
require.NoError(t, err)
require.NotNil(t, config.Apps.HTTP)
server := config.Apps.HTTP.Servers["charon_server"]
require.NotNil(t, server)
require.Len(t, server.Routes, 1)
route := server.Routes[0]
// Verify no crowdsec handler
for _, h := range route.Handle {
assert.NotEqual(t, "crowdsec", h["handler"], "crowdsec handler should not be present when disabled")
}
}