Watch
0
0
Fork
You've already forked hyperhive
0

remove the get_host_journal MCP tool and its capability

swarm-logs covers every host-tier unit this tool could reach, so the
second, capability-gated path into host journald earns nothing and is
removed outright rather than disabled behind a flag.

Removed end to end: the MCP tool definition + handler, the
GetHostJournal/HostJournal wire variants, hive-c0re's
dispatch_host_journal handler, the ReadHostJournal capability, and the
harness-side capability->--allowedTools gate. get_host_journal was the
only capability that mapped to an MCP tool, so allowed_capability_tools
could only ever return an empty vec; it goes too rather than linger as a
function that provably does nothing.

capabilities::has_cap/caps_for stay: #4624 gave ManageRootAgent's
bind-mount enforcement (hive-c0re/src/lifecycle/host_config.rs) a
second caller of has_cap, so they're no longer callerless once this
lands on top of it.

hive-sh4re's journal module (JournalPriority) had no consumer outside
this tool and is deleted.

An existing capabilities.json still naming read_host_journal does not
error: capabilities::prune_unknown drops unrecognised names with a
warn!, and an agent left with no capabilities has its entry removed. No
migration step is needed.

Untouched: hive-c0re/src/dashboard/journal.rs's
read_host_journal_response, which matches the name but is the private
helper behind the operator-only GET /api/journal-host dashboard route
and carries no capability check.
This commit is contained in:
atlas 2026-09-21 19:20:05 +02:00
commit 11097ed336
18 changed files with 21 additions and 401 deletions

View file

@ -7,7 +7,7 @@
//!
//! ```json
//! {
//! "atlas": ["read_host_journal"]
//! "atlas": ["manage_root_agent"]
//! }
//! ```
//!
@ -167,9 +167,9 @@ mod tests {
#[test]
fn prune_unknown_keeps_known_name() {
let mut map = BTreeMap::from([("atlas".to_owned(), vec!["read_host_journal".to_owned()])]);
let mut map = BTreeMap::from([("atlas".to_owned(), vec!["manage_root_agent".to_owned()])]);
assert!(!prune_unknown(&mut map));
assert_eq!(map["atlas"], vec!["read_host_journal".to_owned()]);
assert_eq!(map["atlas"], vec!["manage_root_agent".to_owned()]);
}
#[test]
@ -183,23 +183,16 @@ mod tests {
fn prune_unknown_keeps_known_and_drops_unknown_in_same_entry() {
let mut map = BTreeMap::from([(
"atlas".to_owned(),
vec!["read_host_journal".to_owned(), "fly_to_the_moon".to_owned()],
vec!["manage_root_agent".to_owned(), "fly_to_the_moon".to_owned()],
)]);
assert!(prune_unknown(&mut map));
assert_eq!(map["atlas"], vec!["read_host_journal".to_owned()]);
}
#[test]
fn manage_root_agent_is_still_a_known_name() {
let mut map = BTreeMap::from([("atlas".to_owned(), vec!["manage_root_agent".to_owned()])]);
assert!(!prune_unknown(&mut map));
assert_eq!(map["atlas"], vec!["manage_root_agent".to_owned()]);
}
#[test]
fn apply_known_caps_removes_entry_on_empty_input() {
let mut current =
BTreeMap::from([("atlas".to_owned(), vec!["read_host_journal".to_owned()])]);
BTreeMap::from([("atlas".to_owned(), vec!["manage_root_agent".to_owned()])]);
apply_known_caps(&mut current, "atlas", &[]);
assert!(!current.contains_key("atlas"));
}
@ -207,7 +200,7 @@ mod tests {
#[test]
fn apply_known_caps_removes_entry_when_only_unknown_names_given() {
let mut current =
BTreeMap::from([("atlas".to_owned(), vec!["read_host_journal".to_owned()])]);
BTreeMap::from([("atlas".to_owned(), vec!["manage_root_agent".to_owned()])]);
apply_known_caps(&mut current, "atlas", &["fly_to_the_moon".to_owned()]);
assert!(!current.contains_key("atlas"));
}
@ -218,8 +211,8 @@ mod tests {
apply_known_caps(
&mut current,
"atlas",
&["read_host_journal".to_owned(), "fly_to_the_moon".to_owned()],
&["manage_root_agent".to_owned(), "fly_to_the_moon".to_owned()],
);
assert_eq!(current["atlas"], vec!["read_host_journal".to_owned()]);
assert_eq!(current["atlas"], vec!["manage_root_agent".to_owned()]);
}
}