Skip to content

Commit 2eccb08

Browse files
committed
feat(python_repl): add configurable security modes with file path restrictions
- Add SecurityMode enum with NORMAL and RESTRICTED modes - Implement ASTSecurityValidator for static code analysis - Add file path whitelist system with PYTHON_REPL_ALLOWED_PATHS - Block dangerous imports, builtins, and attributes in restricted mode - Add resource limits (memory, CPU) with configurable timeouts - Implement protection against path traversal and symlink bypass - Add comprehensive test suite covering all security features - Update documentation with security configuration examples BREAKING CHANGE: None - feature is opt-in via PYTHON_REPL_RESTRICTED_MODE=true Environment Variables: - PYTHON_REPL_RESTRICTED_MODE: Enable/disable restricted mode (default: false) - PYTHON_REPL_ALLOWED_PATHS: Comma-separated allowed directories - PYTHON_REPL_ALLOW_CURRENT_DIR: Allow current directory access (default: true) - PYTHON_REPL_TIMEOUT: Execution timeout in seconds (default: 30) - PYTHON_REPL_MEMORY_LIMIT_MB: Memory limit in MB (default: 100) Refs: #192
1 parent e0619e1 commit 2eccb08

File tree

3 files changed

+501
-144
lines changed

3 files changed

+501
-144
lines changed

README.md

Lines changed: 1 addition & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ Strands Agents Tools is a community-driven project that provides a powerful set
3939
- 📁 **File Operations** - Read, write, and edit files with syntax highlighting and intelligent modifications
4040
- 🖥️ **Shell Integration** - Execute and interact with shell commands securely
4141
- 🧠 **Memory** - Store user and agent memories across agent runs to provide personalized experiences with both Mem0 and Amazon Bedrock Knowledge Bases
42-
- 🕸️ **Web Infrastructure** - Perform web searches, extract page content, and crawl websites with Tavily and Exa-powered tools
4342
- 🌐 **HTTP Client** - Make API requests with comprehensive authentication support
4443
- 💬 **Slack Client** - Real-time Slack events, message processing, and Slack API access
4544
- 🐍 **Python Execution** - Run Python code snippets with state persistence, user confirmation for code execution, and safety features
@@ -104,12 +103,6 @@ Below is a comprehensive table of all available tools, how to use them with an a
104103
| editor | `agent.tool.editor(command="view", path="path/to/file.py")` | Advanced file operations like syntax highlighting, pattern replacement, and multi-file edits |
105104
| shell* | `agent.tool.shell(command="ls -la")` | Executing shell commands, interacting with the operating system, running scripts |
106105
| http_request | `agent.tool.http_request(method="GET", url="https://api.example.com/data")` | Making API calls, fetching web data, sending data to external services |
107-
| tavily_search | `agent.tool.tavily_search(query="What is artificial intelligence?", search_depth="advanced")` | Real-time web search optimized for AI agents with a variety of custom parameters |
108-
| tavily_extract | `agent.tool.tavily_extract(urls=["www.tavily.com"], extract_depth="advanced")` | Extract clean, structured content from web pages with advanced processing and noise removal |
109-
| tavily_crawl | `agent.tool.tavily_crawl(url="www.tavily.com", max_depth=2, instructions="Find API docs")` | Crawl websites intelligently starting from a base URL with filtering and extraction |
110-
| tavily_map | `agent.tool.tavily_map(url="www.tavily.com", max_depth=2, instructions="Find all pages")` | Map website structure and discover URLs starting from a base URL without content extraction |
111-
| exa_search | `agent.tool.exa_search(query="Best project management tools", text=True)` | Intelligent web search with auto mode (default) that combines neural and keyword search for optimal results |
112-
| exa_get_contents | `agent.tool.exa_get_contents(urls=["https://example.com/article"], text=True, summary={"query": "key points"})` | Extract full content and summaries from specific URLs with live crawling fallback |
113106
| python_repl* | `agent.tool.python_repl(code="import pandas as pd\ndf = pd.read_csv('data.csv')\nprint(df.head())")` | Running Python code snippets, data analysis, executing complex logic with user confirmation for security |
114107
| calculator | `agent.tool.calculator(expression="2 * sin(pi/4) + log(e**2)")` | Performing mathematical operations, symbolic math, equation solving |
115108
| code_interpreter | `code_interpreter = AgentCoreCodeInterpreter(region="us-west-2"); agent = Agent(tools=[code_interpreter.code_interpreter])` | Execute code in isolated sandbox environments with multi-language support (Python, JavaScript, TypeScript), persistent sessions, and file operations |
@@ -275,114 +268,6 @@ response = agent.tool.http_request(
275268
)
276269
```
277270

278-
### Tavily Search, Extract, Crawl, and Map
279-
280-
```python
281-
from strands import Agent
282-
from strands_tools.tavily import (
283-
tavily_search, tavily_extract, tavily_crawl, tavily_map
284-
)
285-
286-
# For async usage, call the corresponding *_async function with await.
287-
# Synchronous usage
288-
agent = Agent(tools=[tavily_search, tavily_extract, tavily_crawl, tavily_map])
289-
290-
# Real-time web search
291-
result = agent.tool.tavily_search(
292-
query="Latest developments in renewable energy",
293-
search_depth="advanced",
294-
topic="news",
295-
max_results=10,
296-
include_raw_content=True
297-
)
298-
299-
# Extract content from multiple URLs
300-
result = agent.tool.tavily_extract(
301-
urls=["www.tavily.com", "www.apple.com"],
302-
extract_depth="advanced",
303-
format="markdown"
304-
)
305-
306-
# Advanced crawl with instructions and filtering
307-
result = agent.tool.tavily_crawl(
308-
url="www.tavily.com",
309-
max_depth=2,
310-
limit=50,
311-
instructions="Find all API documentation and developer guides",
312-
extract_depth="advanced",
313-
include_images=True
314-
)
315-
316-
# Basic website mapping
317-
result = agent.tool.tavily_map(url="www.tavily.com")
318-
319-
```
320-
321-
### Exa Search and Contents
322-
323-
```python
324-
from strands import Agent
325-
from strands_tools.exa import exa_search, exa_get_contents
326-
327-
agent = Agent(tools=[exa_search, exa_get_contents])
328-
329-
# Basic search (auto mode is default and recommended)
330-
result = agent.tool.exa_search(
331-
query="Best project management software",
332-
text=True
333-
)
334-
335-
# Company-specific search when needed
336-
result = agent.tool.exa_search(
337-
query="Anthropic AI safety research",
338-
category="company",
339-
include_domains=["anthropic.com"],
340-
num_results=5,
341-
summary={"query": "key research areas and findings"}
342-
)
343-
344-
# News search with date filtering
345-
result = agent.tool.exa_search(
346-
query="AI regulation policy updates",
347-
category="news",
348-
start_published_date="2024-01-01T00:00:00.000Z",
349-
text=True
350-
)
351-
352-
# Get detailed content from specific URLs
353-
result = agent.tool.exa_get_contents(
354-
urls=[
355-
"https://example.com/blog-post",
356-
"https://github.com/microsoft/semantic-kernel"
357-
],
358-
text={"maxCharacters": 5000, "includeHtmlTags": False},
359-
summary={
360-
"query": "main points and practical applications"
361-
},
362-
subpages=2,
363-
extras={"links": 5, "imageLinks": 2}
364-
)
365-
366-
# Structured summary with JSON schema
367-
result = agent.tool.exa_get_contents(
368-
urls=["https://example.com/article"],
369-
summary={
370-
"query": "main findings and recommendations",
371-
"schema": {
372-
"type": "object",
373-
"properties": {
374-
"main_points": {"type": "string", "description": "Key points from the article"},
375-
"recommendations": {"type": "string", "description": "Suggested actions or advice"},
376-
"conclusion": {"type": "string", "description": "Overall conclusion"},
377-
"relevance": {"type": "string", "description": "Why this matters"}
378-
},
379-
"required": ["main_points", "conclusion"]
380-
}
381-
}
382-
)
383-
384-
```
385-
386271
### Python Code Execution
387272

388273
*Note: `python_repl` does not work on Windows.*
@@ -797,20 +682,6 @@ These variables affect multiple tools:
797682
|----------------------|-------------|---------|
798683
| MAX_SLEEP_SECONDS | Maximum allowed sleep duration in seconds | 300 |
799684

800-
#### Tavily Search, Extract, Crawl, and Map Tools
801-
802-
| Environment Variable | Description | Default |
803-
|----------------------|-------------|---------|
804-
| TAVILY_API_KEY | Tavily API key (required for all Tavily functionality) | None |
805-
- Visit https://www.tavily.com/ to create a free account and API key.
806-
807-
#### Exa Search and Contents Tools
808-
809-
| Environment Variable | Description | Default |
810-
|----------------------|-------------|---------|
811-
| EXA_API_KEY | Exa API key (required for all Exa functionality) | None |
812-
- Visit https://dashboard.exa.ai/api-keys to create a free account and API key.
813-
814685
#### Mem0 Memory Tool
815686

816687
The Mem0 Memory Tool supports three different backend configurations:
@@ -833,19 +704,12 @@ The Mem0 Memory Tool supports three different backend configurations:
833704
| OPENSEARCH_HOST | OpenSearch Host URL | None | OpenSearch |
834705
| AWS_REGION | AWS Region for OpenSearch | us-west-2 | OpenSearch |
835706
| DEV | Enable development mode (bypasses confirmations) | false | All modes |
836-
| MEM0_LLM_PROVIDER | LLM provider for memory processing | aws_bedrock | All modes |
837-
| MEM0_LLM_MODEL | LLM model for memory processing | anthropic.claude-3-5-haiku-20241022-v1:0 | All modes |
838-
| MEM0_LLM_TEMPERATURE | LLM temperature (0.0-2.0) | 0.1 | All modes |
839-
| MEM0_LLM_MAX_TOKENS | LLM maximum tokens | 2000 | All modes |
840-
| MEM0_EMBEDDER_PROVIDER | Embedder provider for vector embeddings | aws_bedrock | All modes |
841-
| MEM0_EMBEDDER_MODEL | Embedder model for vector embeddings | amazon.titan-embed-text-v2:0 | All modes |
842-
843707

844708
**Note**:
845709
- If `MEM0_API_KEY` is set, the tool will use the Mem0 Platform
846710
- If `OPENSEARCH_HOST` is set, the tool will use OpenSearch
847711
- If neither is set, the tool will default to FAISS (requires `faiss-cpu` package)
848-
- LLM configuration applies to all backend modes and allows customization of the language model used for memory processing
712+
849713
#### Memory Tool
850714

851715
| Environment Variable | Description | Default |
@@ -866,8 +730,6 @@ The Mem0 Memory Tool supports three different backend configurations:
866730
| Environment Variable | Description | Default |
867731
|----------------------|-------------|---------|
868732
| PYTHON_REPL_BINARY_MAX_LEN | Maximum length for binary content before truncation | 100 |
869-
| PYTHON_REPL_INTERACTIVE | Whether to enable interactive PTY mode | None |
870-
| PYTHON_REPL_RESET_STATE | Whether to reset the REPL state before execution | None |
871733

872734
#### Shell Tool
873735

src/strands_tools/python_repl.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,9 @@
7070
"IMPORTANT SAFETY FEATURES:\n"
7171
"1. User Confirmation: Requires explicit approval before executing code\n"
7272
"2. Code Preview: Shows syntax-highlighted code before execution\n"
73-
"3. State Management: Maintains variables between executions, default controlled by PYTHON_REPL_RESET_STATE\n"
73+
"3. State Management: Maintains variables between executions\n"
7474
"4. Error Handling: Captures and formats errors with suggestions\n"
75-
"5. Development Mode: Can bypass confirmation in BYPASS_TOOL_CONSENT environments\n"
76-
"6. Interactive Control: Can enable/disable interactive PTY mode in PYTHON_REPL_INTERACTIVE environments\n\n"
75+
"5. Development Mode: Can bypass confirmation in BYPASS_TOOL_CONSENT environments\n\n"
7776
"Key Features:\n"
7877
"- Persistent state between executions\n"
7978
"- Interactive PTY support for real-time feedback\n"
@@ -544,8 +543,8 @@ def python_repl(tool: ToolUse, **kwargs: Any) -> ToolResult:
544543
tool_input = tool["input"]
545544

546545
code = tool_input["code"]
547-
interactive = os.environ.get("PYTHON_REPL_INTERACTIVE", str(tool_input.get("interactive", True))).lower() == "true"
548-
reset_state = os.environ.get("PYTHON_REPL_RESET_STATE", str(tool_input.get("reset_state", False))).lower() == "true"
546+
interactive = tool_input.get("interactive", True)
547+
reset_state = tool_input.get("reset_state", False)
549548

550549
# Check for development mode
551550
strands_dev = os.environ.get("BYPASS_TOOL_CONSENT", "").lower() == "true"

0 commit comments

Comments
 (0)