bin/dev: scrub foreign bundler activation before Ruby boots - #95
Merged
Conversation
A harness running under bundle exec leaks RUBYOPT/BUNDLE_* into every child, and the interpreter activates the caller's bundle before dev's Ruby half runs a single line — dev then can't load its own gems (observed live as ai-flow#44's LoadError). dev picks its own Ruby and gems; no caller's activation is ever wanted, so the sh shim unsets the activation keys itself, making every caller's scrub defense-in-depth instead of load-bearing. Closes #94 Co-authored-by: Cursor <cursoragent@cursor.com>
2 tasks
The dev.yml probe dragged shadowenv provisioning into the test, which fails on CI runners; a PATH-stubbed ruby printing its env pins the exact unset list hermetically. Co-authored-by: Cursor <cursoragent@cursor.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
The suite's own bundle exec activation is the live truth: any key where ENV differs from Bundler.original_env is something the locked bundler exported, so a bundler bump that exports a new activation key turns the build red naming it. Subset direction only — config-dependent keys the launch didn't export are free no-ops, so exact equality would just add flake. The guard caught its first drift before shipping: bundler 4 exports BUNDLE_LOCKFILE, which the hand-pinned list missed. Co-authored-by: Cursor <cursoragent@cursor.com>
The sh shim is the single source of truth for the scrub list (the unset must run before any Ruby exists), so the tests alias it by parsing bin/dev instead of keeping a pinned copy that could drift; the stub-ruby and env-parsing mechanics move into named helpers and the file comment states what each of the three tests proves. Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
bin/devsh shim now unsets the bundler-activation keys (RUBYOPT,RUBYLIB,BUNDLE_GEMFILE,BUNDLE_PATH,BUNDLE_APP_CONFIG,BUNDLE_BIN,BUNDLE_BIN_PATH,BUNDLER_VERSION,BUNDLER_SETUP) before probing for or exec'ing Ruby — a leakedRUBYOPT=-r.../bundler/setupis processed by the interpreter ahead of the script's first line, so the sh layer is the only place this defense can live.GEM_HOME/GEM_PATHdeliberately stay: they're legitimate user config, and the one resolution they can redirect into an ephemeral cache is guarded at its call site (GemSkillLinker: links minted under a sandboxed session point into ephemeral sandbox cache paths #90).RUBYOPTnorBUNDLE_GEMFILE.Why
Third member of the harness-env-leak family (ai-flow#38, ai-flow#44, dev#89). Every caller patching every spawn site is a discipline that keeps failing — ai-flow#44 happened precisely because a later-added shell-out missed the existing scrub. dev defending itself at its entrypoint retires the class for every caller: ai-flow, sandboxed sessions, CI, anything future.
Test plan
Dev::BinDevTestred without the shim change, green with itsrb tcall greenCloses #94
Made with Cursor