v2026.509.22706.杂鱼 #296
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 签名并重新打包工作流(仅用于正式发布版本) | |
| # 流程: | |
| # 1. 编译当前分支的代码(只编译一次) | |
| # 2. 生成未签名的 ZIP 和 Inno Setup staging 目录 | |
| # 3. 将所有 EXE/DLL 文件提交到 SignPath 签名 | |
| # 4. 用签名文件重新打包 ZIP 便携版 | |
| # 5. 用签名文件替换 Inno Setup staging 目录中的文件并重新打包 | |
| # 6. 签名最终的 Inno Setup 安装包 | |
| # 注意:只在正式发布(非预发布)时运行,确保代码版本和签名文件一致 | |
| name: Sign and Repackage (Release Only) | |
| on: | |
| release: | |
| types: [published] | |
| workflow_dispatch: | |
| inputs: | |
| ref: | |
| description: "Branch or tag to checkout (e.g., master, v2025.1116)" | |
| required: true | |
| default: "master" | |
| release-tag: | |
| description: "Release tag for naming the output files" | |
| required: true | |
| # Opt all Node.js 20 actions onto the Node.js 24 runtime to silence the | |
| # `actions/checkout@v4` deprecation warning until upstream actions cut new | |
| # releases. | |
| env: | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true' | |
| jobs: | |
| sign-and-repackage: | |
| name: Sign Files and Repackage | |
| runs-on: windows-latest | |
| # 只在正式发布时运行(不是预发布) | |
| if: ${{ (github.event_name == 'release' && !github.event.release.prerelease) || github.event_name == 'workflow_dispatch' }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.event.inputs.ref || github.ref }} | |
| submodules: recursive | |
| - name: Setup Dependencies Windows | |
| uses: msys2/setup-msys2@v2 | |
| with: | |
| msystem: ucrt64 | |
| update: true | |
| install: >- | |
| wget | |
| - name: Update Windows dependencies | |
| env: | |
| gcc_version: '15.1.0-5' | |
| shell: msys2 {0} | |
| run: | | |
| broken_deps=( | |
| "mingw-w64-ucrt-x86_64-gcc" | |
| "mingw-w64-ucrt-x86_64-gcc-libs" | |
| ) | |
| tarballs="" | |
| for dep in "${broken_deps[@]}"; do | |
| tarball="${dep}-${gcc_version}-any.pkg.tar.zst" | |
| # download and install working version | |
| wget https://repo.msys2.org/mingw/ucrt64/${tarball} | |
| tarballs="${tarballs} ${tarball}" | |
| done | |
| # install broken dependencies | |
| if [ -n "$tarballs" ]; then | |
| pacman -U --noconfirm ${tarballs} | |
| fi | |
| # install dependencies | |
| dependencies=( | |
| "git" | |
| "mingw-w64-ucrt-x86_64-cmake" | |
| "mingw-w64-ucrt-x86_64-ninja" | |
| "mingw-w64-ucrt-x86_64-cppwinrt" | |
| "mingw-w64-ucrt-x86_64-curl-winssl" | |
| "mingw-w64-ucrt-x86_64-graphviz" | |
| "mingw-w64-ucrt-x86_64-MinHook" | |
| "mingw-w64-ucrt-x86_64-miniupnpc" | |
| "mingw-w64-ucrt-x86_64-nlohmann-json" | |
| "mingw-w64-ucrt-x86_64-nodejs" | |
| # "mingw-w64-ucrt-x86_64-nsis" # Replaced by Inno Setup | |
| "mingw-w64-ucrt-x86_64-onevpl" | |
| "mingw-w64-ucrt-x86_64-openssl" | |
| "mingw-w64-ucrt-x86_64-opus" | |
| "mingw-w64-ucrt-x86_64-toolchain" | |
| ) | |
| # Note: mingw-w64-ucrt-x86_64-rust conflicts with fixed gcc-15.1.0-5 | |
| # We install Rust via rustup in a separate step | |
| pacman -Syu --noconfirm --ignore="$(IFS=,; echo "${broken_deps[*]}")" "${dependencies[@]}" | |
| - name: Install Rust (for Tauri GUI) | |
| shell: msys2 {0} | |
| run: | | |
| echo "Installing Rust via rustup..." | |
| # Rust installs to Windows user directory | |
| WINDOWS_USER=$(cmd //c "echo %USERNAME%" | tr -d '\r') | |
| CARGO_BIN="/c/Users/${WINDOWS_USER}/.cargo/bin" | |
| export PATH="$CARGO_BIN:$PATH" | |
| # Check if cargo already exists | |
| if command -v cargo &> /dev/null; then | |
| echo "Rust already installed: $(cargo --version)" | |
| else | |
| # Download and install rustup | |
| curl --proto '=https' --tlsv1.2 -sSf https://win.rustup.rs/x86_64 -o /tmp/rustup-init.exe | |
| /tmp/rustup-init.exe -y --default-toolchain stable --profile minimal | |
| # Refresh PATH | |
| sleep 3 | |
| export PATH="$CARGO_BIN:$PATH" | |
| # Verify installation | |
| if [ -f "$CARGO_BIN/cargo.exe" ]; then | |
| echo "Rust installed successfully: $(cargo --version)" | |
| else | |
| echo "Warning: Rust installed but cargo not found at $CARGO_BIN" | |
| exit 1 | |
| fi | |
| fi | |
| - name: Verify Build Tools | |
| shell: msys2 {0} | |
| run: | | |
| echo "Verifying build tools are installed..." | |
| which cmake || (echo "cmake not found" && exit 1) | |
| which ninja || (echo "ninja not found" && exit 1) | |
| which gcc || (echo "gcc not found" && exit 1) | |
| # verify Rust is in PATH | |
| WINDOWS_USER=$(cmd //c "echo %USERNAME%" | tr -d '\r') | |
| CARGO_BIN="/c/Users/${WINDOWS_USER}/.cargo/bin" | |
| export PATH="$CARGO_BIN:$PATH" | |
| which cargo || (echo "cargo not found" && exit 1) | |
| echo "All build tools verified successfully" | |
| echo " CMake: $(cmake --version | head -1)" | |
| echo " Ninja: $(ninja --version)" | |
| echo " GCC: $(gcc --version | head -1)" | |
| echo " Cargo: $(cargo --version)" | |
| - name: Build Windows | |
| shell: msys2 {0} | |
| env: | |
| BRANCH: master | |
| BUILD_VERSION: ${{ github.event_name == 'release' && github.event.release.tag_name || github.event.inputs.release-tag }}.杂鱼 | |
| COMMIT: ${{ github.sha }} | |
| run: | | |
| # add Rust to PATH for Tauri GUI build | |
| WINDOWS_USER=$(cmd //c "echo %USERNAME%" | tr -d '\r') | |
| CARGO_BIN="/c/Users/${WINDOWS_USER}/.cargo/bin" | |
| export PATH="$CARGO_BIN:$PATH" | |
| mkdir -p build | |
| cmake \ | |
| -B build \ | |
| -G Ninja \ | |
| -S . \ | |
| -DBUILD_DOCS=OFF \ | |
| -DSUNSHINE_ASSETS_DIR=assets \ | |
| -DSUNSHINE_PUBLISHER_NAME='${{ github.repository_owner }}' \ | |
| -DSUNSHINE_PUBLISHER_WEBSITE='https://github.com/qiin2333/Sunshine-Foundation' \ | |
| -DSUNSHINE_PUBLISHER_ISSUE_URL='https://github.com/qiin2333/Sunshine-Foundation/issues' | |
| ninja -C build | |
| ninja -C build sunshine-control-panel | |
| # Install Inno Setup | |
| - name: Install Inno Setup | |
| shell: pwsh | |
| run: | | |
| $url = "https://jrsoftware.org/download.php/is.exe" | |
| $installer = "$env:TEMP\innosetup.exe" | |
| Invoke-WebRequest -Uri $url -OutFile $installer | |
| Start-Process -FilePath $installer -ArgumentList '/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-' -Wait | |
| echo "C:\Program Files (x86)\Inno Setup 6" >> $env:GITHUB_PATH | |
| # 生成未签名的打包产物 | |
| - name: Package unsigned files | |
| shell: msys2 {0} | |
| run: | | |
| cd build | |
| # 生成 ZIP 便携版(包含所有文件) | |
| cpack -G ZIP --verbose | |
| # 生成 Inno Setup staging 目录 | |
| echo "Generating Inno Setup staging directory..." | |
| cmake --install . --prefix ./inno_staging | |
| cd .. | |
| # 列出生成的文件 | |
| echo "Generated files:" | |
| ls -lh build/cpack_artifacts/ | |
| # 解压 Portable ZIP 获取所有需要签名的文件 | |
| - name: Extract files for signing | |
| shell: bash | |
| run: | | |
| PORTABLE=$(find build/cpack_artifacts -name "*.zip" | head -n 1) | |
| if [ -n "$PORTABLE" ]; then | |
| echo "Extracting: $PORTABLE" | |
| mkdir -p unsigned-files | |
| 7z x "$PORTABLE" -o"unsigned-files" -y -aoa | |
| echo "Extracted files for signing:" | |
| ls -laR unsigned-files/ | |
| else | |
| echo "No portable ZIP found" | |
| exit 1 | |
| fi | |
| # 上传所有未签名的文件到 SignPath | |
| - name: Upload unsigned files for signing | |
| id: upload-unsigned | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: files-for-signing | |
| path: unsigned-files/ | |
| # 提交到 SignPath 签名(使用生产策略) | |
| - name: Submit to SignPath for signing | |
| uses: signpath/github-action-submit-signing-request@v1 | |
| with: | |
| api-token: ${{ secrets.SIGNPATH_API_TOKEN }} | |
| organization-id: ${{ secrets.SIGNPATH_ORGANIZATION_ID }} | |
| project-slug: Sunshine-Foundation | |
| signing-policy-slug: release-signing | |
| artifact-configuration-slug: windows-portable | |
| github-artifact-id: "${{ steps.upload-unsigned.outputs.artifact-id }}" | |
| output-artifact-directory: signed-files | |
| wait-for-completion: true | |
| wait-for-completion-timeout-in-seconds: 600 | |
| service-unavailable-timeout-in-seconds: 600 | |
| # 验证签名 | |
| - name: Verify all signatures | |
| shell: pwsh | |
| run: | | |
| Write-Host "Verifying signatures..." | |
| $signedFiles = Get-ChildItem -Path "signed-files" -Recurse -File -Include *.exe,*.dll | |
| foreach ($file in $signedFiles) { | |
| Write-Host "`n=== $($file.Name) ===" | |
| $signature = Get-AuthenticodeSignature $file.FullName | |
| Write-Host "Status: $($signature.Status)" | |
| if ($signature.Status -ne "Valid") { | |
| Write-Error "Signature invalid for: $($file.Name)" | |
| exit 1 | |
| } | |
| } | |
| Write-Host "`n✓ All signatures are VALID!" -ForegroundColor Green | |
| # 使用签名后的文件重新打包 ZIP 便携版 | |
| - name: Repackage signed Portable ZIP | |
| shell: bash | |
| run: | | |
| cd signed-files | |
| # 使用与输入一致的版本号 | |
| if [ -n "${{ github.event.inputs.release-tag }}" ]; then | |
| VERSION="${{ github.event.inputs.release-tag }}" | |
| elif [ -n "${{ github.event.release.tag_name }}" ]; then | |
| VERSION="${{ github.event.release.tag_name }}" | |
| else | |
| VERSION="v$(date +%Y.%m%d)" | |
| fi | |
| 7z a "../Sunshine-${VERSION}-Windows-Portable-Signed.zip" * -y | |
| cd .. | |
| echo "Created signed portable package:" | |
| ls -lh Sunshine-*-Portable-Signed.zip | |
| # 使用签名文件重新打包 Inno Setup 安装包 | |
| - name: Repackage signed Inno Setup installer | |
| shell: msys2 {0} | |
| run: | | |
| echo "Repackaging Inno Setup installer with signed files..." | |
| STAGING_DIR="build/inno_staging" | |
| # 检查 staging 目录是否存在 | |
| if [ ! -d "$STAGING_DIR" ]; then | |
| echo "Error: Inno Setup staging directory not found: $STAGING_DIR" | |
| ls -laR build/ | |
| exit 1 | |
| fi | |
| # 替换为签名后的文件 | |
| SIGNED_SRC="signed-files/Sunshine" | |
| echo "Replacing with signed files..." | |
| cp -fv "$SIGNED_SRC/sunshine.exe" "$STAGING_DIR/sunshine.exe" | |
| cp -fv "$SIGNED_SRC/zlib1.dll" "$STAGING_DIR/zlib1.dll" | |
| cp -fv "$SIGNED_SRC/tools/sunshinesvc.exe" "$STAGING_DIR/tools/sunshinesvc.exe" | |
| cp -fv "$SIGNED_SRC/tools/qiin-tabtip.exe" "$STAGING_DIR/tools/qiin-tabtip.exe" | |
| cp -fv "$SIGNED_SRC/tools/device-toggler.exe" "$STAGING_DIR/tools/device-toggler.exe" | |
| cp -fv "$SIGNED_SRC/tools/DevManView.exe" "$STAGING_DIR/tools/DevManView.exe" | |
| cp -fv "$SIGNED_SRC/tools/restart64.exe" "$STAGING_DIR/tools/restart64.exe" | |
| cp -fv "$SIGNED_SRC/tools/SetDpi.exe" "$STAGING_DIR/tools/SetDpi.exe" | |
| cp -fv "$SIGNED_SRC/tools/setreg.exe" "$STAGING_DIR/tools/setreg.exe" | |
| cp -fv "$SIGNED_SRC/tools/audio-info.exe" "$STAGING_DIR/tools/audio-info.exe" | |
| cp -fv "$SIGNED_SRC/tools/dxgi-info.exe" "$STAGING_DIR/tools/dxgi-info.exe" | |
| cp -fv "$SIGNED_SRC/assets/gui/sunshine-gui.exe" "$STAGING_DIR/assets/gui/sunshine-gui.exe" | |
| # 运行 Inno Setup 编译器重新打包 | |
| echo "Running ISCC to repackage installer..." | |
| "/c/Program Files (x86)/Inno Setup 6/ISCC.exe" "build/sunshine_installer.iss" | |
| # 使用与 Portable ZIP 一致的版本号 | |
| if [ -n "${{ github.event.inputs.release-tag }}" ]; then | |
| VERSION="${{ github.event.inputs.release-tag }}" | |
| elif [ -n "${{ github.event.release.tag_name }}" ]; then | |
| VERSION="${{ github.event.release.tag_name }}" | |
| else | |
| VERSION="v$(date +%Y.%m%d)" | |
| fi | |
| mv -fv "build/cpack_artifacts/Sunshine.exe" "Sunshine-${VERSION}-Windows-Installer-Signed.exe" | |
| echo "Created signed installer:" | |
| ls -lh Sunshine-*-Installer-Signed.exe | |
| # 签名最终的 Inno Setup 安装包 | |
| - name: Upload installer for final signing | |
| id: upload-installer | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: installer-for-final-signing | |
| path: Sunshine-*-Installer-Signed.exe | |
| - name: Sign installer | |
| uses: signpath/github-action-submit-signing-request@v1 | |
| with: | |
| api-token: ${{ secrets.SIGNPATH_API_TOKEN }} | |
| organization-id: ${{ secrets.SIGNPATH_ORGANIZATION_ID }} | |
| project-slug: Sunshine-Foundation | |
| signing-policy-slug: release-signing | |
| artifact-configuration-slug: windows-installer | |
| github-artifact-id: "${{ steps.upload-installer.outputs.artifact-id }}" | |
| output-artifact-directory: final-signed | |
| wait-for-completion: true | |
| wait-for-completion-timeout-in-seconds: 600 | |
| service-unavailable-timeout-in-seconds: 600 | |
| # 验证最终签名 | |
| - name: Verify final installer signature | |
| shell: pwsh | |
| run: | | |
| $installer = Get-ChildItem "final-signed" -Filter "*.exe" | Select-Object -First 1 | |
| if ($installer) { | |
| Write-Host "Verifying installer signature..." | |
| $signature = Get-AuthenticodeSignature $installer.FullName | |
| Write-Host "Status: $($signature.Status)" | |
| if ($signature.Status -eq "Valid") { | |
| Write-Host "✓ Installer signature is VALID!" -ForegroundColor Green | |
| } | |
| } | |
| # 上传最终的签名文件 | |
| - name: Upload final signed packages | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: sunshine-windows-fully-signed | |
| path: | | |
| Sunshine-*-Portable-Signed.zip | |
| final-signed/*.exe | |
| if-no-files-found: error | |
| # 发布到 GitHub Release | |
| - name: Create Release | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| tag_name: ${{ github.event_name == 'release' && github.event.release.tag_name || github.event.inputs.release-tag }} | |
| name: ${{ github.event_name == 'release' && github.event.release.name || github.event.inputs.release-tag }} (Signed) | |
| files: | | |
| Sunshine-*-Portable-Signed.zip | |
| final-signed/*.exe | |
| draft: true | |
| prerelease: true | |
| allowUpdates: true | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |