Approval(一次性审批,ctx.approval)
回答一个问题:这个具体动作能否进行。调用方消费封闭结果,非 allowed-once 一律 fail closed。
ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable';allowed-once只授予被问的那一次动作。answerer 缺失/抛错/非本 agent/返回不合规 →unavailable(不放行)。ApprovalPolicy = 'ask' | 'never'(per-session):ask委派组合的 answerer 链;never确定性 rejected,不派发任何 answerer——严格 headless 姿态(CI/无人值守)。有效值 = session log 最后一条approval/policy事件 fallback 到服务配置;never在服务内部、waterfall 之前强制执行,prependanswerer 也无法绕过。approval/asked+approval/decided审计事件成对、log-only 不进模型 transcript。ApprovalRequest刻意不含工具参数(answerer 通过 callId 挂到已流式的工具调用上);request()要求会话处于 open turn。- 应答者来源:UI 通道的人类 answerer;ACP automation bridge 的机器一次性决策。
Permission Presets(ctx.permissionPresets)
把两个独立强制旋钮打包成命名 preset:sandbox mode(sandbox/mode)+ approval policy(approval/policy),客户端呈现为 Permissions 选择器。
- 默认表:
workspace-write= (workspace-write + ask);danger-full-access= (danger-full-access + never)。custom保留给派生的非 preset 状态。 - 服务本身不做强制:切换只记录意图(log-only
permission/preset事件),再分别写穿setSandboxMode/setApprovalPolicy。 - 组合要求:必须有 confining 的
ctx.shellexecutor 与ctx.approval;bash executor 缺sandboxMode能力事实时加载即抛错。 - 另有 per-scope 的
ToolRestriction(对继承的全局工具取交集过滤,被过滤的工具从 prompt 消失且拒绝执行,与不存在无法区分)与ToolGuard(单调 deny,见 tool-system 管线第 4 阶段)。 - 模型可通过
sandbox_permissions+justification请求一次性更宽重试——必须先经 approval 批准该次确切调用才执行。
Sandbox(进程隔离 seam,ctx.sandbox)
SandboxProvider.confine(argv, policy) 返回 ConfinedArgv 或抛 SandboxUnavailableError。静默无隔离 passthrough 永不合法(fail closed)。容器/microVM/远程执行是整条 seam 的兄弟实现(如 e2b),不是 ctx.sandbox provider。
- 模式(只管文件系统效果,网络与进程可见性不在词表内):
read-only|workspace-write|danger-full-access(后者 consumer 直接 spawn,不调 sandbox)。 SandboxEnforcement = 'full' | 'partial'(旧 Landlock ABI、Windows ACL 边界属 partial)。- 策略按调用解析:
ctx.sandboxPolicy.resolve()管优先级:批准的显式 mode > 会话最后一条sandbox/mode事件 > 部署默认。它是部署默认 mode + workspace root 的唯一归属,bash 与 fs 两族执行者都读它(不能被限制到不同 root)。并发会话可各持不同边界,provider 无状态。
后端(dsh-sandbox-local)
| 平台 | 后端 | denial 方言 |
|---|---|---|
| Linux | bwrap / Landlock | EROFS(bwrap 只读绑定)/ EACCES(Landlock) |
| macOS | Seatbelt | EPERM |
| Windows | ACL restricted-token(报告 partial) | — |
consumer 只匹配本后端方言,不做跨后端并集。ConfinedArgv 还携带 enforcement 事实与 runnerFailureRules(区分”runner 没跑起来”与”命令被拦”)。
landlock-run(native/)
@deepseek-ai/node-addon-landock-run:一个 self-restrict-then-exec 启动器——约 300 行 C11,直接基于内核 UAPI,musl 静态链接。它在自身安装 Landlock ruleset 然后 exec 被包裹命令;ruleset 跨 execve 继承,命令及其所有子进程均受限,而调用方不受限。内核无法强制时不执行命令直接退出(fail closed)。
- 发布为预编译平台包(linux-x64/arm64)+ 薄 JS 入口;刻意无安装期编译 fallback——缺平台包则 probe 报
unusable,consumer fail closed。 - 极小 API:
launcherPath()、probe() → full|partial|unusable、grantArgs({readOnly, readWrite})、LAUNCHER_FAILURE_EXIT = 125。支持 kernel 5.13+。 - 其它平台刻意无包——consumer 在那里跑别的隔离后端。
衔接:sandboxed bash 报告 ShellSandboxInfo { mode, denied, enforcement, runnerFailed };模型收到 denial 事实后可申请一次性更宽重试(需审批)。filesystem 侧 dsh-fs-sandbox 策略拒绝码 FS_SANDBOX_DENIED(区别于内核拒绝 FS_PERMISSION_DENIED)。
Credentials(秘密不进配置)
- settings 段与
cordis.yml只存引用(POSIX env 名形式的 brandedCredentialRef);provider(如 credentials-local)拥有真实值;consumer 每次操作重新解析(LLM adapter 每次模型请求解析一次)——轮换后的凭据无需重启即生效于下一次请求。 - seam 铁律:空存储值处处视为缺席,空白永不冒充已配置秘密。
- API(
ctx.credentials):resolve(ref)(禁止跨操作缓存)、describe(ref)(面向配置 UI,绝不暴露值;被只读源遮蔽报writable: false)、set/unset(被只读源遮蔽时拒绝;set 拒绝空值)。 - 本地 source 层:
env、file、project-env、user-env。credentials/updated事件供 UI 刷新徽标(进程环境变化不可观测不发事件)。 - 配套:subprocess seam 提供
scrubbedParentEnv——子进程环境默认洗掉凭据形状变量(*KEY*/*SECRET*/*TOKEN*/*PASSWORD*),显式传入才算刻意保留;DSH_*管理变量同样丢弃 ambient 值。 - Web UI 侧:keys are write-only——页面只拿 redacted descriptor,密钥存
$DSH_HOME/.credentials.yaml,settings 里只存 credential reference(见 user-guide)。
相关页面
- tool-system — 管线中审批/guard 的位置
- architecture — fail-closed 与单一 policy home 不变量