feat: ignore github ping webhook messages
All checks were successful
Rust / build (push) Successful in 2m13s
ci/woodpecker/push/cron-docker-builder Pipeline was successful
ci/woodpecker/push/push-next Pipeline was successful
ci/woodpecker/push/tag-created Pipeline was successful

Closes kemitix/git-next#101
This commit is contained in:
Paul Campbell 2024-06-30 15:20:00 +01:00
parent 8fceafc3e1
commit 55d8ccb0bd
5 changed files with 74 additions and 2 deletions

View file

@ -34,6 +34,18 @@ impl git::ForgeLike for Github {
github::webhook::is_authorised(msg, webhook_auth) github::webhook::is_authorised(msg, webhook_auth)
} }
fn should_ignore_message(&self, message: &config::ForgeNotification) -> bool {
let Some(event) = message.header("x-github-event") else {
return false;
};
if event == "ping" {
tracing::info!("successfull ping received");
return true;
}
tracing::info!(%event, "message");
false
}
fn parse_webhook_body( fn parse_webhook_body(
&self, &self,
body: &config::webhook::forge_notification::Body, body: &config::webhook::forge_notification::Body,

File diff suppressed because one or more lines are too long

View file

@ -7,13 +7,20 @@ pub trait ForgeLike: std::fmt::Debug + Send + Sync {
fn duplicate(&self) -> Box<dyn ForgeLike>; fn duplicate(&self) -> Box<dyn ForgeLike>;
fn name(&self) -> String; fn name(&self) -> String;
/// Checks that the message has a valid authorisation /// Checks that the message has a valid authorisation.
fn is_message_authorised( fn is_message_authorised(
&self, &self,
message: &config::ForgeNotification, message: &config::ForgeNotification,
expected: &config::WebhookAuth, expected: &config::WebhookAuth,
) -> bool; ) -> bool;
/// Checks if the message should be ignored.
///
/// Default implementation says that no messages should be ignored.
fn should_ignore_message(&self, _message: &config::ForgeNotification) -> bool {
false
}
/// Parses the webhook body into Some(Push) struct if appropriate, or None if not. /// Parses the webhook body into Some(Push) struct if appropriate, or None if not.
fn parse_webhook_body( fn parse_webhook_body(
&self, &self,

View file

@ -34,6 +34,10 @@ impl Handler<WebhookNotification> for actor::RepoActor {
); );
return; return;
} }
if self.forge.should_ignore_message(&msg) {
actor::logger(&self.log, "forge sent ignorable message");
return;
}
let body = msg.body(); let body = msg.body();
match self.forge.parse_webhook_body(body) { match self.forge.parse_webhook_body(body) {
Err(err) => { Err(err) => {

View file

@ -107,6 +107,48 @@ async fn when_message_auth_is_invalid_drop_notification() -> TestResult {
Ok(()) Ok(())
} }
#[actix::test]
async fn when_message_is_ignorable_drop_notification() -> TestResult {
//given
let fs = given::a_filesystem();
let repo_details = given::repo_details(&fs);
let forge_alias = given::a_forge_alias();
let repo_alias = given::a_repo_alias();
let headers = BTreeMap::new();
let body = Body::new("".to_string());
let forge_notification = ForgeNotification::new(forge_alias, repo_alias, headers, body);
let repository_factory = MockRepositoryFactory::new();
let mut forge = given::a_forge();
forge
.expect_is_message_authorised()
.return_once(|_, _| true); // is valid
forge.expect_should_ignore_message().returning(|_| true);
forge
.expect_parse_webhook_body()
.return_once(|_| Err(git::forge::webhook::Error::NetworkResponseEmpty));
let (actor, log) = given::a_repo_actor(
repo_details,
Box::new(repository_factory),
forge,
given::a_network().into(),
);
let actor = actor.with_webhook_auth(Some(given::a_webhook_auth()));
//when
actor
.start()
.send(actor::messages::WebhookNotification::new(
forge_notification,
))
.await?;
System::current().stop();
//then
log.no_message_contains("send")?;
log.require_message_containing("forge sent ignorable message")?;
Ok(())
}
#[actix::test] #[actix::test]
async fn when_message_is_not_a_push_drop_notification() -> TestResult { async fn when_message_is_not_a_push_drop_notification() -> TestResult {
//given //given
@ -122,6 +164,7 @@ async fn when_message_is_not_a_push_drop_notification() -> TestResult {
forge forge
.expect_is_message_authorised() .expect_is_message_authorised()
.return_once(|_, _| true); // is valid .return_once(|_, _| true); // is valid
forge.expect_should_ignore_message().returning(|_| false);
forge forge
.expect_parse_webhook_body() .expect_parse_webhook_body()
.return_once(|_| Err(git::forge::webhook::Error::NetworkResponseEmpty)); .return_once(|_| Err(git::forge::webhook::Error::NetworkResponseEmpty));
@ -169,6 +212,7 @@ async fn when_message_is_push_on_unknown_branch_drop_notification() -> TestResul
forge forge
.expect_is_message_authorised() .expect_is_message_authorised()
.return_once(|_, _| true); // is valid .return_once(|_, _| true); // is valid
forge.expect_should_ignore_message().returning(|_| false);
forge.expect_parse_webhook_body().return_once(|_| Ok(push)); forge.expect_parse_webhook_body().return_once(|_| Ok(push));
let (actor, log) = given::a_repo_actor( let (actor, log) = given::a_repo_actor(
repo_details, repo_details,
@ -216,6 +260,7 @@ async fn when_message_is_push_already_seen_commit_to_main() -> TestResult {
forge forge
.expect_is_message_authorised() .expect_is_message_authorised()
.return_once(|_, _| true); // is valid .return_once(|_, _| true); // is valid
forge.expect_should_ignore_message().returning(|_| false);
forge.expect_parse_webhook_body().return_once(|_| Ok(push)); forge.expect_parse_webhook_body().return_once(|_| Ok(push));
let (actor, log) = given::a_repo_actor( let (actor, log) = given::a_repo_actor(
repo_details, repo_details,
@ -263,6 +308,7 @@ async fn when_message_is_push_already_seen_commit_to_next() -> TestResult {
forge forge
.expect_is_message_authorised() .expect_is_message_authorised()
.return_once(|_, _| true); // is valid .return_once(|_, _| true); // is valid
forge.expect_should_ignore_message().returning(|_| false);
forge.expect_parse_webhook_body().return_once(|_| Ok(push)); forge.expect_parse_webhook_body().return_once(|_| Ok(push));
let (actor, log) = given::a_repo_actor( let (actor, log) = given::a_repo_actor(
repo_details, repo_details,
@ -310,6 +356,7 @@ async fn when_message_is_push_already_seen_commit_to_dev() -> TestResult {
forge forge
.expect_is_message_authorised() .expect_is_message_authorised()
.return_once(|_, _| true); // is valid .return_once(|_, _| true); // is valid
forge.expect_should_ignore_message().returning(|_| false);
forge.expect_parse_webhook_body().return_once(|_| Ok(push)); forge.expect_parse_webhook_body().return_once(|_| Ok(push));
let (actor, log) = given::a_repo_actor( let (actor, log) = given::a_repo_actor(
repo_details, repo_details,
@ -357,6 +404,7 @@ async fn when_message_is_push_new_commit_to_main_should_stash_and_validate_repo(
forge forge
.expect_is_message_authorised() .expect_is_message_authorised()
.return_once(|_, _| true); // is valid .return_once(|_, _| true); // is valid
forge.expect_should_ignore_message().returning(|_| false);
forge.expect_parse_webhook_body().return_once(|_| Ok(push)); forge.expect_parse_webhook_body().return_once(|_| Ok(push));
let (actor, log) = given::a_repo_actor( let (actor, log) = given::a_repo_actor(
repo_details, repo_details,
@ -404,6 +452,7 @@ async fn when_message_is_push_new_commit_to_next_should_stash_and_validate_repo(
forge forge
.expect_is_message_authorised() .expect_is_message_authorised()
.return_once(|_, _| true); // is valid .return_once(|_, _| true); // is valid
forge.expect_should_ignore_message().returning(|_| false);
forge.expect_parse_webhook_body().return_once(|_| Ok(push)); forge.expect_parse_webhook_body().return_once(|_| Ok(push));
let (actor, log) = given::a_repo_actor( let (actor, log) = given::a_repo_actor(
repo_details, repo_details,
@ -451,6 +500,7 @@ async fn when_message_is_push_new_commit_to_dev_should_stash_and_validate_repo()
forge forge
.expect_is_message_authorised() .expect_is_message_authorised()
.return_once(|_, _| true); // is valid .return_once(|_, _| true); // is valid
forge.expect_should_ignore_message().returning(|_| false);
forge.expect_parse_webhook_body().return_once(|_| Ok(push)); forge.expect_parse_webhook_body().return_once(|_| Ok(push));
let (actor, log) = given::a_repo_actor( let (actor, log) = given::a_repo_actor(
repo_details, repo_details,