Library/Homebrew: move stdin ruby scripts to files under utils.

This avoids can avoid UID/EUID related issues with Ruby scripts passed
over `stdin` clashing with Ruby security features.

It's also just a bit nicer to have Ruby scripts in files instead.

While we're here:
- refactor some shared logic into a new `setup-gem-home-bundle-gemfile`
  function in `ruby.sh`
- do some general cleanup of `lock.sh`
- prioritise `flock` over `python` in `lock.sh`
This commit is contained in:
Mike McQuaid 2024-05-02 10:33:42 +01:00
parent 2862bc2ac6
commit bc0f5ee62a
No known key found for this signature in database
8 changed files with 43 additions and 32 deletions

View File

@ -897,9 +897,6 @@ then
unset HOMEBREW_AUTO_UPDATE_CASK_TAP unset HOMEBREW_AUTO_UPDATE_CASK_TAP
fi fi
# Disable Ruby options we don't need.
export HOMEBREW_RUBY_DISABLE_OPTIONS="--disable=gems,rubyopt"
if [[ -z "${HOMEBREW_RUBY_WARNINGS}" ]] if [[ -z "${HOMEBREW_RUBY_WARNINGS}" ]]
then then
export HOMEBREW_RUBY_WARNINGS="-W1" export HOMEBREW_RUBY_WARNINGS="-W1"

View File

@ -5,9 +5,7 @@
#: command. #: command.
#: #:
# HOMEBREW_LIBRARY is from the user environment. # HOMEBREW_LIBRARY is set by brew.sh
# HOMEBREW_RUBY_PATH is set by utils/ruby.sh
# RUBY_DISABLE_OPTIONS is set by brew.sh
# HOMEBREW_BREW_FILE is set by extend/ENV/super.rb # HOMEBREW_BREW_FILE is set by extend/ENV/super.rb
# shellcheck disable=SC2154 # shellcheck disable=SC2154
homebrew-setup-ruby() { homebrew-setup-ruby() {
@ -37,13 +35,7 @@ homebrew-setup-ruby() {
fi fi
fi fi
GEM_VERSION="$("${HOMEBREW_RUBY_PATH}" "${HOMEBREW_RUBY_DISABLE_OPTIONS}" /dev/stdin <<<'require "rbconfig"; puts RbConfig::CONFIG["ruby_version"]')" setup-gem-home-bundle-gemfile
echo "${GEM_VERSION}"
GEM_HOME="${HOMEBREW_LIBRARY}/Homebrew/vendor/bundle/ruby/${GEM_VERSION}"
BUNDLE_GEMFILE="${HOMEBREW_LIBRARY}/Homebrew/Gemfile"
export GEM_HOME
export BUNDLE_GEMFILE
if ! bundle check &>/dev/null if ! bundle check &>/dev/null
then then

View File

@ -4,25 +4,19 @@
# HOMEBREW_LIBRARY is from the user environment. # HOMEBREW_LIBRARY is from the user environment.
# HOMEBREW_RUBY_PATH is set by utils/ruby.sh # HOMEBREW_RUBY_PATH is set by utils/ruby.sh
# RUBY_DISABLE_OPTIONS is set by brew.sh
# HOMEBREW_BREW_FILE is set by extend/ENV/super.rb # HOMEBREW_BREW_FILE is set by extend/ENV/super.rb
# shellcheck disable=SC2154 # shellcheck disable=SC2154
homebrew-rubocop() { homebrew-rubocop() {
source "${HOMEBREW_LIBRARY}/Homebrew/utils/ruby.sh" source "${HOMEBREW_LIBRARY}/Homebrew/utils/ruby.sh"
setup-ruby-path setup-ruby-path
setup-gem-home-bundle-gemfile
GEM_VERSION="$("${HOMEBREW_RUBY_PATH}" "${HOMEBREW_RUBY_DISABLE_OPTIONS}" /dev/stdin <<<'require "rbconfig"; puts RbConfig::CONFIG["ruby_version"]')"
GEM_HOME="${HOMEBREW_LIBRARY}/Homebrew/vendor/bundle/ruby/${GEM_VERSION}"
BUNDLE_GEMFILE="${HOMEBREW_LIBRARY}/Homebrew/Gemfile"
BUNDLE_WITH="style" BUNDLE_WITH="style"
export GEM_HOME
export BUNDLE_GEMFILE
export BUNDLE_WITH export BUNDLE_WITH
if ! bundle check &>/dev/null if ! bundle check &>/dev/null
then then
"${HOMEBREW_BREW_FILE}" install-bundler-gems --add-groups=style "${HOMEBREW_BREW_FILE}" install-bundler-gems --add-groups="${BUNDLE_WITH}"
fi fi
export PATH="${GEM_HOME}/bin:${PATH}" export PATH="${GEM_HOME}/bin:${PATH}"

View File

@ -1,6 +1,7 @@
# create a lock using `flock(2)`. A name is required as first argument. # create a lock using `flock(2)`. A name is required as first argument.
# the lock will be automatically unlocked when the shell process quits. # the lock will be automatically unlocked when the shell process quits.
# Noted due to the fixed FD, a shell process can only create one lock. # Noted due to the fixed FD, a shell process can only create one lock.
# HOMEBREW_LIBRARY is by brew.sh
# HOMEBREW_PREFIX is set by extend/ENV/super.rb # HOMEBREW_PREFIX is set by extend/ENV/super.rb
# shellcheck disable=SC2154 # shellcheck disable=SC2154
lock() { lock() {
@ -16,7 +17,7 @@ Fix permissions by running:
sudo chown -R ${USER-\$(whoami)} ${HOMEBREW_PREFIX}/var/homebrew sudo chown -R ${USER-\$(whoami)} ${HOMEBREW_PREFIX}/var/homebrew
EOS EOS
fi fi
# 200 is the file descriptor used in the lock. # 200 is the file descriptor (FD) used in the lock.
# This FD should be used exclusively for lock purpose. # This FD should be used exclusively for lock purpose.
# Any value except 0(stdin), 1(stdout) and 2(stderr) can do the job. # Any value except 0(stdin), 1(stdout) and 2(stderr) can do the job.
# Noted, FD is unique per process but it will be shared to subprocess. # Noted, FD is unique per process but it will be shared to subprocess.
@ -37,26 +38,25 @@ EOS
} }
_create_lock() { _create_lock() {
local lock_fd="$1" local lock_file_descriptor="$1"
local name="$2" local name="$2"
local ruby="/usr/bin/ruby" local ruby="/usr/bin/ruby"
local python="/usr/bin/python" local python="/usr/bin/python"
[[ -x "${ruby}" ]] || ruby="$(type -P ruby)" [[ -x "${ruby}" ]] || ruby="$(type -P ruby)"
[[ -x "${python}" ]] || python="$(type -P python)" [[ -x "${python}" ]] || python="$(type -P python)"
# Use /dev/stdin, otherwise Ruby can error if uid != euid. local utils_lock_sh="${HOMEBREW_LIBRARY}/Homebrew/utils/lock_sh"
# Can't use "-" as that's also blocked: local oldest_ruby_with_flock="1.8.7"
# https://github.com/ruby/ruby/blob/e51435177e88fc845528dff7cf2bc2b75dd36144/ruby.c#L2333-L2335 if [[ -x "${ruby}" ]] && "${ruby}" "${utils_lock_sh}/ruby_check_version.rb" "${oldest_ruby_with_flock}"
if [[ -x "${ruby}" ]] && "${ruby}" /dev/stdin <<<"exit(RUBY_VERSION >= '1.8.7')"
then then
"${ruby}" /dev/stdin <<<"File.new(${lock_fd}).flock(File::LOCK_EX | File::LOCK_NB) || exit(1)" "${ruby}" "${utils_lock_sh}/ruby_lock_file_descriptor.rb" "${lock_file_descriptor}"
elif [[ -x "$(type -P flock)" ]]
then
flock -n "${lock_file_descriptor}"
elif [[ -x "${python}" ]] elif [[ -x "${python}" ]]
then then
"${python}" -c "import fcntl; fcntl.flock(${lock_fd}, fcntl.LOCK_EX | fcntl.LOCK_NB)" "${python}" -c "import fcntl; fcntl.flock(${lock_fd}, fcntl.LOCK_EX | fcntl.LOCK_NB)"
elif [[ -x "$(type -P flock)" ]]
then
flock -n "${lock_fd}"
else else
onoe "Cannot create ${name} lock, please avoid running Homebrew in parallel." onoe "Cannot create ${name} lock due to missing/too old ruby/flock/python, please avoid running Homebrew in parallel."
fi fi
} }

View File

@ -0,0 +1,5 @@
# typed: strict
# frozen_string_literal: true
ruby_version_to_check = ARGV.first
exit(ruby_version_to_check < RUBY_VERSION)

View File

@ -0,0 +1,6 @@
# typed: strict
# frozen_string_literal: true
file_descriptor = ARGV.first.to_i
file = File.new(file_descriptor)
file.flock(File::LOCK_EX | File::LOCK_NB) || exit(1)

View File

@ -2,6 +2,9 @@
# When bumping to a new major/minor version, also update the bounds in the Gemfile # When bumping to a new major/minor version, also update the bounds in the Gemfile
export HOMEBREW_REQUIRED_RUBY_VERSION=3.1 export HOMEBREW_REQUIRED_RUBY_VERSION=3.1
# Disable Ruby options we don't need.
export HOMEBREW_RUBY_DISABLE_OPTIONS="--disable=gems,rubyopt"
# HOMEBREW_LIBRARY is from the user environment # HOMEBREW_LIBRARY is from the user environment
# shellcheck disable=SC2154 # shellcheck disable=SC2154
test_ruby() { test_ruby() {
@ -145,3 +148,12 @@ If there's no Homebrew Portable Ruby available for your processor:
export HOMEBREW_RUBY_PATH export HOMEBREW_RUBY_PATH
[[ -n "${HOMEBREW_LINUX}" && -n "${TERMINFO_DIRS}" ]] && export TERMINFO_DIRS [[ -n "${HOMEBREW_LINUX}" && -n "${TERMINFO_DIRS}" ]] && export TERMINFO_DIRS
} }
setup-gem-home-bundle-gemfile() {
GEM_VERSION="$("${HOMEBREW_RUBY_PATH}" "${HOMEBREW_RUBY_DISABLE_OPTIONS}" "${HOMEBREW_LIBRARY}/Homebrew/utils/ruby_sh/ruby_gem_version.rb")"
GEM_HOME="${HOMEBREW_LIBRARY}/Homebrew/vendor/bundle/ruby/${GEM_VERSION}"
BUNDLE_GEMFILE="${HOMEBREW_LIBRARY}/Homebrew/Gemfile"
export GEM_HOME
export BUNDLE_GEMFILE
}

View File

@ -0,0 +1,5 @@
# typed: strict
# frozen_string_literal: true
require "rbconfig"
puts RbConfig::CONFIG["ruby_version"]