feat(orch): debug a sandbox guest kernel with resume-build -gdb - #3040
Conversation
PR SummaryMedium Risk Overview Reviewed by Cursor Bugbot for commit 4b8f14b. Bugbot is set up for automated code reviews on this repo. Configure here. |
❌ 2 Tests Failed:
View the top 3 failed test(s) by shortest run time
To view more test analytics, go to the Test Analytics Dashboard |
There was a problem hiding this comment.
Code Review
Using time.After inside a select loop in waitForSocket creates a new timer on every iteration, which can cause a significant resource leak of timers; replacing it with a reused time.Ticker avoids this issue. Additionally, the write operation to the temporary GDB init script file in writeInitScript does not check for errors, which can lead to silent failures or truncated scripts if the disk is full or write permissions are restricted.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| func waitForSocket(ctx context.Context, path string, timeout time.Duration) error { | ||
| deadline := time.Now().Add(timeout) | ||
| for { | ||
| if info, err := os.Stat(path); err == nil && info.Mode()&os.ModeSocket != 0 { | ||
| return nil | ||
| } | ||
| if time.Now().After(deadline) { | ||
| return errors.New("timeout") | ||
| } | ||
| select { | ||
| case <-ctx.Done(): | ||
| return ctx.Err() | ||
| case <-time.After(50 * time.Millisecond): | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Using time.After inside a select loop creates a new timer on every iteration, which can cause a significant resource leak of timers if GDB takes a while to connect or if the context is canceled. Replacing this with a reused time.Ticker avoids leaking timers and ensures efficient resource usage.
| func waitForSocket(ctx context.Context, path string, timeout time.Duration) error { | |
| deadline := time.Now().Add(timeout) | |
| for { | |
| if info, err := os.Stat(path); err == nil && info.Mode()&os.ModeSocket != 0 { | |
| return nil | |
| } | |
| if time.Now().After(deadline) { | |
| return errors.New("timeout") | |
| } | |
| select { | |
| case <-ctx.Done(): | |
| return ctx.Err() | |
| case <-time.After(50 * time.Millisecond): | |
| } | |
| } | |
| } | |
| func waitForSocket(ctx context.Context, path string, timeout time.Duration) error { | |
| deadline := time.Now().Add(timeout) | |
| ticker := time.NewTicker(50 * time.Millisecond) | |
| defer ticker.Stop() | |
| for { | |
| if info, err := os.Stat(path); err == nil && info.Mode()&os.ModeSocket != 0 { | |
| return nil | |
| } | |
| if time.Now().After(deadline) { | |
| return errors.New("timeout") | |
| } | |
| select { | |
| case <-ctx.Done(): | |
| return ctx.Err() | |
| case <-ticker.C: | |
| } | |
| } | |
| } |
There was a problem hiding this comment.
Good catch — switched waitForSocket to a single reused time.Ticker (created once, defer ticker.Stop()) instead of allocating via time.After each iteration. Fixed in 2e27ece.
| func writeInitScript(symbols, socket string) (string, error) { | ||
| macroLib, err := macroLibPath() | ||
| if err != nil { | ||
| return "", err | ||
| } | ||
| f, err := os.CreateTemp("", "fc-debug-init-*.gdb") | ||
| if err != nil { | ||
| return "", err | ||
| } | ||
| defer f.Close() | ||
| fmt.Fprintf(f, `set pagination off | ||
| set confirm off | ||
| source %s | ||
| # FC boots the uncompressed vmlinux ELF directly, so KASLR never relocates the image: | ||
| # symbols sit at their link-time addresses (offset 0). | ||
| add-symbol-file %s -o 0x0 | ||
| target remote %s | ||
| `, macroLib, symbols, socket) | ||
|
|
||
| return f.Name(), nil | ||
| } |
There was a problem hiding this comment.
The write operation to the temporary GDB init script file does not check for errors, which can lead to silent failures or truncated scripts if the disk is full or write permissions are restricted. Explicitly checking the write error and closing the file descriptor before returning ensures robust error handling.
func writeInitScript(symbols, socket string) (string, error) {
macroLib, err := macroLibPath()
if err != nil {
return "", err
}
f, err := os.CreateTemp("", "fc-debug-init-*.gdb")
if err != nil {
return "", err
}
defer f.Close()
_, err = fmt.Fprintf(f, "set pagination off\nset confirm off\nsource %s\n# FC boots the uncompressed vmlinux ELF directly, so KASLR never relocates the image:\n# symbols sit at their link-time addresses (offset 0).\nadd-symbol-file %s -o 0x0\ntarget remote %s\n", macroLib, symbols, socket)
if err != nil {
return "", err
}
if err := f.Close(); err != nil {
return "", err
}
return f.Name(), nil
}There was a problem hiding this comment.
Fixed in 2e27ece — writeInitScript now checks the Fprintf write error and the explicit Close error, and removes the temp file on the error path (so a failed write does not leave a truncated init script behind).
c2dedd5 to
8ab8d03
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 8ab8d03. Configure here.
8ab8d03 to
89df3d2
Compare
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
Add Config.SkipEnvdWait, gating the post-resume WaitForEnvd in ResumeSandbox. The resume-build gdb debugging flow needs it: the guest is held at a gdb entry breakpoint and never boots envd, so the readiness wait would time out and tear the sandbox down before a debugger can attach. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Nikita Kalyazin <nikita.kalyazin@e2b.dev>
Reusable gdb macros (promoted from the restore-path PoC) loaded by
resume-build -gdb: fc-faults [N] attributes guest page faults to comm/pid/VMA,
plus fc-task, fc-curr, fc-regions, fc-va. Targets Linux 6.1.x x86_64.
Sample output (base template resumed under gdb on a dev node):
fc-faults 3:
FAULT comm=systemd-journal pid=283 addr=0x7f833ca73ea8 vma=0x7f833ca27000-0x7f833cb27000 flags=0xfb
FAULT comm=systemd-journal pid=283 addr=0x7f833e0c7088 vma=0x7f833e0c7000-0x7f833e0c8000 flags=0xfb
FAULT comm=systemd-journal pid=283 addr=0x7f833ca56488 vma=0x7f833ca27000-0x7f833cb27000 flags=0xfb
fc-curr 0 / fc-curr 1 (per-vCPU current task):
task=0xffffffff82419600 comm=swapper/0 pid=0 tgid=0 mm=0x0
task=0xffff888003dad800 comm=systemd-journal pid=283 tgid=283 mm=0xffff888002c62a80
fc-regions / fc-va 0x100000:
page_offset_base = 0xffff888000000000
vmemmap_base = 0xffffea0000000000
vmalloc_base = 0xffffc90000000000
__va(0x100000) = 0xffff888000100000
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Nikita Kalyazin <nikita.kalyazin@e2b.dev>
89df3d2 to
c3978c8
Compare
| // workload, so it is mutually exclusive with the pause/cmd/bench modes — | ||
| // reject the combination rather than silently ignoring the other flags. | ||
| if fphBenchOpts.enabled || runOpts.enabled() || pauseOpts.enabled() || iterations > 0 || reboot || shell { | ||
| return errors.New("-gdb cannot be combined with -pause/-cmd/-iterations/-reboot/-shell/-fph-bench") |
There was a problem hiding this comment.
🔒 Agentic Security Review
Severity: HIGH
[Privacy Guard] The new -gdb execution path does not enforce -no-egress before entering gdbMode, even though this flow is explicitly documented as handling real customer snapshots with -no-egress as a binding rule.
Impact: A debugging run against customer snapshot state can accidentally execute with outbound network still enabled, creating a real exfiltration path for guest-derived sensitive data.
Reviewed by Cursor Security Reviewer for commit c3978c8. Configure here.
There was a problem hiding this comment.
Enforced in 638113a: -gdb now sets noEgress = true before the egress proxy is constructed, so a debugging run can't leave egress open regardless of whether the operator remembers -no-egress.
For the record, the practical risk was already near-zero: in gdb mode the guest is held at Firecracker's entry breakpoint and never boots — no envd, no kernel network init, no workload — so the frozen guest has nothing running that could exfiltrate. The change makes the runbook's "always -no-egress" mechanical rather than a manual step, as defense-in-depth.
| if socket == "" { | ||
| socket = filepath.Join(os.TempDir(), fmt.Sprintf("fc-gdb-%d.sock", time.Now().UnixNano())) | ||
| } | ||
| _ = os.Remove(socket) |
There was a problem hiding this comment.
🔒 Agentic Security Review
Severity: MEDIUM
The -gdb-socket value is used directly in _ = os.Remove(socket) without containment or type checks, and this path is run via sudo -E in the documented workflow.
Impact: If automation or a tool-controlled input can set -gdb-socket, this enables deletion of arbitrary root-accessible filesystem entries outside the intended temp/socket area.
Reviewed by Cursor Security Reviewer for commit c3978c8. Configure here.
There was a problem hiding this comment.
False positive for this tool. resume-build is a manual developer CLI the operator runs as sudo -E; -gdb-socket is an operator-supplied flag, not untrusted/automation-controlled input, so there's no trust boundary being crossed — anyone who can pass the flag already has a root shell and can delete files directly. os.Remove (not RemoveAll) unlinks a single path, and this is the standard "clear the stale socket before bind" step (mirrored in teardown). No change planned.
Resume a snapshot under a gdb-enabled Firecracker held at the kernel entry breakpoint and hand over a ready, symbol-resolving gdb session. Sets FIRECRACKER_GDB_SOCKET (inherited by the no-jailer FC), skips the envd wait, stages the debug FC binary at the resolved path (restored on exit), resumes in the background and connects gdb once FC binds the socket (the stub holds the snapshot load open until a debugger attaches, so resuming first would deadlock), generates a parameterized init script sourcing fc-debug.gdb, prints a debug-context block, and runs gdb interactively or in batch (-gdb-exec/-gdb-script). One session per invocation; FC/UFFD/NBD torn down on exit. The debug artifacts (firecracker-debug, vmlinux.debug) are fetched by version from the release buckets the same way create-build fetches the prod kernel/FC (base overridable via E2B_GDB_ARTIFACTS_URL); -gdb-fc / -gdb-symbols override a fetch with a local build. Symbols load at their link-time addresses (offset 0): Firecracker boots the uncompressed vmlinux ELF directly, so the bzImage KASLR decompressor never runs and the kernel image is never relocated — there is no slide to recover. This holds even with CONFIG_RANDOMIZE_BASE / CONFIG_RANDOMIZE_MEMORY enabled, since both are gated on a boot-params flag that only the decompressor sets. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Nikita Kalyazin <nikita.kalyazin@e2b.dev>
How to debug a sandbox's guest kernel with resume-build -gdb: prerequisites and artifact staging, steps (interactive + scripted), the macro reference, the observer-effect guidance (HW breakpoints, resident set from the UFFD log), and the binding customer-data rules. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Nikita Kalyazin <nikita.kalyazin@e2b.dev>
create-build hardcoded the sandbox proxy port to 5007, so it could not run on a node that already has a live orchestrator bound there. Read PROXY_PORT (default 5007) so create-build can run alongside a live orchestrator on an alternate port, as the gdb e2e does. Signed-off-by: Nikita Kalyazin <nikita.kalyazin@e2b.dev> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
c3978c8 to
4b8f14b
Compare
…d -gdb (#3108) ## Why `resume-build -gdb` (guest-kernel debugging, added in #3040) didn't actually run on a real orchestrator node: it staged the gdb-enabled Firecracker by renaming the prod binary in place, but on a node the FC-versions directory is a **read-only** mount (gcsfuse), so it failed with `read-only file system`. It also located its `fc-debug.gdb` macro library relative to the source tree, so a binary copied to a node without its source failed with `macro library not found`. And bridging a snapshot from another environment for debugging meant hand-copying the FC + kernel debug artifacts. This makes the `-gdb` path portable, adds a one-command artifact bridge, and trims a debug-artifact fetch path that never fired in practice. ## What 1. **`fix(orch): make resume-build -gdb portable to read-only mounts and standalone binaries`** - Stage the gdb-enabled Firecracker into a **writable temp dir** and point the factory's `FirecrackerVersionsDir` at it before the factory captures the config, instead of overwriting the prod binary in the read-only versions dir. The original dir is preserved only for *resolving* the published `firecracker-debug`; the real dir is never written. Removes the old backup/restore (and its interrupted-run recovery). - **Embed** `fc-debug.gdb` with `go:embed` so the binary is self-contained (a colocated copy still wins for local iteration). - **Backstop:** verify the binary about to launch actually contains the gdb feature (`FIRECRACKER_GDB_SOCKET`), so a stale/wrong `firecracker-debug` fails with a clear message instead of an opaque "gdb socket never bound". 2. **`feat(orch): add copy-build -gdb to stage FC + kernel debug artifacts`** - `copy-build -gdb` reads the build's FC/kernel versions from `metadata.json` and ensures the runtime + debug artifacts (`firecracker`, `firecracker-debug`, `vmlinux.bin`, `vmlinux.debug`) exist at the destination, deriving the versions/kernels buckets from the template bucket. CRC-compares like the snapshot copy: skips identical content, otherwise copies — **replacing** a divergent/stale artifact. Requires `gs://` source/dest. 3. **`refactor(orch): drop the unused gdb debug-artifact URL auto-fetch`** - The by-version HTTP fetch never fired in practice (the artifacts aren't published at the default URL, and the per-cluster bucket layout doesn't match the URL scheme); artifacts always resolve locally or via `copy-build -gdb`. Removes the fetch code/env-var and renames `resolveOrFetch` → `resolveLocal`. 4. **`docs(orch): correct the gdb runbook artifact resolution`** - Replaces the inaccurate "auto-fetched by version" claim with how resolution actually works (local, next to the snapshot's FC/kernel; staged by `copy-build -gdb`; or explicit `-gdb-fc`/`-gdb-symbols`). ## Testing - End-to-end on a dev node against a real snapshot, with the FC-versions directory mounted **read-only**: Firecracker bound the gdb socket and launched from the temp staging dir (never the read-only mount); DWARF source-level symbols, vCPU state, and page-fault profiling all worked. - Verified the backstop both ways: a non-gdb binary fails with the clear "is not gdb-enabled" error; a real gdb binary passes and runs. - `copy-build -gdb` exercised both the skip-identical and the copy/replace paths. - `go build`, `go test`, `golangci-lint` clean; each commit builds on its own. ## Scope / risk Touches only the `resume-build` and `copy-build` developer side-tools — no production service code path. The read-only-mount override is gated on `-gdb` and confined to that run (only the FC-versions dir; the kernel dir is untouched). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: Nikita Kalyazin <nikita.kalyazin@e2b.dev> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🤖 I have created a release *beep* *boop* --- ## 0.0.1 (2026-07-30) ### Features * **api:** add sandbox IAM workload token configuration ([13ddb3d](13ddb3d)) * **api:** add sandbox workload identity permission ([#3319](#3319)) ([13ddb3d](13ddb3d)) * **api:** SOCKS5 egress proxy on sandbox network config (BYOP) ([#2642](#2642)) ([1fc3820](1fc3820)) * **cfg:** add DISABLE_STARTUP_RECLAIM flag ([#3081](#3081)) ([7677ca6](7677ca6)) * **clickhouse:** implement multi-cluster fan-out for events and stats ([#2925](#2925)) ([39594c6](39594c6)) * dynamic sandbox log routing and ClickHouse-backed log reads ([#3236](#3236)) ([1b19a3b](1b19a3b)) * **envd:** give envd realtime IO priority, reset for user processes ([#2681](#2681)) ([f4bd1b2](f4bd1b2)) * **envd:** split collapse stats into real migrations vs already-huge ([#3021](#3021)) ([0d77614](0d77614)) * **envd:** support user-defined file metadata via xattrs ([#2732](#2732)) ([da8fbe4](da8fbe4)) * **featureflags:** support per-service context providers ([#3100](#3100)) ([65297c1](65297c1)) * freeze user cgroup across pause/resume to keep envd /init responsive ([#2688](#2688)) ([eceb741](eceb741)) * **metrics:** break down pause-snapshot latency by step ([#3426](#3426)) ([657559e](657559e)) * **metrics:** label pause telemetry by fs_only ([#3425](#3425)) ([411b63e](411b63e)) * **observability:** add kill_reason to sandbox.lifecycle.killed ([#2833](#2833)) ([e45418f](e45418f)) * **observability:** include kill_reason in kill-path structured logs ([#2846](#2846)) ([33c49f7](33c49f7)) * **orch:** add envd-version to LaunchDarkly sandbox context ([#3051](#3051)) ([37d3b92](37d3b92)) * **orch:** add less, nftables, iputils-ping, and jq to base provisioning ([#2736](#2736)) ([a1e010e](a1e010e)) * **orch:** collapse envd's heap into 2 MiB hugepages before pause to cut cold-resume faults ([#2997](#2997)) ([6677f73](6677f73)) * **orch:** debug a sandbox guest kernel with resume-build -gdb ([#3040](#3040)) ([37bb0dc](37bb0dc)) * **orch:** decouple warm resume from memfile dedup ([#3166](#3166)) ([77f25a0](77f25a0)) * **orch:** distro-aware template base-image provisioning ([#3411](#3411)) ([f8c7b5b](f8c7b5b)) * **orchestrator/cgroup:** list and destroy leaked sandbox cgroups ([#3086](#3086)) ([bce1d84](bce1d84)) * **orchestrator/nbd:** inspect and disconnect connected devices ([#3087](#3087)) ([4d47148](4d47148)) * **orchestrator/network:** list slot namespaces ([#3089](#3089)) ([c23dbc7](c23dbc7)) * **orchestrator/network:** list slot namespaces ([#3090](#3090)) ([fbfce25](fbfce25)) * **orchestrator:** add -force-reboot to resume-build to cold-boot memory-snaphsot builds ([#3208](#3208)) ([cf8f15b](cf8f15b)) * **orchestrator:** add allocated resource metrics for sandboxes ([#2943](#2943)) ([95cb6d3](95cb6d3)) * **orchestrator:** add dummy orchestrator binary for local API dev ([#2744](#2744)) ([ab56e25](ab56e25)) * **orchestrator:** add NetworkAssignHook for sandbox lifecycle extensions ([#3290](#3290)) ([3261963](3261963)) * **orchestrator:** add soft-delete marker label to the check metric ([#3144](#3144)) ([1ce64f8](1ce64f8)) * **orchestrator:** add v4HeaderForUncompressed FF bit ([#2669](#2669)) ([1f459ee](1f459ee)) * **orchestrator:** always include execution metrics in sandbox webhook events ([#2852](#2852)) ([440edfe](440edfe)) * **orchestrator:** classify envd-init by exit type ([#3139](#3139)) ([1e39a4f](1e39a4f)) * **orchestrator:** graceful sandbox drain on shutdown ([#3069](#3069)) ([6ce68e3](6ce68e3)) * **orchestrator:** graceful template-build drain on shutdown ([#3079](#3079)) ([1b3001c](1b3001c)) * **orchestrator:** improved read-path telemetry ([#3063](#3063)) ([bc3fe84](bc3fe84)) * **orchestrator:** LD-gated ClickHouse write fan-out feature flag ([#3152](#3152)) ([f046fcf](f046fcf)) * **orchestrator:** make build-reserved-disk-space-mb default 256MB ([#3065](#3065)) ([d473f98](d473f98)) * **orchestrator:** record upload compression metrics ([#2761](#2761)) ([9092e35](9092e35)) * **orchestrator:** report hugepage metrics to API ([#3182](#3182)) ([7735bae](7735bae)) * **orchestrator:** run startup reclaim on boot ([#3123](#3123)) ([79b838e](79b838e)) * **orchestrator:** single-instance flock on startup ([#3143](#3143)) ([1320d6e](1320d6e)) * **orchestrator:** soft-delete consumer enforcement for storage index ([#3034](#3034)) ([fbfc918](fbfc918)) * **orchestrator:** tag envd-init meters with start_type ([#3125](#3125)) ([4466b48](4466b48)) * **orchestrator:** track and report last status change timestamp ([#2980](#2980)) ([f79be77](f79be77)) * **orchestrator:** track sandbox lifecycles ([#2998](#2998)) ([057f20c](057f20c)) * **orchestrator:** write layer sizes (logical/mapped/diff) to object metadata ([#3122](#3122)) ([11869c0](11869c0)) * **orch:** harvest resume-prefetch trace on pause ([#3067](#3067)) ([97bd4a5](97bd4a5)) * **orch:** last-cycle memory prefetch on resume ([#3258](#3258)) ([b22e820](b22e820)) * **orch:** make resume-build -gdb work on real nodes + add copy-build -gdb ([#3108](#3108)) ([c684bd2](c684bd2)) * **orch:** opt-in DSCP marker for sandbox egress (SANDBOX_EGRESS_DSCP) ([#3039](#3039)) ([a98cf2c](a98cf2c)) * **orch:** per-start UFFD startup working-set metric ([#2960](#2960)) ([dc386b2](dc386b2)) * **orch:** premade NixOS base-image support ([#3412](#3412)) ([776ba39](776ba39)) * **orch:** record envd init duration histogram on failure with success attribute ([#2749](#2749)) ([afa7458](afa7458)) * **orch:** snapshot fragmentation metrics ([#2931](#2931)) ([842b007](842b007)) * per-team events TTL limit (tier + addons) ([#3181](#3181)) ([f76b2cb](f76b2cb)) * **shared:** add OTEL instrumentation to AWS S3 storage client ([#3172](#3172)) ([25b0fd1](25b0fd1)) * **storage:** per-role storage URLs, env-free storage library ([#3246](#3246)) ([fcbe909](fcbe909)) * **storage:** stamp provenance custom metadata on uploaded objects (incl. headers) ([#3033](#3033)) ([ba8604e](ba8604e)) * **storage:** write-through compressed templates to NFS on upload ([#2827](#2827)) ([57503c1](57503c1)) ### Bug Fixes * added api and orch ([#3454](#3454)) ([fda5e45](fda5e45)) * **block:** rephrase misleading error message in pwritevAll ([#2816](#2816)) ([1555f1b](1555f1b)) * **cache:** use 512-byte units for stat.Blocks in FileSize ([#2949](#2949)) ([0f632a9](0f632a9)) * **clean-nfs-cache:** exclude zombies from delete_age ([#3191](#3191)) ([3fa2aeb](3fa2aeb)) * **compression:** correctness findings from compression audit ([#2803](#2803)) ([d21a6a9](d21a6a9)) * **copy-build:** resolve compression suffix for build data files ([#2859](#2859)) ([8966f7e](8966f7e)) * correct 3 CVES ([#3218](#3218)) ([076823b](076823b)) * **envd:** stop freezing socat cgroup across pause/resume ([#2923](#2923)) ([8b6f2b9](8b6f2b9)) * **inspect-build:** adapt validate to new Chunker upstream API ([#2989](#2989)) ([2e0d3da](2e0d3da)) * **nbd:** adjust status poll sleep from 100ns to 100µs ([02bf51b](02bf51b)) * **nbd:** change NBD status poll sleep from 100ns to 100µs to avoid useless busy spinning ([#2884](#2884)) ([02bf51b](02bf51b)) * **nfsproxy:** deflake TestRoundTrip EADDRINUSE ([#2987](#2987)) ([55f4d18](55f4d18)) * **orch:** denormalize upload metric file type ([#2865](#2865)) ([b1646ca](b1646ca)) * **orch:** disable the chronyd seccomp filter on Alpine when using PHC ([#3453](#3453)) ([e58af28](e58af28)) * **orchestrator:** anchor rsync CWD to root in template file copy ([#2835](#2835)) ([7160db9](7160db9)) * **orchestrator:** atomically replace metadata ([#3321](#3321)) ([0c4ad6b](0c4ad6b)) * **orchestrator:** avoid serializing upload headers twice ([#2762](#2762)) ([9b7b149](9b7b149)) * **orchestrator:** chunk readiness bug in P2P->compressed ([#3185](#3185)) ([74a6e5b](74a6e5b)) * **orchestrator:** deschedule flaky eviction-loop race in TestDiffSto… ([#3173](#3173)) ([88ff17c](88ff17c)) * **orchestrator:** discard poisoned nftables conn on firewall errors ([#3008](#3008)) ([03f10e0](03f10e0)) * **orchestrator:** drop stale pre-init logs ([#3297](#3297)) ([8ec4be5](8ec4be5)) * **orchestrator:** emit compression ratios as fractions, not BP ([#2772](#2772)) ([866f4c1](866f4c1)) * **orchestrator:** export dirty-page stall counter from process start ([#2992](#2992)) ([badc8ad](badc8ad)) * **orchestrator:** harden Firecracker process shutdown ([#2996](#2996)) ([df662e7](df662e7)) * **orchestrator:** harden shutdown network cleanup ([#3000](#3000)) ([de2f391](de2f391)) * **orchestrator:** implement Docker COPY merge semantics in template builds ([#3283](#3283)) ([9174104](9174104)) * **orchestrator:** keep dedup empty-pages telemetry scan-only ([#2991](#2991)) ([35d0832](35d0832)) * **orchestrator:** let build-cache threshold flag raise above its fal… ([#3175](#3175)) ([06393c3](06393c3)) * **orchestrator:** log missing egress proxy in startup reclaim instead of defaulting silently ([#3116](#3116)) ([6ca3163](6ca3163)) * **orchestrator:** make copy-build handle filesystem-only snapshots ([#3299](#3299)) ([62add04](62add04)) * **orchestrator:** measure ext4 free space from block groups ([#3282](#3282)) ([f18f05f](f18f05f)) * **orchestrator:** normalize upload metric file labels ([#2767](#2767)) ([6dec8b3](6dec8b3)) * **orchestrator:** order egress config/firewall updates to close BYOP enable race ([#3313](#3313)) ([7faa59e](7faa59e)) * **orchestrator:** order envd.service after local-fs.target ([#3043](#3043)) ([ea2663e](ea2663e)) * **orchestrator:** order envd.service after systemd-tmpfiles-setup ([#3130](#3130)) ([9481811](9481811)) * **orchestrator:** pause upload retain retry ([#2993](#2993)) ([4f81799](4f81799)) * **orchestrator:** pin tap device host-side MAC address ([#3271](#3271)) ([3c786ba](3c786ba)) * **orchestrator:** pin UFFD copy source buffers ([#2745](#2745)) ([837fa91](837fa91)) * **orchestrator:** preserve full ENV value across stdout chunks ([#2740](#2740)) ([4822e6d](4822e6d)) * **orchestrator:** read V3 ancestors as uncompressed instead of failing ([#2994](#2994)) ([c479dd3](c479dd3)) * **orchestrator:** reject standby while draining ([#3325](#3325)) ([475a7ee](475a7ee)) * **orchestrator:** report real V4 header compression ratio ([#2771](#2771)) ([ecd344e](ecd344e)) * **orchestrator:** resolve remaining P2P/compression/V5 issues ([#3015](#3015)) ([1e4379e](1e4379e)) * **orchestrator:** sanitize OCI pull errors ([#3096](#3096)) ([a3af6c0](a3af6c0)) * **orchestrator:** scope rootfs hash to provision default ([#3129](#3129)) ([475f955](475f955)) * **orchestrator:** stop Checks health-loop leaking ([#2739](#2739)) ([17e6e60](17e6e60)) * **orchestrator:** survive SIGBUS from failing disks under mmap'd caches ([#3385](#3385)) ([728bba3](728bba3)) * **orchestrator:** tolerate missing header for legacy templates ([#3026](#3026)) ([8a44bfe](8a44bfe)) * **orch:** fall back to ID_LIKE with a warning instead of rejecting ([#3459](#3459)) ([7167818](7167818)) * **orch:** prevent NBD dispatch read-loop stall on WRITE_ZEROES (behind flag) ([#3048](#3048)) ([efd3d4d](efd3d4d)) * **orch:** split scheduling base build id per artifact ([#2920](#2920)) ([3e35a2a](3e35a2a)) * **orch:** validate copy-build -gdb buckets before the snapshot copy ([#3446](#3446)) ([586ad74](586ad74)) * **shared:** never report a failed envd command stream as success ([#3281](#3281)) ([69c06b6](69c06b6)) * **storage:** compression upload & cache correctness fixes ([#3231](#3231)) ([980748f](980748f)) * **storage:** don't assume V4+ ancestor gaps are uncompressed ([#3447](#3447)) ([bfdbb24](bfdbb24)) * **uffd:** dedupe deferred page faults ([#2864](#2864)) ([9680a41](9680a41)) * WrapContextAsUserError should not misclassify internal timeouts as user cancellations ([#3155](#3155)) ([8f83959](8f83959)) ### Performance Improvements * **build:** cache resolved Diff per BuildId within File.ReadAt ([#2838](#2838)) ([53de07f](53de07f)) * **build:** parallelize fragmented backing reads ([#2872](#2872)) ([c7655a7](c7655a7)) * **clean-nfs-cache:** restore dirfd-relative statx ([#2766](#2766)) ([6bdbedb](6bdbedb)) * **header:** add V5 columnar varint header format ([#2847](#2847)) ([9dd931b](9dd931b)) * **header:** pack cached Header.Mapping into a compact form ([#2844](#2844)) ([7f0b13c](7f0b13c)) * **orchestrator:** add memfile dedup density threshold ([#2862](#2862)) ([7ccfa02](7ccfa02)) * **orchestrator:** avoid V3-ancestor header refresh ([#2999](#2999)) ([cb6aa0b](cb6aa0b)) * **orch:** metrics for dirty page throttling ([#2858](#2858)) ([d2aa554](d2aa554)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: e2b-release-please[bot] <298072688+e2b-release-please[bot]@users.noreply.github.com> Co-authored-by: Charlie Wyse <charlie.wyse@e2b.dev>
…d -gdb (#3108) ## Why `resume-build -gdb` (guest-kernel debugging, added in #3040) didn't actually run on a real orchestrator node: it staged the gdb-enabled Firecracker by renaming the prod binary in place, but on a node the FC-versions directory is a **read-only** mount (gcsfuse), so it failed with `read-only file system`. It also located its `fc-debug.gdb` macro library relative to the source tree, so a binary copied to a node without its source failed with `macro library not found`. And bridging a snapshot from another environment for debugging meant hand-copying the FC + kernel debug artifacts. This makes the `-gdb` path portable, adds a one-command artifact bridge, and trims a debug-artifact fetch path that never fired in practice. ## What 1. **`fix(orch): make resume-build -gdb portable to read-only mounts and standalone binaries`** - Stage the gdb-enabled Firecracker into a **writable temp dir** and point the factory's `FirecrackerVersionsDir` at it before the factory captures the config, instead of overwriting the prod binary in the read-only versions dir. The original dir is preserved only for *resolving* the published `firecracker-debug`; the real dir is never written. Removes the old backup/restore (and its interrupted-run recovery). - **Embed** `fc-debug.gdb` with `go:embed` so the binary is self-contained (a colocated copy still wins for local iteration). - **Backstop:** verify the binary about to launch actually contains the gdb feature (`FIRECRACKER_GDB_SOCKET`), so a stale/wrong `firecracker-debug` fails with a clear message instead of an opaque "gdb socket never bound". 2. **`feat(orch): add copy-build -gdb to stage FC + kernel debug artifacts`** - `copy-build -gdb` reads the build's FC/kernel versions from `metadata.json` and ensures the runtime + debug artifacts (`firecracker`, `firecracker-debug`, `vmlinux.bin`, `vmlinux.debug`) exist at the destination, deriving the versions/kernels buckets from the template bucket. CRC-compares like the snapshot copy: skips identical content, otherwise copies — **replacing** a divergent/stale artifact. Requires `gs://` source/dest. 3. **`refactor(orch): drop the unused gdb debug-artifact URL auto-fetch`** - The by-version HTTP fetch never fired in practice (the artifacts aren't published at the default URL, and the per-cluster bucket layout doesn't match the URL scheme); artifacts always resolve locally or via `copy-build -gdb`. Removes the fetch code/env-var and renames `resolveOrFetch` → `resolveLocal`. 4. **`docs(orch): correct the gdb runbook artifact resolution`** - Replaces the inaccurate "auto-fetched by version" claim with how resolution actually works (local, next to the snapshot's FC/kernel; staged by `copy-build -gdb`; or explicit `-gdb-fc`/`-gdb-symbols`). ## Testing - End-to-end on a dev node against a real snapshot, with the FC-versions directory mounted **read-only**: Firecracker bound the gdb socket and launched from the temp staging dir (never the read-only mount); DWARF source-level symbols, vCPU state, and page-fault profiling all worked. - Verified the backstop both ways: a non-gdb binary fails with the clear "is not gdb-enabled" error; a real gdb binary passes and runs. - `copy-build -gdb` exercised both the skip-identical and the copy/replace paths. - `go build`, `go test`, `golangci-lint` clean; each commit builds on its own. ## Scope / risk Touches only the `resume-build` and `copy-build` developer side-tools — no production service code path. The read-only-mount override is gated on `-gdb` and confined to that run (only the FC-versions dir; the kernel dir is untouched). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: Nikita Kalyazin <nikita.kalyazin@e2b.dev> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🤖 I have created a release *beep* *boop* --- ## 0.0.1 (2026-07-30) ### Features * **api:** add sandbox IAM workload token configuration ([13ddb3d](13ddb3d)) * **api:** add sandbox workload identity permission ([#3319](#3319)) ([13ddb3d](13ddb3d)) * **api:** SOCKS5 egress proxy on sandbox network config (BYOP) ([#2642](#2642)) ([1fc3820](1fc3820)) * **cfg:** add DISABLE_STARTUP_RECLAIM flag ([#3081](#3081)) ([7677ca6](7677ca6)) * **clickhouse:** implement multi-cluster fan-out for events and stats ([#2925](#2925)) ([39594c6](39594c6)) * dynamic sandbox log routing and ClickHouse-backed log reads ([#3236](#3236)) ([1b19a3b](1b19a3b)) * **envd:** give envd realtime IO priority, reset for user processes ([#2681](#2681)) ([f4bd1b2](f4bd1b2)) * **envd:** split collapse stats into real migrations vs already-huge ([#3021](#3021)) ([0d77614](0d77614)) * **envd:** support user-defined file metadata via xattrs ([#2732](#2732)) ([da8fbe4](da8fbe4)) * **featureflags:** support per-service context providers ([#3100](#3100)) ([65297c1](65297c1)) * freeze user cgroup across pause/resume to keep envd /init responsive ([#2688](#2688)) ([eceb741](eceb741)) * **metrics:** break down pause-snapshot latency by step ([#3426](#3426)) ([f551118](f551118)) * **metrics:** label pause telemetry by fs_only ([#3425](#3425)) ([4be33ba](4be33ba)) * **observability:** add kill_reason to sandbox.lifecycle.killed ([#2833](#2833)) ([e45418f](e45418f)) * **observability:** include kill_reason in kill-path structured logs ([#2846](#2846)) ([33c49f7](33c49f7)) * **orch:** add envd-version to LaunchDarkly sandbox context ([#3051](#3051)) ([37d3b92](37d3b92)) * **orch:** add less, nftables, iputils-ping, and jq to base provisioning ([#2736](#2736)) ([a1e010e](a1e010e)) * **orch:** collapse envd's heap into 2 MiB hugepages before pause to cut cold-resume faults ([#2997](#2997)) ([6677f73](6677f73)) * **orch:** debug a sandbox guest kernel with resume-build -gdb ([#3040](#3040)) ([37bb0dc](37bb0dc)) * **orch:** decouple warm resume from memfile dedup ([#3166](#3166)) ([77f25a0](77f25a0)) * **orch:** distro-aware template base-image provisioning ([#3411](#3411)) ([1abece1](1abece1)) * **orchestrator/cgroup:** list and destroy leaked sandbox cgroups ([#3086](#3086)) ([bce1d84](bce1d84)) * **orchestrator/nbd:** inspect and disconnect connected devices ([#3087](#3087)) ([4d47148](4d47148)) * **orchestrator/network:** list slot namespaces ([#3089](#3089)) ([c23dbc7](c23dbc7)) * **orchestrator/network:** list slot namespaces ([#3090](#3090)) ([fbfce25](fbfce25)) * **orchestrator:** add -force-reboot to resume-build to cold-boot memory-snaphsot builds ([#3208](#3208)) ([cf8f15b](cf8f15b)) * **orchestrator:** add allocated resource metrics for sandboxes ([#2943](#2943)) ([95cb6d3](95cb6d3)) * **orchestrator:** add dummy orchestrator binary for local API dev ([#2744](#2744)) ([ab56e25](ab56e25)) * **orchestrator:** add NetworkAssignHook for sandbox lifecycle extensions ([#3290](#3290)) ([3261963](3261963)) * **orchestrator:** add soft-delete marker label to the check metric ([#3144](#3144)) ([1ce64f8](1ce64f8)) * **orchestrator:** add v4HeaderForUncompressed FF bit ([#2669](#2669)) ([1f459ee](1f459ee)) * **orchestrator:** always include execution metrics in sandbox webhook events ([#2852](#2852)) ([440edfe](440edfe)) * **orchestrator:** classify envd-init by exit type ([#3139](#3139)) ([1e39a4f](1e39a4f)) * **orchestrator:** graceful sandbox drain on shutdown ([#3069](#3069)) ([6ce68e3](6ce68e3)) * **orchestrator:** graceful template-build drain on shutdown ([#3079](#3079)) ([1b3001c](1b3001c)) * **orchestrator:** improved read-path telemetry ([#3063](#3063)) ([bc3fe84](bc3fe84)) * **orchestrator:** LD-gated ClickHouse write fan-out feature flag ([#3152](#3152)) ([f046fcf](f046fcf)) * **orchestrator:** make build-reserved-disk-space-mb default 256MB ([#3065](#3065)) ([d473f98](d473f98)) * **orchestrator:** record upload compression metrics ([#2761](#2761)) ([9092e35](9092e35)) * **orchestrator:** report hugepage metrics to API ([#3182](#3182)) ([7735bae](7735bae)) * **orchestrator:** run startup reclaim on boot ([#3123](#3123)) ([79b838e](79b838e)) * **orchestrator:** single-instance flock on startup ([#3143](#3143)) ([1320d6e](1320d6e)) * **orchestrator:** soft-delete consumer enforcement for storage index ([#3034](#3034)) ([fbfc918](fbfc918)) * **orchestrator:** tag envd-init meters with start_type ([#3125](#3125)) ([4466b48](4466b48)) * **orchestrator:** track and report last status change timestamp ([#2980](#2980)) ([f79be77](f79be77)) * **orchestrator:** track sandbox lifecycles ([#2998](#2998)) ([057f20c](057f20c)) * **orchestrator:** write layer sizes (logical/mapped/diff) to object metadata ([#3122](#3122)) ([11869c0](11869c0)) * **orch:** harvest resume-prefetch trace on pause ([#3067](#3067)) ([97bd4a5](97bd4a5)) * **orch:** last-cycle memory prefetch on resume ([#3258](#3258)) ([ea94196](ea94196)) * **orch:** make resume-build -gdb work on real nodes + add copy-build -gdb ([#3108](#3108)) ([5385594](5385594)) * **orch:** opt-in DSCP marker for sandbox egress (SANDBOX_EGRESS_DSCP) ([#3039](#3039)) ([a98cf2c](a98cf2c)) * **orch:** per-start UFFD startup working-set metric ([#2960](#2960)) ([dc386b2](dc386b2)) * **orch:** premade NixOS base-image support ([#3412](#3412)) ([4bd42d2](4bd42d2)) * **orch:** record envd init duration histogram on failure with success attribute ([#2749](#2749)) ([afa7458](afa7458)) * **orch:** snapshot fragmentation metrics ([#2931](#2931)) ([842b007](842b007)) * per-team events TTL limit (tier + addons) ([#3181](#3181)) ([f76b2cb](f76b2cb)) * **shared:** add OTEL instrumentation to AWS S3 storage client ([#3172](#3172)) ([25b0fd1](25b0fd1)) * **storage:** per-role storage URLs, env-free storage library ([#3246](#3246)) ([fcbe909](fcbe909)) * **storage:** stamp provenance custom metadata on uploaded objects (incl. headers) ([#3033](#3033)) ([ba8604e](ba8604e)) * **storage:** write-through compressed templates to NFS on upload ([#2827](#2827)) ([57503c1](57503c1)) ### Bug Fixes * added api and orch ([#3454](#3454)) ([d56e0a8](d56e0a8)) * **block:** rephrase misleading error message in pwritevAll ([#2816](#2816)) ([1555f1b](1555f1b)) * **cache:** use 512-byte units for stat.Blocks in FileSize ([#2949](#2949)) ([0f632a9](0f632a9)) * **clean-nfs-cache:** exclude zombies from delete_age ([#3191](#3191)) ([3fa2aeb](3fa2aeb)) * **compression:** correctness findings from compression audit ([#2803](#2803)) ([d21a6a9](d21a6a9)) * **copy-build:** resolve compression suffix for build data files ([#2859](#2859)) ([8966f7e](8966f7e)) * correct 3 CVES ([#3218](#3218)) ([076823b](076823b)) * **envd:** stop freezing socat cgroup across pause/resume ([#2923](#2923)) ([8b6f2b9](8b6f2b9)) * **inspect-build:** adapt validate to new Chunker upstream API ([#2989](#2989)) ([2e0d3da](2e0d3da)) * **nbd:** adjust status poll sleep from 100ns to 100µs ([02bf51b](02bf51b)) * **nbd:** change NBD status poll sleep from 100ns to 100µs to avoid useless busy spinning ([#2884](#2884)) ([02bf51b](02bf51b)) * **nfsproxy:** deflake TestRoundTrip EADDRINUSE ([#2987](#2987)) ([55f4d18](55f4d18)) * **orch:** denormalize upload metric file type ([#2865](#2865)) ([b1646ca](b1646ca)) * **orch:** disable the chronyd seccomp filter on Alpine when using PHC ([#3453](#3453)) ([dfa9764](dfa9764)) * **orchestrator:** anchor rsync CWD to root in template file copy ([#2835](#2835)) ([7160db9](7160db9)) * **orchestrator:** atomically replace metadata ([#3321](#3321)) ([0c4ad6b](0c4ad6b)) * **orchestrator:** avoid serializing upload headers twice ([#2762](#2762)) ([9b7b149](9b7b149)) * **orchestrator:** chunk readiness bug in P2P->compressed ([#3185](#3185)) ([74a6e5b](74a6e5b)) * **orchestrator:** deschedule flaky eviction-loop race in TestDiffSto… ([#3173](#3173)) ([88ff17c](88ff17c)) * **orchestrator:** discard poisoned nftables conn on firewall errors ([#3008](#3008)) ([03f10e0](03f10e0)) * **orchestrator:** drop stale pre-init logs ([#3297](#3297)) ([8ec4be5](8ec4be5)) * **orchestrator:** emit compression ratios as fractions, not BP ([#2772](#2772)) ([866f4c1](866f4c1)) * **orchestrator:** export dirty-page stall counter from process start ([#2992](#2992)) ([badc8ad](badc8ad)) * **orchestrator:** harden Firecracker process shutdown ([#2996](#2996)) ([df662e7](df662e7)) * **orchestrator:** harden shutdown network cleanup ([#3000](#3000)) ([de2f391](de2f391)) * **orchestrator:** implement Docker COPY merge semantics in template builds ([#3283](#3283)) ([9174104](9174104)) * **orchestrator:** keep dedup empty-pages telemetry scan-only ([#2991](#2991)) ([35d0832](35d0832)) * **orchestrator:** let build-cache threshold flag raise above its fal… ([#3175](#3175)) ([06393c3](06393c3)) * **orchestrator:** log missing egress proxy in startup reclaim instead of defaulting silently ([#3116](#3116)) ([6ca3163](6ca3163)) * **orchestrator:** make copy-build handle filesystem-only snapshots ([#3299](#3299)) ([62add04](62add04)) * **orchestrator:** measure ext4 free space from block groups ([#3282](#3282)) ([f18f05f](f18f05f)) * **orchestrator:** normalize upload metric file labels ([#2767](#2767)) ([6dec8b3](6dec8b3)) * **orchestrator:** order egress config/firewall updates to close BYOP enable race ([#3313](#3313)) ([7faa59e](7faa59e)) * **orchestrator:** order envd.service after local-fs.target ([#3043](#3043)) ([ea2663e](ea2663e)) * **orchestrator:** order envd.service after systemd-tmpfiles-setup ([#3130](#3130)) ([9481811](9481811)) * **orchestrator:** pause upload retain retry ([#2993](#2993)) ([4f81799](4f81799)) * **orchestrator:** pin tap device host-side MAC address ([#3271](#3271)) ([3c786ba](3c786ba)) * **orchestrator:** pin UFFD copy source buffers ([#2745](#2745)) ([837fa91](837fa91)) * **orchestrator:** preserve full ENV value across stdout chunks ([#2740](#2740)) ([4822e6d](4822e6d)) * **orchestrator:** read V3 ancestors as uncompressed instead of failing ([#2994](#2994)) ([c479dd3](c479dd3)) * **orchestrator:** reject standby while draining ([#3325](#3325)) ([475a7ee](475a7ee)) * **orchestrator:** report real V4 header compression ratio ([#2771](#2771)) ([ecd344e](ecd344e)) * **orchestrator:** resolve remaining P2P/compression/V5 issues ([#3015](#3015)) ([1e4379e](1e4379e)) * **orchestrator:** sanitize OCI pull errors ([#3096](#3096)) ([a3af6c0](a3af6c0)) * **orchestrator:** scope rootfs hash to provision default ([#3129](#3129)) ([475f955](475f955)) * **orchestrator:** stop Checks health-loop leaking ([#2739](#2739)) ([17e6e60](17e6e60)) * **orchestrator:** survive SIGBUS from failing disks under mmap'd caches ([#3385](#3385)) ([8694d08](8694d08)) * **orchestrator:** tolerate missing header for legacy templates ([#3026](#3026)) ([8a44bfe](8a44bfe)) * **orch:** fall back to ID_LIKE with a warning instead of rejecting ([#3459](#3459)) ([73399b3](73399b3)) * **orch:** prevent NBD dispatch read-loop stall on WRITE_ZEROES (behind flag) ([#3048](#3048)) ([efd3d4d](efd3d4d)) * **orch:** split scheduling base build id per artifact ([#2920](#2920)) ([3e35a2a](3e35a2a)) * **orch:** validate copy-build -gdb buckets before the snapshot copy ([#3446](#3446)) ([9be382f](9be382f)) * **shared:** never report a failed envd command stream as success ([#3281](#3281)) ([69c06b6](69c06b6)) * **storage:** compression upload & cache correctness fixes ([#3231](#3231)) ([980748f](980748f)) * **storage:** don't assume V4+ ancestor gaps are uncompressed ([#3447](#3447)) ([f828d12](f828d12)) * **uffd:** dedupe deferred page faults ([#2864](#2864)) ([9680a41](9680a41)) * WrapContextAsUserError should not misclassify internal timeouts as user cancellations ([#3155](#3155)) ([8f83959](8f83959)) ### Performance Improvements * **build:** cache resolved Diff per BuildId within File.ReadAt ([#2838](#2838)) ([53de07f](53de07f)) * **build:** parallelize fragmented backing reads ([#2872](#2872)) ([c7655a7](c7655a7)) * **clean-nfs-cache:** restore dirfd-relative statx ([#2766](#2766)) ([6bdbedb](6bdbedb)) * **header:** add V5 columnar varint header format ([#2847](#2847)) ([9dd931b](9dd931b)) * **header:** pack cached Header.Mapping into a compact form ([#2844](#2844)) ([7f0b13c](7f0b13c)) * **orchestrator:** add memfile dedup density threshold ([#2862](#2862)) ([7ccfa02](7ccfa02)) * **orchestrator:** avoid V3-ancestor header refresh ([#2999](#2999)) ([cb6aa0b](cb6aa0b)) * **orch:** metrics for dirty page throttling ([#2858](#2858)) ([d2aa554](d2aa554)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: e2b-release-please[bot] <298072688+e2b-release-please[bot]@users.noreply.github.com> Co-authored-by: Charlie Wyse <charlie.wyse@e2b.dev>


Why
Host- and UFFD-side telemetry can't show what happens inside a resumed guest — which process/VMA is faulting, kernel state during the resume. This adds a way to attach
gdbto a resumed sandbox guest with source-level kernel symbols, for diagnosing resume behaviour (page-fault attribution, scheduler/VM state) on a dev node.What
resume-build -gdbresumes a snapshot under a--features gdbFirecracker held at the kernel entry breakpoint, loads the guest kernel's DWARF symbols, and hands over a readygdbsession (interactive, or scripted via-gdb-exec/-gdb-script). Commit-by-commit:feat(orch): allow skipping the envd readiness wait on resume—Config.SkipEnvdWaitgates the post-resumeWaitForEnvdinResumeSandbox(the guest is held at the breakpoint and never boots envd).feat(orch): add fc-debug.gdb guest-kernel debugging macros— reusable gdb macros:fc-faults [N](attributes guest page faults tocomm/pid/VMA),fc-curr,fc-task,fc-regions,fc-va. Targets Linux 6.1.x x86_64.feat(orch): add resume-build -gdb …— the orchestration: armsFIRECRACKER_GDB_SOCKET, stages the debug FC binary, resumes in the background and connects gdb once FC binds the socket (the stub holds the snapshot load open until a debugger attaches — resuming first would deadlock), generates the init script, prints a debug-context block, drives gdb. Debug artifacts (firecracker-debug,vmlinux.debug) are fetched by version frome2b-prod-public-builds(override base viaE2B_GDB_ARTIFACTS_URL; override paths via-gdb-fc/-gdb-symbols). Symbols load at offset 0 — FC boots the uncompressedvmlinuxELF directly, so image KASLR never runs and there's no slide to recover.docs(orch): add … runbook—gdb-debugging.md(usage, macros, observer-effect notes, customer-data rules).feat(orch): honor PROXY_PORT in create-build— letscreate-buildrun alongside a live orchestrator on an alternate port (needed to build the test snapshot on a node).Validation
--features gdbFC on the cluster,create-buildcold-booted the DWARF kernel into a snapshot, thenresume-build -gdb(no flags) fetched both artifacts by version, recovered a ready session, and produced real fault attribution:FAULT comm=systemd-journal pid=283 addr=0x7f83… vma=0x7f83…-… flags=0xfbfc-curr→comm=systemd-journal pid=283 …;fc-regions→page_offset_base=0xffff888000000000 …debugArtifactsBaseURL,resolveOrFetch(override→local→fetch precedence, 404),proxyPortparsing/fallback.golangci-lintclean; every commit builds and passes tests on its own.🤖 Generated with Claude Code