@deepseek-ai/dsh-bash-sandbox 0.0.1-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +28 -0
- package/README.i18n.yaml +6 -0
- package/README.md +88 -0
- package/README.zh.md +88 -0
- package/lib/index.js +237 -0
- package/lib/invariant.js +23 -0
- package/lib/types/helpers.d.ts +55 -0
- package/lib/types/index.d.ts +67 -0
- package/lib/types/invariant.d.ts +16 -0
- package/package.json +53 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, DeepSeek
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.i18n.yaml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
|
2
|
+
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
|
+
# after editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write packages/bash/bash-sandbox/README.md
|
|
5
|
+
README.md: 44321d7ef26e9e4399438f61b3fdfbfa2e4d8c11
|
|
6
|
+
README.zh.md: f3e110c049871a5a6121716307aaa3d1d1f3eedb
|
package/README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# @deepseek-ai/dsh-bash-sandbox
|
|
2
|
+
|
|
3
|
+
English | [中文](README.zh.md)
|
|
4
|
+
|
|
5
|
+
Sandbox-consuming Service provider for the [`@deepseek-ai/dsh-bash`](../bash/) executor seam. Load it **instead of** `@deepseek-ai/dsh-bash-local`, together with a [`ctx.sandbox`](../../sandbox/sandbox/) provider (e.g. [`@deepseek-ai/dsh-sandbox-local`](../../sandbox/sandbox-local/)) and a [`ctx.sandboxPolicy`](../../sandbox/sandbox-policy/) (which owns the default mode + workspace root, shared with the sandboxed filesystem) — no alternate tool plugin is needed; `dsh-tool-bash` detects the executor's `sandboxMode` capability and adds the escalation fields.
|
|
6
|
+
|
|
7
|
+
The package root exports the default and named `SandboxBashExecutor` plugin plus its `Config`; result-classification helpers stay internal.
|
|
8
|
+
|
|
9
|
+
Every command is confined by handing the provider the exact `['bash', '-c', command]` argv this executor is about to spawn and spawning the returned argv directly. With the shipped native runners, the inner Bash retains shell semantics and evaluates `BASH_ENV` only after the runner establishes confinement. WHICH platform runner confines it — and whether one is usable at all (fail closed with a structured `SANDBOX_UNAVAILABLE` error, never a silent unconfined run) — is the provider's concern; this package owns the bash side only.
|
|
10
|
+
|
|
11
|
+
| Mode | File effects |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `read-only` (default) | No writes anywhere (of `/dev`, only the `/dev/null` node is writable, so `>/dev/null` keeps working) |
|
|
14
|
+
| `workspace-write` | Writes only under `workspaceRoot` + `/tmp` (ephemeral under bwrap, the host `/tmp` under Landlock, `/private/tmp` plus the per-user temp dir under Seatbelt) |
|
|
15
|
+
| `danger-full-access` | No confinement; the provider is never consulted. Foreground results carry `sandbox: { mode, denied: false }`; background process handles carry no sandbox facts. |
|
|
16
|
+
|
|
17
|
+
Semantics:
|
|
18
|
+
|
|
19
|
+
- **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).
|
|
20
|
+
- **The runner path or syscall must match.** Before a process starts, a rejection is attributed to the runner only when the caller-owned workdir is independently usable and Node reports `ENOENT` or `EACCES` with either an `error.path` equal to provider argv[0] or, when `error.path` is absent, an exact `syscall: 'spawn <runner>'`. A present path also requires `syscall: 'spawn'` or the exact `spawn <runner>`. This covers a missing runner, a non-executable runner, or an executable script whose shebang interpreter is unavailable. A bare `syscall: 'spawn'` without an exact error path, any other code, an invalid or unusable workdir, a resource failure, an unrelated syscall, or an unstructured rejection retains the local executor's command-start failure semantics. Foreground execution throws `SANDBOX_UNAVAILABLE` with the original spawn detail, while asynchronous background settlement stamps `runnerFailed: true` and `denied: false`. If a `SubprocessService` synchronously throws the same runner-identifying `ENOENT`/`EACCES` shape, background start throws `SANDBOX_UNAVAILABLE`; other synchronous errors propagate unchanged. After a process starts, a rule's optional exit-code check and a remaining fatal stderr line must both match after exact informational-line exclusions. A match takes priority over denial; foreground execution throws `SANDBOX_UNAVAILABLE` with the matched fatal line, while a settled background process stamps `process.sandbox.runnerFailed`, which the bash producer renders through generic `task_output`. Confined background handles retain their mode/enforcement facts and release per-process accounting in either path.
|
|
21
|
+
- **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.
|
|
22
|
+
- **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.
|
|
23
|
+
- 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/).
|
|
24
|
+
|
|
25
|
+
Deny-only at the seam: a denial is a reported fact, and this executor never negotiates permissions itself — the approval question lives in the tool layer (`dsh-tool-bash`), which drives the override this package honors.
|
|
26
|
+
|
|
27
|
+
```yaml
|
|
28
|
+
- id: sandbox
|
|
29
|
+
name: '@deepseek-ai/dsh-sandbox-local'
|
|
30
|
+
- id: sandbox-policy
|
|
31
|
+
name: '@deepseek-ai/dsh-sandbox-policy'
|
|
32
|
+
config:
|
|
33
|
+
mode: read-only
|
|
34
|
+
workspaceRoot: !!js process.cwd() # fallback for calls without a session cwd
|
|
35
|
+
- id: bash
|
|
36
|
+
name: '@deepseek-ai/dsh-bash-sandbox'
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Model Experience
|
|
40
|
+
|
|
41
|
+
### Bash tool schema, indirectly
|
|
42
|
+
|
|
43
|
+
#### What the model sees
|
|
44
|
+
|
|
45
|
+
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.
|
|
46
|
+
|
|
47
|
+
#### Token effect
|
|
48
|
+
|
|
49
|
+
Small fixed schema increment on requests where `bash` is visible, plus the current-policy clause owned by `dsh-sandbox-policy`.
|
|
50
|
+
|
|
51
|
+
#### KV Cache effect
|
|
52
|
+
|
|
53
|
+
A standing-policy change appends a complete owner-rendered context snapshot after retained history, preserving the existing system/history prefix byte-for-byte. Changing executor capabilities alters the `bash` schema.
|
|
54
|
+
|
|
55
|
+
### Bash tool result, indirectly
|
|
56
|
+
|
|
57
|
+
#### What the model sees
|
|
58
|
+
|
|
59
|
+
After ordinary bounded output, a denied call appends exactly `[sandbox: file access denied under <mode> mode]`. When escalation is available it next appends `[sandbox: escalation available — retry this exact command once with sandbox_permissions (the narrowest wider mode that suffices) + justification; the approval prompt asks the user]`. A settled background runner failure instead appends `[sandbox: the sandbox runner itself failed under <mode> mode — the command did not run; this is a sandbox problem, not a command failure]`.
|
|
60
|
+
|
|
61
|
+
#### Token effect
|
|
62
|
+
|
|
63
|
+
Zero additional tokens on an unremarkable allowed run beyond ordinary output. Denial or failure adds the quoted conditional marker, retained until compaction.
|
|
64
|
+
|
|
65
|
+
#### KV Cache effect
|
|
66
|
+
|
|
67
|
+
Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries.
|
|
68
|
+
|
|
69
|
+
### Bash tool error, indirectly
|
|
70
|
+
|
|
71
|
+
#### What the model sees
|
|
72
|
+
|
|
73
|
+
If no runner can enforce a confined mode, the foreground call propagates the [`SANDBOX_UNAVAILABLE` error owned by `dsh-sandbox`](../../sandbox/sandbox/README.md#confinement-error-indirectly). A runner-attributable spawn failure supplies the original spawn error as detail; a rejection without `ENOENT`/`EACCES` path or syscall evidence that names argv[0] remains an ordinary command-start error. A settled runner failure supplies the matched fatal stderr line and preserves the original stderr collection. When present, the appended `Runner failure: <detail>` is the authoritative diagnosis; the preceding backend-install text is the generic `SANDBOX_UNAVAILABLE` prefix.
|
|
74
|
+
|
|
75
|
+
#### Token effect
|
|
76
|
+
|
|
77
|
+
Conditional error text is visible for that call and retained in history until compaction.
|
|
78
|
+
|
|
79
|
+
#### KV Cache effect
|
|
80
|
+
|
|
81
|
+
Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries.
|
|
82
|
+
|
|
83
|
+
## Known Limitations and Deferred Work
|
|
84
|
+
|
|
85
|
+
- **Confinement covers file effects only** — network access and process visibility are unchanged, so the modes are not a general-purpose security sandbox.
|
|
86
|
+
- **Denials are inferred from failed-command stderr** — backend signatures make the inference portable, but a matching application error can be classified as a denial and a denial omitted from the retained tail can be missed.
|
|
87
|
+
- **An asynchronously observed background runner failure has no immediate error channel** — it is recorded on the settled process and surfaces when the caller reads the generic task with `task_output`; a synchronous `SubprocessService` throw that names the runner path instead fails `start()` immediately.
|
|
88
|
+
- **`danger-full-access` deliberately bypasses `ctx.sandbox`** — it is an explicit unconfined mode, not a wider sandbox profile.
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# @deepseek-ai/dsh-bash-sandbox
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 中文
|
|
4
|
+
|
|
5
|
+
这是使用沙箱能力的 [`@deepseek-ai/dsh-bash`](../bash/) 执行器 seam Service provider。加载它时,应**用它替代** `@deepseek-ai/dsh-bash-local`,并同时加载 [`ctx.sandbox`](../../sandbox/sandbox/) 提供方(例如 [`@deepseek-ai/dsh-sandbox-local`](../../sandbox/sandbox-local/))及 [`ctx.sandboxPolicy`](../../sandbox/sandbox-policy/);默认模式和工作区根目录由后者负责,并与受沙箱约束的文件系统共享这些设置。无需使用替代工具插件;`dsh-tool-bash` 会检测执行器的 `sandboxMode` 能力并添加升权字段。
|
|
6
|
+
|
|
7
|
+
包根目录导出默认与具名的 `SandboxBashExecutor` 插件及其 `Config`;结果分类 helper 保留在内部。
|
|
8
|
+
|
|
9
|
+
每条命令的限制方式都是:把本执行器即将 spawn 的精确 `['bash', '-c', command]` argv 交给提供方,并直接 spawn 返回的 argv。使用随附的原生 runner 时,内层 Bash 保留 shell 语义,并且只在 runner 建立约束后才求值 `BASH_ENV`。由哪种平台 runner 执行限制,以及是否有 runner 可用,属于提供方职责;若无可用 runner,则按失败关闭原则拒绝执行并返回结构化 `SANDBOX_UNAVAILABLE` 错误,绝不能静默地无约束运行。本包只负责 bash 侧。
|
|
10
|
+
|
|
11
|
+
| 模式 | 文件影响 |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `read-only`(默认) | 任何位置都不可写(在 `/dev` 中只有 `/dev/null` 节点可写,因此 `>/dev/null` 仍可正常工作) |
|
|
14
|
+
| `workspace-write` | 只能写入 `workspaceRoot` + `/tmp`(在 bwrap 下为临时目录,在 Landlock 下为宿主 `/tmp`,在 Seatbelt 下为 `/private/tmp` 加每用户临时目录) |
|
|
15
|
+
| `danger-full-access` | 不作限制;绝不咨询提供方。前台结果携带 `sandbox: { mode, denied: false }`;后台进程句柄不携带沙箱事实。 |
|
|
16
|
+
|
|
17
|
+
语义:
|
|
18
|
+
|
|
19
|
+
- **拒绝是结果事实。** 如果一次失败运行的 stderr 包含所选后端自身的拒绝方言,即提供方在每次包装时加上的特征(bwrap 下的 EROFS 文本、Landlock 下的 EACCES、Seatbelt 下的 EPERM),则结果报告 `BashRunResult.sandbox.denied: true`(从已收集的 stderr 尾部进行保守分类)。每次受限制运行还会携带执行时模式(`result.sandbox.mode`)与提供方强制执行完整性(`result.sandbox.enforcement`:`full`,或在较旧 Landlock ABI 上为 `partial`)。
|
|
20
|
+
- **Runner 路径或 syscall 必须匹配。** 进程启动前,调用方拥有的 workdir 必须经独立验证可用,Node 必须报告 `ENOENT` 或 `EACCES`,并且错误必须符合以下一种形态:`error.path` 等于提供方返回的 `argv[0]`,同时 `syscall` 为 `'spawn'` 或精确的 `'spawn <runner>'`;或者 `error.path` 不存在,同时 `syscall` 为精确的 `'spawn <runner>'`。这样可以识别缺失的 runner、不可执行的 runner,或 shebang 解释器不可用的可执行脚本。没有精确错误路径的裸 `syscall: 'spawn'`、任何其他错误码、无效或不可用的 workdir、资源失败、无关 syscall 或无结构拒绝仍保留本地执行器的命令启动失败语义。前台执行会抛出 `SANDBOX_UNAVAILABLE` 并附带原始 spawn 错误详情,异步后台结算则会标记 `runnerFailed: true` 和 `denied: false`。如果 `SubprocessService` 同步抛出同样能指明 runner 的 `ENOENT`/`EACCES` 形态,后台启动会抛出 `SANDBOX_UNAVAILABLE`;其他同步错误原样传播。进程启动后,先按整行精确匹配排除信息性行,随后规则的可选退出码检查和余下 stderr 中的一行致命诊断必须同时匹配。匹配结果优先于拒绝;前台执行会抛出 `SANDBOX_UNAVAILABLE` 并附带匹配到的致命行,已结算的后台进程则会标记 `process.sandbox.runnerFailed`,Bash 结果生成方通过通用 `task_output` 渲染它。无论走哪条路径,受限制的后台句柄都会保留自身的模式/强制执行事实,并释放每进程计数。
|
|
21
|
+
- **部署回退,每次调用策略。** [`ctx.sandboxPolicy`](../../sandbox/sandbox-policy/) 为每次工具调用解析完整的 `SandboxExecutionPolicy`:调用会话提供自身的模式覆盖与不可变 cwd 根目录,部署配置则为无 agent(智能体)调用提供回退。已批准的升权只更改该策略的模式,会话根目录仍然附着其上。`resolve()` 把策略带入 spec,因此来自不同项目的重叠命令会在各自的根目录与模式下运行、分类和报告。能力事实 `ctx.bash.sandboxMode` 报告已配置的默认值,因此工具层只在装载该执行器时才公布升权;静态 bash 工具描述则单独负责拒绝与升权引导。
|
|
22
|
+
- **只限制文件影响。** 设计上不限制网络与进程可见性:模式词汇不会声称覆盖后端未强制执行的范围。
|
|
23
|
+
- 进程机制(spawn、进程组终止、输出收集/spill、后台句柄、凭证清理)继承自 [`dsh-bash-local`](../bash-local/);runner 选择位于 [`dsh-sandbox-local`](../../sandbox/sandbox-local/)。
|
|
24
|
+
|
|
25
|
+
该 seam 只报告拒绝:拒绝是一项结果事实,本执行器绝不自行协商权限。批准问题位于工具层(`dsh-tool-bash`),由它设置本包所遵守的模式覆盖值。
|
|
26
|
+
|
|
27
|
+
```yaml
|
|
28
|
+
- id: sandbox
|
|
29
|
+
name: '@deepseek-ai/dsh-sandbox-local'
|
|
30
|
+
- id: sandbox-policy
|
|
31
|
+
name: '@deepseek-ai/dsh-sandbox-policy'
|
|
32
|
+
config:
|
|
33
|
+
mode: read-only
|
|
34
|
+
workspaceRoot: !!js process.cwd() # fallback for calls without a session cwd
|
|
35
|
+
- id: bash
|
|
36
|
+
name: '@deepseek-ai/dsh-bash-sandbox'
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## 模型体验
|
|
40
|
+
|
|
41
|
+
### 间接的 Bash 工具 schema
|
|
42
|
+
|
|
43
|
+
#### 模型看到的内容
|
|
44
|
+
|
|
45
|
+
基线是生成的 [`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` 上下文。
|
|
46
|
+
|
|
47
|
+
#### Token 影响
|
|
48
|
+
|
|
49
|
+
在 `bash` 可见的请求上,schema 固定增加少量内容,另有一条由 `dsh-sandbox-policy` 负责的当前策略子句。
|
|
50
|
+
|
|
51
|
+
#### KV Cache 影响
|
|
52
|
+
|
|
53
|
+
常驻策略变化会在保留的历史之后追加一份由归属方渲染的完整上下文快照,并使既有 system/history 前缀保持逐字节不变。更改执行器能力会改变 `bash` schema。
|
|
54
|
+
|
|
55
|
+
### 间接的 Bash 工具结果
|
|
56
|
+
|
|
57
|
+
#### 模型看到的内容
|
|
58
|
+
|
|
59
|
+
在普通有界输出之后,被拒绝的调用会精确追加 `[sandbox: file access denied under <mode> mode]`。当升权可用时,接下来精确追加 `[sandbox: escalation available — retry this exact command once with sandbox_permissions (the narrowest wider mode that suffices) + justification; the approval prompt asks the user]`。已结算的后台 runner 失败则追加 `[sandbox: the sandbox runner itself failed under <mode> mode — the command did not run; this is a sandbox problem, not a command failure]`。
|
|
60
|
+
|
|
61
|
+
#### Token 影响
|
|
62
|
+
|
|
63
|
+
除普通输出外,正常允许的运行不会增加 token。拒绝或失败会增加上述有条件标记,并保留到上下文压缩(context compaction)。
|
|
64
|
+
|
|
65
|
+
#### KV Cache 影响
|
|
66
|
+
|
|
67
|
+
仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV-cache 条目失效。
|
|
68
|
+
|
|
69
|
+
### 间接的 Bash 工具错误
|
|
70
|
+
|
|
71
|
+
#### 模型看到的内容
|
|
72
|
+
|
|
73
|
+
如果没有 runner 能强制执行受限模式,前台调用会传播 [`SANDBOX_UNAVAILABLE` 错误](../../sandbox/sandbox/README.md#confinement-error-indirectly);该错误由 `dsh-sandbox` 定义。判定为 runner 失败的 spawn 错误会以原始 spawn 错误作为详细信息;如果拒绝没有通过 `ENOENT`/`EACCES` 的 `path` 或 `syscall` 证据指明 `argv[0]`,它仍是普通的命令启动错误。已结算的 runner 失败则以匹配到的致命 stderr 行作为详细信息,并保留原始 stderr 收集结果。如果追加了 `Runner failure: <detail>`,它就是权威诊断;前面的后端安装文本只是通用的 `SANDBOX_UNAVAILABLE` 前缀。
|
|
74
|
+
|
|
75
|
+
#### Token 影响
|
|
76
|
+
|
|
77
|
+
该次调用会在相应条件下显示错误文本,该文本会保留在历史记录中直到上下文压缩。
|
|
78
|
+
|
|
79
|
+
#### KV Cache 影响
|
|
80
|
+
|
|
81
|
+
仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV-cache 条目失效。
|
|
82
|
+
|
|
83
|
+
## 已知限制与暂缓事项
|
|
84
|
+
|
|
85
|
+
- **限制只覆盖文件影响**:网络访问与进程可见性不变,因此这些模式不是通用安全沙箱。
|
|
86
|
+
- **拒绝从失败命令的 stderr 推断**:后端特征使该推断可跨平台使用,但包含相同后端特征的应用错误可能被分类为拒绝,也可能遗漏未出现在保留尾部中的拒绝。
|
|
87
|
+
- **异步观测到的后台 runner 失败没有即时错误通道**:它记录在已结算进程上,并在调用方使用 `task_output` 读取通用任务时呈现;`SubprocessService` 同步抛出的错误包含 runner 路径时,则会使 `start()` 立即失败。
|
|
88
|
+
- **`danger-full-access` 有意绕过 `ctx.sandbox`**:它是显式无约束模式,不是更宽的沙箱 profile。
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { SandboxUnavailableError } from "@deepseek-ai/dsh-sandbox";
|
|
2
|
+
import { LocalBashExecutor } from "@deepseek-ai/dsh-bash-local";
|
|
3
|
+
import { accessSync, constants, statSync } from "node:fs";
|
|
4
|
+
//#region lib/types/helpers.js
|
|
5
|
+
/**
|
|
6
|
+
* Internal sandbox-result classification helpers.
|
|
7
|
+
*
|
|
8
|
+
* @module @deepseek-ai/dsh-bash-sandbox/helpers
|
|
9
|
+
*/
|
|
10
|
+
/** Node-local spawn codes proven to identify executable resolution or permission failure. */
|
|
11
|
+
const EXECUTABLE_SPAWN_CODES = new Set(["EACCES", "ENOENT"]);
|
|
12
|
+
/** Whether the caller-owned spawn cwd can be entered. */
|
|
13
|
+
function isUsableWorkdir(path) {
|
|
14
|
+
try {
|
|
15
|
+
if (!statSync(path).isDirectory()) return false;
|
|
16
|
+
accessSync(path, constants.X_OK);
|
|
17
|
+
return true;
|
|
18
|
+
} catch {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Attribute only Node ENOENT/EACCES failures whose error path equals argv[0]
|
|
24
|
+
* after independently ruling out the caller-owned cwd. A supplied error path
|
|
25
|
+
* must exactly identify the runner; without one, the syscall must. With a
|
|
26
|
+
* usable cwd, these codes describe resolution or execute permission for that
|
|
27
|
+
* argv[0] or its shebang interpreter.
|
|
28
|
+
* The workdir is checked at classification time, not atomically with spawn;
|
|
29
|
+
* concurrent path replacement may change attribution but cannot permit an
|
|
30
|
+
* unconfined execution.
|
|
31
|
+
* @param error - the original spawn rejection.
|
|
32
|
+
* @param runnerProgram - provider argv[0], the executable that establishes confinement.
|
|
33
|
+
* @param workdir - the caller-owned spawn cwd, checked independently for usability.
|
|
34
|
+
* @returns whether the rejection has executable-specific runner evidence.
|
|
35
|
+
*/
|
|
36
|
+
function isRunnerSpawnFailure(error, runnerProgram, workdir) {
|
|
37
|
+
if (runnerProgram === void 0 || !isUsableWorkdir(workdir)) return false;
|
|
38
|
+
if (typeof error !== "object" || error === null) return false;
|
|
39
|
+
const { code, path, syscall } = error;
|
|
40
|
+
if (typeof code !== "string" || !EXECUTABLE_SPAWN_CODES.has(code)) return false;
|
|
41
|
+
if (typeof syscall !== "string") return false;
|
|
42
|
+
const exactSyscall = `spawn ${runnerProgram}`;
|
|
43
|
+
if (path === void 0) return syscall === exactSyscall;
|
|
44
|
+
if (typeof path !== "string" || path.length === 0 || path !== runnerProgram) return false;
|
|
45
|
+
return syscall === "spawn" || syscall === exactSyscall;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Classify a failed run against the selected backend's denial dialect.
|
|
49
|
+
* @param result - settled foreground run.
|
|
50
|
+
* @param signatures - case-insensitive denial substrings from the active wrap.
|
|
51
|
+
* @returns whether the failed run matches that denial dialect.
|
|
52
|
+
*/
|
|
53
|
+
function classifyDenial(result, signatures) {
|
|
54
|
+
return matchesSignature(result.exitCode, result.stderr.text, signatures);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Classify one settled process against the selected backend's structured
|
|
58
|
+
* runner-failure rules. Each rule requires a nonzero exit, its optional
|
|
59
|
+
* exit-code gate, and a fatal signature on one stderr line after exact
|
|
60
|
+
* informational lines are excluded.
|
|
61
|
+
* @param exitCode - process exit code; null means signal termination.
|
|
62
|
+
* @param stderr - collected stderr text, left unchanged.
|
|
63
|
+
* @param rules - structured runner-failure rules from the active wrap.
|
|
64
|
+
* @returns the first matching fatal line, or undefined when evidence is insufficient.
|
|
65
|
+
*/
|
|
66
|
+
function classifyRunnerFailure(exitCode, stderr, rules) {
|
|
67
|
+
if (exitCode === null || exitCode === 0) return void 0;
|
|
68
|
+
const lines = stderr.split(/\r?\n/);
|
|
69
|
+
for (const rule of rules) {
|
|
70
|
+
if (rule.allowedExitCodes !== void 0 && !rule.allowedExitCodes.includes(exitCode)) continue;
|
|
71
|
+
const informationalLines = new Set((rule.informationalLines ?? []).map((line) => line.toLowerCase()));
|
|
72
|
+
const fatalSignatures = rule.fatalSignatures.filter((signature) => signature.trim().length > 0).map((signature) => signature.toLowerCase());
|
|
73
|
+
for (const line of lines) {
|
|
74
|
+
const lowered = line.toLowerCase();
|
|
75
|
+
if (informationalLines.has(lowered)) continue;
|
|
76
|
+
if (fatalSignatures.some((signature) => lowered.includes(signature))) return { detail: line };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Match a non-zero exit against case-insensitive stderr signatures.
|
|
82
|
+
* @param exitCode - process exit code; null means signal termination.
|
|
83
|
+
* @param stderr - collected stderr text.
|
|
84
|
+
* @param signatures - substrings identifying the selected backend's dialect.
|
|
85
|
+
* @returns whether this is a non-zero exit whose stderr matches a signature.
|
|
86
|
+
*/
|
|
87
|
+
function matchesSignature(exitCode, stderr, signatures) {
|
|
88
|
+
if (exitCode === null || exitCode === 0) return false;
|
|
89
|
+
const lowered = stderr.toLowerCase();
|
|
90
|
+
return signatures.some((signature) => lowered.includes(signature.toLowerCase()));
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region lib/types/index.js
|
|
94
|
+
/**
|
|
95
|
+
* Sandbox-consuming bash executor. It wraps the exact local bash argv through
|
|
96
|
+
* `ctx.sandbox`, inherits local process mechanics, and reports the selected
|
|
97
|
+
* mode, enforcement, and denial facts. Positive runner-launch evidence means
|
|
98
|
+
* the command never ran: foreground calls throw `SANDBOX_UNAVAILABLE`, while
|
|
99
|
+
* background processes carry `runnerFailed`; other spawn rejections retain
|
|
100
|
+
* local-executor semantics. The tool owns approval and passes a complete per-call policy.
|
|
101
|
+
* @module @deepseek-ai/dsh-bash-sandbox
|
|
102
|
+
*/
|
|
103
|
+
/**
|
|
104
|
+
* Registers as `ctx.bash` in place of the local executor and requires a
|
|
105
|
+
* `ctx.sandbox` provider plus `ctx.sandboxPolicy`; the tool layer is
|
|
106
|
+
* unchanged. Tool calls pass the calling session's resolved policy; direct
|
|
107
|
+
* calls fall back to deployment policy. `result.sandbox` reports the mode and
|
|
108
|
+
* enforcement actually used.
|
|
109
|
+
*/
|
|
110
|
+
var SandboxBashExecutor = class extends LocalBashExecutor {
|
|
111
|
+
static inject = [
|
|
112
|
+
"subprocess",
|
|
113
|
+
"sandbox",
|
|
114
|
+
"sandboxPolicy"
|
|
115
|
+
];
|
|
116
|
+
mode;
|
|
117
|
+
/**
|
|
118
|
+
* Per-process confinement facts retained until settlement. Providers may
|
|
119
|
+
* vary enforcement and diagnostic dialect between overlapping calls, so a
|
|
120
|
+
* shared latest-wrap value would classify a process against the wrong facts.
|
|
121
|
+
* Unconfined processes have no entry.
|
|
122
|
+
*/
|
|
123
|
+
processFacts = /* @__PURE__ */ new Map();
|
|
124
|
+
constructor(ctx, config) {
|
|
125
|
+
super(ctx, config);
|
|
126
|
+
this.mode = ctx.sandboxPolicy.defaultMode;
|
|
127
|
+
}
|
|
128
|
+
/** The configured default mode — the capability fact the tool layer reads. */
|
|
129
|
+
get sandboxMode() {
|
|
130
|
+
return this.mode;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Stamp a complete per-call policy onto the spec. Tool calls supply the
|
|
134
|
+
* calling session's resolved mode and root; lower-level callers fall back to
|
|
135
|
+
* the deployment policy.
|
|
136
|
+
*/
|
|
137
|
+
resolve(request) {
|
|
138
|
+
return {
|
|
139
|
+
...super.resolve(request),
|
|
140
|
+
sandboxPolicy: request.sandboxPolicy ?? this.ctx.sandboxPolicy.resolve()
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
async run(spec) {
|
|
144
|
+
const policy = spec.sandboxPolicy;
|
|
145
|
+
const { mode } = policy;
|
|
146
|
+
if (mode === "danger-full-access") return {
|
|
147
|
+
...await super.run(spec),
|
|
148
|
+
sandbox: {
|
|
149
|
+
mode,
|
|
150
|
+
denied: false
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
const confined = this.confine(spec.command, {
|
|
154
|
+
...policy,
|
|
155
|
+
mode
|
|
156
|
+
});
|
|
157
|
+
let result;
|
|
158
|
+
try {
|
|
159
|
+
result = await this.runArgv(spec, confined.argv);
|
|
160
|
+
} catch (error) {
|
|
161
|
+
if (spec.signal?.aborted === true) spec.signal.throwIfAborted();
|
|
162
|
+
if (isRunnerSpawnFailure(error, confined.argv[0], spec.workdir)) throw new SandboxUnavailableError(mode, String(error));
|
|
163
|
+
throw error;
|
|
164
|
+
}
|
|
165
|
+
const runnerFailure = classifyRunnerFailure(result.exitCode, result.stderr.text, confined.runnerFailureRules);
|
|
166
|
+
if (runnerFailure !== void 0) throw new SandboxUnavailableError(mode, runnerFailure.detail);
|
|
167
|
+
return {
|
|
168
|
+
...result,
|
|
169
|
+
sandbox: {
|
|
170
|
+
mode,
|
|
171
|
+
denied: classifyDenial(result, confined.denialSignatures),
|
|
172
|
+
enforcement: confined.enforcement
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
start(spec) {
|
|
177
|
+
const policy = spec.sandboxPolicy;
|
|
178
|
+
const { mode } = policy;
|
|
179
|
+
if (mode === "danger-full-access") return super.start(spec);
|
|
180
|
+
const confined = this.confine(spec.command, {
|
|
181
|
+
...policy,
|
|
182
|
+
mode
|
|
183
|
+
});
|
|
184
|
+
let proc;
|
|
185
|
+
try {
|
|
186
|
+
proc = this.startArgv(spec, confined.argv);
|
|
187
|
+
} catch (error) {
|
|
188
|
+
if (isRunnerSpawnFailure(error, confined.argv[0], spec.workdir)) throw new SandboxUnavailableError(mode, String(error));
|
|
189
|
+
throw error;
|
|
190
|
+
}
|
|
191
|
+
const { enforcement, denialSignatures, runnerFailureRules } = confined;
|
|
192
|
+
this.processFacts.set(proc, {
|
|
193
|
+
mode,
|
|
194
|
+
enforcement,
|
|
195
|
+
denialSignatures,
|
|
196
|
+
runnerFailureRules,
|
|
197
|
+
runnerProgram: confined.argv[0],
|
|
198
|
+
workdir: spec.workdir
|
|
199
|
+
});
|
|
200
|
+
return proc;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Stamp per-process sandbox facts before `done` settles. Full-access processes
|
|
204
|
+
* have no facts; signal deaths are not denials.
|
|
205
|
+
*/
|
|
206
|
+
onProcessDone(proc, stderr, spawnFailed, spawnError) {
|
|
207
|
+
const facts = this.processFacts.get(proc);
|
|
208
|
+
if (facts !== void 0) {
|
|
209
|
+
this.processFacts.delete(proc);
|
|
210
|
+
const runnerFailed = spawnFailed ? isRunnerSpawnFailure(spawnError, facts.runnerProgram, facts.workdir) : classifyRunnerFailure(proc.exitCode, stderr, facts.runnerFailureRules) !== void 0;
|
|
211
|
+
proc.sandbox = {
|
|
212
|
+
mode: facts.mode,
|
|
213
|
+
denied: !runnerFailed && matchesSignature(proc.exitCode, stderr, facts.denialSignatures),
|
|
214
|
+
enforcement: facts.enforcement,
|
|
215
|
+
...runnerFailed ? { runnerFailed } : {}
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
super.onProcessDone(proc, stderr, spawnFailed, spawnError);
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Wrap one shell command via the `ctx.sandbox` provider. Provider errors
|
|
222
|
+
* propagate unchanged; the returned argv is handed directly to the local
|
|
223
|
+
* executor's subprocess path.
|
|
224
|
+
* @param command - shell source for the confined inner `bash -c`.
|
|
225
|
+
* @param policy - resolved confined execution policy.
|
|
226
|
+
* @returns the provider's exact argv and settlement-classification facts.
|
|
227
|
+
*/
|
|
228
|
+
confine(command, policy) {
|
|
229
|
+
return this.ctx.sandbox.confine([
|
|
230
|
+
"bash",
|
|
231
|
+
"-c",
|
|
232
|
+
command
|
|
233
|
+
], policy);
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
//#endregion
|
|
237
|
+
export { SandboxBashExecutor, SandboxBashExecutor as default };
|
package/lib/invariant.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region lib/types/invariant.js
|
|
2
|
+
/**
|
|
3
|
+
* Package-owned invariant companion for `@deepseek-ai/dsh-bash-sandbox`.
|
|
4
|
+
* @module @deepseek-ai/dsh-bash-sandbox/invariant
|
|
5
|
+
*/
|
|
6
|
+
const PACKAGE_NAME = "@deepseek-ai/dsh-bash-sandbox";
|
|
7
|
+
/** Cordis companion plugin name. */
|
|
8
|
+
const name = "bash-sandbox-invariant";
|
|
9
|
+
/** Service required before the companion can reserve package ownership. */
|
|
10
|
+
const inject = ["invariants"];
|
|
11
|
+
/**
|
|
12
|
+
* No runtime invariant: this package exposes no independent event sequence or mutable data relation
|
|
13
|
+
* beyond contracts enforced at its owning seam.
|
|
14
|
+
*/
|
|
15
|
+
const install = () => {};
|
|
16
|
+
/**
|
|
17
|
+
* Register this package's invariant companion.
|
|
18
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
19
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
20
|
+
*/
|
|
21
|
+
const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
22
|
+
//#endregion
|
|
23
|
+
export { apply, inject, name };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal sandbox-result classification helpers.
|
|
3
|
+
*
|
|
4
|
+
* @module @deepseek-ai/dsh-bash-sandbox/helpers
|
|
5
|
+
*/
|
|
6
|
+
import type { BashRunResult } from '@deepseek-ai/dsh-bash';
|
|
7
|
+
import type { RunnerFailureRule } from '@deepseek-ai/dsh-sandbox';
|
|
8
|
+
/**
|
|
9
|
+
* Attribute only Node ENOENT/EACCES failures whose error path equals argv[0]
|
|
10
|
+
* after independently ruling out the caller-owned cwd. A supplied error path
|
|
11
|
+
* must exactly identify the runner; without one, the syscall must. With a
|
|
12
|
+
* usable cwd, these codes describe resolution or execute permission for that
|
|
13
|
+
* argv[0] or its shebang interpreter.
|
|
14
|
+
* The workdir is checked at classification time, not atomically with spawn;
|
|
15
|
+
* concurrent path replacement may change attribution but cannot permit an
|
|
16
|
+
* unconfined execution.
|
|
17
|
+
* @param error - the original spawn rejection.
|
|
18
|
+
* @param runnerProgram - provider argv[0], the executable that establishes confinement.
|
|
19
|
+
* @param workdir - the caller-owned spawn cwd, checked independently for usability.
|
|
20
|
+
* @returns whether the rejection has executable-specific runner evidence.
|
|
21
|
+
*/
|
|
22
|
+
export declare function isRunnerSpawnFailure(error: unknown, runnerProgram: string | undefined, workdir: string): boolean;
|
|
23
|
+
/** Fatal runner evidence retained for infrastructure-error detail. */
|
|
24
|
+
interface RunnerFailureMatch {
|
|
25
|
+
/** The original stderr line that matched a fatal signature. */
|
|
26
|
+
detail: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Classify a failed run against the selected backend's denial dialect.
|
|
30
|
+
* @param result - settled foreground run.
|
|
31
|
+
* @param signatures - case-insensitive denial substrings from the active wrap.
|
|
32
|
+
* @returns whether the failed run matches that denial dialect.
|
|
33
|
+
*/
|
|
34
|
+
export declare function classifyDenial(result: BashRunResult, signatures: readonly string[]): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Classify one settled process against the selected backend's structured
|
|
37
|
+
* runner-failure rules. Each rule requires a nonzero exit, its optional
|
|
38
|
+
* exit-code gate, and a fatal signature on one stderr line after exact
|
|
39
|
+
* informational lines are excluded.
|
|
40
|
+
* @param exitCode - process exit code; null means signal termination.
|
|
41
|
+
* @param stderr - collected stderr text, left unchanged.
|
|
42
|
+
* @param rules - structured runner-failure rules from the active wrap.
|
|
43
|
+
* @returns the first matching fatal line, or undefined when evidence is insufficient.
|
|
44
|
+
*/
|
|
45
|
+
export declare function classifyRunnerFailure(exitCode: number | null, stderr: string, rules: readonly RunnerFailureRule[]): RunnerFailureMatch | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Match a non-zero exit against case-insensitive stderr signatures.
|
|
48
|
+
* @param exitCode - process exit code; null means signal termination.
|
|
49
|
+
* @param stderr - collected stderr text.
|
|
50
|
+
* @param signatures - substrings identifying the selected backend's dialect.
|
|
51
|
+
* @returns whether this is a non-zero exit whose stderr matches a signature.
|
|
52
|
+
*/
|
|
53
|
+
export declare function matchesSignature(exitCode: number | null, stderr: string, signatures: readonly string[]): boolean;
|
|
54
|
+
export {};
|
|
55
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sandbox-consuming bash executor. It wraps the exact local bash argv through
|
|
3
|
+
* `ctx.sandbox`, inherits local process mechanics, and reports the selected
|
|
4
|
+
* mode, enforcement, and denial facts. Positive runner-launch evidence means
|
|
5
|
+
* the command never ran: foreground calls throw `SANDBOX_UNAVAILABLE`, while
|
|
6
|
+
* background processes carry `runnerFailed`; other spawn rejections retain
|
|
7
|
+
* local-executor semantics. The tool owns approval and passes a complete per-call policy.
|
|
8
|
+
* @module @deepseek-ai/dsh-bash-sandbox
|
|
9
|
+
*/
|
|
10
|
+
import { Context } from '@deepseek-ai/cordis';
|
|
11
|
+
import type { BashExecRequest, BashExecSpec, BashProcess, BashRunResult } from '@deepseek-ai/dsh-bash';
|
|
12
|
+
import type { SandboxMode } from '@deepseek-ai/dsh-sandbox';
|
|
13
|
+
import { LocalBashExecutor } from '@deepseek-ai/dsh-bash-local';
|
|
14
|
+
import type { Config as LocalConfig } from '@deepseek-ai/dsh-bash-local';
|
|
15
|
+
/**
|
|
16
|
+
* Plugin config: the local executor's knobs, verbatim. The sandbox policy —
|
|
17
|
+
* the default mode and fallback `workspace-write` root — is NOT here: it lives
|
|
18
|
+
* on `ctx.sandboxPolicy` (`@deepseek-ai/dsh-sandbox-policy`), which resolves
|
|
19
|
+
* each calling session's mode and cwd for every enforcing capability. The runner
|
|
20
|
+
* choice is likewise the `ctx.sandbox` provider's config, not this executor's.
|
|
21
|
+
*/
|
|
22
|
+
export type Config = LocalConfig;
|
|
23
|
+
/**
|
|
24
|
+
* Registers as `ctx.bash` in place of the local executor and requires a
|
|
25
|
+
* `ctx.sandbox` provider plus `ctx.sandboxPolicy`; the tool layer is
|
|
26
|
+
* unchanged. Tool calls pass the calling session's resolved policy; direct
|
|
27
|
+
* calls fall back to deployment policy. `result.sandbox` reports the mode and
|
|
28
|
+
* enforcement actually used.
|
|
29
|
+
*/
|
|
30
|
+
export declare class SandboxBashExecutor extends LocalBashExecutor {
|
|
31
|
+
static inject: string[];
|
|
32
|
+
private readonly mode;
|
|
33
|
+
/**
|
|
34
|
+
* Per-process confinement facts retained until settlement. Providers may
|
|
35
|
+
* vary enforcement and diagnostic dialect between overlapping calls, so a
|
|
36
|
+
* shared latest-wrap value would classify a process against the wrong facts.
|
|
37
|
+
* Unconfined processes have no entry.
|
|
38
|
+
*/
|
|
39
|
+
private readonly processFacts;
|
|
40
|
+
constructor(ctx: Context, config: Config);
|
|
41
|
+
/** The configured default mode — the capability fact the tool layer reads. */
|
|
42
|
+
get sandboxMode(): SandboxMode;
|
|
43
|
+
/**
|
|
44
|
+
* Stamp a complete per-call policy onto the spec. Tool calls supply the
|
|
45
|
+
* calling session's resolved mode and root; lower-level callers fall back to
|
|
46
|
+
* the deployment policy.
|
|
47
|
+
*/
|
|
48
|
+
resolve(request: BashExecRequest): BashExecSpec;
|
|
49
|
+
run(spec: BashExecSpec): Promise<BashRunResult>;
|
|
50
|
+
start(spec: BashExecSpec): BashProcess;
|
|
51
|
+
/**
|
|
52
|
+
* Stamp per-process sandbox facts before `done` settles. Full-access processes
|
|
53
|
+
* have no facts; signal deaths are not denials.
|
|
54
|
+
*/
|
|
55
|
+
protected onProcessDone(proc: BashProcess, stderr: string, spawnFailed: boolean, spawnError?: unknown): void;
|
|
56
|
+
/**
|
|
57
|
+
* Wrap one shell command via the `ctx.sandbox` provider. Provider errors
|
|
58
|
+
* propagate unchanged; the returned argv is handed directly to the local
|
|
59
|
+
* executor's subprocess path.
|
|
60
|
+
* @param command - shell source for the confined inner `bash -c`.
|
|
61
|
+
* @param policy - resolved confined execution policy.
|
|
62
|
+
* @returns the provider's exact argv and settlement-classification facts.
|
|
63
|
+
*/
|
|
64
|
+
private confine;
|
|
65
|
+
}
|
|
66
|
+
export default SandboxBashExecutor;
|
|
67
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-owned invariant companion for `@deepseek-ai/dsh-bash-sandbox`.
|
|
3
|
+
* @module @deepseek-ai/dsh-bash-sandbox/invariant
|
|
4
|
+
*/
|
|
5
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
6
|
+
/** Cordis companion plugin name. */
|
|
7
|
+
export declare const name = "bash-sandbox-invariant";
|
|
8
|
+
/** Service required before the companion can reserve package ownership. */
|
|
9
|
+
export declare const inject: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Register this package's invariant companion.
|
|
12
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
13
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
14
|
+
*/
|
|
15
|
+
export declare const apply: (ctx: Context) => Promise<() => void>;
|
|
16
|
+
//# sourceMappingURL=invariant.d.ts.map
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@deepseek-ai/dsh-bash-sandbox",
|
|
3
|
+
"description": "Sandbox-consuming implementation of the DeepSeek Harness bash executor seam (confines every command via ctx.sandbox, reports denial/enforcement result facts)",
|
|
4
|
+
"version": "0.0.1-rc.1",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "restricted"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
|
|
11
|
+
"directory": "packages/bash/bash-sandbox"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "lib/index.js",
|
|
15
|
+
"types": "lib/types/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./lib/types/index.d.ts",
|
|
19
|
+
"default": "./lib/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./invariant": {
|
|
22
|
+
"types": "./lib/types/invariant.d.ts",
|
|
23
|
+
"default": "./lib/invariant.js"
|
|
24
|
+
},
|
|
25
|
+
"./src/*": "./src/*",
|
|
26
|
+
"./package.json": "./package.json"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"lib/index.js",
|
|
30
|
+
"lib/invariant.js",
|
|
31
|
+
"lib/types/**/*.d.ts"
|
|
32
|
+
],
|
|
33
|
+
"license": "BSD-3-Clause",
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@deepseek-ai/dsh-bash": "^0.0.1-rc.1",
|
|
36
|
+
"@deepseek-ai/dsh-bash-local": "^0.0.1-rc.1",
|
|
37
|
+
"@deepseek-ai/dsh-invariants": "^0.0.1-rc.1",
|
|
38
|
+
"@deepseek-ai/dsh-sandbox": "^0.0.1-rc.1",
|
|
39
|
+
"@deepseek-ai/dsh-sandbox-policy": "^0.0.1-rc.1",
|
|
40
|
+
"@deepseek-ai/cordis": "^4.0.1-rc.1"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@deepseek-ai/dsh-bash": "^0.0.1-rc.1",
|
|
44
|
+
"@deepseek-ai/dsh-invariants": "^0.0.1-rc.1",
|
|
45
|
+
"@deepseek-ai/dsh-bash-local": "^0.0.1-rc.1",
|
|
46
|
+
"@deepseek-ai/dsh-subprocess-local": "^0.0.1-rc.1",
|
|
47
|
+
"@deepseek-ai/dsh-sandbox": "^0.0.1-rc.1",
|
|
48
|
+
"@deepseek-ai/dsh-sandbox-local": "^0.0.1-rc.1",
|
|
49
|
+
"@deepseek-ai/dsh-sandbox-policy": "^0.0.1-rc.1",
|
|
50
|
+
"@deepseek-ai/cordis": "^4.0.1-rc.1",
|
|
51
|
+
"@deepseek-ai/node-addon-landlock-run": "0.0.1"
|
|
52
|
+
}
|
|
53
|
+
}
|