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
21 changes: 21 additions & 0 deletions crates/code-server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,14 @@ fn parse_lane_transport_kind(raw: &str) -> Result<LaneTransportKind, String> {
}
}

/// Refuses `tools-agent` unless the operator opted in with `FRONTAL_CODE_SERVER_ALLOW_HOST_AGENT`.
fn check_host_agent_opt_in(kind: LaneTransportKind, allowed: bool) -> Result<(), String> {
if kind == LaneTransportKind::ToolsAgent && !allowed {
return Err("FRONTAL_CODE_SERVER_LANE_TRANSPORT=tools-agent runs agents with the server's privileges; set FRONTAL_CODE_SERVER_ALLOW_HOST_AGENT=1 to allow it, or use local-docker".to_string());
}
Ok(())
}

impl Default for ServerConfig {
fn default() -> Self {
Self {
Expand Down Expand Up @@ -231,6 +239,12 @@ impl ServerConfig {
if let Ok(kind) = env::var("FRONTAL_CODE_SERVER_LANE_TRANSPORT") {
config.lane_transport_kind = parse_lane_transport_kind(&kind)?;
}
// `tools-agent` runs the agent inside the server process with its privileges. It is
// refused unless the operator opts in, for example because the server already runs
// inside an isolated VM. `local-docker` (the default) isolates each task in a container.
let host_agent_allowed = env::var("FRONTAL_CODE_SERVER_ALLOW_HOST_AGENT")
.is_ok_and(|value| matches!(value.trim(), "1" | "true"));
check_host_agent_opt_in(config.lane_transport_kind, host_agent_allowed)?;

if let Ok(api_key) = env::var("FRONTAL_CODE_SERVER_API_KEY") {
let api_key = api_key.trim();
Expand Down Expand Up @@ -5284,6 +5298,13 @@ mod tests {
}
}

#[test]
fn host_agent_transport_requires_an_explicit_opt_in() {
assert!(check_host_agent_opt_in(LaneTransportKind::ToolsAgent, false).is_err());
assert!(check_host_agent_opt_in(LaneTransportKind::ToolsAgent, true).is_ok());
assert!(check_host_agent_opt_in(LaneTransportKind::LocalDocker, false).is_ok());
}

use super::*;
use axum::body::to_bytes;
use axum::body::Body;
Expand Down
3 changes: 3 additions & 0 deletions deploy/deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ env:
FRONTAL_CODE_SERVER_HOST: "0.0.0.0"
FRONTAL_CODE_SERVER_PORT: "8788"
FRONTAL_CODE_SERVER_LANE_TRANSPORT: "tools-agent"
FRONTAL_CODE_SERVER_ALLOW_HOST_AGENT: "1"
FRONTAL_CODE_SERVER_STATE_FILE: "/var/lib/frontal-code/server/state.json"
FRONTAL_CODE_SERVER_WORKSPACE_ROOT: "/workspace/workspaces"
FRONTAL_CODE_SERVER_RECONCILE_INTERVAL_SECS: "15"
Expand Down Expand Up @@ -36,6 +37,7 @@ machines:
FRONTAL_CODE_SERVER_HOST: "0.0.0.0"
FRONTAL_CODE_SERVER_PORT: "8788"
FRONTAL_CODE_SERVER_LANE_TRANSPORT: "tools-agent"
FRONTAL_CODE_SERVER_ALLOW_HOST_AGENT: "1"
FRONTAL_CODE_SERVER_STATE_FILE: "/var/lib/frontal-code/server/state.json"
FRONTAL_CODE_SERVER_WORKSPACE_ROOT: "/workspace/workspaces"
FRONTAL_CODE_SERVER_RECONCILE_INTERVAL_SECS: "15"
Expand All @@ -59,6 +61,7 @@ machines:
FRONTAL_CODE_SERVER_HOST: "0.0.0.0"
FRONTAL_CODE_SERVER_PORT: "8788"
FRONTAL_CODE_SERVER_LANE_TRANSPORT: "tools-agent"
FRONTAL_CODE_SERVER_ALLOW_HOST_AGENT: "1"
FRONTAL_CODE_SERVER_STATE_FILE: "/var/lib/frontal-code/server/state.json"
FRONTAL_CODE_SERVER_WORKSPACE_ROOT: "/workspace/workspaces"
FRONTAL_CODE_SERVER_RECONCILE_INTERVAL_SECS: "15"
Expand Down
2 changes: 2 additions & 0 deletions deploy/fly.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ primary_region = "iad"
FRONTAL_CODE_SERVER_HOST = "0.0.0.0"
FRONTAL_CODE_SERVER_PORT = "8788"
FRONTAL_CODE_SERVER_LANE_TRANSPORT = "tools-agent"
# Fly runs this server in its own microVM, which is the isolation boundary for host-side agents.
FRONTAL_CODE_SERVER_ALLOW_HOST_AGENT = "1"
FRONTAL_CODE_SERVER_STATE_FILE = "/var/lib/frontal-code/server/state.json"
FRONTAL_CODE_SERVER_WORKSPACE_ROOT = "/workspace/workspaces"
FRONTAL_CODE_SERVER_RECONCILE_INTERVAL_SECS = "15"
Expand Down
2 changes: 2 additions & 0 deletions docs/CONTAINERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ docker manifest push frontal-code/cli:multiarch

`code-server` runs each hosted task in its own worker container, built from `docker/worker.Dockerfile`. The image installs both command names, `frontal-code` and `code`; the hosted task runs `frontal-code hosted task run`. This is the default lane transport (`FRONTAL_CODE_SERVER_LANE_TRANSPORT=local-docker`).

`FRONTAL_CODE_SERVER_LANE_TRANSPORT=tools-agent` runs agents inside the server process with its privileges. The server refuses it unless `FRONTAL_CODE_SERVER_ALLOW_HOST_AGENT=1` is set. The managed deploy configs in `deploy/` and `infrastructure/` set that opt-in, because the platform VM or pod is their isolation boundary.

```bash
# Build the worker image from the workspace (the context is limited by .dockerignore)
docker build -f docker/worker.Dockerfile -t frontal-code-worker:local .
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/compose/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
FRONTAL_CODE_SERVER_HOST=0.0.0.0
FRONTAL_CODE_SERVER_PORT=8788
FRONTAL_CODE_SERVER_PUBLISH_ADDR=127.0.0.1
FRONTAL_CODE_SERVER_LANE_TRANSPORT=tools-agent
FRONTAL_CODE_SERVER_LANE_TRANSPORT=local-docker
FRONTAL_CODE_SERVER_API_KEY=replace-with-a-long-random-api-key
FRONTAL_CODE_SERVER_WORKSPACE_ROOT=/workspace/workspaces
FRONTAL_CODE_SERVER_DOCKER_IMAGE=frontal-code-worker:local
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/compose/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ services:
environment:
FRONTAL_CODE_SERVER_HOST: ${FRONTAL_CODE_SERVER_HOST:-0.0.0.0}
FRONTAL_CODE_SERVER_PORT: ${FRONTAL_CODE_SERVER_PORT:-8788}
FRONTAL_CODE_SERVER_LANE_TRANSPORT: ${FRONTAL_CODE_SERVER_LANE_TRANSPORT:-tools-agent}
FRONTAL_CODE_SERVER_LANE_TRANSPORT: ${FRONTAL_CODE_SERVER_LANE_TRANSPORT:-local-docker}
FRONTAL_CODE_SERVER_API_KEY: ${FRONTAL_CODE_SERVER_API_KEY:-}
FRONTAL_CODE_SERVER_WORKSPACE_ROOT: ${FRONTAL_CODE_SERVER_WORKSPACE_ROOT:-/workspace/workspaces}
FRONTAL_CODE_SERVER_DOCKER_IMAGE: ${FRONTAL_CODE_SERVER_DOCKER_IMAGE:-frontal-code-worker:local}
Expand Down
2 changes: 2 additions & 0 deletions infrastructure/kubernetes/base/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ data:
FRONTAL_CODE_SERVER_HOST: "0.0.0.0"
FRONTAL_CODE_SERVER_PORT: "8788"
FRONTAL_CODE_SERVER_LANE_TRANSPORT: "tools-agent"
# The pod is the isolation boundary for host-side agents; set to "0" to refuse them.
FRONTAL_CODE_SERVER_ALLOW_HOST_AGENT: "1"
FRONTAL_CODE_SERVER_RECONCILE_INTERVAL_SECS: "15"
FRONTAL_CODE_SERVER_ORPHAN_APPROVAL_DELAY_SECS: "0"
FRONTAL_CODE_SERVER_ORPHAN_AUTO_RETRY_SECS: "0"
Expand Down
2 changes: 2 additions & 0 deletions infrastructure/terraform/frontal-code-server.tf
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ resource "kubernetes_config_map" "frontal-code_server_config" {
"FRONTAL_CODE_SERVER_HOST" = "0.0.0.0"
"FRONTAL_CODE_SERVER_PORT" = "8788"
"FRONTAL_CODE_SERVER_LANE_TRANSPORT" = "tools-agent"
# The managed instance is the isolation boundary for host-side agents.
"FRONTAL_CODE_SERVER_ALLOW_HOST_AGENT" = "1"
"FRONTAL_CODE_SERVER_RECONCILE_INTERVAL_SECS" = "15"
"FRONTAL_CODE_SERVER_ORPHAN_APPROVAL_DELAY_SECS" = "0"
"FRONTAL_CODE_SERVER_ORPHAN_AUTO_RETRY_SECS" = "0"
Expand Down
Loading