Skip to content

Commit 5fc08ca

Browse files
committed
try_allowed
1 parent c2e00aa commit 5fc08ca

File tree

3 files changed

+54
-41
lines changed

3 files changed

+54
-41
lines changed

lib/api_run/src/run.rs

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use bencher_endpoint::{CorsResponse, Endpoint, Post, ResponseCreated};
22
use bencher_json::{project, system::auth, JsonNewRun, JsonReport, NameIdKind, ResourceName};
3+
use bencher_rbac::project::Permission;
34
use bencher_schema::{
45
conn_lock,
56
context::ApiContext,
6-
error::{bad_request_error, forbidden_error},
7+
error::{bad_request_error, forbidden_error, issue_error},
78
model::{
89
organization::QueryOrganization,
910
project::{report::QueryReport, QueryProject},
@@ -39,27 +40,41 @@ pub async fn run_post(
3940
body: TypedBody<JsonNewRun>,
4041
) -> Result<ResponseCreated<JsonReport>, HttpError> {
4142
let auth_user = AuthUser::from_pub_token(rqctx.context(), bearer_token).await?;
42-
let json = post_inner(&rqctx.log, rqctx.context(), body.into_inner(), auth_user).await?;
43+
let json = post_inner(&rqctx.log, rqctx.context(), auth_user, body.into_inner()).await?;
4344
Ok(Post::auth_response_created(json))
4445
}
4546

4647
async fn post_inner(
4748
log: &Logger,
4849
context: &ApiContext,
49-
json_run: JsonNewRun,
5050
auth_user: Option<AuthUser>,
51+
json_run: JsonNewRun,
5152
) -> Result<JsonReport, HttpError> {
52-
let query_project = QueryProject::get_or_create(
53-
context,
53+
let (auth_user, query_project) = match (
54+
auth_user,
5455
json_run.organization.as_ref(),
5556
json_run.project.as_ref(),
56-
auth_user.as_ref(),
57-
)
58-
.await?;
59-
#[allow(clippy::unimplemented)]
60-
let todo_pub_run_user = |_auth_user: Option<AuthUser>| -> Result<AuthUser, HttpError> {
61-
Err(bad_request_error("pub run creation is not yet implemented"))
57+
) {
58+
(Some(auth_user), Some(organization), Some(project)) => {
59+
let query_project =
60+
QueryProject::get_or_create(context, &auth_user, organization, project)
61+
.await
62+
.map_err(|e| forbidden_error(e.to_string()))?;
63+
(auth_user, query_project)
64+
},
65+
_ => return Err(bad_request_error("Not yet supported")),
6266
};
63-
let auth_user = todo_pub_run_user(auth_user)?;
67+
68+
// Verify that the user is allowed
69+
// This should always succeed if the logic above is correct
70+
query_project
71+
.try_allowed(&context.rbac, &auth_user, Permission::Create)
72+
.map_err(|e| {
73+
issue_error(
74+
"Failed to check run permissions",
75+
"Failed check the run permissions before creating a report",
76+
e,
77+
)
78+
})?;
6479
QueryReport::create(log, context, &query_project, json_run.into(), &auth_user).await
6580
}

lib/bencher_schema/src/model/organization/mod.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ impl QueryOrganization {
6969
permission: bencher_rbac::organization::Permission,
7070
) -> Result<Self, HttpError> {
7171
let query_organization = Self::from_resource_id(conn, organization)?;
72-
query_organization.allowed(rbac, auth_user, permission)
72+
query_organization.try_allowed(rbac, auth_user, permission)?;
73+
Ok(query_organization)
7374
}
7475

7576
pub fn is_allowed_id(
@@ -96,18 +97,18 @@ impl QueryOrganization {
9697
permission: bencher_rbac::organization::Permission,
9798
) -> Result<Self, HttpError> {
9899
let query_organization = Self::get(conn, organization_id)?;
99-
query_organization.allowed(rbac, auth_user, permission)
100+
query_organization.try_allowed(rbac, auth_user, permission)?;
101+
Ok(query_organization)
100102
}
101103

102-
fn allowed(
103-
self,
104+
fn try_allowed(
105+
&self,
104106
rbac: &Rbac,
105107
auth_user: &AuthUser,
106108
permission: bencher_rbac::organization::Permission,
107-
) -> Result<Self, HttpError> {
108-
rbac.is_allowed_organization(auth_user, permission, &self)
109-
.map_err(forbidden_error)?;
110-
Ok(self)
109+
) -> Result<(), HttpError> {
110+
rbac.is_allowed_organization(auth_user, permission, self)
111+
.map_err(forbidden_error)
111112
}
112113

113114
pub fn into_json(self) -> JsonOrganization {

lib/bencher_schema/src/model/project/mod.rs

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,8 @@ use crate::{
1313
conn_lock,
1414
context::{DbConnection, Rbac},
1515
error::{
16-
assert_parentage, bad_request_error, conflict_error, forbidden_error,
17-
resource_conflict_err, resource_not_found_err, resource_not_found_error,
18-
unauthorized_error, BencherResource,
16+
assert_parentage, bad_request_error, forbidden_error, resource_conflict_err,
17+
resource_not_found_error, unauthorized_error, BencherResource,
1918
},
2019
macros::{
2120
fn_get::{fn_from_uuid, fn_get, fn_get_uuid},
@@ -75,23 +74,13 @@ impl QueryProject {
7574

7675
pub async fn get_or_create(
7776
context: &ApiContext,
77+
auth_user: &AuthUser,
7878
organization: &ResourceId,
7979
project: &NameId,
80-
auth_user: &AuthUser,
81-
) -> Result<ProjectId, HttpError> {
80+
) -> Result<Self, HttpError> {
8281
let query_organization =
8382
QueryOrganization::from_resource_id(conn_lock!(context), organization)?;
84-
let query_project =
85-
Self::get_or_create_inner(context, &query_organization, project, auth_user).await?;
86-
Ok(query_project.id)
87-
}
8883

89-
async fn get_or_create_inner(
90-
context: &ApiContext,
91-
query_organization: &QueryOrganization,
92-
project: &NameId,
93-
auth_user: &AuthUser,
94-
) -> Result<Self, HttpError> {
9584
let Ok(kind) = NameIdKind::<ResourceName>::try_from(project) else {
9685
return Err(bad_request_error(format!(
9786
"Project ({project}) must be a valid UUID, slug, or name"
@@ -115,7 +104,7 @@ impl QueryProject {
115104
url: None,
116105
visibility: None,
117106
};
118-
Self::create(context, query_organization, new_project, auth_user).await?
107+
Self::create(context, &query_organization, new_project, auth_user).await?
119108
}
120109
},
121110
NameIdKind::Name(name) => {
@@ -132,7 +121,7 @@ impl QueryProject {
132121
url: None,
133122
visibility: None,
134123
};
135-
Self::create(context, query_organization, new_project, auth_user).await?
124+
Self::create(context, &query_organization, new_project, auth_user).await?
136125
}
137126
},
138127
};
@@ -202,8 +191,7 @@ impl QueryProject {
202191
permission: Permission,
203192
) -> Result<Self, HttpError> {
204193
let query_project = Self::from_resource_id(conn, project)?;
205-
rbac.is_allowed_project(auth_user, permission, &query_project)
206-
.map_err(forbidden_error)?;
194+
query_project.try_allowed(rbac, auth_user, permission)?;
207195
Ok(query_project)
208196
}
209197

@@ -234,14 +222,23 @@ impl QueryProject {
234222
} else if let Some(auth_user) = auth_user {
235223
// If there is an `AuthUser` then validate access
236224
// Verify that the user is allowed
237-
rbac.is_allowed_project(auth_user, Permission::View, &query_project)
238-
.map_err(forbidden_error)?;
225+
query_project.try_allowed(rbac, auth_user, Permission::View)?;
239226
Ok(query_project)
240227
} else {
241228
Err(unauthorized_error(project))
242229
}
243230
}
244231

232+
pub fn try_allowed(
233+
&self,
234+
rbac: &Rbac,
235+
auth_user: &AuthUser,
236+
permission: Permission,
237+
) -> Result<(), HttpError> {
238+
rbac.is_allowed_project(auth_user, permission, self)
239+
.map_err(forbidden_error)
240+
}
241+
245242
#[cfg(feature = "plus")]
246243
pub fn perf_url(&self, console_url: &url::Url) -> Result<Option<url::Url>, HttpError> {
247244
if !self.is_public() {

0 commit comments

Comments
 (0)