mirror of
https://github.com/kvcache-ai/AgentENV.git
synced 2026-11-05 01:17:36 +00:00
[PR #28] [CLOSED] feat(template): E2B build-context uploads, COPY/ADD steps, and alias rebuild (full PR — see stacked PRs) #127
Labels
No labels
bug
documentation
enhancement
enhancement
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
kvcache-ai/AgentENV#127
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/kvcache-ai/AgentENV/pull/28
Author: @JoyboyBrian
Created: 7/28/2026
Status: ❌ Closed
Base:
main← Head:feat/e2b-template-build-context📝 Commits (7)
93dd9c9fix(api): return the JSON error envelope for unmatched routes92a4bb8feat(template): E2B build-context uploads, COPY/ADD steps, and alias rebuild2052736docs: unwrap hard-wrapped lines in the E2B template build sectiona9227cbfix(template): harden COPY step semantics and memory usefb24859fix(template): make build-context upload URLs single-useb632852fix(template): address review findings and create WORKDIR directories6f4b6a5fix(template): address round-2 review findings📊 Changes
34 files changed (+4849 additions, -129 deletions)
View changed files
📝
config/default.toml(+24 -0)📝
docs/src/integration/e2b.md(+28 -0)➕
src/api/build_files.rs(+287 -0)📝
src/api/generated/src/apis/templates.rs(+29 -0)📝
src/api/generated/src/models.rs(+158 -0)📝
src/api/generated/src/server/mod.rs(+172 -0)📝
src/api/impls/mod.rs(+4 -0)📝
src/api/impls/template.rs(+95 -0)📝
src/api/impls/template_helpers.rs(+185 -13)📝
src/api/mod.rs(+1 -0)📝
src/api/openapi.yml(+48 -0)📝
src/api/proxy.rs(+30 -1)📝
src/api/server.rs(+3 -2)📝
src/cfg.rs(+223 -0)📝
src/sandbox/backend.rs(+14 -0)📝
src/sandbox/envd.rs(+35 -0)📝
src/sandbox/process.rs(+12 -0)📝
src/snapshot/manager.rs(+8 -0)➕
src/snapshot/repository/backends/oss/build_files.rs(+169 -0)📝
src/snapshot/repository/backends/oss/mod.rs(+1 -0)...and 14 more files
📄 Description
Summary
The stock E2B SDK's template builder could not build Dockerfiles containing
COPY, and could not rebuild an existing alias. This PR closes both gaps soAsyncTemplate.buildworks end to end against AgentENV:COPYthroughGET /templates/{templateID}/files/{hash}; AgentENV had no such route, so the SDK died on a 404 with an empty body. This PR implements the endpoint (201+{present, url}, matching the E2B spec) plus a streamingPUTendpoint the returned URL points at. Archives are stored in the snapshot repository (posix_fsandossbackends), so in multi-node deployments any node can issue the link, accept the upload, and read it back at build time — no gateway or routing changes needed. The SDKPUTs with a bare HTTP client (no auth headers), so the URL carries a bearer grant persisted in the shared repository — the same shape as an object-store presigned URL. Grants are single-use, and stored archives are immutable: a hash addresses its content, so keeping the first archive costs nothing and means no build can observe its context change while it runs. Spent grants and expired archives are pruned opportunistically. A new optional[template_build]config section (all defaults provided) bounds the upload size, the decompressed archive size, and the URL TTL, and can override the public base URL.COPYsemantics — single file, directory contents-into-dest, globs,WORKDIR-relative destinations (including a relativeWORKDIR, which now resolves against the current one), root:root ownership,--chown/--chmod— then streamed into the build sandbox via envd and extracted with a singletar -xpf.--chownis resolved to numeric ids inside the build sandbox, the way Docker resolves names against the image's own/etc/passwd, and written into the rewritten tar headers, so a copy can only ever change the files it creates. The rewrite runs in two passes (index paths, then stream each entry's bytes) so an archive is never held in memory, and rejects archives past the configured decompressed budget. Its mapping logic is a pure function with unit tests;../absolute entry escapes are rejected.400 … cannot rebind. The alias keeps resolving to the previous template while the new build runs, and moves atomically when the new build commits (E2B rebuild semantics). A failed rebuild leaves the old binding untouched; the previous template stays addressable by id. Implemented in both backends, with the alias bind reordered to be the final fallible operation of publish.{"code":404,"message":"…"}instead of an empty body, so future gaps surface as a readable 404 rather than a client-side JSON parse error (separate first commit).Behavior notes
COPY app.py /optwhere/optis an existing directory fails the build with a clear error; write directory destinations with a trailing slash (/opt/), the style E2B's own docs use. Documented indocs/src/integration/e2b.md.COPY --chownapplies only to the files the copy creates, and an unknown user fails the build rather than silently landing as root.COPYrequirestarin the base image (RUNalready requires/bin/bash); documented.filesHashwas considered and rejected: the SDK derives that hash from the COPY arguments plus per-file metadata and content in its own traversal order, not from the archive bytes, so recomputing it server-side would pin the server to SDK internals. Single-use grants and immutable archives close the same window without that coupling.text/plainbody while the generated client expects JSON; the upload path tolerates the decode error after a completed upload (commented inline — the root fix belongs in the envd http-client spec).Testing
make fmt,cargo clippy --workspace --all-targets --all-features -- -D warnings, and theagentenv/envd/linux-capunit suites. New unit tests cover the Docker COPY plan semantics (gzip, globs, ownership, path escapes, the decompressed budget), the build-file stores, single-use upload grants and their pruning, archive immutability, and alias rebind behavior in create/publish.from_image,from_dockerfilewithout COPY,from_dockerfilewith COPY, alias rebuild, cold sandboxes, and the full exec/files runtime suite all pass. Separately verified in a booted sandbox thatCOPY --chownleaves pre-existing files under the destination untouched, that a relativeWORKDIRresolves against the previous one, that an upload URL is rejected on replay, and that a stored archive keeps its original bytes across a repeat upload on both nodes.make agentenv-server.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.