mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-09-11 04:00:38 +00:00
fix(code-runtime-python): skip relative PATH entries in pythonBin resolution; pin the sealing-threshold rejection
The review's remaining code items: - resolvePythonBin now skips RELATIVE PATH segments (a bare 'bin' or '.'): the returned candidate must be absolute, because spawn() resolves a relative pythonBin against the host CWD, outside the seam contract. - A deterministic-ish regression pins the sealing-threshold corner: 64 MiB of 4 KiB (<= PIPE_BUF, atomic) newline-free writes plus 12289 more A's before the first newline make the first frame exceed FRAME_PARSE_CAP_BYTES; the newline-bearing chunk reaches the first-frame check (sealing is the ELSE half of the newline branch), so the run reports worker-exit with the protocol-frame-exceeded message.
This commit is contained in:
@@ -4901,4 +4901,37 @@ describe('PythonCodeRuntime — hostile peer', () => {
|
||||
expect(result.logs).toContain('after-cap-frames')
|
||||
}, 120_000)
|
||||
|
||||
it('rejects an oversized first frame that lands on the sealing threshold with a newline', async () => {
|
||||
// The fragment-count seal runs only on newline-free chunks (the ELSE half
|
||||
// of the newline branch), so a chunk that carries the first newline always
|
||||
// reaches the join and its first-frame check. Fail-before: sealing that
|
||||
// chunk into a block would empty pendingChunks, leave sawNewline false,
|
||||
// skip the first-frame check, and join the oversized first frame whole.
|
||||
// Whether the pipe delivers exactly 1024 chunks is timing-dependent, but
|
||||
// the oversized first frame (63.9 MiB of A's + 12288 more before the
|
||||
// newline) exceeds FRAME_PARSE_CAP_BYTES no matter how it arrives.
|
||||
const { runtime } = await setup({ maxWallMs: 60_000, addressSpaceMb: 2048 })
|
||||
const result = await runtime.run({
|
||||
program: [
|
||||
'import os',
|
||||
// 4 KiB writes are <= PIPE_BUF, so each os.write is atomic and the
|
||||
// host sees one chunk per write; 16384 of them accumulate 64 MiB of
|
||||
// newline-free bytes (16 fragment-count seals of 1024 chunks).
|
||||
'chunk = b"A" * 4096',
|
||||
'for _ in range(16384):',
|
||||
' os.write(3, chunk)',
|
||||
// 12289 more A's push the first frame past 64 MiB; drain-loop so the
|
||||
// write cannot truncate, then a newline and a small legitimate frame.
|
||||
"data = b'A' * 12289 + b'\\n' + b'{\"type\":\"log\",\"text\":\"after-seal\"}\\n'",
|
||||
'view = memoryview(data)',
|
||||
'while view:',
|
||||
' view = view[os.write(3, view):]',
|
||||
'return "done"',
|
||||
].join('\n'),
|
||||
bindings: [],
|
||||
})
|
||||
expect(result.error?.kind).toBe('worker-exit')
|
||||
expect(result.error?.message).toContain('protocol frame exceeded')
|
||||
}, 120_000)
|
||||
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user