Module: Omen::Inquirer
- Defined in:
- lib/omen/inquirer.rb
Overview
The Postgres role a reading's own SELECT runs as, blind to the tables a reading is kept in. It needs no database.yml entry of its own: NOLOGIN, it is a privilege container reached with SET LOCAL ROLE and never connected as.
Constant Summary collapse
- WHOEVER =
Whom to ask, since the role a host reads through is one this gem has no name for.
'SELECT current_user'- UNGRANTED =
Said on the way through installation step one, where a host has yet to declare the role.
'No %{role} connection is configured, so nothing was granted to whatever ' \ 'reads through it. Run this again once config/database.yml names one.'
- UNMADE =
Said where the role could not be made: a managed database never grants CREATEROLE.
'Could not make %{role}, so every reading will say this app is misconfigured. Ask ' \ 'for that role, NOLOGIN, granted SELECT on every table but %{tables}.'
- REFUSED =
Said per statement, since the grants, the revocations and the functions need nothing from one another and one refusal should not discard the rest.
'Skipped, refused by the database: %{statement} (%{error})'- DANGEROUS =
Said where a role that already existed is one a reading should not be able to reach through.
'%{role} holds %{held}. This gem cannot take that away without being a superuser ' \ 'itself, so ask for it to be taken away.'
Class Method Summary collapse
-
.attempted(connection, statement) ⇒ void
One statement at a time, so a database that refuses one still runs the others -- and each inside a savepoint of its own, since a refusal inside a transaction refuses everything after it too, and this task is as likely to be run from a console as from a deploy.
-
.environments ⇒ Array<String>
The environments whose databases this run should cover.
-
.grant ⇒ void
Creates the role and the function, on every database this environment prepares.
-
.grant_on(connection) ⇒ void
Warns rather than raises: a managed database never grants CREATEROLE, and a deploy that cannot make the role must still finish, having said what has to be made by hand.
-
.reader ⇒ String?
Discovered rather than named: SET LOCAL ROLE needs the connecting role to be a member of this one, and the role a host's reading connection logs in as is the host's own business.
Class Method Details
.attempted(connection, statement) ⇒ void
This method returns an undefined value.
One statement at a time, so a database that refuses one still runs the others -- and each inside a savepoint of its own, since a refusal inside a transaction refuses everything after it too, and this task is as likely to be run from a console as from a deploy.
65 66 67 68 69 |
# File 'lib/omen/inquirer.rb', line 65 def self.attempted(connection, statement) connection.transaction(requires_new: true) { connection.execute statement } rescue ActiveRecord::StatementInvalid => error warn REFUSED % { statement: statement.squish, error: error..lines.first.strip } end |
.environments ⇒ Array<String>
Returns the environments whose databases this run should cover.
39 |
# File 'lib/omen/inquirer.rb', line 39 def self.environments = Rails.env.development? ? %w[ development test ] : [Rails.env.to_s] |
.grant ⇒ void
This method returns an undefined value.
Creates the role and the function, on every database this environment prepares.
27 28 29 30 31 32 33 34 35 36 |
# File 'lib/omen/inquirer.rb', line 27 def self.grant environments.each do |environment| config = ActiveRecord::Base.configurations.configs_for env_name: environment, name: 'primary' next unless config ActiveRecord::Tasks::DatabaseTasks.with_temporary_connection config do |connection| grant_on connection end end end |
.grant_on(connection) ⇒ void
This method returns an undefined value.
Warns rather than raises: a managed database never grants CREATEROLE, and a deploy that cannot make the role must still finish, having said what has to be made by hand.
45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/omen/inquirer.rb', line 45 def self.grant_on(connection) read_by = reader warn UNGRANTED % { role: Omen.config.reading_role } unless read_by members = [ read_by, connection.select_value(WHOEVER) ].compact Grants.statements(connection, members).each { |statement| attempted connection, statement } role = Omen.config.narrow_role return warn UNMADE % { role: role, tables: Omen.tables.to_sentence } unless Attributes.exists? connection held = Attributes.dangerous connection warn DANGEROUS % { role: role, held: held.to_sentence } if held.any? puts "Granted SELECT on #{connection.current_database} to #{role}" end |
.reader ⇒ String?
Discovered rather than named: SET LOCAL ROLE needs the connecting role to be a member of this one, and the role a host's reading connection logs in as is the host's own business.
74 75 76 77 78 79 80 |
# File 'lib/omen/inquirer.rb', line 74 def self.reader Omen.config.record.connected_to role: Omen.config.reading_role do Omen.config.record.with_connection { |connection| connection.select_value WHOEVER } end rescue ActiveRecord::ConnectionNotDefined, ActiveRecord::ConnectionNotEstablished nil end |