diff --git a/internal/acp/providers_sync_test.go b/internal/acp/providers_sync_test.go index f7a7f2c..c8d0b81 100644 --- a/internal/acp/providers_sync_test.go +++ b/internal/acp/providers_sync_test.go @@ -568,6 +568,7 @@ func TestHandleRPCRequiresExplicitBearerForExternalProvider(t *testing.T) { defer externalServer.Close() t.Setenv("INTERNAL_SERVICE_TOKEN", "synced-provider-token") + t.Setenv("BRIDGE_AUTH_TOKEN", "") server := NewServer() setTestBridgeProvider(server, syncedProvider{ ProviderID: "codex", diff --git a/internal/acp/server.go b/internal/acp/server.go index 6d9e681..234faab 100644 --- a/internal/acp/server.go +++ b/internal/acp/server.go @@ -305,10 +305,6 @@ func (s *Server) authorized(r *http.Request) bool { if s == nil { return false } - expected := strings.TrimSpace(shared.EnvOrDefault("BRIDGE_AUTH_TOKEN", "")) - if expected == "" { - return true - } if s.authService == nil { return false } diff --git a/internal/acp/web_contract_test.go b/internal/acp/web_contract_test.go index 74e966c..63d0d99 100644 --- a/internal/acp/web_contract_test.go +++ b/internal/acp/web_contract_test.go @@ -11,6 +11,7 @@ import ( func TestHTTPHandlerRootAndPingExposeRuntimeVersionInfo(t *testing.T) { t.Setenv("IMAGE", "ghcr.io/x-evor/xworkmate-bridge:0123456789abcdef0123456789abcdef01234567") + t.Setenv("BRIDGE_AUTH_TOKEN", "") server := NewServer() handler := server.Handler() @@ -75,6 +76,7 @@ func TestParseImageVersionInfoHandlesTaggedImageRef(t *testing.T) { func TestHandleWebSocketRejectsUnknownOrigin(t *testing.T) { t.Setenv("ACP_ALLOWED_ORIGINS", "https://xworkmate.svc.plus") + t.Setenv("BRIDGE_AUTH_TOKEN", "") server := NewServer() recorder := httptest.NewRecorder() @@ -93,6 +95,7 @@ func TestHandleWebSocketRejectsUnknownOrigin(t *testing.T) { func TestHandleRPCAllowsPreflightForConfiguredOrigin(t *testing.T) { t.Setenv("ACP_ALLOWED_ORIGINS", "https://xworkmate.svc.plus,http://localhost:*") + t.Setenv("BRIDGE_AUTH_TOKEN", "") server := NewServer() recorder := httptest.NewRecorder() @@ -110,7 +113,8 @@ func TestHandleRPCAllowsPreflightForConfiguredOrigin(t *testing.T) { } } -func TestHandleRPCAllowsRequestsWhenBridgeAuthTokenUnset(t *testing.T) { +func TestHandleRPCRequiresAuthorizationEvenWhenBridgeAuthTokenUnset(t *testing.T) { + t.Setenv("BRIDGE_AUTH_TOKEN", "") server := NewServer() recorder := httptest.NewRecorder() request := httptest.NewRequest( @@ -122,8 +126,8 @@ func TestHandleRPCAllowsRequestsWhenBridgeAuthTokenUnset(t *testing.T) { server.HandleRPC(recorder, request) - if recorder.Code != http.StatusOK { - t.Fatalf("expected 200 when BRIDGE_AUTH_TOKEN is unset, got %d", recorder.Code) + if recorder.Code != http.StatusUnauthorized { + t.Fatalf("expected 401 when BRIDGE_AUTH_TOKEN is unset but no header provided, got %d", recorder.Code) } } @@ -148,6 +152,7 @@ func TestHandleRPCRequiresBearerAuthorizationWhenBridgeAuthTokenConfigured(t *te func TestHandleRPCRejectsUnknownOrigin(t *testing.T) { t.Setenv("ACP_ALLOWED_ORIGINS", "https://xworkmate.svc.plus") + t.Setenv("BRIDGE_AUTH_TOKEN", "") server := NewServer() recorder := httptest.NewRecorder() @@ -175,6 +180,7 @@ func TestHandleRPCRejectsUnknownOrigin(t *testing.T) { } func TestHandleRPCMethodErrorUsesJSONEnvelope(t *testing.T) { + t.Setenv("BRIDGE_AUTH_TOKEN", "") server := NewServer() recorder := httptest.NewRecorder() request := httptest.NewRequest(http.MethodGet, "http://127.0.0.1/acp/rpc", nil) @@ -191,6 +197,7 @@ func TestHandleRPCMethodErrorUsesJSONEnvelope(t *testing.T) { } func TestHandleRPCCapabilitiesStillReturnsJSONResult(t *testing.T) { + t.Setenv("BRIDGE_AUTH_TOKEN", "") server := NewServer() recorder := httptest.NewRecorder() request := httptest.NewRequest( @@ -214,15 +221,17 @@ func TestHandleRPCCapabilitiesStillReturnsJSONResult(t *testing.T) { } } -func TestAuthorizedAllowsRequestsWhenBridgeAuthTokenUnset(t *testing.T) { +func TestAuthorizedRejectsUnauthenticatedRequestsWhenBridgeAuthTokenUnset(t *testing.T) { + t.Setenv("BRIDGE_AUTH_TOKEN", "") server := NewServer() request := httptest.NewRequest(http.MethodGet, "http://127.0.0.1/acp", nil) - if !server.authorized(request) { - t.Fatal("expected requests to be authorized when BRIDGE_AUTH_TOKEN is unset") + if server.authorized(request) { + t.Fatal("expected unauthenticated request to be rejected even if BRIDGE_AUTH_TOKEN is unset") } } func TestHandleRPCCapabilitiesReturnsCanonicalProviderContract(t *testing.T) { + t.Setenv("BRIDGE_AUTH_TOKEN", "") server := NewServer() recorder := httptest.NewRecorder() request := httptest.NewRequest( @@ -301,6 +310,7 @@ func TestHandleRPCSessionStartSucceedsWithExplicitProvider(t *testing.T) { defer externalServer.Close() t.Setenv("INTERNAL_SERVICE_TOKEN", "internal-test-token") + t.Setenv("BRIDGE_AUTH_TOKEN", "") server := NewServer() setTestBridgeProvider(server, syncedProvider{ diff --git a/internal/geminiadapter/server.go b/internal/geminiadapter/server.go index 9b33a66..57ff649 100644 --- a/internal/geminiadapter/server.go +++ b/internal/geminiadapter/server.go @@ -523,12 +523,11 @@ func (s *Server) applyCORS(w http.ResponseWriter, r *http.Request) { } func (s *Server) authorized(r *http.Request) bool { - if s == nil || s.authService == nil { - return true + if s == nil { + return false } - expected := strings.TrimSpace(shared.EnvOrDefault("GEMINI_ADAPTER_AUTH_TOKEN", "")) - if expected == "" { - return true + if s.authService == nil { + return false } return s.authService.ValidateAuthorizationHeader(r.Header.Get("Authorization")) } diff --git a/internal/geminiadapter/server_test.go b/internal/geminiadapter/server_test.go index aac54fe..277f427 100644 --- a/internal/geminiadapter/server_test.go +++ b/internal/geminiadapter/server_test.go @@ -85,6 +85,7 @@ func TestHandleRPCSessionStartReturnsUpstreamResult(t *testing.T) { }, }) request := httptest.NewRequest(http.MethodPost, "http://127.0.0.1/acp/rpc", bytes.NewReader(body)) + request.Header.Set("Authorization", "Bearer test-token") recorder := httptest.NewRecorder() server.HandleRPC(recorder, request) @@ -223,7 +224,9 @@ func TestHandleWebSocketCapabilities(t *testing.T) { defer httpServer.Close() wsURL := "ws" + httpServer.URL[len("http"):] - conn, _, err := websocket.DefaultDialer.Dial(wsURL, nil) + header := http.Header{} + header.Set("Authorization", "Bearer test-token") + conn, _, err := websocket.DefaultDialer.Dial(wsURL, header) if err != nil { t.Fatalf("dial websocket: %v", err) } diff --git a/scripts/github-actions/deploy.sh b/scripts/github-actions/deploy.sh index b2d8c50..2a80ff8 100644 --- a/scripts/github-actions/deploy.sh +++ b/scripts/github-actions/deploy.sh @@ -41,4 +41,5 @@ ANSIBLE_CONFIG="${PWD}/ansible.cfg" \ SERVICE_COMPOSE_IMAGE="${SERVICE_COMPOSE_IMAGE}" \ GHCR_USERNAME="${GHCR_USERNAME:-}" \ GHCR_PASSWORD="${GHCR_PASSWORD:-}" \ +BRIDGE_AUTH_TOKEN="${INTERNAL_SERVICE_TOKEN:-}" \ "${args[@]}"