refactor(sandbox-policy): remove capability family registries

This commit is contained in:
Tianyi Cui
2026-07-31 13:28:02 +08:00
parent e6407477a7
commit e088cfa59d
112 changed files with 260 additions and 403 deletions

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/bash/bash-sandbox/README.md
README.md: 8012dbcbd656130b3d7b6701723c880dcf3d9d71
README.zh.md: de1077174ad802c0a18e5910792e61acd33c16ab
README.md: e9b040e7af55192e8afb9abf8bb4b99358ef8342
README.zh.md: f3956111f31ad85331caa47b1755667b096d2969

View File

@@ -18,7 +18,7 @@ Semantics:
- **Denials are result facts.** A failed run whose stderr carries the selected backend's own denial dialect — the signatures the provider stamps on every wrap (EROFS text under bwrap, EACCES under Landlock, EPERM under Seatbelt) — is reported as `BashRunResult.sandbox.denied: true` (conservative classification, read from the collected stderr tail); every CONFINED run also carries the mode it executed under (`result.sandbox.mode`) and the provider's enforcement completeness (`result.sandbox.enforcement`: `full`, or `partial` on an older Landlock ABI).
- **Runner failures are sandbox failures, never command failures.** Foreground execution throws `SANDBOX_UNAVAILABLE`; a settled background process stamps `process.sandbox.runnerFailed`, which the bash producer renders through generic `task_output`. Spawn failures also pass through settlement, so confined background handles retain their mode/enforcement facts and release per-process accounting.
- **Deployment fallback, per-call policy.** [`ctx.sandboxPolicy`](../../sandbox/sandbox-policy/) resolves a complete `SandboxExecutionPolicy` for every tool call: the calling session supplies its mode override and immutable cwd root, while deployment config supplies the fallbacks for agentless calls. An approved escalation changes only that policy's mode; its session root stays attached. `resolve()` carries the policy onto the spec, so overlapping commands from different projects run, classify, and report under their own roots and modes. The capability fact `ctx.bash.sandboxMode` reports the configured default so the tool layer advertises escalation only when this executor is mounted. This backend also contributes the one-shot bash family to the owner-rendered current-policy section; the static bash tool description separately owns denial and escalation guidance.
- **Deployment fallback, per-call policy.** [`ctx.sandboxPolicy`](../../sandbox/sandbox-policy/) resolves a complete `SandboxExecutionPolicy` for every tool call: the calling session supplies its mode override and immutable cwd root, while deployment config supplies the fallbacks for agentless calls. An approved escalation changes only that policy's mode; its session root stays attached. `resolve()` carries the policy onto the spec, so overlapping commands from different projects run, classify, and report under their own roots and modes. The capability fact `ctx.bash.sandboxMode` reports the configured default so the tool layer advertises escalation only when this executor is mounted; the static bash tool description separately owns denial and escalation guidance.
- **File effects only.** Network and process visibility are deliberately not restricted — the mode vocabulary does not pretend to cover what the backend does not enforce.
- Process mechanics (spawn, process-group kills, output collection/spill, background handles, credential scrub) are inherited from [`dsh-bash-local`](../bash-local/); runner selection lives in [`dsh-sandbox-local`](../../sandbox/sandbox-local/).
@@ -44,7 +44,7 @@ The keyless consumer-integration proofs are `tests/bwrap.e2e.ts`, `tests/landloc
#### What the model sees
The generated [`dsh-tool-bash` schemas](../../../docs/tool-catalog.md#deepseek-aidsh-tool-bash) are the baseline. By advertising a confining `sandboxMode`, this backend augments `bash` with `sandbox_permissions` using enum `workspace-write` | `danger-full-access` and with `justification`. Its family contribution also makes one-shot bash commands appear in the owner-rendered `sandbox:policy` section.
The generated [`dsh-tool-bash` schemas](../../../docs/tool-catalog.md#deepseek-aidsh-tool-bash) are the baseline. By advertising a confining `sandboxMode`, this backend augments `bash` with `sandbox_permissions` using enum `workspace-write` | `danger-full-access` and with `justification`. The policy owner separately contributes the current capability-neutral `sandbox:policy` context.
#### Token effect

View File

@@ -18,7 +18,7 @@
- **拒绝是结果事实。** 如果一次失败运行的 stderr 包含所选后端自身的拒绝方言即提供方在每次包装时加上的特征bwrap 下的 EROFS 文本、Landlock 下的 EACCES、Seatbelt 下的 EPERM则结果报告 `BashRunResult.sandbox.denied: true`(从已收集的 stderr 尾部进行保守分类)。每次受限制运行还会携带执行时模式(`result.sandbox.mode`)与提供方强制执行完整性(`result.sandbox.enforcement``full`,或在较旧 Landlock ABI 上为 `partial`)。
- **Runner 失败是沙箱失败,绝不是命令失败。** 前台执行会抛出 `SANDBOX_UNAVAILABLE`;已结算的后台进程会标记 `process.sandbox.runnerFailed`Bash 结果生成方通过通用 `task_output` 渲染它。spawn 失败也会经过结算,因此受限制的后台句柄会保留自身的模式/强制执行事实,并释放每进程计数。
- **部署回退,每次调用策略。** [`ctx.sandboxPolicy`](../../sandbox/sandbox-policy/) 为每次工具调用解析完整的 `SandboxExecutionPolicy`:调用会话提供自身的模式覆盖与不可变 cwd 根目录,部署配置则为无 agent智能体调用提供回退。已批准的升权只更改该策略的模式会话根目录仍然附着其上。`resolve()` 把策略带入 spec因此来自不同项目的重叠命令会在各自的根目录与模式下运行、分类和报告。能力事实 `ctx.bash.sandboxMode` 报告已配置的默认值,因此工具层只在装载该执行器时才公布升权。该后端还会向归属方渲染的当前策略段落贡献一次性 bash 家族;静态 bash 工具描述则单独负责拒绝与升级引导。
- **部署回退,每次调用策略。** [`ctx.sandboxPolicy`](../../sandbox/sandbox-policy/) 为每次工具调用解析完整的 `SandboxExecutionPolicy`:调用会话提供自身的模式覆盖与不可变 cwd 根目录,部署配置则为无 agent智能体调用提供回退。已批准的升权只更改该策略的模式会话根目录仍然附着其上。`resolve()` 把策略带入 spec因此来自不同项目的重叠命令会在各自的根目录与模式下运行、分类和报告。能力事实 `ctx.bash.sandboxMode` 报告已配置的默认值,因此工具层只在装载该执行器时才公布升权;静态 bash 工具描述则单独负责拒绝与升级引导。
- **只限制文件影响。** 设计上不限制网络与进程可见性:模式词汇不会声称覆盖后端未强制执行的范围。
- 进程机制spawn、进程组终止、输出收集spill、后台句柄、凭证清理继承自 [`dsh-bash-local`](../bash-local/)runner 选择位于 [`dsh-sandbox-local`](../../sandbox/sandbox-local/)。
@@ -44,7 +44,7 @@
#### 模型看到的内容
基线是生成的 [`dsh-tool-bash` schema](../../../docs/tool-catalog.md#deepseek-aidsh-tool-bash)。通过公布表明启用隔离的 `sandboxMode` 能力,此后端会为 `bash` 增加 `sandbox_permissions`,其 enum 为 `workspace-write` | `danger-full-access`,并增加 `justification`其家族贡献还会让一次性 bash 命令出现在归属方渲染`sandbox:policy` 段落中
基线是生成的 [`dsh-tool-bash` schema](../../../docs/tool-catalog.md#deepseek-aidsh-tool-bash)。通过公布表明启用隔离的 `sandboxMode` 能力,此后端会为 `bash` 增加 `sandbox_permissions`,其 enum 为 `workspace-write` | `danger-full-access`,并增加 `justification`策略归属方会另行贡献当前且不区分具体能力`sandbox:policy` 上下文
#### Token 影响

View File

@@ -21,7 +21,7 @@ import { classifyDenial, classifyRunnerFailure, matchesSignature, shellQuote } f
* Plugin config: the local executor's knobs, verbatim. The sandbox policy —
* the default mode and fallback `workspace-write` root — is NOT here: it lives
* on `ctx.sandboxPolicy` (`@deepseek-ai/dsh-sandbox-policy`), which resolves
* each calling session's mode and cwd for both enforcing families. The runner
* each calling session's mode and cwd for every enforcing capability. The runner
* choice is likewise the `ctx.sandbox` provider's config, not this executor's.
*/
export type Config = LocalConfig
@@ -30,9 +30,8 @@ export type Config = LocalConfig
* Registers as `ctx.bash` in place of the local executor and requires a
* `ctx.sandbox` provider plus `ctx.sandboxPolicy`; the tool layer is
* unchanged. Tool calls pass the calling session's resolved policy; direct
* calls fall back to deployment policy. Its family contribution lets the
* policy owner state which one-shot bash effects the standing mode governs;
* `result.sandbox` reports the mode and enforcement actually used.
* calls fall back to deployment policy. `result.sandbox` reports the mode and
* enforcement actually used.
*/
export class SandboxBashExecutor extends LocalBashExecutor {
static override inject = ['subprocess', 'sandbox', 'sandboxPolicy']
@@ -60,7 +59,6 @@ export class SandboxBashExecutor extends LocalBashExecutor {
// The default mode is the capability fact used for schema advertisement;
// actual tool executions carry their resolved per-call policy.
this.mode = ctx.sandboxPolicy.defaultMode
ctx.sandboxPolicy.registerEnforcedFamily('bash')
}
/** The configured default mode — the capability fact the tool layer reads. */

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/bash/tool-bash/README.md
README.md: 7af756ef5198b0b459085f28f9f5920b905e7ddb
README.zh.md: cc2e824cdc6cf6da743537cef70997020285b74e
README.md: 29b9fba369e1fc6a4b8bb7bdd6543b7678df627d
README.zh.md: 31f691f7bfb8d2cb905751663151c3f6a6bc6c57

View File

@@ -69,11 +69,9 @@ Commands run with the executor's full authority unless a sandboxing executor ([`
Escalating bash calls resolve `ctx.approval` before execution. `allowed-once` applies the requested mode only to that call; rejection, cancellation, unavailability, or missing approval context executes nothing and returns a distinct error. On a real denial, the model may retry the same command once in the same turn with the narrowest sufficient mode and justification; the approval prompt itself is the consent step. Escalation is never speculative, and a disabled or rejected approval is final. The [sandbox Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md) owns the rationale.
When the executor confines and the schema exposes escalation, this plugin registers the `bash` family as escalatable with `ctx.sandboxPolicy`. The policy owner can therefore add anti-refusal context only when the actual bash tool offers the denial-and-approved-retry path; the contribution disposes with the plugin.
## Per-session mode switching
For sandboxing executors, each call resolves mode as one-shot escalation, then session override, then executor default. Non-sandboxing and agent-less calls carry no session override. The policy owner contributes current standing mode and composition-conditioned anti-refusal context; denial results still own the operation-specific effective mode and retry guidance. See the [`dsh-bash` fold](../bash/README.md) and [sandbox switching contract](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md).
For sandboxing executors, each call resolves mode as one-shot escalation, then session override, then executor default. Non-sandboxing and agent-less calls carry no session override. The policy owner contributes the current capability-neutral standing mode; denial results still own the operation-specific effective mode and retry guidance. See the [`dsh-bash` fold](../bash/README.md) and [sandbox switching contract](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md).
## Model Experience
@@ -81,7 +79,7 @@ For sandboxing executors, each call resolves mode as one-shot escalation, then s
#### What the model sees
Every request in this plugin's registration scope contains the bash guidance below. A sandboxing executor contributes capability facts through the policy owner's cache-safe runtime context rather than changing this section. Scoped tool restrictions can hide the schemas without removing this independently registered section.
Every request in this plugin's registration scope contains the bash guidance below. The policy owner contributes current sandbox state through its cache-safe runtime context rather than changing this section. Scoped tool restrictions can hide the schemas without removing this independently registered section.
##### Bash guidance

View File

@@ -69,11 +69,9 @@ overlay 根据当前 `ToolExecution` 计算,并通过专用的 `BashExecReques
需要升权的 bash 调用会在执行前解析 `ctx.approval``allowed-once` 只对该次调用应用请求模式;审批被拒、取消、不可用或缺少审批上下文时,命令完全不会执行,并返回不同的错误。发生真实拒绝后,模型可以在同一轮次中使用满足需要的最窄模式和理由重试同一命令一次;审批提示本身就是征求同意的步骤。升权绝不能预先推测,禁用或拒绝审批即为最终结果。其理由由 [沙箱 Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md) 持有。
执行器施加沙箱限制且 schema 公开升权能力时,此插件会将 `bash` 家族注册到 `ctx.sandboxPolicy`,标记为可升权。策略归属方因而只会在实际 bash 工具具备「拒绝后经批准重试」路径时添加反预防性拒绝上下文;该贡献随插件 dispose。
## 逐会话模式切换
对于启用沙箱的执行器,每次调用依次按单次升权、会话覆盖、执行器默认值解析模式。未启用沙箱以及没有 agent 的调用不携带会话覆盖。策略归属方通过缓存安全的运行时上下文贡献当前常驻模式与按组合条件化的反预防性拒绝上下文;拒绝结果仍负责操作特定的有效模式与重试引导。参见 [`dsh-bash` 整合](../bash/README.md)和[沙箱切换契约](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)。
对于启用沙箱的执行器,每次调用依次按单次升权、会话覆盖、执行器默认值解析模式。未启用沙箱以及没有 agent 的调用不携带会话覆盖。策略归属方贡献当前且不区分具体能力的常驻模式;拒绝结果仍负责操作特定的有效模式与重试引导。参见 [`dsh-bash` 整合](../bash/README.md)和[沙箱切换契约](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)。
## 模型体验
@@ -81,7 +79,7 @@ overlay 根据当前 `ToolExecution` 计算,并通过专用的 `BashExecReques
#### 模型看到的内容
此插件注册作用域内的每个请求都包含下方 bash 指引。启用沙箱的执行器会通过策略归属方的缓存安全运行时上下文贡献能力事实,而不改变此段落。作用域工具限制可以隐藏 schema但不会移除这个独立注册的段落。
此插件注册作用域内的每个请求都包含下方 bash 指引。策略归属方通过自身的缓存安全运行时上下文贡献当前沙箱状态,而不改变此段落。作用域工具限制可以隐藏 schema但不会移除这个独立注册的段落。
##### Bash 指引

View File

@@ -376,8 +376,6 @@ export function apply(ctx: Context, config: Config = {}): void {
if (defaultMode !== undefined && sandboxPolicy === undefined) {
throw new Error('tool-bash: the mounted bash executor confines but ctx.sandboxPolicy is missing')
}
if (escalationModes.length > 0) sandboxPolicy?.registerEscalatableFamily('bash')
/** Resolve the complete standing policy for this call when a confining executor is mounted. */
const resolveSandboxPolicy = (exec: ToolExecution): SandboxExecutionPolicy | undefined =>
sandboxPolicy?.resolve(exec.agent === undefined ? {} : { session: exec.agent.session })