diff --git a/Makefile b/Makefile index 947b6a2..5139f76 100644 --- a/Makefile +++ b/Makefile @@ -33,3 +33,4 @@ format: ## Auto-format source files. .PHONY: clean clean: > $(MAKE) -C docker/webhook_bridge_development clean +> rm -rf target diff --git a/src/app_state.rs b/src/app_state.rs index 65f5eb5..ac09336 100644 --- a/src/app_state.rs +++ b/src/app_state.rs @@ -1,3 +1,6 @@ +use std::collections::HashSet; +use std::sync::Arc; + use kube::Client; use crate::gitea_client::GiteaClient; @@ -6,4 +9,5 @@ use crate::gitea_client::GiteaClient; pub(crate) struct AppState { pub(crate) kubernetes_client: Client, pub(crate) gitea: GiteaClient, + pub(crate) allowed_repos: Arc>, } diff --git a/src/hook_push.rs b/src/hook_push.rs index 0399f98..99cfc49 100644 --- a/src/hook_push.rs +++ b/src/hook_push.rs @@ -16,7 +16,7 @@ pub(crate) struct HookPush { commits: Vec, total_commits: u64, head_commit: HookCommit, - repository: HookRepository, + pub(crate) repository: HookRepository, pusher: HookUser, sender: HookUser, } @@ -55,7 +55,7 @@ pub(crate) struct HookRepository { id: u64, owner: HookUser, name: String, - full_name: String, + pub(crate) full_name: String, description: String, empty: bool, private: bool, diff --git a/src/lib.rs b/src/lib.rs index 9694e58..7a31ac6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,6 @@ #![forbid(unsafe_code)] +use std::collections::HashSet; +use std::sync::Arc; use std::time::Duration; use axum::http::StatusCode; @@ -35,7 +37,8 @@ pub async fn init_tracing() -> Result<(), Box> { tracing_subscriber::registry() .with( tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| { - "webhook_bridge=info,tower_http=debug,axum::rejection=trace".into() + "webhookbridge=info,webhook_bridge=info,local_trigger=info,tower_http=debug,axum::rejection=trace" + .into() }), ) .with(tracing_subscriber::fmt::layer()) @@ -52,6 +55,15 @@ pub async fn launch_server() -> Result<(), Box> { let gitea_api_token = std::env::var("WEBHOOK_BRIDGE_OAUTH_TOKEN")?; let gitea = GiteaClient::new(gitea_api_root, gitea_api_token); + let allowed_repos = std::env::var("WEBHOOK_BRIDGE_REPO_WHITELIST")?; + let allowed_repos: HashSet<_> = allowed_repos + .split(",") + .filter(|s| !s.is_empty()) + .map(str::to_owned) + .collect(); + tracing::debug!("Using repo whitelist: {:?}", allowed_repos); + + let allowed_repos = HashSet::new(); let app = Router::new() .route("/hook", post(hook)) .layer(middleware::from_fn(verify_signature)) @@ -64,6 +76,7 @@ pub async fn launch_server() -> Result<(), Box> { .with_state(AppState { kubernetes_client, gitea, + allowed_repos: Arc::new(allowed_repos), }); let listener = tokio::net::TcpListener::bind("0.0.0.0:9988").await?; @@ -83,9 +96,19 @@ pub async fn local_trigger(payload: &str) -> Result<(), Box = allowed_repos + .split(",") + .filter(|s| !s.is_empty()) + .map(str::to_owned) + .collect(); + tracing::debug!("Using repo whitelist: {:?}", allowed_repos); + let webhook_payload: HookPush = serde_json::from_str(payload)?; - handle_push(gitea, kubernetes_client, webhook_payload).await?; + handle_push(gitea, kubernetes_client, &allowed_repos, webhook_payload).await?; Ok(()) } diff --git a/src/webhook.rs b/src/webhook.rs index ce39ae4..ce10cd7 100644 --- a/src/webhook.rs +++ b/src/webhook.rs @@ -1,3 +1,5 @@ +use std::borrow::Borrow; +use std::collections::HashSet; use std::future::Future; use axum::async_trait; @@ -40,9 +42,14 @@ pub(crate) async fn hook( debug!("REQ: {:?}", payload); match payload { HookRequest::Push(webhook_payload) => { - handle_push(state.gitea, state.kubernetes_client, webhook_payload) - .await - .expect("Failed to handle push event."); + handle_push( + state.gitea, + state.kubernetes_client, + state.allowed_repos.borrow(), + webhook_payload, + ) + .await + .expect("Failed to handle push event."); ( StatusCode::OK, Json(HookResponse { @@ -167,11 +174,19 @@ fn hex_to_bytes(s: &str) -> Option> { pub(crate) async fn handle_push( gitea: GiteaClient, kubernetes_client: kube::Client, + allowed_repos: &HashSet, webhook_payload: HookPush, ) -> Result<(), Box> { let repo_owner = webhook_payload.get_repo_owner()?; let repo_name = webhook_payload.get_repo_name()?; let pull_base_sha = webhook_payload.get_pull_base_sha()?; + if !allowed_repos.contains(&webhook_payload.repository.full_name) { + tracing::info!( + "{} is not an allowed repository.", + webhook_payload.repository.full_name + ); + return Ok(()); + } let repo_tree = gitea.get_tree(repo_owner, repo_name, pull_base_sha).await?; let remote_config = discover_webhook_bridge_config(&gitea, &repo_tree).await?; let pipelines = discover_matching_push_triggers(