From cd72ddc3809a9a0faacc05cb1ed0294de6df8dd8 Mon Sep 17 00:00:00 2001 From: scanash00 Date: Tue, 25 Aug 2026 03:49:13 -0800 Subject: [PATCH] fix custom app passwords --- crates/tranquil-api/src/server/session.rs | 18 +++++++++++++++ .../src/oauth/permission_set_resolver.rs | 22 ++++++++++++++----- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/crates/tranquil-api/src/server/session.rs b/crates/tranquil-api/src/server/session.rs index 9ac4444..36dc7a4 100644 --- a/crates/tranquil-api/src/server/session.rs +++ b/crates/tranquil-api/src/server/session.rs @@ -193,6 +193,24 @@ pub async fn create_session( ))); } }; + let app_password_scopes = match app_password_scopes { + Some(scopes) => { + let outcome = tranquil_pds::oauth::expand_scopes(state.cache.as_ref(), &scopes).await; + if !outcome.failures.is_empty() { + warn!( + app_password = app_password_name.as_deref().unwrap_or_default(), + failures = ?outcome.failures, + "App password permission bundle expansion failed" + ); + return Err(ApiError::AuthenticationFailed(Some( + "App password permissions could not be resolved; update the app password and try again" + .into(), + ))); + } + Some(outcome.to_scope_string()) + } + None => None, + }; let account_state = AccountState::from_db_fields( row.deactivated_at, row.takedown_ref.clone(), diff --git a/crates/tranquil-pds/src/oauth/permission_set_resolver.rs b/crates/tranquil-pds/src/oauth/permission_set_resolver.rs index defe864..993d605 100644 --- a/crates/tranquil-pds/src/oauth/permission_set_resolver.rs +++ b/crates/tranquil-pds/src/oauth/permission_set_resolver.rs @@ -165,19 +165,31 @@ mod tests { seed( &cache, "io.atcr.authFullApp", - "repo:io.atcr.manifest?action=create identity:*", + "repo:io.atcr.manifest identity:*", + ) + .await; + let out = expand_scopes( + &cache, + "atproto blob:application/vnd.oci.image.manifest.v1+json include:io.atcr.authFullApp rpc:com.atproto.repo.getRecord?aud=*", ) .await; - let out = expand_scopes(&cache, "atproto include:io.atcr.authFullApp").await; assert!(out.failures.is_empty()); - assert_eq!(out.passthrough, vec!["atproto".to_string()]); assert_eq!(out.sets.len(), 1); assert_eq!(out.sets[0].nsid, "io.atcr.authFullApp"); + let flattened = out.flat_scopes(); + assert!(flattened.iter().any(|s| s == "atproto")); assert!( - out.flat_scopes() + flattened + .iter() + .any(|s| s == "blob:application/vnd.oci.image.manifest.v1+json") + ); + assert!(flattened.iter().any(|s| s == "repo:io.atcr.manifest")); + assert!( + flattened .iter() - .any(|s| s == "repo:io.atcr.manifest?action=create") + .any(|s| s == "rpc:com.atproto.repo.getRecord?aud=*") ); + assert!(!flattened.iter().any(|s| s.starts_with("include:"))); } #[tokio::test] -- 2.51.2