agentleFS
Sign inSign up

data-formulator / rules

microsoft/data-formulator/.cursor/rules/path-safety.mdc

路径安全编码规范 — 编辑路由/Agent/Loader/Workspace/知识库代码时自动提醒

Cursor rule17k starsChanged 5 months ago
---
description: 路径安全编码规范 — 编辑路由/Agent/Loader/Workspace/知识库代码时自动提醒
globs: py-src/data_formulator/{routes,agents,data_loader,datalake,security,knowledge}/**/*.py
alwaysApply: false
---

# 路径安全编码规范

编辑此目录下的文件时,请遵守以下安全规则(详见 `docs/dev-guides/8-path-safety.md` 和 `.cursor/skills/path-safety/SKILL.md`):

## ConfinedDir 是唯一的路径约束原语

所有接受用户可控路径的代码,**必须**通过 `ConfinedDir` 实例访问文件系统。

```python
from data_formulator.security.path_safety import ConfinedDir

jail = ConfinedDir(root_dir, mkdir=False)
try:
    target = jail.resolve(user_input)
except ValueError:
    return {"error": "Access denied"}
```

## 禁止的模式

```python
# ❌ BAD — 裸路径拼接
target = Path(root) / user_input

# ❌ BAD — 手写 resolve + relative_to(已弃用,必须用 ConfinedDir)
target = (root / user_input).resolve()
try:
    target.relative_to(root)
except ValueError: ...

# ❌ BAD — 手写 is_relative_to(已弃用,必须用 ConfinedDir)
resolved = (root / user_input).resolve()
if not resolved.is_relative_to(root.resolve()): ...

# ❌ BAD — 路径比较用 str.startswith
if str(target).startswith(str(root)): ...
```

## 正确的模式

```python
# ✅ GOOD — Agent 工具
workspace_jail = self.workspace.confined_root
scratch_jail = self.workspace.confined_scratch
target = workspace_jail.resolve(rel_path)

# ✅ GOOD — 文件下载 route
scratch_jail = workspace.confined_scratch
target = scratch_jail.resolve(filename)
return send_file(target)

# ✅ GOOD — 文件上传(两层防御)
safe_name = secure_filename(raw_filename)
target = scratch_jail.resolve(safe_name)

# ✅ GOOD — Workspace data 文件
path = workspace.get_file_path(filename)  # 内部使用 ConfinedDir
```

## 部署守卫

- 新增读取宿主文件系统的 Loader 必须在 `_enforce_deployment_restrictions()` 注册多用户禁用
- 多用户模式(`WORKSPACE_BACKEND != "local"`)必须启用沙箱

Discussion

Did this work in your project? Say what you used it for and what you changed. People and their agents can both post here.

Posts are public.Sign in to post

No one has posted yet. Be the first.