Skip to content

fix(brew): relocate text in skip-relocation bottles - #11665

Merged
jdx merged 3 commits into
mainfrom
agent/fix-brew-skip-relocation-text
Aug 3, 2026
Merged

fix(brew): relocate text in skip-relocation bottles#11665
jdx merged 3 commits into
mainfrom
agent/fix-brew-skip-relocation-text

Conversation

@jdx

@jdx jdx commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Summary

  • always run text placeholder relocation for Homebrew bottles
  • treat :any_skip_relocation as skipping only binary linkage relocation
  • add regression coverage proving text files are changed while Mach-O content remains untouched

Root cause

The brew pour path skipped relocate_keg entirely for macOS bottles tagged :any_skip_relocation. Homebrew uses that tag only to suppress dynamic linkage relocation; it still replaces text placeholders such as @@HOMEBREW_PREFIX@@ and @@HOMEBREW_CELLAR@@.

This left scripts and configuration files containing unresolved placeholders and produced an empty changed_files receipt entry.

Reported in #11656.

Validation

  • cargo test system::packages::brew::relocate::tests (8 passed)
  • mise run format
  • git diff --check

AI-assisted — Tool: Codex; model: unavailable/unavailable; version: unavailable.


Note

Medium Risk
Touches the Homebrew bottle pour/relocation path used on every install; behavior change is intentional and covered by a regression test, but wrong linkage skipping could still break binaries on edge-case bottles.

Overview
Fixes :any_skip_relocation bottles leaving @@HOMEBREW_*@@ placeholders in scripts and config by always running relocation during pour instead of skipping it entirely on macOS (and on Linux when the bottle was built by Homebrew ≥ 5.1.15).

relocate_keg now takes a skip_linkage flag: when set, Mach-O, ELF, and other binary linkage paths are left unchanged, but text files and shebang-only executables still get placeholder replacement—matching Homebrew’s meaning of :any_skip_relocation. The pour path always invokes relocation and passes skip_linkage from the bottle cellar tag (with the existing Linux Homebrew version gate for mis-tagged older bottles).

Adds test_skip_linkage_still_relocates_text_files to assert text is rewritten, Mach-O bytes and permissions stay untouched, and receipts list only changed text files.

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

Summary by CodeRabbit

  • Bug Fixes
    • Improved bottle relocation to preserve text placeholder replacements while safely skipping binary linkage updates when required.
    • Prevented unintended changes to Mach-O, ELF, and other binary files during relocation.
    • Continued relocating text files and shebang-based executables as expected.
    • Updated relocation results to report only files that were actually modified.
    • Preserved file permissions during relocation and improved compatibility across supported Homebrew and Linux environments.

@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 OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit fe51617. Configure here.

Comment thread src/system/packages/brew/relocate.rs Outdated
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Bottle pouring now always calls keg relocation. The relocation API accepts skip_linkage to skip binary linkage changes while preserving text and shebang replacement. Tests cover text relocation, unchanged Mach-O contents, permissions, and relocation reporting.

Changes

Brew keg relocation

Layer / File(s) Summary
Relocation engine behavior
src/system/packages/brew/relocate.rs
relocate_keg accepts skip_linkage and delegates to a shared implementation. Mach-O, ELF, and opaque binary files are skipped when enabled.
Pour integration and validation
src/system/packages/brew/pour.rs, src/system/packages/brew/relocate.rs
Bottle pouring always invokes relocation. Tests confirm that text files change, Mach-O contents and read-only permissions remain unchanged, and skipped files are absent from the changed-file report.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • jdx/mise#11632: Both changes modify text, shebang, and binary handling during keg relocation.

Poem

A rabbit checks the brew keg twice,
Text paths move while binaries stay nice.
Mach-O keeps its bytes in place,
Shebangs shift with careful grace.
Changed files report the trace.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the Homebrew fix for relocating text in skip-relocation bottles.

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.

@greptile-apps

greptile-apps Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR changes :any_skip_relocation handling so text placeholders are still replaced while binary linkage relocation remains disabled.

  • Always invokes keg relocation from the bottle pour path.
  • Adds a skip_linkage mode that leaves Mach-O, ELF, and opaque binary content untouched.
  • Adds regression coverage for text replacement, binary preservation, permissions, and relocation reporting.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
src/system/packages/brew/pour.rs Replaces the complete relocation bypass with linkage-only gating while retaining the Linux Homebrew-version exception.
src/system/packages/brew/relocate.rs Adds linkage-skipping classification and regression coverage while preserving text and shebang placeholder replacement.

Reviews (3): Last reviewed commit: "fix(brew): remove redundant relocation b..." | Re-trigger Greptile

@coderabbitai coderabbitai Bot left a comment

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/system/packages/brew/relocate.rs (1)

227-240: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Restore file permissions before skipping binary relocation.

Lines 227-234 add owner write permission before Line 238 evaluates skip_linkage. The continue bypasses the restoration at Line 283. A read-only skipped binary remains owner-writable after pouring.

Evaluate skip_linkage before changing permissions, or restore perms before the continue.

Proposed fix
-        let perms = path.metadata()?.permissions();
-        // bottle files are often read-only; lift that while we patch
-        let mut writable = perms.clone();
-        std::os::unix::fs::PermissionsExt::set_mode(
-            &mut writable,
-            std::os::unix::fs::PermissionsExt::mode(&perms) | 0o200,
-        );
-        std::fs::set_permissions(path, writable)?;
         let macho = is_macho(&content);
         let elf = cfg!(target_os = "linux") && super::elf::is_elf(&content);
         let shebang_end = text_executable_shebang_end(&content);
         if skip_linkage && (macho || elf || (content.contains(&0) && shebang_end.is_none())) {
             continue;
         }
+        let perms = path.metadata()?.permissions();
+        let mut writable = perms.clone();
+        std::os::unix::fs::PermissionsExt::set_mode(
+            &mut writable,
+            std::os::unix::fs::PermissionsExt::mode(&perms) | 0o200,
+        );
+        std::fs::set_permissions(path, writable)?;
🤖 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 `@src/system/packages/brew/relocate.rs` around lines 227 - 240, Restore the
original permissions for skipped binaries in the relocation flow before
continuing. Update the skip_linkage branch in the function containing the perms
and macho/elf checks so files identified for skipping do not retain the
owner-write bit added before patching, while preserving the existing relocation
behavior for files that are processed.
🤖 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.

Outside diff comments:
In `@src/system/packages/brew/relocate.rs`:
- Around line 227-240: Restore the original permissions for skipped binaries in
the relocation flow before continuing. Update the skip_linkage branch in the
function containing the perms and macho/elf checks so files identified for
skipping do not retain the owner-write bit added before patching, while
preserving the existing relocation behavior for files that are processed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 1117b696-249c-458d-8984-01063d8cb15c

📥 Commits

Reviewing files that changed from the base of the PR and between 18f68b0 and fe51617.

📒 Files selected for processing (2)
  • src/system/packages/brew/pour.rs
  • src/system/packages/brew/relocate.rs

@jdx
jdx enabled auto-merge (squash) August 3, 2026 16:24
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

Instruction counts

benchmark trend instructions Δ wall (min) Δ
env ▁▅▇█▆ 80,223,085 → 80,205,007 -0.02% 17.61 → 17.83ms +1.26%
hook-env ▁▆▄██ 82,346,637 → 82,345,360 -0.00% 18.33 → 18.56ms +1.26%
ls ▇▂▁█▄ 73,189,665 → 73,171,384 -0.02% 16.37 → 16.76ms +2.42%
registry ▇██▄▁ 49,107,725 → 49,065,130 -0.09% 11.75 → 11.78ms +0.22%
startup ███▂▁ 15,758,094 → 15,752,642 -0.03% 8.80 → 8.77ms -0.42%

No instruction-count regression above 1%.

Only instruction counts gate. Wall clock is shown for context — on identical hardware it moves 4-20% run to run.

Measured by tak — instruction-counted CLI benchmarks, stored in this repository's git notes.

08427d30b574 vs 0c809d49da6a · measured on the runner, not pushed to the history.

@jdx
jdx merged commit 70fb487 into main Aug 3, 2026
30 checks passed
@jdx
jdx deleted the agent/fix-brew-skip-relocation-text branch August 3, 2026 16:50
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