Module: Envoy::Guard

Defined in:
lib/envoy/guard.rb

Class Method Summary collapse

Class Method Details

.failure(type, message, status) ⇒ Object



26
27
28
# File 'lib/envoy/guard.rb', line 26

def failure(type, message, status)
  { value: { error: message, type: type }, status: status }
end

.run(definition, actor:, args:) ⇒ Object

Runs a tool definition's perform block, translating exceptions into model-legible results. Never raises for expected failures.



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/envoy/guard.rb', line 7

def run(definition, actor:, args:)
  args = args.symbolize_keys
  validate_enums!(definition, args)
  value = definition.perform_block.call(actor: actor, **args)
  if value.is_a?(Hash) && value[:error]
    { value: value, status: :failed }
  else
    { value: value, status: :succeeded }
  end
rescue Envoy::Forbidden => e
  failure("forbidden", e.message.presence || "Not permitted.", :denied)
rescue ActiveRecord::RecordNotFound
  failure("not_found", "The requested record was not found.", :failed)
rescue ArgumentError => e
  failure("invalid", e.message, :failed)
rescue StandardError
  failure("error", "An unexpected error occurred.", :failed)
end

.validate_enums!(definition, args) ⇒ Object

A closed vocabulary is a contract: reject an unknown value with the valid list rather than letting the perform block improvise on a hallucinated key.



32
33
34
35
36
37
38
# File 'lib/envoy/guard.rb', line 32

def validate_enums!(definition, args)
  args.each do |name, value|
    allowed = definition.enum_for(name)
    next if allowed.nil? || allowed.include?(value.to_s)
    raise ArgumentError, "#{name} must be one of: #{allowed.join(', ')} (got #{value.inspect})"
  end
end