Skip to content

Commit 368b57f

Browse files
xtexxMingcongBai
authored andcommitted
feat: restrict some bot commands to maintainers-only
1 parent ed3335a commit 368b57f

File tree

3 files changed

+86
-25
lines changed

3 files changed

+86
-25
lines changed

server/src/bot.rs

Lines changed: 77 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::{
33
api::{JobSource, job_restart, pipeline_new, pipeline_new_pr, pipeline_status, worker_status},
44
formatter::to_html_new_pipeline_summary,
55
github::{get_github_token, login_github},
6+
is_maintainer,
67
models::{NewUser, User},
78
paste_to_aosc_io,
89
};
@@ -309,6 +310,42 @@ async fn get_user(pool: DbPool, chat_id: ChatId, access_token: String) -> anyhow
309310
bail!("Failed to get user info")
310311
}
311312

313+
async fn check_maintainership(bot: &Bot, pool: &DbPool, chat_id: ChatId) -> ResponseResult<bool> {
314+
match check_maintainership_inner(pool, chat_id).await {
315+
Ok(_) => Ok(true),
316+
Err(error) => {
317+
bot.send_message(chat_id, format!("Failed maintainership check: {error:?}"))
318+
.await?;
319+
Ok(false)
320+
}
321+
}
322+
}
323+
324+
async fn check_maintainership_inner(pool: &DbPool, chat_id: ChatId) -> anyhow::Result<()> {
325+
let mut conn = pool
326+
.get()
327+
.context("Failed to get db connection from pool")?;
328+
329+
use crate::schema::users::dsl::*;
330+
if let Some(user) = users
331+
.filter(telegram_chat_id.eq(&chat_id.0))
332+
.first::<User>(&mut conn)
333+
.optional()?
334+
{
335+
if let Some(gh_login) = user.github_login {
336+
if is_maintainer(&gh_login).await? {
337+
Ok(())
338+
} else {
339+
bail!("You are not a member of AOSC-Dev yet")
340+
}
341+
} else {
342+
bail!("GitHub account is not connected")
343+
}
344+
} else {
345+
bail!("user not found")
346+
}
347+
}
348+
312349
async fn create_pipeline_from_pr(
313350
pool: DbPool,
314351
pr_number: u64,
@@ -364,6 +401,9 @@ pub async fn answer(bot: Bot, msg: Message, cmd: Command, pool: DbPool) -> Respo
364401
.await?;
365402
}
366403
Command::PR(arguments) => {
404+
if !check_maintainership(&bot, &pool, msg.chat.id).await? {
405+
return Ok(());
406+
}
367407
let parts = arguments.split_ascii_whitespace().collect::<Vec<_>>();
368408
if !(1..=2).contains(&parts.len()) {
369409
bot.send_message(
@@ -406,6 +446,9 @@ pub async fn answer(bot: Bot, msg: Message, cmd: Command, pool: DbPool) -> Respo
406446
}
407447
}
408448
Command::Build(arguments) => {
449+
if !check_maintainership(&bot, &pool, msg.chat.id).await? {
450+
return Ok(());
451+
}
409452
let parts: Vec<&str> = arguments.split(' ').collect();
410453
if parts.len() == 3 {
411454
let git_branch = parts[0];
@@ -596,6 +639,9 @@ pub async fn answer(bot: Bot, msg: Message, cmd: Command, pool: DbPool) -> Respo
596639
}
597640
}
598641
Command::Dickens(arguments) => {
642+
if !check_maintainership(&bot, &pool, msg.chat.id).await? {
643+
return Ok(());
644+
}
599645
let mut pr_numbers = vec![];
600646
for part in arguments.split(',') {
601647
match str::parse::<u64>(part) {
@@ -721,6 +767,9 @@ pub async fn answer(bot: Bot, msg: Message, cmd: Command, pool: DbPool) -> Respo
721767
}
722768
}
723769
Command::QA(arguments) => {
770+
if !check_maintainership(&bot, &pool, msg.chat.id).await? {
771+
return Ok(());
772+
}
724773
let parts: Vec<&str> = arguments.split(' ').collect();
725774
if parts.len() == 2
726775
&& ALL_ARCH.contains(&parts[0])
@@ -786,6 +835,9 @@ pub async fn answer(bot: Bot, msg: Message, cmd: Command, pool: DbPool) -> Respo
786835
}
787836
Command::Restart(arguments) => match str::parse::<i32>(&arguments) {
788837
Ok(job_id) => {
838+
if !check_maintainership(&bot, &pool, msg.chat.id).await? {
839+
return Ok(());
840+
}
789841
match wait_with_send_typing(job_restart(pool, job_id), &bot, msg.chat.id.0).await {
790842
Ok(new_job) => {
791843
bot.send_message(
@@ -813,6 +865,10 @@ pub async fn answer(bot: Bot, msg: Message, cmd: Command, pool: DbPool) -> Respo
813865
}
814866
},
815867
Command::Bump(package_and_version) => {
868+
if !check_maintainership(&bot, &pool, msg.chat.id).await? {
869+
return Ok(());
870+
}
871+
816872
let app_private_key = match ARGS.github_app_key.as_ref() {
817873
Some(p) => p,
818874
None => {
@@ -958,24 +1014,29 @@ pub async fn answer(bot: Bot, msg: Message, cmd: Command, pool: DbPool) -> Respo
9581014
}
9591015
};
9601016
}
961-
Command::Roll => match wait_with_send_typing(roll(), &bot, msg.chat.id.0).await {
962-
Ok(pkgs) => {
963-
let mut s = String::new();
964-
for i in pkgs {
965-
s.push_str(&i.to_string());
966-
s.push('\n');
967-
}
968-
969-
bot.send_message(msg.chat.id, truncate(&s)).await?;
1017+
Command::Roll => {
1018+
if !check_maintainership(&bot, &pool, msg.chat.id).await? {
1019+
return Ok(());
9701020
}
971-
Err(e) => {
972-
bot.send_message(
973-
msg.chat.id,
974-
truncate(&format!("Failed to roll packages: {}", e)),
975-
)
976-
.await?;
1021+
match wait_with_send_typing(roll(), &bot, msg.chat.id.0).await {
1022+
Ok(pkgs) => {
1023+
let mut s = String::new();
1024+
for i in pkgs {
1025+
s.push_str(&i.to_string());
1026+
s.push('\n');
1027+
}
1028+
1029+
bot.send_message(msg.chat.id, truncate(&s)).await?;
1030+
}
1031+
Err(e) => {
1032+
bot.send_message(
1033+
msg.chat.id,
1034+
truncate(&format!("Failed to roll packages: {}", e)),
1035+
)
1036+
.await?;
1037+
}
9771038
}
978-
},
1039+
}
9791040
};
9801041

9811042
Ok(())

server/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,10 @@ async fn test_paste_to_aosc_io() {
165165
.unwrap();
166166
dbg!(id);
167167
}
168+
169+
async fn is_maintainer(user: &str) -> anyhow::Result<bool> {
170+
let crab = octocrab::Octocrab::builder()
171+
.user_access_token(ARGS.github_access_token.clone())
172+
.build()?;
173+
Ok(crab.orgs("AOSC-Dev").check_membership(user).await?)
174+
}

server/src/routes/webhook.rs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use serde_json::Value;
55
use tracing::{info, warn};
66

77
use crate::{
8-
ARGS, DbPool, api, bot::GitHubUser, formatter::to_html_new_pipeline_summary, paste_to_aosc_io,
8+
api, bot::GitHubUser, formatter::to_html_new_pipeline_summary, is_maintainer, paste_to_aosc_io, DbPool, ARGS
99
};
1010

1111
use super::{AnyhowError, AppState};
@@ -76,7 +76,7 @@ async fn handle_webhook_comment(
7676
return Ok(());
7777
}
7878

79-
let is_org_user = is_org_user(&comment.user.login).await?;
79+
let is_org_user = is_maintainer(&comment.user.login).await?;
8080

8181
if !is_org_user {
8282
return Ok(());
@@ -160,10 +160,3 @@ async fn pipeline_new_pr_impl(
160160

161161
Ok(())
162162
}
163-
164-
async fn is_org_user(user: &str) -> anyhow::Result<bool> {
165-
let crab = octocrab::Octocrab::builder()
166-
.user_access_token(ARGS.github_access_token.clone())
167-
.build()?;
168-
Ok(crab.orgs("AOSC-Dev").check_membership(user).await?)
169-
}

0 commit comments

Comments
 (0)