Skip to content

Fail the macOS build if any bundled library links outside the bundle#10135

Open
dpage wants to merge 1 commit into
pgadmin-org:masterfrom
dpage:macos-verify-bundle-linkage
Open

Fail the macOS build if any bundled library links outside the bundle#10135
dpage wants to merge 1 commit into
pgadmin-org:masterfrom
dpage:macos-verify-bundle-linkage

Conversation

@dpage

@dpage dpage commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Belt-and-braces guard for the macOS appbundle build.

Background

9.16 failed to start on Intel Macs (#10123). The cryptography package no longer publishes a prebuilt wheel for Intel macOS, so pip compiled it from source on the builder, and its openssl-sys build linked the build host's Homebrew OpenSSL (/usr/local/opt/openssl@3/...) into _rust.abi3.so rather than the OpenSSL we ship inside the bundle. _fixup_imports deliberately skips _rust.abi3.so, so that dangling reference shipped unnoticed and the app died on startup on every machine that lacked (or could not validate) that external dylib.

The actual fix lives in the build configuration (force cryptography to link the bundled OpenSSL). This PR is the separate safety net so the same class of problem cannot silently reach a release again.

Change

Adds a _verify_bundle_linkage step, run after the bundle is fully assembled and relocated and before code-signing, that walks every .so/.dylib in the bundle and fails the build if any install-name points at a build-host prefix (/usr/local, /opt/homebrew, /opt/local, or $SLAVE_HOME on the CI builders). Legitimate OS libraries (/usr/lib, /System) and bundle-relative references (@loader_path/@rpath/@executable_path) pass untouched.

A correct, self-contained bundle passes silently; a left-behind external reference turns into a hard build failure on the builder instead of a runtime failure on a user's Mac.

Testing

macOS build scripts only; no runtime code paths affected. bash -n clean on both files, and the detection pipeline was checked against the real otool -L output from the #10123 reports (flags the two openssl@3 lines, ignores the @rpath self-id and the /usr/lib system libs).

Summary by CodeRabbit

  • Bug Fixes
    • Added a new validation step during macOS app packaging to catch unsupported library references before release.
    • Build now stops with a clear error if the finished app bundle still points to libraries from common host install locations.
    • This helps prevent shipping packages that depend on local build-machine files and improves bundle reliability.

The macOS appbundle is meant to be self-contained: every binary should
reference only OS libraries (/usr/lib, /System) or bundle-relative paths
(@loader_path/@rpath/@executable_path). An absolute install-name pointing
at a build-host location such as Homebrew's /usr/local/opt/openssl@3 or the
Jenkins workspace will resolve on the build machine but is absent (or, for a
differently-signed dylib, rejected by hardened-runtime library validation)
on an end user's Mac, so the app dies on startup.

This is exactly how 9.16 broke on Intel (issue pgadmin-org#10123): with no Intel
cryptography wheel published upstream, pip compiled it from source and its
openssl-sys build linked the build host's Homebrew OpenSSL into
_rust.abi3.so, which _fixup_imports deliberately skips, so the dangling
reference shipped unnoticed.

Add a _verify_bundle_linkage step that runs after the bundle is fully
assembled and relocated, and before code-signing, walking every .so/.dylib
and failing the build if anything links to a build-host prefix. This turns
the whole class of problem from a silent runtime failure on user machines
into a hard build failure on the builder.
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds a _verify_bundle_linkage function to pkg/mac/build-functions.sh that scans all .so/.dylib files in the app bundle using otool -L, checking for install-names referencing forbidden host prefixes (/usr/local, /opt/homebrew, /opt/local, SLAVE_HOME). If any are found, it prints the offending paths and exits with code 1. The function is invoked in pkg/mac/build.sh between _prune_dangling_symlinks and _generate_sbom.

Changes

Bundle Linkage Verification

Layer / File(s) Summary
_verify_bundle_linkage implementation and build wiring
pkg/mac/build-functions.sh, pkg/mac/build.sh
New function scans Mach-O dependencies via otool -L for disallowed host library prefixes and aborts on any match; wired into the build sequence after symlink pruning and before SBOM generation.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • pgadmin-org/pgadmin4#10108: Introduced _prune_dangling_symlinks in the same build pipeline segment that this PR directly extends with the new verification step.
🚥 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 accurately summarizes the new macOS bundle linkage verification and build failure behavior.
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.
✨ 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.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/mac/build-functions.sh`:
- Around line 498-508: The Mach-O dependency scan in the bundle check is too
narrow because the loop only inspects files matched by the .so and .dylib
suffixes, so shipped executables and framework binaries can be missed. Update
the file discovery in the build-functions.sh scan to target all Mach-O files
under BUNDLE_DIR, then keep the existing otool -L, grep, and error reporting
logic in the same loop so any host-linked binary is caught regardless of
extension.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e48e57f7-c8e9-440b-bd04-fe6b4372a21a

📥 Commits

Reviewing files that changed from the base of the PR and between dfc4ef3 and 6eea4e1.

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

Comment on lines +498 to +508
while IFS= read -r f; do
# otool prints the filename header then one line per dependency; drop
# the header, take the install-name column, and keep only build-host
# paths. grep exits non-zero (no match) for a clean binary, which is
# the common case, so fall through to the next file.
deps=$(otool -L "${f}" 2>/dev/null | tail -n +2 | awk '{print $1}' | \
grep -E "^(${PREFIXES})") || continue
echo "ERROR: ${f} links against build-host libraries:" >&2
echo "${deps}" | sed 's/^/ /' >&2
found="yes"
done < <(find "${BUNDLE_DIR}" \( -name '*.so' -o -name '*.dylib' \) -type f)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm the verifier is suffix-only and that the macOS packaging logic includes framework payloads.
sed -n '460,520p' pkg/mac/build-functions.sh
rg -n -C2 'Python\.framework|\.framework|Contents/MacOS' pkg/mac

Repository: pgadmin-org/pgadmin4

Length of output: 8552


🏁 Script executed:

#!/bin/bash
sed -n '460,520p' pkg/mac/build-functions.sh
sed -n '160,220p' pkg/mac/build-functions.sh
sed -n '360,450p' pkg/mac/build-functions.sh

Repository: pgadmin-org/pgadmin4

Length of output: 10457


🏁 Script executed:

#!/bin/bash
# List Mach-O files in the shipped bundle locations that are not .so/.dylib
# and inspect whether the packaging code already rewrites their imports.
rg -n -C2 'find .*Mach-O 64-bit|otool -L|_fixup_imports|_verify_bundle_linkage' pkg/mac/build-functions.sh

Repository: pgadmin-org/pgadmin4

Length of output: 2201


Scan all Mach-O binaries, not just .so/.dylib files.

This loop misses shipped executables and framework binaries (for example Contents/MacOS/* and Python.framework payloads), so a bundle can still contain host-linked Mach-O files without tripping this check. Broaden the scan to all Mach-O files, not just suffix-matched libraries.

🧰 Tools
🪛 Shellcheck (0.11.0)

[style] 506-506: See if you can use ${variable//search/replace} instead.

(SC2001)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/mac/build-functions.sh` around lines 498 - 508, The Mach-O dependency
scan in the bundle check is too narrow because the loop only inspects files
matched by the .so and .dylib suffixes, so shipped executables and framework
binaries can be missed. Update the file discovery in the build-functions.sh scan
to target all Mach-O files under BUNDLE_DIR, then keep the existing otool -L,
grep, and error reporting logic in the same loop so any host-linked binary is
caught regardless of extension.

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