Upload to Cloudflare R2 #937
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
| name: Upload to Cloudflare R2 | |
| on: | |
| push: | |
| paths: | |
| - 'launcher/Flarial.Launcher.exe' | |
| - 'launcher/NewSupported.txt' | |
| - 'launcher/Supported.json' | |
| - 'launcher/Versions.json' | |
| - 'launcher/Promotions.json' | |
| - 'blacklist_dll_names.txt' | |
| - 'blacklist_dll_hashes.txt' | |
| - '.github/workflows/r2-upload.yml' | |
| # Android APK uploads are intentionally not triggered directly by | |
| # Android/Flarial.apk pushes. The Android hash workflow commits | |
| # AndroidHash.json immediately after the APK changes; uploading on the | |
| # APK push creates a race where R2 can serve a new APK with the old hash. | |
| # Let the workflow_run from "make android hashbrowns" publish the | |
| # validated APK+hash pair atomically instead. | |
| workflow_run: | |
| workflows: ["make hashbrowns", "make android hashbrowns"] | |
| types: | |
| - completed | |
| workflow_dispatch: | |
| jobs: | |
| upload-to-r2: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v3 | |
| - name: Configure AWS CLI for R2 | |
| run: | | |
| aws configure set aws_access_key_id ${{ secrets.R2_ACCESS_KEY_ID }} | |
| aws configure set aws_secret_access_key ${{ secrets.R2_SECRET_ACCESS_KEY }} | |
| aws configure set region auto | |
| - name: Upload files to R2 | |
| env: | |
| R2_ENDPOINT: https://${{ secrets.R2_ACCOUNT_ID }}.r2.cloudflarestorage.com | |
| R2_BUCKET: ${{ secrets.R2_BUCKET_NAME }} | |
| run: | | |
| # Upload Flarial Launcher version metadata. | |
| if [ -f "launcher/launcherVersion.txt" ]; then | |
| aws s3 cp launcher/launcherVersion.txt s3://${R2_BUCKET}/launcher/launcherVersion.txt \ | |
| --endpoint-url ${R2_ENDPOINT} | |
| echo "✓ Uploaded launcherVersion.txt" | |
| fi | |
| # Upload Flarial Launcher executable. | |
| if [ -f "launcher/Flarial.Launcher.exe" ]; then | |
| aws s3 cp launcher/Flarial.Launcher.exe s3://${R2_BUCKET}/launcher/Flarial.Launcher.exe \ | |
| --endpoint-url ${R2_ENDPOINT} | |
| echo "✓ Uploaded Flarial.Launcher.exe" | |
| fi | |
| # Upload DLL hashes metadata. | |
| if [ -f "dll_hashes.json" ]; then | |
| aws s3 cp dll_hashes.json s3://${R2_BUCKET}/dll_hashes.json \ | |
| --endpoint-url ${R2_ENDPOINT} | |
| echo "✓ Uploaded dll_hashes.json" | |
| fi | |
| # Upload third-party DLL deny lists. | |
| if [ -f "blacklist_dll_names.txt" ]; then | |
| aws s3 cp blacklist_dll_names.txt s3://${R2_BUCKET}/blacklist_dll_names.txt \ | |
| --content-type text/plain \ | |
| --endpoint-url ${R2_ENDPOINT} | |
| echo "✓ Uploaded blacklist_dll_names.txt" | |
| fi | |
| if [ -f "blacklist_dll_hashes.txt" ]; then | |
| aws s3 cp blacklist_dll_hashes.txt s3://${R2_BUCKET}/blacklist_dll_hashes.txt \ | |
| --content-type text/plain \ | |
| --endpoint-url ${R2_ENDPOINT} | |
| echo "✓ Uploaded blacklist_dll_hashes.txt" | |
| fi | |
| # Upload supported versions metadata. | |
| if [ -f "launcher/NewSupported.txt" ]; then | |
| aws s3 cp launcher/NewSupported.txt s3://${R2_BUCKET}/launcher/NewSupported.txt \ | |
| --endpoint-url ${R2_ENDPOINT} | |
| echo "✓ Uploaded NewSupported.txt" | |
| fi | |
| if [ -f "launcher/Supported.json" ]; then | |
| aws s3 cp launcher/Supported.json s3://${R2_BUCKET}/launcher/Supported.json \ | |
| --endpoint-url ${R2_ENDPOINT} | |
| echo "✓ Uploaded Supported.json" | |
| fi | |
| if [ -f "launcher/Versions.json" ]; then | |
| aws s3 cp launcher/Versions.json s3://${R2_BUCKET}/launcher/Versions.json \ | |
| --endpoint-url ${R2_ENDPOINT} | |
| echo "✓ Uploaded Versions.json" | |
| fi | |
| if [ -f "launcher/Promotions.json" ]; then | |
| aws s3 cp launcher/Promotions.json s3://${R2_BUCKET}/launcher/Promotions.json \ | |
| --endpoint-url ${R2_ENDPOINT} | |
| echo "✓ Uploaded Promotions.json" | |
| fi | |
| if [ -f "launcher/Flarial.Bootstrapper.exe" ]; then | |
| aws s3 cp launcher/Flarial.Bootstrapper.exe s3://${R2_BUCKET}/launcher/Flarial.Bootstrapper.exe \ | |
| --endpoint-url ${R2_ENDPOINT} | |
| echo "✓ Uploaded Flarial.Bootstrapper.exe" | |
| fi | |
| if [ -f "launcher/Flarial.Version.Changer.exe" ]; then | |
| aws s3 cp launcher/Flarial.Version.Changer.exe s3://${R2_BUCKET}/launcher/Flarial.Version.Changer.exe \ | |
| --endpoint-url ${R2_ENDPOINT} | |
| echo "✓ Uploaded Flarial.Version.Changer.exe" | |
| fi | |
| # Upload release build of the client. | |
| if [ -f "dll/latest.dll" ]; then | |
| aws s3 cp dll/latest.dll s3://${R2_BUCKET}/dll/latest.dll \ | |
| --endpoint-url ${R2_ENDPOINT} | |
| echo "✓ Uploaded latest.dll" | |
| fi | |
| # Upload beta build of the client. | |
| if [ -f "dll/beta.dll" ]; then | |
| aws s3 cp dll/beta.dll s3://${R2_BUCKET}/dll/beta.dll \ | |
| --endpoint-url ${R2_ENDPOINT} | |
| echo "✓ Uploaded beta.dll" | |
| fi | |
| if [ -f "202.txt" ]; then | |
| aws s3 cp 202.txt s3://${R2_BUCKET}/202.txt \ | |
| --endpoint-url ${R2_ENDPOINT} | |
| echo "✓ Uploaded 202.txt" | |
| fi | |
| # Upload latest Android APK and hash metadata. | |
| # Guard against publishing mismatched APK/hash pairs; Android clients | |
| # treat that as a corrupt APK. | |
| if [ -f "Android/Flarial.apk" ] || [ -f "Android/AndroidHash.json" ]; then | |
| if [ ! -f "Android/Flarial.apk" ] || [ ! -f "Android/AndroidHash.json" ]; then | |
| echo "Android APK/hash must be uploaded together" >&2 | |
| exit 1 | |
| fi | |
| actual_android_hash=$(sha256sum Android/Flarial.apk | awk '{ print $1 }') | |
| expected_android_hash=$(python3 -c 'import json; print(json.load(open("Android/AndroidHash.json"))["Android"])') | |
| if [ "${actual_android_hash}" != "${expected_android_hash}" ]; then | |
| echo "Android hash mismatch; refusing to publish corrupt CDN state" >&2 | |
| echo " APK: ${actual_android_hash}" >&2 | |
| echo " JSON: ${expected_android_hash}" >&2 | |
| exit 1 | |
| fi | |
| android_backup_dir=$(mktemp -d) | |
| android_have_backup=0 | |
| if aws s3 cp s3://${R2_BUCKET}/Android/Flarial.apk "${android_backup_dir}/Flarial.apk" \ | |
| --endpoint-url ${R2_ENDPOINT} && \ | |
| aws s3 cp s3://${R2_BUCKET}/Android/AndroidHash.json "${android_backup_dir}/AndroidHash.json" \ | |
| --endpoint-url ${R2_ENDPOINT}; then | |
| android_have_backup=1 | |
| else | |
| echo "No complete existing Android CDN pair to back up; continuing" | |
| fi | |
| android_publish_started=0 | |
| restore_android_pair() { | |
| rc=$? | |
| if [ "${rc}" -ne 0 ] && [ "${android_publish_started}" = "1" ] && [ "${android_have_backup}" = "1" ]; then | |
| echo "Android publish failed; restoring previous APK/hash pair" >&2 | |
| aws s3 cp "${android_backup_dir}/Flarial.apk" s3://${R2_BUCKET}/Android/Flarial.apk \ | |
| --endpoint-url ${R2_ENDPOINT} || true | |
| aws s3 cp "${android_backup_dir}/Flarial.apk" s3://${R2_BUCKET}/android/Flarial.apk \ | |
| --endpoint-url ${R2_ENDPOINT} || true | |
| aws s3 cp "${android_backup_dir}/AndroidHash.json" s3://${R2_BUCKET}/Android/AndroidHash.json \ | |
| --endpoint-url ${R2_ENDPOINT} || true | |
| aws s3 cp "${android_backup_dir}/AndroidHash.json" s3://${R2_BUCKET}/android/AndroidHash.json \ | |
| --endpoint-url ${R2_ENDPOINT} || true | |
| fi | |
| exit "${rc}" | |
| } | |
| trap restore_android_pair EXIT | |
| android_publish_started=1 | |
| aws s3 cp Android/Flarial.apk s3://${R2_BUCKET}/Android/Flarial.apk \ | |
| --endpoint-url ${R2_ENDPOINT} | |
| echo "✓ Uploaded Android/Flarial.apk" | |
| # Keep the legacy lowercase CDN path in sync for older clients/tools. | |
| aws s3 cp Android/Flarial.apk s3://${R2_BUCKET}/android/Flarial.apk \ | |
| --endpoint-url ${R2_ENDPOINT} | |
| echo "✓ Uploaded android/Flarial.apk" | |
| aws s3 cp Android/AndroidHash.json s3://${R2_BUCKET}/Android/AndroidHash.json \ | |
| --endpoint-url ${R2_ENDPOINT} | |
| echo "✓ Uploaded Android/AndroidHash.json" | |
| # Keep the legacy lowercase hash path in sync too. | |
| aws s3 cp Android/AndroidHash.json s3://${R2_BUCKET}/android/AndroidHash.json \ | |
| --endpoint-url ${R2_ENDPOINT} | |
| echo "✓ Uploaded android/AndroidHash.json" | |
| trap - EXIT | |
| fi | |
| # Fetch latest version of Pyroclastic for the launcher to use. | |
| curl -L "https://github.com/Aetopia/Pyroclastic/releases/latest/download/gamelaunchhelper.dll" -o "launcher/gamelaunchhelper.dll" | |
| if [ -f "launcher/gamelaunchhelper.dll" ]; then | |
| aws s3 cp launcher/gamelaunchhelper.dll s3://${R2_BUCKET}/launcher/gamelaunchhelper.dll \ | |
| --endpoint-url ${R2_ENDPOINT} | |
| echo "✓ Uploaded gamelaunchhelper.dll" | |
| fi | |
| - name: Verify uploads | |
| env: | |
| R2_ENDPOINT: https://${{ secrets.R2_ACCOUNT_ID }}.r2.cloudflarestorage.com | |
| R2_BUCKET: ${{ secrets.R2_BUCKET_NAME }} | |
| run: | | |
| echo "Files in R2 bucket:" | |
| aws s3 ls s3://${R2_BUCKET}/ --recursive --endpoint-url ${R2_ENDPOINT} |