Skip to content

test: prune and rewrite SDK tests flagged by the current-main audit rerun - #2142

Open
devin-ai-integration[bot] wants to merge 5 commits into
devin/1793236744-remove-gated-git-testsfrom
devin/1794604210-prune-sdk-tests-rerun
Open

devin-ai-integration[bot] wants to merge 5 commits into
devin/1793236744-remove-gated-git-testsfrom
devin/1794604210-prune-sdk-tests-rerun

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fourth PR in the SDK test cleanup stack (#2048 ← #2054 ← #2052 ← this). It applies the high- and medium-confidence findings from rerunning the TDD-skill audit against current main. Low-confidence findings are not included (they stay in SDK-414). Test-only, so there's no changeset.

JS type assertions now actually run. expectTypeOf in commands/run.test.ts / connect.test.ts was never checked: tsconfig only includes src, and vitest typecheck mode was off. A deliberately wrong assertion still passed. Those assertions now live in tests/sandbox/commands/retainOutput.test-d.ts, checked by a new types vitest project (typecheck.only, tsconfig.typecheck.json = src + tests/**/*.test-d.ts). Bun, deno and browser select projects explicitly, so they don't run it. I checked that a wrong assertion now fails with TypeCheckError.

Deleted (duplicate, tests its own fake, or can't fail):

  • JS: paginator throws once exhausted, which asserted an error thrown by the test's own FakePaginator. Also run retains output by default, which passed retainOutput: true explicitly.
  • JS: run with non-array shell. A Set goes through the same !shellOpt[0] branch as [], so the test still passes with Array.isArray removed.
  • JS: send stdin via command handle, a strict subset of close stdin via command handle. Also pause sandbox, a strict prefix of resume sandbox.
  • JS/Py: the snapshot preserves file system state tests, which repeat create sandbox from snapshot.
  • JS/Py: calculateFilesHash … should not read whole files into memory, which only pins fs.readFileSync / open().read(size). In JS it still passed when the code read the whole file.
  • Py: test_throws_for_none_values, which makes the same call as normalize_build_arguments(), and test_handles_name_without_tag, which goes through the same branch as the string-name test.
  • Py: test_get_timeout (sync/async), which only does an isinstance on a typed dataclass field, and test_volume_token_defaults_to_none, which only checks a constructor default.
  • Py: test_chunk_check_records_the_validation_error (internal ChunkCheck.error identity).
  • Py: test_sync_stream_close_reaches_transport_generator, which still passed with _close_stream(inner) removed, because CPython refcounting closes the generator anyway.
  • Py: test_stream_input_sync.py, which only called the internal stream_input_sync helper. The public-seam fake-envd test now also covers pty.stream_input data and the connect-timeout-ms deadline.

Merged: the {} rows of the CPU-option tests (JS boundOpts, Python test_bound_api_params) duplicated the min-free-disk {} row. The JS apiDefaults maxCpuCount tests duplicated the public Template.buildInBackground tests. Both become a single cpuCount-only row.

Rewritten at a public seam:

  • calculateFilesHash multi-chunk test (JS/Py): it used to rebuild the hash with the implementation's own recipe. Now it flips a byte in the last partial chunk and expects the hash to change, then flip back and the hash to be restored.
  • test_commands_connect_applies_request_timeout now uses the real create_rpc_client against an unresponsive HTTP/2 frame server instead of mocking the factory.
  • test_connect_sends_stable_host_routing_headers_to_envd (sync/async) checks the headers envd actually receives on files.read, instead of mocking _cls_connect/_integration and reading sandbox_headers.
  • envdUnresponsiveAtPause is now checked through Sandbox.get_info / Sandbox.list (sync/async) against a local API, instead of the private SandboxInfo._from_* converters.
  • The on_resume instance form calls sandbox.connect(300, "reboot") and expects a TypeError, instead of inspecting the signature.

Link to Devin session: https://app.devin.ai/sessions/98def51a61574e17908881f74f2f7ded
Open in Devin Desktop: https://app.devin.ai/desktop/session/98def51a61574e17908881f74f2f7ded?variant=devin
Requested by: @mishushakov


🟢 Devin Review found nothing to fix · View findings

Devin Review

devin-ai-integration Bot and others added 5 commits November 13, 2026 21:15
…ling

Co-Authored-By: mish@e2b.dev <mish@e2b.dev>
…lic seam

Co-Authored-By: mish@e2b.dev <mish@e2b.dev>
…public seams

Co-Authored-By: mish@e2b.dev <mish@e2b.dev>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@cla-bot cla-bot Bot added the cla-signed label Nov 13, 2026
@changeset-bot

changeset-bot Bot commented Nov 13, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: cb548ce

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions

Copy link
Copy Markdown
Contributor

Package Artifacts

Built from 3d0716a. Download artifacts from this workflow run.

JS SDK (e2b@2.64.1-devin-1794604210-prune-sdk-tests-rerun.0, with @e2b/dockerfile-utils@0.1.3-devin-1794604210-prune-sdk-tests-rerun.0):

npm install ./e2b-dockerfile-utils-0.1.3-devin-1794604210-prune-sdk-tests-rerun.0.tgz ./e2b-2.64.1-devin-1794604210-prune-sdk-tests-rerun.0.tgz

CLI (@e2b/cli@2.24.1-devin-1794604210-prune-sdk-tests-rerun.0):

npm install ./e2b-cli-2.24.1-devin-1794604210-prune-sdk-tests-rerun.0.tgz

Code Interpreter JS SDK (@e2b/code-interpreter@2.9.2-devin-1794604210-prune-sdk-tests-rerun.0):

npm install ./e2b-code-interpreter-2.9.2-devin-1794604210-prune-sdk-tests-rerun.0.tgz

Desktop JS SDK (@e2b/desktop@2.5.1-devin-1794604210-prune-sdk-tests-rerun.0):

npm install ./e2b-desktop-2.5.1-devin-1794604210-prune-sdk-tests-rerun.0.tgz

Python SDK (e2b==2.64.0+devin.1794604210.prune.sdk.tests.rerun, with e2b-dockerfile-utils==0.1.2+devin.1794604210.prune.sdk.tests.rerun):

pip install ./e2b_dockerfile_utils-0.1.2+devin.1794604210.prune.sdk.tests.rerun-py3-none-any.whl ./e2b-2.64.0+devin.1794604210.prune.sdk.tests.rerun-py3-none-any.whl

Code Interpreter Python SDK (e2b-code-interpreter==2.11.10+devin.1794604210.prune.sdk.tests.rerun):

pip install ./e2b_code_interpreter-2.11.10+devin.1794604210.prune.sdk.tests.rerun-py3-none-any.whl

Desktop Python SDK (e2b-desktop==2.7.2+devin.1794604210.prune.sdk.tests.rerun):

pip install ./e2b_desktop-2.7.2+devin.1794604210.prune.sdk.tests.rerun-py3-none-any.whl

@mishushakov
mishushakov marked this pull request as ready for review November 13, 2026 21:16

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TASTE.md review: complies — this test-only PR changes no public SDK surface, and the added tests are consistent with T-3a (keyword-only on_resume), T-25 (non-literal retainOutput overload) and T-34 (paginator draining); 0 violations.

Written by Devin

@mishushakov
mishushakov self-requested a review as a code owner November 13, 2026 21:16
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-13T21:19:37.680759Z cb548ce Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Devin Review

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing blocking. The comments below are optional suggestions. There is no need to push a fix for them before merging.

Comment on lines 584 to +602
test('should hash file content spanning multiple read chunks', async () => {
const content = randomBytes(3 * 1024 * 1024 + 123)
const filePath = join(testDir, 'big.bin')
const hash = () =>
calculateFilesHash('big.bin', '/app', testDir, [], false, undefined)

await writeFile(filePath, content)
const stats = statSync(filePath)

const expected = createHash('sha256')
.update('COPY big.bin /app')
.update('big.bin')
.update(stats.mode.toString())
.update(stats.size.toString())
.update(content)
.digest('hex')

expect(
await calculateFilesHash('big.bin', '/app', testDir, [], false, undefined)
).toBe(expected)
})
const original = await hash()

test('should not read whole files into memory', async () => {
await writeFile(join(testDir, 'big.bin'), randomBytes(2 * 1024 * 1024))
const readFileSync = vi.spyOn(fs, 'readFileSync')
// Flip one byte in the final, partial chunk; same size and mode.
content[content.length - 1] ^= 0xff
await writeFile(filePath, content)
const changed = await hash()

await calculateFilesHash('big.bin', '/app', testDir, [], false, undefined)
content[content.length - 1] ^= 0xff
await writeFile(filePath, content)

expect(readFileSync).not.toHaveBeenCalled()
expect(changed).not.toBe(original)
expect(await hash()).toBe(original)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 (optional) After this change, no test in either SDK pins the template files-hash value. A recipe change that silently invalidates every user's build cache would now pass CI. The new multi-chunk test only checks that flipping the last byte changes the hash. It still passes if earlier chunks are skipped or if hashFileContent hashes the whole buffer instead of subarray(0, bytesRead). Fix: give both SDKs deterministic content spanning more than one 1 MiB chunk and assert one hard-coded hex digest, shared by JS and Python. The Python twin is at test_get_all_files_in_path.py:576-599.

Why this was flagged

The removed tests recomputed the sha256 recipe (COPY line, relative path, mode, size, content) in both getAllFilesInPath.test.ts and test_get_all_files_in_path.py. They pinned the cache key and kept the two SDKs computing the same digest. The replacement test (getAllFilesInPath.test.ts:584-602, test_get_all_files_in_path.py:576-599) uses random content and only compares hashes against each other. Three regressions now pass in both languages: a loop that hashes only the final chunk, a change to field order or encoding, and in JS hash.update(buffer) without subarray(0, bytesRead) at src/template/utils.ts:297. That last one leaks stale bytes from the reused Buffer.allocUnsafe(HASH_CHUNK_SIZE), so small-file hashes become nondeterministic. Grep finds no 64-hex golden digest under either SDK's tests/template, so nothing else catches these. The base branch failed on all of them. A literal golden digest comes from an independent source, so it does not have the tautology problem that the PR set out to remove.

Verification: The diff deletes the only assertions in either SDK that compared the files hash against an independently computed sha256 of the full content. The new test (getAllFilesInPath.test.ts:584-602; test_get_all_files_in_path.py:576-599) uses random content. It flips only content[content.length - 1]. No hex digest or sha256 recomputation remains anywhere.

Comment on lines +145 to +157
def test_pty_stream_input_sends_pty_data_under_the_stream_timeout(
fake_envd_sandbox: Sandbox,
):
fake_envd_sandbox.pty.stream_input(42, ["a", b"b"], timeout=5)

[(path, headers, messages)] = _FakeEnvdHandler.requests
assert path == "/process.Process/StreamInput"
assert headers["connect-timeout-ms"] == "5000"
assert messages[0] == {"start": {"process": {"pid": 42}}}
data = [
base64.b64decode(message["data"]["input"]["pty"]) for message in messages[1:]
]
assert data == [b"a", b"b"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 (optional) Deleting test_stream_input_sync.py leaves no test showing that stream_input rejects a single bytearray chunk, and no offline test of single-chunk rejection at all. The deleted test_rejects_single_chunk was parametrized over "data", b"data" and bytearray(b"data"). Only live-sandbox tests remain, covering bytes (commands) and str (pty). Fix: add an offline single-chunk test on fake_envd_sandbox for commands and pty. It should cover str, bytes and bytearray (and memoryview, which the guard also lists) and assert that no request reaches the fake envd.

Why this was flagged

The guard is at e2b/sandbox/commands/stream_input.py:52: isinstance(data, (str, bytes, bytearray, memoryview)). It raises InvalidArgumentException so that a lone chunk is not streamed byte by byte as ints. Before this PR, tests/test_stream_input_sync.py ran it offline for "data", b"data" and bytearray(b"data"). This PR deletes that file. The only remaining tests are tests/sync/sandbox_sync/commands/test_stream_input.py:37 (b"ls\n") and tests/sync/sandbox_sync/pty/test_stream_input.py:22 ("ls\n"), and both need a live sandbox fixture. A grep for bytearray in the Python tests finds no other stream_input use. The new pty test at lines 145-157 only adds data and deadline coverage. So dropping bytearray from the guard would now pass CI, and an offline run checks no single-chunk path at all. Neither was true on the base branch.

Verification: The PR deletes packages/python-sdk/tests/test_stream_input_sync.py. The guard is at packages/python-sdk/e2b/sandbox/commands/stream_input.py:52. Only two single-chunk tests remain, and both need a live sandbox. No test in packages/python-sdk/tests passes a bytearray (or memoryview) as one chunk, so a future edit that drops bytearray from the guard tuple goes uncaught.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant