Skip to content

Rails: Default to "sandbox" mode when accessing production-like environments #747

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

stevepolitodesign
Copy link
Contributor

@stevepolitodesign stevepolitodesign commented Apr 4, 2025

In an effort to avoid accidental writing to the production database, we
recommend setting config.sandbox_by_default to true in
production-like environments.

…onments

In an effort to avoid mutating production data, we recommend using
"sandbox" mode when using `rails console`.

If you need to [maniuplate data][data migrate], consider running a
custom Rake task, or use [maintenance_tasks][].

[data migrate]: https://guides.rubyonrails.org/active_record_migrations.html#data-migrations
[maintenance_tasks]: https://github.com/Shopify/maintenance_tasks
@brian-penguin
Copy link

brian-penguin commented Apr 4, 2025

Mixed on this. In my perfect world the console is always sandboxed and no one attempts to change or alter data. In a world in which I regularly live, stuff changes from the console. Being in sandbox mode and attempting to change records will lock the DB rows until the session is ended and the transaction is rolled back, which can cause problems and potentially crash. It also doesn't prevent side effect calls (changing job states in redis/ external api calls/ etc) made during the session.

In a lot of applications, there just aren't the tools available to debug, change config, or run code at a specific enough level. Building those tools only usually happens on large teams which have non-technical admin who are taking responsibility for fixing those problems for their users. When those tools exist as one off scripts or rake tasks they tend to be forgotten about and then you either support code that isn't understood or "correct" over time or you run the risk of the rake task doing something slightly different than the core flow and causing a waterfall of problems. Both of those seem higher risk to me over a longer time than trusting a developer to do something with immediacy in a console session.

So yeah, torn on the outcome here and not sure there's "generalizable" advice. I think maybe if you had to have console access because you didn't have the other tools for debug-ability (or things like deploying those tools takes way too long) I would push for an audit log tagged with the user, if that's possible. You could add an initializer with a custom logger and an ActiveSupport::Notification subscription for events that change the DB (and maybe custom ones for external side-effects or job enqueueing)?

# config/initializers/console_audit.rb
if defined?(Rails::Console)
  console_audit_logger = ActiveSupport::TaggedLogging.new(
    Logger.new(Rails.root.join("log/console_audit.log"))
  )

  ActiveSupport::Notifications.subscribe(/^sql\.active_record$/) do |*args|
    event = ActiveSupport::Notifications::Event.new(*args)

    if /\A(INSERT|UPDATE|DELETE)/i.match?(event.payload[:sql])
      username = `whoami`.strip # am lazy, could make them say the user or give a token or something

      console_audit_logger.tagged("CONSOLE_AUDIT", username) do
        console_audit_logger.info(event.payload[:sql].gsub(/\s+/, " "))
      end
    end
  end

  # Write the notice out to the console
  puts "Console audit logging enabled. All changes will be recorded in log/console_audit.log"
end

But maybe the idea is that if you have sensitive enough data or don't have trust in your dev team, or it's just too many people, maybe don't allow console or ssh access at all?

@brian-penguin
Copy link

I know basecamp has some tools for this I've never used
https://github.com/basecamp/console1984
https://github.com/basecamp/audits1984

rails/README.md Outdated
@@ -81,6 +81,12 @@ Guidance on ActiveRecord, ActiveModel, and other model objects.
- Use `db/seeds.rb` for data that is required in all environments.
- Use `dev:prime` rake task for development environment seed data.

## Console

- Access production-like [console][] sessions in "sandbox" mode: `bin/rails console --sandbox`
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brian-penguin would it help if we changed the framing from "don't change data in production" to "exercise caution when using the rails console in production... you wouldn't wanna delete something on accident"?

Suggested change
- Access production-like [console][] sessions in "sandbox" mode: `bin/rails console --sandbox`
- Access production-like [console][] sessions in "sandbox" mode when possible: `bin/rails console --sandbox`

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The spirit of this guidance is to highlight that this is even an option.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love the spirit of this, but I share the same thoughts as @brian-penguin. But I do think just pointing towards better approaches is a nice way to do this here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nickcharlton @brian-penguin

What do you think about the changes proposed in 4e4e6bd?

This way, you need to explicitly pass --no-sandbox when entering the Rails console.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah, interesting. I'm a fan of that!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's a better default!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants