From d5d4db73bddc95cb61c5d80c800288c81f8d9297 Mon Sep 17 00:00:00 2001 From: Roni Ku Date: Sun, 3 May 2026 16:38:00 +0300 Subject: [PATCH 1/2] CM-62381-add-user-email-for-claude-ide --- .../apps/ai_guardrails/session_start_command.py | 14 ++++++++++---- cycode/cyclient/ai_security_manager_client.py | 2 ++ .../ai_guardrails/test_session_start_command.py | 10 +++++++--- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/cycode/cli/apps/ai_guardrails/session_start_command.py b/cycode/cli/apps/ai_guardrails/session_start_command.py index 5218afde..3a8f7c3f 100644 --- a/cycode/cli/apps/ai_guardrails/session_start_command.py +++ b/cycode/cli/apps/ai_guardrails/session_start_command.py @@ -1,5 +1,5 @@ import sys -from typing import TYPE_CHECKING, Annotated +from typing import TYPE_CHECKING, Annotated, Optional import typer @@ -79,7 +79,9 @@ def _get_cursor_session_context() -> tuple[dict, dict]: return mcp_servers, {} -def _report_session_context(ai_client: 'AISecurityManagerClient', ide: str) -> None: +def _report_session_context( + ai_client: 'AISecurityManagerClient', ide: str, user_email: Optional[str] +) -> None: """Report IDE session context to the AI security manager. Never raises.""" try: if ide == AIIDEType.CLAUDE_CODE: @@ -91,7 +93,11 @@ def _report_session_context(ai_client: 'AISecurityManagerClient', ide: str) -> N if not mcp_servers and not enabled_plugins: return - ai_client.report_session_context(mcp_servers=mcp_servers, enabled_plugins=enabled_plugins) + ai_client.report_session_context( + mcp_servers=mcp_servers, + enabled_plugins=enabled_plugins, + user_email=user_email, + ) except Exception as e: logger.debug('Failed to report session context', exc_info=e) @@ -148,4 +154,4 @@ def session_start_command( logger.debug('Failed to create conversation during session start', exc_info=e) # Step 5: Report session context (MCP servers) - _report_session_context(ai_client, ide) + _report_session_context(ai_client, ide, session_payload.ide_user_email) diff --git a/cycode/cyclient/ai_security_manager_client.py b/cycode/cyclient/ai_security_manager_client.py index f4ae31db..f9b7b124 100644 --- a/cycode/cyclient/ai_security_manager_client.py +++ b/cycode/cyclient/ai_security_manager_client.py @@ -95,11 +95,13 @@ def report_session_context( self, mcp_servers: Optional[dict] = None, enabled_plugins: Optional[dict] = None, + user_email: Optional[str] = None, ) -> None: """Report session context to the backend.""" body: dict = { 'mcp_servers': mcp_servers, 'enabled_plugins': enabled_plugins, + 'user_email': user_email, } try: diff --git a/tests/cli/commands/ai_guardrails/test_session_start_command.py b/tests/cli/commands/ai_guardrails/test_session_start_command.py index 48e0ebe3..82a13043 100644 --- a/tests/cli/commands/ai_guardrails/test_session_start_command.py +++ b/tests/cli/commands/ai_guardrails/test_session_start_command.py @@ -222,7 +222,7 @@ def test_claude_code_reports_mcp_servers( 'gitlab': {'command': 'npx', 'args': ['-y', '@modelcontextprotocol/server-gitlab']}, 'filesystem': {'command': 'npx', 'args': ['-y', '@modelcontextprotocol/server-filesystem']}, } - mock_load_config.return_value = {'oauthAccount': {'emailAddress': 'u@e.com'}, 'mcpServers': mcp_servers} + mock_load_config.return_value = {'oauthAccount': {'emailAddress': 'test@test.com'}, 'mcpServers': mcp_servers} # Marketplace won't resolve (no extraKnownMarketplaces) so plugin gets {"enabled": True} only. mock_load_settings.return_value = {'enabledPlugins': {'cycode-dev@cycode-marketplace': True}} @@ -234,6 +234,7 @@ def test_claude_code_reports_mcp_servers( mock_ai_client.report_session_context.assert_called_once_with( mcp_servers=mcp_servers, enabled_plugins={'cycode-dev@cycode-marketplace': {'enabled': True}}, + user_email='test@test.com', ) @@ -293,6 +294,7 @@ def test_claude_code_merges_plugin_mcp_servers_and_metadata( 'mcp_server_names': ['aspire'], } }, + user_email=None, ) @@ -311,7 +313,7 @@ def test_claude_code_no_mcp_servers_no_plugins_skips_report( mock_get_auth.return_value = MagicMock() mock_ai_client = MagicMock() mock_get_client.return_value = mock_ai_client - mock_load_config.return_value = {'oauthAccount': {'emailAddress': 'u@e.com'}} + mock_load_config.return_value = {'oauthAccount': {'emailAddress': 'test@test.com'}} mock_load_settings.return_value = None payload = {'session_id': 'session-123'} @@ -343,7 +345,9 @@ def test_cursor_reports_mcp_servers( with patch('sys.stdin', new=StringIO(json.dumps(payload))): session_start_command(mock_ctx, ide='cursor') - mock_ai_client.report_session_context.assert_called_once_with(mcp_servers=mcp_servers, enabled_plugins={}) + mock_ai_client.report_session_context.assert_called_once_with( + mcp_servers=mcp_servers, enabled_plugins={}, user_email=None + ) @patch.object(_session_start_mod, 'load_cursor_config') From 8b9dd1d6c9f8995c9b7f10e93b0c9bc66c6f86b3 Mon Sep 17 00:00:00 2001 From: Roni Ku Date: Mon, 4 May 2026 10:30:08 +0300 Subject: [PATCH 2/2] CM-62381-reformat --- cycode/cli/apps/ai_guardrails/session_start_command.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cycode/cli/apps/ai_guardrails/session_start_command.py b/cycode/cli/apps/ai_guardrails/session_start_command.py index 3a8f7c3f..f2d5031c 100644 --- a/cycode/cli/apps/ai_guardrails/session_start_command.py +++ b/cycode/cli/apps/ai_guardrails/session_start_command.py @@ -79,9 +79,7 @@ def _get_cursor_session_context() -> tuple[dict, dict]: return mcp_servers, {} -def _report_session_context( - ai_client: 'AISecurityManagerClient', ide: str, user_email: Optional[str] -) -> None: +def _report_session_context(ai_client: 'AISecurityManagerClient', ide: str, user_email: Optional[str]) -> None: """Report IDE session context to the AI security manager. Never raises.""" try: if ide == AIIDEType.CLAUDE_CODE: