mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
fix(sandbox): close classifier evidence gaps (round 2)
This commit is contained in:
@@ -52,7 +52,12 @@ export function classifyRunnerFailure(
|
||||
for (const rule of rules) {
|
||||
if (rule.allowedExitCodes !== undefined && !rule.allowedExitCodes.includes(exitCode)) continue
|
||||
const informationalLines = new Set((rule.informationalLines ?? []).map(line => line.toLowerCase()))
|
||||
const fatalSignatures = rule.fatalSignatures.map(signature => signature.toLowerCase())
|
||||
// An empty substring matches every string in JavaScript. Ignore it so a
|
||||
// malformed public rule cannot turn a gated exit status into evidence by
|
||||
// itself; keep any valid signatures beside it active.
|
||||
const fatalSignatures = rule.fatalSignatures
|
||||
.filter(signature => signature.length > 0)
|
||||
.map(signature => signature.toLowerCase())
|
||||
for (const line of lines) {
|
||||
const lowered = line.toLowerCase()
|
||||
if (informationalLines.has(lowered)) continue
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Deterministic composition proof for the partial-Landlock diagnostic: the
|
||||
* real local provider and sandbox bash executor wrap commands through a POSIX
|
||||
* fake launcher that prints the native informational line before exec.
|
||||
* Deterministic real-process proofs for runner classification: the real local
|
||||
* provider and sandbox bash executor exercise an outer-shell launch failure
|
||||
* and a POSIX fake Landlock launcher that prints its notice before exec.
|
||||
*/
|
||||
|
||||
import { mkdtemp, rm, writeFile } from 'node:fs/promises'
|
||||
@@ -64,6 +64,26 @@ async function setup(fatal = false): Promise<SandboxBashExecutor> {
|
||||
}
|
||||
|
||||
describe('partial Landlock runner-failure classification', () => {
|
||||
it.skipIf(process.platform === 'win32')('classifies a genuinely missing configured runner through the outer bash exec rule', async () => {
|
||||
const dir = await mkdtemp(join(tmpdir(), 'dsh-missing-sandbox-runner-'))
|
||||
tempDirs.push(dir)
|
||||
const missingRunner = join(dir, 'missing-runner')
|
||||
const ctx = new Context()
|
||||
contexts.push(ctx)
|
||||
await ctx.plugin(LocalSandboxProvider, {
|
||||
runnerCommand: [missingRunner],
|
||||
runnerFailureSignatures: ['configured-runner: fatal'],
|
||||
})
|
||||
await ctx.plugin(SandboxPolicyService, { mode: 'read-only', workspaceRoot: process.cwd() })
|
||||
await ctx.plugin(LocalSubprocessService)
|
||||
await ctx.plugin(SandboxBashExecutor, { cwd: process.cwd(), timeoutMs: 5_000 })
|
||||
|
||||
const error = await ctx.bash.run(ctx.bash.resolve({ command: 'true' })).catch((value: unknown) => value)
|
||||
expect(error).toMatchObject({ name: 'SandboxUnavailableError', code: SANDBOX_UNAVAILABLE })
|
||||
expect(error).toBeInstanceOf(Error)
|
||||
expect((error as Error).message).toContain(missingRunner)
|
||||
})
|
||||
|
||||
it('keeps true, false, and child exit 125 as child outcomes when the notice is the only runner line', async () => {
|
||||
const bash = await setup()
|
||||
for (const [command, exitCode] of [['true', 0], ['false', 1], ['exit 125', 125]] as const) {
|
||||
|
||||
@@ -234,6 +234,24 @@ describe('classifyDenial', () => {
|
||||
})
|
||||
|
||||
describe('classifyRunnerFailure', () => {
|
||||
it('ignores empty fatal signatures instead of treating exit status or notice text as evidence', () => {
|
||||
const notice = 'landlock-run: partial enforcement (older Landlock ABI)'
|
||||
const emptyRule = [{ allowedExitCodes: [125], fatalSignatures: [''] }]
|
||||
expect(classifyRunnerFailure(125, '', emptyRule)).toBeUndefined()
|
||||
expect(classifyRunnerFailure(125, notice, emptyRule)).toBeUndefined()
|
||||
})
|
||||
|
||||
it('keeps valid fatal signatures active beside an ignored empty entry', () => {
|
||||
const notice = 'landlock-run: partial enforcement (older Landlock ABI)'
|
||||
const fatal = 'landlock-run: ruleset creation failed'
|
||||
const rules = [{
|
||||
allowedExitCodes: [125],
|
||||
fatalSignatures: ['', 'landlock-run: '],
|
||||
informationalLines: [notice],
|
||||
}]
|
||||
expect(classifyRunnerFailure(125, `${notice}\nchild diagnostic\n${fatal}`, rules)).toEqual({ detail: fatal })
|
||||
})
|
||||
|
||||
it('matches an outer-shell rule case-insensitively only at its exit codes and configured argv0', () => {
|
||||
const rules = [{
|
||||
allowedExitCodes: [126, 127],
|
||||
|
||||
Reference in New Issue
Block a user