☰
把Fence嵌入你的工具:Go库API完全实战(以编程方式沙箱化任意命令)
2026/10/23 1:54:00 网站建设 项目流程
  • 开发工具
  • 应用安全
  • AI 安全治理

【免费下载链接】fence

Lightweight, container-free sandbox for running commands with network and filesystem restrictions

项目地址:https://gitcode.com/gh_mirrors/fence/fence
点击查看免费下载

Fence 是一个轻量级、无需容器的沙箱工具,能通过网络与文件系统限制安全运行命令。除了命令行用法,Fence 还可以作为Go 库直接嵌入你的应用:几行代码即可对任意命令做编程式沙箱化(Go library API),实现网络白名单、文件读写隔离和危险命令拦截。本文将带你完成从安装到实战的完整流程,让你快速把 Fence 沙箱能力集成进自己的 CI、插件或 Agent 工具中。

一、为什么选择 Fence Go 库模式?

很多团队需要在自己的程序里"跑命令但不能失控":CI Runner 执行未知构建脚本、IDE 插件运行 AI 生成的代码、Agent 框架调用 shell 工具……手动拼bwrap或sandbox-exec参数既繁琐又容易踩坑。

Fence 库模式把这些全部封装好了:

  • 默认断网:所有出站网络流量默认被阻断,只放行白名单域名;
  • 文件系统策略:按路径精确控制读/写权限,并内置危险路径强制保护;
  • 命令黑名单:自动拦截rm -rf /、git push等高危命令,支持管道与&&链解析;
  • 跨平台:macOS 走 sandbox-exec(Seatbelt),Linux 走 bubblewrap + Landlock + seccomp,核心逻辑统一在 internal/sandbox/ 中实现。

库的公共 API 全部收敛在 pkg/fence/fence.go,一个 package 就是完整入口;配置结构定义见 internal/config/config.go。

二、安装 Fence 库

Fence 的标准模块路径是github.com/fencesandbox/fence(见 go.mod),在你的 Go 项目里执行:

go get github.com/fencesandbox/fence

导入时只需用到公共包:

import "github.com/fencesandbox/fence/pkg/fence"

💡 Linux 平台还依赖系统包bubblewrap(沙箱)与socat(网络桥接);macOS 无额外依赖。

三、快速上手:5 步沙箱化一条命令

下面是库模式最核心的工作流(完整示例见 docs/library.md):

// 1. 平台检查 if !fence.IsSupported() { return } // 2. 定义配置:只允许访问 api.example.com cfg := &fence.Config{ Network: fence.NetworkConfig{ AllowedDomains: []string{"api.example.com"}, }, } // 3. 创建并初始化 Manager manager := fence.NewManager(cfg, false, false) defer manager.Cleanup() // 4. 包装命令,得到"带沙箱"的新命令 wrapped, err := manager.WrapCommand("curl https://api.example.com/data") // 5. 用 sh 执行包装后的命令 output, _ := exec.Command("sh", "-c", wrapped).CombinedOutput()

其中NewManager(cfg, debug, monitor)的 实现 很简洁:debug打开详细日志(代理活动、沙箱命令),monitor只记录被拦截的请求。WrapCommand内部会先做命令策略预检、再生成平台对应的沙箱包装命令,核心逻辑见 WrapCommandInDir。

Linux 多一步:配置 helper 可执行文件

Linux 下需要告知 Fence 一个能实现私有 helper 模式的程序(可以是安装好的 fence CLI,也可以是你的程序自己):

// 方式 A:指向已安装的 fence 二进制 manager.SetLinuxHelperPath("/usr/local/bin/fence") // 方式 B:让自己的可执行文件充当 helper if handled, code, err := fence.DispatchInternalHelper(os.Args); handled { if err != nil { fmt.Fprintln(os.Stderr, err) } os.Exit(code) } manager.SetLinuxHelperPath(mustExecutable()) // os.Executable()

未配置 helper 时,Linux 上的WrapCommand会直接返回ErrLinuxHelperRequired——它绝不悄悄降级到更弱的沙箱,这个"失败即报错"的设计值得称赞。

四、核心 API 速查表

API作用备注
IsSupported()判断当前平台是否支持沙箱目前为 macOS / Linux
NewManager(cfg, debug, monitor)创建沙箱管理器内部启动 HTTP + SOCKS 过滤代理
manager.Initialize()初始化沙箱基础设施WrapCommand会自动调用
manager.WrapCommand(cmd)把命令包装为沙箱命令返回可直接执行的 shell 字符串
manager.SetService(opts)声明入站端口暴露须在Initialize之前调用
manager.ExposeHostPath(path, writable)把宿主文件暴露进沙箱须在WrapCommand之前调用
manager.Cleanup()停止代理、释放资源务必defer调用
DefaultConfig()/LoadConfig(path)创建 / 加载配置支持 JSON 与 JSONC 注释
CheckCommand/CheckReadPath等策略预检(不实际运行)无需 Manager 即可使用

完整 API 参考请阅读 docs/library.md。

五、配置三种姿势:从代码到文件

姿势 1:代码里直接构造——适合策略由程序动态生成的场景:

cfg := &fence.Config{ Network: fence.NetworkConfig{AllowedDomains: []string{"registry.npmjs.org", "*.github.com"}}, Filesystem: fence.FilesystemConfig{AllowWrite: []string{".", "/tmp"}, DenyRead: []string{"~/.ssh", "~/.aws"}}, Command: fence.CommandConfig{Deny: []string{"git push", "npm publish"}}, }

姿势 2:加载配置文件——复用用户已有的fence.jsonc,与 CLI 完全一致的行为:

path := fence.ResolveDefaultConfigPath() // 自动发现 fence.jsonc / fence.json cfg, err := fence.LoadConfigResolved(path) // 会解析 extends 继承链 if err != nil { log.Fatal(err) } if cfg == nil { cfg = fence.DefaultConfig() }

姿势 3:基线 + 覆盖合并——多配置源场景非常实用:

merged := fence.MergeConfigs(baseCfg, overrideCfg)

配置字段的完整 schema 可参考 docs/schema/fence.schema.json,内置模板(如code)源码在 internal/templates/。

六、进阶:端口暴露与宿主文件共享

暴露开发服务器端口。沙箱默认隔离网络,但你的 dev server 仍需被宿主访问。通过SetService声明入站端口,Fence 会自动建立反向桥接:

manager.SetService(fence.ServiceOptions{ Exposures: []fence.ExposedPort{fence.LoopbackPort(3000)}, // 默认只绑 127.0.0.1 }) wrapped, _ := manager.WrapCommand("npm run dev")

若端口实际由外部守护进程(dockerd、systemctl 等)在宿主绑定,改用ExecutionModel: fence.ServiceBindsOnHost,避免桥接冲突。

把宿主临时文件"递"进沙箱。Linux 上 Fence 会用 tmpfs 覆盖/tmp,导致os.CreateTemp生成的文件在沙箱内不可见。此时一行ExposeHostPath解决,无需理解其内部挂载计划:

manager.ExposeHostPath(tempFile, false) // 只读暴露

两种能力的细节与实现分别见 manager.go#L143-L174 和 docs/library.md#L225-L292。

七、策略预检:不启动沙箱就判定"能不能做"

如果你的工具里有不经过WrapCommand的代码路径(如 Agent 的read_file/web_fetch工具),Fence 提供一组轻量预检函数,让同一份fence.jsonc成为全局唯一策略来源:

if err := fence.CheckCommand(cfg, "echo ok && git push origin main"); err != nil { var blocked *fence.CommandBlockedError if errors.As(err, &blocked) { // blocked.Command = "git push origin main" // blocked.BlockedPrefix = "git push" } return err // 拒绝执行 }
  • CheckReadPath/CheckWritePath:判定文件读/写,返回*PathBlockedError(含匹配规则与拒绝原因);
  • CheckCommand:能解析管道、&&/||/;链与嵌套sh -c,逐个子命令检查;
  • CheckURL:按allowedDomains/deniedDomains判定 URL,deny 规则优先。

⚠️ 注意:预检只是"意图检查",权威执行仍在内核级沙箱与流量代理,不要用它替代WrapCommand。

八、库模式 vs CLI 模式:四个差异要知道

差异点fenceCLIGo 库
环境加固自动剥离LD_PRELOAD等注入变量需自己在 exec 时清理子进程环境
违规监控-m附带平台级监控(log stream / eBPF)monitor参数仅覆盖代理拦截
交互会话管理 TTY 交接、作业控制、信号转发需自行接管 stdio
配置发现自动寻找最近fence.jsonc需显式LoadConfigResolved

详见 docs/library.md#CLI vs Library Differences。

九、实战避坑清单

  1. Manager 非线程安全:每个 goroutine 建一个 manager,或自行加锁;代理本身可并发处理连接(docs/library.md#L636-L639)。
  2. SetService与ExposeHostPath有时序:前者必须在Initialize前,后者必须在WrapCommand前。
  3. Cleanup一定要defer,否则代理进程会残留。
  4. 空AllowedDomains= 全拒绝:想放行流量必须显式配置白名单,这正是"默认最安全"的哲学。
  5. Linux 忘记配 helper会得到ErrLinuxHelperRequired,属于预期报错而非 bug。

十、总结

Fence 的 Go 库 API 用极小的表面积(一个 package + 一个 Manager)覆盖了沙箱化的全部关键场景:配置 → 包装 → 执行 → 预检 → 清理。无论是给 CI 系统加一层保险,还是为 AI Agent 的命令工具装"护栏",只需十几行代码即可实现网络与文件系统的强隔离——而这一切都不需要容器。

📚 延伸阅读:

  • 库完整参考:docs/library.md
  • 配置参考:docs/configuration.md
  • 安全模型:docs/security-model.md
  • 内置模板:internal/templates/
  • 架构总览:ARCHITECTURE.md
  • 开发工具
  • 应用安全
  • AI 安全治理

【免费下载链接】fence

Lightweight, container-free sandbox for running commands with network and filesystem restrictions

项目地址:https://gitcode.com/gh_mirrors/fence/fence
点击查看免费下载

相关推荐

上一篇:如何在5分钟内掌握cargo-ndk:终极Android Rust编译指南
下一篇:FunASR性能优化:如何将RTF降至0.0076的秘诀

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询