Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,6 @@ All notable changes to this repository are documented in this file.
- `community_agent/` moved to `contributors/community_agent/` — all new community agents must use `contributors/<agent-name>/`
- `CONTRIBUTING.md`, `README.md`, `ISSUES_GUIDE.md`, and PR template updated for contributor folder workflow
- `README.md` rewritten with project overview, quickstart guide, categorized examples index table, folder structure, Docker instructions, and resource links
- `CONTRIBUTING.md` expanded with setup script reference, tagging/categorization guidance, Docker support section, and issue flow references
- `CONTRIBUTING.md` expanded with setup script reference, tagging/categorization guidance, Docker support section, and issue flow references
### Fixed
- Fixed sandbox validation in `scan_directory` to properly reject paths outside the demo sandbox using `Path.relative_to()` (#159)
2 changes: 2 additions & 0 deletions contributors/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- `gemini-research-agent/`: Added Gemini-powered research assistant demonstrating the standard Agent Chat Protocol (@Kavurubuvanesh)
- `contributors/` folder and contribution guide for community agent examples
- `contributors/community_agent/` — moved from repository root; AI community growth agent for events and hackathons
### Fixed
- Fixed sandbox validation in `scan_directory` to properly reject paths outside the demo sandbox using `Path.relative_to()` (#159)
- `contributors/news-summarizer-agent/` — beginner-friendly agent that fetches top headlines via NewsAPI and summarizes them with ASI:One; now a uAgent with Chat Protocol support
22 changes: 12 additions & 10 deletions openclaw/fetchai-openclaw-orchestrator/connector/policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,8 @@
_DEMO_DIR = os.getenv("DEMO_PROJECTS_DIR", "./demo_projects")

DEFAULT_ALLOWED_PATHS: list[str] = [
os.path.expanduser("~/projects"),
os.path.expanduser("~/Documents"),
"/tmp",
str(Path(_DEMO_DIR).resolve()), # demo directory (safe testing)
str(Path(".").resolve()), # current working directory
]
str(Path(_DEMO_DIR).resolve()),
] # restricted sandbox


# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -76,14 +72,20 @@ def check_action(self, step: TaskStep) -> RejectionReason | None:

def check_path(self, step: TaskStep) -> RejectionReason | None:
raw_path = step.params.get("path")

if raw_path is None:
return None # no path param → OK
return None

resolved = Path(os.path.expanduser(raw_path)).resolve()

resolved = str(Path(os.path.expanduser(raw_path)).resolve())
for allowed in self.allowed_paths:
allowed_resolved = str(Path(allowed).resolve())
if resolved.startswith(allowed_resolved):
allowed_resolved = Path(allowed).resolve()

try:
resolved.relative_to(allowed_resolved)
return None
except ValueError:
continue

logger.warning("Path '%s' not within allowed sandboxes", resolved)
return RejectionReason.PATH_NOT_ALLOWED
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,9 @@ def scan_directory(params: dict[str, Any]) -> dict[str, Any]:

Defaults to the demo projects directory for safe testing.
"""
raw_path = params.get("path", _DEFAULT_SCAN_PATH)
raw_path = _DEFAULT_SCAN_PATH

# Sanitise: resolve relative to project root, never expose home dir
if raw_path.startswith("~"):
# In testing mode, redirect ~ paths to the demo directory
raw_path = _DEFAULT_SCAN_PATH
logger.info("Redirected home-relative path to demo directory: %s", raw_path)

root = Path(raw_path).resolve()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,13 @@ def plan_objective(objective: str) -> TaskPlan:
"""
# Try LLM first
plan = _plan_with_llm(objective)

if plan is not None:

for step in plan.steps:
if step.action == "scan_directory":
step.params["path"] = "./demo_projects"

return plan

# Fallback to keywords
Expand Down
12 changes: 12 additions & 0 deletions openclaw/fetchai-openclaw-orchestrator/orchestrator/policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"""

from __future__ import annotations
from pathlib import Path

import logging
import time
Expand Down Expand Up @@ -86,6 +87,17 @@ def check_plan(self, plan: TaskPlan) -> RejectionReason | None:
logger.warning("Action '%s' not in allowlist", step.action)
return RejectionReason.ACTION_NOT_ALLOWED

if step.action == "scan_directory":
raw_path = step.params.get("path")
if raw_path:
demo_dir = Path("./demo_projects").resolve()
requested = Path(raw_path).expanduser().resolve()

try:
requested.relative_to(demo_dir)
except ValueError:
logger.warning("Path '%s' outside demo sandbox", requested)
return RejectionReason.PATH_NOT_ALLOWED
return None

def validate(self, user_id: str, plan: TaskPlan) -> RejectionReason | None:
Expand Down
Loading