mirror of
https://github.com/wirenboard/agent-vm.git
synced 2026-07-12 01:11:21 +00:00
agent-vm: fix long-session ECONNRESET burst + MCP proxy auth
Long Claude Code sessions in agent-vm (the failure mode users see
as "every 10 seconds, Retrying in 17s · attempt 6/10" until the
session is dead) were hitting a false positive in the secret-
substitution layer. When a session's prompt body contained the
literal name of any non-Anthropic placeholder string (e.g.
investigation sessions reading other sessions' jsonl), the scan
flagged the request, dropped the conn mid-upload, and undici
reported it as ECONNRESET. Retries hit the same content, same
violation; the session became permanently wedged from that turn on.
This commit pairs with the vendor change `secrets/handler: scope
violation scan to header bytes only`, which restricts the scan to
credential-bearing positions (Authorization / X-*-Key headers, URL
query params on the request line) and leaves user-supplied body
content alone. See the bumped submodule for full rationale.
Local changes:
* **secrets.rs**: add ANTHROPIC_MCP_PROXY_HOST. Claude Code's MCP
relay endpoint sends the same Anthropic access token but wasn't
in the placeholder's allowed_hosts list, so every MCP request
tripped the violation scan (also surfaced as ECONNRESET to the
MCP client). Allowing this host fixes MCP for in-VM Claude.
* **run.rs**: thread that new host into the network builder, and
add a focused post-mortem hint when `attach()` returns an error.
The hint points at the per-sandbox log files
(`~/.microsandbox/sandboxes/<name>/logs/{runtime.log,
msb.stderr.log,msb-exit.log}`) and suggests `dmesg -T | tail`
for host-OOM-kill cases. Surfaces what the vendor's `runtime:
tee msb stderr` change makes available.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
920f6c155c
commit
dbe92103b1
3 changed files with 41 additions and 5 deletions
|
|
@ -407,6 +407,7 @@ pub async fn launch(agent: Agent, args: Args) -> Result<i32> {
|
|||
.inject_basic_auth(false)
|
||||
.allow_host(ANTHROPIC_API_HOST)
|
||||
.allow_host(ANTHROPIC_OAUTH_HOST)
|
||||
.allow_host(ANTHROPIC_MCP_PROXY_HOST)
|
||||
});
|
||||
}
|
||||
if let Some(file) = openai {
|
||||
|
|
@ -622,10 +623,26 @@ pub async fn launch(agent: Agent, args: Args) -> Result<i32> {
|
|||
let t_run = Instant::now();
|
||||
let exit = if std::io::stdin().is_terminal() {
|
||||
eprintln!("==> Attaching to {inner_cmd}");
|
||||
sandbox
|
||||
.attach(cmd, agent_args)
|
||||
.await
|
||||
.with_context(|| format!("attaching to {inner_cmd}"))?
|
||||
match sandbox.attach(cmd, agent_args).await {
|
||||
Ok(code) => code,
|
||||
Err(err) => {
|
||||
// Print focused pointers to the post-mortem logs the
|
||||
// runtime writes (spawn.rs tees msb's stderr;
|
||||
// handle.rs appends to msb-exit.log on reap). The
|
||||
// raw-mode scopeguard inside attach_inner has already
|
||||
// restored the terminal by the time we see this Err.
|
||||
eprintln!("==> attach failed: {err:#}");
|
||||
eprintln!(
|
||||
"==> Post-mortem (if a VM death happened, the cause is usually in one of these):"
|
||||
);
|
||||
let log_dir = msb_sandbox_log_dir(&session.sandbox_name);
|
||||
eprintln!(" {}/runtime.log (msb tracing / panic)", log_dir.display());
|
||||
eprintln!(" {}/msb.stderr.log (libkrun / kernel printk / OOM)", log_dir.display());
|
||||
eprintln!(" {}/msb-exit.log (exit status of each boot)", log_dir.display());
|
||||
eprintln!(" dmesg -T | tail (host-side OOM-kill of the msb process)");
|
||||
return Err(err).with_context(|| format!("attaching to {inner_cmd}"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No host TTY (piped, redirected, smoke-tested under `sg`/`sudo` etc.).
|
||||
// attach() needs a real /dev/tty for raw-mode stdin, so use the
|
||||
|
|
@ -703,6 +720,20 @@ pub async fn launch(agent: Agent, args: Args) -> Result<i32> {
|
|||
Ok(exit)
|
||||
}
|
||||
|
||||
/// Best-effort guess at where msb writes per-sandbox runtime logs.
|
||||
/// Mirrors `microsandbox_utils::resolve_home()` / `sandboxes_dir()`:
|
||||
/// `$MSB_HOME` or `~/.microsandbox`, then `sandboxes/<name>/logs`.
|
||||
/// Used only for human-readable post-mortem hints, so a stale guess
|
||||
/// (e.g. caller overrode the home via config) just makes the hint
|
||||
/// slightly off rather than breaking anything.
|
||||
fn msb_sandbox_log_dir(sandbox_name: &str) -> PathBuf {
|
||||
let home = env::var_os("MSB_HOME")
|
||||
.map(PathBuf::from)
|
||||
.or_else(|| env::var_os("HOME").map(|h| PathBuf::from(h).join(".microsandbox")))
|
||||
.unwrap_or_else(|| PathBuf::from("/var/lib/microsandbox"));
|
||||
home.join("sandboxes").join(sandbox_name).join("logs")
|
||||
}
|
||||
|
||||
/// One `--mount HOST[:GUEST]` argument resolved into separate paths.
|
||||
struct ExtraMount {
|
||||
host: PathBuf,
|
||||
|
|
|
|||
|
|
@ -81,6 +81,11 @@ pub const GH_TOKEN_PLACEHOLDER: &str = "MSB_PLACEHOLDER_GH_TOKEN_v1";
|
|||
|
||||
pub const ANTHROPIC_API_HOST: &str = "api.anthropic.com";
|
||||
pub const ANTHROPIC_OAUTH_HOST: &str = "platform.claude.com";
|
||||
/// Claude Code's MCP relay endpoint. Claude Code's HTTP client sends
|
||||
/// the same Anthropic access token here, so the secret substitution
|
||||
/// has to allow this destination too — otherwise the placeholder
|
||||
/// trips the violation scan and the conn gets dropped, breaking MCP.
|
||||
pub const ANTHROPIC_MCP_PROXY_HOST: &str = "mcp-proxy.anthropic.com";
|
||||
pub const OPENAI_API_HOST: &str = "api.openai.com";
|
||||
pub const OPENAI_CHATGPT_HOST: &str = "chatgpt.com";
|
||||
pub const OPENAI_OAUTH_HOST: &str = "auth.openai.com";
|
||||
|
|
|
|||
2
vendor/microsandbox
vendored
2
vendor/microsandbox
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 4ad3a67f91e237aea2e4e295a086675ae37dddde
|
||||
Subproject commit db9865556d66e3a06cebb9583c6b83d5253a8bd0
|
||||
Loading…
Add table
Add a link
Reference in a new issue