Skip to content

fix(mac): prune dangling symlinks before codesign so Gatekeeper accepts the bundle#10108

Merged
asheshv merged 1 commit into
pgadmin-org:masterfrom
dpage:fix-macos-gatekeeper-symlinks
Jun 18, 2026
Merged

fix(mac): prune dangling symlinks before codesign so Gatekeeper accepts the bundle#10108
asheshv merged 1 commit into
pgadmin-org:masterfrom
dpage:fix-macos-gatekeeper-symlinks

Conversation

@dpage

@dpage dpage commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Problem

A signed, notarised and stapled pgAdmin 4.app is rejected by Gatekeeper even though signing and notarisation are completely valid:

$ spctl -a -vvv -t install "pgAdmin 4.app"
pgAdmin 4.app: rejected (invalid destination for symbolic link in bundle)

Gatekeeper walks every symlink in the bundle and rejects the whole app if any link does not resolve to a real file inside it. Notarisation does not catch this, so a broken link slips through stapling and only surfaces as a Gatekeeper failure on the end user's machine.

The embedded Python.framework (pulled in via relocatable-python) ships three such dangling links:

Symlink (under Versions/3.13) Why it dangles
bin/python3-intel64 arm64-only build; the Intel launcher target is removed by _strip_architecture, leaving the link
Frameworks/Tcl.framework/PrivateHeaders points at Versions/Current/PrivateHeaders, which does not exist
Frameworks/Tk.framework/PrivateHeaders same as Tcl

Fix

Add a _prune_dangling_symlinks step to the macOS build pipeline that removes every dangling symlink in the bundle, rather than hunting individual offenders by name, so a future stray link cannot reintroduce the problem. It runs after _strip_architecture (which orphans the intel link by deleting its target) and before the codesign steps, and it then re-scans and fails the build if anything still dangles, so this can never silently slip past notarisation again.

Verification

  • bash -n passes on both scripts.
  • The find -type l ! -exec test -e {} \; prune idiom was exercised on a scratch tree: it deletes dangling links, preserves valid symlinks and real files, and the post-check guard passes.

Full end-to-end confirmation (spctl -a accepting a freshly signed/notarised/stapled build) requires the codesign credentials and a real Mac, and should be done as part of the next macOS package build.

Summary by CodeRabbit

  • Chores
    • Enhanced the macOS build pipeline with automated detection and removal of invalid symbolic links during the pre-signing phase. The build process now includes protective checks that prevent completion if problematic symbolic links remain after cleanup, ensuring distributed applications meet system security requirements and successfully pass Gatekeeper validation.

…ts the bundle

A signed, notarised and stapled pgAdmin 4.app was rejected by Gatekeeper
with "invalid destination for symbolic link in bundle". Gatekeeper walks
every symlink in the bundle and rejects the whole app if any link does
not resolve to a real file inside it; notarisation does not catch this, so
a broken link slips through stapling and only surfaces as a Gatekeeper
failure on the end user's machine.

The embedded Python.framework ships such links: an arm64-only build still
carries a bin/python3-intel64 launcher symlink (whose target
_strip_architecture deletes when it removes the foreign-arch files), and
the bundled Tcl/Tk frameworks carry PrivateHeaders links pointing at a
Versions/Current that has none.

Add a _prune_dangling_symlinks step that removes every dangling symlink in
the bundle after architecture stripping and before signing, then fails the
build if any remain, so this cannot slip past notarisation again.
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 213edafa-e60c-478a-9881-f076bd8332d5

📥 Commits

Reviewing files that changed from the base of the PR and between 3660d19 and 492d208.

📒 Files selected for processing (2)
  • pkg/mac/build-functions.sh
  • pkg/mac/build.sh

Walkthrough

A new _prune_dangling_symlinks function is added to pkg/mac/build-functions.sh. It locates and removes dangling symlinks inside BUNDLE_DIR, then hard-fails the build if any remain. pkg/mac/build.sh calls this function after architecture stripping and before SBOM generation and code signing.

Changes

macOS Build — Dangling Symlink Pruning

Layer / File(s) Summary
Symlink pruning function and build pipeline wiring
pkg/mac/build-functions.sh, pkg/mac/build.sh
_prune_dangling_symlinks is defined to find and delete dangling symlinks under BUNDLE_DIR, failing the build if any remain after deletion. build.sh inserts a call to this function between architecture stripping and _generate_sbom/signing steps.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: introducing symlink pruning to fix Gatekeeper rejection issues in macOS builds.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@asheshv asheshv merged commit 888a053 into pgadmin-org:master Jun 18, 2026
33 of 34 checks passed
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.

2 participants