From 78adf8225b39f071ac23ac037b73d86db6675754 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Tue, 22 Sep 2026 00:26:10 -0300 Subject: [PATCH 1/5] fix: rebuild nightly PR release notes from clean base Signed-off-by: Vitor Mattos --- workflow-templates/nightly-release.yml | 77 +------------------------- 1 file changed, 2 insertions(+), 75 deletions(-) diff --git a/workflow-templates/nightly-release.yml b/workflow-templates/nightly-release.yml index 6818195..eee1c2b 100644 --- a/workflow-templates/nightly-release.yml +++ b/workflow-templates/nightly-release.yml @@ -242,45 +242,9 @@ jobs: shell: bash env: NIGHTLY_BRANCH: ${{ steps.nightly.outputs.branch }} - run: | - last_tag="$(git tag --list --sort=-version:refname | grep -v '^nightly echo - echo "---" - printf 'Generated from commit `%s`.\n' "${GITHUB_SHA:0:7}" - } > release-notes.md - - - name: Create or update GitHub release - shell: bash - env: GH_TOKEN: ${{ github.token }} - NIGHTLY_BRANCH: ${{ steps.nightly.outputs.branch }} run: | - title="Nightly ${APP_VERSION} (${NIGHTLY_BRANCH})" - notes="${APP_NAME}/release-notes.md" - if gh release view nightly --repo "${GITHUB_REPOSITORY}" >/dev/null 2>&1; then - gh release edit nightly --repo "${GITHUB_REPOSITORY}" --title "${title}" --notes-file "${notes}" --prerelease - else - gh release create nightly --repo "${GITHUB_REPOSITORY}" --title "${title}" --notes-file "${notes}" --prerelease - fi - - - name: Attach tarball to GitHub release - id: attach-to-release - uses: svenstaro/upload-release-action@29e53e917877a24fad85510ded594ab3c9ca12de # v2.11.5 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: ${{ env.APP_NAME }}/build/artifacts/${{ env.APP_NAME }}.tar.gz - asset_name: ${{ env.APP_NAME }}-nightly.tar.gz - tag: nightly - overwrite: true - - - name: Upload nightly to Nextcloud App Store - uses: nextcloud-libraries/nextcloud-appstore-push-action@a011fe619bcf6e77ddebc96f9908e1af4071b9c1 # v1.0.3 - with: - app_name: ${{ env.APP_NAME }} - appstore_token: ${{ secrets.APPSTORE_TOKEN }} - download_url: ${{ steps.attach-to-release.outputs.browser_download_url }} - app_private_key: ${{ secrets.APP_PRIVATE_KEY }} - nightly: true - | head -1 || true)" + last_tag="$(git tag --list --sort=-version:refname | grep -v '^nightly$' | head -1 || true)" if [ -n "${last_tag}" ]; then mapfile -t commit_shas < <(git rev-list --reverse "${last_tag}..HEAD") else @@ -304,44 +268,7 @@ jobs: ' <<<"${pr_json}")" if [ -n "${pr_line}" ]; then - IFS= echo - echo "---" - printf 'Generated from commit `%s`.\n' "${GITHUB_SHA:0:7}" - } > release-notes.md - - - name: Create or update GitHub release - shell: bash - env: - GH_TOKEN: ${{ github.token }} - NIGHTLY_BRANCH: ${{ steps.nightly.outputs.branch }} - run: | - title="Nightly ${APP_VERSION} (${NIGHTLY_BRANCH})" - notes="${APP_NAME}/release-notes.md" - if gh release view nightly --repo "${GITHUB_REPOSITORY}" >/dev/null 2>&1; then - gh release edit nightly --repo "${GITHUB_REPOSITORY}" --title "${title}" --notes-file "${notes}" --prerelease - else - gh release create nightly --repo "${GITHUB_REPOSITORY}" --title "${title}" --notes-file "${notes}" --prerelease - fi - - - name: Attach tarball to GitHub release - id: attach-to-release - uses: svenstaro/upload-release-action@29e53e917877a24fad85510ded594ab3c9ca12de # v2.11.5 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: ${{ env.APP_NAME }}/build/artifacts/${{ env.APP_NAME }}.tar.gz - asset_name: ${{ env.APP_NAME }}-nightly.tar.gz - tag: nightly - overwrite: true - - - name: Upload nightly to Nextcloud App Store - uses: nextcloud-libraries/nextcloud-appstore-push-action@a011fe619bcf6e77ddebc96f9908e1af4071b9c1 # v1.0.3 - with: - app_name: ${{ env.APP_NAME }} - appstore_token: ${{ secrets.APPSTORE_TOKEN }} - download_url: ${{ steps.attach-to-release.outputs.browser_download_url }} - app_private_key: ${{ secrets.APP_PRIVATE_KEY }} - nightly: true -\t' read -r pr_number pr_title pr_url <<<"${pr_line}" + IFS=$'\t' read -r pr_number pr_title pr_url <<<"${pr_line}" if [ -z "${seen_prs[${pr_number}]+x}" ]; then printf -- '- %s ([#%s](%s))\n' "${pr_title}" "${pr_number}" "${pr_url}" >> nightly-changes.md seen_prs["${pr_number}"]=1 From 1a0ae3a5a4f8c4cf68a0a5f7973867b4dd2e8ada Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Tue, 22 Sep 2026 00:26:38 -0300 Subject: [PATCH 2/5] chore: use release-tool 0.10.2 Signed-off-by: Vitor Mattos --- actions/release-tool-setup/release-tool-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/release-tool-setup/release-tool-version b/actions/release-tool-setup/release-tool-version index 5712157..5eef0f1 100644 --- a/actions/release-tool-setup/release-tool-version +++ b/actions/release-tool-setup/release-tool-version @@ -1 +1 @@ -0.10.1 +0.10.2 From 08eec063f2f32d2626bb961ba56a3f95093b9908 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Tue, 22 Sep 2026 00:26:41 -0300 Subject: [PATCH 3/5] chore: release v0.6.6 Signed-off-by: Vitor Mattos --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index ef5e445..05e8a45 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.6.5 +0.6.6 From 44309da7533ccd3f3a8841aa66d1084e5ea15169 Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Tue, 22 Sep 2026 00:27:33 -0300 Subject: [PATCH 4/5] fix: strip GitHub auth on artifact storage redirects Signed-off-by: Vitor Mattos --- scripts/restore_release_artifact.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/scripts/restore_release_artifact.py b/scripts/restore_release_artifact.py index fa7d16b..e984341 100755 --- a/scripts/restore_release_artifact.py +++ b/scripts/restore_release_artifact.py @@ -9,11 +9,23 @@ import json import os from pathlib import Path -from urllib.parse import quote -from urllib.request import Request, urlopen +from urllib.parse import quote, urlparse +from urllib.request import HTTPRedirectHandler, Request, build_opener, urlopen from zipfile import ZipFile + +class CrossHostAuthStrippingRedirectHandler(HTTPRedirectHandler): + def redirect_request(self, req, fp, code, msg, headers, newurl): + redirected = super().redirect_request(req, fp, code, msg, headers, newurl) + if redirected is None: + return None + if urlparse(req.full_url).netloc != urlparse(newurl).netloc: + redirected.remove_header("Authorization") + redirected.remove_header("X-GitHub-Api-Version") + redirected.remove_header("Accept") + return redirected + def select_artifact(payload: object, name: str, expected_head_sha: str | None) -> dict[str, object]: if not isinstance(payload, dict) or not isinstance(payload.get("artifacts"), list): raise RuntimeError("GitHub returned an invalid artifact listing") @@ -77,7 +89,8 @@ def request_bytes(url: str, token: str) -> bytes: "X-GitHub-Api-Version": "2022-11-28", "User-Agent": "LibreCodeCoop/github-workflows", }) - with urlopen(request, timeout=60) as response: + opener = build_opener(CrossHostAuthStrippingRedirectHandler()) + with opener.open(request, timeout=60) as response: return response.read() From 58b7aab055a7780c7bd7480fa02ee36d42a9787d Mon Sep 17 00:00:00 2001 From: Vitor Mattos Date: Tue, 22 Sep 2026 00:27:46 -0300 Subject: [PATCH 5/5] test: cover artifact cross-host redirect auth stripping Signed-off-by: Vitor Mattos --- tests/test_restore_release_artifact.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/test_restore_release_artifact.py b/tests/test_restore_release_artifact.py index 92b846b..11a92ab 100644 --- a/tests/test_restore_release_artifact.py +++ b/tests/test_restore_release_artifact.py @@ -5,6 +5,7 @@ import importlib.util import io +from email.message import Message import tempfile import unittest from pathlib import Path @@ -20,6 +21,30 @@ class RestoreReleaseArtifactTest(unittest.TestCase): + def test_cross_host_redirect_strips_github_auth_headers(self) -> None: + request = module.Request( + "https://api.github.com/repos/example/project/actions/artifacts/1/zip", + headers={ + "Authorization": "Bearer secret", + "Accept": "application/vnd.github+json", + "X-GitHub-Api-Version": "2022-11-28", + }, + ) + redirected = module.CrossHostAuthStrippingRedirectHandler().redirect_request( + request, + None, + 302, + "Found", + Message(), + "https://artifact-storage.example.test/archive.zip?sig=signed", + ) + + self.assertIsNotNone(redirected) + assert redirected is not None + self.assertIsNone(redirected.get_header("Authorization")) + self.assertIsNone(redirected.get_header("Accept")) + self.assertIsNone(redirected.get_header("X-GitHub-Api-Version")) + def test_selects_latest_non_expired_artifact_for_expected_head(self) -> None: payload = {"artifacts": [ {"id": 1, "name": "release-preparation-pr-10", "expired": False, "created_at": "2026-01-01T00:00:00Z", "workflow_run": {"id": 11, "head_sha": "a" * 40}},