From c0f956a984da1be7b0772351f7d73014808436f7 Mon Sep 17 00:00:00 2001 From: "warp-agent-staging[bot]" <240773466+warp-agent-staging[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2026 03:05:11 +0000 Subject: [PATCH 1/3] Add optional team_uid to sharer InitPayload. Session create needs the initiating view's team so warp-server can grant the initial team guest ACL to that team instead of GetTeamForPrincipal's lowest numeric team ID. Older payloads omit the field. --- src/sharer.rs | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/sharer.rs b/src/sharer.rs index 283cbff..b3d0a0a 100644 --- a/src/sharer.rs +++ b/src/sharer.rs @@ -281,6 +281,11 @@ pub struct InitPayload { /// Client feature support declaration. #[serde(default)] pub feature_support: FeatureSupport, + + /// Team the sharer is initiating the session from, when the selected view is team-scoped. + /// Absent or omitted for personal/unscoped views. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub team_uid: Option, } /// The reconnection token for a shared session. @@ -627,3 +632,59 @@ impl UpstreamMessage { } } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::common::{ + ActivePrompt, BlockId, InputReplicaId, Scrollback, Selection, UserID, WindowSize, + }; + + fn sample_init_payload(team_uid: Option) -> InitPayload { + InitPayload { + scrollback: Scrollback { + blocks: Vec::new(), + is_alt_screen_active: false, + }, + active_prompt: ActivePrompt::PS1, + window_size: WindowSize { + num_rows: 24, + num_cols: 80, + }, + user_id: UserID::default(), + selection: Selection::None, + init_block_id: BlockId::default(), + input_replica_id: InputReplicaId::default(), + telemetry_context: None, + lifetime: Lifetime::Ephemeral, + universal_developer_input_context: None, + source_type: SessionSourceType::User, + source_task_id: None, + feature_support: FeatureSupport::default(), + team_uid, + } + } + + #[test] + fn init_payload_deserializes_missing_team_uid_as_none() { + let json = serde_json::to_value(sample_init_payload(None)).unwrap(); + let mut without_team_uid = json.as_object().cloned().unwrap(); + without_team_uid.remove("team_uid"); + let payload: InitPayload = + serde_json::from_value(serde_json::Value::Object(without_team_uid)).unwrap(); + assert_eq!(payload.team_uid, None); + } + + #[test] + fn init_payload_omits_none_team_uid_and_round_trips_some() { + let none_json = serde_json::to_value(sample_init_payload(None)).unwrap(); + assert!(none_json.get("team_uid").is_none()); + + let team_uid = "team-uid-123".to_string(); + let some_json = serde_json::to_value(sample_init_payload(Some(team_uid.clone()))).unwrap(); + assert_eq!(some_json["team_uid"], team_uid); + + let payload: InitPayload = serde_json::from_value(some_json).unwrap(); + assert_eq!(payload.team_uid.as_deref(), Some(team_uid.as_str())); + } +} From 6c24d7408005e6c7c6e92a4de0ad66f991b885d7 Mon Sep 17 00:00:00 2001 From: "warp-agent-staging[bot]" <240773466+warp-agent-staging[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2026 05:16:08 +0000 Subject: [PATCH 2/3] Rename InitPayload team_uid to share_with_team_uid. The field grants initial viewer access to a team and does not change session ownership. firebase_uid remains the owner identity. --- src/sharer.rs | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/sharer.rs b/src/sharer.rs index b3d0a0a..df22d66 100644 --- a/src/sharer.rs +++ b/src/sharer.rs @@ -282,10 +282,10 @@ pub struct InitPayload { #[serde(default)] pub feature_support: FeatureSupport, - /// Team the sharer is initiating the session from, when the selected view is team-scoped. - /// Absent or omitted for personal/unscoped views. + /// Team granted initial viewer access when the selected view is team-scoped. + /// Does not change session ownership. Absent or omitted for personal/unscoped views. #[serde(default, skip_serializing_if = "Option::is_none")] - pub team_uid: Option, + pub share_with_team_uid: Option, } /// The reconnection token for a shared session. @@ -640,7 +640,7 @@ mod tests { ActivePrompt, BlockId, InputReplicaId, Scrollback, Selection, UserID, WindowSize, }; - fn sample_init_payload(team_uid: Option) -> InitPayload { + fn sample_init_payload(share_with_team_uid: Option) -> InitPayload { InitPayload { scrollback: Scrollback { blocks: Vec::new(), @@ -661,30 +661,34 @@ mod tests { source_type: SessionSourceType::User, source_task_id: None, feature_support: FeatureSupport::default(), - team_uid, + share_with_team_uid, } } #[test] - fn init_payload_deserializes_missing_team_uid_as_none() { + fn init_payload_deserializes_missing_share_with_team_uid_as_none() { let json = serde_json::to_value(sample_init_payload(None)).unwrap(); - let mut without_team_uid = json.as_object().cloned().unwrap(); - without_team_uid.remove("team_uid"); + let mut without_share_with_team_uid = json.as_object().cloned().unwrap(); + without_share_with_team_uid.remove("share_with_team_uid"); let payload: InitPayload = - serde_json::from_value(serde_json::Value::Object(without_team_uid)).unwrap(); - assert_eq!(payload.team_uid, None); + serde_json::from_value(serde_json::Value::Object(without_share_with_team_uid)).unwrap(); + assert_eq!(payload.share_with_team_uid, None); } #[test] - fn init_payload_omits_none_team_uid_and_round_trips_some() { + fn init_payload_omits_none_share_with_team_uid_and_round_trips_some() { let none_json = serde_json::to_value(sample_init_payload(None)).unwrap(); - assert!(none_json.get("team_uid").is_none()); + assert!(none_json.get("share_with_team_uid").is_none()); - let team_uid = "team-uid-123".to_string(); - let some_json = serde_json::to_value(sample_init_payload(Some(team_uid.clone()))).unwrap(); - assert_eq!(some_json["team_uid"], team_uid); + let share_with_team_uid = "team-uid-123".to_string(); + let some_json = + serde_json::to_value(sample_init_payload(Some(share_with_team_uid.clone()))).unwrap(); + assert_eq!(some_json["share_with_team_uid"], share_with_team_uid); let payload: InitPayload = serde_json::from_value(some_json).unwrap(); - assert_eq!(payload.team_uid.as_deref(), Some(team_uid.as_str())); + assert_eq!( + payload.share_with_team_uid.as_deref(), + Some(share_with_team_uid.as_str()) + ); } } From 5183d97ebac8de4f12315cf67b0198c2480554c4 Mon Sep 17 00:00:00 2001 From: "warp-agent-staging[bot]" <240773466+warp-agent-staging[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2026 14:15:34 +0000 Subject: [PATCH 3/3] Document omitted share_with_team_uid as legacy team fallback. Omission is not "no initial team share": the server keeps selecting the owner's default team for initial viewer access. --- src/sharer.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sharer.rs b/src/sharer.rs index df22d66..93898ac 100644 --- a/src/sharer.rs +++ b/src/sharer.rs @@ -282,8 +282,9 @@ pub struct InitPayload { #[serde(default)] pub feature_support: FeatureSupport, - /// Team granted initial viewer access when the selected view is team-scoped. - /// Does not change session ownership. Absent or omitted for personal/unscoped views. + /// Team granted initial viewer access. Does not change session ownership. + /// If omitted, the server preserves legacy behavior by selecting the owner's + /// default team for initial viewer access. #[serde(default, skip_serializing_if = "Option::is_none")] pub share_with_team_uid: Option, }