From a91dd4f92af08661919bdd941ec925ce72adf877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 3 Sep 2026 15:47:49 +0200 Subject: [PATCH 1/4] fix: release picks up main branch if no maintenance branch exists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .github/workflows/release.yml | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 134fa87fff..d432a95088 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,23 +34,19 @@ jobs: RELEASE_VERSION="${{ github.event.release.tag_name }}" RELEASE_VERSION="${RELEASE_VERSION#v}" RELEASE_MAJOR_MINOR=$(echo "$RELEASE_VERSION" | cut -d. -f1-2) + MAINTENANCE_BRANCH="${RELEASE_MAJOR_MINOR}.x" - MAIN_POM_VERSION=$(curl -fsSL "https://raw.githubusercontent.com/${{ github.repository }}/main/pom.xml" | yq -p xml '.project.version') - if [ -z "$MAIN_POM_VERSION" ]; then - echo "Failed to determine main branch POM version" - exit 1 - fi - MAIN_MAJOR_MINOR=$(echo "$MAIN_POM_VERSION" | cut -d. -f1-2) - + # A maintenance branch (e.g. 5.3.x) exists only for streams no longer + # developed on main, so its absence means main is the stream being + # released. Main's pom cannot be used to identify the stream: it carries + # the 999-SNAPSHOT sentinel version. echo "Release tag major.minor: $RELEASE_MAJOR_MINOR" - echo "Main branch major.minor: $MAIN_MAJOR_MINOR" - - if [ "$RELEASE_MAJOR_MINOR" = "$MAIN_MAJOR_MINOR" ]; then - echo "Setting version_branch to main" - echo "tmp_version_branch=main" >> "$GITHUB_ENV" + if git ls-remote --exit-code --heads "${{ github.server_url }}/${{ github.repository }}.git" "refs/heads/${MAINTENANCE_BRANCH}" >/dev/null 2>&1; then + echo "Setting version_branch to ${MAINTENANCE_BRANCH}" + echo "tmp_version_branch=${MAINTENANCE_BRANCH}" >> "$GITHUB_ENV" else - echo "Setting version_branch to ${RELEASE_MAJOR_MINOR}.x" - echo "tmp_version_branch=${RELEASE_MAJOR_MINOR}.x" >> "$GITHUB_ENV" + echo "No ${MAINTENANCE_BRANCH} branch, setting version_branch to main" + echo "tmp_version_branch=main" >> "$GITHUB_ENV" fi - if: ${{ env.tmp_version_branch == '' }} name: Fail if version_branch is not set From daff6be66eee21b189f41c312173dde3a4a5dd4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 3 Sep 2026 18:40:54 +0200 Subject: [PATCH 2/4] wip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- .github/workflows/release.yml | 40 +++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d432a95088..8d9e694bca 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,6 +4,10 @@ env: on: release: types: [ released ] + +permissions: + contents: read + jobs: prepare-release: @@ -30,6 +34,8 @@ jobs: echo "Setting version_branch to v4" echo "tmp_version_branch=v4" >> "$GITHUB_ENV" - if: ${{ startsWith(github.event.release.tag_name, 'v5.' ) }} + env: + GH_TOKEN: ${{ github.token }} run: | RELEASE_VERSION="${{ github.event.release.tag_name }}" RELEASE_VERSION="${RELEASE_VERSION#v}" @@ -41,13 +47,30 @@ jobs: # released. Main's pom cannot be used to identify the stream: it carries # the 999-SNAPSHOT sentinel version. echo "Release tag major.minor: $RELEASE_MAJOR_MINOR" - if git ls-remote --exit-code --heads "${{ github.server_url }}/${{ github.repository }}.git" "refs/heads/${MAINTENANCE_BRANCH}" >/dev/null 2>&1; then - echo "Setting version_branch to ${MAINTENANCE_BRANCH}" - echo "tmp_version_branch=${MAINTENANCE_BRANCH}" >> "$GITHUB_ENV" - else - echo "No ${MAINTENANCE_BRANCH} branch, setting version_branch to main" - echo "tmp_version_branch=main" >> "$GITHUB_ENV" - fi + + # Only 404 means "no such branch". Any other status is a lookup failure + # and must abort: silently falling back to main would release the wrong + # stream. + HTTP_STATUS=$(curl -sS -o /dev/null -w '%{http_code}' \ + -H "Authorization: Bearer ${GH_TOKEN}" \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "${{ github.api_url }}/repos/${{ github.repository }}/branches/${MAINTENANCE_BRANCH}") + + case "$HTTP_STATUS" in + 200) + echo "Setting version_branch to ${MAINTENANCE_BRANCH}" + echo "tmp_version_branch=${MAINTENANCE_BRANCH}" >> "$GITHUB_ENV" + ;; + 404) + echo "No ${MAINTENANCE_BRANCH} branch, setting version_branch to main" + echo "tmp_version_branch=main" >> "$GITHUB_ENV" + ;; + *) + echo "Could not determine whether ${MAINTENANCE_BRANCH} exists (HTTP ${HTTP_STATUS})" + exit 1 + ;; + esac - if: ${{ env.tmp_version_branch == '' }} name: Fail if version_branch is not set run: | @@ -59,6 +82,9 @@ jobs: release-sdk: needs: prepare-release + # The reusable workflow commits and pushes the SNAPSHOT version bump. + permissions: + contents: write uses: ./.github/workflows/release-project-in-dir.yml secrets: inherit with: From 3bc4eff3b66efe39748af7e480217e1a833ec901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 3 Sep 2026 19:40:49 +0200 Subject: [PATCH 3/4] fix: bound branch lookup with timeouts and explicit curl exit check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Transient network issues could stall the release workflow indefinitely, and a curl failure was only distinguishable from an HTTP response via the status output. Add connect/overall timeouts with a small retry policy, check curl's exit code explicitly, and cap the job with timeout-minutes. Signed-off-by: Attila Mészáros --- .github/workflows/release.yml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8d9e694bca..b2aad3e614 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,6 +12,7 @@ jobs: prepare-release: runs-on: ubuntu-latest + timeout-minutes: 10 env: tmp_version_branch: '' outputs: @@ -48,14 +49,22 @@ jobs: # the 999-SNAPSHOT sentinel version. echo "Release tag major.minor: $RELEASE_MAJOR_MINOR" - # Only 404 means "no such branch". Any other status is a lookup failure + # Only 404 means "no such branch". Any other outcome is a lookup failure # and must abort: silently falling back to main would release the wrong - # stream. + # stream. Timeouts are bounded so a network stall fails fast. + CURL_EXIT=0 HTTP_STATUS=$(curl -sS -o /dev/null -w '%{http_code}' \ + --connect-timeout 10 --max-time 30 \ + --retry 3 --retry-delay 2 --retry-all-errors \ -H "Authorization: Bearer ${GH_TOKEN}" \ -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: 2022-11-28" \ - "${{ github.api_url }}/repos/${{ github.repository }}/branches/${MAINTENANCE_BRANCH}") + "${{ github.api_url }}/repos/${{ github.repository }}/branches/${MAINTENANCE_BRANCH}") || CURL_EXIT=$? + + if [ "$CURL_EXIT" -ne 0 ]; then + echo "Branch lookup for ${MAINTENANCE_BRANCH} failed (curl exit ${CURL_EXIT})" + exit 1 + fi case "$HTTP_STATUS" in 200) From b193d746c392f9478430afbcc15b3b3830150cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 3 Sep 2026 19:52:31 +0200 Subject: [PATCH 4/4] fix: validate derived release stream and avoid template expansion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A tag such as v5.3/rc derived the branch name 5.3/rc.x, whose slash split the API URL path into a non-existent endpoint; the resulting 404 quietly selected main. Reject anything that is not a bare major.minor. Pass the release tag through the environment rather than expanding it directly into the shell script, so a tag name can never be interpreted as code. Signed-off-by: Attila Mészáros --- .github/workflows/release.yml | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b2aad3e614..050f692746 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -37,10 +37,19 @@ jobs: - if: ${{ startsWith(github.event.release.tag_name, 'v5.' ) }} env: GH_TOKEN: ${{ github.token }} + RAW_TAG: ${{ github.event.release.tag_name }} run: | - RELEASE_VERSION="${{ github.event.release.tag_name }}" - RELEASE_VERSION="${RELEASE_VERSION#v}" + RELEASE_VERSION="${RAW_TAG#v}" RELEASE_MAJOR_MINOR=$(echo "$RELEASE_VERSION" | cut -d. -f1-2) + + # Reject anything that is not a bare major.minor. A tag such as + # "v5.3/rc" would otherwise derive the branch "5.3/rc.x", whose slash + # splits the API URL path into a non-existent endpoint, and the + # resulting 404 would quietly select main. + if ! printf '%s' "$RELEASE_MAJOR_MINOR" | grep -Eq '^[0-9]+\.[0-9]+$'; then + echo "Cannot derive a release stream from tag '${RAW_TAG}'" + exit 1 + fi MAINTENANCE_BRANCH="${RELEASE_MAJOR_MINOR}.x" # A maintenance branch (e.g. 5.3.x) exists only for streams no longer @@ -82,8 +91,10 @@ jobs: esac - if: ${{ env.tmp_version_branch == '' }} name: Fail if version_branch is not set + env: + RAW_TAG: ${{ github.event.release.tag_name }} run: | - echo "Failed to find appropriate branch to release ${{github.event.release.tag_name}} from" + echo "Failed to find appropriate branch to release ${RAW_TAG} from" exit 1 - id: set-version-branch name: Set version_branch if matched