-
Notifications
You must be signed in to change notification settings - Fork 6
Add tenant isolation for Crew storage (Redis, Manager, Handlers) #549
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
d6ac176
16db083
a5a9e28
d36c40f
93b04dd
39f2e46
c2c69df
f0c6be8
31767ae
9990efc
0d6ac1b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -230,6 +230,7 @@ async def upload(self): | |||||||||||||||||
| { | ||||||||||||||||||
| "message": "Crew uploaded and created successfully", | ||||||||||||||||||
| "crew_id": crew_def.crew_id, | ||||||||||||||||||
| "tenant": crew_def.tenant, | ||||||||||||||||||
| "name": crew_def.name, | ||||||||||||||||||
| "execution_mode": crew_def.execution_mode.value, # pylint: disable=E1101 #noqa | ||||||||||||||||||
| "agents": [agent.agent_id for agent in crew_def.agents], | ||||||||||||||||||
|
|
@@ -285,6 +286,7 @@ async def put(self): | |||||||||||||||||
| # Parse request body | ||||||||||||||||||
| data = await self.request.json() | ||||||||||||||||||
| crew_def = CrewDefinition(**data) | ||||||||||||||||||
| tenant = crew_def.tenant | ||||||||||||||||||
|
|
||||||||||||||||||
| # Validate bot manager availability | ||||||||||||||||||
| if not self.bot_manager: | ||||||||||||||||||
|
|
@@ -296,7 +298,7 @@ async def put(self): | |||||||||||||||||
| ) | ||||||||||||||||||
| # if crew_id is provided, then is an update | ||||||||||||||||||
| if url_crew_id: | ||||||||||||||||||
| existing_crew = await self.bot_manager.get_crew(url_crew_id) | ||||||||||||||||||
| existing_crew = await self.bot_manager.get_crew(url_crew_id, tenant=tenant) | ||||||||||||||||||
| if not existing_crew: | ||||||||||||||||||
| return self.error( | ||||||||||||||||||
| response={ | ||||||||||||||||||
|
|
@@ -311,7 +313,7 @@ async def put(self): | |||||||||||||||||
| crew_def.updated_at = None # Will be set on save | ||||||||||||||||||
|
|
||||||||||||||||||
| # Remove old crew | ||||||||||||||||||
| await self.bot_manager.remove_crew(url_crew_id) | ||||||||||||||||||
| await self.bot_manager.remove_crew(url_crew_id, tenant=tenant) | ||||||||||||||||||
|
|
||||||||||||||||||
| self.logger.info(f"Updating crew '{url_crew_id}'") | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
@@ -335,6 +337,7 @@ async def put(self): | |||||||||||||||||
| { | ||||||||||||||||||
| "message": f"Crew {action} successfully", | ||||||||||||||||||
| "crew_id": crew_def.crew_id, | ||||||||||||||||||
| "tenant": crew_def.tenant, | ||||||||||||||||||
| "name": crew_def.name, | ||||||||||||||||||
| "execution_mode": crew_def.execution_mode.value, # pylint: disable=E1101 | ||||||||||||||||||
| "agents": [agent.agent_id for agent in crew_def.agents], | ||||||||||||||||||
|
|
@@ -380,6 +383,7 @@ async def get(self): | |||||||||||||||||
| match_params = self.match_parameters(self.request) | ||||||||||||||||||
| crew_id = match_params.get('id') or qs.get('crew_id') | ||||||||||||||||||
| crew_name = qs.get('name') | ||||||||||||||||||
| tenant = qs.get('tenant') or "global" | ||||||||||||||||||
|
||||||||||||||||||
| tenant = qs.get('tenant') or "global" | |
| tenant = qs.get('tenant') | |
| if not tenant: | |
| self.logger.warning( | |
| "Tenant parameter missing in CrewHandler.get request; " | |
| "defaulting to 'global'." | |
| ) | |
| tenant = "global" |
phenobarbital marked this conversation as resolved.
Show resolved
Hide resolved
Copilot
AI
Feb 4, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tenant parameter defaults to "global" when not provided, which mirrors the same issue in the GET handler. In a multi-tenant system, silently defaulting to "global" could lead to accidental deletion of global tenant crews when the client intended to delete from a specific tenant but forgot the parameter. Consider making tenant a required parameter or at least validating/logging when the default is used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot open a new pull request to apply changes based on this feedback
Copilot
AI
Feb 4, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to the GET handler, the tenant parameter from the query string is not validated or sanitized. This creates a security risk where malicious tenant values could be used to construct invalid Redis keys or potentially access data from other tenants if the key construction is vulnerable to injection. Implement tenant validation to ensure only safe, expected tenant identifiers are accepted.
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -69,6 +69,10 @@ class CrewDefinition(BaseModel): | |||||
| default_factory=lambda: str(uuid.uuid4()), | ||||||
| description="Unique identifier for the crew" | ||||||
| ) | ||||||
| tenant: str = Field( | ||||||
| default="global", | ||||||
|
||||||
| default="global", | |
| ..., |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tenant parameter from the request body is not validated or sanitized before use. A malicious actor could inject special characters or patterns that could compromise tenant isolation or cause issues with Redis key construction. This is particularly concerning for an execution endpoint where tenant determines which crew is executed. Implement strict tenant validation to prevent injection attacks and ensure proper tenant isolation.