diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2d6d2496a..c5f450e0c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -268,6 +268,7 @@ jobs: run: | python - <<'PY' import base64 + import binascii import os from pathlib import Path @@ -286,46 +287,31 @@ jobs: if "\\n" in raw and "\n" not in raw: add(raw.replace("\\r\\n", "\n").replace("\\n", "\n")) - for candidate in list(candidates): - compact = candidate.strip() - if not compact: - continue - padding = (-len(compact)) % 4 - compact = compact + ("=" * padding) + def as_tauri_secret_key(value: str) -> str: + compact = "".join(value.split()) try: - decoded = base64.b64decode(compact, validate=True).decode("utf-8") - except Exception: - continue - add(decoded) - if "\\n" in decoded and "\n" not in decoded: - add(decoded.replace("\\r\\n", "\n").replace("\\n", "\n")) + base64.b64decode(compact, validate=True) + except (binascii.Error, ValueError): + return "" + return compact normalized_key = next( ( - candidate + key for candidate in candidates - if candidate.lstrip().startswith("untrusted comment:") - and "\n" in candidate + for key in [as_tauri_secret_key(candidate)] + if key ), "", ) - if not normalized_key: - normalized_key = next( - ( - candidate - for candidate in candidates - if candidate.lstrip().startswith("untrusted comment:") - ), - "", - ) if not normalized_key: raise SystemExit( - "Unable to normalize TAURI_SIGNING_PRIVATE_KEY into minisign secret key content. " - "Expected raw multiline key, literal \\\\n escaped key, or base64 encoded key." + "Unable to normalize TAURI_SIGNING_PRIVATE_KEY into Tauri signer base64 key content. " + "Expected the private key value generated by `npx tauri signer generate --write-keys`." ) key_path = Path(os.environ["RUNNER_TEMP"]) / "tauri-updater.key" - key_path.write_text(normalized_key.rstrip("\n") + "\n", encoding="utf-8") + key_path.write_text(normalized_key, encoding="utf-8") key_path.chmod(0o600) with open(os.environ["GITHUB_ENV"], "a", encoding="utf-8") as env_file: diff --git a/src/lib/oemCloudStartupLogin.test.ts b/src/lib/oemCloudStartupLogin.test.ts index 5f1e831f6..3fbc26220 100644 --- a/src/lib/oemCloudStartupLogin.test.ts +++ b/src/lib/oemCloudStartupLogin.test.ts @@ -40,6 +40,7 @@ describe("oemCloudStartupLogin", () => { delete window.__LIME_BOOTSTRAP__; delete window.__LIME_OEM_CLOUD__; delete window.__LIME_SESSION_TOKEN__; + vi.spyOn(console, "warn").mockImplementation(() => undefined); mockListPublicOAuthProviders.mockResolvedValue([ { provider: "google", @@ -120,4 +121,17 @@ describe("oemCloudStartupLogin", () => { expect(result.status).toBe("no_google_provider"); expect(mockStartOemCloudLogin).not.toHaveBeenCalled(); }); + + it("读取后端登录策略失败时不应阻塞主应用启动", async () => { + configureRuntime(); + mockListPublicOAuthProviders.mockRejectedValue(new Error("network down")); + + const result = await startOemCloudStartupLoginIfRequired(); + + expect(result).toEqual({ + status: "failed", + reason: "network down", + }); + expect(mockStartOemCloudLogin).not.toHaveBeenCalled(); + }); }); diff --git a/src/lib/oemCloudStartupLogin.ts b/src/lib/oemCloudStartupLogin.ts index ae4079b00..8b943458c 100644 --- a/src/lib/oemCloudStartupLogin.ts +++ b/src/lib/oemCloudStartupLogin.ts @@ -83,7 +83,18 @@ export async function startOemCloudStartupLoginIfRequired( return { status: "already_attempted" }; } - const providers = await listPublicOAuthProviders(runtime.tenantId); + let providers: OemCloudPublicOAuthProvider[]; + try { + providers = await listPublicOAuthProviders(runtime.tenantId); + } catch (error) { + const reason = + error instanceof Error && error.message.trim() + ? error.message.trim() + : "读取云端登录配置失败"; + console.warn("读取启动期云端登录配置失败:", error); + return { status: "failed", reason }; + } + if (!hasGoogleOAuthProvider(providers)) { return { status: "no_google_provider" }; }