summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPietro Albini <pietro@pietroalbini.org>2019-03-03 21:19:49 +0100
committerPietro Albini <pietro@pietroalbini.org>2019-03-10 12:07:32 +0100
commite5a6e75ce81720fbac3f6eb14924d5248aed3088 (patch)
treef2eaeaecb4b1ab24e95707b09bffdf2efbfc8df4 /src
parenta6c88e3b7657cba0a27b068441d9d8e07509f924 (diff)
permissions: add support for bors permissions
Diffstat (limited to 'src')
-rw-r--r--src/permissions.rs124
-rw-r--r--src/schema.rs6
-rw-r--r--src/validate.rs43
3 files changed, 141 insertions, 32 deletions
diff --git a/src/permissions.rs b/src/permissions.rs
index f181e21..3670f59 100644
--- a/src/permissions.rs
+++ b/src/permissions.rs
@@ -1,46 +1,140 @@
use crate::data::Data;
-use failure::Error;
+use failure::{Error, bail};
use std::collections::HashSet;
-#[macro_export]
macro_rules! permissions {
- ($vis:vis struct $name:ident { $($key:ident,)* }) => {
+ (
+ booleans {
+ $($boolean:ident,)*
+ }
+ bors_repos {
+ $($bors:ident,)*
+ }
+ ) => {
+ #[derive(serde_derive::Deserialize, Debug)]
+ #[serde(deny_unknown_fields)]
+ pub(crate) struct BorsACL {
+ #[serde(default)]
+ review: bool,
+ #[serde(rename = "try", default)]
+ try_: bool,
+ }
+
+ impl Default for BorsACL {
+ fn default() -> Self {
+ BorsACL {
+ review: false,
+ try_: false,
+ }
+ }
+ }
+
+ #[derive(serde_derive::Deserialize, Debug)]
+ #[serde(deny_unknown_fields)]
+ pub(crate) struct BorsPermissions {
+ $(
+ #[serde(default)]
+ $bors: BorsACL,
+ )*
+ }
+
+ impl Default for BorsPermissions {
+ fn default() -> Self {
+ BorsPermissions {
+ $($bors: BorsACL::default(),)*
+ }
+ }
+ }
+
#[derive(serde_derive::Deserialize, Debug)]
#[serde(rename_all = "kebab-case", deny_unknown_fields)]
- $vis struct $name {
+ pub(crate) struct Permissions {
$(
#[serde(default)]
- $key: bool,
+ $boolean: bool,
)*
+ #[serde(default)]
+ bors: BorsPermissions,
}
- impl Default for $name {
+ impl Default for Permissions {
fn default() -> Self {
- $name {
- $($key: false,)*
+ Permissions {
+ $($boolean: false,)*
+ bors: BorsPermissions::default(),
}
}
}
- impl $name {
- $vis const AVAILABLE: &'static [&'static str] = &[$(stringify!($key),)*];
+ impl Permissions {
+ pub(crate) const AVAILABLE: &'static [&'static str] = &[
+ $(stringify!($boolean),)*
+ $(concat!("bors.", stringify!($bors), ".review"),)*
+ $(concat!("bors.", stringify!($bors), ".try"),)*
+ ];
- $vis fn has(&self, permission: &str) -> bool {
+ pub(crate) fn has(&self, permission: &str) -> bool {
+ $(
+ if permission == stringify!($boolean) {
+ return self.$boolean;
+ }
+ )*
$(
- if permission == stringify!($key) {
- return self.$key;
+ if permission == concat!("bors.", stringify!($bors), ".review") {
+ return self.bors.$bors.review;
}
)*
+ $(
+ if permission == concat!("bors.", stringify!($bors), ".try") {
+ return self.bors.$bors.try_ || self.bors.$bors.review;
+ }
+ )*
+ false
+ }
+
+ pub(crate) fn has_any(&self) -> bool {
false
+ $(|| self.$boolean)*
+ $(|| self.bors.$bors.review)*
+ $(|| self.bors.$bors.try_)*
}
- $vis fn has_any(&self) -> bool {
- false $(|| self.$key)*
+ pub(crate) fn validate(&self, what: String) -> Result<(), Error> {
+ $(
+ if self.bors.$bors.try_ == true && self.bors.$bors.review == true {
+ bail!(
+ "{} has both the `bors.{}.review` and `bors.{}.try` permissions",
+ what,
+ stringify!($bors),
+ stringify!($bors),
+ );
+ }
+ )*
+ Ok(())
}
}
}
}
+permissions! {
+ booleans {
+ perf,
+ crater,
+ }
+ bors_repos {
+ cargo,
+ clippy,
+ compiler_builtins,
+ crater,
+ crates_io,
+ libc,
+ regex,
+ rls,
+ rust,
+ rustup_rs,
+ }
+}
+
pub(crate) fn allowed_github_users(
data: &Data,
permission: &str,
diff --git a/src/schema.rs b/src/schema.rs
index f53fd19..0143301 100644
--- a/src/schema.rs
+++ b/src/schema.rs
@@ -1,4 +1,5 @@
use crate::data::Data;
+pub(crate) use crate::permissions::Permissions;
use failure::{bail, err_msg, Error};
use std::collections::HashSet;
@@ -217,11 +218,6 @@ struct TeamPeople {
include_all_team_members: bool,
}
-permissions!(pub(crate) struct Permissions {
- perf,
- crater,
-});
-
pub(crate) struct DiscordInvite<'a> {
pub(crate) url: &'a str,
pub(crate) channel: &'a str,
diff --git a/src/validate.rs b/src/validate.rs
index 93a87ac..97fb655 100644
--- a/src/validate.rs
+++ b/src/validate.rs
@@ -4,21 +4,28 @@ use failure::{bail, ensure, Error};
use regex::Regex;
use std::collections::HashSet;
+static CHECKS: &[fn(&Data, &mut Vec<String>)] = &[
+ validate_wg_names,
+ validate_subteam_of,
+ validate_team_leads,
+ validate_team_members,
+ validate_inactive_members,
+ validate_list_email_addresses,
+ validate_list_extra_people,
+ validate_list_extra_teams,
+ validate_list_addresses,
+ validate_people_addresses,
+ validate_discord_name,
+ validate_duplicate_permissions,
+ validate_permissions,
+];
+
pub(crate) fn validate(data: &Data) -> Result<(), Error> {
let mut errors = Vec::new();
- validate_wg_names(data, &mut errors);
- validate_subteam_of(data, &mut errors);
- validate_team_leads(data, &mut errors);
- validate_team_members(data, &mut errors);
- validate_inactive_members(data, &mut errors);
- validate_list_email_addresses(data, &mut errors);
- validate_list_extra_people(data, &mut errors);
- validate_list_extra_teams(data, &mut errors);
- validate_list_addresses(data, &mut errors);
- validate_people_addresses(data, &mut errors);
- validate_discord_name(data, &mut errors);
- validate_duplicate_permissions(data, &mut errors);
+ for check in CHECKS {
+ check(data, &mut errors);
+ }
if !errors.is_empty() {
errors.sort();
@@ -260,6 +267,18 @@ fn validate_duplicate_permissions(data: &Data, errors: &mut Vec<String>) {
});
}
+/// Ensure the permissions are valid
+fn validate_permissions(data: &Data, errors: &mut Vec<String>) {
+ wrapper(data.teams(), errors, |team, _| {
+ team.permissions().validate(format!("team `{}`", team.name()))?;
+ Ok(())
+ });
+ wrapper(data.people(), errors, |person, _| {
+ person.permissions().validate(format!("user `{}`", person.github()))?;
+ Ok(())
+ });
+}
+
fn wrapper<T, I, F>(iter: I, errors: &mut Vec<String>, mut func: F)
where
I: Iterator<Item = T>,