Module: Omen::Grants
- Defined in:
- lib/omen/grants.rb
Overview
Everything said to a database to make the role a statement runs as: what it may be, what it may read, and what it may not. Kept apart from the task that runs them, which is about a database it has to find and a refusal it has to survive rather than about privileges.
Constant Summary collapse
- APART =
Membership without inheritance, so a role that enters a narrowed one with SET LOCAL ROLE is not itself held back by its policies. Postgres 16 and later; below that the grant is refused and the task says so, which leaves a reading misconfigured rather than narrowing somebody nobody meant to narrow.
'GRANT %{role} TO %{member} WITH INHERIT FALSE'
Class Method Summary collapse
-
.apart(role, member) ⇒ String
The statement that lets it in without handing it what the role holds.
-
.granted(connection, name, table, refused) ⇒ Array<String>
Named one by one rather than granted whole: a column added to hold a secret, or to count what belongs to everybody, is one a role has to be given before it can read it.
-
.made(connection, name, login: false) ⇒ Array<String>
The statements that make it and say what it may be.
-
.narrowed(connection, name, members) ⇒ Array<String>
Who may enter the role, and the schema it reads in.
-
.revoked(connection, role) ⇒ Array<String>
Intersected, so a bare db:create with no table yet to revoke on is not a failure.
-
.statements(connection, members) ⇒ Array<String>
DDL, which Active Record has no expression for, and not a query.
Class Method Details
.apart(role, member) ⇒ String
Returns the statement that lets it in without handing it what the role holds.
52 |
# File 'lib/omen/grants.rb', line 52 def self.apart(role, member) = APART % { role: role, member: member } |
.granted(connection, name, table, refused) ⇒ Array<String>
Named one by one rather than granted whole: a column added to hold a secret, or to count what belongs to everybody, is one a role has to be given before it can read it. Taken away first, since a grant only ever adds: without the revoke, a column dropped from the list stays readable by whoever was granted it the last time this ran.
63 64 65 66 67 68 69 70 |
# File 'lib/omen/grants.rb', line 63 def self.granted(connection, name, table, refused) role = connection.quote_table_name name quoted = connection.quote_table_name table columns = connection.columns(table).map(&:name).grep_v(refused) .map { |column| connection.quote_column_name column } [ "REVOKE ALL ON #{quoted} FROM #{role}", "GRANT SELECT (#{columns.join ', '}) ON #{quoted} TO #{role}", ] end |
.made(connection, name, login: false) ⇒ Array<String>
Returns the statements that make it and say what it may be.
76 77 78 79 80 81 82 |
# File 'lib/omen/grants.rb', line 76 def self.made(connection, name, login: false) role = connection.quote_table_name name entered = login ? 'LOGIN' : 'NOLOGIN' [ 'DO $$ BEGIN IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = ' \ "#{connection.quote name}) THEN CREATE ROLE #{role} #{entered}; END IF; END $$", "ALTER ROLE #{role} WITH #{Attributes.settable login: login}", ] end |
.narrowed(connection, name, members) ⇒ Array<String>
Who may enter the role, and the schema it reads in. Kept apart from making the role: a managed database refuses to make one at all, and a refusal takes its whole transaction with it -- so membership granted in the same breath would be lost to a role that was already there and only needed letting into.
41 42 43 44 45 46 47 |
# File 'lib/omen/grants.rb', line 41 def self.narrowed(connection, name, members) role = connection.quote_table_name name [ *members.map { |member| apart role, connection.quote_table_name(member) }, "GRANT USAGE ON SCHEMA public TO #{role}", ] end |
.revoked(connection, role) ⇒ Array<String>
Intersected, so a bare db:create with no table yet to revoke on is not a failure.
88 89 90 91 92 |
# File 'lib/omen/grants.rb', line 88 def self.revoked(connection, role) (connection.tables & Omen.tables).map do |table| "REVOKE SELECT ON #{connection.quote_table_name table} FROM #{role}" end end |
.statements(connection, members) ⇒ Array<String>
DDL, which Active Record has no expression for, and not a query.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/omen/grants.rb', line 18 def self.statements(connection, members) role = connection.quote_table_name Omen.config.narrow_role [ *made(connection, Omen.config.narrow_role), *members.map { |member| "GRANT #{role} TO #{connection.quote_table_name member}" }, "GRANT USAGE ON SCHEMA public TO #{role}", "GRANT SELECT ON ALL TABLES IN SCHEMA public TO #{role}", "ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO #{role}", *revoked(connection, role), *Omen::Renamed.statements, *Omen::TimeZone.statements(connection), *Omen::Distance.statements(connection), ] end |