Skip to content

feat(website): record a website env's traffic as PCAP, served through traffic/v1 (FD-4683) - #469

Open
williamloo-scale wants to merge 5 commits into
wloo/website-computer-routingfrom
wloo/website-traffic-capture
Open

williamloo-scale wants to merge 5 commits into
wloo/website-computer-routingfrom
wloo/website-traffic-capture

Conversation

@williamloo-scale

@williamloo-scale williamloo-scale commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #448.

A website env can record every packet its websites' server and frontend containers send and receive, as PCAP, and serve the files through its card. This is opt-in.

  • Turning it on: deploy_env takes capture_traffic, and agent-env env deploy takes --capture-traffic. It works for a website env, or a multi env with a website, on a VM. Any other env, and container mode, refuse it.

  • Capture: each website container gets a tcpdump service beside it.

    • tcpdump comes from the gateway image and runs in that container's network namespace (network_mode: "service:<container>").
    • It's the only service holding NET_RAW/NET_ADMIN.
    • It writes rotating classic pcap files, 10 of 20 MB each with the oldest overwritten, to a volume no website container mounts. The gateway mounts it read-only.
    • The deploy is refused if a capture isn't running once the gateway is up.
  • Protocol: the new agentenv_protocol.traffic defines urn:agentenv:traffic/v1 with two ops:

    • list returns a TrafficCaptureListing, oldest file first;
    • get streams one file as application/vnd.tcpdump.pcap.

    Client helpers: list_traffic_captures, fetch_traffic_capture, serves_traffic. The gateway's constants.py mirrors the names, with a test keeping them equal.

  • Access: both ops require the per-deploy control token (DeployedEnv.control_token). The gateway removes Authorization from a proxied request only when it carries that token (compared with hmac.compare_digest), so no site can read the token, and a site's own bearer auth still reaches it.

  • Collection: the new collect_traffic_capture step stores each capture as a pcap FileArtifact in one FileArtifactUniverse, recorded under context.metadata["traffic_captures"][env_id]. It's best effort unless fail_task_on_error is set. Teardown also collects any capturing env the run didn't collect, before the env closes, so a capture isn't lost with its VM.

Before merging

  • Not yet run on a deployed VM. The compose wiring, gateway routes, token stripping, step and teardown are covered by unit tests.

Test

Unit suite on this branch: 13,358 passed, lint clean. One GitHub-clone test from main is deselected because it hangs on the local machine on main too.

🤖 Generated with Claude Code

RetriggerView in GreptileConfidence Score: 4/5

Preserve partial capture results before merging so teardown cannot discard links to files it already uploaded.

Fix All in CursorFindings

  1. P1 Partial captures lose their links ▶
Fix with agent prompt
### Issue 1
src/agent_env/task_step/task_steps/traffic_capture.py:166-169
`_store` saves the universe and its run reference only after every capture finishes. If teardown times out during a later download or upload, files already uploaded remain without a universe or run reference. The `finally` in `collect_uncollected_captures` saves only completed environment entries, so it cannot preserve these files. Teardown then removes the VM, preventing another attempt.

Save each completed file's reference as collection progresses, and preserve partial results when collection stops.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Adds opt-in website traffic capture through tcpdump services and the traffic/v1 protocol.

  • Website containers can record bounded packet captures on VM deployments.
  • Gateway cards list and stream captures through a token-protected traffic API.
  • Task runs can save captures as artifacts and collect them before teardown.

The previous-review ancestry check failed, and the two revisions have different merge bases with the target. This review therefore used the full PR diff. All supplied previous threads were unnumbered and were not reposted.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    W[Website container] --> T[tcpdump in shared network namespace]
    T --> V[Rotating PCAP volume]
    V --> G[Gateway read-only mount]
    G -->|traffic/v1 with control token| C[Capture collection]
    C --> F[File artifacts]
    F --> U[File artifact universe]
    U --> R[Stored run metadata]
Loading

Reviews (6) · Last reviewed commit: "fix(website): teardown saves the capture..." · Reviewed by Greptile

@williamloo-scale
williamloo-scale requested a review from a team as a code owner November 3, 2026 21:53
Comment thread src/agent_env/env/gateway/gateway.py Resolved
Comment thread src/agent_env/env/gateway/gateway.py Resolved
@williamloo-scale
williamloo-scale force-pushed the wloo/website-computer-routing branch from a767a25 to d160d31 Compare November 3, 2026 22:52
@williamloo-scale
williamloo-scale force-pushed the wloo/website-traffic-capture branch from 194572e to 3b757da Compare November 3, 2026 22:52
@williamloo-scale
williamloo-scale force-pushed the wloo/website-computer-routing branch from d160d31 to 5953d5a Compare November 3, 2026 23:53
@williamloo-scale
williamloo-scale force-pushed the wloo/website-traffic-capture branch from 3b757da to 73241f9 Compare November 4, 2026 00:00
@williamloo-scale
williamloo-scale force-pushed the wloo/website-computer-routing branch from 5953d5a to 9f2a5ca Compare November 4, 2026 00:32
@williamloo-scale
williamloo-scale force-pushed the wloo/website-traffic-capture branch from 73241f9 to 0192f08 Compare November 4, 2026 00:33
Comment thread src/agent_env/task/teardown.py Resolved
Comment thread src/agent_env/task/teardown.py Resolved
williamloo-scale and others added 5 commits November 3, 2026 17:16
… traffic/v1 (FD-4683)

This PR's change, rebased as one commit onto #448.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…refix of its own, and capture loopback too (FD-4683)

- The gateway's traffic/v1 get copies a capture before sending any of it, copying again when tcpdump truncates the
  file to reuse it, and answers 503 when every copy was rewritten.
- collect_traffic_capture writes each collection under its own attempt prefix, and the upload owns its temp file
  (finish_on_thread), so a cancelled collection never removes a file an upload still reads.
- tcpdump captures every interface of the container, its loopback among them.
- The read size and error limits are named.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… the env closes (FD-4683)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…collects a retry's rolled-back deployments too (FD-4683)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…time runs out partway (FD-4683)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@williamloo-scale
williamloo-scale force-pushed the wloo/website-computer-routing branch from 4283738 to 0cca3db Compare November 4, 2026 01:30
@williamloo-scale
williamloo-scale force-pushed the wloo/website-traffic-capture branch from 77c1ede to 965deb7 Compare November 4, 2026 01:30
Comment on lines +166 to +169
artifact = None
if files:
universe = FileArtifactUniverse.put(id=universe_id, file_artifacts=files)
artifact = {"id": universe.id, "version": universe.version}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Partial captures lose their links

_store saves the universe and its run reference only after every capture finishes. If teardown times out during a later download or upload, files already uploaded remain without a universe or run reference. The finally in collect_uncollected_captures saves only completed environment entries, so it cannot preserve these files. Teardown then removes the VM, preventing another attempt.

Save each completed file's reference as collection progresses, and preserve partial results when collection stops.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agent_env/task_step/task_steps/traffic_capture.py
Line: 166-169

Comment:
**Partial captures lose their links**

`_store` saves the universe and its run reference only after every capture finishes. If teardown times out during a later download or upload, files already uploaded remain without a universe or run reference. The `finally` in `collect_uncollected_captures` saves only completed environment entries, so it cannot preserve these files. Teardown then removes the VM, preventing another attempt.

Save each completed file's reference as collection progresses, and preserve partial results when collection stops.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Cursor Fix in Claude Code Fix in Codex

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant