Class: StandardAudit::Configuration
- Inherits:
-
Object
- Object
- StandardAudit::Configuration
- Defined in:
- lib/standard_audit/configuration.rb
Instance Attribute Summary collapse
-
#actor_extractor ⇒ Object
Returns the value of attribute actor_extractor.
-
#anonymizable_metadata_keys ⇒ Object
Returns the value of attribute anonymizable_metadata_keys.
-
#async ⇒ Object
Returns the value of attribute async.
-
#audit_catalogue ⇒ Object
Returns the value of attribute audit_catalogue.
-
#audit_write_error_handler ⇒ Object
Returns the value of attribute audit_write_error_handler.
-
#before_checksum_hooks ⇒ Object
Returns the value of attribute before_checksum_hooks.
-
#current_actor_resolver ⇒ Object
Returns the value of attribute current_actor_resolver.
-
#current_ip_address_resolver ⇒ Object
Returns the value of attribute current_ip_address_resolver.
-
#current_request_id_resolver ⇒ Object
Returns the value of attribute current_request_id_resolver.
-
#current_session_id_resolver ⇒ Object
Returns the value of attribute current_session_id_resolver.
-
#current_user_agent_resolver ⇒ Object
Returns the value of attribute current_user_agent_resolver.
-
#enabled ⇒ Object
Returns the value of attribute enabled.
-
#filter_nested_metadata ⇒ Object
Returns the value of attribute filter_nested_metadata.
-
#metadata_builder ⇒ Object
Returns the value of attribute metadata_builder.
-
#queue_name ⇒ Object
Returns the value of attribute queue_name.
-
#raise_on_audit_write_error ⇒ Object
Returns the value of attribute raise_on_audit_write_error.
-
#retention_days ⇒ Object
Returns the value of attribute retention_days.
-
#scope_extractor ⇒ Object
Returns the value of attribute scope_extractor.
-
#sensitive_key_exceptions ⇒ Object
Returns the value of attribute sensitive_key_exceptions.
-
#sensitive_key_patterns ⇒ Object
Returns the value of attribute sensitive_key_patterns.
-
#sensitive_keys ⇒ Object
Returns the value of attribute sensitive_keys.
-
#target_extractor ⇒ Object
Returns the value of attribute target_extractor.
-
#verify_audit_declarations ⇒ Object
Returns the value of attribute verify_audit_declarations.
Class Method Summary collapse
-
.retention_days_from_env ⇒ Object
Parses STANDARD_AUDIT_RETENTION_DAYS into a positive Integer, or nil when unset/blank/zero/negative/non-numeric (=> infinite retention).
Instance Method Summary collapse
-
#before_checksum(hook = nil, &block) ⇒ Object
Registers a hook to run between
assign_uuidandcompute_checksumon every audit write that instantiates a model. -
#initialize ⇒ Configuration
constructor
A new instance of Configuration.
- #subscribe_to(pattern) ⇒ Object
- #subscriptions ⇒ Object
Constructor Details
#initialize ⇒ Configuration
Returns a new instance of Configuration.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/standard_audit/configuration.rb', line 15 def initialize @subscriptions = [] @async = false @queue_name = :default @enabled = true @actor_extractor = ->(payload) { payload[:actor] } @target_extractor = ->(payload) { payload[:target] } @scope_extractor = ->(payload) { payload[:scope] } @current_actor_resolver = -> { defined?(Current) && Current.respond_to?(:user) ? Current.user : nil } @current_request_id_resolver = -> { defined?(Current) && Current.respond_to?(:request_id) ? Current.request_id : nil } @current_ip_address_resolver = -> { defined?(Current) && Current.respond_to?(:ip_address) ? Current.ip_address : nil } @current_user_agent_resolver = -> { defined?(Current) && Current.respond_to?(:user_agent) ? Current.user_agent : nil } @current_session_id_resolver = -> { defined?(Current) && Current.respond_to?(:session_id) ? Current.session_id : nil } # Note: :authorization filters the HTTP Authorization header value. # If you use "authorization" as a metadata key for policy decisions, # rename it (e.g. :authorization_policy) to avoid accidental filtering. @sensitive_keys = %i[ password password_confirmation token secret api_key access_token refresh_token private_key certificate_chain ssn credit_card authorization ] # Regexps matched against every metadata key name, in addition to the # exact-match `sensitive_keys` list. This is the supported way to catch a # family of keys: `/secret/i` redacts `client_secret`, `webhook_secret`, # and `secret` alike. # # There is deliberately NO substring *mode* for `sensitive_keys` — see # the note in MetadataFilter. Patterns are opt-in and per-app, which is # the only safe shape for a rule applied to append-only rows. @sensitive_key_patterns = [] # Key names (String/Symbol, exact) or Regexps that are never redacted, # even when `sensitive_keys` or `sensitive_key_patterns` matches. Lets an # app adopt a broad pattern while keeping the handful of real audit keys # it would otherwise swallow, e.g. # `sensitive_key_patterns = [/token/i]` with # `sensitive_key_exceptions = %i[input_tokens output_tokens]`. @sensitive_key_exceptions = [] # When true, redaction descends into nested Hashes (and Hashes inside # Arrays), so `metadata: { stripe: { client_secret: … } }` is caught. # Defaults to false: it changes what gets written, and audit rows are # append-only. Reserved keys are never descended into. @filter_nested_metadata = false @metadata_builder = nil # Callables (or Symbols naming an AuditLog instance method) run on # `before_create` AFTER the UUID is assigned and BEFORE the checksum is # computed. See Configuration#before_checksum. @before_checksum_hooks = [] @anonymizable_metadata_keys = %i[email name ip_address] # ── StandardAudit::Operation (the operation-audit DSL) ──────────────── # The host's canonical action vocabulary, used by `audit!` to reject an # action absent from it. Normally a CALLABLE, because referencing an # autoloadable constant eagerly from an initializer pins the first-loaded # copy and breaks Zeitwerk reloading: # # config.audit_catalogue = -> { AuditCatalogue::ACTIONS } # # A plain Array is accepted when the vocabulary really is a frozen # literal. `nil` (the default) skips the membership check entirely, so # the DSL is adoptable before an app has a catalogue. # # Membership is the ONLY rule applied — see StandardAudit::Operation. @audit_catalogue = nil # Whether `audit!` verifies the declaration before writing. A callable # (or a plain boolean). Defaults to local environments only: in # production `audit!` just writes, because a developer's declaration # mistake must not 500 a user — the host's meta-spec is the real gate. @verify_audit_declarations = -> { defined?(Rails) && Rails.respond_to?(:env) && Rails.env.respond_to?(:local?) && Rails.env.local? } # Whether a failed audit *write* aborts the operation. `false` (report # and swallow) matches four of the five apps this DSL was extracted from. # Set `true` where an unaudited state change is itself a compliance # failure — one app deliberately does not rescue, and defaulting to # swallow would have silently downgraded that posture. # # StandardAudit::Operation::DeclarationError is NEVER governed by this; # it always propagates. @raise_on_audit_write_error = false # Optional callable invoked instead of the built-in logger/Rails.error # reporting when an audit write fails: # # config.audit_write_error_handler = # ->(error, action:, operation:) { ErrorReporting.notify(error, ...) } # # Runs before `raise_on_audit_write_error` is applied, so it sees every # write failure under either policy. @audit_write_error_handler = nil # Retention defaults from ENV so it can be set per-environment without a # code change. Unset/blank/non-positive => nil (infinite retention, the # compliance-safe default that never auto-deletes). A host app can still # override with `config.retention_days = N` in its initializer. @retention_days = self.class.retention_days_from_env end |
Instance Attribute Details
#actor_extractor ⇒ Object
Returns the value of attribute actor_extractor.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def actor_extractor @actor_extractor end |
#anonymizable_metadata_keys ⇒ Object
Returns the value of attribute anonymizable_metadata_keys.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def @anonymizable_metadata_keys end |
#async ⇒ Object
Returns the value of attribute async.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def async @async end |
#audit_catalogue ⇒ Object
Returns the value of attribute audit_catalogue.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def audit_catalogue @audit_catalogue end |
#audit_write_error_handler ⇒ Object
Returns the value of attribute audit_write_error_handler.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def audit_write_error_handler @audit_write_error_handler end |
#before_checksum_hooks ⇒ Object
Returns the value of attribute before_checksum_hooks.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def before_checksum_hooks @before_checksum_hooks end |
#current_actor_resolver ⇒ Object
Returns the value of attribute current_actor_resolver.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def current_actor_resolver @current_actor_resolver end |
#current_ip_address_resolver ⇒ Object
Returns the value of attribute current_ip_address_resolver.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def current_ip_address_resolver @current_ip_address_resolver end |
#current_request_id_resolver ⇒ Object
Returns the value of attribute current_request_id_resolver.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def current_request_id_resolver @current_request_id_resolver end |
#current_session_id_resolver ⇒ Object
Returns the value of attribute current_session_id_resolver.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def current_session_id_resolver @current_session_id_resolver end |
#current_user_agent_resolver ⇒ Object
Returns the value of attribute current_user_agent_resolver.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def current_user_agent_resolver @current_user_agent_resolver end |
#enabled ⇒ Object
Returns the value of attribute enabled.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def enabled @enabled end |
#filter_nested_metadata ⇒ Object
Returns the value of attribute filter_nested_metadata.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def @filter_nested_metadata end |
#metadata_builder ⇒ Object
Returns the value of attribute metadata_builder.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def @metadata_builder end |
#queue_name ⇒ Object
Returns the value of attribute queue_name.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def queue_name @queue_name end |
#raise_on_audit_write_error ⇒ Object
Returns the value of attribute raise_on_audit_write_error.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def raise_on_audit_write_error @raise_on_audit_write_error end |
#retention_days ⇒ Object
Returns the value of attribute retention_days.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def retention_days @retention_days end |
#scope_extractor ⇒ Object
Returns the value of attribute scope_extractor.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def scope_extractor @scope_extractor end |
#sensitive_key_exceptions ⇒ Object
Returns the value of attribute sensitive_key_exceptions.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def sensitive_key_exceptions @sensitive_key_exceptions end |
#sensitive_key_patterns ⇒ Object
Returns the value of attribute sensitive_key_patterns.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def sensitive_key_patterns @sensitive_key_patterns end |
#sensitive_keys ⇒ Object
Returns the value of attribute sensitive_keys.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def sensitive_keys @sensitive_keys end |
#target_extractor ⇒ Object
Returns the value of attribute target_extractor.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def target_extractor @target_extractor end |
#verify_audit_declarations ⇒ Object
Returns the value of attribute verify_audit_declarations.
3 4 5 |
# File 'lib/standard_audit/configuration.rb', line 3 def verify_audit_declarations @verify_audit_declarations end |
Class Method Details
.retention_days_from_env ⇒ Object
Parses STANDARD_AUDIT_RETENTION_DAYS into a positive Integer, or nil when unset/blank/zero/negative/non-numeric (=> infinite retention).
136 137 138 139 140 141 142 |
# File 'lib/standard_audit/configuration.rb', line 136 def self.retention_days_from_env raw = ENV["STANDARD_AUDIT_RETENTION_DAYS"] return nil if raw.nil? || raw.strip.empty? days = Integer(raw, exception: false) days&.positive? ? days : nil end |
Instance Method Details
#before_checksum(hook = nil, &block) ⇒ Object
Registers a hook to run between assign_uuid and compute_checksum on
every audit write that instantiates a model.
config.before_checksum { |log| log.scope = derive_scope(log) }
config.before_checksum :backfill_organization_scope
A hook may set a CHECKSUM_FIELDS member (scope_gid, metadata, …) and
the row will still verify, because the checksum is computed afterwards.
That is the whole point: before this existed, hosts had to register their
own before_create ..., prepend: true to beat the gem's checksum
callback, which is fragile ordering knowledge no host should need.
Hooks accumulate and run in registration order. Each is rescued individually — a failing hook logs and is skipped; it never fails the audit write.
A Symbol/String is sent to the AuditLog instance (use this for methods supplied by a concern mixed into the model). A callable is passed the instance.
NOTE: batched writes (StandardAudit.batch { … } → insert_all!) never
instantiate a model, so hooks do not run there. A batched writer that
needs a derived column has to set it on the buffered attrs.
167 168 169 170 171 172 173 |
# File 'lib/standard_audit/configuration.rb', line 167 def before_checksum(hook = nil, &block) hook ||= block raise ArgumentError, "before_checksum needs a callable, a Symbol, or a block" if hook.nil? @before_checksum_hooks << hook hook end |
#subscribe_to(pattern) ⇒ Object
175 176 177 |
# File 'lib/standard_audit/configuration.rb', line 175 def subscribe_to(pattern) @subscriptions << pattern end |
#subscriptions ⇒ Object
179 180 181 |
# File 'lib/standard_audit/configuration.rb', line 179 def subscriptions @subscriptions.dup.freeze end |