Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ By default a remote run uses **credential routing**: only requests that need a S
stashbase agent run --remote --remote-mode full --profile coding -- codex
```

`--remote-mode full` sends all agent traffic through the remote proxy, so the remote side sees and enforces policy on everything. Which modes you can use depends on your plan (Free: local only, Pro: credential routing, Scale: credential routing or full) and on workspace policy, which can enforce a mode. If a mode is not allowed, the CLI says which one is. In credential mode, requests to a host that is not routed cannot carry a credential placeholder; the relay refuses them (`proxy.credential_host_not_routed`) instead of sending the placeholder upstream. The audit log records the session's routing mode and, for each event, whether it went `remote` or `direct`; `stashbase agent audit --group-by route` summarizes the split. A remote HTTPS tunnel is opaque to the local relay, so for remote hosts the local log shows the connection and the requests inside it appear in the remote-side logs, while direct hosts get full per-request local logging. If Stashbase does not return a host list (an older service), the CLI falls back to `full` and says so.
`--remote-mode full` sends all agent traffic through the remote proxy, so the remote side sees and enforces policy on everything. Both modes are available on paid plans, and workspace policy can enforce one of them. A session also runs in `full` when a credential binding covers every host (`hosts = ["*"]` in the binding, not `egress_hosts = ["*"]`, which doesn't affect routing) and so can't be listed. If a mode is not allowed, the CLI says which one is. In credential mode, requests to a host that is not routed cannot carry a credential placeholder; the relay refuses them (`proxy.credential_host_not_routed`) instead of sending the placeholder upstream. The audit log records the session's routing mode and, for each event, whether it went `remote` or `direct`; `stashbase agent audit --group-by route` summarizes the split. A remote HTTPS tunnel is opaque to the local relay, so for remote hosts the local log shows the connection and the requests inside it appear in the remote-side logs, while direct hosts get full per-request local logging. If Stashbase does not return a host list (an older service), the CLI falls back to `full` and says so.

Remote Agent Proxy is not a general network sandbox; it relays supported HTTP traffic for supported coding-agent workflows. SSH, raw TCP, and arbitrary third-party integrations are unsupported.

Expand Down
12 changes: 9 additions & 3 deletions src/handlers/entry/root.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1164,7 +1164,7 @@ pub async fn handle_cli(args: Cli) -> Exit {
}
};
if !silent {
eprintln!("{}", routing_summary(&routing, session_request.routing_mode, session.route_hosts.is_some()));
eprintln!("{}", routing_summary(&routing, session_request.routing_mode, session.routing_mode.is_some()));
}
crate::telemetry::set_agent_run_remote_mode(routing.mode);
let routing = Arc::new(RwLock::new(routing));
Expand Down Expand Up @@ -2138,7 +2138,7 @@ fn ensure_replacement_session_is_compatible(
fn routing_summary(
routing: &crate::handlers::run::routing::RemoteRouting,
requested: Option<crate::handlers::run::routing::RemoteMode>,
sent_route_hosts: bool,
backend_sent_mode: bool,
) -> String {
use crate::handlers::run::routing::RemoteMode;
match routing.mode {
Expand All @@ -2153,7 +2153,7 @@ fn routing_summary(
"Routing: credential ({count} {noun} {verb} the Remote Agent Proxy; other traffic goes direct)"
)
}
RemoteMode::Full if requested == Some(RemoteMode::Credential) && !sent_route_hosts => {
RemoteMode::Full if requested == Some(RemoteMode::Credential) && !backend_sent_mode => {
"Routing: full (this Remote Agent Proxy does not support credential routing yet)"
.to_owned()
}
Expand Down Expand Up @@ -2916,6 +2916,12 @@ mod tests {
super::routing_summary(&RemoteRouting::full(), Some(RemoteMode::Full), true),
"Routing: full (all traffic uses the Remote Agent Proxy)"
);
// The service chose `full` itself (for example a binding that covers every
// host), so it does support credential routing.
assert_eq!(
super::routing_summary(&RemoteRouting::full(), Some(RemoteMode::Credential), true),
"Routing: full (all traffic uses the Remote Agent Proxy)"
);
assert_eq!(
super::routing_summary(&RemoteRouting::full(), Some(RemoteMode::Credential), false),
"Routing: full (this Remote Agent Proxy does not support credential routing yet)"
Expand Down
Loading