Skip to content

沙盒 API

dcc_mcp_core (sandbox 模块)

带有 API 白名单、路径控制、审计日志和输入验证的脚本执行沙盒。

概述

企业级用户(游戏工作室、VFX 机构)有严格的安全需求,而原始的基于 Python 的 DCC MCP 集成无法满足。沙盒模块提供:

  • API 白名单 — 限制 AI 智能体可调用的 DCC 操作
  • 路径白名单 — 将文件系统访问限制在安全目录内
  • 审计日志 — 每次操作调用的结构化记录(AuditEntry / AuditLog
  • 输入验证 — 带注入防护的字段级规则(InputValidator
  • 只读模式 — 智能体可查询但不能修改场景

SandboxPolicy

沙盒会话的安全策略配置。

构造函数

python
from dcc_mcp_core import SandboxPolicy

policy = SandboxPolicy()

方法

方法返回值说明
allow_actions(actions)None限制只允许这些操作(替换之前的白名单)
deny_actions(actions)None即使在白名单中也拒绝这些操作
allow_paths(paths)None允许访问这些目录路径内的文件系统
set_timeout_ms(ms)None设置执行超时(毫秒)
set_max_actions(count)None设置每个会话允许的最大操作数
set_read_only(read_only)None启用/禁用只读模式

属性

属性类型说明
is_read_onlybool策略是否处于只读模式

示例

python
policy = SandboxPolicy()
policy.allow_actions(["get_scene_info", "list_objects", "get_object_info"])
policy.deny_actions(["delete_scene", "delete_object"])
policy.allow_paths(["/studio/assets", "/tmp/renders"])
policy.set_timeout_ms(5000)
policy.set_max_actions(100)
policy.set_read_only(False)

print(policy.is_read_only)  # False

使用白名单而非黑名单

不允许任何操作开始,然后明确许可安全的操作。这比列出所有要阻止的内容更安全。

SandboxContext

主沙盒执行上下文。将 SandboxPolicyAuditLog 和操作计数器组合在一起。

构造函数

python
from dcc_mcp_core import SandboxPolicy, SandboxContext

policy = SandboxPolicy()
policy.allow_actions(["get_scene_info", "list_objects"])

ctx = SandboxContext(policy)

方法

方法返回值说明
set_actor(actor)None设置审计条目的调用者身份
execute_json(action, params_json)str使用 JSON 参数执行操作,返回 JSON 结果
is_allowed(action)bool检查操作是否被当前策略允许
is_path_allowed(path)bool检查路径是否在允许目录内

属性

属性类型说明
action_countint成功执行的操作数量
audit_logAuditLog当前上下文的审计日志

执行

python
ctx.set_actor("claude-agent")

# 使用 JSON 参数执行——返回 JSON 字符串
result = ctx.execute_json("get_scene_info", "{}")
print(result)  # '{"name": "my_scene", "object_count": 42, ...}'

# 在不执行的情况下检查权限
if ctx.is_allowed("delete_object"):
    ctx.execute_json("delete_object", '{"name": "pSphere1"}')

错误会抛出 RuntimeError

如果操作被拒绝、验证失败或发生沙盒错误,execute_json() 会抛出 RuntimeError

审计日志访问

python
log = ctx.audit_log
print(len(log))  # 已记录条目数

for entry in log.entries():
    print(f"{entry.actor}: {entry.action}{entry.outcome} ({entry.duration_ms}ms)")

# 筛选视图
denied = log.denials()
succeeded = log.successes()

# 序列化为 JSON
json_str = log.to_json()

AuditEntry

单次操作调用的审计记录。所有属性均为只读属性。

属性

属性类型说明
timestamp_msintUnix 时间戳(毫秒)
actorstr | None调用者身份,或 None
actionstr操作名称
params_jsonstrJSON 字符串形式的参数
duration_msint执行耗时(毫秒)
outcomestr"success""denied""error""timeout"
outcome_detailstr | None拒绝原因或错误消息,或 None
python
for entry in ctx.audit_log.entries():
    print(f"[{entry.timestamp_ms}] {entry.actor}: {entry.action}")
    print(f"  参数: {entry.params_json}")
    print(f"  结果: {entry.outcome} ({entry.duration_ms}ms)")
    if entry.outcome_detail:
        print(f"  详情: {entry.outcome_detail}")

AuditLog

沙盒审计日志的只读视图。

方法

方法返回值说明
entries()list[AuditEntry]所有已记录的条目
successes()list[AuditEntry]outcome 为 "success" 的条目
denials()list[AuditEntry]outcome 为 "denied" 的条目
entries_for_action(action)list[AuditEntry]特定操作的条目
to_json()str所有条目序列化为 JSON 数组字符串
__len__()int条目数量
python
log = ctx.audit_log

print(f"总计: {len(log)}")
print(f"成功: {len(log.successes())}")
print(f"拒绝: {len(log.denials())}")

# 查询特定操作的历史记录
scene_queries = log.entries_for_action("get_scene_info")

# 导出到日志系统
json_str = log.to_json()

InputValidator

带注入防护的字段级输入验证器。在调用 SandboxContext.execute_json() 之前对参数进行验证。

构造函数

python
from dcc_mcp_core import InputValidator

validator = InputValidator()

方法

方法返回值说明
require_string(field, max_length=None, min_length=None)None注册必填字符串字段,支持可选长度约束
require_number(field, min_value=None, max_value=None)None注册必填数值字段,支持可选范围约束
forbid_substrings(field, substrings)None注入防护:字段不得包含任何指定子串
validate(params_json)tuple[bool, str | None]验证 JSON 参数;返回 (True, None)(False, 错误消息)

示例

python
from dcc_mcp_core import InputValidator

validator = InputValidator()

# 字段约束
validator.require_string("name", min_length=1, max_length=64)
validator.require_number("radius", min_value=0.01, max_value=1000.0)

# 注入防护
validator.forbid_substrings("script", ["__import__", "exec(", "eval(", "os.system"])

# 有效输入
ok, error = validator.validate('{"name": "sphere1", "radius": 2.0}')
print(ok, error)  # True, None

# 注入尝试被阻止
ok, error = validator.validate('{"script": "__import__(os)"}')
print(ok, error)  # False, "field 'script' contains forbidden substring '__import__'"

# 无效 JSON 抛出 RuntimeError
try:
    validator.validate("not json")
except RuntimeError as e:
    print(f"无效 JSON: {e}")

InputValidator vs ToolValidator

InputValidator 用于沙盒字段级规则(长度、范围、注入防护)。 ToolValidator(来自 actions 模块)根据 JSON Schema 进行验证。 在沙盒中使用 InputValidator;在操作分派层使用 ToolValidator

最佳实践

  1. 始终使用白名单 — 从不允许任何操作开始,然后明确许可安全的操作
  2. 设置超时 — 防止失控脚本挂起 DCC
  3. 限制操作数量set_max_actions() 防止 AI 智能体进入无限循环
  4. 启用审计日志 — 会话结束后始终检查 ctx.audit_log
  5. 使用只读模式 — 仅查询数据时启用,防止意外修改
  6. 添加注入防护 — 对任何脚本/代码参数使用 InputValidator.forbid_substrings()
  7. 验证路径 — 使用 allow_paths() + ctx.is_path_allowed() 防止路径遍历

完整示例

python
from dcc_mcp_core import SandboxPolicy, SandboxContext, InputValidator

# 构建策略
policy = SandboxPolicy()
policy.allow_actions(["get_scene_info", "list_objects", "run_script"])
policy.allow_paths(["/studio/assets"])
policy.set_timeout_ms(10000)
policy.set_max_actions(50)

# 为 run_script 构建验证器
validator = InputValidator()
validator.require_string("script", max_length=10000)
validator.forbid_substrings("script", [
    "__import__", "exec(", "eval(", "os.system", "subprocess",
])

# 创建上下文
ctx = SandboxContext(policy)
ctx.set_actor("my-ai-agent")

# 执行安全查询
result = ctx.execute_json("get_scene_info", "{}")
print(result)

# 尝试受限操作(被策略阻止)
try:
    ctx.execute_json("delete_scene", "{}")
except RuntimeError as e:
    print(f"已阻止: {e}")

# 审查审计日志
for entry in ctx.audit_log.entries():
    print(f"{entry.action}: {entry.outcome}")

Released under the MIT License.