| 285 | |
| 286 | #[test] |
| 287 | fn cycle_detection() { |
| 288 | let store = ScopeStore::new(); |
| 289 | // Create a → b → a cycle (manually bypass validation for test). |
| 290 | { |
| 291 | let mut scopes = store.scopes.write().unwrap(); |
| 292 | scopes.insert( |
| 293 | "a".into(), |
| 294 | ScopeDefinition { |
| 295 | name: "a".into(), |
| 296 | grants: vec![("read".into(), "t1".into())], |
| 297 | includes: vec!["b".into()], |
| 298 | created_by: "test".into(), |
| 299 | created_at: 0, |
| 300 | }, |
| 301 | ); |
| 302 | scopes.insert( |
| 303 | "b".into(), |
| 304 | ScopeDefinition { |
| 305 | name: "b".into(), |
| 306 | grants: vec![("write".into(), "t2".into())], |
| 307 | includes: vec!["a".into()], |
| 308 | created_by: "test".into(), |
| 309 | created_at: 0, |
| 310 | }, |
| 311 | ); |
| 312 | } |
| 313 | // Should not infinite loop. |
| 314 | let resolved = store.resolve("a"); |
| 315 | assert_eq!(resolved.len(), 2); |
| 316 | } |
| 317 | |
| 318 | #[test] |
| 319 | fn scope_grants_check() { |