@@ -435,38 +435,101 @@ gh release create "v${VERSION}" \
435435
436436echo -e " ${GREEN} GitHub release created${NC} "
437437
438- # CRITICAL: Verify uploaded ZIP and re-sign if needed
439- echo " Verifying uploaded ZIP..."
440- sleep 3 # Give GitHub time to process
438+ # CRITICAL: Verify uploaded ZIP and re-sign with the ACTUAL GitHub file
439+ # This ensures Sparkle signature always matches what users download
440+ echo " Waiting for GitHub to process upload..."
441+ sleep 10 # Give GitHub more time to process
442+
443+ GITHUB_ZIP_URL=" https://github.com/${REPO} /releases/download/v${VERSION} /${APP_NAME} -v${VERSION} .zip"
444+ GITHUB_ZIP_PATH=" /tmp/github-uploaded-${VERSION} .zip"
445+
446+ # Download with retries and verification
447+ MAX_RETRIES=5
448+ RETRY_DELAY=5
449+ for i in $( seq 1 $MAX_RETRIES ) ; do
450+ echo " Downloading GitHub ZIP (attempt $i /$MAX_RETRIES )..."
451+ curl -L -s -o " $GITHUB_ZIP_PATH " " $GITHUB_ZIP_URL "
452+
453+ # Verify it's actually a ZIP file (not HTML error page)
454+ if file " $GITHUB_ZIP_PATH " | grep -q " Zip archive" ; then
455+ echo -e " ${GREEN} Downloaded valid ZIP file${NC} "
456+ break
457+ else
458+ echo -e " ${YELLOW} Download failed or not a ZIP file, retrying in ${RETRY_DELAY} s...${NC} "
459+ rm -f " $GITHUB_ZIP_PATH "
460+ sleep $RETRY_DELAY
461+ RETRY_DELAY=$(( RETRY_DELAY * 2 ))
462+ fi
463+
464+ if [ $i -eq $MAX_RETRIES ]; then
465+ echo -e " ${RED} ERROR: Failed to download valid ZIP from GitHub after $MAX_RETRIES attempts${NC} "
466+ echo " Please verify manually and update appcast.xml"
467+ exit 1
468+ fi
469+ done
470+
471+ # ALWAYS re-sign with the actual GitHub file to ensure signature matches
472+ # This is the ONLY way to guarantee the signature is correct
473+ echo " Signing the actual GitHub ZIP file..."
474+ GITHUB_FILE_SIZE=$( stat -f%z " $GITHUB_ZIP_PATH " )
475+
476+ echo " $SPARKLE_PRIVATE_KEY " > /tmp/sparkle_key_verify
477+ GITHUB_SIGNATURE_OUTPUT=$( " $SPARKLE_SIGN " --ed-key-file /tmp/sparkle_key_verify " $GITHUB_ZIP_PATH " )
478+ rm -f /tmp/sparkle_key_verify
479+
480+ GITHUB_ED_SIGNATURE=$( echo " $GITHUB_SIGNATURE_OUTPUT " | grep -o ' sparkle:edSignature="[^"]*"' | cut -d' "' -f2)
481+
482+ if [ -z " $GITHUB_ED_SIGNATURE " ]; then
483+ echo -e " ${RED} ERROR: Failed to generate signature for GitHub ZIP${NC} "
484+ exit 1
485+ fi
486+
487+ echo " GitHub ZIP size: $GITHUB_FILE_SIZE bytes"
488+ echo " GitHub ZIP signature: ${GITHUB_ED_SIGNATURE: 0: 30} ..."
489+
490+ # Update appcast.xml with the CORRECT signature for the GitHub file
491+ # Use Python for reliable XML-safe replacement
492+ python3 << PYEOF
493+ import re
494+
495+ version = "${VERSION} "
496+ new_signature = "${GITHUB_ED_SIGNATURE} "
497+ new_size = "${GITHUB_FILE_SIZE} "
441498
442- curl -L -s -o " /tmp/github-uploaded- ${VERSION} .zip " \
443- " https://github.com/ ${REPO} /releases/download/v ${VERSION} / ${APP_NAME} -v ${VERSION} .zip "
499+ with open('appcast.xml', 'r') as f:
500+ content = f.read()
444501
445- LOCAL_SHA=$( shasum -a 256 " build/${APP_NAME} -v${VERSION} .zip" | cut -d' ' -f1)
446- GITHUB_SHA=$( shasum -a 256 " /tmp/github-uploaded-${VERSION} .zip" | cut -d' ' -f1)
502+ # Find and update the enclosure for this version
503+ # Match the enclosure line for this specific version
504+ pattern = r'(download/v' + re.escape(version) + r'/[^"]+\.zip"\s+sparkle:edSignature=")[^"]*("\s+length=")[^"]*(")'
505+ replacement = r'\g<1>' + new_signature + r'\g<2>' + new_size + r'\g<3>'
447506
448- if [ " $LOCAL_SHA " != " $GITHUB_SHA " ]; then
449- echo -e " ${YELLOW} Warning: GitHub ZIP differs from local! Re-signing with GitHub version...${NC} "
507+ new_content, count = re.subn(pattern, replacement, content)
450508
451- # Re-sign the GitHub version
452- echo " $SPARKLE_PRIVATE_KEY " > /tmp/sparkle_key_verify
453- GITHUB_SIGNATURE_OUTPUT=$( " $SPARKLE_SIGN " --ed-key-file /tmp/sparkle_key_verify " /tmp/github-uploaded-${VERSION} .zip" )
454- rm -f /tmp/sparkle_key_verify
509+ if count == 0:
510+ print(f"ERROR: Could not find enclosure for version {version} in appcast.xml")
511+ exit(1)
455512
456- GITHUB_ED_SIGNATURE= $( echo " $GITHUB_SIGNATURE_OUTPUT " | grep -o ' sparkle:edSignature="[^"]*" ' | cut -d ' " ' -f2 )
457- GITHUB_FILE_SIZE= $( stat -f%z " /tmp/github-uploaded- ${VERSION} .zip " )
513+ with open('appcast.xml', 'w') as f:
514+ f.write(new_content )
458515
459- # Update appcast.xml with correct signature
460- sed -i ' ' " s|sparkle:edSignature=\" ${ED_SIGNATURE} \" |sparkle:edSignature=\" ${GITHUB_ED_SIGNATURE} \" |g" appcast.xml
461- sed -i ' ' " s|length=\" ${FILE_SIZE} \" |length=\" ${GITHUB_FILE_SIZE} \" |g" appcast.xml
516+ print(f"Updated appcast.xml: signature and length for v{version}")
517+ PYEOF
462518
463- ED_SIGNATURE=" $GITHUB_ED_SIGNATURE "
464- FILE_SIZE=" $GITHUB_FILE_SIZE "
519+ # Verify the update was successful
520+ if ! grep -q " sparkle:edSignature=\" ${GITHUB_ED_SIGNATURE} \" " appcast.xml; then
521+ echo -e " ${RED} ERROR: Failed to update appcast.xml with new signature${NC} "
522+ exit 1
523+ fi
465524
466- echo -e " ${GREEN} Appcast updated with correct GitHub signature${NC} "
525+ if ! grep -q " length=\" ${GITHUB_FILE_SIZE} \" " appcast.xml; then
526+ echo -e " ${RED} ERROR: Failed to update appcast.xml with new file size${NC} "
527+ exit 1
467528fi
468529
469- rm -f " /tmp/github-uploaded-${VERSION} .zip"
530+ echo -e " ${GREEN} Appcast verified: signature and size match GitHub ZIP${NC} "
531+
532+ rm -f " $GITHUB_ZIP_PATH "
470533
471534# Git commit and push
472535git add -A
0 commit comments