use oso_cloud::{fact, Value};
macro_rules! assert_eq_lists {
($left:expr, $right:expr $(, $tt:tt)*) => {
let mut left = $left;
let mut right = $right;
left.sort();
right.sort();
assert_eq!(left, right $($tt)*)
};
}
struct User {
id: u32,
}
impl From<User> for Value<'static> {
fn from(user: User) -> Self {
Value::new("User", user.id.to_string())
}
}
impl<'a> From<&'a User> for Value<'static> {
fn from(user: &'a User) -> Self {
Value::new("User", user.id.to_string())
}
}
#[derive(PartialEq, PartialOrd, Eq, Ord, Debug)]
struct Repo {
id: u32,
}
impl From<Repo> for Value<'static> {
fn from(repo: Repo) -> Self {
Value::new("Repo", repo.id.to_string())
}
}
impl<'a> From<&'a Repo> for Value<'a> {
fn from(repo: &'a Repo) -> Self {
Value::new("Repo", repo.id.to_string())
}
}
#[tokio::test]
#[ignore] async fn base() {
let _ = tracing_subscriber::fmt::try_init();
let o = oso_cloud::Builder::from_env().build().unwrap();
o.policy(
r#"
actor User {}
resource Repo {
roles = ["member"];
permissions = ["read", "write"];
relations = { parent: Repo };
"read" if "member";
"write" if "member";
}
"#,
)
.await
.expect("Setting policy failed");
let user = User { id: 1 };
let repo = Repo { id: 1 };
o.delete(fact!("has_role", &user, "member", &repo))
.await
.expect("Error deleting");
let allowed = o.authorize(&user, "read", &repo).await.unwrap();
assert!(!allowed);
o.tell(fact!("has_role", User{"1"}, "member", Repo{"1"}))
.await
.expect("Error telling");
let allowed = o.authorize(&user, "read", &repo).await.unwrap();
assert!(allowed);
let allowed_actions = o.actions(&user, &repo).await.unwrap();
assert_eq_lists!(allowed_actions, vec!["read", "write"]);
let allowed_resources = o
.with_context(vec![fact!("has_role", &user, "member", Repo{"2"})])
.list(&user, "write", "Repo")
.await
.unwrap();
assert_eq_lists!(allowed_resources, vec!["1", "2"]);
let mut resources = vec![Repo { id: 1 }, Repo { id: 2 }];
o.authorize_resources(&user, "read", &mut resources).await.unwrap();
let expected = vec![Repo { id: 1 }];
assert_eq_lists!(resources, expected);
let mut resources = vec![Repo { id: 2 }, Repo { id: 1 }];
o.authorize_resources(&user, "read", &mut resources).await.unwrap();
let expected = vec![Repo { id: 1 }];
assert_eq_lists!(resources, expected);
let facts = o
.get(&fact!("has_role", User { "1" }, "member", Repo { "1" }))
.await
.unwrap();
assert_eq_lists!(
facts,
vec![fact! {
"has_role",
User{"1"},
"member",
Repo{"1"}
}]
);
o.delete(fact!("has_role", &user, "member", &repo))
.await
.expect("Error deleting");
let facts = o.get(&fact!("has_role", &user, "member", &repo)).await.unwrap();
assert_eq_lists!(facts, vec![]);
let bulk_facts = vec![(1, 1)]
.into_iter()
.map(|(actor, resource)| fact!("has_role", User { actor.to_string() }, "member", Repo { resource.to_string() }))
.collect::<Vec<_>>();
o.bulk_tell(&bulk_facts).await.expect("Error telling");
let facts = o.get(&fact!("has_role", &user, "member", &repo)).await.unwrap();
assert_eq_lists!(
facts,
vec![fact! {
"has_role",
User{"1"},
"member",
Repo{"1"}
}]
);
let facts = o
.query(&fact!("has_permission", &user, Value::any(), &repo))
.await
.unwrap();
assert_eq_lists!(
facts,
vec![
fact! {
"has_permission",
User{"1"},
"read",
Repo{"1"}
},
fact! {
"has_permission",
User{"1"},
"write",
Repo{"1"}
}
]
);
o.bulk_delete(&[fact!("has_role", &user, "member", &repo)])
.await
.expect("Error deleting");
let facts = o.get(&fact!("has_role", &user, "member", &repo)).await.unwrap();
assert_eq_lists!(facts, vec![]);
o.with_context(vec![fact!("has_role", &user, "member", Repo{"2"})])
.authorize(&user, "read", &Repo { id: 2 })
.await
.unwrap();
let api_error_result = o.tell(fact!("does_not_exist", User{"1"}, "taco")).await;
let err = api_error_result.unwrap_err();
let err_message = err.to_string();
assert!(err_message.starts_with("Oso Server Error: "));
let large_payload = vec!["a".repeat(1024 * 1024); 10].join(""); let payload_error_result = o.tell(fact!("has_role", User{"1"}, large_payload)).await;
let payload_error = payload_error_result.unwrap_err();
assert!(payload_error
.to_string()
.starts_with("Input error: Request payload too large"));
}