- Implement GeoIPService for IP-to-country lookups with comprehensive error handling. - Add tests for GeoIPService covering various scenarios including invalid IPs and database loading. - Extend AccessListService to handle GeoIP service integration, including graceful degradation when GeoIP service is unavailable. - Introduce new tests for AccessListService to validate geo ACL behavior and country code parsing. - Update SecurityService to include new fields for WAF configuration and enhance decision logging functionality. - Add extensive tests for SecurityService covering rule set management and decision logging. - Create a detailed Security Coverage QA Plan to ensure 100% code coverage for security-related functionality.
123 lines
3.7 KiB
Go
123 lines
3.7 KiB
Go
package handlers
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/Wikid82/charon/backend/internal/config"
|
|
"github.com/Wikid82/charon/backend/internal/services"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestSecurityHandler_GetGeoIPStatus_NotInitialized(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
|
|
h := NewSecurityHandler(config.SecurityConfig{}, nil, nil)
|
|
r := gin.New()
|
|
r.GET("/security/geoip/status", h.GetGeoIPStatus)
|
|
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest(http.MethodGet, "/security/geoip/status", http.NoBody)
|
|
r.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
|
|
var body map[string]any
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &body))
|
|
assert.Equal(t, false, body["loaded"])
|
|
assert.Equal(t, "GeoIP service not initialized", body["message"])
|
|
}
|
|
|
|
func TestSecurityHandler_GetGeoIPStatus_Initialized_NotLoaded(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
|
|
h := NewSecurityHandler(config.SecurityConfig{}, nil, nil)
|
|
h.SetGeoIPService(&services.GeoIPService{})
|
|
|
|
r := gin.New()
|
|
r.GET("/security/geoip/status", h.GetGeoIPStatus)
|
|
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest(http.MethodGet, "/security/geoip/status", http.NoBody)
|
|
r.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
|
|
var body map[string]any
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &body))
|
|
assert.Equal(t, false, body["loaded"])
|
|
assert.Equal(t, "GeoIP service available", body["message"])
|
|
}
|
|
|
|
func TestSecurityHandler_ReloadGeoIP_NotInitialized(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
|
|
h := NewSecurityHandler(config.SecurityConfig{}, nil, nil)
|
|
r := gin.New()
|
|
r.POST("/security/geoip/reload", h.ReloadGeoIP)
|
|
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest(http.MethodPost, "/security/geoip/reload", http.NoBody)
|
|
r.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusServiceUnavailable, w.Code)
|
|
}
|
|
|
|
func TestSecurityHandler_ReloadGeoIP_LoadError(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
|
|
h := NewSecurityHandler(config.SecurityConfig{}, nil, nil)
|
|
h.SetGeoIPService(&services.GeoIPService{}) // dbPath empty => Load() will error
|
|
|
|
r := gin.New()
|
|
r.POST("/security/geoip/reload", h.ReloadGeoIP)
|
|
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest(http.MethodPost, "/security/geoip/reload", http.NoBody)
|
|
r.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusInternalServerError, w.Code)
|
|
assert.Contains(t, w.Body.String(), "Failed to reload GeoIP database")
|
|
}
|
|
|
|
func TestSecurityHandler_LookupGeoIP_MissingIPAddress(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
|
|
h := NewSecurityHandler(config.SecurityConfig{}, nil, nil)
|
|
r := gin.New()
|
|
r.POST("/security/geoip/lookup", h.LookupGeoIP)
|
|
|
|
payload := []byte(`{}`)
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest(http.MethodPost, "/security/geoip/lookup", bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
r.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
|
assert.Contains(t, w.Body.String(), "ip_address is required")
|
|
}
|
|
|
|
func TestSecurityHandler_LookupGeoIP_ServiceUnavailable(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
|
|
h := NewSecurityHandler(config.SecurityConfig{}, nil, nil)
|
|
h.SetGeoIPService(&services.GeoIPService{}) // present but not loaded
|
|
|
|
r := gin.New()
|
|
r.POST("/security/geoip/lookup", h.LookupGeoIP)
|
|
|
|
payload, _ := json.Marshal(map[string]string{"ip_address": "8.8.8.8"})
|
|
w := httptest.NewRecorder()
|
|
req := httptest.NewRequest(http.MethodPost, "/security/geoip/lookup", bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
r.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusServiceUnavailable, w.Code)
|
|
assert.Contains(t, w.Body.String(), "GeoIP service not available")
|
|
}
|