mirror of
https://github.com/facebook/sapling.git
synced 2024-10-10 16:57:49 +03:00
Integrate Aclchecker with hooks
Summary: Integrate AclChecker into hooks. Note, TODO: Create a new hipster group "reviewers" Reviewed By: StanislavGlebik Differential Revision: D10507735 fbshipit-source-id: 62c02bdd2e79b8b77ea118ed97bec4a8f48f01db
This commit is contained in:
parent
aae4562523
commit
dafbef1dc3
@ -14,6 +14,7 @@
|
||||
#![deny(warnings)]
|
||||
#![feature(try_from)]
|
||||
|
||||
extern crate aclchecker;
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
extern crate assert_matches;
|
||||
@ -54,7 +55,9 @@ pub mod lua_hook;
|
||||
pub mod rust_hook;
|
||||
pub mod hook_loader;
|
||||
pub mod errors;
|
||||
mod facebook;
|
||||
|
||||
use aclchecker::{AclChecker, Identity};
|
||||
use asyncmemo::{Asyncmemo, Filler, Weight};
|
||||
use blobrepo::{BlobRepo, HgBlobChangeset};
|
||||
use bookmarks::Bookmark;
|
||||
@ -91,6 +94,7 @@ pub struct HookManager {
|
||||
changeset_store: Box<ChangesetStore>,
|
||||
content_store: Arc<FileContentStore>,
|
||||
logger: Logger,
|
||||
reviewers_acl_checker: Arc<Option<AclChecker>>,
|
||||
}
|
||||
|
||||
impl HookManager {
|
||||
@ -110,7 +114,15 @@ impl HookManager {
|
||||
repo_name: repo_name.clone(),
|
||||
};
|
||||
let cache = Asyncmemo::with_limits("hooks", filler, entrylimit, weightlimit);
|
||||
|
||||
let reviewers_acl_checker =
|
||||
AclChecker::new(&Identity::from_groupname(facebook::REVIEWERS_ACL_GROUP_NAME));
|
||||
// This can block, but not too big a deal as we create hook manager in server startup
|
||||
let updated = reviewers_acl_checker.do_wait_updated(10000);
|
||||
let reviewers_acl_checker = if updated {
|
||||
Some(reviewers_acl_checker)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
HookManager {
|
||||
cache,
|
||||
changeset_hooks,
|
||||
@ -120,6 +132,7 @@ impl HookManager {
|
||||
changeset_store,
|
||||
content_store,
|
||||
logger,
|
||||
reviewers_acl_checker: Arc::new(reviewers_acl_checker),
|
||||
}
|
||||
}
|
||||
|
||||
@ -414,6 +427,7 @@ impl HookManager {
|
||||
let hg_changeset = self.changeset_store
|
||||
.get_changeset_by_changesetid(&changeset_id);
|
||||
let changed_files = self.changeset_store.get_changed_files(&changeset_id);
|
||||
let reviewers_acl_checker = self.reviewers_acl_checker.clone();
|
||||
Box::new((hg_changeset, changed_files).into_future().and_then(
|
||||
move |(changeset, changed_files)| {
|
||||
let author = str::from_utf8(changeset.user())?.into();
|
||||
@ -432,6 +446,7 @@ impl HookManager {
|
||||
parents,
|
||||
changeset_id,
|
||||
content_store,
|
||||
reviewers_acl_checker,
|
||||
))
|
||||
},
|
||||
))
|
||||
@ -499,6 +514,7 @@ pub struct HookChangeset {
|
||||
pub parents: HookChangesetParents,
|
||||
content_store: Arc<FileContentStore>,
|
||||
changeset_id: HgChangesetId,
|
||||
reviewers_acl_checker: Arc<Option<AclChecker>>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for HookChangeset {
|
||||
@ -637,6 +653,7 @@ impl HookChangeset {
|
||||
parents: HookChangesetParents,
|
||||
changeset_id: HgChangesetId,
|
||||
content_store: Arc<FileContentStore>,
|
||||
reviewers_acl_checker: Arc<Option<AclChecker>>,
|
||||
) -> HookChangeset {
|
||||
HookChangeset {
|
||||
author,
|
||||
@ -645,6 +662,7 @@ impl HookChangeset {
|
||||
parents,
|
||||
content_store,
|
||||
changeset_id,
|
||||
reviewers_acl_checker,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1419,6 +1437,7 @@ mod test {
|
||||
.collect();
|
||||
let parents =
|
||||
HookChangesetParents::One("2f866e7e549760934e31bf0420a873f65100ad63".into());
|
||||
let reviewers_acl_checker = Arc::new(None);
|
||||
let data = HookChangeset::new(
|
||||
"Stanislau Hlebik <stash@fb.com>".into(),
|
||||
hook_files,
|
||||
@ -1426,6 +1445,7 @@ mod test {
|
||||
parents,
|
||||
cs_id,
|
||||
content_store,
|
||||
reviewers_acl_checker,
|
||||
);
|
||||
let expected_context = HookContext {
|
||||
hook_name: "hook1".into(),
|
||||
|
@ -11,6 +11,7 @@
|
||||
use super::{ChangedFileType, Hook, HookChangeset, HookChangesetParents, HookContext,
|
||||
HookExecution, HookFile, HookRejectionInfo};
|
||||
use super::errors::*;
|
||||
use aclchecker::Identity;
|
||||
use failure::Error;
|
||||
use futures::{failed, Future};
|
||||
use futures::future::ok;
|
||||
@ -199,14 +200,15 @@ impl Hook<HookChangeset> for LuaHook {
|
||||
};
|
||||
let parse_commit_msg = function0(parse_commit_msg);
|
||||
|
||||
let reviewers_acl_checker = context.data.reviewers_acl_checker.clone();
|
||||
let is_valid_reviewer = {
|
||||
move |user: String| -> Result<AnyFuture, Error> {
|
||||
// TODO(stash): actual implementation that checks the permissions
|
||||
if user == "invalidreviewer" {
|
||||
Ok(AnyFuture::new(ok(AnyLuaValue::LuaBoolean(false))))
|
||||
} else {
|
||||
Ok(AnyFuture::new(ok(AnyLuaValue::LuaBoolean(true))))
|
||||
}
|
||||
let user = Identity::with_user(&user);
|
||||
let valid = match *reviewers_acl_checker {
|
||||
Some(ref reviewers_acl_checker) => reviewers_acl_checker.is_member(&[&user]),
|
||||
None => false,
|
||||
};
|
||||
Ok(AnyFuture::new(ok(AnyLuaValue::LuaBoolean(valid))))
|
||||
}
|
||||
};
|
||||
let is_valid_reviewer = function1(is_valid_reviewer);
|
||||
@ -521,6 +523,7 @@ mod test {
|
||||
use super::*;
|
||||
use super::super::{ChangedFileType, HookChangeset, HookChangesetParents,
|
||||
InMemoryFileContentStore};
|
||||
use aclchecker::AclChecker;
|
||||
use async_unit;
|
||||
use bytes::Bytes;
|
||||
use futures::Future;
|
||||
@ -721,6 +724,7 @@ Signature: 111111111:1111111111:bbbbbbbbbbbbbbbb",
|
||||
let cs_id =
|
||||
HgChangesetId::from_str("473b2e715e0df6b2316010908879a3c78e275dd9").unwrap();
|
||||
let content_store = InMemoryFileContentStore::new();
|
||||
let reviewers_acl_checker = acl_checker();
|
||||
let hcs = HookChangeset::new(
|
||||
"some-author".into(),
|
||||
vec![],
|
||||
@ -728,6 +732,7 @@ Signature: 111111111:1111111111:bbbbbbbbbbbbbbbb",
|
||||
HookChangesetParents::One("p1-hash".into()),
|
||||
cs_id,
|
||||
Arc::new(content_store),
|
||||
reviewers_acl_checker,
|
||||
);
|
||||
let code = String::from(
|
||||
"hook = function (ctx)\n\
|
||||
@ -757,6 +762,7 @@ Signature: 111111111:1111111111:bbbbbbbbbbbbbbbb",
|
||||
let cs_id =
|
||||
HgChangesetId::from_str("473b2e715e0df6b2316010908879a3c78e275dd9").unwrap();
|
||||
let content_store = InMemoryFileContentStore::new();
|
||||
let reviewers_acl_checker = acl_checker();
|
||||
let hcs = HookChangeset::new(
|
||||
"some-author".into(),
|
||||
vec![],
|
||||
@ -764,6 +770,7 @@ Signature: 111111111:1111111111:bbbbbbbbbbbbbbbb",
|
||||
HookChangesetParents::One("p1-hash".into()),
|
||||
cs_id,
|
||||
Arc::new(content_store),
|
||||
reviewers_acl_checker,
|
||||
);
|
||||
let code = String::from(
|
||||
"hook = function (ctx)\n\
|
||||
@ -792,6 +799,7 @@ Signature: 111111111:1111111111:bbbbbbbbbbbbbbbb",
|
||||
let cs_id =
|
||||
HgChangesetId::from_str("473b2e715e0df6b2316010908879a3c78e275dd9").unwrap();
|
||||
let content_store = InMemoryFileContentStore::new();
|
||||
let reviewers_acl_checker = acl_checker();
|
||||
let hcs = HookChangeset::new(
|
||||
"Stanislau Hlebik <stash@fb.com>".into(),
|
||||
vec![],
|
||||
@ -799,6 +807,7 @@ Signature: 111111111:1111111111:bbbbbbbbbbbbbbbb",
|
||||
HookChangesetParents::One("p1-hash".into()),
|
||||
cs_id,
|
||||
Arc::new(content_store),
|
||||
reviewers_acl_checker,
|
||||
);
|
||||
let code = String::from(
|
||||
"hook = function (ctx)\n\
|
||||
@ -809,6 +818,38 @@ Signature: 111111111:1111111111:bbbbbbbbbbbbbbbb",
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cs_hook_valid_reviewer() {
|
||||
async_unit::tokio_unit_test(|| {
|
||||
let changeset = default_changeset();
|
||||
let code = String::from(
|
||||
"hook = function (ctx)\n\
|
||||
return ctx.is_valid_reviewer('tfox')\n\
|
||||
end",
|
||||
);
|
||||
assert_matches!(
|
||||
run_changeset_hook(code, changeset),
|
||||
Ok(HookExecution::Accepted)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cs_hook_not_valid_reviewer() {
|
||||
async_unit::tokio_unit_test(|| {
|
||||
let changeset = default_changeset();
|
||||
let code = String::from(
|
||||
"hook = function (ctx)\n\
|
||||
return not ctx.is_valid_reviewer('uyqdyqduygqwduygqwuydgqdfgbducbe2ubjweuhqwudh37')\n\
|
||||
end",
|
||||
);
|
||||
assert_matches!(
|
||||
run_changeset_hook(code, changeset),
|
||||
Ok(HookExecution::Accepted)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cs_hook_rejected_short_and_long_desc() {
|
||||
async_unit::tokio_unit_test(|| {
|
||||
@ -1552,7 +1593,7 @@ Signature: 111111111:1111111111:bbbbbbbbbbbbbbbb",
|
||||
hook_files.extend(create_hook_files(added, ChangedFileType::Added));
|
||||
hook_files.extend(create_hook_files(deleted, ChangedFileType::Deleted));
|
||||
hook_files.extend(create_hook_files(modified, ChangedFileType::Modified));
|
||||
|
||||
let reviewers_acl_checker = acl_checker();
|
||||
HookChangeset::new(
|
||||
"some-author".into(),
|
||||
hook_files,
|
||||
@ -1560,6 +1601,7 @@ Signature: 111111111:1111111111:bbbbbbbbbbbbbbbb",
|
||||
HookChangesetParents::One("p1-hash".into()),
|
||||
cs_id,
|
||||
content_store2,
|
||||
reviewers_acl_checker,
|
||||
)
|
||||
}
|
||||
|
||||
@ -1604,4 +1646,10 @@ Signature: 111111111:1111111111:bbbbbbbbbbbbbbbb",
|
||||
)
|
||||
}
|
||||
|
||||
fn acl_checker() -> Arc<Option<AclChecker>> {
|
||||
let checker = AclChecker::new(&Identity::from_groupname("engineers"));
|
||||
assert!(checker.do_wait_updated(10000));
|
||||
Arc::new(Some(checker))
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user