refactor(sandbox): defer native protocol exports (round 3)

This commit is contained in:
Hypatia May
2026-08-04 13:37:33 +08:00
parent 319376ef1c
commit f91aedd074
14 changed files with 44 additions and 69 deletions
+1 -1
View File
@@ -1037,7 +1037,7 @@ export interface Config {
}
```
Source: [`packages/sandbox/sandbox-local/src/index.ts:25`](../packages/sandbox/sandbox-local/src/index.ts)
Source: [`packages/sandbox/sandbox-local/src/index.ts:24`](../packages/sandbox/sandbox-local/src/index.ts)
## `@deepseek-ai/dsh-sandbox-policy`
@@ -1,10 +1,7 @@
import type { ConfinedArgv, SandboxPolicy } from '@deepseek-ai/dsh-sandbox'
import { SandboxProvider } from '@deepseek-ai/dsh-sandbox'
import {
LAUNCHER_FAILURE_EXIT,
LAUNCHER_FATAL_PREFIX,
PARTIAL_ENFORCEMENT_NOTICE,
} from 'node-addon-landlock-run'
const NOTICE = 'landlock-run: partial enforcement (older Landlock ABI)'
/** Snapshot-only provider that reproduces an older-ABI Landlock launch. */
export default class PartialLandlockSandboxProvider extends SandboxProvider {
@@ -13,16 +10,16 @@ export default class PartialLandlockSandboxProvider extends SandboxProvider {
argv: [
'bash',
'-c',
`printf '%s\\n' '${PARTIAL_ENFORCEMENT_NOTICE}' >&2; exec "$@"`,
`printf '%s\\n' '${NOTICE}' >&2; exec "$@"`,
'partial-landlock-run',
...argv,
],
enforcement: 'partial',
denialSignatures: ['permission denied'],
runnerFailureRules: [{
allowedExitCodes: [LAUNCHER_FAILURE_EXIT],
fatalSignatures: [LAUNCHER_FATAL_PREFIX],
informationalLines: [PARTIAL_ENFORCEMENT_NOTICE],
allowedExitCodes: [125],
fatalSignatures: ['landlock-run: '],
informationalLines: [NOTICE],
}],
}
}
+1 -2
View File
@@ -100,7 +100,6 @@
"@deepseek-ai/dsh-web": "workspace:*",
"@deepseek-ai/dsh-web-fetch-local": "workspace:*",
"@deepseek-ai/dsh-workflow-workerthread": "workspace:*",
"@deepseek-ai/dsh-workspace-context": "workspace:*",
"node-addon-landlock-run": "0.0.0-test.0"
"@deepseek-ai/dsh-workspace-context": "workspace:*"
}
}
+2 -2
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 native/landlock-run/README.md
README.md: 483b14df7cb91fc6486f69efc1ddc560ab635ed5
README.zh.md: a239889ec68a8d56bb901b17feaac7f7acbf66fa
README.md: 19cc18830b90609f648cfb2ce1ee509ad9fe381b
README.zh.md: c93c33b843e3afc15b1890ce14edf436e051592c
+1 -1
View File
@@ -39,7 +39,7 @@ The public API is intentionally small:
- `launcherPath()`: absolute path of this host's launcher (existence deliberately unchecked — the probe is the availability signal).
- `probe(launcher?, { timeoutMs? })`: functional enforcement probe — `'full' | 'partial' | 'unusable'`.
- `grantArgs({ readOnly?, readWrite? })`: the launcher's grant argv; everything not granted is denied.
- `LAUNCHER_BIN`, `LAUNCHER_FAILURE_EXIT` (125), `LAUNCHER_FATAL_PREFIX`, and `PARTIAL_ENFORCEMENT_NOTICE`: contract constants. Every launcher failure uses 125, but a successfully exec'd child may also return 125, so failure attribution requires the fatal prefix too.
- `LAUNCHER_BIN` and `LAUNCHER_FAILURE_EXIT` (125): contract constants. A successfully exec'd child may also return 125, so consumers need the fatal diagnostic as well as the status to attribute launcher failure.
The full binary contract (argv grammar, exit codes, report lines) is pinned in [docs/cli-contract.md](docs/cli-contract.md).
+1 -1
View File
@@ -39,7 +39,7 @@ if (probe(launcher) !== 'unusable') {
- `launcherPath()`:当前宿主启动器的绝对路径(有意不检查是否存在;探测结果才是可用性信号)。
- `probe(launcher?, { timeoutMs? })`:功能性强制执行探测,返回 `'full' | 'partial' | 'unusable'`
- `grantArgs({ readOnly?, readWrite? })`:启动器的授权 argv;未授予的一切都被拒绝。
- `LAUNCHER_BIN``LAUNCHER_FAILURE_EXIT`125`LAUNCHER_FATAL_PREFIX``PARTIAL_ENFORCEMENT_NOTICE`:契约常量。所有 launcher 失败的退出码都是 125,但成功完成 exec 的子进程也可能返回 125,因此还必须有致命前缀,才能将结果归因为 launcher 失败。
- `LAUNCHER_BIN``LAUNCHER_FAILURE_EXIT`125:契约常量。成功完成 exec 的子进程也可能返回 125,因此消费者必须同时看到致命诊断和该状态,才能将结果归因为 launcher 失败。
完整的二进制契约(argv 语法、退出码、报告行)锁定在 [docs/cli-contract.md](docs/cli-contract.md) 中。
+4 -4
View File
@@ -1,6 +1,6 @@
# CLI contract: landlock-run
This file pins the launcher's externally observable behavior — the cross-repo compatibility surface between the binaries and every consumer. Consumers interact with it only through the entry package (`launcherPath`/`probe`/`grantArgs` and its protocol constants); changing anything below requires a version bump for the whole package family and a note in the release notes.
This file pins the launcher's externally observable behavior — the cross-repo compatibility surface between the binaries and every consumer. Consumers interact with it through the entry package (`launcherPath`/`probe`/`grantArgs`) and the launcher protocol; changing anything below requires a version bump for the whole package family and a note in the release notes.
## Invocation grammar
@@ -20,14 +20,14 @@ landlock-run --probe
## Exit codes
- `125` (`LAUNCHER_FAILURE_EXIT`): every launcher-level failure — usage error, kernel that cannot enforce Landlock, unopenable grant root, failed `exec`. The wrapped command was NOT run.
- After a successful `exec`, every child status is passed through unchanged, including 125. Consumers therefore require both status 125 and a `LAUNCHER_FATAL_PREFIX` line to attribute launcher failure.
- After a successful `exec`, every child status is passed through unchanged, including 125. Consumers therefore require both status 125 and a `landlock-run: ` fatal line to attribute launcher failure.
- `--probe`: `0` when the kernel enforces (fully or partially), `125` otherwise.
## Report lines
- Probe success prints exactly one stdout line: `landlock: fully enforced` or `landlock: partially enforced (older ABI)`. The entry package's `probe()` maps these to `full`/`partial`; a non-zero probe exit maps to `unusable`.
- A confined run under a partial-ABI kernel prints one stderr line `landlock-run: partial enforcement (older Landlock ABI)` (`PARTIAL_ENFORCEMENT_NOTICE`) and proceeds — still confined for everything the kernel supports.
- Every fatal error prints one stderr line prefixed `landlock-run: ` (`LAUNCHER_FATAL_PREFIX`) before exiting `125`.
- A confined run under a partial-ABI kernel prints one stderr line `landlock-run: partial enforcement (older Landlock ABI)` and proceeds — still confined for everything the kernel supports.
- Every fatal error prints one stderr line prefixed `landlock-run: ` before exiting `125`.
## Confinement semantics
@@ -21,18 +21,12 @@ import { fileURLToPath } from 'node:url'
/** The launcher binary's file name inside each platform package's `bin/`. */
export const LAUNCHER_BIN = 'landlock-run'
/** Prefix on every launcher-owned fatal stderr line. */
export const LAUNCHER_FATAL_PREFIX = 'landlock-run: '
/** Informational stderr line emitted before child execution under partial enforcement. */
export const PARTIAL_ENFORCEMENT_NOTICE = 'landlock-run: partial enforcement (older Landlock ABI)'
/**
* The exit code for every launcher-level failure (usage error, unenforcing
* kernel, unopenable grant root, failed exec). After a successful `exec`, the
* wrapped command may also return 125, so consumers require a matching
* {@link LAUNCHER_FATAL_PREFIX} diagnostic to attribute launcher failure.
* Part of the CLI contract.
* wrapped command may also return 125, so consumers also require a matching
* launcher-owned fatal diagnostic to attribute launcher failure. Part of the
* CLI contract.
*/
export const LAUNCHER_FAILURE_EXIT = 125
-4
View File
@@ -12,8 +12,6 @@ import path from 'node:path';
import {
LAUNCHER_BIN,
LAUNCHER_FAILURE_EXIT,
LAUNCHER_FATAL_PREFIX,
PARTIAL_ENFORCEMENT_NOTICE,
grantArgs,
launcherPath,
probe,
@@ -22,8 +20,6 @@ import {
// --- constants are part of the CLI contract ---
assert.equal(LAUNCHER_BIN, 'landlock-run');
assert.equal(LAUNCHER_FAILURE_EXIT, 125);
assert.equal(LAUNCHER_FATAL_PREFIX, 'landlock-run: ');
assert.equal(PARTIAL_ENFORCEMENT_NOTICE, 'landlock-run: partial enforcement (older Landlock ABI)');
// --- grantArgs: flag spelling, ordering, and empty grants ---
assert.deepEqual(grantArgs({}), []);
+5 -5
View File
@@ -19,13 +19,13 @@ import path from 'node:path';
import { spawnSync } from 'node:child_process';
import {
LAUNCHER_FAILURE_EXIT,
LAUNCHER_FATAL_PREFIX,
PARTIAL_ENFORCEMENT_NOTICE,
grantArgs,
launcherPath,
probe,
} from 'node-addon-landlock-run';
const FATAL_PREFIX = 'landlock-run: ';
const PARTIAL_NOTICE = 'landlock-run: partial enforcement (older Landlock ABI)';
const requireLandlock = process.env.NALR_REQUIRE_LANDLOCK === '1';
if (process.platform !== 'linux') {
@@ -45,7 +45,7 @@ const run = (args, options = {}) => spawnSync(launcher, args, { encoding: 'utf8'
{
const noCommand = run([]);
assert.equal(noCommand.status, LAUNCHER_FAILURE_EXIT);
assert.ok(noCommand.stderr.startsWith(LAUNCHER_FATAL_PREFIX));
assert.ok(noCommand.stderr.startsWith(FATAL_PREFIX));
assert.match(noCommand.stderr, /usage error: missing `-- <argv>\.\.\.` command/);
const unknownFlag = run(['--bogus', '--', 'true']);
@@ -78,7 +78,7 @@ if (enforcement === 'unusable') {
console.log('launcher.test: SKIP enforcement half — kernel does not enforce Landlock');
process.exit(0);
}
const expectedNotice = enforcement === 'partial' ? `${PARTIAL_ENFORCEMENT_NOTICE}\n` : '';
const expectedNotice = enforcement === 'partial' ? `${PARTIAL_NOTICE}\n` : '';
{
const probeRun = run(['--probe']);
assert.equal(probeRun.status, 0);
@@ -129,7 +129,7 @@ const expectedNotice = enforcement === 'partial' ? `${PARTIAL_ENFORCEMENT_NOTICE
const marker = path.join(os.tmpdir(), `nalr-should-not-exist-${process.pid}`);
const badGrant = run(['--ro', '/no/such/grant/root', '--', '/bin/sh', '-c', `echo x > ${marker}`]);
assert.equal(badGrant.status, LAUNCHER_FAILURE_EXIT);
assert.ok(badGrant.stderr.startsWith(LAUNCHER_FATAL_PREFIX));
assert.ok(badGrant.stderr.startsWith(FATAL_PREFIX));
assert.match(badGrant.stderr, /cannot open rule path/);
assert.ok(!fs.existsSync(marker), 'the command must never run when the launcher fails');
}
@@ -9,18 +9,16 @@ import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
import { Context } from 'cordis'
import {
LAUNCHER_FAILURE_EXIT,
LAUNCHER_FATAL_PREFIX,
PARTIAL_ENFORCEMENT_NOTICE,
} from 'node-addon-landlock-run'
import { LAUNCHER_FAILURE_EXIT } from 'node-addon-landlock-run'
import { SANDBOX_UNAVAILABLE } from '@deepseek-ai/dsh-sandbox'
import { LocalSandboxProvider } from '@deepseek-ai/dsh-sandbox-local'
import { SandboxPolicyService } from '@deepseek-ai/dsh-sandbox-policy'
import { SandboxBashExecutor } from '@deepseek-ai/dsh-bash-sandbox'
import LocalSubprocessService from '@deepseek-ai/dsh-subprocess-local'
const FATAL = `${LAUNCHER_FATAL_PREFIX}landlock ruleset error: Invalid argument`
const NOTICE = 'landlock-run: partial enforcement (older Landlock ABI)'
const FATAL_PREFIX = 'landlock-run: '
const FATAL = `${FATAL_PREFIX}landlock ruleset error: Invalid argument`
const contexts: Context[] = []
const tempDirs: string[] = []
@@ -41,10 +39,10 @@ while [ "$#" -gt 0 ]; do
case "$1" in
--ro|--rw) shift 2 ;;
--) shift; break ;;
*) printf '%s\\n' '${LAUNCHER_FATAL_PREFIX}usage error: unexpected fake argument' >&2; exit ${LAUNCHER_FAILURE_EXIT} ;;
*) printf '%s\\n' '${FATAL_PREFIX}usage error: unexpected fake argument' >&2; exit ${LAUNCHER_FAILURE_EXIT} ;;
esac
done
printf '%s\\n' '${PARTIAL_ENFORCEMENT_NOTICE}' >&2
printf '%s\\n' '${NOTICE}' >&2
${fatalBranch}exec "$@"
`, { mode: 0o755 })
return launcher
@@ -113,7 +111,7 @@ describe('partial Landlock runner-failure classification', () => {
const bash = await setup()
const result = await bash.run(bash.resolve({ command: `exit ${exitCode}` }))
expect(result.exitCode).toBe(exitCode)
expect(result.stderr.text).toBe(`${PARTIAL_ENFORCEMENT_NOTICE}\n`)
expect(result.stderr.text).toBe(`${NOTICE}\n`)
expect(result.sandbox).toEqual({ mode: 'read-only', denied: false, enforcement: 'partial' })
},
)
@@ -122,7 +120,7 @@ describe('partial Landlock runner-failure classification', () => {
const bash = await setup()
const result = await bash.run(bash.resolve({ command: `exit ${exitCode}` }))
expect(result.exitCode).toBe(exitCode)
expect(result.stderr.text).toBe(`${PARTIAL_ENFORCEMENT_NOTICE}\n`)
expect(result.stderr.text).toBe(`${NOTICE}\n`)
expect(result.sandbox).toEqual({ mode: 'read-only', denied: false, enforcement: 'partial' })
})
@@ -130,7 +128,7 @@ describe('partial Landlock runner-failure classification', () => {
const bash = await setup(exitCode)
const result = await bash.run(bash.resolve({ command: 'true' }))
expect(result.exitCode).toBe(exitCode)
expect(result.stderr.text).toBe(`${PARTIAL_ENFORCEMENT_NOTICE}\n${FATAL}\n`)
expect(result.stderr.text).toBe(`${NOTICE}\n${FATAL}\n`)
expect(result.sandbox).toEqual({ mode: 'read-only', denied: false, enforcement: 'partial' })
})
@@ -140,13 +138,13 @@ describe('partial Landlock runner-failure classification', () => {
expect(error).toMatchObject({ name: 'SandboxUnavailableError', code: SANDBOX_UNAVAILABLE })
expect(error).toBeInstanceOf(Error)
expect((error as Error).message).toContain(`Runner failure: ${FATAL}`)
expect((error as Error).message).not.toContain(PARTIAL_ENFORCEMENT_NOTICE)
expect((error as Error).message).not.toContain(NOTICE)
})
it('classifies a notice plus child Permission denied as a denial, not runner failure', async () => {
const bash = await setup()
const result = await bash.run(bash.resolve({ command: 'printf "%s\\n" "child: Permission denied" >&2; exit 1' }))
expect(result.stderr.text).toBe(`${PARTIAL_ENFORCEMENT_NOTICE}\nchild: Permission denied\n`)
expect(result.stderr.text).toBe(`${NOTICE}\nchild: Permission denied\n`)
expect(result.sandbox).toEqual({ mode: 'read-only', denied: true, enforcement: 'partial' })
})
@@ -156,7 +154,7 @@ describe('partial Landlock runner-failure classification', () => {
const task = bash.start(bash.resolve({ command }))
await task.done
expect(task.sandbox).toEqual({ mode: 'read-only', denied: false, enforcement: 'partial' })
expect(task.readOutput().delta).toContain(PARTIAL_ENFORCEMENT_NOTICE)
expect(task.readOutput().delta).toContain(NOTICE)
}
})
@@ -165,7 +163,7 @@ describe('partial Landlock runner-failure classification', () => {
const task = bash.start(bash.resolve({ command: 'printf "%s\\n" "child: Permission denied" >&2; exit 1' }))
await task.done
expect(task.sandbox).toEqual({ mode: 'read-only', denied: true, enforcement: 'partial' })
expect(task.readOutput().delta).toContain(PARTIAL_ENFORCEMENT_NOTICE)
expect(task.readOutput().delta).toContain(NOTICE)
})
it('makes a background fatal line outrank denial text after the notice', async () => {
@@ -179,7 +177,7 @@ describe('partial Landlock runner-failure classification', () => {
runnerFailed: true,
})
const output = task.readOutput().delta
expect(output).toContain(PARTIAL_ENFORCEMENT_NOTICE)
expect(output).toContain(NOTICE)
expect(output).toContain(FATAL)
})
})
+3 -4
View File
@@ -8,9 +8,8 @@
import { spawnSync } from 'node:child_process'
import {
LAUNCHER_FATAL_PREFIX,
LAUNCHER_BIN,
LAUNCHER_FAILURE_EXIT,
PARTIAL_ENFORCEMENT_NOTICE,
launcherPath as landlockLauncherPath,
probe as defaultProbeLandlock,
} from 'node-addon-landlock-run'
@@ -157,8 +156,8 @@ const RUNNER_FAILURE_RULES = {
bwrap: [{ fatalSignatures: ['bwrap: '] }],
landlock: [{
allowedExitCodes: [LAUNCHER_FAILURE_EXIT],
fatalSignatures: [LAUNCHER_FATAL_PREFIX],
informationalLines: [PARTIAL_ENFORCEMENT_NOTICE],
fatalSignatures: [`${LAUNCHER_BIN}: `],
informationalLines: [`${LAUNCHER_BIN}: partial enforcement (older Landlock ABI)`],
}],
seatbelt: [{ fatalSignatures: ['sandbox-exec: '] }],
} as const satisfies Record<SelectedRunner['runner'], readonly RunnerFailureRule[]>
@@ -12,11 +12,7 @@ import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { describe, expect, it, vi } from 'vitest'
import { Context } from 'cordis'
import {
LAUNCHER_FAILURE_EXIT,
LAUNCHER_FATAL_PREFIX,
PARTIAL_ENFORCEMENT_NOTICE,
} from 'node-addon-landlock-run'
import { LAUNCHER_FAILURE_EXIT } from 'node-addon-landlock-run'
import { SANDBOX_UNAVAILABLE, SandboxUnavailableError } from '@deepseek-ai/dsh-sandbox'
import type { SandboxPolicy } from '@deepseek-ai/dsh-sandbox'
import {
@@ -179,8 +175,8 @@ describe('the platform chains', () => {
denialSignatures: ['permission denied'],
runnerFailureRules: [{
allowedExitCodes: [LAUNCHER_FAILURE_EXIT],
fatalSignatures: [LAUNCHER_FATAL_PREFIX],
informationalLines: [PARTIAL_ENFORCEMENT_NOTICE],
fatalSignatures: ['landlock-run: '],
informationalLines: ['landlock-run: partial enforcement (older Landlock ABI)'],
}],
})
expect(probeLandlock).toHaveBeenCalledWith(launcher)
-4
View File
@@ -848,10 +848,6 @@ importers:
'@deepseek-ai/dsh-workspace-context':
specifier: workspace:*
version: link:../packages/context/workspace-context
node-addon-landlock-run:
specifier: 0.0.0-test.0
version: 0.0.0-test.0
packages/acp/acp:
dependencies:
'@agentclientprotocol/sdk':