这个示例保留原有 Go 工具,额外展示一个由 native Python 实现的固定工具。两端都是 Python,但权限和执行位置不同。
一个命令
./demos/core.sh python
输入 [2, 4, 6, 8],native worker 计算 count=4、total=20,Guest 根据结果计算 mean=5。这里求和只是为了让桥接容易看懂;实际不值得为这么小的计算启动进程。
先打开两个 Python 文件
- examples/python_provider.py:真正运行在 Wasm CPython 中的程序,调用
report_stats并计算平均值。 - providers/report.py:真正运行在宿主 native Python 中的实现,读取 stdin JSON,计算并向 stdout 输出 JSON。
这两个文件都可直接阅读。Guest 的工具名由 Host 注入,IDE 类型提示见 Python 编辑器说明。按定义跳转通常到 .pyi 接口声明,业务实现要打开上述 provider 文件。
Guest Python:report_stats(numbers=inputs["numbers"])
|
v
已有 C / Wasm ABI → Go Host reportStats
|
| 校验参数;固定工具、固定脚本
v
exec.CommandContext(ctx, "python3", "providers/report.py")
|
| stdin: {"numbers":[2,4,6,8]}
v
native Python:校验输入,求和
|
| stdout: {"count":4,"total":20}
v
Go 解析结果 → Guest 计算 mean → result 返回
Go 桥接做了什么
cmd/python-provider/main.go 的 run 创建 Runner,manifest 只注册 report_stats,没有授予 early-read。
reportStats 接受 1–100 个有限数值,校验后启动固定 worker。没有 shell 命令拼接,Guest 参数不能选择可执行程序或脚本路径。python3 由 Host 的 PATH 解析,所以 Host 环境仍须可信。
每次调用创建一个进程,输入与输出通过 JSON 传递。子进程退出失败、输出不是合法 JSON、计数不匹配等错误回到 Guest,不伪造成功。worker 再独立验证输入,错误写 stderr,并返回非零退出码。
验证
go test ./cmd/python-provider -count=1
uvx pyright --project pyrightconfig.json
真实 Guest 测试覆盖成功路径、坏输入、worker 失败和 malformed JSON;另外直接启动 worker 验证其参数检查。类型检查只处理示例,不会执行工具。
边界与取舍
- native worker 不在 Wasm Guest 内,拥有启动它的 Host 用户权限。固定路径和 JSON 不是操作系统沙箱。
- 当前脚本是可信的本地演示代码,不应把这个桥接当作不可信 native 代码的隔离方案。stdin/stdout 收集也不是通用恶意 worker 资源防护。
CommandContext提供本进程的取消行为,不等于任意子进程树都被收回,也不撤销已发生的外部效果。- 每次启动解释器有额外开销。本示例没有 worker pool,没有性能优势声明。
- 不改 Spine 核心,不替换 PLM/prefix 的 Go 工具,也不自动授予提前执行许可。
面试时可以用一句话概括:Pysolate 的能力边界由 Host 控制,工具业务实现可以用 Python;Guest 不因工具采用 Python 实现而获得宿主执行权限。