module Cased
Constants
- VERSION
Attributes
Public Class Methods
# File lib/cased.rb, line 102 def self.clients @clients ||= Cased::Clients.new end
@return [Cased::Config]
# File lib/cased.rb, line 63 def self.config @config ||= Cased::Config.new end
@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
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
@return [Cased::Context]
# File lib/cased.rb, line 145 def self.context Context.current end
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
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
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
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
@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
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
@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
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
# File lib/cased.rb, line 28 def self.sensitive(label, handler) Cased::Sensitive::Handler.register(label, handler) end
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
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