Files
goclaw/internal/http/auth_helpers_test.go
viettranx 0494721af2 test(gateway,http): add unit tests for server/methods/handlers
Add server and RPC handler tests:
- gateway/ratelimit_test.go: rate limiter pure unit
- gateway/event_filter_test.go: event routing logic
- gateway/server_test.go: handleHealth, tokenAuth, checkOrigin, desktopCORS
- gateway/methods/sessions_test.go: sessions RPC handlers
- gateway/methods/skills_test.go: skills RPC handlers
- gateway/methods/cron_test.go: cron RPC handlers
- http/files_path_security_test.go: path traversal, workspace boundary, auth
- http/auth_helpers_test.go: extractBearerToken, tokenMatch, extractUserID/AgentID
2026-04-11 21:22:23 +07:00

185 lines
5.6 KiB
Go

package http
import (
"net/http/httptest"
"strings"
"testing"
)
// Tests for auth helper functions not covered by the existing auth_test.go.
// auth_test.go covers resolveAuth/requireAuth at a higher level.
// These tests exercise the low-level helpers directly.
// ---- extractBearerToken ----
func TestExtractBearerToken_ValidBearer(t *testing.T) {
r := httptest.NewRequest("GET", "/", nil)
r.Header.Set("Authorization", "Bearer my-secret-token")
got := extractBearerToken(r)
if got != "my-secret-token" {
t.Errorf("extractBearerToken = %q, want %q", got, "my-secret-token")
}
}
func TestExtractBearerToken_NoAuthHeader_ReturnsEmpty(t *testing.T) {
r := httptest.NewRequest("GET", "/", nil)
if got := extractBearerToken(r); got != "" {
t.Errorf("extractBearerToken with no header = %q, want empty", got)
}
}
func TestExtractBearerToken_BasicScheme_ReturnsEmpty(t *testing.T) {
r := httptest.NewRequest("GET", "/", nil)
r.Header.Set("Authorization", "Basic dXNlcjpwYXNz")
if got := extractBearerToken(r); got != "" {
t.Errorf("extractBearerToken with Basic scheme = %q, want empty", got)
}
}
func TestExtractBearerToken_EmptyBearerValue(t *testing.T) {
r := httptest.NewRequest("GET", "/", nil)
r.Header.Set("Authorization", "Bearer ")
got := extractBearerToken(r)
// "Bearer " → TrimPrefix("Bearer ") = "" — returns empty string
if got != "" {
t.Errorf("extractBearerToken with empty bearer value = %q, want empty", got)
}
}
// ---- tokenMatch ----
func TestTokenMatch_EmptyExpected_AlwaysTrue(t *testing.T) {
// No auth configured → tokenMatch returns true for any provided value.
if !tokenMatch("anything", "") {
t.Error("tokenMatch with empty expected should return true (no auth mode)")
}
if !tokenMatch("", "") {
t.Error("tokenMatch with both empty should return true")
}
}
func TestTokenMatch_CorrectToken_ReturnsTrue(t *testing.T) {
if !tokenMatch("secret123", "secret123") {
t.Error("tokenMatch with matching token should return true")
}
}
func TestTokenMatch_WrongToken_ReturnsFalse(t *testing.T) {
if tokenMatch("wrong", "secret123") {
t.Error("tokenMatch with wrong token should return false")
}
}
func TestTokenMatch_EmptyProvided_ReturnsFalse(t *testing.T) {
if tokenMatch("", "secret123") {
t.Error("tokenMatch with empty provided should return false when expected is set")
}
}
// ---- extractUserID ----
func TestExtractUserID_ValidHeader(t *testing.T) {
r := httptest.NewRequest("GET", "/", nil)
r.Header.Set("X-GoClaw-User-Id", "user-abc-123")
if got := extractUserID(r); got != "user-abc-123" {
t.Errorf("extractUserID = %q, want %q", got, "user-abc-123")
}
}
func TestExtractUserID_NoHeader_ReturnsEmpty(t *testing.T) {
r := httptest.NewRequest("GET", "/", nil)
if got := extractUserID(r); got != "" {
t.Errorf("extractUserID with no header = %q, want empty", got)
}
}
func TestExtractUserID_TooLongID_ReturnsEmpty(t *testing.T) {
// MaxUserIDLength is 255 — send 256 chars
longID := strings.Repeat("a", 256)
r := httptest.NewRequest("GET", "/", nil)
r.Header.Set("X-GoClaw-User-Id", longID)
if got := extractUserID(r); got != "" {
t.Errorf("extractUserID with too-long ID = %q, want empty (security rejection)", got)
}
}
// ---- extractAgentID ----
func TestExtractAgentID_FromModelPrefix_Goclaw(t *testing.T) {
got := extractAgentID(httptest.NewRequest("GET", "/", nil), "goclaw:my-agent")
if got != "my-agent" {
t.Errorf("extractAgentID goclaw: prefix = %q, want %q", got, "my-agent")
}
}
func TestExtractAgentID_FromModelPrefix_Agent(t *testing.T) {
got := extractAgentID(httptest.NewRequest("GET", "/", nil), "agent:support-bot")
if got != "support-bot" {
t.Errorf("extractAgentID agent: prefix = %q, want %q", got, "support-bot")
}
}
func TestExtractAgentID_FromHeader_XGoClawAgentId(t *testing.T) {
r := httptest.NewRequest("GET", "/", nil)
r.Header.Set("X-GoClaw-Agent-Id", "header-agent")
got := extractAgentID(r, "some-other-model")
if got != "header-agent" {
t.Errorf("extractAgentID from X-GoClaw-Agent-Id = %q, want %q", got, "header-agent")
}
}
func TestExtractAgentID_FromHeader_XGoClawAgent(t *testing.T) {
r := httptest.NewRequest("GET", "/", nil)
r.Header.Set("X-GoClaw-Agent", "legacy-agent")
got := extractAgentID(r, "")
if got != "legacy-agent" {
t.Errorf("extractAgentID from X-GoClaw-Agent = %q, want %q", got, "legacy-agent")
}
}
func TestExtractAgentID_DefaultsToDefault(t *testing.T) {
r := httptest.NewRequest("GET", "/", nil)
got := extractAgentID(r, "gpt-4o")
if got != "default" {
t.Errorf("extractAgentID no match = %q, want 'default'", got)
}
}
func TestExtractAgentID_ModelPrefixTakesPriorityOverHeader(t *testing.T) {
r := httptest.NewRequest("GET", "/", nil)
r.Header.Set("X-GoClaw-Agent-Id", "header-agent")
got := extractAgentID(r, "goclaw:model-agent")
if got != "model-agent" {
t.Errorf("extractAgentID model prefix should take priority, got %q", got)
}
}
// ---- isHTTPOwnerID ----
func TestIsHTTPOwnerID_MatchesConfiguredOwner(t *testing.T) {
if !isHTTPOwnerID("alice", []string{"alice", "bob"}) {
t.Error("alice should be owner")
}
}
func TestIsHTTPOwnerID_EmptyUserID_NotOwner(t *testing.T) {
if isHTTPOwnerID("", []string{"alice"}) {
t.Error("empty user ID should never be owner")
}
}
func TestIsHTTPOwnerID_EmptyOwnerList_OnlySystemIsOwner(t *testing.T) {
if !isHTTPOwnerID("system", nil) {
t.Error("'system' is default owner when no owner IDs configured")
}
if isHTTPOwnerID("admin", nil) {
t.Error("non-system user should not be owner with empty owner list")
}
}
func TestIsHTTPOwnerID_UnknownUser_NotOwner(t *testing.T) {
if isHTTPOwnerID("charlie", []string{"alice", "bob"}) {
t.Error("charlie is not in owner list")
}
}