diff options
| author | akbash <akbash@herdr.dev> | 2026-09-14 01:11:07 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-14 02:11:07 +0400 |
| commit | 3b478e69dcbe8e416ddd46f0e24156392d4e71da (patch) | |
| tree | e4ae8adfc09dce6eb09bd036fb727cc7f19edff7 /src/client/endpoint/control.rs | |
| parent | 4e1096b1018496a23fb9de7f9ae737d3792bb38b (diff) | |
fix: scope agent views to the selected machine (#3784)
* fix: scope agent views to the selected machine
refs #3732
* fix: preserve stable agent view ordering
refs #3732
---------
Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com>
Co-authored-by: JJ Liebig <jonathan.liebig@gmail.com>
Diffstat (limited to 'src/client/endpoint/control.rs')
| -rw-r--r-- | src/client/endpoint/control.rs | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/src/client/endpoint/control.rs b/src/client/endpoint/control.rs index 7cf1159f..6eef8dc8 100644 --- a/src/client/endpoint/control.rs +++ b/src/client/endpoint/control.rs @@ -1,7 +1,14 @@ use super::ClientEndpointId; +pub(crate) struct DecodedAgentViewProjection { + pub(crate) boot_id: String, + pub(crate) revision: u64, + pub(crate) view: Result<Option<crate::api::schema::AgentViewSetParams>, ()>, +} + pub(crate) enum EndpointControlMessage { HealthPong, + AgentViewProjection(DecodedAgentViewProjection), Snapshot(Box<crate::protocol::ClientShellSnapshot>), Ignored, } @@ -13,6 +20,33 @@ pub(crate) fn decode_endpoint_control( if kind == crate::protocol::endpoint::HEALTH_PONG_KIND { return Ok(EndpointControlMessage::HealthPong); } + if kind == crate::protocol::endpoint::AGENT_VIEW_PROJECTION_KIND { + let Ok(projection): Result<crate::protocol::endpoint::EndpointAgentViewProjection, _> = + serde_json::from_str(data) + else { + return Ok(EndpointControlMessage::Ignored); + }; + let view = match projection.view { + Some(value) => serde_json::from_value(value) + .map(Some) + .map_err(|_| ()) + .and_then(|mut view| { + view.as_mut() + .map(crate::app::agent_view::validate_agent_view) + .transpose() + .map(|_| view) + .map_err(|_| ()) + }), + None => Ok(None), + }; + return Ok(EndpointControlMessage::AgentViewProjection( + DecodedAgentViewProjection { + boot_id: projection.boot_id, + revision: projection.revision, + view, + }, + )); + } if kind == crate::protocol::endpoint::ENDPOINT_SNAPSHOT_KIND { let snapshot = serde_json::from_str(data) .map_err(|error| format!("invalid endpoint snapshot: {error}"))?; @@ -44,6 +78,63 @@ mod tests { } #[test] + fn agent_view_projection_decodes_and_validates_the_view() { + let view = crate::api::schema::AgentViewSetParams { + source: "example.views".into(), + label: Some("focus".into()), + filter: None, + sort: Vec::new(), + }; + let crate::protocol::ServerMessage::EndpointControl { kind, data } = + crate::protocol::endpoint::agent_view_projection_message("boot", 4, Some(&view)) + .unwrap() + else { + panic!("projection control"); + }; + let EndpointControlMessage::AgentViewProjection(decoded) = + decode_endpoint_control(&kind, &data).unwrap() + else { + panic!("decoded projection"); + }; + assert_eq!(decoded.boot_id, "boot"); + assert_eq!(decoded.revision, 4); + assert_eq!(decoded.view, Ok(Some(view))); + } + + #[test] + fn unsupported_agent_view_payload_falls_back_without_rejecting_endpoint() { + let projection = crate::protocol::endpoint::EndpointAgentViewProjection { + boot_id: "boot".into(), + revision: 5, + view: Some(serde_json::json!({ + "source": "example.views", + "filter": {"op": "future_filter"} + })), + }; + let decoded = decode_endpoint_control( + crate::protocol::endpoint::AGENT_VIEW_PROJECTION_KIND, + &serde_json::to_string(&projection).unwrap(), + ) + .unwrap(); + let EndpointControlMessage::AgentViewProjection(decoded) = decoded else { + panic!("decoded projection"); + }; + assert_eq!(decoded.view, Err(())); + } + + #[test] + fn malformed_agent_view_envelope_is_ignored() { + assert!(matches!( + decode_endpoint_control( + crate::protocol::endpoint::AGENT_VIEW_PROJECTION_KIND, + "not json" + ) + .unwrap(), + EndpointControlMessage::Ignored + )); + } + + #[test] fn unknown_snapshot_codecs_are_rejected() { assert_eq!( decode_endpoint_control("shell.snapshot.v2", "{}") |
