Skip to content

Resolve cask system languages before artifact installation - #23612

Merged
MikeMcQuaid merged 7 commits into
Homebrew:mainfrom
dot-agi:cask-eager-languages
Aug 22, 2026
Merged

Resolve cask system languages before artifact installation#23612
MikeMcQuaid merged 7 commits into
Homebrew:mainfrom
dot-agi:cask-eager-languages

Conversation

@dot-agi

@dot-agi dot-agi commented Aug 22, 2026

Copy link
Copy Markdown
Contributor
  • Have you followed our Contributing guidelines?
  • Have you checked for other open Pull Requests for the same change?
  • Have you explained what your changes do? Performance claims (e.g. "this is faster") must include Hyperfine benchmarks.
  • Have you explained why you'd like these changes included, not just what they do?
  • For bug fixes, have you given step-by-step brew commands to reproduce the bug?
  • Have you written new tests (excluding integration tests)? Here's an example.
  • Have you successfully run brew lgtm (style, typechecking and tests) locally?

  • I did not use AI/LLM to create this PR, or I disclosed the tool/model below and reviewed its output; I did not attribute commits to AI and will answer maintainer questions and review comments myself without AI/LLM.

AI disclosure: this PR was produced with Claude Code (model: Claude Fable 5), in the same session as #23606 and #23607. It is the follow-up requested by @MikeMcQuaid in #23606 (comment). Verified locally as described below.


Follow-up to #23607 (analysis in #23606). Preventive hardening, not a standalone bug fix.

What this does

  • Cask::Config's languages default is a LazyObject. Nothing forces it until save_config_file serializes the config at the very end of artifact installation — the JSON generator's respond_to?(:to_json) probe forces it as a side effect.
  • That late resolution forks the whole brew process (Utils.popen running defaults read -g AppleLanguages) after the installer has already run in-process Security.framework signing checks. That is the exact fork that crashed in Cask upgrade segfault: Ruby GC releases Security.framework objects on the child side of fork in Utils.popen #23606.
  • This PR memoizes MacOS.languages in Cask::Installer#prelude, via a new extend/os/mac/cask/installer.rb. prelude is the run-once early setup shared by cask operations: #install and #fetch call it first, and Cask::Upgrade calls it explicitly before scanning the existing apps' signing identities. So the fork happens before any download, artifact or signing work, and the later lazy resolution becomes a memo lookup.
  • prelude is not run by uninstalls, and never when no casks are being processed, so nothing changes for formula-only or cask-less commands.

Why

Reproduction

# The underlying crash and full analysis: #23606 (brew update && brew upgrade --greedy
# with a quarantined cask). This change is preventive; there is no new bug to reproduce.

Verification

  • brew style, brew typecheck and the changed spec suites (cask/installer, cask/quarantine) all pass locally.
  • New specs assert the invariant directly: MacOS.languages resolves first in #prelude, and before any artifact install_phase in a full #install run.
  • Negative-tested: with the MacOS.languages call commented out, the prelude spec fails with expected: :languages / got: :prelude_requirements; restored, everything passes.

`Cask::Config`'s `languages` default is a `LazyObject` that is only
forced while serialising the config at the end of artifact
installation. That late resolution forks the whole process
(`Utils.popen` running `defaults read`) after the installer has
already used fork-hostile frameworks such as Security.framework for
signing checks.

Memoise `MacOS.languages` at the start of
`Cask::Installer#install_artifacts`, which both installs and upgrades
go through, so the fork happens before any artifact or signing work
and the later lazy resolution becomes a memo lookup.

Follow-up to Homebrew#23607, requested in
Homebrew#23606 (comment).

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0e13641522

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Library/Homebrew/extend/os/mac/cask/installer.rb
Cask upgrades call `Quarantine.signing_identity` for existing apps
before `Cask::Installer#install_artifacts` runs, so on the first
upgrade the languages fork could still happen after Security.framework
work. Prime `MacOS.languages` before the first Security call in
`signing_identity` as well; memoisation makes repeat calls free.

Addresses Codex review feedback on the pull request.

Copilot AI 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.

Pull request overview

Primes MacOS.languages at the start of Cask::Installer#install_artifacts on macOS so the defaults read -g AppleLanguages fork happens before any artifact/signing work, avoiding late-process forks during config serialization.

Changes:

  • Add a macOS-specific Cask::Installer#install_artifacts prepend that eagerly resolves MacOS.languages.
  • Load the new macOS extension from the OS cask installer extension loader.
  • Add a spec asserting languages resolution happens before artifact install_phase.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

File Description
Library/Homebrew/test/cask/installer_spec.rb Adds an ordering spec for resolving system languages before artifact installation.
Library/Homebrew/extend/os/mac/cask/installer.rb Prepends Cask::Installer#install_artifacts on macOS to call MacOS.languages before artifact work.
Library/Homebrew/extend/os/cask/installer.rb Requires the new macOS installer extension when running on macOS.

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread Library/Homebrew/test/cask/installer_spec.rb Outdated
Comment thread Library/Homebrew/extend/os/mac/cask/installer.rb Outdated
- Assert the ordering invariant (languages first, artifact/Security
  call present) instead of an exact call sequence, and return a
  representative value from the stubbed `MacOS.languages`.
- Use American English spelling in the new installer comment.

@MikeMcQuaid MikeMcQuaid left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for PR! Game for this fix just not sure it's quite right yet.

Comment thread Library/Homebrew/extend/os/mac/cask/quarantine.rb Outdated
Move the eager `MacOS.languages` resolution to a single early, shared
site per review feedback: `Cask::Installer#prelude` is run-once, is
called first by `#install` and `#fetch`, and is called explicitly by
`Cask::Upgrade` before the signing-identity scan. It is not run by
uninstalls or when no casks are being processed.

Remove the `install_artifacts` and `Quarantine.signing_identity`
hooks this replaces.

@MikeMcQuaid MikeMcQuaid left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good, thanks!

@MikeMcQuaid

Copy link
Copy Markdown
Member

Here are some automated review suggestions for this pull request.

@dot-agi Please disable this on your Homebrew PRs 🙇🏻

@MikeMcQuaid
MikeMcQuaid added this pull request to the merge queue Aug 22, 2026
Merged via the queue into Homebrew:main with commit 400d757 Aug 22, 2026
46 checks passed
@dot-agi
dot-agi deleted the cask-eager-languages branch August 22, 2026 11:26
@dot-agi

dot-agi commented Aug 22, 2026

Copy link
Copy Markdown
Contributor Author

Done — disabled. The Codex GitHub app no longer has access to my brew/homebrew-core forks, so it can't auto-review PRs to Homebrew repos anymore. Sorry for the noise! 🙇

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.

3 participants