From c28da210b45db0289537c419f3b3cf089583aa4b Mon Sep 17 00:00:00 2001 From: atlas Date: Fri, 11 Sep 2026 16:06:20 +0200 Subject: [PATCH 1/2] scheduling: clamp get_logs host-side, and fix two authorization claims MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `docs/tools/scheduling.md` said three things about who may do what. Two were wrong prose; the third was the code. "All scheduling ops go through the operator approval queue" — one of the five does. Cancel, edit, list and fire are `require_group("scheduling")` and nothing else (socket_server/mod.rs:594-643), which is what the MCP tool descriptions already tell an agent. The page pushed in the cautious direction: someone watching a runaway recurring schedule would wait for an operator rather than cancel it themselves. The authorization sentence covered "read/cancel/edit". Cancel, edit and fire really do check `cancel_authorized` (self, operator, or subtree) from three call sites. `handle_list_schedules` takes no requester at all and returns every row — now stated, along with the part that matters: the snapshot includes other agents' schedule bodies. `lines` was documented as "host-capped at 500" and the 500 was in the agent's own MCP layer, not the host; `handle_get_logs` passed any u32 straight into JournalQuery. A limit in the caller is not a limit, so the host clamps instead of the sentence changing. That also makes args.rs's arg doc and the tool description agents read correct, untouched. The sibling `get_host_journal` already clamps host-side at 100, which is both the precedent and the control that the missing clamp here was real. Closes #4230. --- docs/tools/scheduling.md | 21 ++++++++++++++++----- hive-c0re/src/socket_server/mod.rs | 5 ++++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/docs/tools/scheduling.md b/docs/tools/scheduling.md index 57e00328..c10374f5 100644 --- a/docs/tools/scheduling.md +++ b/docs/tools/scheduling.md @@ -3,11 +3,18 @@ ## `scheduling` tool group Scheduled prompts fan a message body out to one or more agent inboxes -at a future time, optionally recurring. All scheduling ops go through -the operator approval queue (even self-targeted schedules — use -`remind` for unapproved self-wake). Authorization for read/cancel/edit -ops: you can act on schedules you own or any owned by a sub-agent in -your topology subtree. +at a future time, optionally recurring. + +**Creating** one goes through the operator approval queue, even when it +targets only yourself — use `remind` for an unapproved self-wake. The +other four verbs need no approval: holding the `scheduling` tool group +is the whole gate. + +Authorization for cancel / edit / fire: you can act on schedules you own +or any owned by an agent in your topology subtree. **`list_schedules` is +not scoped at all** — it returns every schedule on the hive, bodies +included, which is what makes it useful for auditing and worth knowing +before you put anything private in a schedule body. ### `request_schedule_prompt(targets, body, first_fire_at_unix, interval_seconds?, description?)` @@ -55,6 +62,10 @@ and `last_result`, `next_fire_at_unix`, `interval_seconds`. Use to look up an id before cancelling, or to audit upcoming wake-ups in your subtree. +Unscoped on purpose — unlike the verbs that _change_ a schedule, this +one applies no ownership filter, so the snapshot covers other agents' +schedules and the operator's. + ## `diagnostics` tool group ### `get_logs(agent, lines?)` diff --git a/hive-c0re/src/socket_server/mod.rs b/hive-c0re/src/socket_server/mod.rs index ec50aafe..e73a0e45 100644 --- a/hive-c0re/src/socket_server/mod.rs +++ b/hive-c0re/src/socket_server/mod.rs @@ -1121,7 +1121,10 @@ pub(crate) fn handle_send( /// `-M` read needs root). `journalctl -M` wants the `h-` machine /// name, which `container_name` derives. async fn handle_get_logs(agent: &str, lines: Option) -> Response { - let n = lines.unwrap_or(50); + // Clamped here and not only in the MCP layer that also clamps it: a + // caller-side limit is not a limit, and anything speaking this socket + // sets `lines` itself. Mirrors `handle_get_host_journal`'s own cap. + let n = lines.unwrap_or(50).min(500); let machine = crate::lifecycle::container_name(agent); tracing::info!(%agent, %machine, %n, "manager: get_logs"); match crate::priv_client::read_container_journal( From 6d7565a30d9013852849f616996cdf71181b2795 Mon Sep 17 00:00:00 2001 From: atlas Date: Fri, 11 Sep 2026 17:35:37 +0200 Subject: [PATCH 2/2] scheduling.md: drop the list_schedules prose, keep the approval-scope fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mara's call on this PR was "list schedules not being scoped at all is a bug - dont document it, file the bug and fix it". The bug is fixed in damocles's separate PR, which also rewrites this page's `list_schedules()` section. So both of my paragraphs about scoping go: the "not scoped at all" sentence in the intro (documenting the bug, which is what she objected to) and the follow-up in the `list_schedules()` section. That section is now byte-identical to main again, leaving it entirely to the PR that changes the behaviour — the two PRs no longer touch a common hunk in this file. What stays is the claim this PR was actually filed for: the page said "All scheduling ops go through the operator approval queue", and only creating one does. The intro now splits creating from the other four verbs and states the one authorization rule that covers all of them, which the scoping fix makes true. --- docs/tools/scheduling.md | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/docs/tools/scheduling.md b/docs/tools/scheduling.md index c10374f5..5b7b6517 100644 --- a/docs/tools/scheduling.md +++ b/docs/tools/scheduling.md @@ -10,11 +10,10 @@ targets only yourself — use `remind` for an unapproved self-wake. The other four verbs need no approval: holding the `scheduling` tool group is the whole gate. -Authorization for cancel / edit / fire: you can act on schedules you own -or any owned by an agent in your topology subtree. **`list_schedules` is -not scoped at all** — it returns every schedule on the hive, bodies -included, which is what makes it useful for auditing and worth knowing -before you put anything private in a schedule body. +Authorization is one rule for all four verbs: you reach schedules you own +and any owned by an agent in your topology subtree. `list_schedules` +applies it too, so the snapshot only ever shows schedules you could also +cancel. ### `request_schedule_prompt(targets, body, first_fire_at_unix, interval_seconds?, description?)` @@ -62,10 +61,6 @@ and `last_result`, `next_fire_at_unix`, `interval_seconds`. Use to look up an id before cancelling, or to audit upcoming wake-ups in your subtree. -Unscoped on purpose — unlike the verbs that _change_ a schedule, this -one applies no ownership filter, so the snapshot covers other agents' -schedules and the operator's. - ## `diagnostics` tool group ### `get_logs(agent, lines?)`