Proto commits in e2b-dev/infra

These commits are when the Protocol Buffers files have changed: (only the last 100 relevant commits are shown)

Commit:51e7be0
Author:Mish Ushakov

feat: derive filesystem-only snapshot from memory checkpoint Rework the memory:false snapshot flow so the source sandbox keeps its memory: the checkpoint takes a full memory snapshot (build A, the sandbox's own snapshot row) after a guest sync quiesce, derives a filesystem-only sibling build (B) whose rootfs header references A's data without duplicating it, memory-resumes the sandbox from A as a normal checkpoint, and returns B as the snapshot template. Sandboxes created from B cold-boot from the captured filesystem. The sibling upload is header+metadata only and runs after A's upload (its ancestor wait requires A's finalized header). Quiesce uses guest sync rather than fsfreeze: RAM captured with a frozen filesystem would memory-resume frozen and wedge all writes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Commit:4ef8048
Author:Mish Ushakov
Committer:Mish Ushakov

feat(envd): kill tree on request timeout when started with child_processes Address PR review (timeout killed leader only): add a child_processes field to StartRequest so a command started with it also tears down its whole process group when a request timeout fires, keeping the timeout path consistent with an opted-in SendSignal. Non-opted-in commands and PTY processes keep the original leader-only behavior. Regenerated the process protos and added a timeout regression test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Commit:bc47f29
Author:Mish Ushakov
Committer:GitHub

Merge branch 'main' into mishushakov/envd-kill-process-tree

Commit:9269abd
Author:Mish Ushakov

feat(envd): make process-tree kill opt-in via child_processes flag Add a child_processes field to SendSignalRequest. When set, the signal is delivered to the command's whole process group (leader + children); otherwise only the leader is signaled, preserving the original behavior. Non-PTY commands still always start in their own process group so the opt-in kill can reach the tree, but the timeout-driven kill is left as leader-only. Regenerated the process protos and added a test covering the leader-only default. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Commit:282de08
Author:Mish Ushakov

feat: filesystem-only variant of sandbox snapshot endpoint (memory: false) Add a memory flag to POST /sandboxes/{sandboxID}/snapshots. When false, the snapshot template persists only the rootfs: sandboxes created from it cold-boot, and the source sandbox is rebooted in place (checkpoint cannot memory-resume without a memory snapshot) while keeping its identity and end time. Wired through SandboxCheckpointRequest.filesystem_only; the orchestrator branches to RebootSandbox and skips memory-prefetch work. Also tag linux-only files in cmd/create-build, cmd/resume-build, cmd/inspect-build, and pkg/server/prefetch_harvest.go with //go:build linux so make lint passes on macOS. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Commit:f76b2cb
Author:Jakub Novák
Committer:GitHub

feat: per-team events TTL limit (tier + addons) (#3181) Allow customization for teams to extend ttl for events

Commit:7735bae
Author:Jakub Novák
Committer:GitHub

feat(orchestrator): report hugepage metrics to API (#3182) Expose HugePages_Total/Used/Rsvd and hugepage size from /proc/meminfo via ServiceInfo gRPC and NodeMetrics on the admin /nodes endpoints. Page counts, not bytes, to match kernel accounting.

Commit:4c0f658
Author:Jakub Novak

chore: clean up

Commit:ebfba1c
Author:Jakub Novak

feat: per-team events TTL limit (tier + addons) Add events_ttl_days to tiers with extra_events_ttl_days addon column, summed into the team_limits view. The limit flows through team limits into SandboxConfig (proto field 26) so the orchestrator stamps it on every published sandbox event; the events store TTL was switched to read it in a previous change. Dashboard exposes the limit and uses it for the sandbox record retention-expired check instead of a hardcoded 7 days.

Commit:0cf3173
Author:ValentaTomas

refactor: keep layer-size categories whole - DB carries only logical sizes Move the rootfs mapped/diff sizes out of the gRPC/DB path so each size category lives in one place: logical sizes go via gRPC into env_builds (memfile logical; rootfs logical is already total_disk_size_mb), while mapped and diff sizes for both artifacts are written to the data objects' metadata (see the memfile-layer -metadata PR). Drops the rootfs_*_size_bytes columns and the now-unused Mapping.MappedBytes helper.

Commit:a131641
Author:ValentaTomas

feat: persist synchronously-available layer sizes to env_builds via gRPC Replace the object-metadata approach with returning per-artifact layer sizes over gRPC (pause/checkpoint responses and TemplateBuildMetadata) and persisting them on the env_builds row. Only sizes available without blocking on the async memfile dedup header are included: rootfs mapped/diff and memfile logical (rootfs logical is already stored as total_disk_size_mb). The async memfile mapped/diff sizes are handled separately.

Commit:ef856b2
Author:Tomas Valenta

storage-api: drop stale "block size" from ingest RPC comment No block_size field exists on the proto; align the comment.

Commit:5320d56
Author:Tomas Valenta

orchestrator: index builds into storage-api after headers are ready Best-effort, feature-flagged (storage-api-ingest-build); no-op when unconfigured.

Commit:a7c8320
Author:Weilu Jia
Committer:Weilu Jia

feat(orchestrator): force-stop sandboxes and bound shutdown drain Escalate shutdown from graceful drain to a bounded force stop. Add SHUTDOWN_DRAIN_TIMEOUT to cap the graceful phase; on expiry (or when force-stop is requested) the orchestrator force-closes live sandboxes and cancels in-flight template builds, detaching cleanup from the canceled shutdown context while preserving its deadline. Introduce the drain-gate state both servers shut down through: the sandbox server's start gate and the template server's build gate, with StartDraining replacing the old done channel and the drain paths waiting for admitted in-flight starts to finish before snapshotting the live set. New work is still admitted here; rejecting it is layered in separately. Plumb a force_stop flag from the node status API through gRPC so an operator can drain-and-force a node, make ServiceInfo status transitions atomic so a drain override cannot race back to healthy and drain cannot be reversed, and run drains as managed services with deterministic exit reporting. Cleanup rollbacks now preserve deadlines via RunRollback.

Commit:ecd13b0
Author:Babis Chalios
Committer:GitHub

Filesystem-only snapshots for auto-pause (#3055) Summary Adds a per-sandbox autoPauseMemory create option (default true). When false, a sandbox that auto-pauses on timeout takes a filesystem-only snapshot (no memory) instead of a full memory snapshot, so it cold-boots from disk on resume. Builds on the filesystem-only snapshot machinery from #3027 — this PR just lets the timeout auto-pause path opt into it, where previously only an explicit pause(memory=false) could. How it works The FilesystemOnly flag was already plumbed end-to-end through the pause path (RemoveOpts → pauseSandbox → snapshot → Pause RPC); the only missing piece was a per-sandbox policy for the evictor to act on. 1. Create — autoPauseMemory=false → Sandbox.AutoPauseFilesystemOnly=true (runtime state, persisted to Redis). 2. Evict — when the evictor auto-pauses on timeout, it threads opts.FilesystemOnly = sbx.AutoPauseFilesystemOnly. 3. Persist — the policy is stamped onto the snapshot's PausedSandboxConfig, and... 4. Restore — re-read on resume (covers explicit /resume, /connect, and auto-resume — they share buildResumeSandboxData), so the policy survives a pause/resume cycle. 5. Re-sync — also carried through SandboxConfig.auto_pause_filesystem_only in the orchestrator proto, mirroring auto_pause, so an API restart that rebuilds from the orchestrator's sandbox list doesn't lose it. The orchestrator is unchanged — the existing IsFilesystemOnly() dispatch already routes any resume of an fs-only snapshot to RebootSandbox. Constraints (rejected at create, 400) - autoPauseMemory=false requires autoPause=true (it only governs the timeout auto-pause; otherwise a no-op). - autoPauseMemory=false is incompatible with autoResume — a filesystem-only snapshot can't be auto-resumed by arbitrary traffic (it'd cold-boot, losing processes/connections) and must be resumed explicitly. Design notes - Two distinct fields. AutoPauseFilesystemOnly (the policy for the next auto-pause) is kept separate from FilesystemOnly (the kind of this snapshot), so an explicit pause(memory=true) on such a sandbox produces a memory snapshot yet still restores the fs-only policy on the next cycle. - Resume inherits the policy. Unlike auto_pause (overridable via the resume body, now deprecated), the auto-pause kind is always inherited from the snapshot — changing it means creating a new sandbox. Deliberate, to avoid extending a deprecated path. - Backward-compatible: default true, omitempty on both the JSON config and the proto, so existing sandboxes/snapshots decode to memory auto-pause. Testing - Unit — evictor wiring (kill/pause × snapshot kind); PausedSandboxConfig serialization round-trip + legacy-row default; proto re-sync round-trip via GetSandboxes. - Integration — create → timeout auto-pause → resume cold-boots (rootfs marker survives, fresh boot id, correct default user), and the policy persists across a second pause/resume cycle; both create-time guards return 400. Usage ``` # auto-pause this sandbox as a filesystem-only snapshot on timeout POST /sandboxes { "templateID": "...", "autoPause": true, "autoPauseMemory": false } ``` --------- Signed-off-by: Babis Chalios <babis.chalios@e2b.dev> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

Commit:ce556e8
Author:Weilu Jia
Committer:Weilu Jia

fix(orchestrator): honor drain status overrides Make ServiceInfo status transitions atomic via TransitionStatus so a drain override cannot race a transition back to healthy, reject drain reversal, and guard ForceStop with sync.Once. Plumb a forceStop flag from the API through the node status change so draining can force stop sandboxes and template builds.

Commit:7b45c54
Author:Babis Chalios
Committer:Babis Chalios

feat(api): support filesystem-only snapshots for auto-pause Timeout auto-pause always took a full memory snapshot. Add a per-sandbox autoPauseMemory option (default true) so a timeout auto-pause can instead take a filesystem-only snapshot (no memory; cold-boots on resume), reusing the existing FilesystemOnly pause path. The evictor reads the policy off the sandbox and threads FilesystemOnly into the pause. The policy is persisted on the snapshot (PausedSandboxConfig) and carried through the orchestrator SandboxConfig (auto_pause_filesystem_only) so it survives a pause/resume cycle and an API re-sync from the orchestrator's sandbox list — mirroring how auto_pause itself is handled. Reject autoPauseMemory=false combined with autoResume: a filesystem-only snapshot cannot be auto-resumed by traffic and must be resumed explicitly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Babis Chalios <babis.chalios@e2b.dev>

Commit:f79be77
Author:Jakub Novák
Committer:GitHub

feat(orchestrator): track and report last status change timestamp (#2980) Add service_status_changed_at to ServiceInfoResponse so the API can see when the orchestrator's status last changed. The timestamp is updated on actual status transitions and initialized to the service startup time. --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

Commit:c09d96a
Author:Babis Chalios
Committer:GitHub

Filesystem-only snapshots: control plane wiring (#3027) ## Summary Adds filesystem-only snapshots: pause can persist only the rootfs (no memory snapshot), and resuming such a snapshot cold-boots (reboots) the guest from disk instead of restoring memory. Useful when in-memory state isn't worth persisting — cheaper, faster pauses. ## What's included ### Resume side - Server.Create dispatches reboot-vs-resume from the snapshot's own metadata.json (IsFilesystemOnly()); a safety gate in reboot.go refuses to cold-boot a memory snapshot. ### Control plane - filesystem_only on the pause gRPC → threaded through the API pause path → persisted in PausedSandboxConfig. - Public trigger: optional memory: bool (default true) on POST /sandboxes/{id}/pause; memory:false requests a filesystem-only snapshot. - Gating (a disk-only resume cold-boots, losing in-memory state, so implicit resumes are refused): - auto-resume → FailedPrecondition (request must resume explicitly) - /connect → 409 - explicit /resume is allowed and performs the reboot. Existing pause callers are unaffected: no body / memory unset = full memory snapshot. ## Tests Five integration tests, one per behavior: - <s>/connect refused (409) on a filesystem-only snapshot</s> - proxy traffic does not auto-resume a filesystem-only snapshot - explicit resume cold-boots: rootfs marker survives, boot_id changes - secure sandbox keeps working envd auth across the reboot (MMDS token path) - build-installed CA is in the live trust store after the reboot (boot-time half of #3025's cert validation) Validation The integration tests above are the validation gates; they require the Firecracker integration runner to actually execute (compile/vet/lint verified locally). They must pass in CI before merge. --------- Signed-off-by: Babis Chalios <babis.chalios@e2b.dev> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: ValentaTomas <49156497+ValentaTomas@users.noreply.github.com>

Commit:79fa9d7
Author:Babis Chalios
Committer:Babis Chalios

feat(orchestrator): add filesystem_only to the pause RPC Adds SandboxPauseRequest.filesystem_only so a caller can request a filesystem-only pause over gRPC. Server.Pause threads it to sandbox.WithFilesystemSnapshot, which (via PR-A1) stamps the snapshot's metadata so resume cold-boots from the rootfs. Default false = full memory snapshot, so existing pause callers are unaffected; Checkpoint always passes false (filesystem-only checkpoint is not supported yet). The public memory:false API surface and DB persistence land next in this PR. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Babis Chalios <babis.chalios@e2b.dev>

Commit:ba8604e
Author:Tomas Valenta
Committer:GitHub

feat(storage): stamp provenance custom metadata on uploaded objects (incl. headers) (#3033) Attach immutable `team_id`, `template_id`, and `origin` (`pause`/`template_build`/`snapshot_template`) as custom object metadata on every uploaded object, including header objects (which previously carried no custom metadata at all). This lets the storage index attribute ownership/usage and classify root kinds from the object it already downloads, without the infra DB. Lineage stays in the header (`base_build_id` + reference edges); mutable, DB-owned state is deliberately excluded. --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

Commit:d5c56aa
Author:Weilu Jia
Committer:Weilu Jia

fix(orchestrator): honor drain status overrides Make ServiceInfo status transitions atomic via TransitionStatus so a drain override cannot race a concurrent transition back to healthy, reject drain reversal (including via an Unhealthy detour), guard ForceStop with sync.Once while preserving drain-to-force-stop escalation, and plumb a forceStop flag from the API through the node status change so draining can force stop sandboxes and template builds.

Commit:9799dd0
Author:Mish Ushakov
Committer:GitHub

feat(envd): allow opting into watching network mounts (#2982) ## Summary - Adds an `allow_network_mounts` field to `WatchDirRequest` and `CreateWatcherRequest` so clients can explicitly opt into watching paths on network filesystem mounts (NFS, CIFS, SMB, FUSE), which are rejected by default since #1810. - The streaming (`WatchDir`) and non-streaming (`CreateWatcher`) handlers skip the network-mount rejection when the flag is set; default behavior is unchanged. - Regenerates the filesystem proto code in envd and shared, and bumps envd to 0.6.4. ## Test Plan - Added `TestCreateWatcherOnNetworkMount` (bindfs FUSE mount, Linux-only) verifying the watcher is rejected without the flag and created with it; existing filesystem watch tests pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

Commit:a0660de
Author:Jakub Novak
Committer:Jakub Novak

feat(orchestrator): track and report last status change timestamp Add service_status_changed_at to ServiceInfoResponse so the API can see when the orchestrator's status last changed. The timestamp is updated on actual status transitions and initialized to the service startup time.

Commit:1fc3820
Author:Petr Vaněk
Committer:GitHub

feat(api): SOCKS5 egress proxy on sandbox network config (BYOP) (#2642) Sandboxes have two related egress problems we cannot solve from our side: operators want a predictable egress identity (their public IP, not ours), and they want sandboxes to reach hosts that are reachable from their own proxy server — corporate networks, VPN endpoints, internal LAN. This PR adds Bring-Your-Own-Proxy: an optional `egressProxy: {address, username, password}` on the sandbox network config tunnels all sandbox TCP egress through a user-supplied SOCKS5 server, with our allow/deny rules still applied before the tunnel. Scope here is the API + orchestrator plumbing: OpenAPI, DB types, proto, the API create/get handlers (password omitted from GET), the `BYOPProxyEnabledFlag` LD gate, and a validator that rejects a SOCKS5 endpoint pointing at our own infra at create time and re-checks on every dial (DNS-rebind guard). For BYOP-enabled sandboxes only, the sandbox-netns kernel firewall is narrowed on demand so TCP destined for the user's internal networks reaches the userspace egress proxy instead of being dropped — without this the user's LAN destinations would never make it past the kernel. Non-BYOP sandboxes keep the existing hard kernel drop. --------- Co-authored-by: Jakub Novák <jakub@e2b.dev>

Commit:bbbc7c8
Author:Mish Ushakov
Committer:GitHub

feat(envd): add optional EntryInfo to watch FilesystemEvent (#2930) Adds an `include_entryinfo` flag to `WatchDirRequest` and `CreateWatcherRequest`; when set, each `FilesystemEvent` carries the affected entry's `EntryInfo` (new `optional EntryInfo entry` field). The entry is populated best-effort and left `nil` for remove/rename-away events where the path no longer exists, so the watch stream/watcher is never torn down by a stat of a gone file. Both the streaming `WatchDir` and the polling `CreateWatcher`/`GetWatcherEvents` paths are supported, with regenerated proto code in `packages/envd` and `packages/shared`. Bumps the envd version to `0.6.2` and adds `watch_test.go` covering entry-present, entry-absent, and removed-entry cases. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

Commit:da8fbe4
Author:Mish Ushakov
Committer:GitHub

feat(envd): support user-defined file metadata via xattrs (#2732) ## Summary - Adds optional user-defined file metadata to `POST /files`. Any request header of the form `X-Metadata-<key>: <value>` is persisted as an extended attribute (xattr) on the uploaded file. The `X-Metadata-` prefix is stripped and the remaining header name is lowercased to form the key. Multiple files in one multipart upload receive the same metadata. - Surfaces that metadata on every `EntryInfo`: the HTTP upload response, and the filesystem gRPC service (`Stat`, `ListDir`, `Move`, `MakeDir`, etc.) via a new `map<string, string> metadata` proto field (field 11). The wiring is centralized in `filesystem.GetEntryInfo`, so all callers pick it up. - xattrs are stored under the `user.e2b.` namespace — `user.` is required by the Linux VFS for unprivileged xattrs, and `e2b.` namespaces our keys so they don't collide with other tooling writing to `user.*`. Foreign `user.*` xattrs are filtered out and not surfaced. - Replace-on-upload semantics: each upload rewrites the file's full metadata set. Keys present from a prior upload but absent from the new request are removed, and an upload with no `X-Metadata-*` headers clears all existing metadata (`O_TRUNC` preserves xattrs, so we always rewrite). - Validation: keys and values must be printable US-ASCII (`0x20`–`0x7E`), else HTTP 400. Keys are capped at 246 bytes (255-byte VFS xattr-name limit minus the `user.e2b.` prefix); values at 1024 bytes. - Error handling on write: xattr-unsupported filesystems (e.g. `/proc`, `/sys`) are best-effort — the body is persisted and we log a warning rather than fail; `ENOSPC`/`EDQUOT` map to HTTP 507. The response `EntryInfo` reads xattrs back from disk, so it never falsely claims metadata was persisted. ## Implementation - xattr read/write/validate helpers live in a single cross-platform `packages/shared/pkg/filesystem/xattr.go`, backed by the [`github.com/pkg/xattr`](https://github.com/pkg/xattr) library rather than hand-rolled syscalls. The library handles the size-probe/retry and name parsing that previously lived in our own `xattr_linux.go`. - `ReadMetadata`/`WriteMetadata` carry the e2b-specific policy on top of the library: `user.e2b.` namespacing, full-set replace semantics, and `ValidateMetadata`. `IsXattrUnsupported` is exported so `upload.go` can treat xattr-less filesystems as best-effort without duplicating the errno check. - No platform shims needed — `pkg/xattr` is cross-platform, so the metadata tests run on Linux and macOS alike (only `extractStatTimes` keeps a `linux`/`darwin` split, for `Stat_t` field differences). - Bumps envd version to `0.5.28` and the OpenAPI spec to `0.1.3`. ## Test plan - [x] `make lint` clean for envd and shared - [x] `go test ./...` passes for `packages/envd` and `packages/shared/pkg/filesystem` (metadata tests now run on macOS too) - [ ] Upload a file with `-H 'X-Metadata-author: mish' -H 'X-Metadata-purpose: upload'` and confirm `Stat` returns the same map - [ ] Confirm xattrs land under `user.e2b.*` via `getfattr -d <path>` inside a sandbox - [ ] Re-upload the same path with different headers and confirm prior keys are cleared 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> Co-authored-by: Jakub Novak <jakub@e2b.dev>

Commit:a87e341
Author:Mish Ushakov

refactor: split sandbox logs LogQL query filter into its own PR Move the /v2/sandboxes/{sandboxID}/logs `query` field and its supporting provider/resources/edge changes out to a separate PR (#2963). This branch now contains only the envd command-output persistence: stdout/stderr is written to the log pipeline (stamped with pid, capped per command). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Commit:b632744
Author:Mish Ushakov

Merge remote-tracking branch 'origin/main' into mishushakov/command-logs-method # Conflicts: # packages/api/internal/api/api.gen.go

Commit:28467c0
Author:Mish Ushakov

refactor(api): identify command logs by pid + time window instead of cid Drop the envd-assigned cid (and its proto changes); commands are already identified by the pid returned in StartEvent. Output lines are now stamped with pid, and the retrieval endpoint becomes GET /v2/sandboxes/{sandboxID}/commands/{pid}/logs with start/end query params. The time window disambiguates a reused pid: within [start, end] a pid maps to a single command execution. Filter stays scoped to event_type=process_output. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Commit:3e35a2a
Author:Tomas Valenta
Committer:GitHub

fix(orch): split scheduling base build id per artifact (#2920) Memfile and rootfs can have different base builds, so the single `base_build_id` in `SchedulingMetadata` was lossy. Replace it with `memfile_base_build_id` and `rootfs_base_build_id`, each pinned into its own artifact build list. Made with [Cursor](https://cursor.com) Co-authored-by: Cursor <cursoragent@cursor.com>

Commit:2fb00a0
Author:Mish Ushakov

feat(envd): persist command output and add per-command log retrieval Commands started via envd now get a unique cid that is returned in the StartEvent and stamped on every stdout/stderr log line, so their output is persisted through the existing Loki pipeline and capped per command. Adds GET /v2/sandboxes/{sandboxID}/commands/{cid}/logs to retrieve a single command's output, with the cid filter threaded through the local Loki query and the remote edge contract. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Commit:b48f213
Author:Tomas Valenta
Committer:GitHub

Expose internal scheduling metadata (#2873) Expose compact scheduling metadata from orchestrator and template-manager without DB or public API changes. --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

Commit:e45418f
Author:Rauf Guliyev
Committer:GitHub

feat(observability): add kill_reason to sandbox.lifecycle.killed (#2833) Sandbox terminations were unattributed at the event/metric layer, leaving only `"SandboxError: 2: [unknown] terminated"` as a signal. Adds a `KillReason` on `RemoveOpts` and an optional `kill_reason` field on SandboxDeleteRequest; Server.Delete writes it to `event_data.kill_reason` (consumed by the existing webhook and ClickHouse delivery, no schema change) and increments `orchestrator.sandbox.killed` labeled by reason. Reasons: `request`, `timeout`, `admin`, `orphaned`, `base_template_missing`. Kills that reach Server.Delete without a specific reason fall through as `unknown`. --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

Commit:c594f68
Author:Jakub Dobry
Committer:Jakub Dobry

fix(orchestrator): preserve checkpoint state

Commit:e5bbf42
Author:Matt Brockman

Merge origin/main into feat/traffic-keepalive

Commit:afd3e65
Author:Lev Brouk
Committer:Lev Brouk

fix(orch): P2P reader race on peer→storage transition When a peer signaled UseStorage to indicate its upload finished, the current reader saw `uploaded=true` and routed to base storage, but concurrent sibling reads on the same File could fall through with a stale FrameTable — V4 chunk offsets shift between the pre-finalize in-memory header and the post-finalize GCS header, so reads decoded the wrong bytes. The peer now ships the final V4 header inline on its UseStorage response (new `header_bytes` field on `PeerAvailability`). The bytes are the same `[]byte` produced once by `header.StoreHeader` during upload — captured on `*Upload` and forwarded into the server's `uploadedBuilds` cache, no second serialization, no failure path. Client side, the resolver's per-buildID state holds the parsed header. `build.File.installPendingHeader` polls the state at the top of every Slice/ReadAt iteration and CAS-installs the new header atomically. Concurrent readers either install the same value or observe it already installed — no coordination primitive needed, no GCS poll. Also: mid-stream peer abort (NotAvailable from cache eviction) now surfaces as `storage.ErrPeerAborted` so the chunker reopens via base on a single retry, instead of silently truncating the stream.

Commit:6d217f9
Author:Lev
Committer:GitHub

fix(peerclient): resolve base path per-call from live FrameTable (#2585) After a peer→storage transition, peerSeekable kept opening base against the original (uncompressed) path captured at construction. With the recent compression work, post-transition reads now target a compressed object, so the cached base resolved to a non-existent path. P2P routing produced the stale binding (it captured a path while the build was still uncompressed); it also contains the fix. peerSeekable now holds (buildID, basic name, base provider, objType) and composes the actual storage path at base-open time using the CompressionType from the live FrameTable. The base seekable is reopened on ct change. No changes outside peerclient.

Commit:fe2bbe2
Author:Matt Brockman

Merge remote-tracking branch 'origin/main' into feat/traffic-keepalive

Commit:66bcdba
Author:Matt Brockman

Persist keepalive policy in orchestrator config

Commit:08810db
Author:Lev
Committer:GitHub

feature: Compression for memfile/rootfs assets (#2034) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Jakub Dobry <jakub.dobry8@gmail.com>

Commit:c840405
Author:Matt Brockman

Merge branch 'main' into feat/traffic-keepalive # Conflicts: # packages/api/internal/api/api.gen.go # packages/client-proxy/internal/proxy/proxy.go

Commit:758e726
Author:George (Jiri Sveceny)
Committer:GitHub

Api for setting up domain transform (#2515) Support for setting injection headers. Sandbox creation and network update are supported. Configuration is stored in the database to support the sandbox resume flow. --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

Commit:c3f08c7
Author:Matt Brockman

Merge remote-tracking branch 'origin/main' into feat/traffic-keepalive # Conflicts: # packages/api/internal/api/api.gen.go

Commit:c51de22
Author:Matt Brockman

keepalive only via redis

Commit:4f23815
Author:Jakub Novák
Committer:GitHub

fix(orch): resolve firecracker version via feature flag in template builder (#2484) * fix(orch): resolve firecracker version via feature flag in template build path The template build path took the API-supplied firecracker version verbatim, while the sandbox create path (pkg/server/sandboxes.go:161) already routed it through featureflags.ResolveFirecrackerVersion. Orchestrators that lag behind the API's preferred FC binary would fail builds because the binary did not exist on disk. Resolve the version inside Builder.Build right after the LD context is set up, mirroring the sandbox path. Also leaves TODOs at the two API call sites to stop sending the version entirely in a follow-up. * feat(template-manager): return kernel and firecracker versions in build metadata Kernel and firecracker versions in TemplateConfig are deprecated on the wire: the template-manager now selects its own versions (falling back to DefaultKernelVersion and the BuildFirecrackerVersion feature flag when the API leaves them empty, then running them through ResolveFirecrackerVersion) and reports the versions it actually used back via TemplateBuildMetadata. The API still seeds kernel_version and firecracker_version on the env_builds row at registration time for backwards compatibility with consumers that read the record before the build completes. Once FinishTemplateBuild runs, it overwrites the row with whatever the template-manager reported. A COALESCE(NULLIF(..., ''), column) fallback in the SQL keeps the seeded values intact when talking to an older template-manager that does not populate the new fields. * chore: clean up * fix(api): format Deprecated notices in dedicated paragraphs (gocritic) * fix(orch): recompute HugePages in Builder.Build from the resolved FC version The API still computes HugePages from its own BuildFirecrackerVersion evaluation and sends it to the template-manager over gRPC. The API and the orchestrator evaluate the feature flag under different LaunchDarkly contexts (API: team/user/tier/cluster; orchestrator: template/team), and the resolutions happen at different times, so the two sides can legitimately disagree on the firecracker version. HasHugePages() flips at v1.7, and a cross-1.7 divergence configures the VM's memfile page size (2 MiB vs 4 KiB) for a firecracker binary the orchestrator is not actually going to launch — corrupting the memory file. Move the firecracker version parsing helper to packages/shared/pkg/fcversion so both services share a single implementation, and have Builder.Build override cfg.HugePages right after it has resolved the firecracker version it will actually use. The API keeps computing HugePages for backwards compatibility with older orchestrators; new orchestrators treat the wire value as a hint and always recompute locally. * chore: auto-commit generated changes * refactor(orch): resolve kernel/FC version and HugePages in the gRPC handler Builder.Build was unconditionally rewriting cfg.KernelVersion, cfg.FirecrackerVersion and cfg.HugePages on every call. That was fine for the gRPC path where those fields come from a deprecated proto message and are effectively unset, but it silently clobbered in-process callers: packages/orchestrator/cmd/create-build/main.go passes explicit -kernel and -firecracker CLI flags, and packages/orchestrator/cmd/smoketest iterates FirecrackerVersionMap and hands each version to Builder.Build directly. Move the resolution to the gRPC handler in packages/orchestrator/pkg/template/server/create_template.go: - ServerStore now holds the featureflags client. - TemplateCreate sets up the LaunchDarkly template+team context, reads the BuildFirecrackerVersion flag, derives HugePages from the resolved firecracker semver (fcversion.New + HasHugePages), and passes all three into the TemplateConfig it hands to Builder.Build. - Builder.Build itself no longer mutates these fields; it trusts what the caller passed. The LD context it adds remains (for any downstream flag reads from the builder) and is override-safe when the handler already added the same keys. Also mark TemplateConfig.hugePages as [deprecated = true] on the wire, mirroring the existing kernel/firecracker deprecations. HugePages is derived from the firecracker version and the orchestrator now computes it locally, so senders should leave it at the zero value. * chore: clean up * chore: clean up * chore: clean up * chore: add reference to linear task --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

Commit:8398fcb
Author:Lev Brouk
Committer:Lev Brouk

PR feedback: switch to PATCH and carry live metadata on RunningSandbox - PUT → PATCH /sandboxes/{id}/metadata with merge semantics (k=v upserts, k=null or "" removes, absent keys untouched). Addresses ValentaTomas's concern that full-replace would force clients to round-trip existing tags to avoid wiping them. - Keep APIStoredConfig write-once (it was already deprecated and never mutated elsewhere). Add a metadata field to RunningSandbox so List ships the live sbx.GetAPIMetadata() instead of the create-time snapshot; the API-side nodemanager now reads from there. Checkpoint overrides the resumed sandbox's metadata with the live value after ResumeSandbox seeds from the stale proto. Fixes the claude[bot]/codex P1 about PATCH values reverting on resume and being invisible to List reconciles.

Commit:20eaa6e
Author:Lev Brouk
Committer:Lev Brouk

feat(api): add PUT /sandboxes/{id}/metadata Replace metadata on a running sandbox. Full-replace semantics — keys absent from the body are removed. `null` and `{}` both clear the map. Paused sandboxes and merge semantics deferred. Wire-up: gRPC SandboxUpdateRequest gains an optional SandboxMetadataUpdate wrapper so proto3 can distinguish "don't touch" from "clear" (bare map<string,string> cannot).

Commit:7f466bd
Author:Matt Brockman

Refresh sandboxes from proxy traffic

Commit:ff454b7
Author:Matt Brockman

Add traffic keepalive lifecycle config

Commit:ef4c168
Author:Joe Lombrozo

more progress!

Commit:01e28f6
Author:djeebot

feat: persist volume path to database and pass through gRPC Adds volume_path persistence throughout the stack so the orchestrator no longer needs to recompute filesystem paths for volumes. Changes: - DB: add nullable volume_path column to volumes table - Proto: add optional volume_path to VolumeInfo, SandboxVolumeMount, and CreateVolumeResponse - Orchestrator: CreateVolume returns the computed path; getVolumeRootPath and getFilesystemAndPath use persisted path when available, falling back to BuildVolumePath for existing volumes without a path - NFS handler: same fallback pattern for chroot resolution - API: store orchestrator-returned path in DB after creation, include in JWT (volpath claim), pass through to sandbox mounts and resume - Types: add VolumePath to SandboxVolumeMountConfig for snapshot persistence Fully backwards-compatible: existing volumes without volume_path continue to work via the legacy path computation.

Commit:35ae165
Author:Lev Brouk

Merge remote-tracking branch 'e2b/main' into lev-ingress-control

Commit:0b0e1db
Author:Matt Brockman
Committer:GitHub

Autoresume timeout persisted on resume (#1969) * autoresume: persist and clamp timeout on resume to min 5 minutes

Commit:80eea09
Author:Lev Brouk

Merge branch 'main' of github.com:e2b-dev/infra into lev-ingress-control

Commit:3c2f7d9
Author:Joe Lombrozo
Committer:GitHub

Simplify delete file|dir to just delete path (#2181)

Commit:547cbb7
Author:Lev Brouk

Merge branch 'main' of github.com:e2b-dev/infra into lev-ingress-control

Commit:260cd55
Author:Lev Brouk

Unify egress/ingress proto format to repeated string CIDRs Delete IngressRule proto message; ingress now uses repeated string allowed_cidrs/denied_cidrs in CIDR[:port[-port]] format, matching egress. Merge parseEgressRules and parseIngressRules into a single ParseValidRules in sandbox-network. Strings pass through from API to orchestrator without intermediate conversion. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Commit:dbafa25
Author:Joe Lombrozo
Committer:GitHub

use chroot/umount/pivotroot instead of jailing (#2091) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>

Commit:78d19ba
Author:Lev Brouk

Merge branch 'main' of github.com:e2b-dev/infra into lev-ingress-control

Commit:4e70f8e
Author:Jakub Novák
Committer:GitHub

feat(orch): add ScallignDown status (#2146) * feat(orch): add ScallignDown status * chore: add description * chore: auto-commit generated changes * chore: fix TOCTOU race * chore: regenerate spec * chore: rename scalling down to standy --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

Commit:caaf9ca
Author:Lev Brouk

feat: add egress/ingress Off switches for O(1) traffic blocking Add `off` bool to egress/ingress proto configs, OpenAPI spec, and DB types. When set, all traffic is denied immediately without iterating rules. Replaces the legacy `allow_internet_access=false` pattern of injecting 0.0.0.0/0 into denied list. Off is mutually exclusive with allow/deny rules (validated at API layer). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Commit:63b8b4a
Author:Lev
Committer:GitHub

feat: dynamic egress network rule updates for running sandboxes (#2074)

Commit:15eccf1
Author:Lev Brouk

refactor: revert egress to allow-deny API, add structured ingress proto Egress: revert gRPC to allowed_cidrs/denied_cidrs/allowed_domains (no port support). Firewall reverts to IP-set-only nftables rules. TCP proxy reverts to no-port egress matching. Ingress: add IngressRule proto {cidr, port_low, port_high}. API does all parsing/validation and sends pre-validated structs to orchestrator. Orchestrator trusts data, no re-parsing. API now rejects bare IPs — inputs must be CIDRs or domains (egress) and CIDRs only (ingress). Remove egress port integration tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Commit:0082dd0
Author:Lev Brouk

Merge branch 'lev-egress-port-ranges' into lev-ingress-control

Commit:1fdee8a
Author:Lev Brouk

feat(orch): unify proto fields, add port-specific egress rules, integration tests Rename proto fields (allowed_cidrs→allowed, denied_cidrs→denied, drop allowed_domains) and update all consumers. Refactor isEgressAllowed into matchRule with domain/CIDR+port matching. Fix domain entry leak into nftables path. Add comprehensive integration tests for port-specific egress rules covering TCP, UDP, port ranges, CIDR:port, domain:port, and allow/deny precedence. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Commit:71ff3e0
Author:Lev Brouk

Merge remote-tracking branch 'e2b/lev-allow-deny-dynamic' into lev-ingress-control

Commit:6f21b57
Author:Lev Brouk

Merge branch 'main' of github.com:e2b-dev/infra into lev-allow-deny-dynamic

Commit:5c6a1de
Author:Joe Lombrozo
Committer:GitHub

Implement depth parameter (#2102) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

Commit:89c30ef
Author:Lev Brouk
Committer:Lev Brouk

feat: add dynamic ingress control for sandboxes Add port-level and client IP-level ingress restrictions that can be configured at sandbox creation and updated at runtime. Follows the same allow-wins-over-deny priority semantics as egress control. Key changes: - OpenAPI spec: add allowPorts, denyPorts, allowIn, denyIn fields to SandboxNetworkConfig (both create and update endpoints) - Proto: add allowed_ports, denied_ports, allowed_client_cidrs, denied_client_cidrs to SandboxNetworkIngressConfig - API handlers: validate ingress rules (port ranges, CIDR format), co-locate with egress validation - Orchestrator proxy: enforce port and client IP restrictions on the hot path with pre-parsed CIDRs stored on sandbox Metadata - Orchestrator server: ingress updates with rollback support alongside egress and end_time updates, eventData threaded through update closures - Error pages: TemplatedError-based HTML/JSON responses for blocked ports and client IPs, matching existing traffic token error pattern - Envd port (49983) is always exempt from ingress restrictions - Unit tests for validation, proxy helpers, pre-parsed CIDRs, and server update rollback logic Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Commit:31175f4
Author:Lev Brouk

Merge branch 'main' of github.com:e2b-dev/infra into lev-allow-deny-dynamic

Commit:af7671d
Author:Jiri Sveceny
Committer:GitHub

Label based sandbox scheduler (#2066) * Support exposing node labels via orchestrator info service * IaC allowing to set node metadata for each compute pool * Schedule based on node metadata * Fallback to `default` label when sbx/node list is empty * Always create `node_labels` metadata key * Orchestrator reporting host labels * Node labels for template manager * Schedule sandboxes using team-level scheduling labels from DB Add sandbox_scheduling_labels column to teams table and wire it through PlaceSandbox so placement uses team labels instead of hardcoded defaults. Node labels stored as map[string]struct{} for efficient subset matching. * Add sandbox-label-based-scheduling feature flag to gate label filtering Label-based node filtering is disabled by default behind the sandbox-label-based-scheduling feature flag. The flag is read into BestOfKConfig and dynamically refreshed every 30s. * Remove module defaults * Feature flag with team context for label filtering * chore: add sandbox context --------- Co-authored-by: Jakub Novak <jakub@e2b.dev>

Commit:dcbc89d
Author:Lev Brouk
Committer:Lev Brouk

PR feedback: merge UpdateNetwork into unified Update RPC with transactional apply/revert Combine the separate UpdateNetwork and Update gRPC RPCs into a single Update RPC that handles both end_time and egress changes. Updates are applied sequentially using a functional updater pattern — on failure, already-applied changes are rolled back in reverse order. Publish a SandboxUpdatedEvent for any successful update, including network egress details (allowed/denied CIDRs, allowed domains) in the event data alongside the existing set_timeout field. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Commit:3e5923b
Author:Lev Brouk

PR feedback: embed SandboxNetworkEgressConfig in update network request Reuse the existing SandboxNetworkEgressConfig message in SandboxUpdateNetworkRequest instead of repeating flat fields. Change UpdateInternet to accept the egress proto message directly. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Commit:4511929
Author:Lev Brouk

feat(api): support domain filtering in network update path The creation path splits AllowOut entries into CIDRs and domains via ParseAddressesAndDomains, but the update path only handled CIDRs. Now the update path mirrors the creation path: domains are extracted, the default nameserver is added when domains are present, and domains are passed through gRPC to the orchestrator's in-memory config for the TCP proxy. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Commit:d541327
Author:Lev Brouk
Committer:Lev Brouk

feat(orchestrator): wire dynamic network egress updates end-to-end Add full gRPC flow for runtime sandbox network config updates: - Proto: SandboxUpdateNetworkRequest + UpdateNetwork RPC - Orchestrator: UpdateNetwork handler updates nftables (non-TCP) and in-memory egress config (TCP proxy) with RWMutex thread safety - API: normalize bare IPs to CIDR notation before gRPC call - Slot.UpdateInternet: reset + re-apply firewall rules in sandbox netns - Thread-safe networkEgress field on Metadata (same pattern as endAt) - Integration tests verify actual connectivity changes (not just 204s) - test-network-update Makefile target for convenience Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Commit:926ced6
Author:Joseph Lombrozo
Committer:GitHub

Add files API (#1893) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Mish Ushakov <10400064+mishushakov@users.noreply.github.com>

Commit:9bdd4a4
Author:Jakub Dobry
Committer:GitHub

feat(orchestrator): implement direct peer-to-peer chunk transfer (#2032)

Commit:fdc1a2c
Author:Jakub Dobry
Committer:GitHub

feat: snapshots (#1799)

Commit:1eae0a6
Author:Matt Brockman
Committer:GitHub

Feature: Sandbox AutoResume (#1862) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Jakub Novák <jakub@e2b.dev>

Commit:c0dacfe
Author:Joseph Lombrozo
Committer:GitHub

Add volume CRUD and API usage (#1804) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

Commit:01da054
Author:Tomas Valenta
Committer:GitHub

Add stdin close to envd to correctly handle command that wait for stdin EOF (#1761) Co-authored-by: Matt Brockman <mattbrockman@gmail.com>

Commit:c930399
Author:Joe Lombrozo

linting, expose the api

Commit:4d5d712
Author:Jakub Dobry
Committer:GitHub

feat: add hostname based egress firewall (#1597)

Commit:c3d2ffe
Author:Jakub Dobry
Committer:GitHub

feat: add separate build logs endpoint (#1589) Co-authored-by: Jakub Novák <jakub@e2b.dev>

Commit:a3c2803
Author:Jakub Novák
Committer:GitHub

Add CPU info to the service info (#1511)

Commit:eabfe52
Author:Jakub Dobry
Committer:GitHub

feat: add mask request host (#1479) Co-authored-by: Joe Lombrozo <joe.lombrozo@e2b.dev>

Commit:5e97a45
Author:Jiri Sveceny
Committer:GitHub

Allow optional sandbox ingress traffic auth (#1474)

Commit:802fdaf
Author:Jakub Dobry
Committer:GitHub

feat: add sandbox network out configuration (#1447)

Commit:09d9394
Author:Jakub Dobry
Committer:Jakub Dobry

feat: add sandbox egress firewall for ip addresses

Commit:cbfe1d9
Author:Tomas Valenta

wip: rpc adapter

Commit:ac5c6f6
Author:ValentaTomas

Add orchestrator save and extend create

Commit:0cd8c98
Author:Jakub Dobry
Committer:GitHub

fix: minimize template manager logs response size (#1375)

The documentation is generated from this commit.

Commit:a8d150d
Author:Jakub Dobry
Committer:GitHub

feat: keep user and workdir from the template in the sandbox (#1349)

Commit:ef6d3f8
Author:Tomas Valenta

[WIP] Add new clone methods

Commit:f6c8507
Author:Jakub Dobry
Committer:GitHub

Track total and concurrent builds by team (#1255)

Commit:9b0cbd5
Author:Jakub Dobry
Committer:GitHub

Attach build logs to the error reason (#1187)

Commit:311eb85
Author:Jakub Dobry
Committer:Jakub Dobry

attach logs to the error reason

Commit:9749ac0
Author:Jakub Novák
Committer:GitHub

Set stdin to `/dev/null` for non pty command by default (#1093) Co-authored-by: Jakub Dobry <jakub.dobry8@gmail.com>

Commit:9ba388e
Author:Jakub Novák
Committer:Jakub Novak

Update packages/envd/spec/process/process.proto Co-authored-by: Jakub Dobry <jakub.dobry8@gmail.com>