fix: respect authentication status for first-time users

Previously, _initialize_batch forced use_ephemeral=True for all
  first-time users, bypassing _check_authenticated() entirely. This
  meant logged-in users in a new project directory were routed to the
  ephemeral endpoint instead of their account's tracing endpoint.

  Now _check_authenticated() runs for all users including first-time.
  Authenticated first-time users get non-ephemeral tracing (traces
  linked to their account); only unauthenticated first-time users
  fall back to ephemeral. The deferred backend init in
  FirstTimeTraceHandler also reads is_current_batch_ephemeral instead
  of hardcoding use_ephemeral=True.
This commit is contained in:
Tiago Freire
2026-03-18 14:31:10 -03:00
parent 4141233a78
commit bcba620a41
3 changed files with 107 additions and 3 deletions

View File

@@ -99,7 +99,7 @@ class FirstTimeTraceHandler:
self.batch_manager._initialize_backend_batch(
user_context=user_context,
execution_metadata=execution_metadata,
use_ephemeral=True,
use_ephemeral=self.batch_manager.is_current_batch_ephemeral,
)
if not self.batch_manager.trace_batch_id:

View File

@@ -706,13 +706,14 @@ class TraceCollectionListener(BaseEventListener):
user_context: User context information.
execution_metadata: Metadata about the execution.
"""
use_ephemeral = not self._check_authenticated()
if self.first_time_handler.is_first_time:
self.batch_manager.initialize_batch(
user_context, execution_metadata, use_ephemeral=True
user_context, execution_metadata, use_ephemeral=use_ephemeral
)
return
use_ephemeral = not self._check_authenticated()
self.batch_manager.initialize_batch(
user_context, execution_metadata, use_ephemeral=use_ephemeral
)

View File

@@ -1344,3 +1344,106 @@ class TestFirstTimeHandlerBackendInitGuard:
mock_send.assert_not_called()
mock_finalize.assert_not_called()
mock_fail.assert_called_once()
class TestFirstTimeAuthRespected:
"""Tests for Fix 3: first-time users respect authentication status."""
def test_first_time_authenticated_uses_non_ephemeral(self):
"""Authenticated first-time user should use non-ephemeral (use_ephemeral=False)."""
with (
patch(
"crewai.events.listeners.tracing.trace_batch_manager.get_auth_token",
return_value="mock_token",
),
patch(
"crewai.events.listeners.tracing.trace_listener.get_auth_token",
return_value="mock_token",
),
):
from crewai.events.listeners.tracing.trace_listener import TraceCollectionListener
listener = TraceCollectionListener.__new__(TraceCollectionListener)
listener.first_time_handler = FirstTimeTraceHandler()
listener.first_time_handler.is_first_time = True
listener.batch_manager = TraceBatchManager()
with patch.object(
listener.batch_manager, "initialize_batch"
) as mock_init_batch:
listener._initialize_batch(
user_context={"privacy_level": "standard"},
execution_metadata={"execution_type": "crew"},
)
mock_init_batch.assert_called_once_with(
{"privacy_level": "standard"},
{"execution_type": "crew"},
use_ephemeral=False,
)
def test_first_time_unauthenticated_uses_ephemeral(self):
"""Unauthenticated first-time user should use ephemeral (use_ephemeral=True)."""
with (
patch(
"crewai.events.listeners.tracing.trace_batch_manager.get_auth_token",
return_value="mock_token",
),
patch(
"crewai.events.listeners.tracing.trace_listener.get_auth_token",
return_value=None,
),
):
from crewai.events.listeners.tracing.trace_listener import TraceCollectionListener
listener = TraceCollectionListener.__new__(TraceCollectionListener)
listener.first_time_handler = FirstTimeTraceHandler()
listener.first_time_handler.is_first_time = True
listener.batch_manager = TraceBatchManager()
with patch.object(
listener.batch_manager, "initialize_batch"
) as mock_init_batch:
listener._initialize_batch(
user_context={"privacy_level": "standard"},
execution_metadata={"execution_type": "crew"},
)
mock_init_batch.assert_called_once_with(
{"privacy_level": "standard"},
{"execution_type": "crew"},
use_ephemeral=True,
)
def test_first_time_handler_deferred_init_uses_batch_ephemeral_flag(self):
"""Deferred backend init should use is_current_batch_ephemeral, not hardcoded True."""
with patch(
"crewai.events.listeners.tracing.trace_batch_manager.get_auth_token",
return_value="mock_token",
):
bm = TraceBatchManager()
bm.current_batch = TraceBatch(
user_context={"privacy_level": "standard"},
execution_metadata={"execution_type": "crew", "crew_name": "test"},
)
bm.trace_batch_id = bm.current_batch.batch_id
bm.is_current_batch_ephemeral = False # authenticated user
handler = FirstTimeTraceHandler()
handler.is_first_time = True
handler.collected_events = True
handler.batch_manager = bm
with (
patch.object(bm, "_initialize_backend_batch") as mock_init,
patch.object(bm, "_send_events_to_backend"),
patch.object(bm, "finalize_batch"),
):
# trace_batch_id stays set (simulating success)
mock_init.side_effect = lambda **kwargs: None
bm.event_buffer = [MagicMock()]
handler._initialize_backend_and_send_events()
mock_init.assert_called_once()
call_kwargs = mock_init.call_args
assert call_kwargs.kwargs["use_ephemeral"] is False