Skip to content

fix(ci): Use ditto instead of zip for Sparkle update archive#111

Merged
eyelock merged 1 commit into
mainfrom
fix/sparkle-zip-ditto
Apr 12, 2026
Merged

fix(ci): Use ditto instead of zip for Sparkle update archive#111
eyelock merged 1 commit into
mainfrom
fix/sparkle-zip-ditto

Conversation

@eyelock
Copy link
Copy Markdown
Owner

@eyelock eyelock commented Apr 12, 2026

Summary

  • Replace zip -r with ditto -c -k --keepParent for creating the Sparkle update ZIP archive in the release workflow
  • Add sparkle-updater skill documenting the full update pipeline, known pitfalls, and verification checklist

Root Cause

zip -r dereferences symlinks in Sparkle.framework's versioned directory structure (Versions/Current -> B, top-level items → Versions/Current/*). This creates a ZIP with:

  • 3x duplicate copies of every framework file
  • No symlinks (all converted to regular files/directories)

When Sparkle extracts this ZIP on the user's machine, codesign --verify fails with "bundle format is ambiguous" and the update is rejected.

Proof

Downloaded TermQ-0.7.0-beta.7.zip, extracted, ran codesign --verify --deep --strict:

TermQ.app: bundle format is ambiguous (could be app or framework)
In subcomponent: .../Sparkle.framework

Local comparison:

  • zip -r output: 2.8MB, no symlinks, 3x file copies
  • ditto output: 940KB, symlinks preserved

Why Previous Fixes Didn't Help

Fix What it addressed This bug?
PR #109 — EdDSA signing Missing signatures in appcast No
Commit 67e80b7 — curl -L GitHub redirect for .sig fetch No
PR #108 — XPC signing --deep breaking XPC trust chain No

All were real bugs, but none touched the ZIP creation step where the actual failure occurs.

Test plan

  • CI passes on this branch
  • After merge: tag v0.7.0-beta.8, monitor release workflow
  • Download the beta.8 ZIP and verify:
    • ls -la shows symlinks in Sparkle.framework/
    • codesign --verify --deep --strict passes on extracted app

🤖 Generated with Claude Code

zip -r dereferences symlinks in Sparkle.framework's versioned directory
structure (Versions/Current -> B, top-level -> Versions/Current/*),
storing 3x duplicate files. When Sparkle extracts this ZIP, codesign
--verify fails with "bundle format is ambiguous" and the update is
rejected. ditto preserves symlinks and macOS extended attributes.

Also adds sparkle-updater skill documenting the full update pipeline,
known pitfalls, and verification checklist.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@eyelock eyelock merged commit 8be83a1 into main Apr 12, 2026
7 checks passed
@eyelock eyelock deleted the fix/sparkle-zip-ditto branch April 12, 2026 13:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant