Compare commits

...

2 commits

Author SHA1 Message Date
ad358ad7c2 refactor: cleanup pedantic clippy in forge-github crate
All checks were successful
Rust / build (push) Successful in 2m17s
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
Release Please / Release-plz (push) Successful in 37s
2024-08-06 16:21:25 +01:00
067296ffab refactor: cleanup pedantic clippy in forge-forgejo crate
Some checks are pending
Rust / build (push) Successful in 1m21s
Release Please / Release-plz (push) Waiting to run
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
2024-08-06 16:15:56 +01:00
13 changed files with 63 additions and 65 deletions

View file

@ -6,6 +6,15 @@ license = { workspace = true }
repository = { workspace = true } repository = { workspace = true }
description = "Forgejo support for git-next, the trunk-based development manager" description = "Forgejo support for git-next, the trunk-based development manager"
[lints.clippy]
nursery = { level = "warn", priority = -1 }
pedantic = { level = "warn", priority = -1 }
unwrap_used = "warn"
expect_used = "warn"
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tarpaulin_include)'] }
[dependencies] [dependencies]
git-next-core = { workspace = true } git-next-core = { workspace = true }
@ -32,12 +41,3 @@ tokio = { workspace = true }
# Testing # Testing
assert2 = { workspace = true } assert2 = { workspace = true }
rand = { workspace = true } rand = { workspace = true }
[lints.clippy]
nursery = { level = "warn", priority = -1 }
# pedantic = "warn"
unwrap_used = "warn"
expect_used = "warn"
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tarpaulin_include)'] }

View file

@ -4,6 +4,8 @@ mod tests;
mod webhook; mod webhook;
use std::borrow::ToOwned;
use git_next_core::{ use git_next_core::{
self as core, self as core,
git::{self, forge::commit::Status}, git::{self, forge::commit::Status},
@ -20,6 +22,7 @@ pub struct ForgeJo {
net: Network, net: Network,
} }
impl ForgeJo { impl ForgeJo {
#[must_use]
pub const fn new(repo_details: git::RepoDetails, net: Network) -> Self { pub const fn new(repo_details: git::RepoDetails, net: Network) -> Self {
Self { repo_details, net } Self { repo_details, net }
} }
@ -37,10 +40,9 @@ impl git::ForgeLike for ForgeJo {
let authorization = msg.header("authorization"); let authorization = msg.header("authorization");
tracing::info!(?authorization, %expected, "is message authorised?"); tracing::info!(?authorization, %expected, "is message authorised?");
authorization authorization
.and_then(|header| header.strip_prefix("Basic ").map(|v| v.to_owned())) .and_then(|header| header.strip_prefix("Basic ").map(ToOwned::to_owned))
.and_then(|value| WebhookAuth::try_new(value.as_str()).ok()) .and_then(|value| WebhookAuth::try_new(value.as_str()).ok())
.map(|auth| &auth == expected) .is_some_and(|auth| &auth == expected)
.unwrap_or(false)
} }
fn parse_webhook_body( fn parse_webhook_body(
@ -75,10 +77,8 @@ impl git::ForgeLike for ForgeJo {
Ok(response) => match response.response_body() { Ok(response) => match response.response_body() {
Some(status) => match status.state { Some(status) => match status.state {
ForgejoState::Success => Status::Pass, ForgejoState::Success => Status::Pass,
ForgejoState::Pending => Status::Pending, ForgejoState::Pending | ForgejoState::Blank => Status::Pending,
ForgejoState::Failure => Status::Fail, ForgejoState::Failure | ForgejoState::Error => Status::Fail,
ForgejoState::Error => Status::Fail,
ForgejoState::Blank => Status::Pending,
}, },
None => { None => {
#[cfg(not(tarpaulin_include))] #[cfg(not(tarpaulin_include))]

View file

@ -284,7 +284,7 @@ mod forgejo {
let forge = given::a_forgejo_forge(&repo_details, net); let forge = given::a_forgejo_forge(&repo_details, net);
let_assert!(Ok(_) = forge.unregister_webhook(&webhook_id).await); let_assert!(Ok(()) = forge.unregister_webhook(&webhook_id).await);
} }
#[tokio::test] #[tokio::test]
@ -397,13 +397,15 @@ mod forgejo {
repo_path, repo_path,
token, token,
}; };
let hook1 = with::ReturnedWebhook::new(given::a_forgejo_webhook_id(), &repo_listen_url); let hook_1 =
let hook2 = with::ReturnedWebhook::new(given::a_forgejo_webhook_id(), &repo_listen_url); with::ReturnedWebhook::new(given::a_forgejo_webhook_id(), &repo_listen_url);
let hook3 = with::ReturnedWebhook::new( let hook_2 =
with::ReturnedWebhook::new(given::a_forgejo_webhook_id(), &repo_listen_url);
let hook_3 = with::ReturnedWebhook::new(
given::a_forgejo_webhook_id(), given::a_forgejo_webhook_id(),
&given::a_repo_listen_url(&repo_details), &given::a_repo_listen_url(&repo_details),
); );
let hooks = [hook1, hook2, hook3]; let hooks = [hook_1, hook_2, hook_3];
// there are three existing webhooks, two are matching webhooks // there are three existing webhooks, two are matching webhooks
with::get_webhooks_by_page(1, &hooks, &mut args); with::get_webhooks_by_page(1, &hooks, &mut args);
@ -585,7 +587,7 @@ mod forgejo {
a_commit_status_url(repo_details, commit).as_str(), a_commit_status_url(repo_details, commit).as_str(),
StatusCode::OK, StatusCode::OK,
response.to_string().as_str(), response.to_string().as_str(),
) );
} }
pub fn a_commit_status_url( pub fn a_commit_status_url(
@ -709,7 +711,7 @@ mod forgejo {
a_name(), a_name(),
a_name(), a_name(),
a_name(), a_name(),
Default::default(), // no repos BTreeMap::default(), // no repos
) )
} }

View file

@ -4,12 +4,12 @@ use git_next_core::{git, webhook, BranchName, WebhookId};
use std::collections::HashMap; use std::collections::HashMap;
mod list; mod list;
mod parse; mod parser;
mod register; mod register;
mod unregister; mod unregister;
pub use list::list; pub use list::list;
pub use parse::parse_body; pub use parser::parse_body;
pub use register::register; pub use register::register;
pub use unregister::unregister; pub use unregister::unregister;

View file

@ -1,14 +1,14 @@
use git_next_core::server::RepoListenUrl;
// //
use git_next_core::{git, RegisteredWebhook, WebhookAuth, WebhookId}; use git_next_core::{git, server::RepoListenUrl, RegisteredWebhook, WebhookAuth, WebhookId};
use kxio::network; use kxio::network;
use tracing::{info, warn}; use secrecy::ExposeSecret as _;
use tracing::{info, instrument, warn};
use crate::webhook; use crate::webhook;
use crate::webhook::Hook; use crate::webhook::Hook;
#[tracing::instrument(skip_all)] #[instrument(skip_all)]
pub async fn register( pub async fn register(
repo_details: &git::RepoDetails, repo_details: &git::RepoDetails,
repo_listen_url: &RepoListenUrl, repo_listen_url: &RepoListenUrl,
@ -26,7 +26,6 @@ pub async fn register(
let hostname = &repo_details.forge.hostname(); let hostname = &repo_details.forge.hostname();
let repo_path = &repo_details.repo_path; let repo_path = &repo_details.repo_path;
use secrecy::ExposeSecret;
let token = repo_details.forge.token().expose_secret(); let token = repo_details.forge.token().expose_secret();
let url = network::NetUrl::new(format!( let url = network::NetUrl::new(format!(
"https://{hostname}/api/v1/repos/{repo_path}/hooks?token={token}" "https://{hostname}/api/v1/repos/{repo_path}/hooks?token={token}"

View file

@ -2,6 +2,7 @@
use git_next_core::{git, WebhookId}; use git_next_core::{git, WebhookId};
use kxio::network; use kxio::network;
use secrecy::ExposeSecret as _;
pub async fn unregister( pub async fn unregister(
webhook_id: &WebhookId, webhook_id: &WebhookId,
@ -10,7 +11,6 @@ pub async fn unregister(
) -> git::forge::webhook::Result<()> { ) -> git::forge::webhook::Result<()> {
let hostname = &repo_details.forge.hostname(); let hostname = &repo_details.forge.hostname();
let repo_path = &repo_details.repo_path; let repo_path = &repo_details.repo_path;
use secrecy::ExposeSecret;
let token = repo_details.forge.token().expose_secret(); let token = repo_details.forge.token().expose_secret();
let url = network::NetUrl::new(format!( let url = network::NetUrl::new(format!(
"https://{hostname}/api/v1/repos/{repo_path}/hooks/{webhook_id}?token={token}" "https://{hostname}/api/v1/repos/{repo_path}/hooks/{webhook_id}?token={token}"

View file

@ -6,6 +6,15 @@ license = { workspace = true }
repository = { workspace = true } repository = { workspace = true }
description = "GitHub support for git-next, the trunk-based development manager" description = "GitHub support for git-next, the trunk-based development manager"
[lints.clippy]
nursery = { level = "warn", priority = -1 }
pedantic = { level = "warn", priority = -1 }
unwrap_used = "warn"
expect_used = "warn"
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tarpaulin_include)'] }
[dependencies] [dependencies]
git-next-core = { workspace = true } git-next-core = { workspace = true }
@ -43,12 +52,3 @@ tokio = { workspace = true }
# Testing # Testing
assert2 = { workspace = true } assert2 = { workspace = true }
rand = { workspace = true } rand = { workspace = true }
[lints.clippy]
nursery = { level = "warn", priority = -1 }
# pedantic = "warn"
unwrap_used = "warn"
expect_used = "warn"
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tarpaulin_include)'] }

View file

@ -6,7 +6,7 @@ use kxio::network;
/// Checks the results of any (e.g. CI) status checks for the commit. /// Checks the results of any (e.g. CI) status checks for the commit.
/// ///
/// GitHub: https://docs.github.com/en/rest/commits/statuses?apiVersion=2022-11-28#list-commit-statuses-for-a-reference /// GitHub: <https://docs.github.com/en/rest/commits/statuses?apiVersion=2022-11-28#list-commit-statuses-for-a-reference>
pub async fn status(github: &github::Github, commit: &git::Commit) -> git::forge::commit::Status { pub async fn status(github: &github::Github, commit: &git::Commit) -> git::forge::commit::Status {
let repo_details = &github.repo_details; let repo_details = &github.repo_details;
let hostname = repo_details.forge.hostname(); let hostname = repo_details.forge.hostname();
@ -33,17 +33,13 @@ pub async fn status(github: &github::Github, commit: &git::Commit) -> git::forge
.into_iter() .into_iter()
.map(|status| match status.state { .map(|status| match status.state {
GithubState::Success => Status::Pass, GithubState::Success => Status::Pass,
GithubState::Pending => Status::Pending, GithubState::Pending | GithubState::Blank => Status::Pending,
GithubState::Failure => Status::Fail, GithubState::Failure | GithubState::Error => Status::Fail,
GithubState::Error => Status::Fail,
GithubState::Blank => Status::Pending,
}) })
.reduce(|l, r| match (l, r) { .reduce(|l, r| match (l, r) {
(Status::Pass, Status::Pass) => Status::Pass, (Status::Pass, Status::Pass) => Status::Pass,
(_, Status::Fail) => Status::Fail, (_, Status::Fail) | (Status::Fail, _) => Status::Fail,
(Status::Fail, _) => Status::Fail, (_, Status::Pending) | (Status::Pending, _) => Status::Pending,
(_, Status::Pending) => Status::Pending,
(Status::Pending, _) => Status::Pending,
}) })
}) })
.unwrap_or_else(|| { .unwrap_or_else(|| {

View file

@ -231,7 +231,7 @@ mod github {
let forge = given::a_github_forge(&repo_details, net); let forge = given::a_github_forge(&repo_details, net);
let_assert!(Ok(_) = forge.unregister_webhook(&webhook_id).await); let_assert!(Ok(()) = forge.unregister_webhook(&webhook_id).await);
} }
#[tokio::test] #[tokio::test]
async fn should_return_error_on_network_error() { async fn should_return_error_on_network_error() {
@ -335,11 +335,11 @@ mod github {
hostname, hostname,
repo_path, repo_path,
}; };
let hook1 = with::ReturnedWebhook::new(given::a_github_webhook_id(), &repo_listen_url); let hook_1 = with::ReturnedWebhook::new(given::a_github_webhook_id(), &repo_listen_url);
let hook2 = with::ReturnedWebhook::new(given::a_github_webhook_id(), &repo_listen_url); let hook_2 = with::ReturnedWebhook::new(given::a_github_webhook_id(), &repo_listen_url);
let hook3 = let hook_3 =
with::ReturnedWebhook::new(given::a_github_webhook_id(), &given::any_webhook_url()); with::ReturnedWebhook::new(given::a_github_webhook_id(), &given::any_webhook_url());
let hooks = [hook1, hook2, hook3]; let hooks = [hook_1, hook_2, hook_3];
// there are three existing webhooks, two are matching webhooks // there are three existing webhooks, two are matching webhooks
with::get_webhooks_by_page(1, &hooks, &mut args); with::get_webhooks_by_page(1, &hooks, &mut args);
with::get_webhooks_by_page(2, &[], &mut args); with::get_webhooks_by_page(2, &[], &mut args);
@ -511,7 +511,7 @@ mod github {
a_commit_status_url(repo_details, commit).as_str(), a_commit_status_url(repo_details, commit).as_str(),
StatusCode::OK, StatusCode::OK,
response.to_string().as_str(), response.to_string().as_str(),
) );
} }
pub fn a_commit_status_url( pub fn a_commit_status_url(

View file

@ -1,17 +1,20 @@
// //
use std::string::ToString;
use git_next_core::{ForgeNotification, WebhookAuth}; use git_next_core::{ForgeNotification, WebhookAuth};
use hmac::Mac;
type HmacSha256 = hmac::Hmac<sha2::Sha256>;
pub fn is_authorised(msg: &ForgeNotification, webhook_auth: &WebhookAuth) -> bool { pub fn is_authorised(msg: &ForgeNotification, webhook_auth: &WebhookAuth) -> bool {
msg.header("x-hub-signature-256") msg.header("x-hub-signature-256")
.map(|x| x.trim_matches('"').to_string()) .map(|x| x.trim_matches('"').to_string())
.and_then(|sha| sha.strip_prefix("sha256=").map(|k| k.to_string())) .and_then(|sha| sha.strip_prefix("sha256=").map(ToString::to_string))
.and_then(|github_signature| hex::decode(github_signature).ok()) .and_then(|github_signature| hex::decode(github_signature).ok())
.and_then(|gh_sig| { .and_then(|gh_sig| {
let payload = &msg.body().as_str(); let payload = &msg.body().as_str();
use hmac::Mac;
type HmacSha256 = hmac::Hmac<sha2::Sha256>;
let mut hmac = HmacSha256::new_from_slice(webhook_auth.to_string().as_bytes()).ok()?; let mut hmac = HmacSha256::new_from_slice(webhook_auth.to_string().as_bytes()).ok()?;
hmac::Mac::update(&mut hmac, payload.as_ref()); hmac::Mac::update(&mut hmac, payload.as_ref());
Some(hmac::Mac::verify_slice(hmac, gh_sig.as_ref()).is_ok()) Some(hmac::Mac::verify_slice(hmac, gh_sig.as_ref()).is_ok())
@ -25,8 +28,6 @@ pub fn sign_body(
body: &git_next_core::webhook::forge_notification::Body, body: &git_next_core::webhook::forge_notification::Body,
) -> Option<String> { ) -> Option<String> {
let payload = body.as_str(); let payload = body.as_str();
use hmac::Mac;
type HmacSha256 = hmac::Hmac<sha2::Sha256>;
let mut hmac = HmacSha256::new_from_slice(webhook_auth.to_string().as_bytes()).ok()?; let mut hmac = HmacSha256::new_from_slice(webhook_auth.to_string().as_bytes()).ok()?;
hmac::Mac::update(&mut hmac, payload.as_ref()); hmac::Mac::update(&mut hmac, payload.as_ref());
let f = hmac::Mac::finalize(hmac); let f = hmac::Mac::finalize(hmac);

View file

@ -1,20 +1,20 @@
// //
use git_next_core::{git, webhook, ApiToken, BranchName}; use git_next_core::{git, webhook, ApiToken, BranchName};
mod authorised; mod authorisation;
mod list; mod list;
mod parse; mod parser;
mod register; mod register;
mod unregister; mod unregister;
pub use authorised::is_authorised; pub use authorisation::is_authorised;
pub use list::list; pub use list::list;
pub use parse::parse_body; pub use parser::parse_body;
pub use register::register; pub use register::register;
pub use unregister::unregister; pub use unregister::unregister;
#[cfg(test)] #[cfg(test)]
pub use authorised::sign_body; pub use authorisation::sign_body;
pub fn headers(token: &ApiToken) -> kxio::network::NetRequestHeaders { pub fn headers(token: &ApiToken) -> kxio::network::NetRequestHeaders {
use secrecy::ExposeSecret; use secrecy::ExposeSecret;