From c9558857f7ad345c75dc5c84e0b9bc65a8a80a01 Mon Sep 17 00:00:00 2001 From: nitin sanghi Date: Thu, 30 Jul 2026 17:33:24 +0530 Subject: [PATCH 1/2] CHEF-37444: add ~/.chef/ruby/VERSION/gems to GEM_PATH for dynamic plugin loading - binstub_patch.rb: inject Gem.user_dir (~/.gem/ruby/VERSION) and ~/.chef/ruby/RUBY_API_VERSION/gems into GEM_PATH ahead of existing paths so gems installed via `gem install` or `chef gem install` are immediately visible to the ohai binstub. - habitat/plan.sh, habitat/aarch64-darwin/plan.sh: expand the runtime wrapper's GEM_PATH to four entries: 1. $pkg_prefix/vendor (ohai's vendored deps, flat) 2. $pkg_prefix/vendor/ruby/VERSION (bundler-nested deps, e.g. train-core) 3. ~/.gem/ruby/VERSION (standard `gem install` target) 4. ~/.chef/ruby/VERSION/gems (`chef gem install` target) ruby_gem_version is now derived from the packaged Ruby's on-disk lib/ruby/gems/ directory instead of executing `ruby -e`, which could silently fail during Habitat's do_install phase and leave the version segment empty. Falls back to 3.4.0 with a build_line warning. - habitat/plan.ps1: inject binstub_patch.rb into Windows binstubs after appbundler generates them, using the same require-rubygems insertion point used on Linux/macOS. Signed-off-by: nitin sanghi --- binstub_patch.rb | 16 +++++++++++++++- habitat/aarch64-darwin/plan.sh | 16 +++++++++++++++- habitat/plan.ps1 | 13 +++++++++++++ habitat/plan.sh | 16 +++++++++++++++- 4 files changed, 58 insertions(+), 3 deletions(-) diff --git a/binstub_patch.rb b/binstub_patch.rb index 00599425f..02a1aabdb 100644 --- a/binstub_patch.rb +++ b/binstub_patch.rb @@ -1,4 +1,18 @@ unless ENV["APPBUNDLER_ALLOW_RVM"] ENV["APPBUNDLER_ALLOW_RVM"] = "true" - ENV["GEM_PATH"] = [File.expand_path(File.join(__dir__, "..", "vendor")), ENV["GEM_PATH"]].compact.join(File::PATH_SEPARATOR) end + +# Prepend the package vendor dir, the current user's gem dir, and the Chef gem dir to +# GEM_PATH so that: +# 1. Ohai's vendored dependencies are always found. +# 2. Plugins installed via `gem install ` are discoverable on both +# Linux (~/.gem/ruby/VERSION) and Windows (%USERPROFILE%\.gem\ruby\VERSION). +# 3. Gems installed via `chef gem install` (~/.chef/ruby/VERSION/gems) are immediately available. +# +# This block runs before appbundler's env_sanitizer (which calls Gem.clear_paths and +# re-reads GEM_PATH from ENV), so these additions are always picked up correctly. +ohai_vendor = File.expand_path(File.join(__dir__, "..", "vendor")) +# chef-cli gem install places gems under ~/.chef/ruby/RUBY_API_VERSION/gems +chef_gem_dir = File.join(Dir.home, ".chef", "ruby", RbConfig::CONFIG["ruby_version"], "gems") +existing_paths = ENV["GEM_PATH"]&.split(File::PATH_SEPARATOR) || [] +ENV["GEM_PATH"] = ([ohai_vendor, Gem.user_dir, chef_gem_dir] + existing_paths).uniq.join(File::PATH_SEPARATOR) diff --git a/habitat/aarch64-darwin/plan.sh b/habitat/aarch64-darwin/plan.sh index 70341303b..e2ca30dcd 100644 --- a/habitat/aarch64-darwin/plan.sh +++ b/habitat/aarch64-darwin/plan.sh @@ -110,6 +110,15 @@ do_install() { build_line "** creating wrapper for runtime environment" mkdir -p "$pkg_prefix/libexec" mv "$pkg_prefix/bin/ohai" "$pkg_prefix/libexec/ohai" + # Derive the Ruby API version (e.g. 3.4.0) from the packaged Ruby's on-disk gem layout + # rather than executing `ruby -e`. Invoking the hab-provided ruby during the build can + # silently fail (its runtime library paths aren't set up here), which would leave + # ruby_gem_version empty and corrupt every GEM_PATH entry written below. + ruby_gem_version="$(basename "$(pkg_path_for "${ruby_pkg}")/lib/ruby/gems/"*)" + if [[ -z "$ruby_gem_version" ]]; then + build_line "WARNING: unable to determine Ruby API version from ${ruby_pkg}; falling back to 3.4.0" + ruby_gem_version="3.4.0" + fi cat < "$pkg_prefix/bin/ohai" #!/bin/bash set -e @@ -117,7 +126,12 @@ set -e export PATH="$(pkg_path_for ${ruby_pkg})/bin:/sbin:/usr/sbin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:$pkg_prefix/vendor/bin:\$PATH" export DYLD_LIBRARY_PATH="$(pkg_path_for core/libarchive)/lib:\$DYLD_LIBRARY_PATH" export GEM_HOME="$pkg_prefix/vendor" -export GEM_PATH="$pkg_prefix/vendor" +# GEM_PATH includes the flat vendor tree, the bundler-nested vendor tree +# (vendor/ruby/VERSION, where train-core and other runtime deps are installed), the +# standard user gem dir (~/.gem/ruby/VERSION), and the Chef gem dir +# (~/.chef/ruby/VERSION/gems) so that both ohai's own runtime deps and plugins installed +# via 'gem install' or 'chef gem install' are found at runtime. +export GEM_PATH="$pkg_prefix/vendor:$pkg_prefix/vendor/ruby/${ruby_gem_version}:\${HOME}/.gem/ruby/${ruby_gem_version}:\${HOME}/.chef/ruby/${ruby_gem_version}/gems" exec $(pkg_path_for ${ruby_pkg})/bin/ruby $pkg_prefix/libexec/ohai "\$@" EOF diff --git a/habitat/plan.ps1 b/habitat/plan.ps1 index 47299d532..445a60dcf 100644 --- a/habitat/plan.ps1 +++ b/habitat/plan.ps1 @@ -85,6 +85,19 @@ function Invoke-Install { Write-BuildLine "** generating binstubs for ohai with precise version pins $project_root $pkg_prefix/bin " Invoke-Expression -Command "appbundler.bat $project_root $pkg_prefix/bin ohai" If ($lastexitcode -ne 0) { Exit $lastexitcode } + + Write-BuildLine "** patching binstubs for direct execution and dynamic plugin loading" + $binstubPatch = Get-Content -Path "$project_root\binstub_patch.rb" + Get-ChildItem "$pkg_prefix\bin" | Where-Object { $_.Extension -notin @(".bat", ".ps1") } | ForEach-Object { + $lines = Get-Content -Path $_.FullName + $matchLine = $lines | Select-String -Pattern 'require "rubygems"' | Select-Object -First 1 + if ($matchLine) { + $lineNum = $matchLine.LineNumber # 1-based; insert patch after this line + $newLines = $lines[0..($lineNum - 1)] + $binstubPatch + $lines[$lineNum..($lines.Count - 1)] + Set-Content -Path $_.FullName -Value $newLines + } + } + Write-BuildLine " ** Running the ohai project's 'rake install' to install the path-based gems so they look like any other installed gem." If ($lastexitcode -ne 0) { Exit $lastexitcode } diff --git a/habitat/plan.sh b/habitat/plan.sh index 36c0e8804..d8bba2e24 100644 --- a/habitat/plan.sh +++ b/habitat/plan.sh @@ -92,6 +92,15 @@ do_install() { build_line "** creating wrapper for runtime environment" mkdir -p "$pkg_prefix/libexec" mv "$pkg_prefix/bin/ohai" "$pkg_prefix/libexec/ohai" + # Derive the Ruby API version (e.g. 3.4.0) from the packaged Ruby's on-disk gem layout + # rather than executing `ruby -e`. Invoking the hab-provided ruby during the build can + # silently fail (its runtime library paths aren't set up here), which would leave + # ruby_gem_version empty and corrupt every GEM_PATH entry written below. + ruby_gem_version="$(basename "$(pkg_path_for "${ruby_pkg}")/lib/ruby/gems/"*)" + if [[ -z "$ruby_gem_version" ]]; then + build_line "WARNING: unable to determine Ruby API version from ${ruby_pkg}; falling back to 3.4.0" + ruby_gem_version="3.4.0" + fi cat < "$pkg_prefix/bin/ohai" #!$(pkg_path_for core/bash)/bin/bash set -e @@ -99,7 +108,12 @@ set -e export PATH="$(pkg_path_for ${ruby_pkg})/bin:/sbin:/usr/sbin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:\$PATH" export LD_LIBRARY_PATH="$(pkg_path_for core/libarchive)/lib:\$LD_LIBRARY_PATH" export GEM_HOME="$pkg_prefix/vendor" -export GEM_PATH="$pkg_prefix/vendor" +# GEM_PATH includes the flat vendor tree, the bundler-nested vendor tree +# (vendor/ruby/VERSION, where train-core and other runtime deps are installed), the +# standard user gem dir (~/.gem/ruby/VERSION), and the Chef gem dir +# (~/.chef/ruby/VERSION/gems) so that both ohai's own runtime deps and plugins installed +# via 'gem install' or 'chef gem install' are found at runtime. +export GEM_PATH="$pkg_prefix/vendor:$pkg_prefix/vendor/ruby/${ruby_gem_version}:\${HOME}/.gem/ruby/${ruby_gem_version}:\${HOME}/.chef/ruby/${ruby_gem_version}/gems" exec $(pkg_path_for ${ruby_pkg})/bin/ruby $pkg_prefix/libexec/ohai "\$@" EOF From 5e653982a52ad9001953fd49ee2daa80407dd776 Mon Sep 17 00:00:00 2001 From: nitin sanghi Date: Mon, 10 Aug 2026 13:14:53 +0530 Subject: [PATCH 2/2] Adding ruby version near pkg so we don't forgot to change Signed-off-by: nitin sanghi --- habitat/aarch64-darwin/plan.sh | 18 +++++++++--------- habitat/plan.sh | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/habitat/aarch64-darwin/plan.sh b/habitat/aarch64-darwin/plan.sh index e2ca30dcd..695bf7760 100644 --- a/habitat/aarch64-darwin/plan.sh +++ b/habitat/aarch64-darwin/plan.sh @@ -1,6 +1,15 @@ export HAB_BLDR_CHANNEL="base-2025" export HAB_REFRESH_CHANNEL="base-2025" ruby_pkg="core/ruby3_4" +# Derive the Ruby API version (e.g. 3.4.0) from the packaged Ruby's on-disk gem layout +# rather than executing `ruby -e`. Invoking the hab-provided ruby during the build can +# silently fail (its runtime library paths aren't set up here), which would leave +# ruby_gem_version empty and corrupt every GEM_PATH entry that uses it. +ruby_gem_version="$(basename "$(pkg_path_for "${ruby_pkg}")/lib/ruby/gems/"*)" +if [[ -z "$ruby_gem_version" ]]; then + build_line "WARNING: unable to determine Ruby API version from ${ruby_pkg}; falling back to 3.4.0" + ruby_gem_version="3.4.0" +fi pkg_name="ohai" pkg_origin="chef" pkg_maintainer="The Chef Maintainers " @@ -110,15 +119,6 @@ do_install() { build_line "** creating wrapper for runtime environment" mkdir -p "$pkg_prefix/libexec" mv "$pkg_prefix/bin/ohai" "$pkg_prefix/libexec/ohai" - # Derive the Ruby API version (e.g. 3.4.0) from the packaged Ruby's on-disk gem layout - # rather than executing `ruby -e`. Invoking the hab-provided ruby during the build can - # silently fail (its runtime library paths aren't set up here), which would leave - # ruby_gem_version empty and corrupt every GEM_PATH entry written below. - ruby_gem_version="$(basename "$(pkg_path_for "${ruby_pkg}")/lib/ruby/gems/"*)" - if [[ -z "$ruby_gem_version" ]]; then - build_line "WARNING: unable to determine Ruby API version from ${ruby_pkg}; falling back to 3.4.0" - ruby_gem_version="3.4.0" - fi cat < "$pkg_prefix/bin/ohai" #!/bin/bash set -e diff --git a/habitat/plan.sh b/habitat/plan.sh index d8bba2e24..417e84808 100644 --- a/habitat/plan.sh +++ b/habitat/plan.sh @@ -1,6 +1,15 @@ export HAB_BLDR_CHANNEL="base-2025" export HAB_REFRESH_CHANNEL="base-2025" ruby_pkg="core/ruby3_4" +# Derive the Ruby API version (e.g. 3.4.0) from the packaged Ruby's on-disk gem layout +# rather than executing `ruby -e`. Invoking the hab-provided ruby during the build can +# silently fail (its runtime library paths aren't set up here), which would leave +# ruby_gem_version empty and corrupt every GEM_PATH entry that uses it. +ruby_gem_version="$(basename "$(pkg_path_for "${ruby_pkg}")/lib/ruby/gems/"*)" +if [[ -z "$ruby_gem_version" ]]; then + build_line "WARNING: unable to determine Ruby API version from ${ruby_pkg}; falling back to 3.4.0" + ruby_gem_version="3.4.0" +fi pkg_name="ohai" pkg_origin="chef" pkg_maintainer="The Chef Maintainers " @@ -92,15 +101,6 @@ do_install() { build_line "** creating wrapper for runtime environment" mkdir -p "$pkg_prefix/libexec" mv "$pkg_prefix/bin/ohai" "$pkg_prefix/libexec/ohai" - # Derive the Ruby API version (e.g. 3.4.0) from the packaged Ruby's on-disk gem layout - # rather than executing `ruby -e`. Invoking the hab-provided ruby during the build can - # silently fail (its runtime library paths aren't set up here), which would leave - # ruby_gem_version empty and corrupt every GEM_PATH entry written below. - ruby_gem_version="$(basename "$(pkg_path_for "${ruby_pkg}")/lib/ruby/gems/"*)" - if [[ -z "$ruby_gem_version" ]]; then - build_line "WARNING: unable to determine Ruby API version from ${ruby_pkg}; falling back to 3.4.0" - ruby_gem_version="3.4.0" - fi cat < "$pkg_prefix/bin/ohai" #!$(pkg_path_for core/bash)/bin/bash set -e