mongoid-auditor 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +21 -0
- data/README.md +272 -0
- data/Rakefile +12 -0
- data/lib/mongoid/auditor/audit.rb +52 -0
- data/lib/mongoid/auditor/configuration.rb +27 -0
- data/lib/mongoid/auditor/generators/install_generator.rb +18 -0
- data/lib/mongoid/auditor/generators/templates/mongoid_auditor_initializer.rb +12 -0
- data/lib/mongoid/auditor/helpers/controller_helpers/audit_controller_error_log.rb +75 -0
- data/lib/mongoid/auditor/helpers/controller_helpers/controller_audit_helper.rb +22 -0
- data/lib/mongoid/auditor/helpers/controller_helpers/init_audit_log.rb +35 -0
- data/lib/mongoid/auditor/helpers/jobs/auditor_job.rb +56 -0
- data/lib/mongoid/auditor/helpers/jobs/concerns/auditable_job_error.rb +58 -0
- data/lib/mongoid/auditor/helpers/jobs/concerns/init_job_audit_log.rb +68 -0
- data/lib/mongoid/auditor/helpers/models/audit_log.rb +64 -0
- data/lib/mongoid/auditor/helpers/models/concerns/audit_log_helpers.rb +68 -0
- data/lib/mongoid/auditor/helpers/models/concerns/auditable.rb +89 -0
- data/lib/mongoid/auditor/helpers/models/concerns/model_logs_helper.rb +53 -0
- data/lib/mongoid/auditor/helpers/models/current.rb +10 -0
- data/lib/mongoid/auditor/helpers/models/request_context.rb +19 -0
- data/lib/mongoid/auditor/railtie.rb +34 -0
- data/lib/mongoid/auditor/version.rb +7 -0
- data/lib/mongoid/auditor.rb +21 -0
- data/sig/mongoid/auditor.rbs +6 -0
- metadata +115 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 869c768a48b7fb7e52b1d437b89b484f72cc397dd74b0416c229088c6967189e
|
|
4
|
+
data.tar.gz: e1b3f3f5c59eb810af348dad24268b6b06fa1dbe2874c9c631b4d15a19463908
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 0200e27d63508fb92aabc155a487497720e0657de998b3ae15ec41f787aed92d94e02bbfcd0ba9ed5d62e3603f8ab37652ab45053eb17a759e84a97843abbffa
|
|
7
|
+
data.tar.gz: e4c4d32d87f3b4f07b68dac2caad98aceb2bab67dcdd461328b35ea52730155f97c5defd341b41fcc2698ffcde0692000cf634dda24bdfcadd27e89686c6dcd7
|
data/CHANGELOG.md
ADDED
data/CODE_OF_CONDUCT.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our
|
|
6
|
+
community a harassment-free experience for everyone, regardless of age, body
|
|
7
|
+
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
|
8
|
+
identity and expression, level of experience, education, socio-economic status,
|
|
9
|
+
nationality, personal appearance, race, caste, color, religion, or sexual
|
|
10
|
+
identity and orientation.
|
|
11
|
+
|
|
12
|
+
We pledge to act and interact in ways that contribute to an open, welcoming,
|
|
13
|
+
diverse, inclusive, and healthy community.
|
|
14
|
+
|
|
15
|
+
## Our Standards
|
|
16
|
+
|
|
17
|
+
Examples of behavior that contributes to a positive environment for our
|
|
18
|
+
community include:
|
|
19
|
+
|
|
20
|
+
* Demonstrating empathy and kindness toward other people
|
|
21
|
+
* Being respectful of differing opinions, viewpoints, and experiences
|
|
22
|
+
* Giving and gracefully accepting constructive feedback
|
|
23
|
+
* Accepting responsibility and apologizing to those affected by our mistakes,
|
|
24
|
+
and learning from the experience
|
|
25
|
+
* Focusing on what is best not just for us as individuals, but for the overall
|
|
26
|
+
community
|
|
27
|
+
|
|
28
|
+
Examples of unacceptable behavior include:
|
|
29
|
+
|
|
30
|
+
* The use of sexualized language or imagery, and sexual attention or advances of
|
|
31
|
+
any kind
|
|
32
|
+
* Trolling, insulting or derogatory comments, and personal or political attacks
|
|
33
|
+
* Public or private harassment
|
|
34
|
+
* Publishing others' private information, such as a physical or email address,
|
|
35
|
+
without their explicit permission
|
|
36
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
|
37
|
+
professional setting
|
|
38
|
+
|
|
39
|
+
## Enforcement Responsibilities
|
|
40
|
+
|
|
41
|
+
Community leaders are responsible for clarifying and enforcing our standards of
|
|
42
|
+
acceptable behavior and will take appropriate and fair corrective action in
|
|
43
|
+
response to any behavior that they deem inappropriate, threatening, offensive,
|
|
44
|
+
or harmful.
|
|
45
|
+
|
|
46
|
+
Community leaders have the right and responsibility to remove, edit, or reject
|
|
47
|
+
comments, commits, code, wiki edits, issues, and other contributions that are
|
|
48
|
+
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
|
49
|
+
decisions when appropriate.
|
|
50
|
+
|
|
51
|
+
## Scope
|
|
52
|
+
|
|
53
|
+
This Code of Conduct applies within all community spaces, and also applies when
|
|
54
|
+
an individual is officially representing the community in public spaces.
|
|
55
|
+
Examples of representing our community include using an official email address,
|
|
56
|
+
posting via an official social media account, or acting as an appointed
|
|
57
|
+
representative at an online or offline event.
|
|
58
|
+
|
|
59
|
+
## Enforcement
|
|
60
|
+
|
|
61
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
62
|
+
reported to the community leaders responsible for enforcement at
|
|
63
|
+
[INSERT CONTACT METHOD].
|
|
64
|
+
All complaints will be reviewed and investigated promptly and fairly.
|
|
65
|
+
|
|
66
|
+
All community leaders are obligated to respect the privacy and security of the
|
|
67
|
+
reporter of any incident.
|
|
68
|
+
|
|
69
|
+
## Enforcement Guidelines
|
|
70
|
+
|
|
71
|
+
Community leaders will follow these Community Impact Guidelines in determining
|
|
72
|
+
the consequences for any action they deem in violation of this Code of Conduct:
|
|
73
|
+
|
|
74
|
+
### 1. Correction
|
|
75
|
+
|
|
76
|
+
**Community Impact**: Use of inappropriate language or other behavior deemed
|
|
77
|
+
unprofessional or unwelcome in the community.
|
|
78
|
+
|
|
79
|
+
**Consequence**: A private, written warning from community leaders, providing
|
|
80
|
+
clarity around the nature of the violation and an explanation of why the
|
|
81
|
+
behavior was inappropriate. A public apology may be requested.
|
|
82
|
+
|
|
83
|
+
### 2. Warning
|
|
84
|
+
|
|
85
|
+
**Community Impact**: A violation through a single incident or series of
|
|
86
|
+
actions.
|
|
87
|
+
|
|
88
|
+
**Consequence**: A warning with consequences for continued behavior. No
|
|
89
|
+
interaction with the people involved, including unsolicited interaction with
|
|
90
|
+
those enforcing the Code of Conduct, for a specified period of time. This
|
|
91
|
+
includes avoiding interactions in community spaces as well as external channels
|
|
92
|
+
like social media. Violating these terms may lead to a temporary or permanent
|
|
93
|
+
ban.
|
|
94
|
+
|
|
95
|
+
### 3. Temporary Ban
|
|
96
|
+
|
|
97
|
+
**Community Impact**: A serious violation of community standards, including
|
|
98
|
+
sustained inappropriate behavior.
|
|
99
|
+
|
|
100
|
+
**Consequence**: A temporary ban from any sort of interaction or public
|
|
101
|
+
communication with the community for a specified period of time. No public or
|
|
102
|
+
private interaction with the people involved, including unsolicited interaction
|
|
103
|
+
with those enforcing the Code of Conduct, is allowed during this period.
|
|
104
|
+
Violating these terms may lead to a permanent ban.
|
|
105
|
+
|
|
106
|
+
### 4. Permanent Ban
|
|
107
|
+
|
|
108
|
+
**Community Impact**: Demonstrating a pattern of violation of community
|
|
109
|
+
standards, including sustained inappropriate behavior, harassment of an
|
|
110
|
+
individual, or aggression toward or disparagement of classes of individuals.
|
|
111
|
+
|
|
112
|
+
**Consequence**: A permanent ban from any sort of public interaction within the
|
|
113
|
+
community.
|
|
114
|
+
|
|
115
|
+
## Attribution
|
|
116
|
+
|
|
117
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
|
118
|
+
version 2.1, available at
|
|
119
|
+
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
|
120
|
+
|
|
121
|
+
Community Impact Guidelines were inspired by
|
|
122
|
+
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
|
123
|
+
|
|
124
|
+
For answers to common questions about this code of conduct, see the FAQ at
|
|
125
|
+
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
|
126
|
+
[https://www.contributor-covenant.org/translations][translations].
|
|
127
|
+
|
|
128
|
+
[homepage]: https://www.contributor-covenant.org
|
|
129
|
+
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
|
130
|
+
[Mozilla CoC]: https://github.com/mozilla/diversity
|
|
131
|
+
[FAQ]: https://www.contributor-covenant.org/faq
|
|
132
|
+
[translations]: https://www.contributor-covenant.org/translations
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Pralad Mishra
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# Mongoid::Auditor
|
|
2
|
+
|
|
3
|
+
Mongoid::Auditor is a Rails engine that provides automatic auditing for Mongoid models, controllers, and background jobs. It tracks changes, errors, and events in your application using a structured `AuditLog` model and is recorded asynchronously using a background job called `AuditorJob`.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
* Automatic auditing of Mongoid model changes (`create`, `update`, `destroy`).
|
|
8
|
+
* Error logging for controllers and background jobs.
|
|
9
|
+
* Asynchronous audit logging with `AuditorJob`.
|
|
10
|
+
* Configurable auditing for models and controllers.
|
|
11
|
+
* Compatible with Rails 7+ and Mongoid 7+.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
Add this in your Gemfile:
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
gem 'mongoid-auditor', path: '../gems/mongoid-auditor' # adjust path if using a local gem
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
gem install mongoid-auditor
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Setup
|
|
28
|
+
|
|
29
|
+
Generate the initializer with the Rails generator:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
rails generate mongoid:auditor:install
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
This creates `config/initializers/mongoid_auditor.rb` with default configuration:
|
|
36
|
+
|
|
37
|
+
```ruby
|
|
38
|
+
Mongoid::Auditor.configure do |config|
|
|
39
|
+
config.enabled = true
|
|
40
|
+
config.log_models = true # logs the changes made to the model
|
|
41
|
+
config.log_controllers = true # logs the errors
|
|
42
|
+
end
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
### Models
|
|
48
|
+
|
|
49
|
+
Include the `Auditable` concern in your Mongoid models to log create, update, and destroy events automatically:
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
class Product
|
|
53
|
+
include Mongoid::Document
|
|
54
|
+
include Mongoid::Auditor::Auditable
|
|
55
|
+
end
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Or add this to the `ApplicationDocument` module to apply it to all models:
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
module ApplicationDocument
|
|
62
|
+
extend ActiveSupport::Concern
|
|
63
|
+
|
|
64
|
+
included do
|
|
65
|
+
include Mongoid::Auditor::Auditable
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
This ensures that all mutations to models are automatically recorded in `AuditLog`.
|
|
71
|
+
|
|
72
|
+
**Note:** GET requests are not recorded. If a POST behaves like a GET, add this to your controller:
|
|
73
|
+
|
|
74
|
+
```ruby
|
|
75
|
+
skip_before_action :init_audit_log, only: %i[your_method_name_here]
|
|
76
|
+
```
|
|
77
|
+
***Note:** if you want to skip specific jobs from being logged add this in specific job file:
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
class BackgroundJob < ApplicationJob
|
|
81
|
+
queue_as :default
|
|
82
|
+
|
|
83
|
+
self.skip_audit = true
|
|
84
|
+
end
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
### Controllers
|
|
89
|
+
|
|
90
|
+
Include the `InitAuditLog` concern to initialize the RequestStore to store basic information about the request.
|
|
91
|
+
Include the `AuditControllerErrorLog` concern to log controller errors.
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
class ProductsController < ApplicationController
|
|
95
|
+
include Mongoid::Auditor::InitAuditLog
|
|
96
|
+
include Mongoid::Auditor::AuditControllerErrorLog
|
|
97
|
+
end
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Jobs
|
|
101
|
+
|
|
102
|
+
Include the `InitJobAuditLog` concern and `audit_skip` class attribute in your `ApplicationJob` to audit background jobs:
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
class ApplicationJob < ActiveJob::Base
|
|
106
|
+
include Mongoid::Auditor::InitJobAuditLog
|
|
107
|
+
class_attribute :skip_audit, default: false
|
|
108
|
+
end
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Jobs automatically track `request_id`, `actor`, API endpoint, and parameters.
|
|
112
|
+
|
|
113
|
+
### Testing Instances
|
|
114
|
+
During testing, the number of AuditorJob records can grow significantly depending on the number of calls and background operations.
|
|
115
|
+
It is therefore recommended to disable the auditor in test environments.
|
|
116
|
+
```ruby
|
|
117
|
+
# config/initializers/mongoid_auditor.rb
|
|
118
|
+
|
|
119
|
+
Mongoid::Auditor.configure do |config|
|
|
120
|
+
# Disable auditor in test environment to avoid excessive job creation
|
|
121
|
+
config.enabled = !Rails.env.test?
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### AuditLog Model
|
|
127
|
+
|
|
128
|
+
The `Mongoid::Auditor::AuditLog` model stores audit entries with the following attributes:
|
|
129
|
+
|
|
130
|
+
* `request_id` — Request or job ID.
|
|
131
|
+
* `actor` — User or background job (e.g., `AuditorJob`).
|
|
132
|
+
* `path` — Controller action or job name.
|
|
133
|
+
* `model_type` — Class of the audited model (e.g., `Product`).
|
|
134
|
+
* `model_id` — ID of the audited model.
|
|
135
|
+
* `event` — `create`, `update`, `destroy`, or `error`.
|
|
136
|
+
* `dirties` — Before/after attribute snapshots (hash with `attribute: [before_value, after_value]` format).
|
|
137
|
+
* `sequence` — Incremental sequence number for ordering events within a request.
|
|
138
|
+
* `error` — Contains class, message and backtrace of the error (when `has_error` is true).
|
|
139
|
+
|
|
140
|
+
Logs are written asynchronously by `Mongoid::Auditor::AuditorJob` to minimize performance impact.
|
|
141
|
+
|
|
142
|
+
### RequestContext Model
|
|
143
|
+
|
|
144
|
+
The `Mongoid::Auditor::RequestContext` model stores context information for requests and background jobs, providing a reference for audit logging.
|
|
145
|
+
|
|
146
|
+
**Attributes:**
|
|
147
|
+
|
|
148
|
+
* `job_id` — ID of the background job (e.g., `AuditorJob`), if applicable.
|
|
149
|
+
* `request_id` — Unique ID representing the request or job context.
|
|
150
|
+
|
|
151
|
+
**Indexes:**
|
|
152
|
+
|
|
153
|
+
* `job_id` — Unique index to ensure one context per job.
|
|
154
|
+
* `request_id` — Standard index to optimize lookups by request.
|
|
155
|
+
|
|
156
|
+
**Usage:**
|
|
157
|
+
`RequestContext` allows the auditor to link audit logs to a specific request or background job, making it easier to
|
|
158
|
+
trace changes and errors back to the original operation.
|
|
159
|
+
|
|
160
|
+
**NOTE:** The `RequestContext` data is automatically deleted after 24 hours (via TTL index) and also cleaned up when jobs complete to prevent unbounded growth and minimize database usage. This ensures the audit system remains efficient and does not consume unnecessary space.
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
### Mongoid::Auditor::Current
|
|
164
|
+
|
|
165
|
+
`Mongoid::Auditor::Current` is a `CurrentAttributes` singleton that keeps request-specific audit state in memory. It provides a thread-safe way to store and access audit-related data during a request or job execution.
|
|
166
|
+
|
|
167
|
+
**Attributes:**
|
|
168
|
+
|
|
169
|
+
* `request_id` — Current request or job ID for the audit.
|
|
170
|
+
* `actor_id` — ID of the user or system performing the action.
|
|
171
|
+
* `path` — Controller action name or job name being executed.
|
|
172
|
+
* `request_params` — Parameters of the current request.
|
|
173
|
+
* `audit_logs` — Collection of `AuditLog` entries accumulated during the request.
|
|
174
|
+
* `audit_sequence` — Incremental sequence number used to order audit events for the current request.
|
|
175
|
+
|
|
176
|
+
**Usage:**
|
|
177
|
+
`Mongoid::Auditor::Current` ensures that every audit event created during a request or background job has consistent context. For example, `AuditLog` entries can reference `Current.request_id` and `Current.actor_id` to maintain traceability across all operations within that request.
|
|
178
|
+
|
|
179
|
+
### Example Audit Workflow
|
|
180
|
+
|
|
181
|
+
**Creating a Product:**
|
|
182
|
+
|
|
183
|
+
```ruby
|
|
184
|
+
product = Product.create(name: "Laptop", price: 999.99)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
`AuditorJob` creates an `AuditLog` entry:
|
|
188
|
+
|
|
189
|
+
```ruby
|
|
190
|
+
{
|
|
191
|
+
request_id: "req-456",
|
|
192
|
+
actor: "",
|
|
193
|
+
path: "POST api/v1/products/create",
|
|
194
|
+
model_type: "Product",
|
|
195
|
+
model_id: '68d95bc84cf7bc8798179ebd',
|
|
196
|
+
event: "create",
|
|
197
|
+
dirties: { name: [nil, "Laptop"], price: [nil, 999.99] },
|
|
198
|
+
sequence: 1,
|
|
199
|
+
has_error: false,
|
|
200
|
+
error: nil
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**Updating a Product:**
|
|
205
|
+
|
|
206
|
+
```ruby
|
|
207
|
+
product.update(price: 1099.99)
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
`AuditorJob` logs:
|
|
211
|
+
|
|
212
|
+
```ruby
|
|
213
|
+
{
|
|
214
|
+
request_id: "req-457",
|
|
215
|
+
actor: "user@example.com",
|
|
216
|
+
path: "PUT api/v1/products/#{product.id}",
|
|
217
|
+
model_type: "Product",
|
|
218
|
+
model_id: product.id.to_s,
|
|
219
|
+
event: "update",
|
|
220
|
+
dirties: { price: [999.99, 1099.99] },
|
|
221
|
+
sequence: 2,
|
|
222
|
+
has_error: false,
|
|
223
|
+
error: nil
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Controller Error:**
|
|
228
|
+
If a validation fails in `ProductsController`:
|
|
229
|
+
|
|
230
|
+
```ruby
|
|
231
|
+
{
|
|
232
|
+
request_id: "req-458",
|
|
233
|
+
actor: "user@example.com",
|
|
234
|
+
path: "PUT api/v1/products/123",
|
|
235
|
+
model_type: "Product",
|
|
236
|
+
model_id: "123",
|
|
237
|
+
event: "update",
|
|
238
|
+
has_error: true,
|
|
239
|
+
dirties: {},
|
|
240
|
+
sequence: 3,
|
|
241
|
+
error: {
|
|
242
|
+
class: "ActiveRecord::RecordInvalid",
|
|
243
|
+
message: "Validation failed: Name can't be blank",
|
|
244
|
+
backtrace: ["..."]
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Development
|
|
250
|
+
|
|
251
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt.
|
|
252
|
+
|
|
253
|
+
To install this gem locally, run `bundle exec rake install`. To release a new version, update the version in `version.rb`, then run `bundle exec rake release` to create a git tag, push commits, and release to [RubyGems](https://rubygems.org).
|
|
254
|
+
|
|
255
|
+
## Troubleshooting
|
|
256
|
+
|
|
257
|
+
* **Performance Concerns:** `Mongoid::Auditor::AuditorJob` processes logs asynchronously. Disable auditing for high-traffic endpoints using `skip_before_action` or `skip_audit_for`.
|
|
258
|
+
* **Large Audit Logs:** Use Mongoid's query capabilities to filter or archive old `AuditLog` entries. Consider adding TTL indexes for automatic cleanup.
|
|
259
|
+
* **Missing Logs:** Ensure `config.enabled` is true and relevant concerns are included. Check that `Current.path` is set (it's nil for GET requests by default).
|
|
260
|
+
* **Database Indexes:** The gem includes indexes on commonly queried fields (`request_id`, `model_type`, `model_id`, `actor`, `has_error`, `created_at`) for optimal query performance.
|
|
261
|
+
|
|
262
|
+
## Contributing
|
|
263
|
+
|
|
264
|
+
Bug reports and pull requests are welcome on GitHub at [https://github.com/[USERNAME]/mongoid-auditor](https://github.com/[USERNAME]/mongoid-auditor). Please follow the [code of conduct](https://github.com/[USERNAME]/mongoid-auditor/blob/main/CODE_OF_CONDUCT.md).
|
|
265
|
+
|
|
266
|
+
## License
|
|
267
|
+
|
|
268
|
+
The gem is available under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
269
|
+
|
|
270
|
+
## Code of Conduct
|
|
271
|
+
|
|
272
|
+
Everyone interacting in the Mongoid::Auditor project is expected to follow the [code of conduct](https://github.com/[USERNAME]/mongoid-auditor/blob/main/CODE_OF_CONDUCT.md).
|
data/Rakefile
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mongoid
|
|
4
|
+
module Auditor
|
|
5
|
+
class Audit
|
|
6
|
+
class << self
|
|
7
|
+
def log(entry)
|
|
8
|
+
return unless entry.is_a?(Hash)
|
|
9
|
+
|
|
10
|
+
::Mongoid::Auditor::AuditLog.create!(entry)
|
|
11
|
+
rescue StandardError => e
|
|
12
|
+
logger&.error("Auditor::Audit.log failed: #{e.class} #{e.message}\n#{e.backtrace&.take(5)&.join("\n")}")
|
|
13
|
+
log_error(e, entry)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def logger
|
|
17
|
+
defined?(Rails) ? Rails.logger : nil
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def log_error(err, entry)
|
|
23
|
+
::Mongoid::Auditor::AuditLog.create!(
|
|
24
|
+
request_id: entry[:request_id],
|
|
25
|
+
actor: entry[:actor],
|
|
26
|
+
path: entry[:path],
|
|
27
|
+
params: entry[:params],
|
|
28
|
+
model_type: entry[:model_type],
|
|
29
|
+
model_id: entry[:model_id],
|
|
30
|
+
has_error: true,
|
|
31
|
+
event: entry[:event] || 'error',
|
|
32
|
+
dirties: entry[:dirties] || {},
|
|
33
|
+
sequence: entry[:sequence],
|
|
34
|
+
error: error_data(err)
|
|
35
|
+
)
|
|
36
|
+
rescue StandardError => e
|
|
37
|
+
logger&.error("Auditor::Audit.log failed to persist error: #{e.class} #{e.message}\n#{e.backtrace&.take(5)&.join("\n")}")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def error_data(err)
|
|
41
|
+
if err.is_a?(StandardError)
|
|
42
|
+
{ class: err.class.to_s, message: err.message, backtrace: err.backtrace&.take(10) }
|
|
43
|
+
elsif err.is_a?(Hash)
|
|
44
|
+
{ class: err[:class] || err['class'], message: err[:message] || err['message'], backtrace: err[:backtrace] || err['backtrace'] }
|
|
45
|
+
else
|
|
46
|
+
{ class: err.class.to_s, message: err.to_s, backtrace: nil }
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mongoid
|
|
4
|
+
module Auditor
|
|
5
|
+
class Configuration
|
|
6
|
+
attr_accessor :enabled, :log_models, :log_controllers, :queue_name, :skip_password_fields
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
@enabled = true
|
|
10
|
+
@log_models = true
|
|
11
|
+
@log_controllers = true
|
|
12
|
+
@queue_name = :default
|
|
13
|
+
@skip_password_fields = %w[password password_confirmation token secret api_key]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Helper method to check if auditing should be skipped for a specific environment
|
|
17
|
+
def enabled_for_environment?
|
|
18
|
+
return false unless enabled
|
|
19
|
+
|
|
20
|
+
# Skip in test environment by default unless explicitly enabled
|
|
21
|
+
return false if defined?(Rails) && Rails.env.test? && enabled == true
|
|
22
|
+
|
|
23
|
+
enabled
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/generators'
|
|
4
|
+
|
|
5
|
+
module Mongoid
|
|
6
|
+
module Auditor
|
|
7
|
+
module Generators
|
|
8
|
+
class InstallGenerator < Rails::Generators::Base
|
|
9
|
+
source_root File.expand_path('templates', __dir__)
|
|
10
|
+
desc 'Creates a Mongoid Auditor initializer in your Rails application.'
|
|
11
|
+
|
|
12
|
+
def copy_initializer
|
|
13
|
+
template 'mongoid_auditor_initializer.rb', 'config/initializers/mongoid_auditor.rb'
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mongoid
|
|
4
|
+
module Auditor
|
|
5
|
+
module AuditControllerErrorLog
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
included do
|
|
9
|
+
around_action :audit_exceptions
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def audit_exceptions
|
|
15
|
+
yield
|
|
16
|
+
rescue StandardError => e
|
|
17
|
+
audit_error(e)
|
|
18
|
+
raise
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def audit_error(exception)
|
|
22
|
+
return unless ::Mongoid::Auditor.config.enabled && ::Mongoid::Auditor.config.log_controllers
|
|
23
|
+
|
|
24
|
+
data = build_entry(exception)
|
|
25
|
+
::Mongoid::Auditor::AuditorJob.perform_later(:controller, data[:error], data[:entry])
|
|
26
|
+
rescue StandardError => e
|
|
27
|
+
Rails.logger&.error("AuditLogger failed to log error: #{e.class} #{e.message}\n#{e.backtrace&.take(5)&.join("\n")}")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def build_entry(exception)
|
|
31
|
+
model_name = model_context_from_params(request.params)
|
|
32
|
+
{
|
|
33
|
+
entry: {
|
|
34
|
+
request_id: request&.request_id,
|
|
35
|
+
actor: current_user&.id&.to_s,
|
|
36
|
+
path: "#{request.method} #{request.fullpath}",
|
|
37
|
+
params: filter_sensitive_params(request.filtered_parameters.except(:controller, :action)),
|
|
38
|
+
model_type: model_name,
|
|
39
|
+
model_id: request.params[:id],
|
|
40
|
+
has_error: true,
|
|
41
|
+
event: request.params[:action],
|
|
42
|
+
dirties: {},
|
|
43
|
+
sequence: ::Mongoid::Auditor::Current.audit_sequence.to_i + 1
|
|
44
|
+
},
|
|
45
|
+
error: {
|
|
46
|
+
class: exception.class.to_s,
|
|
47
|
+
message: exception.message,
|
|
48
|
+
backtrace: exception.backtrace&.take(5)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def model_context_from_params(params)
|
|
54
|
+
extract_model_type(params) || fallback_model_type(params[:controller])
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def extract_model_type(params)
|
|
58
|
+
params.keys
|
|
59
|
+
.reject { |k| k.in?(%w[controller action id]) || k.end_with?('_id') }
|
|
60
|
+
.first
|
|
61
|
+
&.singularize
|
|
62
|
+
&.camelize
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def fallback_model_type(controller_name)
|
|
66
|
+
controller_name.split('/').last.singularize.camelize
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def filter_sensitive_params(params)
|
|
70
|
+
skip_fields = ::Mongoid::Auditor.config.skip_password_fields || []
|
|
71
|
+
params.except(*skip_fields)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mongoid
|
|
4
|
+
module Auditor
|
|
5
|
+
module ControllerAuditHelper
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
class_methods do
|
|
9
|
+
def skip_audit_for(*actions)
|
|
10
|
+
skip_before_action :init_audit_store, only: actions
|
|
11
|
+
before_action :set_skip_audit_flag, only: actions
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def set_skip_audit_flag
|
|
18
|
+
::Mongoid::Auditor::Current.path = nil
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|