diff --git a/crates/google-workspace-cli/src/auth_commands.rs b/crates/google-workspace-cli/src/auth_commands.rs index d7571e74..f84ddb23 100644 --- a/crates/google-workspace-cli/src/auth_commands.rs +++ b/crates/google-workspace-cli/src/auth_commands.rs @@ -289,6 +289,7 @@ pub const FULL_SCOPES: &[&str] = &[ "https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/spreadsheets", "https://www.googleapis.com/auth/gmail.modify", + "https://www.googleapis.com/auth/gmail.settings.basic", "https://www.googleapis.com/auth/calendar", "https://www.googleapis.com/auth/documents", "https://www.googleapis.com/auth/presentations", @@ -857,14 +858,20 @@ fn filter_redundant_restrictive_scopes(scopes: Vec) -> Vec { // broader scopes. Each entry maps a restrictive scope to the broader scopes // that make it redundant. The restrictive scope is removed only if at least // one of its broader alternatives is already in the list. - const RESTRICTIVE_SCOPES: &[(&str, &[&str])] = &[( - "https://www.googleapis.com/auth/gmail.metadata", - &[ - "https://mail.google.com/", - "https://www.googleapis.com/auth/gmail.modify", - "https://www.googleapis.com/auth/gmail.readonly", - ], - )]; + const RESTRICTIVE_SCOPES: &[(&str, &[&str])] = &[ + ( + "https://www.googleapis.com/auth/gmail.metadata", + &[ + "https://mail.google.com/", + "https://www.googleapis.com/auth/gmail.modify", + "https://www.googleapis.com/auth/gmail.readonly", + ], + ), + ( + "https://www.googleapis.com/auth/gmail.settings.basic", + &["https://mail.google.com/"], + ), + ]; let scope_set: std::collections::HashSet = scopes.iter().cloned().collect(); @@ -1549,6 +1556,10 @@ const SCOPE_ENTRIES: &[ScopeEntry] = &[ scope: "https://www.googleapis.com/auth/gmail.modify", label: "Gmail", }, + ScopeEntry { + scope: "https://www.googleapis.com/auth/gmail.settings.basic", + label: "Gmail Settings", + }, ScopeEntry { scope: "https://www.googleapis.com/auth/calendar", label: "Google Calendar", @@ -1745,6 +1756,9 @@ mod tests { let scopes = run_resolve_scopes(ScopeMode::Default, None); assert_eq!(scopes.len(), DEFAULT_SCOPES.len()); assert_eq!(scopes[0], "https://www.googleapis.com/auth/drive"); + assert!( + !scopes.contains(&"https://www.googleapis.com/auth/gmail.settings.basic".to_string()) + ); } #[test] @@ -1789,6 +1803,9 @@ mod tests { fn resolve_scopes_full_returns_full_scopes() { let scopes = run_resolve_scopes(ScopeMode::Full, None); assert_eq!(scopes.len(), FULL_SCOPES.len()); + assert!( + scopes.contains(&"https://www.googleapis.com/auth/gmail.settings.basic".to_string()) + ); } #[test] @@ -2360,6 +2377,26 @@ mod tests { assert_eq!(result, scopes); } + #[test] + fn filter_restrictive_removes_settings_basic_when_full_gmail_present() { + let scopes = vec![ + "https://mail.google.com/".to_string(), + "https://www.googleapis.com/auth/gmail.settings.basic".to_string(), + ]; + let result = filter_redundant_restrictive_scopes(scopes); + assert_eq!(result, vec!["https://mail.google.com/"]); + } + + #[test] + fn filter_restrictive_keeps_settings_basic_without_full_gmail() { + let scopes = vec![ + "https://www.googleapis.com/auth/gmail.modify".to_string(), + "https://www.googleapis.com/auth/gmail.settings.basic".to_string(), + ]; + let result = filter_redundant_restrictive_scopes(scopes.clone()); + assert_eq!(result, scopes); + } + #[test] fn mask_secret_long_string() { let masked = mask_secret("GOCSPX-abcdefghijklmnopqrstuvwxyz");