Git Product home page Git Product logo

console1984's Introduction

example workflow

Console1984

A Rails console extension that protects sensitive accesses and makes them auditable.

“If you want to keep a secret, you must also hide it from yourself.”

― George Orwell, 1984

If you are looking for the auditing tool, check audits1984.

Terminal screenshot showing console1984 asking for a reason for the session

Installation

Important: console1984 depends on Active Record encryption which is a Rails 7 feature.

Add it to your Gemfile:

gem 'console1984'

Create tables to store console activity in the database:

rails console1984:install:migrations
rails db:migrate

By default, console1984 is only enabled in production. You can configure the target environments in your application.rb:

config.console1984.protected_environments = %i[ production staging ]

Finally, you need to configure Active Record Encryption in your project. This is because the library stores the tracked console commands encrypted.

How it works

Session activity logging

When starting a console session, it will ask for a reason. Internally, it will use this reason to document the console session and record all the commands executed in it.

$ rails c

You have access to production data here. That's a big deal. As part of our promise to keep customer data safe and private, we audit the commands you type here. Let's get started!



Commands:

* decrypt!: enter unprotected mode with access to encrypted information

Unnamed, why are you using this console today?

> ...

Auditing sessions

Check out audits1984, a companion auditing tool prepared to work with console1984 database session trails.

Access to encrypted data

By default, console1984 won't decrypt data encrypted with Active Record encryption. Users will just see the ciphertexts.

To decrypt data, enter the command decrypt!. It will ask for a justification, and these accesses will be flagged internally as sensitive.

irb(main)> Topic.last.name
  Topic Load (1.4ms)  SELECT `topics`.* FROM `topics` ORDER BY `topics`.`id` DESC LIMIT 1
=> "{\"p\":\"iu6+LfnNlurC6sL++JyOIDvedjNSz/AvnZQ=\",\"h\":{\"iv\":\"BYa86+JNM/LdkC18\",\"at\":\"r4sQNoSyIlAjJdZEKHVMow==\",\"k\":{\"p\":\"7L1l/5UiYsFQqqo4jfMZtLwp90KqcrIgS7HqgteVjuM=\",\"h\":{\"iv\":\"ItwRYxZAerKIoSZ8\",\"at\":\"ZUSNVfvtm4wAYWLBKRAx/g==\",\"e\":\"QVNDSUktOEJJVA==\"}},\"i\":\"OTdiOQ==\"}}"
irb(main)> decrypt!
Before you can access personal information, you need to ask for and get explicit consent from the user(s). Unnamed, where can we find this consent (a URL would be great)?

> ...

Ok! You have access to encrypted information now. We pay extra close attention to any commands entered while you have this access. You can go back to protected mode with 'encrypt!'

WARNING: Make sure you don`t save objects that were loaded while in protected mode, as this can result in saving the encrypted texts.
irb(main)> Topic.last.name
  Topic Load (1.2ms)  SELECT `topics`.* FROM `topics` ORDER BY `topics`.`id` DESC LIMIT 1
=> "Thanks for the inspiration"

You can type encrypt! to go back to protected mode again.

irb(main):004:0> encrypt!
Great! You are back in protected mode. When we audit, we may reach out for a conversation about the commands you entered. What went well? Did you solve the problem without accessing personal data?
irb(main)> Topic.last.name
  Topic Load (1.4ms)  SELECT `topics`.* FROM `topics` ORDER BY `topics`.`id` DESC LIMIT 1
=> "{\"p\":\"iu6+LfnNlurC6sL++JyOIDvedjNSz/AvnZQ=\",\"h\":{\"iv\":\"BYa86+JNM/LdkC18\",\"at\":\"r4sQNoSyIlAjJdZEKHVMow==\",\"k\":{\"p\":\"7L1l/5UiYsFQqqo4jfMZtLwp90KqcrIgS7HqgteVjuM=\",\"h\":{\"iv\":\"ItwRYxZAerKIoSZ8\",\"at\":\"ZUSNVfvtm4wAYWLBKRAx/g==\",\"e\":\"QVNDSUktOEJJVA==\"}},\"i\":\"OTdiOQ==\"}}"

While in protected mode, you can't modify encrypted data, but can save unencrypted attributes normally. If you try to modify an encrypted column it will raise an error.

Access to external systems

While Active Record encryption can protect personal information in the database, there are other systems can contain very sensitive information. For example: Elasticsearch indexing user information or Redis caching template fragments.

To protect the access to such systems, you can add their URLs to config.console1984.protected_urls in the corresponding environment config file (e.g: production.rb):

config.console1984.protected_urls = [ "https://my-app-us-east-1-whatever.us-east-1.es.amazonaws.com", "redis://my-app-cache-1.whatever.cache.amazonaws.com:6379" ]

In the default protected mode, trying to read data from a protected system will be aborted with an error:

irb(main)> Rails.cache.read("some key") # raises Console1984::Errors::ProtectedConnection

Running decrypt! will switch you to unprotected mode and let you access these systems normally. The system will ask for a justification and will flag those accesses as sensitive.

This will work for systems that use Ruby sockets as the underlying communication mechanism.

Automatic scheduled incineration for sessions

By default, sessions will be incinerated with a job 30 days after they are created. You can configure this period by setting config.console1984.incinerate_after = 1.year and you can disable incineration completely by setting config.console1984.incinerate = false.

Eager loading

When starting a console session, console1984 will eager load all the application classes if necessary. In practice, production environments already load classes eagerly, so this won't represent any change for those.

Configuration

These config options are namespaced in config.console1984:

Name Description
protected_environments The list of environments where console1984 will act on. Defaults to %i[ production ].
protected_urls The list of URLs corresponding with external systems to protect.
session_logger The system used to record session data. The default logger is Console1984::SessionsLogger::Database.
username_resolver Configure how the current user is determined for a given console session. The default is Console1984::Username::EnvResolver.new("CONSOLE_USER"), which returns the value of the environment variable CONSOLE_USER.
ask_for_username_if_empty If true, the console will ask for a username if it is empty. If false, it will raise an error if no username is set. Defaults to false.
production_data_warning The text to show when a console session starts.
enter_unprotected_encryption_mode_warning The text to show when user enters into unprotected mode.
enter_protected_mode_warning The text to show when user go backs to protected mode.
incinerate Whether incinerate sessions automatically after a period of time or not. Default to true.
incinerate_after The period to keep sessions around before incinerate them. Default 30.days.
incineration_queue The name of the queue for session incineration jobs. Default console1984_incineration.
base_record_class The host application base class that will be the parent of console1984 records. By default it's ::ApplicationRecord.

SSH Config

To automatically set the CONSOLE_USER env var for sessions, you'll need to configure SSH on the server to accept the environment variable.

On the server, edit /etc/ssh/sshd_config to accept the environment variable:

AcceptEnv LANG LC_* CONSOLE_USER

Restart the SSH server to use the new config:

service sshd restart

On the client side, you can provide this env var from your clients by adding the variable to the ssh config:

Host *
  SetEnv CONSOLE_USER=david

About built-in protection mechanisms

console1984 adds many protection mechanisms to prevent tampering. This includes attempts to alter data in auditing tables or monkey patching certain classes to change how the system works. If you find a way to circumvent these tampering controls, please report an issue.

We aim to make these defense mechanisms as robust as possible, but there might always be open doors because Ruby is highly dynamic. If your organization needs bullet-proof protection against malicious actors using the console, you should consider additional security measures. An example would be using a read-only database user for auditing data while in a console. The gem doesn't offer direct support for doing this, but it's on our radar for future improvement.

Running the test suite

The test suite runs against SQLite by default, but can be run against Postgres and MySQL too. It will run against the three in the CI server.

To run the suite in your computer, first, run bin/setup to create the docker containers for MySQL/PostgreSQL and create the databases. Then run:

bin/rails test # against SQLite (default) 
bin/rails test TARGET_DB=mysql 
bin/rails test TARGET_DB=postgres 
bin/rails test TARGET_DB=sqlite  

console1984's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

console1984's Issues

Bypass audit table protections by opening a direct connection with the database

I need to admit that #20 made this a lot more robust, but it can still be bypassed by using a low level database connection. A Postgresql example:

# if you need to get the database connection config: ActiveRecord::Base.send(:resolve_config_for_connection, :development)
conn = PG::Connection.open(:dbname => 'rails_edge_development')
conn.exec "delete from console1984_sessions"

Protecting ENV

Hey @jorgemanrubia,

I've been trying out a way to prevent direct access to certain ENV values in the console. The gem already takes care of Rails Credentials, so I thought it'd be a nice addition to the gem doing something similar for ENV. If you're up for it, I'd be happy to open a PR so we could work together on this feature.

Why set username ?

What is the objective of theCONSOLE_USER or the ask_for_username_if_empty if i can inform any name here, how do you use it in 37signal?

Can't start a console session

When starting a console session in my development environment, I get the following error:

Unnamed, why are you using this console today?
testing
Traceback (most recent call last):
        42: from -e:1:in `<main>'
        41: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:72:in `require'
        40: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:72:in `require'
        39: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/activesupport-7.0.2.3/lib/active_support/fork_tracker.rb:18:in `fork'
        38: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/activesupport-7.0.2.3/lib/active_support/fork_tracker.rb:18:in `fork'
        37: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/activesupport-7.0.2.3/lib/active_support/fork_tracker.rb:20:in `block in fork'
        36: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:59:in `load'
        35: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:59:in `load'
        34: from /Users/jerome/c/my_app/my_app/bin/rails:9:in `<main>'
        33: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/zeitwerk-2.5.4/lib/zeitwerk/kernel.rb:35:in `require'
        32: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
        31: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
        30: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
        29: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
        28: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/bootsnap-1.7.5/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
        27: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/railties-7.0.2.3/lib/rails/commands.rb:18:in `<main>'
        26: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/railties-7.0.2.3/lib/rails/command.rb:48:in `invoke'
        25: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/railties-7.0.2.3/lib/rails/command/base.rb:87:in `perform'
        24: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/thor-1.2.1/lib/thor.rb:392:in `dispatch'
        23: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/thor-1.2.1/lib/thor/invocation.rb:127:in `invoke_command'
        22: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/thor-1.2.1/lib/thor/command.rb:27:in `run'
        21: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/railties-7.0.2.3/lib/rails/commands/console/console_command.rb:102:in `perform'
        20: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/railties-7.0.2.3/lib/rails/commands/console/console_command.rb:19:in `start'
        19: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/railties-7.0.2.3/lib/rails/commands/console/console_command.rb:19:in `new'
        18: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/railties-7.0.2.3/lib/rails/commands/console/console_command.rb:35:in `initialize'
        17: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/railties-7.0.2.3/lib/rails/engine.rb:449:in `load_console'
        16: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/railties-7.0.2.3/lib/rails/application.rb:525:in `run_console_blocks'
        15: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/railties-7.0.2.3/lib/rails/engine/railties.rb:15:in `each'
        14: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/railties-7.0.2.3/lib/rails/engine/railties.rb:15:in `each'
        13: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/railties-7.0.2.3/lib/rails/application.rb:525:in `block in run_console_blocks'
        12: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/railties-7.0.2.3/lib/rails/railtie.rb:267:in `run_console_blocks'
        11: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/railties-7.0.2.3/lib/rails/railtie.rb:292:in `each_registered_block'
        10: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/railties-7.0.2.3/lib/rails/railtie.rb:292:in `each'
         9: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/railties-7.0.2.3/lib/rails/railtie.rb:267:in `block in run_console_blocks'
         8: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/console1984-0.1.22/lib/console1984/engine.rb:24:in `block in <class:Engine>'
         7: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/console1984-0.1.22/lib/console1984/supervisor.rb:25:in `start'
         6: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/console1984-0.1.22/lib/console1984/supervisor.rb:57:in `start_session'
         5: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/console1984-0.1.22/lib/console1984/sessions_logger/database.rb:8:in `start_session'
         4: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/console1984-0.1.22/lib/console1984/sessions_logger/database.rb:55:in `silence_logging'
         3: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/activesupport-7.0.2.3/lib/active_support/logger_silence.rb:18:in `silence'
         2: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/activesupport-7.0.2.3/lib/active_support/logger_thread_safe_level.rb:43:in `log_at'
         1: from /Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/activesupport-7.0.2.3/lib/active_support/logger_silence.rb:18:in `block in silence'
/Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/gems/2.7.0/gems/console1984-0.1.22/lib/console1984/sessions_logger/database.rb:56:in `block in silence_logging': undefined method `silence' for #<Logger:0x00007f9b4367e590> (NoMethodError)

FYI my logger config is

logger           = ActiveSupport::Logger.new(STDOUT)
logger.formatter = config.log_formatter
config.logger    = ActiveSupport::TaggedLogging.new(logger)

but it seems to be ignored as Console1984::Base is set to a a basic Logger, and I cannot find why. Looking at the gem's source code it seems that Console1984::Base is getting its logger from ApplicationRecord and ultimately ActiveRecord::Base, unless I am wrong.

I can sort of work around the issue by doing the following hack in an initializer:

ActiveSupport.on_load(:console_1984_base) do
  Console1984::Base.logger = ActiveRecord::Base.logger
end

But I don't think that is recommended, and when I do this my commands generate logs that aren't silenced (but maybe that is a separate problem):

irb(main):001:0> 1+1
D, [2022-03-30T16:39:24.098179 #28421] DEBUG -- :   Console1984::Command Count (2.0ms)  SELECT COUNT(*) FROM "console1984_commands" WHERE "console1984_commands"."session_id" = 10 /*application:MyApp,line:/Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/2.7.0/irb.rb:540:in `block (2 levels) in eval_input'*/
D, [2022-03-30T16:39:24.143082 #28421] DEBUG -- :   TRANSACTION (0.4ms)  BEGIN /*application:MyApp,line:/Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/2.7.0/irb.rb:540:in `block (2 levels) in eval_input'*/
D, [2022-03-30T16:39:24.144492 #28421] DEBUG -- :   Console1984::Command Create (1.1ms)  INSERT INTO "console1984_commands" ("statements", "session_id", "created_at", "updated_at") VALUES ('{"p":"N8tbIg==","h":{"iv":"cmbLlXNgsAOPnxXB","at":"dhqC9V1LpbCF3KM91bNplw=="}}', 10, '2022-03-30 23:39:24.139532', '2022-03-30 23:39:24.139532') RETURNING "id" /*application:MyApp,line:/Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/2.7.0/irb.rb:540:in `block (2 levels) in eval_input'*/
D, [2022-03-30T16:39:24.146245 #28421] DEBUG -- :   TRANSACTION (0.7ms)  COMMIT /*application:MyApp,line:/Users/jerome/.asdf/installs/ruby/2.7.1/lib/ruby/2.7.0/irb.rb:540:in `block (2 levels) in eval_input'*/
2
irb(main):002:0>

Thank you for making this cool gem!

Encrypted attributes printed in cleartext in error message

We've recently started using console1984. Thanks for the fantastic gem! We just noticed an issue where it leaks encrypted data, however, even without using decrypt. Simply take any model with encrypted attributes and attempt to call a method on it that doesn't exist. model.foobar => 'method_missing': undefined method 'last4' for #<inspect output with decrypted values>

I was curious if this is a known issue? Is this caused by a combination with another gem on our end? Where would we start to try and fix this?

Ast override makes is possible to bypass

Parser should be in the forbidden list, because it is still possible to bypass the protection by monkey-patching it:

class ::Parser::AST::Processor
	def on_const(node)
		node = [:String]
	end
end
conn = PG::Connection.open(:dbname => 'rails_edge_development')
conn.exec "delete from console1984_sessions"

Crashes on edge Rails

Since rails/rails#51760, apps using console1984 won't boot, because this line raises:

require 'rails/console/app'

I think that line is necessary, but I'm not sure how it works. If you comment it out, the test suite fails:

/Users/alex/code/console1984/lib/console1984/freezeable.rb:27:in `included': undefined method `thread_mattr_accessor' for Console1984::InputOutput:Module (NoMethodError)

    base.thread_mattr_accessor :prevent_instance_data_manipulation_after_freezing, default: true
        ^^^^^^^^^^^^^^^^^^^^^^
	from /Users/alex/code/console1984/lib/console1984/input_output.rb:2:in `include'
	from /Users/alex/code/console1984/lib/console1984/input_output.rb:2:in `<module:InputOutput>'
	from /Users/alex/code/console1984/lib/console1984/input_output.rb:1:in `<top (required)>'
	from /Users/alex/.rvm/gems/ruby-3.2.2/gems/zeitwerk-2.6.8/lib/zeitwerk/kernel.rb:30:in `require'
	from /Users/alex/.rvm/gems/ruby-3.2.2/gems/zeitwerk-2.6.8/lib/zeitwerk/kernel.rb:30:in `require'
	from /Users/alex/code/console1984/lib/console1984/supervisor.rb:4:in `<class:Supervisor>'
	from /Users/alex/code/console1984/lib/console1984/supervisor.rb:3:in `<top (required)>'
	from /Users/alex/.rvm/gems/ruby-3.2.2/gems/zeitwerk-2.6.8/lib/zeitwerk/kernel.rb:30:in `require'
	from /Users/alex/.rvm/gems/ruby-3.2.2/gems/zeitwerk-2.6.8/lib/zeitwerk/kernel.rb:30:in `require'
	from /Users/alex/code/console1984/lib/console1984.rb:43:in `<module:Console1984>'
	from /Users/alex/code/console1984/lib/console1984.rb:40:in `<top (required)>'

@st0012 are you able to advise?

Add password protection in console sessions

It currently asks for a name to log info, but with multiple folks having access any one can use anyone's name. Would be great to have a password issued to each user so they can use to only login using their password.

Add support for pry

Any statements entered while inside a pry console aren't added to the console1984_commands table.

Steps to reproduce

I created a dummy repo to test this. It's a vanilla rails new on version 7.0.4.2 with pry and console1984 added.

console1984-pry-test % CONSOLE_USER=james bin/rails c

# ... console1984 setup truncated ...

Loading development environment (Rails 7.0.4.2)
irb(main):001:0> puts "Before pry"
Before pry
=> nil                                                                           
irb(main):002:0> pry
[1] pry(main)> puts "Inside pry"
Inside pry                                                                       
=> nil                                                                           
[2] pry(main)> exit                                                              
=> nil                                                                           
irb(main):003:0> puts "After pry"
After pry
=> nil                                                                           
irb(main):004:0> exit

Expected logged commands

puts "Before pry"
pry
puts "Inside pry"
exit
puts "After pry"
exit

Actual logged commands

console1984-pry-test % bin/rails runner "puts Console1984::Session.last.commands.map(&:statements)"
puts "Before pry"
pry
puts "After pry"
exit

Extra info

rails version 7.0.4.2
console1984 version 0.1.26
pry version 0.14.2

I've tried gem "pry", require: false and changing the order of gems in the Gemfile, but the result always appears to be the same.

Question? Running in API only mode

Hi!
So was looking forward to trying this out, but I get the following error when running with a Rails app that is in api_only mode and this happens when trying to install the migration.

rails console1984:install:migrations

        16: from app/config/environment.rb:5:in `<main>'
	15: from /.rvm/gems/ruby-2.7.2/gems/railties-6.1.3.2/lib/rails/application.rb:384:in `initialize!'
	14: from /.rvm/gems/ruby-2.7.2/gems/railties-6.1.3.2/lib/rails/initializable.rb:60:in `run_initializers'
	13: from /.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/tsort.rb:205:in `tsort_each'
	12: from /.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/tsort.rb:226:in `tsort_each'
	11: from /.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/tsort.rb:347:in `each_strongly_connected_component'
	10: from /.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/tsort.rb:347:in `call'
	 9: from /.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/tsort.rb:347:in `each'
	 8: from /.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/tsort.rb:349:in `block in each_strongly_connected_component'
	 7: from /.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/tsort.rb:431:in `each_strongly_connected_component_from'
	 6: from /.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
	 5: from /.rvm/rubies/ruby-2.7.2/lib/ruby/2.7.0/tsort.rb:228:in `block in tsort_each'
	 4: from /.rvm/gems/ruby-2.7.2/gems/railties-6.1.3.2/lib/rails/initializable.rb:61:in `block in run_initializers'
	 3: from /.rvm/gems/ruby-2.7.2/gems/railties-6.1.3.2/lib/rails/initializable.rb:32:in `run'
	 2: from /.rvm/gems/ruby-2.7.2/gems/railties-6.1.3.2/lib/rails/initializable.rb:32:in `instance_exec'
	 1: from /.rvm/gems/ruby-2.7.2/gems/audits1984-0.1.1/lib/audits1984/engine.rb:22:in `block in <class:Engine>'
/.rvm/gems/ruby-2.7.2/gems/railties-6.1.3.2/lib/rails/railtie/configuration.rb:97:in `method_missing': undefined method `assets' for #<Rails::Application::Configuration:0x00007fec796d75a0> (NoMethodError)

Obviously I'm still running Rails6 - but I am pretty sure this error is unrelated to that and this is specific to being run on an api only application. I'm kinda missing where exactly the assets are being looked up from, but searching the repo I find this in the tests files which that line throws the same error if I just type into rails console.

I know this might not be a priority to fix (or even on the roadmap) but hopefully there might be a tweak we can make to ignore anything to do with assets (and leave the assets to audits1984?).
Either way - thanks for this and looking forward to a response!

Thanks!
-scott

NoMethodError: undefined method `thread_mattr_accessor' when generating migrations

Whenever you run rails console1984:install:migrations, you receive a NoMethodError.

Output of the command:

rails aborted!
NoMethodError: undefined method `thread_mattr_accessor' for Console1984:Module
/home/robert/critter/config/application.rb:18:in `<main>'
/home/robert/critter/Rakefile:6:in `<main>'
bin/rails:6:in `<main>'
(See full trace by running task with --trace)

ApplicationRecord::abstract_class not working

Hi,
I'm getting a really unexpected error.

Console1984::Command.table_name
=> "console1984_bases"

This comes just by testing the console in development and getting this error:

activerecord-7.0.4/lib/active_record/connection_adapters/postgresql/database_statements.rb:19:in `exec': PG::UndefinedTable: ERROR:  relation "console1984_bases" does not exist (ActiveRecord::StatementInvalid)
LINE 9:  WHERE a.attrelid = '"console1984_bases"'::regclass

Using:

  • rails: 7.0.4
  • ruby: 3.2.0 (mri)
  • pg: 1.4.5
  • audits1984: 0.1.2
  • console1984: 0.1.26

Of course that happens with all the models:

Loading development environment (Rails 7.0.4)
[1](main)> Console1984::Command.table_name
=> "console1984_bases"
[2](main)> Console1984::SensitiveAccess.table_name
=> "console1984_bases"
[3](main)> Console1984::Session.table_name
=> "console1984_bases"
[4](main)> Console1984::User.table_name
=> "console1984_bases"

rails documentation

Avoid potential data corruption by allowing decryption by default

In our app we have methods that read encrypted attributes from one record and save them in another record.

# first_name is encrypted
user = User.find(id)
other_user = User.find(other_id)
other_user.first_name = user.first_name
other_user.save!

My worry is that someone does this in a (production) console without running decrypt! first potentially corrupting other_user (which will now have the encrypted version of first_name encrypted again and saved instead of first_name).

How do you avoid this?

Potential solution could be to make encryption optional (we mainly use console1984 for the logging and auditing so we could turn it off).

Another solution could be to not decrypt console output but to still make any other output decrypted (maybe also make this a configuration option).

Not able to access protected mode

When i try to access protected mode, it returns nil and i am still in unprotected mode. I am running Ruby 3.1.0 and Rails 7.0.2.3

decrypt!

Ok! You have access to encrypted information now. We pay extra close attention to any commands entered while you have this access. You can go back to protected mode with 'encrypt!'                                                        
                                                                         
WARNING: Make sure you don't save objects that were loaded while in protected mode, as this can result in saving the encrypted texts.
                                                                         
                                                                         
                                                                         
Before you can access personal information, you need to ask for and get explicit consent from the user(s). Drale2k, where can we find this consent (a URL would be great)?
can be found in email
=> nil 

User.first.first_name

  User Load (1.3ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1  [["LIMIT", 1]]
=> "{\"p\":\"tO1k0DL6\",\"h\":{\"iv\":\"u0qCh3ipBClxk8p6\",\"at\":\"ZjRwQReAdfJAr2+CABnkLg==\"}}"

I am using the following config

config.active_record.encryption.support_unencrypted_data = true
config.console1984.protected_environments = %i[ production development ]

The above test was done on production and locally in development - both with the same result.

Can't open a console with rails master

@jorgemanrubia I wanted to try to bypass the protection after the latest improvements, but I can't even open a console due to a weird ActiveRecord error:

Unnamed, why are you using this console today?
testing...
Traceback (most recent call last):
	32: from bin/rails:5:in `<main>'
	31: from bin/rails:5:in `require'
	30: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/bundler/gems/rails-a692e63bf400/railties/lib/rails/commands.rb:18:in `<top (required)>'
	29: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/bundler/gems/rails-a692e63bf400/railties/lib/rails/command.rb:48:in `invoke'
	28: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/bundler/gems/rails-a692e63bf400/railties/lib/rails/command/base.rb:87:in `perform'
	27: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/thor-1.1.0/lib/thor.rb:392:in `dispatch'
	26: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/thor-1.1.0/lib/thor/invocation.rb:127:in `invoke_command'
	25: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/gems/thor-1.1.0/lib/thor/command.rb:27:in `run'
	24: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/bundler/gems/rails-a692e63bf400/railties/lib/rails/commands/console/console_command.rb:102:in `perform'
	23: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/bundler/gems/rails-a692e63bf400/railties/lib/rails/commands/console/console_command.rb:19:in `start'
	22: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/bundler/gems/rails-a692e63bf400/railties/lib/rails/commands/console/console_command.rb:19:in `new'
	21: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/bundler/gems/rails-a692e63bf400/railties/lib/rails/commands/console/console_command.rb:35:in `initialize'
	20: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/bundler/gems/rails-a692e63bf400/railties/lib/rails/engine.rb:449:in `load_console'
	19: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/bundler/gems/rails-a692e63bf400/railties/lib/rails/application.rb:522:in `run_console_blocks'
	18: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/bundler/gems/rails-a692e63bf400/railties/lib/rails/engine/railties.rb:15:in `each'
	17: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/bundler/gems/rails-a692e63bf400/railties/lib/rails/engine/railties.rb:15:in `each'
	16: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/bundler/gems/rails-a692e63bf400/railties/lib/rails/application.rb:522:in `block in run_console_blocks'
	15: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/bundler/gems/rails-a692e63bf400/railties/lib/rails/railtie.rb:250:in `run_console_blocks'
	14: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/bundler/gems/rails-a692e63bf400/railties/lib/rails/railtie.rb:275:in `each_registered_block'
	13: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/bundler/gems/rails-a692e63bf400/railties/lib/rails/railtie.rb:275:in `each'
	12: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/bundler/gems/rails-a692e63bf400/railties/lib/rails/railtie.rb:250:in `block in run_console_blocks'
	11: from /Users/gregmolnar/Git/console1984/lib/console1984/engine.rb:24:in `block in <class:Engine>'
	10: from /Users/gregmolnar/Git/console1984/lib/console1984/supervisor.rb:25:in `start'
	 9: from /Users/gregmolnar/Git/console1984/lib/console1984/supervisor.rb:51:in `start_session'
	 8: from /Users/gregmolnar/Git/console1984/lib/console1984/sessions_logger/database.rb:8:in `start_session'
	 7: from /Users/gregmolnar/Git/console1984/lib/console1984/sessions_logger/database.rb:53:in `silence_logging'
	 6: from /Users/gregmolnar/Git/console1984/lib/console1984/sessions_logger/database.rb:9:in `block in start_session'
	 5: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/bundler/gems/rails-a692e63bf400/activerecord/lib/active_record/querying.rb:22:in `find_or_create_by!'
	 4: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/bundler/gems/rails-a692e63bf400/activerecord/lib/active_record/relation.rb:182:in `find_or_create_by!'
	 3: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/bundler/gems/rails-a692e63bf400/activerecord/lib/active_record/relation/finder_methods.rb:81:in `find_by'
	 2: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/bundler/gems/rails-a692e63bf400/activerecord/lib/active_record/relation/query_methods.rb:715:in `where'
	 1: from /Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/bundler/gems/rails-a692e63bf400/activerecord/lib/active_record/relation/query_methods.rb:720:in `where!'
/Users/gregmolnar/.rbenv/versions/2.7.2/lib/ruby/gems/2.7.0/bundler/gems/rails-a692e63bf400/activerecord/lib/active_record/relation/query_methods.rb:124:in `where_clause': uninitialized constant ActiveRecord::QueryMethods::Relation (NameError)
Did you mean?  ActiveRecord::Relation

If I remove the console1984 from my Gemfile, ActiveRecord works as expected. Do you have any idea what causes this?

ActiveRecord::ConnectionAdapters::SQLite3Adapter (FrozenError)

Hi everyone,

We have recently updated our application to Ruby 3.0.2 and Rails 7.0.0.alpha2 so I wanted to try console1984. I've enabled it in development environment but I am getting ActiveRecord::ConnectionAdapters::PostgreSQLAdapter (FrozenError).

To make sure it is not caused by our application I created new vanila rails app (ruby 3.0.2 and rails 7.0.0.alpha2) with console1984 but problem stayed the same but with SQLite database.

Here is the stacktrace from test app:

[consoletest#main]→ rails c


You have access to production data here. That's a big deal. As part of our promise to keep customer data safe and private, we audit the commands you type here. Let's get started!



Commands:

* decrypt!: enter unprotected mode with access to encrypted information

Unnamed, why are you using this console today?
asdfsadf
/Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/connection_adapters/abstract_adapter.rb:79:in `quoted_table_names': can't modify frozen #<Class:ActiveRecord::ConnectionAdapters::SQLite3Adapter>: ActiveRecord::ConnectionAdapters::SQLite3Adapter (FrozenError)
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/connection_adapters/sqlite3/quoting.rb:16:in `quote_table_name'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/connection_adapters/sqlite3_adapter.rb:386:in `table_structure'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/connection_adapters/abstract/schema_statements.rb:116:in `columns'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/connection_adapters/schema_cache.rb:117:in `block in columns'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/connection_adapters/schema_cache.rb:116:in `fetch'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/connection_adapters/schema_cache.rb:116:in `columns'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/connection_adapters/schema_cache.rb:125:in `block in columns_hash'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/connection_adapters/schema_cache.rb:124:in `fetch'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/connection_adapters/schema_cache.rb:124:in `columns_hash'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/model_schema.rb:568:in `load_schema!'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/attributes.rb:264:in `load_schema!'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/encryption/encryptable_record.rb:124:in `load_schema!'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/model_schema.rb:554:in `block in load_schema'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/model_schema.rb:551:in `synchronize'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/model_schema.rb:551:in `load_schema'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/model_schema.rb:417:in `attribute_types'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/model_schema.rb:443:in `type_for_attribute'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/type_caster/map.rb:16:in `type_for_attribute'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/arel/table.rb:107:in `type_for_attribute'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/table_metadata.rb:18:in `type'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/relation/predicate_builder.rb:59:in `build'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/relation/predicate_builder.rb:54:in `[]'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/relation/predicate_builder.rb:126:in `block in expand_from_hash'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/relation/predicate_builder.rb:79:in `each'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/relation/predicate_builder.rb:79:in `flat_map'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/relation/predicate_builder.rb:79:in `expand_from_hash'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/relation/predicate_builder.rb:25:in `build_from_hash'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/relation/query_methods.rb:1277:in `build_where_clause'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/relation/query_methods.rb:720:in `where!'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/relation/query_methods.rb:715:in `where'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/relation/finder_methods.rb:81:in `find_by'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/relation.rb:182:in `find_or_create_by!'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activerecord-7.0.0.alpha2/lib/active_record/querying.rb:22:in `find_or_create_by!'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/console1984-0.1.15/lib/console1984/sessions_logger/database.rb:9:in `block in start_session'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activesupport-7.0.0.alpha2/lib/active_support/logger_silence.rb:18:in `block in silence'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activesupport-7.0.0.alpha2/lib/active_support/logger_thread_safe_level.rb:44:in `log_at'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activesupport-7.0.0.alpha2/lib/active_support/logger_silence.rb:18:in `silence'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activesupport-7.0.0.alpha2/lib/active_support/logger.rb:64:in `block (3 levels) in broadcast'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activesupport-7.0.0.alpha2/lib/active_support/logger_silence.rb:18:in `block in silence'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activesupport-7.0.0.alpha2/lib/active_support/logger_thread_safe_level.rb:44:in `log_at'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activesupport-7.0.0.alpha2/lib/active_support/logger_silence.rb:18:in `silence'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activesupport-7.0.0.alpha2/lib/active_support/logger.rb:62:in `block (2 levels) in broadcast'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/console1984-0.1.15/lib/console1984/sessions_logger/database.rb:56:in `block in silence_logging'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activesupport-7.0.0.alpha2/lib/active_support/logger_silence.rb:18:in `block in silence'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activesupport-7.0.0.alpha2/lib/active_support/logger_thread_safe_level.rb:44:in `log_at'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activesupport-7.0.0.alpha2/lib/active_support/logger_silence.rb:18:in `silence'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activesupport-7.0.0.alpha2/lib/active_support/logger.rb:64:in `block (3 levels) in broadcast'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activesupport-7.0.0.alpha2/lib/active_support/logger_silence.rb:18:in `block in silence'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activesupport-7.0.0.alpha2/lib/active_support/logger_thread_safe_level.rb:44:in `log_at'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activesupport-7.0.0.alpha2/lib/active_support/logger_silence.rb:18:in `silence'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/activesupport-7.0.0.alpha2/lib/active_support/logger.rb:62:in `block (2 levels) in broadcast'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/console1984-0.1.15/lib/console1984/sessions_logger/database.rb:55:in `silence_logging'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/console1984-0.1.15/lib/console1984/sessions_logger/database.rb:8:in `start_session'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/console1984-0.1.15/lib/console1984/supervisor.rb:57:in `start_session'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/console1984-0.1.15/lib/console1984/supervisor.rb:25:in `start'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/console1984-0.1.15/lib/console1984/engine.rb:24:in `block in <class:Engine>'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/railties-7.0.0.alpha2/lib/rails/railtie.rb:250:in `block in run_console_blocks'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/railties-7.0.0.alpha2/lib/rails/railtie.rb:275:in `each'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/railties-7.0.0.alpha2/lib/rails/railtie.rb:275:in `each_registered_block'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/railties-7.0.0.alpha2/lib/rails/railtie.rb:250:in `run_console_blocks'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/railties-7.0.0.alpha2/lib/rails/application.rb:522:in `block in run_console_blocks'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/railties-7.0.0.alpha2/lib/rails/engine/railties.rb:15:in `each'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/railties-7.0.0.alpha2/lib/rails/engine/railties.rb:15:in `each'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/railties-7.0.0.alpha2/lib/rails/application.rb:522:in `run_console_blocks'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/railties-7.0.0.alpha2/lib/rails/engine.rb:449:in `load_console'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/railties-7.0.0.alpha2/lib/rails/commands/console/console_command.rb:35:in `initialize'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/railties-7.0.0.alpha2/lib/rails/commands/console/console_command.rb:19:in `new'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/railties-7.0.0.alpha2/lib/rails/commands/console/console_command.rb:19:in `start'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/railties-7.0.0.alpha2/lib/rails/commands/console/console_command.rb:102:in `perform'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/thor-1.1.0/lib/thor/command.rb:27:in `run'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/thor-1.1.0/lib/thor/invocation.rb:127:in `invoke_command'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/thor-1.1.0/lib/thor.rb:392:in `dispatch'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/railties-7.0.0.alpha2/lib/rails/command/base.rb:87:in `perform'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/railties-7.0.0.alpha2/lib/rails/command.rb:48:in `invoke'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/railties-7.0.0.alpha2/lib/rails/commands.rb:18:in `<main>'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/bootsnap-1.9.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/bootsnap-1.9.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/bootsnap-1.9.1/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/bootsnap-1.9.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
	from /Users/edariedl/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/bootsnap-1.9.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
	from bin/rails:4:in `<main>'

Everything works fine without console1984. Is there something I might have done wrong or it is possible it might be some weird bug?

Freezable triggers on external objects when using fibers

Because thread_mattr_accessor uses Thread.current[], doing self.prevent_instance_data_manipulation_after_freezing = false in the Object extension doesn't work when using fibers (it defaults to true). FWIW discussions in rails/rails#19693 seem related.

In our case we set config.active_support.isolation_level = :fiber in the Rails config.

For instance:

/usr/local/bundle/gems/console1984-0.1.31/lib/console1984/freezeable.rb:42:in `block in prevent_sensitive_method': You can't invoke instance_variable_get on #<ActiveRecord::Reflection::RuntimeReflection:0x00007fb3f5340700> (Console1984::Errors::ForbiddenCommandAttempted)
        from /usr/local/bundle/bundler/gems/activerecord-jsonb-associations-dde23b72bdb7/lib/activerecord/jsonb/associations/association_scope.rb:7:in `last_chain_scope'
        from /usr/local/bundle/gems/activerecord-7.1.3/lib/active_record/associations/association_scope.rb:125:in `add_constraints'
        from /usr/local/bundle/gems/activerecord-7.1.3/lib/active_record/associations/association_scope.rb:29:in `scope'

Any reason to use thread_mattr_accessor in this case versus mattr_accessor?

Incompatibility with the google-api-client gem

It seems that there is some incompatibility between this gem and the google-api-client gem.

I hesitated between posting here or in the googleapis/google-api-ruby-client repo, please let me know if I should post there instead.

Error message

When starting a console session in my development environment, I get the following error:

~/c/tmp/my_app $ CONSOLE_USER=jerome rails c
/Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/uber-0.1.0/lib/uber/inheritable_attr.rb:12:in `map': uninitialized constant #<Class:Representable::Decorator>::InheritableAttribute (NameError)

          @map = InheritableAttribute.inherit_for(self, :map, {})
                 ^^^^^^^^^^^^^^^^^^^^
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/representable-3.1.1/lib/representable/cached.rb:9:in `block in build_definition'
        from <internal:kernel>:90:in `tap'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/representable-3.1.1/lib/representable/cached.rb:6:in `build_definition'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/declarative-0.0.20/lib/declarative/schema.rb:25:in `property'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/google-apis-core-0.4.2/lib/google/apis/core/json_representation.rb:100:in `property'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/google-api-client-0.53.0/generated/google/apis/webmasters_v3/representations.rb:88:in `<class:Representation>'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/google-api-client-0.53.0/generated/google/apis/webmasters_v3/representations.rb:87:in `<class:ApiDataRow>'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/google-api-client-0.53.0/generated/google/apis/webmasters_v3/representations.rb:85:in `<module:WebmastersV3>'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/google-api-client-0.53.0/generated/google/apis/webmasters_v3/representations.rb:23:in `<module:Apis>'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/google-api-client-0.53.0/generated/google/apis/webmasters_v3/representations.rb:22:in `<module:Google>'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/google-api-client-0.53.0/generated/google/apis/webmasters_v3/representations.rb:21:in `<main>'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/bootsnap-1.11.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/bootsnap-1.11.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/kernel.rb:35:in `require'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/google-api-client-0.53.0/generated/google/apis/webmasters_v3.rb:17:in `<main>'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/bootsnap-1.11.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/bootsnap-1.11.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/kernel.rb:35:in `require'
        from /Users/jerome/c/tmp/my_app/app/models/foo.rb:1:in `<main>'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/bootsnap-1.11.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/bootsnap-1.11.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/kernel.rb:27:in `require'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/console1984-0.1.24/lib/console1984/ext/core/object.rb:34:in `const_get'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/console1984-0.1.24/lib/console1984/ext/core/object.rb:34:in `const_get'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/loader/helpers.rb:95:in `cget'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/loader.rb:237:in `block (2 levels) in eager_load'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/loader/helpers.rb:26:in `block in ls'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/loader/helpers.rb:18:in `each_child'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/loader/helpers.rb:18:in `ls'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/loader.rb:232:in `block in eager_load'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/loader.rb:217:in `synchronize'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/zeitwerk-2.5.4/lib/zeitwerk/loader.rb:217:in `eager_load'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/railties-7.0.2.3/lib/rails/autoloaders.rb:32:in `each'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/railties-7.0.2.3/lib/rails/application.rb:497:in `eager_load!'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/console1984-0.1.24/lib/console1984/refrigerator.rb:15:in `eager_load_all_classes'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/console1984-0.1.24/lib/console1984/refrigerator.rb:6:in `freeze_all'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/console1984-0.1.24/lib/console1984/shield.rb:24:in `install'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/console1984-0.1.24/lib/console1984/supervisor.rb:15:in `install'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/console1984-0.1.24/lib/console1984/engine.rb:23:in `block in <class:Engine>'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/railties-7.0.2.3/lib/rails/railtie.rb:267:in `block in run_console_blocks'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/railties-7.0.2.3/lib/rails/railtie.rb:292:in `each'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/railties-7.0.2.3/lib/rails/railtie.rb:292:in `each_registered_block'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/railties-7.0.2.3/lib/rails/railtie.rb:267:in `run_console_blocks'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/railties-7.0.2.3/lib/rails/application.rb:525:in `block in run_console_blocks'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/railties-7.0.2.3/lib/rails/engine/railties.rb:15:in `each'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/railties-7.0.2.3/lib/rails/engine/railties.rb:15:in `each'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/railties-7.0.2.3/lib/rails/application.rb:525:in `run_console_blocks'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/railties-7.0.2.3/lib/rails/engine.rb:449:in `load_console'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/railties-7.0.2.3/lib/rails/commands/console/console_command.rb:35:in `initialize'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/railties-7.0.2.3/lib/rails/commands/console/console_command.rb:19:in `new'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/railties-7.0.2.3/lib/rails/commands/console/console_command.rb:19:in `start'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/railties-7.0.2.3/lib/rails/commands/console/console_command.rb:102:in `perform'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/thor-1.2.1/lib/thor/command.rb:27:in `run'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/thor-1.2.1/lib/thor/invocation.rb:127:in `invoke_command'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/thor-1.2.1/lib/thor.rb:392:in `dispatch'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/railties-7.0.2.3/lib/rails/command/base.rb:87:in `perform'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/railties-7.0.2.3/lib/rails/command.rb:48:in `invoke'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/railties-7.0.2.3/lib/rails/commands.rb:18:in `<main>'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/bootsnap-1.11.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
        from /Users/jerome/.asdf/installs/ruby/3.1.0/lib/ruby/gems/3.1.0/gems/bootsnap-1.11.1/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
        from bin/rails:4:in `<main>'

Steps to repro

  1. Make a new Rails 7 app

  2. Install the console1984 gem

  3. Use the following in application.rb:

    config.console1984.protected_environments = %i(development staging production)
  4. Add gem 'google-api-client' in your gemfile and run bundle install

  5. Create the following file:

    # app/models/foo.rb
    require 'google/apis/webmasters_v3'
    
    class Foo
    end
  6. Run CONSOLE_USER=your_name rails c

  7. The error message I mentioned appears

Other notes

  • The issue also happens if you skip step 5, launch the rails console successfully, and type require 'google/apis/webmasters_v3'
  • require 'google/apis/webmasters_v3' works fine if console1984 is not installed

`rails console --sandbox` allows for untracked read-only access to the database, including decryption of values

As the name suggests, storing console session data in the primary database results in the session record being rolled back in a transaction when running rails console --sandbox once it terminates.

While I'm not sure there's an actual "fix" to this behavior (it seems to be working as intended), I'd be interested to understand if the team would find an update to the README documenting this useful. I'd be happy to add a line or two about this if so.

Receiving notifications for specific commands

Hello @jorgemanrubia. I'd like to receive a notification every time a specific command is executed (for instance, every time a decrypt! is invoked).

Is that something you'd consider adding? I'd be glad to jump on it myself, so If you have any suggestions on such implementation I'd love to hear it.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.