2 Commits

Author SHA1 Message Date
Tom Alexander
613026b326 Adding repo whitelist.
Some checks failed
semver Build semver has succeeded
format Build format has succeeded
clippy Build clippy has failed
build Build build has succeeded
rust-test Build rust-test has succeeded
2024-09-29 16:54:58 -04:00
Tom Alexander
cd56bb2fe1 Fix debug build in docker container by adding cranelift.
All checks were successful
semver Build semver has succeeded
format Build format has succeeded
clippy Build clippy has succeeded
build Build build has succeeded
rust-test Build rust-test has succeeded
2024-09-29 15:31:24 -04:00
6 changed files with 51 additions and 7 deletions

View File

@@ -33,3 +33,4 @@ format: ## Auto-format source files.
.PHONY: clean .PHONY: clean
clean: clean:
> $(MAKE) -C docker/webhook_bridge_development clean > $(MAKE) -C docker/webhook_bridge_development clean
> rm -rf target

View File

@@ -2,5 +2,6 @@ FROM rustlang/rust:nightly-alpine3.20 AS builder
RUN apk add --no-cache musl-dev pkgconfig libressl3.8-libssl libressl-dev RUN apk add --no-cache musl-dev pkgconfig libressl3.8-libssl libressl-dev
RUN cargo install --locked --no-default-features --features ci-autoclean cargo-cache RUN cargo install --locked --no-default-features --features ci-autoclean cargo-cache
RUN rustup component add rustc-codegen-cranelift
RUN rustup component add rustfmt RUN rustup component add rustfmt
RUN rustup component add clippy RUN rustup component add clippy

View File

@@ -1,3 +1,6 @@
use std::collections::HashSet;
use std::sync::Arc;
use kube::Client; use kube::Client;
use crate::gitea_client::GiteaClient; use crate::gitea_client::GiteaClient;
@@ -6,4 +9,5 @@ use crate::gitea_client::GiteaClient;
pub(crate) struct AppState { pub(crate) struct AppState {
pub(crate) kubernetes_client: Client, pub(crate) kubernetes_client: Client,
pub(crate) gitea: GiteaClient, pub(crate) gitea: GiteaClient,
pub(crate) allowed_repos: Arc<HashSet<String>>,
} }

View File

@@ -16,7 +16,7 @@ pub(crate) struct HookPush {
commits: Vec<HookCommit>, commits: Vec<HookCommit>,
total_commits: u64, total_commits: u64,
head_commit: HookCommit, head_commit: HookCommit,
repository: HookRepository, pub(crate) repository: HookRepository,
pusher: HookUser, pusher: HookUser,
sender: HookUser, sender: HookUser,
} }
@@ -55,7 +55,7 @@ pub(crate) struct HookRepository {
id: u64, id: u64,
owner: HookUser, owner: HookUser,
name: String, name: String,
full_name: String, pub(crate) full_name: String,
description: String, description: String,
empty: bool, empty: bool,
private: bool, private: bool,

View File

@@ -1,4 +1,6 @@
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
use std::collections::HashSet;
use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use axum::http::StatusCode; use axum::http::StatusCode;
@@ -35,7 +37,8 @@ pub async fn init_tracing() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::registry() tracing_subscriber::registry()
.with( .with(
tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| { 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()) .with(tracing_subscriber::fmt::layer())
@@ -52,6 +55,15 @@ pub async fn launch_server() -> Result<(), Box<dyn std::error::Error>> {
let gitea_api_token = std::env::var("WEBHOOK_BRIDGE_OAUTH_TOKEN")?; let gitea_api_token = std::env::var("WEBHOOK_BRIDGE_OAUTH_TOKEN")?;
let gitea = GiteaClient::new(gitea_api_root, gitea_api_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() let app = Router::new()
.route("/hook", post(hook)) .route("/hook", post(hook))
.layer(middleware::from_fn(verify_signature)) .layer(middleware::from_fn(verify_signature))
@@ -64,6 +76,7 @@ pub async fn launch_server() -> Result<(), Box<dyn std::error::Error>> {
.with_state(AppState { .with_state(AppState {
kubernetes_client, kubernetes_client,
gitea, gitea,
allowed_repos: Arc::new(allowed_repos),
}); });
let listener = tokio::net::TcpListener::bind("0.0.0.0:9988").await?; 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<dyn std::error::Erro
let gitea_api_token = std::env::var("WEBHOOK_BRIDGE_OAUTH_TOKEN")?; let gitea_api_token = std::env::var("WEBHOOK_BRIDGE_OAUTH_TOKEN")?;
let gitea = GiteaClient::new(gitea_api_root, gitea_api_token); let gitea = GiteaClient::new(gitea_api_root, gitea_api_token);
let allowed_repos = std::env::var("WEBHOOK_BRIDGE_REPO_WHITELIST")
.ok()
.unwrap_or_else(String::new);
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 webhook_payload: HookPush = serde_json::from_str(payload)?; 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(()) Ok(())
} }

View File

@@ -1,3 +1,5 @@
use std::borrow::Borrow;
use std::collections::HashSet;
use std::future::Future; use std::future::Future;
use axum::async_trait; use axum::async_trait;
@@ -40,9 +42,14 @@ pub(crate) async fn hook(
debug!("REQ: {:?}", payload); debug!("REQ: {:?}", payload);
match payload { match payload {
HookRequest::Push(webhook_payload) => { HookRequest::Push(webhook_payload) => {
handle_push(state.gitea, state.kubernetes_client, webhook_payload) handle_push(
.await state.gitea,
.expect("Failed to handle push event."); state.kubernetes_client,
state.allowed_repos.borrow(),
webhook_payload,
)
.await
.expect("Failed to handle push event.");
( (
StatusCode::OK, StatusCode::OK,
Json(HookResponse { Json(HookResponse {
@@ -167,11 +174,19 @@ fn hex_to_bytes(s: &str) -> Option<Vec<u8>> {
pub(crate) async fn handle_push( pub(crate) async fn handle_push(
gitea: GiteaClient, gitea: GiteaClient,
kubernetes_client: kube::Client, kubernetes_client: kube::Client,
allowed_repos: &HashSet<String>,
webhook_payload: HookPush, webhook_payload: HookPush,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
let repo_owner = webhook_payload.get_repo_owner()?; let repo_owner = webhook_payload.get_repo_owner()?;
let repo_name = webhook_payload.get_repo_name()?; let repo_name = webhook_payload.get_repo_name()?;
let pull_base_sha = webhook_payload.get_pull_base_sha()?; 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 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 remote_config = discover_webhook_bridge_config(&gitea, &repo_tree).await?;
let pipelines = discover_matching_push_triggers( let pipelines = discover_matching_push_triggers(