P6: browser.goto — real Chromium browsing with live web taint
- SandboxSpec gains an egress flag (default false — the kernel suite
still proves zero-network for agent sandboxes). Egress-enabled
containers exist ONLY for the browser: no credentials, no broker
route, bridge network with host-gateway alias for local test pages
- images/agent-browser: Alpine Chromium, uid 10001, setuid bits
stripped — same non-root hardening as agent-base
- browser.goto tool: headless chromium --dump-dom in the agent's
browser container; HTML stripped to readable text (4k cap) and
returned with output_taint=web; viewport screenshot captured,
base64'd out of the container, stored in the blob store
- Taint semantics tightened: the step that PRODUCED untrusted output
now carries its own taint (recorded before the step row), not just
later steps — chat.inbox test updated to the stricter §15 reading
- GET /api/claws/{id}/browser/viewport.png serves the latest capture;
BrowserApp polls it and renders the live viewport (spec §7.1),
keeping the empty state until the agent has browsed
- Proven end to end with REAL Chromium against a REAL local page:
content 'Revenue up 14 percent' returned tainted web; the gated
email.send that follows carries 'web' in its approval taint_sources
(untrusted content can never quietly reach outward); screenshot
verified by PNG magic bytes
152 Rust tests + 63 frontend + 27 Playwright journeys.
Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Fable 5
parent
7392ce1d08
commit
4f253bec93
@@ -20,6 +20,7 @@ impl std::fmt::Debug for SandboxManager {
|
||||
pub struct SandboxManager {
|
||||
driver: Arc<dyn SandboxDriver>,
|
||||
image: String,
|
||||
egress: bool,
|
||||
handles: Mutex<HashMap<AgentId, SandboxHandle>>,
|
||||
}
|
||||
|
||||
@@ -28,10 +29,18 @@ impl SandboxManager {
|
||||
SandboxManager {
|
||||
driver,
|
||||
image: image.to_owned(),
|
||||
egress: false,
|
||||
handles: Mutex::new(HashMap::new()),
|
||||
}
|
||||
}
|
||||
|
||||
/// The browser-container variant: egress on, no credentials inside,
|
||||
/// all output tainted `web` by the calling tool.
|
||||
pub fn with_egress(mut self) -> SandboxManager {
|
||||
self.egress = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Runs `sh -lc <command>` in the agent's sandbox, provisioning it on
|
||||
/// first use. The sandbox has no egress and no credentials — running
|
||||
/// agent-authored code here is the point of the architecture.
|
||||
@@ -49,6 +58,7 @@ impl SandboxManager {
|
||||
memory_bytes: 512 * 1024 * 1024,
|
||||
nano_cpus: 1_000_000_000,
|
||||
pids_limit: 256,
|
||||
egress: self.egress,
|
||||
};
|
||||
let handle = self
|
||||
.driver
|
||||
|
||||
Reference in New Issue
Block a user