Skip to content

Commit 0e07715

Browse files
committed
only allow triggering rebuilds for crate maintainers
1 parent 84d7ca1 commit 0e07715

File tree

1 file changed

+51
-3
lines changed

1 file changed

+51
-3
lines changed

src/controllers/version/docs.rs

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
use super::CrateVersionPath;
44
use crate::app::AppState;
55
use crate::auth::AuthCheck;
6-
use crate::util::errors::{AppResult, server_error};
6+
use crate::controllers::helpers::authorization::Rights;
7+
use crate::util::errors::{AppResult, custom, server_error};
78
use crate::worker::jobs;
89
use axum::response::{IntoResponse as _, Response};
910
use crates_io_worker::BackgroundJob as _;
@@ -27,10 +28,20 @@ pub async fn rebuild_version_docs(
2728
req: Parts,
2829
) -> AppResult<Response> {
2930
let mut conn = app.db_write().await?;
30-
AuthCheck::only_cookie().check(&req, &mut conn).await?;
31+
let auth = AuthCheck::only_cookie().check(&req, &mut conn).await?;
3132

3233
// validate if version & crate exist
33-
path.load_version_and_crate(&mut conn).await?;
34+
let (_, krate) = path.load_version_and_crate(&mut conn).await?;
35+
36+
// Check that the user is an owner of the crate, or a team member (= publish rights)
37+
let user = auth.user();
38+
let owners = krate.owners(&mut conn).await?;
39+
if Rights::get(user, &*app.github, &owners).await? < Rights::Publish {
40+
return Err(custom(
41+
StatusCode::FORBIDDEN,
42+
"user doesn't have permission to trigger a docs rebuild",
43+
));
44+
}
3445

3546
jobs::DocsRsQueueRebuild::new(path.name, path.version)
3647
.enqueue(&mut conn)
@@ -53,6 +64,7 @@ mod tests {
5364
builders::{CrateBuilder, VersionBuilder},
5465
util::{RequestHelper as _, TestApp},
5566
};
67+
use crates_io_database::models::NewUser;
5668
use crates_io_docs_rs::MockDocsRsClient;
5769

5870
#[tokio::test(flavor = "multi_thread")]
@@ -83,6 +95,42 @@ mod tests {
8395
Ok(())
8496
}
8597

98+
#[tokio::test(flavor = "multi_thread")]
99+
async fn test_trigger_rebuild_permission_failed() -> anyhow::Result<()> {
100+
let mut docs_rs_mock = MockDocsRsClient::new();
101+
docs_rs_mock
102+
.expect_rebuild_docs()
103+
.returning(|_, _| Ok(()))
104+
.never();
105+
106+
let (app, _client, cookie_client) =
107+
TestApp::full().with_docs_rs(docs_rs_mock).with_user().await;
108+
109+
let mut conn = app.db_conn().await;
110+
111+
let other_user = NewUser::builder()
112+
.gh_id(111)
113+
.gh_login("other_user")
114+
.gh_access_token("token")
115+
.build()
116+
.insert(&mut conn)
117+
.await?;
118+
119+
CrateBuilder::new("krate", other_user.id)
120+
.version(VersionBuilder::new("0.1.0"))
121+
.build(&mut conn)
122+
.await?;
123+
124+
let response = cookie_client
125+
.post::<()>("/api/v1/crates/krate/0.1.0/rebuild_docs", "")
126+
.await;
127+
assert_eq!(response.status(), StatusCode::FORBIDDEN);
128+
129+
app.run_pending_background_jobs().await;
130+
131+
Ok(())
132+
}
133+
86134
#[tokio::test(flavor = "multi_thread")]
87135
async fn test_trigger_rebuild_unknown_crate_doesnt_queue_job() -> anyhow::Result<()> {
88136
let mut docs_rs_mock = MockDocsRsClient::new();

0 commit comments

Comments
 (0)