Class: Reeve::Invocation

Inherits:
Object
  • Object
show all
Defined in:
lib/reeve/invocation.rb

Overview

The single funnel every guarded tool call passes through:

resolve principal → look up guard → authorize → execute → scope → record → return

One envelope rather than middleware or a patched dispatcher, so there is exactly one place where "did this get authorized and recorded?" can be answered — and exactly one place to audit when the answer must be yes.

Collaborators are injected and default to null objects that fail closed: a kernel with no authorization module wired in denies everything, and one with no ledger refuses the call rather than performing it silently.

Defined Under Namespace

Classes: NullAuthorizer, NullRecorder, NullRegistry, NullScoper

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(context, registry: nil, authorizer: nil, scoper: nil, recorder: nil, config: nil) ⇒ Invocation

Returns a new instance of Invocation.



52
53
54
55
56
57
58
59
60
# File 'lib/reeve/invocation.rb', line 52

def initialize(context, registry: nil, authorizer: nil, scoper: nil, recorder: nil,
               config: nil)
  @context    = context
  @config     = config || Reeve.config
  @registry   = registry   || NullRegistry.new
  @authorizer = authorizer || NullAuthorizer.new
  @scoper     = scoper     || NullScoper.new
  @recorder   = recorder   || @config.audit_recorder || NullRecorder.new
end

Class Method Details

.call(context, **collaborators, &tool) ⇒ Object



48
49
50
# File 'lib/reeve/invocation.rb', line 48

def self.call(context, **collaborators, &tool)
  new(context, **collaborators).call(&tool)
end

Instance Method Details

#call(&tool) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/reeve/invocation.rb', line 62

def call(&tool)
  started = monotonic_now
  @guard_label = "policy"
  @scope_result = nil

  @decision = authorize_and_run(&tool)
  raise denial_error(@decision) if @decision.denied?

  @scope_result.records
ensure
  # Whatever is already on its way out of this method — a tool error or a denial.
  @in_flight_error = $ERROR_INFO
  @duration_ms = ((monotonic_now - started) * 1000).round
  write_entry
  context.clear_principal!
end