Putting your rbenv-managed bundler-specified executables in your PATH (more) securely
There have been a smattering of solutions offered over the years for getting rid of bundle exec
. To me they all have drawbacks -- they either solve the problem at the wrong layer, involve remembering an extra step, require a manually-managed whitelist, or are messy for some other reason.
- carsomyr/rbenv-bundler
- gma/bundler-exec
- mpapis/rubygems-bundler
- various flavors of
bundle exec bash
: here's one, here's my own quick experiment that I never used - various flavors of adding ./bin to your path: David Chelimsky post and the comments on this blog post
The last one is my favorite -- it uses native shell and bundler features in a straightforward way. However, it's considered a security risk to have
./bin
in your path. Someone could trick you into downloading something that youcd
into which has a script in./bin/ls
that deletes your home directory or reads your personal information.
Here is my solution to that. If you are using zsh, you can execute arbitrary shell code whenever cd
is invoked. So here, I add ./bin
to PATH, but only when there is a Gemfile
present. Put this somewhere in your zsh config:
function chpwd {
if [ -r $PWD/Gemfile ]; then
export PATH=./bin:${PATH//\.\/bin:}
else
regexp-replace PATH '\./bin:' ''
fi
}
Ta-da! Now you just have to remember to use the --binstubs
flag whenever you install new gems. This part could be more smoothly handled by Bunder, I've opened a ticket to begin exploring this issue and might put together a solution sometime.
notes
- There is still a security risk when downloading projects with
Gemfile
present, but now it's much smaller. An alternative would be to check for.my_special_file
instead of Gemfile -- that file would have to have a non-standard name in order to be fully secure. Eventually I want to switch to this even more secure method, but I can't think of an elegant way to pick its name, so I'm sticking with Gemfile :-D. - if you have something already defined in
chpwd
, you have to put this code inside the samechpwd
-- consecutivechpwd
s will overwrite each other. This also stops me from making a flexible oh-my-zsh plugin. If anyone knows how to addchpwd
behavior without overwriting previouschpwd
behavior, let me know! - It works with foreman too --
foreman run foo
will use the correct executable andforeman run which foo
shows the correct path. However for some reasonforeman run type foo
does not -- I guesstype
starts a fresh environment for some reason? - Next I would like to automatically prepend everything with
foreman run
:-D I imagine that will be hackier though. Any ideas?