use derive_builder::Builder;
use git_checks_core::impl_prelude::*;
use crate::binary_format;
#[derive(Builder, Debug, Default, Clone, Copy)]
#[builder(field(private))]
pub struct RejectBinaries {}
impl RejectBinaries {
pub fn builder() -> RejectBinariesBuilder {
RejectBinariesBuilder::default()
}
}
impl ContentCheck for RejectBinaries {
fn name(&self) -> &str {
"reject-binaries"
}
fn check(
&self,
ctx: &CheckGitContext,
content: &dyn Content,
) -> Result<CheckResult, Box<dyn Error>> {
let mut result = CheckResult::new();
for diff in content.diffs() {
match diff.status {
StatusChange::Added | StatusChange::Modified(_) => (),
_ => continue,
}
let binary_attr = ctx.check_attr("hooks-allow-binary", diff.name.as_path())?;
let allowed_binary_type = match binary_attr {
AttributeState::Set => continue,
AttributeState::Value(ref v) => Some(v),
_ => None,
};
let binary_type = {
let cat_file = ctx
.git()
.arg("cat-file")
.arg("blob")
.arg(diff.new_blob.as_str())
.output()
.map_err(|err| GitError::subcommand("cat-file", err))?;
let stdout = cat_file.stdout;
binary_format::detect_binary_format(stdout)
};
if let Some(binary_type) = binary_type {
let type_name = binary_type.name();
if let Some(allowed_binary_type) = allowed_binary_type {
if allowed_binary_type != type_name {
result.add_error(format!(
"{}adds the {} (not {}) binary `{}`.",
commit_prefix(content),
type_name,
allowed_binary_type,
diff.name,
));
}
} else {
result.add_error(format!(
"{}adds the {} binary `{}`.",
commit_prefix(content),
type_name,
diff.name,
));
}
}
}
Ok(result)
}
}
#[cfg(feature = "config")]
pub(crate) mod config {
use git_checks_config::{register_checks, CommitCheckConfig, IntoCheck, TopicCheckConfig};
use serde::Deserialize;
#[cfg(test)]
use serde_json::json;
use crate::RejectBinaries;
#[derive(Deserialize, Debug)]
pub struct RejectBinariesConfig {}
impl IntoCheck for RejectBinariesConfig {
type Check = RejectBinaries;
fn into_check(self) -> Self::Check {
RejectBinaries::default()
}
}
register_checks! {
RejectBinariesConfig {
"reject_binaries" => CommitCheckConfig,
"reject_binaries/topic" => TopicCheckConfig,
},
}
#[test]
fn test_reject_binaries_config_empty() {
let json = json!({});
let check: RejectBinariesConfig = serde_json::from_value(json).unwrap();
let _ = check.into_check();
}
}
#[cfg(test)]
mod tests {
use git_checks_core::{Check, TopicCheck};
use crate::test::*;
use crate::RejectBinaries;
const BAD_COMMIT: &str = "8ca74bdcc09a1a9e0b44c0b9e6cd8e6af9097c89";
const BAD_COMMIT_EXE: &str = "1de03da52b04d5394b75d222f246d3524572bd12";
const DELETE_COMMIT: &str = "141bc952382f9e9276e46a58dbb79aa8fe3ea435";
const ATTR_COMMIT: &str = "f27e6907d6c0d112e47f63b2b91178c1c23c9f4d";
const ATTR_COMMIT_BAD: &str = "2a9649acf5a4af7d1e8e393c11a7ab0c268a9b44";
const FIX_ATTR_COMMIT: &str = "1c53216257cb8af8fb0dc7b1577ef63605305318";
#[test]
fn test_reject_binaries_builder_default() {
assert!(RejectBinaries::builder().build().is_ok());
}
#[test]
fn test_reject_binaries_name_commit() {
let check = RejectBinaries::default();
assert_eq!(Check::name(&check), "reject-binaries");
}
#[test]
fn test_reject_binaries_name_topic() {
let check = RejectBinaries::default();
assert_eq!(TopicCheck::name(&check), "reject-binaries");
}
#[test]
fn test_reject_binaries() {
let check = RejectBinaries::default();
let result = run_check("test_reject_binaries", BAD_COMMIT, check);
test_result_errors(result, &[
"commit e5e1e2c8db62ac8f50f249d3cf3f334ddf158936 adds the ELF binary `elf-header`.",
"commit e5e1e2c8db62ac8f50f249d3cf3f334ddf158936 adds the Mach-O binary `macho-cigam-header`.",
"commit e5e1e2c8db62ac8f50f249d3cf3f334ddf158936 adds the Mach-O binary `macho-fat-cigam-header`.",
"commit e5e1e2c8db62ac8f50f249d3cf3f334ddf158936 adds the Mach-O binary `macho-fat-magic-header`.",
"commit e5e1e2c8db62ac8f50f249d3cf3f334ddf158936 adds the Mach-O binary `macho-magic-header`.",
"commit 8326e6bcc8cd6718e367d889bcb64739982b6c66 adds the AR binary `ar-header`.",
"commit 8ca74bdcc09a1a9e0b44c0b9e6cd8e6af9097c89 adds the PE binary `pe-le-header`.",
]);
}
#[test]
fn test_reject_binaries_plus_x() {
let check = RejectBinaries::default();
let result = run_check("test_reject_binaries_plus_x", BAD_COMMIT_EXE, check);
test_result_errors(result, &[
"commit e5e1e2c8db62ac8f50f249d3cf3f334ddf158936 adds the ELF binary `elf-header`.",
"commit e5e1e2c8db62ac8f50f249d3cf3f334ddf158936 adds the Mach-O binary `macho-cigam-header`.",
"commit e5e1e2c8db62ac8f50f249d3cf3f334ddf158936 adds the Mach-O binary `macho-fat-cigam-header`.",
"commit e5e1e2c8db62ac8f50f249d3cf3f334ddf158936 adds the Mach-O binary `macho-fat-magic-header`.",
"commit e5e1e2c8db62ac8f50f249d3cf3f334ddf158936 adds the Mach-O binary `macho-magic-header`.",
"commit 261577469c6790190d866a928dc3bd8e91d238cf adds the ELF binary `elf-header`.",
"commit 261577469c6790190d866a928dc3bd8e91d238cf adds the Mach-O binary `macho-cigam-header`.",
"commit 261577469c6790190d866a928dc3bd8e91d238cf adds the Mach-O binary `macho-fat-cigam-header`.",
"commit 261577469c6790190d866a928dc3bd8e91d238cf adds the Mach-O binary `macho-fat-magic-header`.",
"commit 261577469c6790190d866a928dc3bd8e91d238cf adds the Mach-O binary `macho-magic-header`.",
"commit b8c710757905c59cf880ade2af288b6891b5723c adds the AR binary `ar-header`.",
"commit 1de03da52b04d5394b75d222f246d3524572bd12 adds the PE binary `pe-le-header`.",
]);
}
#[test]
fn test_reject_binaries_delete_file() {
let check = RejectBinaries::default();
let conf = make_check_conf(&check);
let result = test_check_base(
"test_reject_binaries_delete_file",
DELETE_COMMIT,
BAD_COMMIT,
&conf,
);
test_result_ok(result);
}
#[test]
fn test_reject_binaries_delete_file_topic() {
let check = RejectBinaries::default();
run_topic_check_ok(
"test_reject_binaries_delete_file_topic",
DELETE_COMMIT,
check,
);
}
#[test]
fn test_reject_binaries_attr_ok() {
let check = RejectBinaries::default();
run_check_ok("test_reject_binaries_attr_ok", ATTR_COMMIT, check)
}
#[test]
fn test_reject_binaries_attr_bad() {
let check = RejectBinaries::default();
let result = run_check("test_reject_binaries_attr_bad", ATTR_COMMIT_BAD, check);
test_result_errors(result, &[
"commit 71fa463c4bedeb40807b6c73b08ce207b0fe0309 adds the ELF (not Mach-O) binary `elf-header`.",
"commit 71fa463c4bedeb40807b6c73b08ce207b0fe0309 adds the Mach-O (not ELF) binary `macho-cigam-header`.",
"commit 71fa463c4bedeb40807b6c73b08ce207b0fe0309 adds the Mach-O (not ELF) binary `macho-fat-cigam-header`.",
"commit 71fa463c4bedeb40807b6c73b08ce207b0fe0309 adds the Mach-O (not ELF) binary `macho-fat-magic-header`.",
"commit 71fa463c4bedeb40807b6c73b08ce207b0fe0309 adds the Mach-O (not ELF) binary `macho-magic-header`.",
"commit 107c49759fe7d603d83264cd2e013054f730f534 adds the AR (not ELF) binary `ar-header`.",
"commit 2a9649acf5a4af7d1e8e393c11a7ab0c268a9b44 adds the PE (not ELF) binary `pe-le-header`.",
]);
}
#[test]
fn test_reject_binaries_topic() {
let check = RejectBinaries::default();
let result = run_topic_check("test_reject_binaries_topic", BAD_COMMIT, check);
test_result_errors(
result,
&[
"adds the AR binary `ar-header`.",
"adds the ELF binary `elf-header`.",
"adds the Mach-O binary `macho-cigam-header`.",
"adds the Mach-O binary `macho-fat-cigam-header`.",
"adds the Mach-O binary `macho-fat-magic-header`.",
"adds the Mach-O binary `macho-magic-header`.",
"adds the PE binary `pe-le-header`.",
],
);
}
#[test]
fn test_reject_binaries_topic_attr_ok() {
let check = RejectBinaries::default();
run_topic_check_ok("test_reject_binaries_topic_attr_ok", ATTR_COMMIT, check)
}
#[test]
fn test_reject_binaries_topic_attr_bad() {
let check = RejectBinaries::default();
let result = run_topic_check(
"test_reject_binaries_topic_attr_bad",
ATTR_COMMIT_BAD,
check,
);
test_result_errors(
result,
&[
"adds the AR (not ELF) binary `ar-header`.",
"adds the ELF (not Mach-O) binary `elf-header`.",
"adds the Mach-O (not ELF) binary `macho-cigam-header`.",
"adds the Mach-O (not ELF) binary `macho-fat-cigam-header`.",
"adds the Mach-O (not ELF) binary `macho-fat-magic-header`.",
"adds the Mach-O (not ELF) binary `macho-magic-header`.",
"adds the PE (not ELF) binary `pe-le-header`.",
],
);
}
#[test]
fn test_reject_binaries_topic_plus_x() {
let check = RejectBinaries::default();
let result = run_topic_check("test_reject_binaries_topic_plus_x", BAD_COMMIT_EXE, check);
test_result_errors(
result,
&[
"adds the AR binary `ar-header`.",
"adds the ELF binary `elf-header`.",
"adds the Mach-O binary `macho-cigam-header`.",
"adds the Mach-O binary `macho-fat-cigam-header`.",
"adds the Mach-O binary `macho-fat-magic-header`.",
"adds the Mach-O binary `macho-magic-header`.",
"adds the PE binary `pe-le-header`.",
],
);
}
#[test]
fn test_reject_binaries_topic_fixed() {
let check = RejectBinaries::default();
run_topic_check_ok("test_reject_binaries_topic_fixed", DELETE_COMMIT, check);
}
#[test]
fn test_reject_binaries_topic_attr_fixed() {
let check = RejectBinaries::default();
run_topic_check_ok(
"test_reject_binaries_topic_attr_fixed",
FIX_ATTR_COMMIT,
check,
);
}
}