diff --git a/.github/workflows/live-host-release.yml b/.github/workflows/live-host-release.yml index 8fc91eb8b52..33b4e627d3b 100644 --- a/.github/workflows/live-host-release.yml +++ b/.github/workflows/live-host-release.yml @@ -120,21 +120,32 @@ jobs: env: APPLE_CERTIFICATE: '${{ secrets.APPLE_CERTIFICATE }}' APPLE_CERTIFICATE_PASSWORD: '${{ secrets.APPLE_CERTIFICATE_PASSWORD }}' + LEGACY_APPLE_CERTIFICATE: '${{ secrets.MAC_CSC_LINK }}' + LEGACY_APPLE_CERTIFICATE_PASSWORD: '${{ secrets.MAC_CSC_KEY_PASSWORD }}' KEYCHAIN_PASSWORD: '${{ secrets.APPLE_KEYCHAIN_PASSWORD }}' run: | set -euo pipefail - for name in APPLE_CERTIFICATE APPLE_CERTIFICATE_PASSWORD KEYCHAIN_PASSWORD; do - if [ -z "${!name}" ]; then echo "::error::$name is required for published Qwen Live Host releases."; exit 1; fi - done + if [ -n "$APPLE_CERTIFICATE" ] && [ -n "$APPLE_CERTIFICATE_PASSWORD" ]; then + certificate_data="$APPLE_CERTIFICATE" + certificate_password="$APPLE_CERTIFICATE_PASSWORD" + elif [ -n "$LEGACY_APPLE_CERTIFICATE" ] && [ -n "$LEGACY_APPLE_CERTIFICATE_PASSWORD" ]; then + certificate_data="$LEGACY_APPLE_CERTIFICATE" + certificate_password="$LEGACY_APPLE_CERTIFICATE_PASSWORD" + else + echo '::error::A complete APPLE_CERTIFICATE pair or MAC_CSC pair is required for published Qwen Live Host releases.' + exit 1 + fi + keychain_password="${KEYCHAIN_PASSWORD:-$(openssl rand -hex 32)}" certificate="$RUNNER_TEMP/qwen-live-host.p12" keychain="$RUNNER_TEMP/qwen-live-host.keychain-db" - printf '%s' "$APPLE_CERTIFICATE" | base64 --decode > "$certificate" - security create-keychain -p "$KEYCHAIN_PASSWORD" "$keychain" + certificate_data="${certificate_data#*base64,}" + printf '%s' "$certificate_data" | base64 --decode > "$certificate" + security create-keychain -p "$keychain_password" "$keychain" security set-keychain-settings -lut 21600 "$keychain" - security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$keychain" - security import "$certificate" -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$keychain" + security unlock-keychain -p "$keychain_password" "$keychain" + security import "$certificate" -P "$certificate_password" -A -t cert -f pkcs12 -k "$keychain" security list-keychains -d user -s "$keychain" login.keychain-db - security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$keychain" + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$keychain_password" "$keychain" identity="$(security find-identity -v -p codesigning "$keychain" | sed -n 's/.*"\(Developer ID Application:.*\)"/\1/p' | head -n 1)" if [ -z "$identity" ]; then echo '::error::Developer ID Application identity was not found.'; exit 1; fi { @@ -149,18 +160,31 @@ jobs: APPLE_API_ISSUER: '${{ secrets.APPLE_API_ISSUER }}' APPLE_API_KEY_ID: '${{ secrets.APPLE_API_KEY }}' APPLE_API_KEY_P8: '${{ secrets.APPLE_API_KEY_P8 }}' + LEGACY_APPLE_API_ISSUER: '${{ secrets.APPLE_NOTARY_ISSUER_ID }}' + LEGACY_APPLE_API_KEY_ID: '${{ secrets.APPLE_NOTARY_KEY_ID }}' + LEGACY_APPLE_API_KEY_P8: '${{ secrets.APPLE_NOTARY_API_KEY_P8_BASE64 }}' APPLE_TEAM_ID: '${{ secrets.APPLE_TEAM_ID }}' run: | set -euo pipefail - for name in APPLE_API_ISSUER APPLE_API_KEY_ID APPLE_API_KEY_P8 APPLE_TEAM_ID; do - if [ -z "${!name}" ]; then echo "::error::$name is required for Qwen Live Host notarization."; exit 1; fi - done - key_path="$RUNNER_TEMP/AuthKey_${APPLE_API_KEY_ID}.p8" - printf '%s' "$APPLE_API_KEY_P8" > "$key_path" + if [ -n "$APPLE_API_ISSUER" ] && [ -n "$APPLE_API_KEY_ID" ] && [ -n "$APPLE_API_KEY_P8" ]; then + api_issuer="$APPLE_API_ISSUER" + api_key_id="$APPLE_API_KEY_ID" + key_path="$RUNNER_TEMP/AuthKey_${api_key_id}.p8" + printf '%s' "$APPLE_API_KEY_P8" > "$key_path" + elif [ -n "$LEGACY_APPLE_API_ISSUER" ] && [ -n "$LEGACY_APPLE_API_KEY_ID" ] && [ -n "$LEGACY_APPLE_API_KEY_P8" ]; then + api_issuer="$LEGACY_APPLE_API_ISSUER" + api_key_id="$LEGACY_APPLE_API_KEY_ID" + key_path="$RUNNER_TEMP/AuthKey_${api_key_id}.p8" + printf '%s' "$LEGACY_APPLE_API_KEY_P8" | base64 --decode > "$key_path" + else + echo '::error::A complete APPLE_API notarization set or APPLE_NOTARY set is required for Qwen Live Host notarization.' + exit 1 + fi + if [ -z "$APPLE_TEAM_ID" ]; then echo '::error::APPLE_TEAM_ID is required for Qwen Live Host notarization.'; exit 1; fi { echo "APPLE_API_KEY=$key_path" - echo "APPLE_API_KEY_ID=$APPLE_API_KEY_ID" - echo "APPLE_API_ISSUER=$APPLE_API_ISSUER" + echo "APPLE_API_KEY_ID=$api_key_id" + echo "APPLE_API_ISSUER=$api_issuer" echo "APPLE_TEAM_ID=$APPLE_TEAM_ID" } >> "$GITHUB_ENV" diff --git a/scripts/tests/release-workflow.test.js b/scripts/tests/release-workflow.test.js index 28a7af6033b..254e30d6ea1 100644 --- a/scripts/tests/release-workflow.test.js +++ b/scripts/tests/release-workflow.test.js @@ -90,6 +90,32 @@ describe('Live Host release workflow', () => { 'https://github.com/QwenLM/qwen-code/releases/download/live-host-latest', ); }); + + it('accepts the repository macOS signing and notarization secrets', () => { + for (const secret of [ + 'MAC_CSC_LINK', + 'MAC_CSC_KEY_PASSWORD', + 'APPLE_NOTARY_ISSUER_ID', + 'APPLE_NOTARY_KEY_ID', + 'APPLE_NOTARY_API_KEY_P8_BASE64', + 'APPLE_TEAM_ID', + ]) { + expect(liveHostReleaseWorkflow).toContain(`secrets.${secret}`); + } + expect(liveHostReleaseWorkflow).toContain( + 'keychain_password="${KEYCHAIN_PASSWORD:-$(openssl rand -hex 32)}"', + ); + expect(liveHostReleaseWorkflow).toContain( + 'certificate_data="${certificate_data#*base64,}"', + ); + expect(liveHostReleaseWorkflow).toContain( + 'printf \'%s\' "$LEGACY_APPLE_API_KEY_P8" | base64 --decode > "$key_path"', + ); + expect(liveHostReleaseWorkflow).toContain('echo "APPLE_API_KEY=$key_path"'); + expect(liveHostReleaseWorkflow).toContain( + 'echo "APPLE_API_KEY_ID=$api_key_id"', + ); + }); }); describe('Live Host CI workflow', () => {