From 60119a4317118fa3f077db0382664f15266a6682 Mon Sep 17 00:00:00 2001 From: mesalogo Date: Mon, 17 Aug 2026 22:17:43 +0800 Subject: [PATCH] fix: align mirror publishing region The v0.10.3 release index was generated, but the pinned upload client rejected object uploads because V4 signing did not receive a region. The application and website also addressed the Beijing bucket through the previous Hangzhou endpoint. Derive and pass the endpoint region to every upload, pin workflow configuration to the trusted production bucket, and align application and website URL validation with its actual endpoint. Advance recovery metadata to 0.10.4 and remove the unpublished 0.10.3 note. Release note: 0.10.4 carries forward the approved mirror-node and conversation timestamp improvements from the unpublished candidates. --- .github/workflows/packages.yml | 19 ++++++++++++++++--- package-lock.json | 4 ++-- package.json | 2 +- resources/release-notes.json | 6 +++--- sites/app.js | 4 ++-- sites/scripts/validate.mjs | 2 +- src/main/version-checker.test.ts | 2 +- src/main/version-checker.ts | 2 +- tests/packages-workflow.test.ts | 16 ++++++++++++++++ tests/site-release.test.ts | 6 +++--- 10 files changed, 46 insertions(+), 17 deletions(-) diff --git a/.github/workflows/packages.yml b/.github/workflows/packages.yml index f94398d..cc3173f 100644 --- a/.github/workflows/packages.yml +++ b/.github/workflows/packages.yml @@ -198,11 +198,12 @@ jobs: test -n "$OIDC_PROVIDER_ARN" test -n "$ROLE_ARN" case "$OSS_BUCKET" in - *[!a-z0-9-]*|'') echo "OSS Bucket 名称无效" >&2; exit 1 ;; + goodbuddy) ;; + *) echo "OSS Bucket 必须与应用内置镜像地址一致" >&2; exit 1 ;; esac case "$OSS_ENDPOINT" in - https://oss-*.aliyuncs.com) ;; - *) echo "OSS Endpoint 必须使用标准 HTTPS 地址" >&2; exit 1 ;; + https://oss-cn-beijing.aliyuncs.com) ;; + *) echo "OSS Endpoint 必须与应用内置镜像地址一致" >&2; exit 1 ;; esac case "$OIDC_PROVIDER_ARN" in acs:ram::*:oidc-provider/*) ;; @@ -248,18 +249,25 @@ jobs: run: | set -euo pipefail endpoint_host="${OSS_ENDPOINT#https://}" + oss_region="${endpoint_host#oss-}" + oss_region="${oss_region%.aliyuncs.com}" + case "$oss_region" in + *[!a-z0-9-]*|'') echo "无法从 OSS Endpoint 推导 Region" >&2; exit 1 ;; + esac base_url="https://${OSS_BUCKET}.${endpoint_host}/releases/${GITHUB_REF_NAME}/" node build/create-site-release.cjs \ --manifest dist/release-upload/release-manifest.json \ --base-url "$base_url" \ --output dist/site-release.json echo "base-url=$base_url" >> "$GITHUB_OUTPUT" + echo "region=$oss_region" >> "$GITHUB_OUTPUT" - name: Upload immutable release assets to OSS shell: bash env: OSS_BUCKET: ${{ vars.ALIYUN_OSS_BUCKET }} OSS_ENDPOINT: ${{ vars.ALIYUN_OSS_ENDPOINT }} + OSS_REGION: ${{ steps.oss-release.outputs.region }} run: | set -euo pipefail export OSS_ACCESS_KEY_ID="$ALIBABA_CLOUD_ACCESS_KEY_ID" @@ -268,11 +276,13 @@ jobs: test -n "$OSS_ACCESS_KEY_ID" test -n "$OSS_ACCESS_KEY_SECRET" test -n "$OSS_SESSION_TOKEN" + test -n "$OSS_REGION" for file in dist/release-upload/* dist/site-release.json; do name="$(basename "$file")" ossutil cp "$file" \ "oss://${OSS_BUCKET}/releases/${GITHUB_REF_NAME}/${name}" \ --endpoint "$OSS_ENDPOINT" \ + --region "$OSS_REGION" \ --update done @@ -300,12 +310,15 @@ jobs: env: OSS_BUCKET: ${{ vars.ALIYUN_OSS_BUCKET }} OSS_ENDPOINT: ${{ vars.ALIYUN_OSS_ENDPOINT }} + OSS_REGION: ${{ steps.oss-release.outputs.region }} run: | set -euo pipefail export OSS_ACCESS_KEY_ID="$ALIBABA_CLOUD_ACCESS_KEY_ID" export OSS_ACCESS_KEY_SECRET="$ALIBABA_CLOUD_ACCESS_KEY_SECRET" export OSS_SESSION_TOKEN="$ALIBABA_CLOUD_SECURITY_TOKEN" + test -n "$OSS_REGION" ossutil cp dist/site-release.json \ "oss://${OSS_BUCKET}/releases/latest.json" \ --endpoint "$OSS_ENDPOINT" \ + --region "$OSS_REGION" \ --force diff --git a/package-lock.json b/package-lock.json index 356e755..7409792 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "goodbuddy", - "version": "0.10.3", + "version": "0.10.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "goodbuddy", - "version": "0.10.3", + "version": "0.10.4", "license": "0BSD", "dependencies": { "@agentclientprotocol/sdk": "0.25.1", diff --git a/package.json b/package.json index eb1fa45..f1177f4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "goodbuddy", - "version": "0.10.3", + "version": "0.10.4", "private": true, "description": "Secure desktop AI workspace with controlled Agent Runtimes", "desktopName": "GoodBuddy", diff --git a/resources/release-notes.json b/resources/release-notes.json index 58286a6..5196f75 100644 --- a/resources/release-notes.json +++ b/resources/release-notes.json @@ -2,12 +2,12 @@ "formatVersion": 1, "releases": [ { - "version": "0.10.3", + "version": "0.10.4", "releasedAt": "2026-08-17", "notes": { "zh-CN": { "highlights": [ - "GoodBuddy 0.10.3 新增可选的镜像节点,并改进最近对话的时间显示。" + "GoodBuddy 0.10.4 新增可选的镜像节点,并改进最近对话的时间显示。" ], "features": [ "**镜像节点与更新源。** 在“关于与更新”中可选择 GitHub(默认)或镜像节点。手动检查、启动时检查和打开下载页会使用同一选择,应用仍只检查版本,不会自动下载安装。" @@ -21,7 +21,7 @@ }, "en-US": { "highlights": [ - "GoodBuddy 0.10.3 adds an optional mirror node and improves how recent conversation times are displayed." + "GoodBuddy 0.10.4 adds an optional mirror node and improves how recent conversation times are displayed." ], "features": [ "**Mirror node and update source.** About & Updates now lets you choose GitHub (default) or the mirror node. Manual checks, startup checks, and the download page use the same selection. GoodBuddy still checks versions only and never downloads or installs updates automatically." diff --git a/sites/app.js b/sites/app.js index 7f6184e..c94ea39 100644 --- a/sites/app.js +++ b/sites/app.js @@ -13,7 +13,7 @@ const finePointer = window.matchMedia("(hover: hover) and (pointer: fine)"); const reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)"); const releaseManifestUrl = - "https://goodbuddy.oss-cn-hangzhou.aliyuncs.com/releases/latest.json"; + "https://goodbuddy.oss-cn-beijing.aliyuncs.com/releases/latest.json"; const releaseFallbackUrl = "https://github.com/mesalogo/goodbuddy/releases/latest"; const releaseStatus = document.querySelector("[data-release-status]"); @@ -44,7 +44,7 @@ const url = new URL(value); return ( url.protocol === "https:" && - url.hostname === "goodbuddy.oss-cn-hangzhou.aliyuncs.com" && + url.hostname === "goodbuddy.oss-cn-beijing.aliyuncs.com" && url.pathname.startsWith("/releases/") ); } catch { diff --git a/sites/scripts/validate.mjs b/sites/scripts/validate.mjs index 85a2e6a..651727b 100644 --- a/sites/scripts/validate.mjs +++ b/sites/scripts/validate.mjs @@ -149,7 +149,7 @@ report( report(/data-release-status/.test(html), "下载区缺少发布源状态"); report( appJs.includes( - "https://goodbuddy.oss-cn-hangzhou.aliyuncs.com/releases/latest.json", + "https://goodbuddy.oss-cn-beijing.aliyuncs.com/releases/latest.json", ), "官网必须从 GoodBuddy OSS 加载最新发布索引", ); diff --git a/src/main/version-checker.test.ts b/src/main/version-checker.test.ts index 0a40e3b..1d2ca0d 100644 --- a/src/main/version-checker.test.ts +++ b/src/main/version-checker.test.ts @@ -151,7 +151,7 @@ function mirrorIndexPayload(): MirrorTestIndex { { platform: 'linux', arch: 'arm64', formats: ['AppImage', 'deb'] } ] const releaseBase = - `https://goodbuddy.oss-cn-hangzhou.aliyuncs.com/releases/` + + `https://goodbuddy.oss-cn-beijing.aliyuncs.com/releases/` + `v${latestVersion}/` const targets: Record = {} for (const definition of definitions) { diff --git a/src/main/version-checker.ts b/src/main/version-checker.ts index 0d4ea1b..c02d244 100644 --- a/src/main/version-checker.ts +++ b/src/main/version-checker.ts @@ -13,7 +13,7 @@ export type { export const GOODBUDDY_LATEST_RELEASE_API_URL = 'https://api.github.com/repos/mesalogo/goodbuddy/releases/latest' export const GOODBUDDY_MIRROR_RELEASE_INDEX_URL = - 'https://goodbuddy.oss-cn-hangzhou.aliyuncs.com/releases/latest.json' + 'https://goodbuddy.oss-cn-beijing.aliyuncs.com/releases/latest.json' const PRODUCT_NAME = 'GoodBuddy' const RELEASE_WEB_ROOT = diff --git a/tests/packages-workflow.test.ts b/tests/packages-workflow.test.ts index 27a1da5..3a232e1 100644 --- a/tests/packages-workflow.test.ts +++ b/tests/packages-workflow.test.ts @@ -28,4 +28,20 @@ describe('packages workflow', () => { ]) ) }) + + it('passes the endpoint-derived region to every OSS upload', () => { + expect(workflow).toContain( + 'https://oss-cn-beijing.aliyuncs.com' + ) + expect(workflow).toContain('goodbuddy) ;;') + expect(workflow).toContain( + 'oss_region="${endpoint_host#oss-}"' + ) + expect(workflow).toContain( + 'echo "region=$oss_region" >> "$GITHUB_OUTPUT"' + ) + expect( + [...workflow.matchAll(/--region "\$OSS_REGION"/gu)] + ).toHaveLength(2) + }) }) diff --git a/tests/site-release.test.ts b/tests/site-release.test.ts index 8431e60..85394eb 100644 --- a/tests/site-release.test.ts +++ b/tests/site-release.test.ts @@ -94,7 +94,7 @@ describe('site release manifest', () => { it('creates direct HTTPS download entries for all release targets', () => { const result = siteRelease.createSiteRelease( createAggregateManifest(), - 'https://goodbuddy.oss-cn-hangzhou.aliyuncs.com/releases/v1.2.3' + 'https://goodbuddy.oss-cn-beijing.aliyuncs.com/releases/v1.2.3' ) expect(result.version).toBe('1.2.3') @@ -102,7 +102,7 @@ describe('site release manifest', () => { expect( result.targets['windows-x64']?.files.nsis?.url ).toBe( - 'https://goodbuddy.oss-cn-hangzhou.aliyuncs.com/releases/v1.2.3/GoodBuddy-1.2.3-windows-x64-setup.exe' + 'https://goodbuddy.oss-cn-beijing.aliyuncs.com/releases/v1.2.3/GoodBuddy-1.2.3-windows-x64-setup.exe' ) expect(result.checksumUrl).toMatch(/\/SHA256SUMS$/u) expect(result.fallbackUrl).toBe( @@ -128,7 +128,7 @@ describe('site release manifest', () => { it('verifies every public OSS object with HEAD and size checks', async () => { const manifest = siteRelease.createSiteRelease( createAggregateManifest(), - 'https://goodbuddy.oss-cn-hangzhou.aliyuncs.com/releases/v1.2.3/' + 'https://goodbuddy.oss-cn-beijing.aliyuncs.com/releases/v1.2.3/' ) const sizes = new Map( Object.values(manifest.targets).flatMap((target) =>