Merge pull request 'finish/jail-socket-and-doc-fixup' (#37) from finish/jail-socket-and-doc-fixup into main
Some checks are pending
CI / rust (push) Waiting to run
CI / markdown (push) Waiting to run

Reviewed-on: #37
This commit is contained in:
clawdie 2026-06-13 20:34:35 +02:00
commit 4490543284
5 changed files with 14 additions and 6 deletions

View file

@ -4,7 +4,7 @@ The Clawdie control plane core — a small, cross-platform (FreeBSD + Linux) Rus
daemon that unifies coordination (task board, agent registry, skills catalog)
with cache-first cost discipline (byte-stable prompt prefixes, cache-hit metering).
**Status:** 11 crates; workspace gates are expected to be fmt/clippy/test/release green. Avoid fixed test-count status here — run the gate commands below for the current count. Phase 3 (coordination core) is in progress.
**Status:** 10 crates; workspace gates are expected to be fmt/clippy/test/release green. Avoid fixed test-count status here — run the gate commands below for the current count. Phase 3 (coordination core) is in progress.
Next ISO integration plan: `docs/ISO-INTEGRATION-PLAN.md`.
ISO acceptance runbook: `docs/ISO-ACCEPTANCE-RUNBOOK.md`.

View file

@ -109,6 +109,7 @@ impl DaemonClient {
session_id,
system_prompt,
local_args: None,
jail: None,
})
.await
}

View file

@ -47,6 +47,9 @@ pub enum ColibriCommand {
/// to pass argv without a wrapper script).
#[serde(default)]
local_args: Option<Vec<String>>,
/// Optional FreeBSD jail confinement for the spawned agent.
#[serde(default)]
jail: Option<crate::spawner::JailConfig>,
},
#[serde(rename = "kill-agent")]
KillAgent { agent_id: String },

View file

@ -19,7 +19,7 @@ use tokio::select;
use tokio::sync::broadcast;
use tracing::{debug, error, info, trace, warn};
use crate::spawner::{AgentSpawnConfig, Provider, Spawner};
use crate::spawner::{AgentSpawnConfig, JailConfig, Provider, Spawner};
use crate::{ColibriCommand, ColibriResponse, SharedState};
// ---------------------------------------------------------------------------
@ -172,6 +172,7 @@ async fn dispatch(cmd: ColibriCommand, state: &SharedState) -> ColibriResponse {
session_id,
system_prompt,
local_args,
jail,
} => {
cmd_spawn_agent(
state,
@ -180,6 +181,7 @@ async fn dispatch(cmd: ColibriCommand, state: &SharedState) -> ColibriResponse {
session_id,
system_prompt,
local_args,
jail,
)
.await
}
@ -331,6 +333,7 @@ async fn cmd_spawn_agent(
session_id: Option<String>,
system_prompt: Option<String>,
local_args: Option<Vec<String>>,
jail: Option<JailConfig>,
) -> ColibriResponse {
let provider = match provider_str.to_lowercase().as_str() {
"deepseek" => Provider::DeepSeek,
@ -360,6 +363,7 @@ async fn cmd_spawn_agent(
model,
session_id: session_id.clone(),
system_prompt,
jail,
..Default::default()
};

View file

@ -122,9 +122,9 @@ there is no unprivileged path. But `colibri_daemon` runs as the unprivileged
cross that line — and we pick **per deployment context**, matching the
live-vs-deployed split.
The deciding fact: the ISO's mac*do rules are **identity** mappings, not command
The deciding fact: the ISO's `mac_do` rules are **identity** mappings, not command
filters — `security.mac.do.rules=gid=0>uid=0` (clawdie-iso `build.sh:1274`) means
"wheel may become root." mac_do **cannot** restrict \_which* command runs as root.
"wheel may become root." `mac_do` **cannot** restrict _which_ command runs as root.
| | `mdo -u root` | setuid/Capsicum helper |
| ------------------------------------- | ------------------------ | ---------------------- |
@ -134,10 +134,10 @@ filters — `security.mac.do.rules=gid=0>uid=0` (clawdie-iso `build.sh:1274`) me
| Root blast radius if daemon is popped | **full root** | **just jexec-pi** |
| Extra setup | one mac_do rule | helper + install |
Because mac*do is command-blind, **wrapping mdo in a helper does NOT narrow it**:
Because `mac_do` is command-blind, **wrapping mdo in a helper does NOT narrow it**:
once `colibri` may `mdo -u root`, a compromise just runs `mdo -u root sh`. The
helper is hygiene, not a boundary. Only a setuid/Capsicum helper (where colibri
is \_not* granted general root) is a true boundary.
is _not_ granted general root) is a true boundary.
### Decision