Implement event-based logging for encrypted agent communication

Co-authored-by: theCyberTech <84775494+theCyberTech@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2025-08-13 05:48:00 +00:00
parent 09226e34b2
commit 8d88ed3ef9
5 changed files with 493 additions and 8 deletions

View File

@@ -14,6 +14,13 @@ from cryptography.fernet import Fernet
from pydantic import BaseModel, Field
from crewai.security.fingerprint import Fingerprint
from crewai.utilities.events.crewai_event_bus import crewai_event_bus
from crewai.utilities.events.encryption_events import (
EncryptionStartedEvent,
EncryptionCompletedEvent,
DecryptionStartedEvent,
DecryptionCompletedEvent,
)
logger = logging.getLogger(__name__)
@@ -42,14 +49,16 @@ class AgentCommunicationEncryption:
Provides methods to encrypt and decrypt communication payloads.
"""
def __init__(self, agent_fingerprint: Fingerprint):
def __init__(self, agent_fingerprint: Fingerprint, agent=None):
"""
Initialize encryption handler for an agent.
Args:
agent_fingerprint (Fingerprint): The agent's unique fingerprint
agent: The agent instance (optional, needed for events)
"""
self.agent_fingerprint = agent_fingerprint
self.agent = agent
self._encryption_keys: Dict[str, Fernet] = {}
def _derive_communication_key(self, sender_fp: str, recipient_fp: str) -> bytes:
@@ -102,7 +111,8 @@ class AgentCommunicationEncryption:
self,
message: Union[str, Dict[str, Any]],
recipient_fingerprint: Fingerprint,
message_type: str = "communication"
message_type: str = "communication",
recipient_agent=None
) -> EncryptedMessage:
"""
Encrypt a message for a specific recipient agent.
@@ -111,6 +121,7 @@ class AgentCommunicationEncryption:
message (Union[str, Dict[str, Any]]): The message to encrypt
recipient_fingerprint (Fingerprint): The recipient agent's fingerprint
message_type (str): Type of message being sent
recipient_agent: The recipient agent instance (optional, needed for events)
Returns:
EncryptedMessage: Encrypted message container
@@ -119,6 +130,17 @@ class AgentCommunicationEncryption:
ValueError: If encryption fails
"""
try:
# Emit encryption started event if both agents are available
if self.agent and recipient_agent:
crewai_event_bus.emit(
self.agent,
EncryptionStartedEvent(
sender_agent=self.agent,
recipient_agent=recipient_agent,
message_type=message_type
)
)
logger.info(f"Starting encryption for {message_type} message to recipient {recipient_fingerprint.uuid_str[:8]}...")
# Convert message to JSON string if it's a dict
@@ -137,6 +159,17 @@ class AgentCommunicationEncryption:
encrypted_bytes = fernet.encrypt(message_str.encode('utf-8'))
encrypted_payload = encrypted_bytes.decode('utf-8')
# Emit encryption completed event if both agents are available
if self.agent and recipient_agent:
crewai_event_bus.emit(
self.agent,
EncryptionCompletedEvent(
sender_agent=self.agent,
recipient_agent=recipient_agent,
message_type=message_type
)
)
logger.info(f"Successfully encrypted {message_type} message from {self.agent_fingerprint.uuid_str[:8]}... to {recipient_fingerprint.uuid_str[:8]}...")
logger.debug(f"Encrypted message from {self.agent_fingerprint.uuid_str[:8]}... to {recipient_fingerprint.uuid_str[:8]}...")
@@ -165,6 +198,17 @@ class AgentCommunicationEncryption:
ValueError: If decryption fails or message is not for this agent
"""
try:
# Emit decryption started event if agent is available
if self.agent:
crewai_event_bus.emit(
self.agent,
DecryptionStartedEvent(
recipient_agent=self.agent,
sender_fingerprint=encrypted_message.sender_fingerprint,
message_type=encrypted_message.message_type
)
)
logger.info(f"Starting decryption of {encrypted_message.message_type} message from sender {encrypted_message.sender_fingerprint[:8]}...")
# Verify this message is intended for this agent
@@ -186,6 +230,17 @@ class AgentCommunicationEncryption:
decrypted_content = json.loads(decrypted_str)
except json.JSONDecodeError:
decrypted_content = decrypted_str
# Emit decryption completed event if agent is available
if self.agent:
crewai_event_bus.emit(
self.agent,
DecryptionCompletedEvent(
recipient_agent=self.agent,
sender_fingerprint=encrypted_message.sender_fingerprint,
message_type=encrypted_message.message_type
)
)
logger.info(f"Successfully decrypted {encrypted_message.message_type} message from {encrypted_message.sender_fingerprint[:8]}... to {encrypted_message.recipient_fingerprint[:8]}...")

View File

@@ -8,6 +8,12 @@ from crewai.task import Task
from crewai.tools.base_tool import BaseTool
from crewai.utilities import I18N
from crewai.security import AgentCommunicationEncryption, EncryptedMessage
from crewai.utilities.events.crewai_event_bus import crewai_event_bus
from crewai.utilities.events.encryption_events import (
EncryptedCommunicationStartedEvent,
EncryptedCommunicationEstablishedEvent,
EncryptedTaskExecutionEvent,
)
logger = logging.getLogger(__name__)
@@ -44,10 +50,11 @@ class BaseAgentTool(BaseTool):
if not getattr(sender_agent.security_config, 'encrypted_communication', False):
return None
# Create encryption handler if it doesn't exist
# Create encryption handler if it doesn't exist, passing the agent instance
if self._encryption_handler is None:
self._encryption_handler = AgentCommunicationEncryption(
sender_agent.security_config.fingerprint
sender_agent.security_config.fingerprint,
agent=sender_agent
)
return self._encryption_handler
@@ -83,13 +90,33 @@ class BaseAgentTool(BaseTool):
encryption_handler = self._get_encryption_handler(sender_agent)
if encryption_handler and hasattr(recipient_agent, 'security_config') and recipient_agent.security_config:
try:
# Emit communication started event
crewai_event_bus.emit(
sender_agent,
EncryptedCommunicationStartedEvent(
sender_agent=sender_agent,
recipient_agent=recipient_agent
)
)
logger.info(f"Starting encrypted communication from '{sender_agent.role}' to '{recipient_agent.role}'")
# Encrypt the message for the recipient
encrypted_msg = encryption_handler.encrypt_message(
message_payload,
recipient_agent.security_config.fingerprint,
message_type="agent_communication"
message_type="agent_communication",
recipient_agent=recipient_agent
)
# Emit communication established event
crewai_event_bus.emit(
sender_agent,
EncryptedCommunicationEstablishedEvent(
sender_agent=sender_agent,
recipient_agent=recipient_agent
)
)
logger.info(f"Encrypted communication established between '{sender_agent.role}' and '{recipient_agent.role}'")
logger.debug(f"Encrypted communication from {sender_agent.role} to {recipient_agent.role}")
return encrypted_msg
@@ -117,15 +144,23 @@ class BaseAgentTool(BaseTool):
if isinstance(message, EncryptedMessage) or (
isinstance(message, dict) and 'encrypted_payload' in message
):
encryption_handler = self._get_encryption_handler(recipient_agent)
if encryption_handler:
# We need an encryption handler for the recipient agent
recipient_encryption_handler = None
if hasattr(recipient_agent, 'security_config') and recipient_agent.security_config:
if getattr(recipient_agent.security_config, 'encrypted_communication', False):
recipient_encryption_handler = AgentCommunicationEncryption(
recipient_agent.security_config.fingerprint,
agent=recipient_agent
)
if recipient_encryption_handler:
try:
logger.info(f"Starting decryption of received communication for '{recipient_agent.role}'")
# Convert dict to EncryptedMessage if needed
if isinstance(message, dict):
message = EncryptedMessage(**message)
decrypted = encryption_handler.decrypt_message(message)
decrypted = recipient_encryption_handler.decrypt_message(message)
logger.info(f"Successfully decrypted communication for '{recipient_agent.role}'")
logger.debug(f"Decrypted communication for {recipient_agent.role}")
return decrypted
@@ -257,6 +292,14 @@ class BaseAgentTool(BaseTool):
# Execute with processed communication context
if isinstance(communication_payload, EncryptedMessage):
# Emit encrypted task execution event
crewai_event_bus.emit(
target_agent,
EncryptedTaskExecutionEvent(
agent=target_agent
)
)
logger.info(f"Executing encrypted communication task for agent '{self.sanitize_agent_name(target_agent.role)}'")
logger.debug(f"Executing encrypted communication task for agent '{self.sanitize_agent_name(target_agent.role)}'")
# For encrypted messages, pass the encrypted payload as additional context

View File

@@ -0,0 +1,165 @@
"""
Encryption events for agent-to-agent communication
"""
from typing import Optional
from crewai.agents.agent_builder.base_agent import BaseAgent
from .base_events import BaseEvent
class EncryptionStartedEvent(BaseEvent):
"""Event emitted when agent-to-agent encryption starts"""
sender_agent: BaseAgent
recipient_agent: BaseAgent
message_type: str = "agent_communication"
type: str = "encryption_started"
model_config = {"arbitrary_types_allowed": True}
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the sender agent
if hasattr(self.sender_agent, "fingerprint") and self.sender_agent.fingerprint:
self.source_fingerprint = self.sender_agent.fingerprint.uuid_str
self.source_type = "agent"
if (
hasattr(self.sender_agent.fingerprint, "metadata")
and self.sender_agent.fingerprint.metadata
):
self.fingerprint_metadata = self.sender_agent.fingerprint.metadata
class EncryptionCompletedEvent(BaseEvent):
"""Event emitted when agent-to-agent encryption completes successfully"""
sender_agent: BaseAgent
recipient_agent: BaseAgent
message_type: str = "agent_communication"
type: str = "encryption_completed"
model_config = {"arbitrary_types_allowed": True}
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the sender agent
if hasattr(self.sender_agent, "fingerprint") and self.sender_agent.fingerprint:
self.source_fingerprint = self.sender_agent.fingerprint.uuid_str
self.source_type = "agent"
if (
hasattr(self.sender_agent.fingerprint, "metadata")
and self.sender_agent.fingerprint.metadata
):
self.fingerprint_metadata = self.sender_agent.fingerprint.metadata
class DecryptionStartedEvent(BaseEvent):
"""Event emitted when agent-to-agent decryption starts"""
recipient_agent: BaseAgent
sender_fingerprint: str
message_type: str = "agent_communication"
type: str = "decryption_started"
model_config = {"arbitrary_types_allowed": True}
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the recipient agent
if hasattr(self.recipient_agent, "fingerprint") and self.recipient_agent.fingerprint:
self.source_fingerprint = self.recipient_agent.fingerprint.uuid_str
self.source_type = "agent"
if (
hasattr(self.recipient_agent.fingerprint, "metadata")
and self.recipient_agent.fingerprint.metadata
):
self.fingerprint_metadata = self.recipient_agent.fingerprint.metadata
class DecryptionCompletedEvent(BaseEvent):
"""Event emitted when agent-to-agent decryption completes successfully"""
recipient_agent: BaseAgent
sender_fingerprint: str
message_type: str = "agent_communication"
type: str = "decryption_completed"
model_config = {"arbitrary_types_allowed": True}
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the recipient agent
if hasattr(self.recipient_agent, "fingerprint") and self.recipient_agent.fingerprint:
self.source_fingerprint = self.recipient_agent.fingerprint.uuid_str
self.source_type = "agent"
if (
hasattr(self.recipient_agent.fingerprint, "metadata")
and self.recipient_agent.fingerprint.metadata
):
self.fingerprint_metadata = self.recipient_agent.fingerprint.metadata
class EncryptedCommunicationStartedEvent(BaseEvent):
"""Event emitted when encrypted communication between agents begins"""
sender_agent: BaseAgent
recipient_agent: BaseAgent
type: str = "encrypted_communication_started"
model_config = {"arbitrary_types_allowed": True}
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the sender agent
if hasattr(self.sender_agent, "fingerprint") and self.sender_agent.fingerprint:
self.source_fingerprint = self.sender_agent.fingerprint.uuid_str
self.source_type = "agent"
if (
hasattr(self.sender_agent.fingerprint, "metadata")
and self.sender_agent.fingerprint.metadata
):
self.fingerprint_metadata = self.sender_agent.fingerprint.metadata
class EncryptedCommunicationEstablishedEvent(BaseEvent):
"""Event emitted when encrypted communication is successfully established"""
sender_agent: BaseAgent
recipient_agent: BaseAgent
type: str = "encrypted_communication_established"
model_config = {"arbitrary_types_allowed": True}
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the sender agent
if hasattr(self.sender_agent, "fingerprint") and self.sender_agent.fingerprint:
self.source_fingerprint = self.sender_agent.fingerprint.uuid_str
self.source_type = "agent"
if (
hasattr(self.sender_agent.fingerprint, "metadata")
and self.sender_agent.fingerprint.metadata
):
self.fingerprint_metadata = self.sender_agent.fingerprint.metadata
class EncryptedTaskExecutionEvent(BaseEvent):
"""Event emitted when an encrypted communication task is being executed"""
agent: BaseAgent
task_type: str = "encrypted_communication"
type: str = "encrypted_task_execution"
model_config = {"arbitrary_types_allowed": True}
def __init__(self, **data):
super().__init__(**data)
# Set fingerprint data from the agent
if hasattr(self.agent, "fingerprint") and self.agent.fingerprint:
self.source_fingerprint = self.agent.fingerprint.uuid_str
self.source_type = "agent"
if (
hasattr(self.agent.fingerprint, "metadata")
and self.agent.fingerprint.metadata
):
self.fingerprint_metadata = self.agent.fingerprint.metadata

View File

@@ -37,6 +37,15 @@ from .agent_events import (
LiteAgentExecutionErrorEvent,
LiteAgentExecutionStartedEvent,
)
from .encryption_events import (
EncryptionStartedEvent,
EncryptionCompletedEvent,
DecryptionStartedEvent,
DecryptionCompletedEvent,
EncryptedCommunicationStartedEvent,
EncryptedCommunicationEstablishedEvent,
EncryptedTaskExecutionEvent,
)
from .crew_events import (
CrewKickoffCompletedEvent,
CrewKickoffFailedEvent,
@@ -513,5 +522,70 @@ class EventListener(BaseEventListener):
event.verbose,
)
# Encryption event handlers
@crewai_event_bus.on(EncryptedCommunicationStartedEvent)
def on_encrypted_communication_started(source, event: EncryptedCommunicationStartedEvent):
self.formatter.handle_encryption_communication_started(
event.sender_agent.role,
event.recipient_agent.role
)
@crewai_event_bus.on(EncryptedCommunicationEstablishedEvent)
def on_encrypted_communication_established(source, event: EncryptedCommunicationEstablishedEvent):
self.formatter.handle_encryption_communication_established(
event.sender_agent.role,
event.recipient_agent.role
)
@crewai_event_bus.on(EncryptionStartedEvent)
def on_encryption_started(source, event: EncryptionStartedEvent):
recipient_fingerprint = ""
if hasattr(event.recipient_agent, "fingerprint") and event.recipient_agent.fingerprint:
recipient_fingerprint = event.recipient_agent.fingerprint.uuid_str[:8] + "..."
self.formatter.handle_encryption_started(
event.message_type,
recipient_fingerprint
)
@crewai_event_bus.on(EncryptionCompletedEvent)
def on_encryption_completed(source, event: EncryptionCompletedEvent):
sender_fingerprint = ""
recipient_fingerprint = ""
if hasattr(event.sender_agent, "fingerprint") and event.sender_agent.fingerprint:
sender_fingerprint = event.sender_agent.fingerprint.uuid_str[:8] + "..."
if hasattr(event.recipient_agent, "fingerprint") and event.recipient_agent.fingerprint:
recipient_fingerprint = event.recipient_agent.fingerprint.uuid_str[:8] + "..."
self.formatter.handle_encryption_completed(
event.message_type,
sender_fingerprint,
recipient_fingerprint
)
@crewai_event_bus.on(DecryptionStartedEvent)
def on_decryption_started(source, event: DecryptionStartedEvent):
sender_fingerprint = event.sender_fingerprint[:8] + "..." if event.sender_fingerprint else ""
self.formatter.handle_decryption_started(
event.message_type,
sender_fingerprint
)
@crewai_event_bus.on(DecryptionCompletedEvent)
def on_decryption_completed(source, event: DecryptionCompletedEvent):
sender_fingerprint = event.sender_fingerprint[:8] + "..." if event.sender_fingerprint else ""
recipient_fingerprint = ""
if hasattr(event.recipient_agent, "fingerprint") and event.recipient_agent.fingerprint:
recipient_fingerprint = event.recipient_agent.fingerprint.uuid_str[:8] + "..."
self.formatter.handle_decryption_completed(
event.message_type,
sender_fingerprint,
recipient_fingerprint
)
@crewai_event_bus.on(EncryptedTaskExecutionEvent)
def on_encrypted_task_execution(source, event: EncryptedTaskExecutionEvent):
self.formatter.handle_encrypted_task_execution(
event.agent.role
)
event_listener = EventListener()

View File

@@ -1754,3 +1754,151 @@ class ConsoleFormatter:
Attempts=f"{retry_count + 1}",
)
self.print_panel(content, "🛡️ Guardrail Failed", "red")
# Encryption event handlers
def handle_encryption_communication_started(
self, sender_role: str, recipient_role: str
) -> None:
"""Handle encrypted communication started event."""
if not self.verbose:
return
content = Text()
content.append("Starting encrypted communication from '", style="white")
content.append(f"{sender_role}", style="bright_cyan bold")
content.append("' to '", style="white")
content.append(f"{recipient_role}", style="bright_cyan bold")
content.append("'", style="white")
panel = Panel(
content,
title="🔐 Encrypted Communication",
border_style="cyan",
padding=(0, 1),
)
self.print(panel)
def handle_encryption_communication_established(
self, sender_role: str, recipient_role: str
) -> None:
"""Handle encrypted communication established event."""
if not self.verbose:
return
content = Text()
content.append("Encrypted communication established between '", style="white")
content.append(f"{sender_role}", style="bright_green bold")
content.append("' and '", style="white")
content.append(f"{recipient_role}", style="bright_green bold")
content.append("'", style="white")
panel = Panel(
content,
title="✅ Communication Secured",
border_style="green",
padding=(0, 1),
)
self.print(panel)
def handle_encryption_started(
self, message_type: str, recipient_fingerprint: str
) -> None:
"""Handle encryption started event."""
if not self.verbose:
return
content = Text()
content.append(f"Starting encryption for {message_type} message to recipient ", style="white")
content.append(f"{recipient_fingerprint}", style="bright_yellow")
content.append("...", style="white")
panel = Panel(
content,
title="🔒 Encrypting Message",
border_style="yellow",
padding=(0, 1),
)
self.print(panel)
def handle_encryption_completed(
self, message_type: str, sender_fingerprint: str, recipient_fingerprint: str
) -> None:
"""Handle encryption completed event."""
if not self.verbose:
return
content = Text()
content.append(f"Successfully encrypted {message_type} message from ", style="white")
content.append(f"{sender_fingerprint}", style="bright_green")
content.append(" to ", style="white")
content.append(f"{recipient_fingerprint}", style="bright_green")
content.append("...", style="white")
panel = Panel(
content,
title="✅ Message Encrypted",
border_style="green",
padding=(0, 1),
)
self.print(panel)
def handle_decryption_started(
self, message_type: str, sender_fingerprint: str
) -> None:
"""Handle decryption started event."""
if not self.verbose:
return
content = Text()
content.append(f"Starting decryption of {message_type} message from sender ", style="white")
content.append(f"{sender_fingerprint}", style="bright_yellow")
content.append("...", style="white")
panel = Panel(
content,
title="🔓 Decrypting Message",
border_style="yellow",
padding=(0, 1),
)
self.print(panel)
def handle_decryption_completed(
self, message_type: str, sender_fingerprint: str, recipient_fingerprint: str
) -> None:
"""Handle decryption completed event."""
if not self.verbose:
return
content = Text()
content.append(f"Successfully decrypted {message_type} message from ", style="white")
content.append(f"{sender_fingerprint}", style="bright_green")
content.append(" to ", style="white")
content.append(f"{recipient_fingerprint}", style="bright_green")
content.append("...", style="white")
panel = Panel(
content,
title="✅ Message Decrypted",
border_style="green",
padding=(0, 1),
)
self.print(panel)
def handle_encrypted_task_execution(self, agent_role: str) -> None:
"""Handle encrypted task execution event."""
if not self.verbose:
return
content = Text()
content.append("Executing encrypted communication task for agent '", style="white")
content.append(f"{agent_role}", style="bright_blue bold")
content.append("'", style="white")
panel = Panel(
content,
title="🔐 Executing Encrypted Task",
border_style="blue",
padding=(0, 1),
)
self.print(panel)