fix(#702): route container journal reads through hive-priv

The privsep drop to the hive-core user left four journalctl -M <container>
call sites shelling out directly. -M enters the container namespace via the
machine bus, which needs root, so all container-journal reads failed with
Permission denied. Add a ReadContainerJournal verb to hive-priv and route
dashboard get_journal, manager get_logs, the rebuild-failure journal tail,
and the agent host-journal -M path through it. Host-journal reads (no -M)
stay direct via systemd-journal group membership.
This commit is contained in:
müde 2026-06-02 23:43:02 +02:00
commit 9e12012a95
7 changed files with 279 additions and 65 deletions

View file

@ -378,6 +378,36 @@ pub async fn dispatch_host_journal(
};
}
let n = lines.unwrap_or(30).min(100);
// A container (`-M`) read enters the container namespace and needs
// root, so it's delegated to hive-priv. A host read (no container)
// the unprivileged hive-core user can do directly via its
// systemd-journal group membership.
if let Some(c) = container {
tracing::info!(%agent, machine = %c, %n, "get_host_journal (container)");
return match crate::priv_client::read_container_journal(
c,
n,
false,
hive_sh4re::priv_proto::JournalOutput::Short,
unit.clone(),
priority.as_ref().map(|p| p.as_str().to_owned()),
grep.clone(),
since.clone(),
until.clone(),
)
.await
{
Ok((stdout, stderr)) => {
let content = if !stdout.is_empty() { stdout } else { stderr };
AgentResponse::HostJournal { content }
}
Err(e) => AgentResponse::Err {
message: format!("journal read: {e:#}"),
},
};
}
let mut args: Vec<String> = vec![
"--no-pager".to_owned(),
"--output=short".to_owned(),
@ -388,10 +418,6 @@ pub async fn dispatch_host_journal(
args.push("-u".to_owned());
args.push(u.clone());
}
if let Some(c) = container {
args.push("-M".to_owned());
args.push(c.clone());
}
if let Some(p) = priority {
args.push("-p".to_owned());
args.push(p.as_str().to_owned());