Skip to content

Fix codesign: path filter excluded all files inside outer .app - #2680

Merged
austinywang merged 1 commit into
mainfrom
fix-codesign-path-filter
Apr 7, 2026
Merged

austinywang merged 1 commit into
mainfrom
fix-codesign-path-filter

Conversation

@austinywang

@austinywang austinywang commented Apr 7, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Fix: -not -path '*.app/*' in Pass 2's find matched the outer cmux NIGHTLY.app/ in every path, excluding ALL files — Autoupdate was never reached
  • Replace with find -prune on nested .app dirs, which correctly skips only Updater.app/ contents while finding standalone executables like Autoupdate

Root cause

find "$DIR" -type f -not -path '*.app/*' where $DIR is cmux NIGHTLY.app/Contents/Frameworks — every file's full path contains cmux NIGHTLY.app/, so the glob *.app/* matches everything and Pass 2 signs nothing.

Fix

-find "$DIR" -type f -not -path '*.app/*' -print0
+find "$DIR" \( -type d -name '*.app' -prune \) -o \( -type f -print0 \)

-prune on *.app directories prevents descending into nested app bundles (like Updater.app, already signed in Pass 1) without filtering by full path.

🤖 Generated with Claude Code


Note

Medium Risk
Touches the macOS release/nightly signing pipeline; a mistake could cause unsigned binaries or failed notarization, but the change is a small, targeted find filter correction.

Overview
Fixes Pass 2 of the macOS codesigning loops in nightly.yml and release.yml so standalone Mach-O files inside Contents/Frameworks/Contents/PlugIns are actually discovered and signed.

Replaces the previous find ... -not -path '*.app/*' filter (which could exclude everything under an outer .app) with a find -prune on nested *.app directories, skipping only embedded app bundles while still signing executables like Sparkle’s Autoupdate.

Reviewed by Cursor Bugbot for commit e2d5cff. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Fix codesign filter in GitHub workflows so Pass 2 signs standalone executables (e.g., Autoupdate) instead of skipping everything inside the outer .app. This restores proper signing for nightly and release builds.

  • Bug Fixes
    • Replaced -not -path '*.app/*' with find ... -prune to skip only nested .app bundles (e.g., Updater.app).
    • Ensures Mach-O files under Contents/Frameworks are found and signed in Pass 2.
    • Applied to .github/workflows/nightly.yml and .github/workflows/release.yml.

Written for commit e2d5cff. Summary will update on new commits.

Summary by CodeRabbit

Release Notes

  • Chores
    • Updated macOS app codesigning process in build workflows to use an improved file enumeration method.

Note: These are internal build system improvements with no user-facing changes.

The find filter `-not -path '*.app/*'` matched the OUTER app bundle
(cmux NIGHTLY.app/) in every file's full path, so Pass 2 found zero
files and Autoupdate was never signed.

Fix: use `-prune` on nested .app directories instead. This skips
Updater.app's contents (already signed in Pass 1) while still finding
standalone executables like Autoupdate.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@vercel

vercel Bot commented Apr 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Building Building Preview, Comment Apr 7, 2026 9:57am

@austinywang
austinywang merged commit 2afa083 into main Apr 7, 2026
11 of 12 checks passed
@coderabbitai

coderabbitai Bot commented Apr 7, 2026 •

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1b64c347-e820-48a7-ae7b-969dec56d5a3

📥 Commits

Reviewing files that changed from the base of the PR and between 2ff7478 and e2d5cff.

📒 Files selected for processing (2)
  • .github/workflows/nightly.yml
  • .github/workflows/release.yml

📝 Walkthrough

Walkthrough

Two GitHub Actions workflow files are updated to modify macOS app codesigning Pass 2 file enumeration. The change replaces -not -path '*.app/*' path exclusion with -type d -name '*.app' -prune directory pruning during nested app signing.

Changes

Cohort / File(s) Summary
macOS Codesigning File Enumeration
.github/workflows/nightly.yml, .github/workflows/release.yml
Pass 2 codesigning file discovery now prunes entire *.app directories using find -prune instead of excluding paths via -not -path, altering which nested paths are visited during file enumeration for signing.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Possibly related PRs

Poem

🐰 A rabbit hops through directories deep,
Pruning .app bundles from their sleep,
No more patterns to exclude and deny—
Just prune the branches as we pass by! ✨

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-codesign-path-filter

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps

greptile-apps Bot commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a broken find command in Pass 2 of the three-pass codesign sequence in both nightly.yml and release.yml. The original -not -path '*.app/*' filter inadvertently excluded every file because the search root ($DIR) is itself inside cmux NIGHTLY.app/Contents/Frameworks, so every file path already contained .app/ — meaning Sparkle's standalone Autoupdate binary was never being codesigned. The fix replaces the broken filter with a -prune expression that correctly skips descent into nested .app directories without matching on the full path; the three-pass ordering and the final --verify --deep --strict safety net are unchanged.

Confidence Score: 5/5

Safe to merge — the fix is correct and the only findings are P2 style suggestions

The root-cause analysis is accurate, the -prune expression is verified correct on BSD find (macOS), the three-pass signing order is sound, and --verify --deep --strict provides a safety net. Both P2 comments are non-blocking style suggestions that don't represent regressions.

No files require special attention; both nightly.yml and release.yml apply an identical, correct fix

Important Files Changed

Filename Overview
.github/workflows/nightly.yml Pass 2 find command fixed from broken -not -path '.app/' to correct -prune on .app dirs; codesign order and --verify --deep --strict safety net unchanged
.github/workflows/release.yml Identical Pass 2 find fix applied; same correct three-pass codesign structure with --verify --deep --strict verification

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["for DIR in PlugIns / Frameworks"] --> B
    B["Pass 1: Sign nested .app & .xpc bundles\nfind -depth -type d '*.app' or '*.xpc'\n(deepest-first, e.g. Updater.app)"] --> C
    C["Pass 2: Sign standalone Mach-O executables\nfind with -prune on .app dirs\n(e.g. Autoupdate — previously skipped!)"] --> D
    D["Pass 3: Sign .framework / .plugin / .appex\nfind -depth -type d\n(deepest-first, e.g. Sparkle.framework)"] --> E
    E{More DIRs?} -- Yes --> A
    E -- No --> F[Sign outer .app bundle]
    F --> G["codesign --verify --deep --strict\n(safety net catches any ordering error)"]
    G --> H[assert-passkey-entitlement.sh]
Loading

Reviews (1): Last reviewed commit: "Fix codesign: -path '*.app/*' excluded e..." | Re-trigger Greptile

/usr/bin/codesign --force --options runtime --timestamp --sign "$APPLE_SIGNING_IDENTITY" --entitlements "$EMBEDDED_ENTITLEMENTS" "$f"
fi
done < <(find "$DIR" -type f -not -path '*.app/*' -print0)
done < <(find "$DIR" \( -type d -name '*.app' -prune \) -o \( -type f -print0 \))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 .xpc contents not pruned in Pass 2

Pass 1 signs .xpc bundles as whole bundles (line 419), but Pass 2 only prunes .app directories. If any .xpc bundles sit directly inside Frameworks (not nested within Updater.app), Pass 2 would re-sign individual files inside them after Pass 1 already committed a bundle signature — invalidating it. This isn't a regression from the original code, and the --verify --deep --strict check on line 435 would catch any resulting invalidity. For correctness, consider also pruning .xpc dirs:

Suggested change
done < <(find "$DIR" \( -type d -name '*.app' -prune \) -o \( -type f -print0 \))
done < <(find "$DIR" \( -type d \( -name '*.app' -o -name '*.xpc' \) -prune \) -o \( -type f -print0 \))

/usr/bin/codesign --force --options runtime --timestamp --sign "$APPLE_SIGNING_IDENTITY" --entitlements "$EMBEDDED_ENTITLEMENTS" "$f"
fi
done < <(find "$DIR" -type f -not -path '*.app/*' -print0)
done < <(find "$DIR" \( -type d -name '*.app' -prune \) -o \( -type f -print0 \))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Same .xpc pruning gap as in nightly.yml

Same observation as nightly.yml line 426: Pass 2 prunes only .app directories, leaving .xpc bundle contents reachable. Consider adding .xpc to the prune list:

Suggested change
done < <(find "$DIR" \( -type d -name '*.app' -prune \) -o \( -type f -print0 \))
done < <(find "$DIR" \( -type d \( -name '*.app' -o -name '*.xpc' \) -prune \) -o \( -type f -print0 \))

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is kicking off a free cloud agent to fix this issue. This run is complimentary, but you can enable autofix for all future PRs in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e2d5cff. Configure here.

/usr/bin/codesign --force --options runtime --timestamp --sign "$APPLE_SIGNING_IDENTITY" --entitlements "$EMBEDDED_ENTITLEMENTS" "$f"
fi
done < <(find "$DIR" -type f -not -path '*.app/*' -print0)
done < <(find "$DIR" \( -type d -name '*.app' -prune \) -o \( -type f -print0 \))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pass 2 prune misses .xpc bundles signed in Pass 1

High Severity

Pass 1 signs both *.app and *.xpc bundles, but the new find in Pass 2 only prunes *.app directories. Since Sparkle 2.x bundles Installer.xpc and Downloader.xpc inside the framework (each containing a Mach-O executable), Pass 2 will descend into those .xpc bundles and re-sign their internal executables individually. This invalidates the .xpc bundle signatures created by Pass 1, and Pass 3 (which signs *.framework) does not re-sign nested .xpc bundles — causing codesign --verify --deep --strict to fail. The -prune clause needs to include -name '*.xpc' to match what Pass 1 handles.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e2d5cff. Configure here.

This branch was successfully deployed

1 active deployment
Preview — e2d5cff1 Deployed Apr 7, 2026 by vercel[bot]
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