Our Personal Data Server from scratch!
0

Configure Feed

Select the types of activity you want to include in your feed.

refactor: clean up property names and document stringy values

Signed-off-by: Trezy <tre@trezy.com>

author
Trezy
committer
Tangled
date (Jul 24, 2026, 8:11 PM +0300) commit 7244551a parent 01d93e44
+195 -121
+23 -25
crates/tranquil-oauth-server/src/endpoints/authorize/consent.rs
··· 29 29 30 30 #[derive(Debug, Serialize)] 31 31 pub struct FailedSetInfo { 32 - pub nsid: String, 33 - #[serde(skip_serializing_if = "Option::is_none")] 34 - pub aud: Option<String>, 32 + // `given_*` is the value as requested by the client. 33 + // Left as strings because the value from the client could be malformed. 34 + #[serde(rename = "nsid")] 35 + pub given_nsid: String, 36 + #[serde(rename = "aud", skip_serializing_if = "Option::is_none")] 37 + pub given_aud: Option<String>, 35 38 pub reason: tranquil_scopes::ResolveFailure, 36 39 } 37 40 ··· 147 150 Some(grant) => scope_resolution::Authority::Delegated(&grant.granted_scopes), 148 151 None => scope_resolution::Authority::FullSelf, 149 152 }; 150 - let effective = scope_resolution::resolve_effective_scopes( 151 - &*state.cache, 152 - requested_scope_str, 153 - authority, 154 - ) 155 - .await; 156 - let requested_scopes: Vec<&str> = effective.resolved.split_whitespace().collect(); 153 + let effective = 154 + scope_resolution::resolve_effective_scopes(&*state.cache, requested_scope_str, authority) 155 + .await; 156 + let requested_scopes: Vec<&str> = effective.permitted.split_whitespace().collect(); 157 157 let preferences = state 158 158 .repos 159 159 .oauth ··· 184 184 .unwrap_or(true); 185 185 let has_granular_scopes = requested_scopes.iter().any(|s| is_granular_scope(s)); 186 186 187 - let grant_scope_str: Option<&str> = delegation_grant 188 - .as_ref() 189 - .map(|g| g.granted_scopes.as_str()); 187 + let grant_scope_str: Option<&str> = 188 + delegation_grant.as_ref().map(|g| g.granted_scopes.as_str()); 190 189 let is_restricted = |scope: &str| -> bool { 191 190 grant_scope_str.is_some_and(|g| !tranquil_pds::delegation::grant_covers(g, scope)) 192 191 }; ··· 254 253 Some(a) => format!("include:{}?aud={}", g.nsid, a), 255 254 None => format!("include:{}", g.nsid), 256 255 }; 257 - let expanded: Vec<ScopeInfo> = 258 - g.expanded.iter().map(|s| make_scope_info(s)).collect(); 256 + let expanded: Vec<ScopeInfo> = g.expanded.iter().map(|s| make_scope_info(s)).collect(); 259 257 let restricted = !expanded.is_empty() && expanded.iter().all(|s| s.restricted); 260 258 PermissionSetInfo { 261 259 nsid: g.nsid.clone(), ··· 275 273 .failures 276 274 .iter() 277 275 .map(|f| FailedSetInfo { 278 - nsid: f.nsid.clone(), 279 - aud: f.aud.clone(), 276 + given_nsid: f.given_nsid.clone(), 277 + given_aud: f.given_aud.clone(), 280 278 reason: f.reason.clone(), 281 279 }) 282 280 .collect(); ··· 422 420 Some(grant) => scope_resolution::Authority::Delegated(&grant.granted_scopes), 423 421 None => scope_resolution::Authority::FullSelf, 424 422 }; 425 - let effective = scope_resolution::resolve_effective_scopes( 426 - &*state.cache, 427 - original_scope_str, 428 - authority, 429 - ) 430 - .await; 423 + let effective = 424 + scope_resolution::resolve_effective_scopes(&*state.cache, original_scope_str, authority) 425 + .await; 431 426 let include_token = |nsid: &str, aud: &Option<String>| -> String { 432 427 match aud { 433 428 Some(a) => format!("include:{}?aud={}", nsid, a), ··· 438 433 .outcome 439 434 .failures 440 435 .iter() 441 - .filter(|f| form.approved_scopes.contains(&include_token(&f.nsid, &f.aud))) 442 - .map(|f| f.nsid.clone()) 436 + .filter(|f| { 437 + form.approved_scopes 438 + .contains(&include_token(&f.given_nsid, &f.given_aud)) 439 + }) 440 + .map(|f| f.given_nsid.clone()) 443 441 .collect(); 444 442 if !approved_failed_sets.is_empty() { 445 443 return json_error(
+54 -20
crates/tranquil-oauth-server/src/endpoints/authorize/scope_resolution.rs
··· 10 10 } 11 11 12 12 pub struct EffectiveScopes { 13 - pub resolved: String, 13 + // The expanded set of scopes, minus any denied by delegation 14 + pub permitted: String, 15 + // The expanded set of scopes, before delegation processing 14 16 pub outcome: ExpansionOutcome, 15 17 } 16 18 ··· 21 23 ) -> EffectiveScopes { 22 24 let outcome = expand_scopes(cache, requested).await; 23 25 let expanded = outcome.to_scope_string(); 24 - let resolved = match authority { 26 + let permitted = match authority { 25 27 Authority::FullSelf => expanded, 26 28 Authority::Delegated(granted) => intersect_scopes(&expanded, granted.as_str()), 27 29 }; 28 - EffectiveScopes { resolved, outcome } 30 + EffectiveScopes { permitted, outcome } 29 31 } 30 32 31 33 #[cfg(test)] ··· 40 42 struct MapCache(Mutex<HashMap<String, String>>); 41 43 #[async_trait::async_trait] 42 44 impl Cache for MapCache { 43 - async fn get(&self, k: &str) -> Option<String> { self.0.lock().unwrap().get(k).cloned() } 45 + async fn get(&self, k: &str) -> Option<String> { 46 + self.0.lock().unwrap().get(k).cloned() 47 + } 44 48 async fn set(&self, k: &str, v: &str, _t: Duration) -> Result<(), CacheError> { 45 - self.0.lock().unwrap().insert(k.into(), v.into()); Ok(()) 49 + self.0.lock().unwrap().insert(k.into(), v.into()); 50 + Ok(()) 51 + } 52 + async fn delete(&self, k: &str) -> Result<(), CacheError> { 53 + self.0.lock().unwrap().remove(k); 54 + Ok(()) 55 + } 56 + async fn get_bytes(&self, _k: &str) -> Option<Vec<u8>> { 57 + None 58 + } 59 + async fn set_bytes(&self, _k: &str, _v: &[u8], _t: Duration) -> Result<(), CacheError> { 60 + Ok(()) 46 61 } 47 - async fn delete(&self, k: &str) -> Result<(), CacheError> { self.0.lock().unwrap().remove(k); Ok(()) } 48 - async fn get_bytes(&self, _k: &str) -> Option<Vec<u8>> { None } 49 - async fn set_bytes(&self, _k: &str, _v: &[u8], _t: Duration) -> Result<(), CacheError> { Ok(()) } 50 62 } 51 63 52 64 fn cache_with(nsid: &str, scopes: &str) -> MapCache { 53 65 let c = MapCache::default(); 54 - let key = tranquil_pds::cache_keys::permission_set_key(&tranquil_types::Nsid::new(nsid).unwrap(), None); 66 + let key = tranquil_pds::cache_keys::permission_set_key( 67 + &tranquil_types::Nsid::new(nsid).unwrap(), 68 + None, 69 + ); 55 70 let json = serde_json::json!({ 56 71 "scope": scopes, 57 72 "title": null, ··· 65 80 66 81 #[tokio::test] 67 82 async fn full_self_keeps_all_expanded() { 68 - let c = cache_with("io.atcr.authFullApp", "repo:io.atcr.manifest?action=create identity:*"); 69 - let eff = resolve_effective_scopes(&c, "atproto include:io.atcr.authFullApp", Authority::FullSelf).await; 70 - assert!(eff.resolved.contains("atproto")); 71 - assert!(eff.resolved.contains("repo:io.atcr.manifest?action=create")); 72 - assert!(eff.resolved.contains("identity:*")); 83 + let c = cache_with( 84 + "io.atcr.authFullApp", 85 + "repo:io.atcr.manifest?action=create identity:*", 86 + ); 87 + let eff = resolve_effective_scopes( 88 + &c, 89 + "atproto include:io.atcr.authFullApp", 90 + Authority::FullSelf, 91 + ) 92 + .await; 93 + assert!(eff.permitted.contains("atproto")); 94 + assert!( 95 + eff.permitted 96 + .contains("repo:io.atcr.manifest?action=create") 97 + ); 98 + assert!(eff.permitted.contains("identity:*")); 73 99 assert!(eff.outcome.failures.is_empty()); 74 100 } 75 101 76 102 #[tokio::test] 77 103 async fn delegated_intersects_expanded_against_grant() { 78 - let c = cache_with("io.atcr.authFullApp", "repo:io.atcr.manifest?action=create identity:*"); 104 + let c = cache_with( 105 + "io.atcr.authFullApp", 106 + "repo:io.atcr.manifest?action=create identity:*", 107 + ); 79 108 let granted = DbScope::new("atproto repo:* blob:*/* account:*?action=manage").unwrap(); 80 109 let eff = resolve_effective_scopes( 81 - &c, "atproto include:io.atcr.authFullApp", 110 + &c, 111 + "atproto include:io.atcr.authFullApp", 82 112 Authority::Delegated(&granted), 83 - ).await; 84 - assert!(eff.resolved.contains("atproto")); 85 - assert!(eff.resolved.contains("repo:io.atcr.manifest?action=create")); 86 - assert!(!eff.resolved.contains("identity")); 113 + ) 114 + .await; 115 + assert!(eff.permitted.contains("atproto")); 116 + assert!( 117 + eff.permitted 118 + .contains("repo:io.atcr.manifest?action=create") 119 + ); 120 + assert!(!eff.permitted.contains("identity")); 87 121 } 88 122 }
+36 -34
crates/tranquil-oauth-server/src/endpoints/token/grants.rs
··· 133 133 let controller_did = authorized.controller_did.clone(); 134 134 let requested_scope = authorized.parameters.scope.clone(); 135 135 136 - let granted_scopes: Option<tranquil_db_traits::DbScope> = if let Some(ref controller) = controller_did { 137 - let grant = state 138 - .repos 139 - .delegation 140 - .get_delegation(&did, controller) 141 - .await 142 - .ok() 143 - .flatten() 144 - .ok_or_else(|| { 145 - OAuthError::InvalidGrant("Delegation grant not found or revoked".to_string()) 146 - })?; 147 - Some(grant.granted_scopes.clone()) 148 - } else { 149 - None 150 - }; 136 + let granted_scopes: Option<tranquil_db_traits::DbScope> = 137 + if let Some(ref controller) = controller_did { 138 + let grant = state 139 + .repos 140 + .delegation 141 + .get_delegation(&did, controller) 142 + .await 143 + .ok() 144 + .flatten() 145 + .ok_or_else(|| { 146 + OAuthError::InvalidGrant("Delegation grant not found or revoked".to_string()) 147 + })?; 148 + Some(grant.granted_scopes.clone()) 149 + } else { 150 + None 151 + }; 151 152 let authority = match granted_scopes.as_ref() { 152 153 Some(g) => crate::endpoints::authorize::scope_resolution::Authority::Delegated(g), 153 154 None => crate::endpoints::authorize::scope_resolution::Authority::FullSelf, ··· 164 165 .outcome 165 166 .failures 166 167 .iter() 167 - .map(|f| f.nsid.clone()) 168 + .map(|f| f.given_nsid.clone()) 168 169 .collect(); 169 170 return Err(OAuthError::InvalidScope(format!( 170 171 "Could not resolve permission set(s): {}", 171 172 names.join(", ") 172 173 ))); 173 174 } 174 - let resolved_scope = effective.resolved; 175 + let resolved_scope = effective.permitted; 175 176 176 177 let access_token = create_access_token_with_delegation( 177 178 &token_id, ··· 254 255 token_data: &TokenData, 255 256 ) -> Result<String, OAuthError> { 256 257 let requested = token_data.scope.as_deref().unwrap_or("atproto"); 257 - let granted_scopes: Option<tranquil_db_traits::DbScope> = if let Some(ref controller) = token_data.controller_did { 258 - let grant = state 259 - .repos 260 - .delegation 261 - .get_delegation(&token_data.did, controller) 262 - .await 263 - .ok() 264 - .flatten() 265 - .ok_or_else(|| { 266 - OAuthError::InvalidGrant("Delegation grant not found or revoked".to_string()) 267 - })?; 268 - Some(grant.granted_scopes.clone()) 269 - } else { 270 - None 271 - }; 258 + let granted_scopes: Option<tranquil_db_traits::DbScope> = 259 + if let Some(ref controller) = token_data.controller_did { 260 + let grant = state 261 + .repos 262 + .delegation 263 + .get_delegation(&token_data.did, controller) 264 + .await 265 + .ok() 266 + .flatten() 267 + .ok_or_else(|| { 268 + OAuthError::InvalidGrant("Delegation grant not found or revoked".to_string()) 269 + })?; 270 + Some(grant.granted_scopes.clone()) 271 + } else { 272 + None 273 + }; 272 274 let authority = match granted_scopes.as_ref() { 273 275 Some(g) => crate::endpoints::authorize::scope_resolution::Authority::Delegated(g), 274 276 None => crate::endpoints::authorize::scope_resolution::Authority::FullSelf, ··· 284 286 .outcome 285 287 .failures 286 288 .iter() 287 - .map(|f| f.nsid.clone()) 289 + .map(|f| f.given_nsid.clone()) 288 290 .collect(); 289 291 return Err(OAuthError::InvalidScope(format!( 290 292 "Permission set(s) expired and unresolvable: {}", 291 293 names.join(", ") 292 294 ))); 293 295 } 294 - Ok(effective.resolved) 296 + Ok(effective.permitted) 295 297 } 296 298 297 299 pub async fn handle_refresh_token_grant(
+4 -1
crates/tranquil-pds/src/delegation/scopes.rs
··· 268 268 "repo:app.bsky.feed.post?action=create identity:* account:*?action=manage", 269 269 granted, 270 270 ); 271 - assert!(grant_covers(granted, "repo:app.bsky.feed.post?action=create")); 271 + assert!(grant_covers( 272 + granted, 273 + "repo:app.bsky.feed.post?action=create" 274 + )); 272 275 assert!(grant_covers(granted, "account:*?action=manage")); 273 276 assert!(!grant_covers(granted, "identity:*")); 274 277 assert_eq!(
+21 -9
crates/tranquil-pds/src/oauth/permission_set_resolver.rs
··· 3 3 use serde::{Deserialize, Serialize}; 4 4 use std::time::Duration; 5 5 use tranquil_scopes::{ 6 - fetch_and_expand, parse_include_scope, ExpansionOutcome, FailedSet, ResolveFailure, 7 - ResolvedSetGroup, ScopeExpansionError, 6 + ExpansionOutcome, FailedSet, ResolveFailure, ResolvedSetGroup, ScopeExpansionError, 7 + fetch_and_expand, parse_include_scope, 8 8 }; 9 9 use tranquil_types::Nsid; 10 10 ··· 38 38 match resolve_one(cache, nsid, aud).await { 39 39 Ok(group) => outcome.sets.push(group), 40 40 Err(reason) => outcome.failures.push(FailedSet { 41 - nsid: nsid.to_string(), 42 - aud: aud.map(str::to_string), 41 + given_nsid: nsid.to_string(), 42 + given_aud: aud.map(str::to_string), 43 43 reason, 44 44 }), 45 45 } ··· 84 84 }; 85 85 if let Ok(json) = serde_json::to_string(&stored) { 86 86 let _ = cache 87 - .set(&key, &json, Duration::from_secs(PERMISSION_SET_CACHE_TTL_SECS)) 87 + .set( 88 + &key, 89 + &json, 90 + Duration::from_secs(PERMISSION_SET_CACHE_TTL_SECS), 91 + ) 88 92 .await; 89 93 } 90 - Ok(group_from(parsed, aud, fetched.expanded, fetched.title, fetched.detail)) 94 + Ok(group_from( 95 + parsed, 96 + aud, 97 + fetched.expanded, 98 + fetched.title, 99 + fetched.detail, 100 + )) 91 101 } 92 102 Err(e) => match cached { 93 103 Some(v) => Ok(group_from(parsed, aud, v.scope, v.title, v.detail)), ··· 160 170 } 161 171 162 172 fn seed_at(cache: &MapCache, nsid: &str, scope: &str, refreshed_at: i64) { 163 - let key = crate::cache_keys::permission_set_key(&tranquil_types::Nsid::new(nsid).unwrap(), None); 173 + let key = 174 + crate::cache_keys::permission_set_key(&tranquil_types::Nsid::new(nsid).unwrap(), None); 164 175 let val = serde_json::to_string(&CachedPermissionSet { 165 176 scope: scope.to_string(), 166 177 title: Some("Basic".into()), ··· 225 236 None, 226 237 ); 227 238 // Shape written before `refreshed_at` existed. 228 - let legacy = r#"{"scope":"repo:nonexistent.fake.record?action=create","title":null,"detail":null}"#; 239 + let legacy = 240 + r#"{"scope":"repo:nonexistent.fake.record?action=create","title":null,"detail":null}"#; 229 241 cache.0.lock().unwrap().insert(key, legacy.to_string()); 230 242 let out = expand_scopes(&cache, "include:nonexistent.fake.permissionSet").await; 231 243 assert!(out.failures.is_empty()); ··· 247 259 let out = expand_scopes(&cache, "include:nonexistent.fake.permissionSet").await; 248 260 assert_eq!(out.sets.len(), 0); 249 261 assert_eq!(out.failures.len(), 1); 250 - assert_eq!(out.failures[0].nsid, "nonexistent.fake.permissionSet"); 262 + assert_eq!(out.failures[0].given_nsid, "nonexistent.fake.permissionSet"); 251 263 } 252 264 }
+9 -6
crates/tranquil-pds/tests/oauth_permission_sets.rs
··· 53 53 54 54 async fn seed_permission_set(nsid: &str, granular_scope: &str) { 55 55 let state = common::get_test_app_state().await; 56 - let key = tranquil_pds::cache_keys::permission_set_key(&tranquil_types::Nsid::new(nsid).unwrap(), None); 56 + let key = tranquil_pds::cache_keys::permission_set_key( 57 + &tranquil_types::Nsid::new(nsid).unwrap(), 58 + None, 59 + ); 57 60 let now = std::time::SystemTime::now() 58 61 .duration_since(std::time::UNIX_EPOCH) 59 62 .unwrap() ··· 597 600 ); 598 601 599 602 let state = common::get_test_app_state().await; 600 - let key = tranquil_pds::cache_keys::permission_set_key(&tranquil_types::Nsid::new(UNRESOLVABLE_NSID).unwrap(), None); 603 + let key = tranquil_pds::cache_keys::permission_set_key( 604 + &tranquil_types::Nsid::new(UNRESOLVABLE_NSID).unwrap(), 605 + None, 606 + ); 601 607 state.cache.delete(&key).await.unwrap(); 602 608 603 609 let approved_scopes: Vec<&str> = scope.split_whitespace().collect(); ··· 663 669 let client_id = mock_client.uri(); 664 670 let (_code_verifier, code_challenge) = generate_pkce(); 665 671 666 - let scope = format!( 667 - "atproto include:{} include:{}", 668 - GOOD_SET_NSID, BAD_SET_NSID 669 - ); 672 + let scope = format!("atproto include:{} include:{}", GOOD_SET_NSID, BAD_SET_NSID); 670 673 let par_res = http_client 671 674 .post(format!("{}/oauth/par", url)) 672 675 .form(&[
+27 -7
crates/tranquil-scopes/src/coverage.rs
··· 27 27 Some(gc) => match &r.collection { 28 28 None => false, 29 29 Some(rc) => match gc.strip_suffix(".*") { 30 - Some(prefix) => rc.starts_with(prefix) && rc.as_bytes().get(prefix.len()) == Some(&b'.'), 30 + Some(prefix) => { 31 + rc.starts_with(prefix) && rc.as_bytes().get(prefix.len()) == Some(&b'.') 32 + } 31 33 None => gc == rc, 32 34 }, 33 35 }, ··· 94 96 fn repo_action_subset_required() { 95 97 assert!(c("repo:*", "repo:*?action=create")); 96 98 assert!(!c("repo:*?action=create", "repo:*?action=delete")); 97 - assert!(c("repo:*?action=create&action=delete", "repo:*?action=create")); 98 - assert!(!c("repo:*?action=create", "repo:*?action=create&action=delete")); 99 + assert!(c( 100 + "repo:*?action=create&action=delete", 101 + "repo:*?action=create" 102 + )); 103 + assert!(!c( 104 + "repo:*?action=create", 105 + "repo:*?action=create&action=delete" 106 + )); 99 107 } 100 108 101 109 #[test] 102 110 fn repo_partial_action_grant_does_not_cover_actionless_request() { 103 - assert!(!c("repo:*?action=create&action=delete", "repo:app.bsky.feed.post")); 111 + assert!(!c( 112 + "repo:*?action=create&action=delete", 113 + "repo:app.bsky.feed.post" 114 + )); 104 115 } 105 116 106 117 #[test] ··· 125 136 #[test] 126 137 fn rpc_wildcards() { 127 138 assert!(c("rpc:*?aud=did:web:x", "rpc:app.bsky.getX?aud=did:web:x")); 128 - assert!(c("rpc:app.bsky.getX?aud=*", "rpc:app.bsky.getX?aud=did:web:x")); 129 - assert!(!c("rpc:app.bsky.getX?aud=did:web:x", "rpc:app.bsky.getY?aud=did:web:x")); 139 + assert!(c( 140 + "rpc:app.bsky.getX?aud=*", 141 + "rpc:app.bsky.getX?aud=did:web:x" 142 + )); 143 + assert!(!c( 144 + "rpc:app.bsky.getX?aud=did:web:x", 145 + "rpc:app.bsky.getY?aud=did:web:x" 146 + )); 130 147 } 131 148 132 149 #[test] 133 150 fn account_manage_covers_read_and_wildcard_attr() { 134 151 assert!(c("account:*?action=manage", "account:email?action=read")); 135 152 assert!(c("account:*?action=manage", "account:email?action=manage")); 136 - assert!(!c("account:email?action=read", "account:email?action=manage")); 153 + assert!(!c( 154 + "account:email?action=read", 155 + "account:email?action=manage" 156 + )); 137 157 } 138 158 139 159 #[test]
+2 -2
crates/tranquil-scopes/src/lib.rs
··· 16 16 ParsedScope, RepoAction, RepoScope, RpcScope, parse_scope, parse_scope_string, 17 17 }; 18 18 pub use permission_set::{ 19 - ExpansionOutcome, FailedSet, FetchedSet, ResolveFailure, ResolvedSetGroup, 20 - ScopeExpansionError, fetch_and_expand, parse_include_scope, 19 + ExpansionOutcome, FailedSet, FetchedSet, ResolveFailure, ResolvedSetGroup, ScopeExpansionError, 20 + fetch_and_expand, parse_include_scope, 21 21 }; 22 22 pub use permissions::ScopePermissions;
+19 -17
crates/tranquil-scopes/src/permission_set.rs
··· 45 45 46 46 #[derive(Debug, Clone)] 47 47 pub struct FailedSet { 48 - pub nsid: String, 49 - pub aud: Option<String>, 48 + // NSID and aud are left as strings to avoid issues from malformed requests. 49 + pub given_nsid: String, 50 + pub given_aud: Option<String>, 50 51 pub reason: ResolveFailure, 51 52 } 52 53 ··· 70 71 pub fn flat_scopes(&self) -> Vec<String> { 71 72 let mut out = Vec::new(); 72 73 let mut seen = std::collections::HashSet::new(); 73 - for s in self.passthrough.iter().chain( 74 - self.sets 75 - .iter() 76 - .flat_map(|group| group.expanded.iter()), 77 - ) { 74 + for s in self 75 + .passthrough 76 + .iter() 77 + .chain(self.sets.iter().flat_map(|group| group.expanded.iter())) 78 + { 78 79 if seen.insert(s.as_str()) { 79 80 out.push(s.clone()); 80 81 } ··· 163 164 main_def.def_type.clone(), 164 165 )); 165 166 } 166 - let permissions = main_def 167 - .permissions 168 - .as_ref() 169 - .ok_or(ScopeExpansionError::MissingDefinition( 170 - "permissions".to_string(), 171 - ))?; 167 + let permissions = 168 + main_def 169 + .permissions 170 + .as_ref() 171 + .ok_or(ScopeExpansionError::MissingDefinition( 172 + "permissions".to_string(), 173 + ))?; 172 174 let namespace_authority = extract_namespace_authority(nsid); 173 175 let expanded = build_expanded_scopes(permissions, aud, &namespace_authority); 174 176 if expanded.is_empty() { ··· 235 237 }); 236 238 } 237 239 238 - let record: GetRecordResponse = serde_json::from_str(&body) 239 - .map_err(|e| ScopeExpansionError::HttpFailed(e.to_string()))?; 240 + let record: GetRecordResponse = 241 + serde_json::from_str(&body).map_err(|e| ScopeExpansionError::HttpFailed(e.to_string()))?; 240 242 241 243 Ok(record.value) 242 244 } ··· 641 643 ], 642 644 }], 643 645 failures: vec![FailedSet { 644 - nsid: "nonexistent.fake.permissionSet".into(), 645 - aud: None, 646 + given_nsid: "nonexistent.fake.permissionSet".into(), 647 + given_aud: None, 646 648 reason: ResolveFailure::NotFound, 647 649 }], 648 650 };