patchpal 0.24.1__tar.gz → 0.24.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. {patchpal-0.24.1/patchpal.egg-info → patchpal-0.24.2}/PKG-INFO +1 -1
  2. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/__init__.py +1 -1
  3. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/agent/bedrock_profile_utils.py +26 -1
  4. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/cli/sandbox.py +59 -8
  5. {patchpal-0.24.1 → patchpal-0.24.2/patchpal.egg-info}/PKG-INFO +1 -1
  6. {patchpal-0.24.1 → patchpal-0.24.2}/LICENSE +0 -0
  7. {patchpal-0.24.1 → patchpal-0.24.2}/MANIFEST.in +0 -0
  8. {patchpal-0.24.1 → patchpal-0.24.2}/README.md +0 -0
  9. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/agent/__init__.py +0 -0
  10. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/agent/function_calling.py +0 -0
  11. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/agent/react.py +0 -0
  12. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/cli/__init__.py +0 -0
  13. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/cli/autopilot.py +0 -0
  14. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/cli/interactive.py +0 -0
  15. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/cli/mcp.py +0 -0
  16. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/cli/streaming.py +0 -0
  17. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/config.py +0 -0
  18. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/context.py +0 -0
  19. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/permissions.py +0 -0
  20. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/prompts/react_prompt.md +0 -0
  21. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/prompts/system_prompt.md +0 -0
  22. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/skills.py +0 -0
  23. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/tools/__init__.py +0 -0
  24. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/tools/audit.py +0 -0
  25. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/tools/browser_tools.py +0 -0
  26. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/tools/code_analysis.py +0 -0
  27. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/tools/common.py +0 -0
  28. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/tools/definitions.py +0 -0
  29. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/tools/file_reading.py +0 -0
  30. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/tools/file_writing.py +0 -0
  31. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/tools/find_tool.py +0 -0
  32. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/tools/grep_tool.py +0 -0
  33. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/tools/image_handler.py +0 -0
  34. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/tools/mcp.py +0 -0
  35. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/tools/repo_map.py +0 -0
  36. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/tools/shell_tools.py +0 -0
  37. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/tools/todo_tools.py +0 -0
  38. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/tools/tool_schema.py +0 -0
  39. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/tools/user_interaction.py +0 -0
  40. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal/tools/web_tools.py +0 -0
  41. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal.egg-info/SOURCES.txt +0 -0
  42. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal.egg-info/dependency_links.txt +0 -0
  43. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal.egg-info/entry_points.txt +0 -0
  44. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal.egg-info/requires.txt +0 -0
  45. {patchpal-0.24.1 → patchpal-0.24.2}/patchpal.egg-info/top_level.txt +0 -0
  46. {patchpal-0.24.1 → patchpal-0.24.2}/pyproject.toml +0 -0
  47. {patchpal-0.24.1 → patchpal-0.24.2}/setup.cfg +0 -0
  48. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_agent.py +0 -0
  49. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_cli.py +0 -0
  50. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_config_dynamic.py +0 -0
  51. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_context.py +0 -0
  52. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_custom_tools.py +0 -0
  53. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_enabled_tools.py +0 -0
  54. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_find_tool.py +0 -0
  55. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_guardrails.py +0 -0
  56. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_image_blocking.py +0 -0
  57. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_maximum_security.py +0 -0
  58. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_mcp_config.py +0 -0
  59. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_memory.py +0 -0
  60. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_memory_locations.py +0 -0
  61. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_operational_safety.py +0 -0
  62. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_optional_tools.py +0 -0
  63. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_permissions.py +0 -0
  64. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_react.py +0 -0
  65. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_reasoning_content.py +0 -0
  66. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_repo_map.py +0 -0
  67. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_simplified_prompt.py +0 -0
  68. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_skills.py +0 -0
  69. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_streaming.py +0 -0
  70. {patchpal-0.24.1 → patchpal-0.24.2}/tests/test_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: patchpal
3
- Version: 0.24.1
3
+ Version: 0.24.2
4
4
  Summary: An agentic coding and automation assistant, supporting both local and cloud LLMs
5
5
  Author: PatchPal Contributors
6
6
  License-Expression: Apache-2.0
@@ -1,6 +1,6 @@
1
1
  """PatchPal - An open-source Claude Code clone implemented purely in Python."""
2
2
 
3
- __version__ = "0.24.1"
3
+ __version__ = "0.24.2"
4
4
 
5
5
  from patchpal.agent import create_agent, create_react_agent
6
6
  from patchpal.cli.autopilot import autopilot_loop
@@ -29,8 +29,33 @@ def _extract_model_from_arn(arn: str) -> str | None:
29
29
  else:
30
30
  region = os.getenv("AWS_REGION_NAME") or os.getenv("AWS_REGION") or "us-east-1"
31
31
 
32
+ # Check for custom Bedrock endpoint (VPC endpoint, custom domain, etc.)
33
+ # The control plane and runtime may use the same VPC endpoint base
34
+ custom_endpoint = (
35
+ os.getenv("AWS_BEDROCK_ENDPOINT")
36
+ or os.getenv("AWS_ENDPOINT_URL_BEDROCK")
37
+ or os.getenv("AWS_ENDPOINT_URL")
38
+ )
39
+
40
+ # CRITICAL FIX: Derive control plane endpoint from runtime VPC endpoint
41
+ # Scenario: User has VPC endpoint for runtime but not explicit control plane endpoint
42
+ # Problem: boto3.client("bedrock") defaults to public endpoint, not VPC endpoint
43
+ # Solution: Automatically derive control plane VPC endpoint from runtime endpoint
44
+ # VPC endpoint pattern:
45
+ # Runtime: vpce-{id}.bedrock-runtime.{region}.vpce.amazonaws.com
46
+ # Control plane: vpce-{id}.bedrock.{region}.vpce.amazonaws.com
47
+ # This matches the automatic derivation in sandbox.py endpoint detection
48
+ if custom_endpoint and "bedrock-runtime" in custom_endpoint:
49
+ # Try to construct control plane VPC endpoint by removing -runtime
50
+ control_endpoint = custom_endpoint.replace("bedrock-runtime", "bedrock")
51
+ else:
52
+ control_endpoint = custom_endpoint
53
+
32
54
  # Create bedrock client
33
- bedrock = boto3.client("bedrock", region_name=region)
55
+ if control_endpoint:
56
+ bedrock = boto3.client("bedrock", region_name=region, endpoint_url=control_endpoint)
57
+ else:
58
+ bedrock = boto3.client("bedrock", region_name=region)
34
59
 
35
60
  # Get inference profile details
36
61
  response = bedrock.get_inference_profile(inferenceProfileIdentifier=arn)
@@ -144,6 +144,7 @@ def detect_llm_endpoints_from_env():
144
144
  "ANTHROPIC_API_BASE",
145
145
  "AWS_BEDROCK_ENDPOINT",
146
146
  "AWS_ENDPOINT_URL_BEDROCK_RUNTIME",
147
+ "AWS_ENDPOINT_URL_BEDROCK", # Control plane endpoint
147
148
  "AWS_ENDPOINT_URL",
148
149
  "AWS_BEDROCK_RUNTIME_ENDPOINT",
149
150
  "AZURE_OPENAI_ENDPOINT",
@@ -162,6 +163,18 @@ def detect_llm_endpoints_from_env():
162
163
  # Ensure it's a valid URL
163
164
  if value.startswith("http://") or value.startswith("https://"):
164
165
  detected_urls.append(value)
166
+
167
+ # CRITICAL FIX: For Bedrock VPC endpoints, derive control plane endpoint
168
+ # Scenario: User has VPC endpoint for runtime API (e.g., AWS GovCloud private network)
169
+ # Problem: Model capability detection needs control plane API (get_inference_profile)
170
+ # but boto3 doesn't automatically derive control plane from runtime endpoint
171
+ # VPC endpoint pattern:
172
+ # Runtime: vpce-{id}.bedrock-runtime.{region}.vpce.amazonaws.com
173
+ # Control plane: vpce-{id}.bedrock.{region}.vpce.amazonaws.com
174
+ # Without this, capability detection hangs trying to reach public control plane endpoint
175
+ if "bedrock-runtime" in value and ".vpce.amazonaws.com" in value:
176
+ control_plane_url = value.replace("bedrock-runtime", "bedrock")
177
+ detected_urls.append(control_plane_url)
165
178
  else:
166
179
  # Assume https if no protocol specified
167
180
  detected_urls.append(f"https://{value}")
@@ -177,18 +190,37 @@ def detect_llm_endpoints_from_env():
177
190
  if aws_region and (
178
191
  os.environ.get("AWS_ACCESS_KEY_ID") or os.environ.get("AWS_SECRET_ACCESS_KEY")
179
192
  ):
180
- # Add Bedrock endpoint for the region
193
+ # Add Bedrock endpoints for the region
181
194
  # Support both GovCloud and standard regions
182
195
  # Also support AWS China regions
196
+
197
+ # IMPORTANT: boto3 uses standard endpoint names by default, even in GovCloud
198
+ # Only use -fips suffix if AWS_USE_FIPS_ENDPOINT=true is explicitly set
199
+ # Scenario 1: Standard GovCloud → bedrock.us-gov-east-1.amazonaws.com (boto3 default)
200
+ # Scenario 2: FIPS required → bedrock-fips.us-gov-east-1.amazonaws.com (explicit opt-in)
201
+ use_fips = os.environ.get("AWS_USE_FIPS_ENDPOINT", "").lower() == "true"
202
+
183
203
  if "gov" in aws_region:
184
- # GovCloud regions use FIPS endpoints
185
- detected_urls.append(f"https://bedrock-runtime-fips.{aws_region}.amazonaws.com")
204
+ # GovCloud regions
205
+ # Add both runtime (for LLM inference) and control plane (for model capability detection)
206
+ if use_fips:
207
+ # FIPS endpoints (only when explicitly requested via AWS_USE_FIPS_ENDPOINT=true)
208
+ detected_urls.append(f"https://bedrock-runtime-fips.{aws_region}.amazonaws.com")
209
+ detected_urls.append(f"https://bedrock-fips.{aws_region}.amazonaws.com")
210
+ else:
211
+ # Standard GovCloud endpoints (boto3 default behavior)
212
+ # This is what boto3 uses unless FIPS is explicitly configured
213
+ detected_urls.append(f"https://bedrock-runtime.{aws_region}.amazonaws.com")
214
+ detected_urls.append(f"https://bedrock.{aws_region}.amazonaws.com")
186
215
  elif "cn-" in aws_region:
187
- # AWS China regions use .amazonaws.com.cn
216
+ # AWS China regions use .amazonaws.com.cn domain
188
217
  detected_urls.append(f"https://bedrock-runtime.{aws_region}.amazonaws.com.cn")
218
+ detected_urls.append(f"https://bedrock.{aws_region}.amazonaws.com.cn")
189
219
  else:
190
- # Standard commercial regions
220
+ # Standard commercial regions (us-east-1, eu-west-1, etc.)
221
+ # Add both runtime (for LLM inference) and control plane (for model capability detection)
191
222
  detected_urls.append(f"https://bedrock-runtime.{aws_region}.amazonaws.com")
223
+ detected_urls.append(f"https://bedrock.{aws_region}.amazonaws.com")
192
224
 
193
225
  # Azure OpenAI: Extract from resource name if AZURE_OPENAI_KEY is set
194
226
  azure_key = os.environ.get("AZURE_OPENAI_KEY") or os.environ.get("AZURE_API_KEY")
@@ -276,9 +308,28 @@ fi
276
308
  # Configure iptables
277
309
  echo "Configuring firewall rules..."
278
310
 
279
- # Allow DNS (required for hostname resolution)
280
- iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
281
- iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT
311
+ # Extract DNS resolver IP(s) from /etc/resolv.conf
312
+ # This locks DNS queries to only the container's configured resolver,
313
+ # preventing agents from directly querying attacker-controlled DNS servers
314
+ RESOLVER_IPS=$(grep '^nameserver' /etc/resolv.conf | awk '{print $2}')
315
+
316
+ if [ -z "$RESOLVER_IPS" ]; then
317
+ echo "❌ ERROR: Could not detect DNS resolver from /etc/resolv.conf"
318
+ echo "Cannot configure secure DNS filtering without a resolver"
319
+ exit 1
320
+ fi
321
+
322
+ # Allow DNS ONLY to detected resolver IPs (SECURITY FIX)
323
+ # This prevents the OpenAI-style DNS tunneling attack where agents
324
+ # send DNS packets directly to attacker-controlled DNS servers
325
+ echo "Locking DNS queries to container's resolver(s):"
326
+ while IFS= read -r RESOLVER_IP; do
327
+ if [ -n "$RESOLVER_IP" ]; then
328
+ echo " $RESOLVER_IP (DNS)"
329
+ iptables -A OUTPUT -d $RESOLVER_IP -p udp --dport 53 -j ACCEPT
330
+ iptables -A OUTPUT -d $RESOLVER_IP -p tcp --dport 53 -j ACCEPT
331
+ fi
332
+ done <<< "$RESOLVER_IPS"
282
333
 
283
334
  # Allow localhost
284
335
  iptables -A OUTPUT -d 127.0.0.1/8 -j ACCEPT
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: patchpal
3
- Version: 0.24.1
3
+ Version: 0.24.2
4
4
  Summary: An agentic coding and automation assistant, supporting both local and cloud LLMs
5
5
  Author: PatchPal Contributors
6
6
  License-Expression: Apache-2.0
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes