Class: Vangrail::ReferenceMonitor

Inherits:
Object
  • Object
show all
Includes:
ReferenceMonitorAuthority
Defined in:
lib/vangrail/reference_monitor.rb

Overview

Complete authorization point for calls routed through the public adapter.

Constant Summary collapse

CONSTRAINT_KEYS =
%i[type origins integrity equals in pattern].freeze
TYPES =
{
  string: String,
  integer: Integer,
  number: Numeric,
  array: Array,
  hash: Hash,
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(plan) ⇒ ReferenceMonitor

Returns a new instance of ReferenceMonitor.

Raises:

  • (ArgumentError)


159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/vangrail/reference_monitor.rb', line 159

def initialize(plan)
  raise ArgumentError, 'plan must be a Plan' unless plan.is_a?(Plan)

  @plan = plan.lock!
  @audit = @plan.audit
  @usage = Hash.new(0)
  @authorized = {}
  @claimed = {}
  @finished = {}
  @confirmations = {}
  @transactions = {}
  @completed = []
  @mutex = Mutex.new
end

Instance Attribute Details

#auditObject (readonly)

Returns the value of attribute audit.



157
158
159
# File 'lib/vangrail/reference_monitor.rb', line 157

def audit
  @audit
end

#planObject (readonly)

Returns the value of attribute plan.



157
158
159
# File 'lib/vangrail/reference_monitor.rb', line 157

def plan
  @plan
end

Instance Method Details

#authorize(call, risk: nil) ⇒ Object

Raises:

  • (ArgumentError)


174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/vangrail/reference_monitor.rb', line 174

def authorize(call, risk: nil)
  raise ArgumentError, 'call must be a Call' unless call.is_a?(Call)

  @mutex.synchronize do
    audit.record_call_attempt(call)
    preliminary = preliminary_denial(call)
    return audited(preliminary) if preliminary

    denials = plan.grants_for(call.tool).map do |grant|
      denial = grant_denial(call, grant, risk)
      next denial if denial

      @usage[grant.id] += 1
      authorization = Authorization.allow(call, grant)
      @authorized[call.id] = authorization
      return audited(authorization)
    end
    audited(denials.compact.first || deny(call, :no_grant, "no grant for #{call.tool}"))
  end
end

#claim(authorization) ⇒ Object Originally defined in module ReferenceMonitorAuthority

#confirm(call, actor:) ⇒ Object Originally defined in module ReferenceMonitorAuthority

Raises:

  • (ArgumentError)

#finish(call, success:) ⇒ Object

Raises:

  • (ArgumentError)


195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/vangrail/reference_monitor.rb', line 195

def finish(call, success:)
  raise ArgumentError, 'call must be a Call' unless call.is_a?(Call)

  @mutex.synchronize do
    authorization = @authorized[call.id]
    return false unless authorization&.allowed?
    return @finished[call.id] if @finished.key?(call.id)

    @finished[call.id] = success.equal?(true)
    @completed << call.tool if success
    audit.record(:handler_outcome, call_id: call.id, tool: call.tool,
                                   success: @finished[call.id])
    @finished[call.id]
  end
end

#finish_transaction(prepared, committed:) ⇒ Object Originally defined in module ReferenceMonitorAuthority

#prepare_transaction(call, prepared) ⇒ Object Originally defined in module ReferenceMonitorAuthority

Raises:

  • (ArgumentError)

#usage(grant) ⇒ Object



211
212
213
214
# File 'lib/vangrail/reference_monitor.rb', line 211

def usage(grant)
  grant_id = grant.respond_to?(:id) ? grant.id : grant.to_s
  @mutex.synchronize { @usage[grant_id] }
end