module Cased

Constants

VERSION

Attributes

publishers[W]

Public Class Methods

clients() click to toggle source
# File lib/cased.rb, line 102
def self.clients
  @clients ||= Cased::Clients.new
end
config() click to toggle source

@return [Cased::Config]

# File lib/cased.rb, line 63
def self.config
  @config ||= Cased::Config.new
end
configure(&block) click to toggle source

@example

Cased.configure do |config|
  config.policy_key = 'policy_test_1dQpY5JliYgHSkEntAbMVzuOROh'
end

@return [void]

# File lib/cased.rb, line 73
def self.configure(&block)
  block.call(config)
end
console(options = {}) click to toggle source

Configures a default context for console sessions.

When a console session is started you don't have the context generated from a typical web request lifecycle where authentication will happen and an IP address is present. This uses the server's hostname as a standard location for migrations or data transitions.

@param options [Hash]

@return [void]

# File lib/cased.rb, line 209
def self.console(options = {})
  context.merge({
    location: Socket.gethostname,
  }.merge(options))
end
context() click to toggle source

@return [Cased::Context]

# File lib/cased.rb, line 145
def self.context
  Context.current
end
exception_handler() click to toggle source

Applications can determine where they want exceptions generated by Cased to be sent.

@return [Proc, nil]

# File lib/cased.rb, line 169
def self.exception_handler
  @exception_handler
end
exception_handler=(handler) click to toggle source

Sets the system user to be used for Cased events that do not contain an actor.

@param handler [Proc] - The Proc or lambda that takes a single exception argument.

@example

Cased.exception_handler = Proc.new do |exception|
  Raven.capture_exception(exception)
end

@return [void] @raise [ArgumentError] if the provided handler does not respond to call or

accept an argument.
# File lib/cased.rb, line 185
def self.exception_handler=(handler)
  if handler.nil?
    @exception_handler = nil
    return
  elsif !handler.respond_to?(:call)
    @exception_handler = nil
    raise ArgumentError, "#{handler.class} does not respond to #call"
  elsif handler.arity != 1
    raise ArgumentError, 'handler does not accept any arguments'
  end

  @exception_handler = handler
end
handle_exception(exception) click to toggle source

The main entry point to handling any exceptions encountered in the event creation lifecycle.

@param exception [Exception] the exception to be raised

@return [void] @raise [Exception] if Cased is configured to raise on errors

# File lib/cased.rb, line 155
def self.handle_exception(exception)
  raise exception if config.raise_on_errors?

  if exception_handler.nil?
    warn exception.message
    return
  end

  exception_handler.call(exception)
end
id(model) click to toggle source

Generates Cased compatible resource identifier.

@param model [Object] an object that responds to cased_id

@return [String] the Cased::Model#cased_id @raise [Cased::Error::MissingIdentifier] when the provided model does not

respond to #cased_id
# File lib/cased.rb, line 222
def self.id(model)
  raise Cased::Error::MissingIdentifier unless model.respond_to?(:cased_id)

  model.cased_id
end
policies() click to toggle source

@example

Cased.policies[:organization]

@return [Hash{Symbol => Cased::Policy, nil}]

# File lib/cased.rb, line 37
def self.policies
  @policies ||= Hash.new do |hash, name|
    key = name.to_sym
    api_key = Cased.config.policy_key(key)
    hash[key] = Policy.new(api_key: api_key)
  end
end
policy() click to toggle source

Helper method for accessing the applications default policy.

@example

Cased.configure do |config|
  config.policy_key = 'policy_test_1dQpY5JliYgHSkEntAbMVzuOROh'
end

policy = Cased.policy
policy.events.each do |event|
  puts event['action'] # => user.login
end

@return [Cased::Policy, nil]

# File lib/cased.rb, line 58
def self.policy
  policies[:default]
end
publish(audit_event) click to toggle source

@param audit_event [Hash] the audit event.

@example

Cased.publish(
  action: "user.login",
  actor: "garrett@cased.com",
  actor_id: "user_1dQpY5JliYgHSkEntAbMVzuOROh",
  http_user_agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36",
  http_url: "https://app.cased.com/",
  http_method: "GET",
  language: "en-US"
)

@example With User object that includes Cased::Model

Cased.publish(
  action: "user.login",
  actor: User.find(1),
)

@return [Array] of responses from Cased.publishers @return [false] if Cased has been silenced. @raise [ArgumentError] if a publisher does not implement the publish method

# File lib/cased.rb, line 128
def self.publish(audit_event)
  return false if config.silence?

  processed_audit_event = process(audit_event)

  publishers.each do |publisher|
    unless publisher.respond_to?(:publish)
      raise ArgumentError, "#{publisher.class} must implement #{publisher.class}#publish"
    end

    publisher.publish(processed_audit_event.dup)
  rescue StandardError => e
    handle_exception(e)
  end
end
publishers() click to toggle source

The list of publishers that will receive the processed audit event when calling Cased.publish.

The desired behavior for Cased.publish should not change based on the order of the publishers.

@example Adding a publisher to the stack

Cased.publishers << Cased::Publishers::KafkaPublisher.new

@example Setting the list of publishers

Cased.publishers = [
  Cased::Publishers::KafkaPublisher.new,
]

@return [Array<Cased::Publishers::Base>]

# File lib/cased.rb, line 95
def self.publishers
  @publishers ||= [
    Cased::Publishers::HTTPPublisher.new,
    Cased::Publishers::ActiveSupportPublisher.new,
  ]
end
sensitive(label, handler) click to toggle source
# File lib/cased.rb, line 28
def self.sensitive(label, handler)
  Cased::Sensitive::Handler.register(label, handler)
end
silence() { || ... } click to toggle source

Don't send any events to Cased that are created within the lifecycle of the block.

@example

Cased.silence do
  user.save
end
# File lib/cased.rb, line 234
def self.silence
  original_silence = config.silence?
  config.silence = true
  yield
ensure
  config.silence = original_silence
end

Private Class Methods

process(payload) click to toggle source

Publish the Cased event so all subscribers can handle storing the Cased event.

@param payload [Hash] payload to publish.

@return [Hash] the processed audit event payload.

# File lib/cased.rb, line 247
                     def self.process(payload)
  expanded_audit_event = Cased::Context::Expander.expand(payload)
  event = expanded_audit_event.merge(
    cased_id: SecureRandom.hex,
    timestamp: Time.now.utc.iso8601(6),
  )

  safe_context = context.context.dup
  audit_event = safe_context.merge(event)

  Cased::Sensitive::Processor.process!(audit_event)

  audit_event
end