Hi!
When I start Ruby, I see that it scans the home directory for user-installed gems:
strace -e file ruby30 -e nil |& fgrep $HOME
It's a long list, have a loook at it yourself. For me, it's roughly 300 system calls.
When I deploy Ruby scripts in my company, I want these Ruby scripts **not** to access the user home directory. All the gems that are necessary for my deployed Ruby scripts are installed using RPMs, alongside the interpreter.
## Problems
It want to prevent these accesses to user home directory for multiple reasons.
### Reproducible/Correct/Safe Behavior
The user might have installed a newer or patched version of a gem in his home directory. The newer version might behave differently from the installed gem. That's I want my deployed Ruby scripts to use the installed gems, and the installed gems only. Reproducible behavior is of paramount importance, because many of these Ruby scripts are used in builds that *must* be reproducible
### Maintenance
Some users user-installed gems using prior versions of Ruby. My deployed scripts use a newer interpreter. Whenever one of these users starts one of my Ruby scripts, they get warnings like this one, at every single start:
Ignoring mysql2-0.4.8 because its extensions are not built. Try: gem pristine mysql2 --version 0.4.8
### Performance
The user home directories are one a network share, mounted using NFS. Scanning the home directory via NFS makes Ruby startup much slow.
## Approaches
### `--disable=gems`
* (good) `ruby --disable=gems` prevents Ruby from accessing to the user gems. (According to `strace`: no access to the user home directory at all.)
* (good) It makes Ruby startup roughly 10 times faster (in my setup).
* (good) Requires a simple change in the shebang line: `#!/usr/bin/ruby30 --disable=gems`
* (bad) It prevents me from loading some gems (e.g.: `nokogiri`); I guess this is about a Gem being built-in or not being built-in.
* (bad) `--disable=gems` is deprecated for Ruby >=3.1: File: NEWS.md [Ruby 3.1.0]
### Setting `$GEM_PATH` and `$GEM_SPEC_CACHE`
* (good) `env GEM_PATH= GEM_SPEC_CACHE= ruby` prevents Ruby from accessing the user gems. (According to `strace`: no access to the user home directory at all.)
* (good) Ruby startup is much slower than `ruby --disable=gems`, but it is still much faster than the default behavior.
* (good) Ruby is still able to load all gems that are installed using RPMs
* (?) I have to create and deploy a wrapper:
#!/bin/sh
GEM_PATH= GEM_SPEC_CACHE= exec /usr/bin/ruby30 "$@"
All my deployed scripts have to use this wrapper.
### Setting `Gem.paths`
Inserting this snippet right at the start of the script:
#!/usr/bin/ruby
Gem.paths = {
"GEM_HOME" => Gem.paths.home,
"GEM_PATH" => Gem.path.reject { |path| path.start_with? "/home/" }.join(":"),
"SPEC_CACHE_DIR" => ""
}
[...]
* (good) It prevents Ruby from loading the user gems.
* (bad) Ruby accesses (and checks) all user gems before the start of the script.
* (bad) Aesthetics
## Feature Request?
Isn't there a better solution? Something like `python -s`? For me, it would be very useful.
Best regards
Johannes