From 6b77ac31513b62369607f592902d177765f27d5a Mon Sep 17 00:00:00 2001 From: famfo Date: Fri, 13 Feb 2026 19:30:00 +0100 Subject: [PATCH] feat: add proxyproto test --- .forgejo/workflows/end-to-end.yml | 18 ++++ end-to-end.sh | 1 + lib/dependencies.sh | 9 +- proxyproto/default-app.ini | 28 +++++++ proxyproto/haproxy.cfg | 19 +++++ proxyproto/proxyproto.sh | 131 ++++++++++++++++++++++++++++++ run.sh | 4 +- 7 files changed, 206 insertions(+), 4 deletions(-) create mode 100644 proxyproto/default-app.ini create mode 100644 proxyproto/haproxy.cfg create mode 100644 proxyproto/proxyproto.sh diff --git a/.forgejo/workflows/end-to-end.yml b/.forgejo/workflows/end-to-end.yml index 3921e400..b7a558e4 100644 --- a/.forgejo/workflows/end-to-end.yml +++ b/.forgejo/workflows/end-to-end.yml @@ -164,3 +164,21 @@ jobs: - name: full logs if: always() run: su forgejo -c "./end-to-end.sh show_logs" + + proxyproto: + name: PROXY protocol + needs: [build] + runs-on: lxc-trixie + steps: + - uses: https://data.forgejo.org/actions/checkout@v4 + - uses: ./.forgejo/prepare-end-to-end + with: + built: ${{ needs.build.outputs.built }} + - run: su forgejo -c "./end-to-end.sh test_proxyproto" + - if: ${{ needs.build.outputs.built == 'yes' }} + uses: ./.forgejo/upload-coverage + with: + scope: proxy + - name: full logs + if: always() + run: su forgejo -c "./end-to-end.sh show_logs" diff --git a/end-to-end.sh b/end-to-end.sh index 86c48410..9be4968d 100755 --- a/end-to-end.sh +++ b/end-to-end.sh @@ -12,5 +12,6 @@ source "$SELF_DIR/forgejo/fixtures.sh" source "$SELF_DIR/storage/storage.sh" source "$SELF_DIR/upgrade/upgrade.sh" source "$SELF_DIR/packages/packages.sh" +source "$SELF_DIR/proxyproto/proxyproto.sh" "$@" diff --git a/lib/dependencies.sh b/lib/dependencies.sh index e1422441..ef88f148 100644 --- a/lib/dependencies.sh +++ b/lib/dependencies.sh @@ -4,9 +4,9 @@ function dependencies() { $SUDO chmod +x /usr/local/bin/forgejo-curl.sh fi - if ! which make curl daemon git-lfs jq sqlite3 skopeo podman podman-compose pasta pup >/dev/null; then + if ! which make curl daemon git-lfs jq sqlite3 skopeo podman podman-compose pasta pup haproxy >/dev/null; then $SUDO apt-get update -qq - $SUDO apt-get install -y -qq --no-install-recommends make curl daemon git-lfs jq sqlite3 skopeo podman podman-compose passt aardvark-dns pup + $SUDO apt-get install -y -qq --no-install-recommends make curl daemon git-lfs jq sqlite3 skopeo podman podman-compose passt aardvark-dns pup haproxy fi if ! test -f /usr/local/bin/mc || ! test -f /usr/local/bin/minio; then @@ -20,4 +20,9 @@ function dependencies() { $SUDO curl --fail https://garagehq.deuxfleurs.fr/_releases/v0.8.2/x86_64-unknown-linux-musl/garage -o /usr/local/bin/garage $SUDO chmod +x /usr/local/bin/garage fi + + if ! test -f /usr/local/bin/bombardier > /dev/null; then + $SUDO curl --fail -L https://github.com/codesenberg/bombardier/releases/download/v2.0.2/bombardier-linux-amd64 -o /usr/local/bin/bombardier + $SUDO chmod +x /usr/local/bin/bombardier + fi } diff --git a/proxyproto/default-app.ini b/proxyproto/default-app.ini new file mode 100644 index 00000000..b24618c5 --- /dev/null +++ b/proxyproto/default-app.ini @@ -0,0 +1,28 @@ +RUN_MODE = dev +WORK_PATH = forgejo-work-path + +[server] +APP_DATA_PATH = ${WORK_PATH}/data +DOMAIN = ${IP} +HTTP_PORT = 3000 +SSH_LISTEN_PORT = 2222 +USE_PROXY_PROTOCOL = true +ROOT_URL = http://${IP}:3001 + +[queue] +TYPE = immediate + +[database] +DB_TYPE = sqlite3 +PATH = ${WORK_PATH}/forgejo.db + +[log] +MODE = file +LEVEL = trace + +[log.file] +FILE_NAME = forgejo.log + +[security] +INSTALL_LOCK = true + diff --git a/proxyproto/haproxy.cfg b/proxyproto/haproxy.cfg new file mode 100644 index 00000000..9d13d707 --- /dev/null +++ b/proxyproto/haproxy.cfg @@ -0,0 +1,19 @@ +defaults + timeout connect 5s + timeout client 50s + timeout server 50s + +frontend main_v1 + bind :3001 + default_backend forgejo_v1 + +frontend main_v2 + bind :3002 + default_backend forgejo_v2 + +backend forgejo_v1 + server main localhost:3000 send-proxy + +backend forgejo_v2 + server main localhost:3000 send-proxy-v2 + diff --git a/proxyproto/proxyproto.sh b/proxyproto/proxyproto.sh new file mode 100644 index 00000000..5bf367e1 --- /dev/null +++ b/proxyproto/proxyproto.sh @@ -0,0 +1,131 @@ +# Copyright 2026 The Forgejo Authors +# SPDX-License-Identifier: MIT + +PROXYPROTO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +proxyproto_test_basic() { + local home="$(curl -s "http://localhost:3001")" + if ! grep -q "Forgejo" <<< "$home"; then + echo "[PROXY v1] Forgejo homepage not found" + exit 1 + fi + + local home="$(curl -s "http://localhost:3002")" + if ! grep -q "Forgejo" <<< "$home"; then + echo "[PROXY v2] Forgejo homepage not found" + exit 1 + fi +} + +check_bombardier_output() { + [[ -z "$1" || -z "$2" ]] && exit 1 + + if [[ "$(jq '.result.req5xx' <<< "$2")" > 10 ]]; then + echo "[$1] more than 10 requests failed" + exit 1 + fi + + # The 5000 is kind of chose arbitrarily to make sure some requests pass + if [[ "$(jq '.result.req2xx' <<< "$2")" -lt 5000 ]]; then + echo "[$1] les than 5000 requests were made in 10 seconds" + exit 1 + fi +} + +proxyproto_test_bombardier() { + local res="$(bombardier -p r -o j http://localhost:3001)" + check_bombardier_output "PROXY v1" "$res" || exit 1 + + local res="$(bombardier -p r -o j http://localhost:3002)" + check_bombardier_output "PROXY v2" "$res" || exit 1 +} + +check_repo_readme() { + [[ -z "$1" || -z "$2" ]] && exit 1 + + out="$(curl -s "$1")" + grep -q "$2" <<< "$out" || exit 1 +} + +proxyproto_push_http() { + forgejo_tmp="$(mktemp -d)" + "$CURL" api_json \ + --data '{"name":"repo","auto_init":true}' \ + "http://$V1_HOST_PORT/api/v1/user/repos" > "$forgejo_tmp/one-repo.json" + + rm -rf "$DIR/repo" + mkdir -p "$DIR/repo" + + ( + cd "$DIR/repo" + + git init + git checkout -b main + + git config user.email "$FORGEJO_USER@example.com" + git config user.name "$FORGEJO_USER" + + echo "frog!" > README + git add README + git commit -m 'PROXY v1' + + git push -f "http://$FORGEJO_USER:$FORGEJO_PASSWORD@localhost:3001/$FORGEJO_USER/repo" main + check_repo_readme "http://localhost:3001/$FORGEJO_USER/repo" "frog!" + + echo "frog2!" > README + git add README + git commit -m 'PROXY v2' + + git push -f "http://$FORGEJO_USER:$FORGEJO_PASSWORD@localhost:3002/$FORGEJO_USER/repo" main + check_repo_readme "http://localhost:3001/$FORGEJO_USER/repo" "frog2!" + ) +} + +proxyproto_run_test() { + [[ -z "$1" ]] && exit 1 + + local version="$1" + local config="$PROXYPROTO_DIR/default-app.ini" + + reset_forgejo "$config" + start_forgejo "$version" "$config" + + export CURL="$DIR/$(work_path_base "$config")/forgejo-curl.sh" + export V1_HOST_PORT="$(get_host_port "$config")" + + run proxyproto_test_basic + run proxyproto_test_bombardier + run proxyproto_push_http + + stop_forgejo $config +} + +proxyproto_setup_haproxy() { + daemon \ + --chdir="$DIR" \ + --unsafe \ + --pidfile="$DIR/haproxy-pid" \ + --errlog="$DIR/haproxy-err.log" \ + --output="$DIR/haproxy-out.log" \ + -- \ + haproxy \ + -f "$PROXYPROTO_DIR/haproxy.cfg" +} + +test_proxyproto() { + local versions="${1:-$RELEASE_NUMBERS}" + + mkdir -p "$DIR" + proxyproto_setup_haproxy + + for v in $versions; do + if dpkg --compare-versions "$v" lt "15.0"; then + continue + fi + + proxyproto_run_test "$v" + done + + stop_daemon "haproxy" +} + diff --git a/run.sh b/run.sh index 92a91611..c4fc4604 100755 --- a/run.sh +++ b/run.sh @@ -4,8 +4,8 @@ podman build -t forgejo-e2e . patchelf ../forgejo/forgejo --set-interpreter /lib64/ld-linux-x86-64.so.2 podman run \ -it --privileged \ - -v ../forgejo/gitea:/srv/forgejo-binaries/forgejo-14.0 \ - -p 3001-3003:3001-3003 \ + -v ../forgejo/gitea:/srv/forgejo-binaries/forgejo-15.0 \ + -p 3000-3003:3000-3003 \ -p 4000:4000 \ -p 8080:8080 \ forgejo-e2e