Production stage runsDocumentation Index
Fetch the complete documentation index at: https://tally.wharflab.com/llms.txt
Use this file to discover all available pages before exploring further.
bundle install without excluding the development gem group via BUNDLE_WITHOUT.
| Property | Value |
|---|---|
| Severity | Warning |
| Category | Security |
| Default | Enabled |
| Auto-fix | Yes (FixSafe) |
Description
Bundler installs every gem in theGemfile by default. The Rails generator template explicitly excludes the
development group at the image level via ENV BUNDLE_WITHOUT="development" precisely because, without it,
production images ship web-console, byebug, pry, rspec-rails, letter_opener, bullet, spring, and
similar development-only gems — bloating image size and exposing development-only attack surface.
web-console in particular has documented RCE history when it leaks into production. The
Rails security guide calls this out, and Bundler 2.x documents
BUNDLE_WITHOUT and bundle config set without as the
supported mechanism to scope the install.
This rule fires when a Ruby-shaped production stage runs bundle install and:
- Neither
ENV BUNDLE_WITHOUT=...(withdevelopmentin the value) nor a priorbundle config set [--local|--global] without ...development...invocation is observable in the stage, AND ENV BUNDLE_ONLY=...(the Bundler 2.5+ inverse selector) does not containproduction.
tally/ruby/missing-bundle-deployment rule:
the Dockerfile binds RAILS_ENV (or RACK_ENV) to "production" somewhere, or the stage has no
explicit non-production marker and the rest of the stage shape (Ruby base, no dev-stage name, etc.) implies a
runtime image.
Stages explicitly named dev, development, test, testing, ci, or debug are skipped, as are stages
whose effective env binds RAILS_ENV/RACK_ENV to development or test.
Because the rule lives in the Ruby namespace and its remedy is Rails-flavored, it only fires on stages that
look like a Ruby runtime: an official ruby:* base, a familiar name containing ruby or rails, a
Ruby-runtime derivative, a stage env carrying Ruby/Rails/Bundler signals, or an ENTRYPOINT/CMD that invokes
ruby, rails, bundle, puma, etc.
Context-aware refinement
When tally is invoked with--context (or via Bake/Compose), the rule consults the project’s Gemfile to
sharpen its behavior:
- Suppressed when there is nothing to exclude. If the
Gemfileis observable and contains nogroup :development doblock (some library-style or ops-tool gems don’t), the rule skips entirely — the recommendation would be moot. - Smarter fix wording. If the
Gemfilecontains bothgroup :developmentandgroup :testblocks, the auto-fix emitsENV BUNDLE_WITHOUT="development:test"so production images don’t shiprspec-rails,capybara, or other test-only gems either. With only:development, the fix uses the Rails generator’s exact wording,ENV BUNDLE_WITHOUT="development".
Gemfile is not observable (Dockerfile-only mode), the rule applies and the fix defaults to
ENV BUNDLE_WITHOUT="development".
Examples
Before
After
The Rails-generator-style fix declaresBUNDLE_WITHOUT once at the top of the stage so every nested
bundle install (including any inside CI scripts or entrypoints) honors it:
Auto-fix
The rule offers aFixSafe that inserts ENV BUNDLE_WITHOUT="development" (or "development:test" when
both groups are observable in the project’s Gemfile) on the line immediately following the stage’s FROM.
Insertion is zero-width at column 0, so it composes cleanly with other rule edits in the same stage.
References
- Rails Dockerfile generator template —
emits
ENV BUNDLE_WITHOUT="development"in the base stage. - Bundler
bundle configdocumentation —BUNDLE_WITHOUTandBUNDLE_ONLYsemantics. - Bundler 2 upgrade guide — deprecation of
bundle install --without. - Rails security guide — context for keeping development-only gems out of production images.