Skip to content

Commit 27d0fca

Browse files
Read workspace settings for a teamless scope, not a permissive constant
Isaiah's ruling for this stack is that falling back to workspace settings when the scope has no team is the intended behaviour. A hardcoded `UNRESTRICTED` was not that: on a sharing control it was potentially more permissive than the workspace's own policy. Drop the `has_teams()` guard so a teamless scope reads `current_workspace().settings` directly, and delete the constant, returning `workspace.rs` to master. The no-workspace arm stays permissive, preserving the `unwrap_or(true)` these getters had before they took a scope; there is no workspace policy to read there, and denying would newly hide the share UI while workspaces load.
1 parent c9e1c43 commit 27d0fca

3 files changed

Lines changed: 24 additions & 30 deletions

File tree

app/src/workspaces/user_workspaces.rs

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1951,12 +1951,12 @@ impl UserWorkspaces {
19511951
/// The link-sharing policy that governs `scope`.
19521952
///
19531953
/// A scope that resolves to a team reads that team's effective policy, so two windows on
1954-
/// different teams disagree exactly as their admins configured them.
1954+
/// different teams disagree exactly as their admins configured them. A scope with no team
1955+
/// falls back to the workspace's own settings, which never lets another team's policy
1956+
/// stand in for a team the scope does not have.
19551957
///
1956-
/// A scope with no team is not on a team, and no team's policy may stand in for that.
1957-
/// [`Self::current_workspace`]'s settings are only genuine workspace-level data while the
1958-
/// workspace has no teams; once it has any, the server resolved them for one arbitrarily
1959-
/// chosen team, so a teamless scope gets [`LinkSharingSettings::UNRESTRICTED`] instead.
1958+
/// With no workspace either there is nothing to govern the read, and both channels are
1959+
/// permitted -- the behaviour this getter had before it took a scope.
19601960
fn link_sharing_settings(&self, scope: &impl TeamScope) -> LinkSharingSettings {
19611961
if let Some(team) = self.team_from_scope(scope) {
19621962
let link_sharing = &team.settings.link_sharing;
@@ -1968,17 +1968,12 @@ impl UserWorkspaces {
19681968
};
19691969
}
19701970

1971-
// No window reaches this today: one is only registered teamless while the user has no
1972-
// teams, and `reconcile_window_team_assignments` moves it onto a team the moment any
1973-
// appear. It stops being dead the first time a caller reads a
1974-
// [`TeamContextForOperation`] captured before its window had a team.
1975-
if self.has_teams() {
1976-
return LinkSharingSettings::UNRESTRICTED;
1977-
}
1978-
19791971
self.current_workspace()
19801972
.map(|workspace| workspace.settings.link_sharing_settings.clone())
1981-
.unwrap_or(LinkSharingSettings::UNRESTRICTED)
1973+
.unwrap_or(LinkSharingSettings {
1974+
anyone_with_link_sharing_enabled: true,
1975+
direct_link_sharing_enabled: true,
1976+
})
19821977
}
19831978

19841979
/// Whether `scope` may share an object with anyone who holds its link.

app/src/workspaces/user_workspaces_tests.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,10 +1353,16 @@ fn test_link_sharing_resolves_each_windows_own_team() {
13531353
}
13541354

13551355
#[test]
1356-
fn test_link_sharing_for_a_teamless_window_ignores_the_users_other_teams() {
1357-
let (_, restricted_team) = a_sharing_team_and_a_restricted_team();
1358-
let mut workspace = workspace_for_test(&restricted_team);
1359-
workspace.settings.link_sharing_settings = LinkSharingSettings::default();
1356+
fn test_link_sharing_for_a_teamless_window_reads_the_workspace_not_another_team() {
1357+
let mut team = team_for_test();
1358+
// Deliberately the mirror image of the workspace's policy, so reading the wrong one of the
1359+
// two is visible in both channels rather than only one.
1360+
team.settings.link_sharing = team_link_sharing(false, true);
1361+
let mut workspace = workspace_for_test(&team);
1362+
workspace.settings.link_sharing_settings = LinkSharingSettings {
1363+
anyone_with_link_sharing_enabled: true,
1364+
direct_link_sharing_enabled: false,
1365+
};
13601366

13611367
App::test((), |mut app| async move {
13621368
initialize_window_team_test_app(&mut app, vec![workspace]);
@@ -1376,10 +1382,12 @@ fn test_link_sharing_for_a_teamless_window_ignores_the_users_other_teams() {
13761382

13771383
assert!(
13781384
user_workspaces.is_anyone_with_link_sharing_enabled(&scope),
1379-
"a window with no team is not on a team, so neither the restricting team's \
1380-
policy nor the workspace's teams[0] settings may govern it"
1385+
"a window with no team should read the workspace's own policy"
1386+
);
1387+
assert!(
1388+
!user_workspaces.is_direct_link_sharing_enabled(&scope),
1389+
"and must not pick up the policy of a team it is not on"
13811390
);
1382-
assert!(user_workspaces.is_direct_link_sharing_enabled(&scope));
13831391
});
13841392
})
13851393
}

app/src/workspaces/workspace.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -977,15 +977,6 @@ pub struct LinkSharingSettings {
977977
pub direct_link_sharing_enabled: bool,
978978
}
979979

980-
impl LinkSharingSettings {
981-
/// The policy in force when neither a team nor a workspace governs link sharing: both
982-
/// channels are permitted. Deliberately not `Default`, which is all-`false`.
983-
pub(crate) const UNRESTRICTED: Self = Self {
984-
anyone_with_link_sharing_enabled: true,
985-
direct_link_sharing_enabled: true,
986-
};
987-
}
988-
989980
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
990981
pub struct EnterpriseSecretRegex {
991982
pub pattern: String,

0 commit comments

Comments
 (0)