From fc906153501bb1e8d4ac6399f95d9015cfd5ab2e Mon Sep 17 00:00:00 2001 From: DarkSky Date: Sat, 4 Jul 2026 00:13:48 +0800 Subject: [PATCH] feat: faster sign --- .github/workflows/release-desktop.yml | 6 +- .github/workflows/windows-signer.yml | 44 ++++++++++--- scripts/check-windows-signer.mjs | 95 ++++----------------------- 3 files changed, 51 insertions(+), 94 deletions(-) diff --git a/.github/workflows/release-desktop.yml b/.github/workflows/release-desktop.yml index 6b94fd9317..5b28263853 100644 --- a/.github/workflows/release-desktop.yml +++ b/.github/workflows/release-desktop.yml @@ -89,9 +89,13 @@ jobs: id: check run: node ./scripts/check-windows-signer.mjs env: + AFFINE_SIGN_CLIENT_HASH: ${{ secrets.AFFINE_SIGN_CLIENT_HASH }} + AFFINE_SIGNER_ADDR: ${{ secrets.AFFINE_SIGNER_ADDR }} + AFFINE_SIGNER_TOKEN: ${{ secrets.AFFINE_SIGNER_TOKEN }} + AFFINE_SIGNER_TS_AUTH_KEY: ${{ secrets.AFFINE_SIGNER_TS_AUTH_KEY }} BUILD_TYPE: ${{ inputs.build-type }} - GITHUB_TOKEN: ${{ github.token }} REQUIRE_SIGNER: ${{ inputs.require-windows-signing }} + WINDOWS_SIGNER_PUBLIC_CERT_BASE64: ${{ secrets.WINDOWS_SIGNER_PUBLIC_CERT_BASE64 }} make-distribution-macos: if: ${{ inputs.desktop_macos }} diff --git a/.github/workflows/windows-signer.yml b/.github/workflows/windows-signer.yml index df6753a281..abd47fc268 100644 --- a/.github/workflows/windows-signer.yml +++ b/.github/workflows/windows-signer.yml @@ -10,26 +10,52 @@ on: type: string jobs: sign: - runs-on: [self-hosted, win-signer] + runs-on: windows-latest env: ARCHIVE_DIR: ${{ github.run_id }}-${{ github.run_attempt }}-${{ inputs.artifact-name }} + AFFINE_SIGNER_ADDR: ${{ secrets.AFFINE_SIGNER_ADDR }} + AFFINE_SIGNER_TOKEN: ${{ secrets.AFFINE_SIGNER_TOKEN }} + TS_AUTH_KEY: ${{ secrets.AFFINE_SIGNER_TS_AUTH_KEY }} + TS_CONTROL_URL: ${{ secrets.AFFINE_SIGNER_TS_CONTROL_URL }} + TS_RS_EXPERIMENT: this_is_unstable_software steps: - uses: actions/download-artifact@v4 with: name: ${{ inputs.artifact-name }} path: ${{ env.ARCHIVE_DIR }} + - name: Download remote signer client + shell: pwsh + run: | + if (!$env:AFFINE_SIGN_CLIENT_HASH) { + throw 'AFFINE_SIGN_CLIENT_HASH is required.' + } + Invoke-WebRequest -Uri "https://cdn.affine.pro/sign-client/$env:AFFINE_SIGN_CLIENT_HASH" -OutFile affine-sign-client.exe + env: + AFFINE_SIGN_CLIENT_HASH: ${{ secrets.AFFINE_SIGN_CLIENT_HASH }} + - name: Prepare public signing certificate + shell: pwsh + run: | + if (!$env:WINDOWS_SIGNER_PUBLIC_CERT_BASE64) { + throw 'WINDOWS_SIGNER_PUBLIC_CERT_BASE64 is required.' + } + [IO.File]::WriteAllBytes('windows-signer-public.cer', [Convert]::FromBase64String($env:WINDOWS_SIGNER_PUBLIC_CERT_BASE64)) + env: + WINDOWS_SIGNER_PUBLIC_CERT_BASE64: ${{ secrets.WINDOWS_SIGNER_PUBLIC_CERT_BASE64 }} - name: unzip file - shell: cmd - # 7za is pre-installed on the signer machine + shell: pwsh run: | - cd ${{ env.ARCHIVE_DIR }} - md out - 7za x archive.zip -y -oout + New-Item -ItemType Directory -Path '${{ env.ARCHIVE_DIR }}/out' -Force | Out-Null + Expand-Archive -Path '${{ env.ARCHIVE_DIR }}/archive.zip' -DestinationPath '${{ env.ARCHIVE_DIR }}/out' - name: sign - shell: cmd + shell: pwsh run: | - cd ${{ env.ARCHIVE_DIR }}/out - signtool sign /tr http://timestamp.globalsign.com/tsa/r6advanced1 /td sha256 /fd sha256 /a ${{ inputs.files }} + ./affine-sign-client.exe ` + --server "$env:AFFINE_SIGNER_ADDR" ` + --token "$env:AFFINE_SIGNER_TOKEN" ` + --workdir '${{ env.ARCHIVE_DIR }}/out' ` + --files '${{ inputs.files }}' ` + --cert windows-signer-public.cer ` + --allow-file-fallback - name: collect signed file diff shell: powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File {0} run: | diff --git a/scripts/check-windows-signer.mjs b/scripts/check-windows-signer.mjs index d01a5a1a37..28b33b0ceb 100644 --- a/scripts/check-windows-signer.mjs +++ b/scripts/check-windows-signer.mjs @@ -4,47 +4,21 @@ const buildType = process.env.BUILD_TYPE; const requireSigner = process.env.REQUIRE_SIGNER === 'true' || ['beta', 'stable'].includes(buildType); -const githubToken = process.env.GITHUB_TOKEN; -const repository = process.env.GITHUB_REPOSITORY; -const apiUrl = process.env.GITHUB_API_URL ?? 'https://api.github.com'; const outputPath = process.env.GITHUB_OUTPUT; -if (!githubToken) { - fail('Missing GITHUB_TOKEN.'); -} +const missing = [ + 'AFFINE_SIGN_CLIENT_HASH', + 'AFFINE_SIGNER_ADDR', + 'AFFINE_SIGNER_TOKEN', + 'AFFINE_SIGNER_TS_AUTH_KEY', + 'WINDOWS_SIGNER_PUBLIC_CERT_BASE64', +].filter(name => !process.env[name]); -if (!repository) { - fail('Missing GITHUB_REPOSITORY.'); -} - -const [owner, repo] = repository.split('/'); -if (!owner || !repo) { - fail(`Invalid GITHUB_REPOSITORY: ${repository}`); -} - -try { - const runners = await listAllRunners(owner, repo); - const signerAvailable = runners.some(runner => { - const labels = (runner.labels ?? []).map(label => label.name); - return runner.status === 'online' && labels.includes('win-signer'); - }); - - setOutput('signer_available', signerAvailable ? 'true' : 'false'); - - if (!signerAvailable) { - const message = - 'No online self-hosted runner with label "win-signer" is available.'; - if (requireSigner) { - fail(message); - } else { - console.warn( - `::warning::${message} Windows installer executables will be skipped.` - ); - } - } -} catch (error) { +if (missing.length === 0) { + setOutput('signer_available', 'true'); +} else { setOutput('signer_available', 'false'); - const message = `Failed to query self-hosted runner availability: ${formatError(error)}`; + const message = `Missing remote Windows signer configuration: ${missing.join(', ')}.`; if (requireSigner) { fail(message); } else { @@ -54,46 +28,6 @@ try { } } -async function listAllRunners(owner, repo) { - const runners = []; - let page = 1; - - while (true) { - const url = new URL( - `/repos/${owner}/${repo}/actions/runners`, - ensureTrailingSlash(apiUrl) - ); - url.searchParams.set('per_page', '100'); - url.searchParams.set('page', String(page)); - - const response = await fetch(url, { - headers: { - Accept: 'application/vnd.github+json', - Authorization: `Bearer ${githubToken}`, - 'X-GitHub-Api-Version': '2022-11-28', - }, - }); - - if (!response.ok) { - const body = await response.text(); - throw new Error(`GitHub API ${response.status}: ${body}`); - } - - const data = await response.json(); - runners.push(...(data.runners ?? [])); - - if ((data.runners ?? []).length < 100) { - return runners; - } - - page += 1; - } -} - -function ensureTrailingSlash(url) { - return url.endsWith('/') ? url : `${url}/`; -} - function setOutput(name, value) { if (!outputPath) return; fs.appendFileSync(outputPath, `${name}=${value}\n`); @@ -103,10 +37,3 @@ function fail(message) { console.error(`::error::${message}`); process.exit(1); } - -function formatError(error) { - if (error instanceof Error) { - return error.message; - } - return String(error); -}