easyop 0.1.4 → 0.1.5
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 +4 -4
- data/CHANGELOG.md +39 -1
- data/README.md +32 -10
- data/lib/easyop/configuration.rb +12 -3
- data/lib/easyop/plugins/recording.rb +53 -3
- data/lib/easyop/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c649ea27731299fcf70421b41e0a19cca45612aa621310bf1bb87a70f5100da6
|
|
4
|
+
data.tar.gz: 7589af6ce926df84ccafb1df8b705430aaabc82b0929a0b9d8ed9bb4b7db818d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fc1a7e1c0427da2abb6588c61ece675431708b3b2a2bb623e62356ebfb6edf69025f6c13004ef6967d62f9381cb6c003793958f1c98326c34ba6266a9a56f774
|
|
7
|
+
data.tar.gz: d40f2a49035f449f95bfcefaae66dacc6c4d2e015d03d66c88f5f74e1680f8d7713d3f079ece4011d77ea238fc6181cf7072fbfe651a4be9be0876e5c8839eb2
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,43 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.1.5] — 2026-04-14
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`scrub_params` DSL for `Easyop::Plugins::Recording`** — declare additional params keys/patterns to scrub from `params_data` on a per-class basis. Accepts `Symbol`, `String`, or `Regexp`. Additive with `SCRUBBED_KEYS` and never replaces the built-in list. Inherited by subclasses; any level of the hierarchy can override.
|
|
15
|
+
|
|
16
|
+
```ruby
|
|
17
|
+
class ApplicationOperation < ...
|
|
18
|
+
scrub_params :api_token, /access.?key/i
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class Orders::CreateOrder < ApplicationOperation
|
|
22
|
+
scrub_params :card_number # stacks on top of parent's scrub list
|
|
23
|
+
end
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
- **`scrub_keys:` option on `plugin Easyop::Plugins::Recording`** — supply a list of extra keys/patterns to scrub at plugin install time. Inherited by all classes that share the same `plugin` declaration.
|
|
27
|
+
|
|
28
|
+
```ruby
|
|
29
|
+
plugin Easyop::Plugins::Recording,
|
|
30
|
+
model: OperationLog,
|
|
31
|
+
scrub_keys: [:stripe_token, /secret/i]
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- **`Easyop::Configuration#recording_scrub_keys`** — new global config key. Set once at boot and every recorded operation will scrub these keys in addition to `SCRUBBED_KEYS` and any class-level declarations. Accepts `Symbol`, `String`, or `Regexp`.
|
|
35
|
+
|
|
36
|
+
```ruby
|
|
37
|
+
Easyop.configure do |c|
|
|
38
|
+
c.recording_scrub_keys = [:api_token, /token/i]
|
|
39
|
+
end
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Scrub precedence (all layers are additive):**
|
|
43
|
+
1. `SCRUBBED_KEYS` — always applied (built-in list)
|
|
44
|
+
2. `Easyop.config.recording_scrub_keys` — global config
|
|
45
|
+
3. `scrub_keys:` plugin option + `scrub_params` DSL — class hierarchy
|
|
46
|
+
|
|
10
47
|
## [0.1.4] — 2026-04-14
|
|
11
48
|
|
|
12
49
|
### Added
|
|
@@ -258,6 +295,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
258
295
|
- `examples/easyop_test_app/` — full Rails 8 blog application demonstrating all features in real-world code
|
|
259
296
|
- `examples/usage.rb` — 13 runnable plain-Ruby examples
|
|
260
297
|
|
|
261
|
-
[Unreleased]: https://github.com/pniemczyk/easyop/compare/v0.1.
|
|
298
|
+
[Unreleased]: https://github.com/pniemczyk/easyop/compare/v0.1.5...HEAD
|
|
299
|
+
[0.1.5]: https://github.com/pniemczyk/easyop/compare/v0.1.4...v0.1.5
|
|
262
300
|
[0.1.4]: https://github.com/pniemczyk/easyop/compare/v0.1.3...v0.1.4
|
|
263
301
|
[0.1.3]: https://github.com/pniemczyk/easyop/compare/v0.1.2...v0.1.3
|
data/README.md
CHANGED
|
@@ -647,6 +647,7 @@ end
|
|
|
647
647
|
| `model:` | required | ActiveRecord class to write logs into |
|
|
648
648
|
| `record_params:` | `true` | Set `false` to skip serializing ctx params |
|
|
649
649
|
| `record_result:` | `nil` | Plugin-level default for result capture (Hash/Proc/Symbol — see below) |
|
|
650
|
+
| `scrub_keys:` | `[]` | Extra keys/patterns to scrub from `params_data` (Symbol, String, Regexp) — additive with built-in list |
|
|
650
651
|
|
|
651
652
|
**Required model columns:**
|
|
652
653
|
|
|
@@ -696,7 +697,28 @@ root_log = OperationLog.find_by(operation_name: "FullCheckout", parent_reference
|
|
|
696
697
|
OperationLog.for_tree(root_log.root_reference_id)
|
|
697
698
|
```
|
|
698
699
|
|
|
699
|
-
|
|
700
|
+
**Scrubbing params** — all layers are additive (none replaces the built-in list):
|
|
701
|
+
|
|
702
|
+
1. **Built-in `SCRUBBED_KEYS`** — always applied: `:password`, `:password_confirmation`, `:token`, `:secret`, `:api_key`
|
|
703
|
+
2. **Global config** — applied to every recorded operation:
|
|
704
|
+
```ruby
|
|
705
|
+
Easyop.configure { |c| c.recording_scrub_keys = [:api_token, /token/i] }
|
|
706
|
+
```
|
|
707
|
+
3. **Plugin `scrub_keys:` option** — applied to all subclasses that share the plugin install:
|
|
708
|
+
```ruby
|
|
709
|
+
plugin Easyop::Plugins::Recording, model: OperationLog, scrub_keys: [:stripe_secret]
|
|
710
|
+
```
|
|
711
|
+
4. **`scrub_params` DSL** — per-class, inheritable, and stackable at any level of the hierarchy:
|
|
712
|
+
```ruby
|
|
713
|
+
class ApplicationOperation < ...
|
|
714
|
+
scrub_params :internal_token, /access.?key/i
|
|
715
|
+
end
|
|
716
|
+
class Payments::ChargeCard < ApplicationOperation
|
|
717
|
+
scrub_params :card_number # stacks on top of parent's list
|
|
718
|
+
end
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
Internal tracing keys (`__recording_*`) are always excluded. ActiveRecord objects are serialized as `{ id:, class: }` rather than their full representation.
|
|
700
722
|
|
|
701
723
|
**`record_result` DSL — capture output data:**
|
|
702
724
|
|
|
@@ -1459,7 +1481,7 @@ Edit `lib/easyop/version.rb` and increment the version string following [Semanti
|
|
|
1459
1481
|
```ruby
|
|
1460
1482
|
# lib/easyop/version.rb
|
|
1461
1483
|
module Easyop
|
|
1462
|
-
VERSION = "0.1.
|
|
1484
|
+
VERSION = "0.1.5" # was 0.1.4
|
|
1463
1485
|
end
|
|
1464
1486
|
```
|
|
1465
1487
|
|
|
@@ -1470,45 +1492,45 @@ In `CHANGELOG.md`, move everything under `[Unreleased]` into a new versioned sec
|
|
|
1470
1492
|
```markdown
|
|
1471
1493
|
## [Unreleased]
|
|
1472
1494
|
|
|
1473
|
-
## [0.1.
|
|
1495
|
+
## [0.1.5] — YYYY-MM-DD # ← new section
|
|
1474
1496
|
|
|
1475
1497
|
### Added
|
|
1476
1498
|
- …
|
|
1477
1499
|
|
|
1478
|
-
## [0.1.
|
|
1500
|
+
## [0.1.4] — 2026-04-14
|
|
1479
1501
|
```
|
|
1480
1502
|
|
|
1481
1503
|
Add a comparison link at the bottom of the file:
|
|
1482
1504
|
|
|
1483
1505
|
```markdown
|
|
1484
|
-
[Unreleased]: https://github.com/pniemczyk/easyop/compare/v0.1.
|
|
1506
|
+
[Unreleased]: https://github.com/pniemczyk/easyop/compare/v0.1.5...HEAD
|
|
1507
|
+
[0.1.5]: https://github.com/pniemczyk/easyop/compare/v0.1.4...v0.1.5
|
|
1485
1508
|
[0.1.4]: https://github.com/pniemczyk/easyop/compare/v0.1.3...v0.1.4
|
|
1486
|
-
[0.1.3]: https://github.com/pniemczyk/easyop/compare/v0.1.2...v0.1.3
|
|
1487
1509
|
```
|
|
1488
1510
|
|
|
1489
1511
|
### 3. Commit the release changes
|
|
1490
1512
|
|
|
1491
1513
|
```bash
|
|
1492
1514
|
git add lib/easyop/version.rb CHANGELOG.md
|
|
1493
|
-
git commit -m "Release v0.1.
|
|
1515
|
+
git commit -m "Release v0.1.5"
|
|
1494
1516
|
```
|
|
1495
1517
|
|
|
1496
1518
|
### 4. Tag the commit
|
|
1497
1519
|
|
|
1498
1520
|
```bash
|
|
1499
|
-
git tag -a v0.1.
|
|
1521
|
+
git tag -a v0.1.5 -m "Release v0.1.5"
|
|
1500
1522
|
```
|
|
1501
1523
|
|
|
1502
1524
|
### 5. Push the commit and tag
|
|
1503
1525
|
|
|
1504
1526
|
```bash
|
|
1505
1527
|
git push origin master
|
|
1506
|
-
git push origin v0.1.
|
|
1528
|
+
git push origin v0.1.5
|
|
1507
1529
|
```
|
|
1508
1530
|
|
|
1509
1531
|
### 6. Build and push the gem (optional)
|
|
1510
1532
|
|
|
1511
1533
|
```bash
|
|
1512
1534
|
gem build easyop.gemspec
|
|
1513
|
-
gem push easyop-0.1.
|
|
1535
|
+
gem push easyop-0.1.5.gem
|
|
1514
1536
|
```
|
data/lib/easyop/configuration.rb
CHANGED
|
@@ -15,10 +15,19 @@ module Easyop
|
|
|
15
15
|
# Easyop.configure { |c| c.event_bus = :active_support }
|
|
16
16
|
attr_accessor :event_bus
|
|
17
17
|
|
|
18
|
+
# Extra keys to scrub from params_data across all recorded operations.
|
|
19
|
+
# Appended to Recording::SCRUBBED_KEYS — never replaces the built-in list.
|
|
20
|
+
# Accepts Symbol, String, or Regexp (matched against the stringified key name).
|
|
21
|
+
#
|
|
22
|
+
# @example
|
|
23
|
+
# Easyop.configure { |c| c.recording_scrub_keys = [:api_token, /token/i] }
|
|
24
|
+
attr_accessor :recording_scrub_keys
|
|
25
|
+
|
|
18
26
|
def initialize
|
|
19
|
-
@type_adapter
|
|
20
|
-
@strict_types
|
|
21
|
-
@event_bus
|
|
27
|
+
@type_adapter = :native
|
|
28
|
+
@strict_types = false
|
|
29
|
+
@event_bus = nil # nil = Memory bus (see Easyop::Events::Registry)
|
|
30
|
+
@recording_scrub_keys = []
|
|
22
31
|
end
|
|
23
32
|
end
|
|
24
33
|
|
|
@@ -38,8 +38,10 @@ module Easyop
|
|
|
38
38
|
# model: (required) ActiveRecord class
|
|
39
39
|
# record_params: true pass false to skip params serialization
|
|
40
40
|
# record_result: nil configure result capture at plugin level (Hash/Proc/Symbol)
|
|
41
|
+
# scrub_keys: [] additional keys/patterns to scrub from params_data
|
|
42
|
+
# (Symbol, String, or Regexp — additive with SCRUBBED_KEYS)
|
|
41
43
|
module Recording
|
|
42
|
-
# Sensitive keys scrubbed from params_data before persisting.
|
|
44
|
+
# Sensitive keys always scrubbed from params_data before persisting.
|
|
43
45
|
SCRUBBED_KEYS = %i[password password_confirmation token secret api_key].freeze
|
|
44
46
|
|
|
45
47
|
# Internal ctx keys used for flow tracing — excluded from params_data.
|
|
@@ -49,12 +51,13 @@ module Easyop
|
|
|
49
51
|
__recording_parent_reference_id
|
|
50
52
|
].freeze
|
|
51
53
|
|
|
52
|
-
def self.install(base, model:, record_params: true, record_result: nil, **_options)
|
|
54
|
+
def self.install(base, model:, record_params: true, record_result: nil, scrub_keys: [], **_options)
|
|
53
55
|
base.extend(ClassMethods)
|
|
54
56
|
base.prepend(RunWrapper)
|
|
55
57
|
base.instance_variable_set(:@_recording_model, model)
|
|
56
58
|
base.instance_variable_set(:@_recording_record_params, record_params)
|
|
57
59
|
base.instance_variable_set(:@_recording_record_result, record_result)
|
|
60
|
+
base.instance_variable_set(:@_recording_scrub_keys, Array(scrub_keys))
|
|
58
61
|
end
|
|
59
62
|
|
|
60
63
|
module ClassMethods
|
|
@@ -109,6 +112,32 @@ module Easyop
|
|
|
109
112
|
nil
|
|
110
113
|
end
|
|
111
114
|
end
|
|
115
|
+
|
|
116
|
+
# DSL to declare additional keys/patterns to scrub from params_data.
|
|
117
|
+
# Accepts Symbol, String, or Regexp. Additive with SCRUBBED_KEYS and
|
|
118
|
+
# any scrub_keys declared on parent classes or at the plugin install level.
|
|
119
|
+
#
|
|
120
|
+
# @example
|
|
121
|
+
# class ApplicationOperation < ...
|
|
122
|
+
# scrub_params :api_token, /access.?key/i
|
|
123
|
+
# end
|
|
124
|
+
def scrub_params(*keys)
|
|
125
|
+
@_recording_scrub_keys = _own_recording_scrub_keys + keys
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Returns the merged scrub list: parent class keys + this class's own keys.
|
|
129
|
+
# Does NOT include SCRUBBED_KEYS or the global config list — those are
|
|
130
|
+
# merged at persist time so they stay hot-reloadable.
|
|
131
|
+
def _recording_scrub_keys
|
|
132
|
+
parent = superclass.respond_to?(:_recording_scrub_keys) ? superclass._recording_scrub_keys : []
|
|
133
|
+
parent + _own_recording_scrub_keys
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
private
|
|
137
|
+
|
|
138
|
+
def _own_recording_scrub_keys
|
|
139
|
+
instance_variable_defined?(:@_recording_scrub_keys) ? @_recording_scrub_keys : []
|
|
140
|
+
end
|
|
112
141
|
end
|
|
113
142
|
|
|
114
143
|
module RunWrapper
|
|
@@ -182,14 +211,35 @@ module Easyop
|
|
|
182
211
|
end
|
|
183
212
|
|
|
184
213
|
def _recording_safe_params(ctx)
|
|
214
|
+
# Merge all scrub layers (additive, never replaces built-ins):
|
|
215
|
+
# 1. SCRUBBED_KEYS — built-in sensitive keys, always applied
|
|
216
|
+
# 2. Easyop.config — global extra keys set in an initializer
|
|
217
|
+
# 3. self.class — plugin install scrub_keys: + class scrub_params DSL
|
|
218
|
+
extra = Easyop.config.recording_scrub_keys.to_a + self.class._recording_scrub_keys
|
|
185
219
|
ctx.to_h
|
|
186
|
-
.except(*
|
|
220
|
+
.except(*INTERNAL_CTX_KEYS)
|
|
221
|
+
.reject { |k, _| _recording_scrub_key?(k, extra) }
|
|
187
222
|
.transform_values { |v| v.is_a?(ActiveRecord::Base) ? { id: v.id, class: v.class.name } : v }
|
|
188
223
|
.to_json
|
|
189
224
|
rescue
|
|
190
225
|
nil
|
|
191
226
|
end
|
|
192
227
|
|
|
228
|
+
# Returns true when +key+ matches any entry in +scrub_list+.
|
|
229
|
+
# Regexp entries match against the stringified key name (case-sensitive
|
|
230
|
+
# unless the Regexp itself uses /i). Symbol/String entries match by value.
|
|
231
|
+
def _recording_scrub_key?(key, extra_list)
|
|
232
|
+
return true if SCRUBBED_KEYS.include?(key.to_sym)
|
|
233
|
+
|
|
234
|
+
extra_list.any? do |pattern|
|
|
235
|
+
case pattern
|
|
236
|
+
when Regexp then pattern.match?(key.to_s)
|
|
237
|
+
when Symbol then pattern == key.to_sym
|
|
238
|
+
else pattern.to_s == key.to_s
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
193
243
|
def _recording_safe_result(ctx)
|
|
194
244
|
config = self.class._recording_record_result_config
|
|
195
245
|
return nil unless config
|
data/lib/easyop/version.rb
CHANGED