Files
harmony/fleet/harmony-fleet-agent/Cargo.toml
Jean-Gabriel Gill-Couture 6893813f48 feat(fleet): device exec + container log tail over NATS
Operator→agent request/reply gains an `exec` verb (the protocol's
second, after `ping`). The dashboard's "Run command" tab and the
device log panels now reach a real device instead of stubs.

- contracts: `Verb::Exec`, `CommandRequest::Exec`, `ExecReply`
  (capped output + truncated flag). Reuses the existing
  `device-commands.<id>.>` subject — no callout permission change.
- agent: command server runs `sh -c` with a 25s deadline
  (kill_on_drop), captures stdout/stderr capped at 256 KiB.
- operator: `FleetCommandsClient::exec` (30s timeout); thread the
  authenticated NATS client into `RealFleetService` via
  `spawn_dashboard`. `run_command` and a new `device_logs`
  (`podman logs --tail 200` of the device's deployment container)
  compose exec — no separate logs verb at n=1.
- frontend: replace the fake SSE log stream with a one-shot
  `/devices/{id}/logs/tail` fetch (load + Refresh), CSP-safe;
  auto-scroll to the latest line.

serve-web (no NATS) returns a clear "not configured" error for these
two actions; the deployed operator wires them.
2026-06-02 06:38:54 -04:00

25 lines
845 B
TOML

[package]
name = "harmony-fleet-agent"
version = "0.1.0"
edition = "2024"
rust-version = "1.85"
[dependencies]
harmony-fleet-auth = { path = "../harmony-fleet-auth" }
harmony-reconciler-contracts = { path = "../../harmony-reconciler-contracts" }
harmony = { path = "../../harmony", default-features = false, features = ["podman"] }
async-nats = { workspace = true }
async-trait = { workspace = true }
chrono = { workspace = true }
futures-util = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
# `process` is agent-local: only the exec command server shells out.
tokio = { workspace = true, features = ["process"] }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
anyhow = { workspace = true }
clap = { workspace = true }
toml = { workspace = true }
thiserror = { workspace = true }