Class: CurrentScope::Configuration
- Inherits:
-
Object
- Object
- CurrentScope::Configuration
- Defined in:
- lib/current_scope/configuration.rb
Constant Summary collapse
- PROD_MUTATIONS_ENV =
Env var that opts a PRODUCTION deploy into impersonated writes. Any value (even "false" or "0" — presence is what counts) lifts the production refusal; unset in production means allow_mutations_while_impersonating=true raises at boot. development/test/staging never consult it.
"CURRENT_SCOPE_ALLOW_PROD_IMPERSONATION_MUTATIONS"
Instance Attribute Summary collapse
-
#actor_method ⇒ Object
Host controller method returning the REAL actor while impersonating (the pretender's true_user).
-
#allow_mutations_while_impersonating ⇒ Object
When false (the default), an impersonated session is read-only: any non-GET/HEAD request is denied while a real actor acts as a different subject — INCLUDING the engine's own management UI.
-
#allow_sod_bypass ⇒ Object
Break-glass override for the SoD veto.
-
#audit ⇒ Object
Tri-state: false | true (default) | :strict — controls CurrentScope::Event.record!.
-
#excluded_controllers ⇒ Object
Regexps matched against controller paths to keep infrastructure controllers out of the permission grid.
-
#parent_controller ⇒ Object
Class the management UI's controllers inherit from, so they pick up the host's authentication and layout.
-
#permission_grid_groups ⇒ Object
How the role-editor grid folds RESTful actions into columns.
-
#sod_actions ⇒ Object
Action names subject to the separation-of-duties veto: whoever initiated a record can never perform these actions on it.
-
#sod_bypass_permission ⇒ Object
The grantable permission the record's initiator must hold for a break-glass bypass to lift the veto (default "bypass_sod").
-
#sod_identity ⇒ Object
Which identities the separation-of-duties veto weighs: :either (default) — veto if the effective subject OR (while impersonating) the REAL actor initiated the record, so impersonation can never approve the actor's own record.
-
#subject_class ⇒ Object
Host class acting as the subject, used by the management UI to list assignable subjects.
-
#subject_label ⇒ Object
How a subject is identified in the management UI (subjects table, picker, bulk bar).
-
#user_method ⇒ Object
Host controller method that returns the authenticated subject.
-
#warn_on_nil_sod_record ⇒ Object
A5 (opt-in, dev/test aid): when true, the gate logs a nudge if an SoD action is gated with a nil record and the request is allowed — i.e.
Instance Method Summary collapse
-
#initialize ⇒ Configuration
constructor
A new instance of Configuration.
Constructor Details
#initialize ⇒ Configuration
Returns a new instance of Configuration.
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/current_scope/configuration.rb', line 132 def initialize @user_method = :current_user @actor_method = nil @sod_actions = [] @sod_identity = :either @allow_sod_bypass = false @sod_bypass_permission = "bypass_sod" @allow_mutations_while_impersonating = false @excluded_controllers = [ %r{\Arails/}, %r{\Aactive_storage/}, %r{\Aaction_mailbox/}, %r{\Aturbo/}, %r{\Acurrent_scope/} ] @parent_controller = "::ApplicationController" @subject_class = "User" @audit = true @warn_on_nil_sod_record = false @permission_grid_groups = { "read" => %w[index show], "create" => %w[new create], "update" => %w[edit update], "destroy" => %w[destroy] } end |
Instance Attribute Details
#actor_method ⇒ Object
Host controller method returning the REAL actor while impersonating (the pretender's true_user). nil means actor == user (no impersonation), so the actor is never resolved and falls back to the subject.
9 10 11 |
# File 'lib/current_scope/configuration.rb', line 9 def actor_method @actor_method end |
#allow_mutations_while_impersonating ⇒ Object
When false (the default), an impersonated session is read-only: any non-GET/HEAD request is denied while a real actor acts as a different subject — INCLUDING the engine's own management UI. The host's stop-impersonation, sign-out, and sign-in endpoints must opt out with skip_before_action :current_scope_mutation_guard!, or impersonation can never end. The gate runs BEFORE the permission check, so sod_identity is only observable once mutations are allowed (or on a GET-listed sod_action).
Setting this true is refused in production unless the env opt-in below is set — letting a real actor write as someone else is a privilege-escalation and audit-integrity risk, so a prod deploy must acknowledge it explicitly. See the custom writer.
43 44 45 |
# File 'lib/current_scope/configuration.rb', line 43 def allow_mutations_while_impersonating @allow_mutations_while_impersonating end |
#allow_sod_bypass ⇒ Object
Break-glass override for the SoD veto. Default false — OFF preserves v0.1
exactly: the separation-of-duties veto is absolute and this hook is never
consulted. When true, the veto is lifted for a record ONLY when all three
hold, re-checked live at decision time: this flag is on, the record's
current_scope_sod_bypassed? hook returns true, AND the record's initiator
holds the bypass permission (sod_bypass_permission). Every lifted veto is
recorded by the engine (sod.bypassed) and surfaced on
X-Current-Scope-Reason.
HONEST FRAMING: this converts SoD from a structural guarantee into an audited policy override — it's break-glass, not SoD. Its legitimacy rests on being default-off, privilege-gated, and always audited. Unlike allow_mutations_while_impersonating there is NO production env-gate: the feature is per-record, privilege-scoped, and audited-by-construction, so production is its intended home.
89 90 91 |
# File 'lib/current_scope/configuration.rb', line 89 def allow_sod_bypass @allow_sod_bypass end |
#audit ⇒ Object
Tri-state: false | true (default) | :strict — controls
CurrentScope::Event.record!.
false — record! is a silent no-op; hosts that don't want the ledger
set this and skip the events migration.
true — append a row for every event; if the current_scope_events
table hasn't been migrated yet, degrade gracefully (skip +
warn once), so an existing host never breaks on first mutation.
:strict — an audit-mandatory host: a missing events table RAISES instead
of degrading, so a mutation-wrapping transaction rolls back
rather than committing an unaudited grant. (Impersonation-
boundary events have no mutation to roll back — a raise there
is a loud 500 on a mis-migrated host.)
Read as == :strict, never == true — don't flatten the tri-state.
111 112 113 |
# File 'lib/current_scope/configuration.rb', line 111 def audit @audit end |
#excluded_controllers ⇒ Object
Regexps matched against controller paths to keep infrastructure controllers out of the permission grid. An excluded controller cannot be granted, so it must also skip the gate (skip_before_action :current_scope_check!) — Guard raises otherwise.
55 56 57 |
# File 'lib/current_scope/configuration.rb', line 55 def excluded_controllers @excluded_controllers end |
#parent_controller ⇒ Object
Class the management UI's controllers inherit from, so they pick up the host's authentication and layout.
59 60 61 |
# File 'lib/current_scope/configuration.rb', line 59 def parent_controller @parent_controller end |
#permission_grid_groups ⇒ Object
How the role-editor grid folds RESTful actions into columns. An ordered Hash of { column_label => [action names] }: ticking a group column grants every routed action in it. The default collapses the seven RESTful verbs into CRUD — new/create and edit/update pair up (the "new"/"edit" actions just render the form for their mutation), index+show read as one. Actions not in any group (e.g. "approve") get their own column. Set to nil (or {}) to show every raw action as its own column instead. Either way the grid renders ALIGNED columns — a controller that doesn't route a column's actions shows a blank cell, never a shifted one.
130 131 132 |
# File 'lib/current_scope/configuration.rb', line 130 def @permission_grid_groups end |
#sod_actions ⇒ Object
Action names subject to the separation-of-duties veto: whoever initiated a record can never perform these actions on it. Not editable in the UI by design — SoD is a structural guarantee, not a preference. Records hit by these actions must define current_scope_initiator (return nil to exempt a record type).
EMPTY BY DEFAULT — SoD is opt-in. The engine's baseline is scoped RBAC;
many hosts want nothing to do with four-eyes. Enable it by listing the
actions to gate, e.g. config.sod_actions = %w[approve].
20 21 22 |
# File 'lib/current_scope/configuration.rb', line 20 def sod_actions @sod_actions end |
#sod_bypass_permission ⇒ Object
The grantable permission the record's initiator must hold for a break-glass bypass to lift the veto (default "bypass_sod"). Resolved against the record's route key like any permission, so it's editable in the role grid — never a hardcoded role. Must NOT be listed in sod_actions (it isn't an SoD action; keeping it out also bounds the bypass re-entrancy).
96 97 98 |
# File 'lib/current_scope/configuration.rb', line 96 def @sod_bypass_permission end |
#sod_identity ⇒ Object
Which identities the separation-of-duties veto weighs:
:either (default) — veto if the effective subject OR (while
impersonating) the REAL actor initiated the record,
so impersonation can never approve the actor's own
record.
:subject — veto only on the effective subject.
The two are identical when not impersonating (actor == subject).
29 30 31 |
# File 'lib/current_scope/configuration.rb', line 29 def sod_identity @sod_identity end |
#subject_class ⇒ Object
Host class acting as the subject, used by the management UI to list assignable subjects.
63 64 65 |
# File 'lib/current_scope/configuration.rb', line 63 def subject_class @subject_class end |
#subject_label ⇒ Object
How a subject is identified in the management UI (subjects table, picker, bulk bar). A subject id is meaningless with UUID keys, so pick something human. Accepts:
- a Symbol — a method on the subject, e.g. :email or :name
- a Proc — subject -> String, e.g. ->(u) { "#{u.first_name} #{u.last_name}" }
- nil (default) — best-effort, people-first: email, else name, else
first+last, else the generic current_scope_label / "Class #id".
72 73 74 |
# File 'lib/current_scope/configuration.rb', line 72 def subject_label @subject_label end |
#user_method ⇒ Object
Host controller method that returns the authenticated subject.
4 5 6 |
# File 'lib/current_scope/configuration.rb', line 4 def user_method @user_method end |
#warn_on_nil_sod_record ⇒ Object
A5 (opt-in, dev/test aid): when true, the gate logs a nudge if an SoD action is gated with a nil record and the request is allowed — i.e. the SoD veto was silently skipped because current_scope_record returned nil on a member action. Off by default; prod behavior never changes. Emitted from the Guard seam (not the shared resolver), so it doesn't fire on advisory allowed_to?/scope_for calls.
119 120 121 |
# File 'lib/current_scope/configuration.rb', line 119 def warn_on_nil_sod_record @warn_on_nil_sod_record end |