sequel-privacy 0.7.0 → 0.7.2
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 +9 -0
- data/README.md +7 -4
- data/lib/sequel/privacy/cache.rb +30 -6
- data/lib/sequel/privacy/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3a775f6a706825d2606e667f2b83076f00bed29b079e18581be62a6452bbff32
|
|
4
|
+
data.tar.gz: 538b8ca6f3eb9c748a2697dab1a0d9f5b013c2a0cabaa4f06702513def743bd9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8c1e2f5aad69229373e401207e4e3aa664f8c9f8a5e615d147208c24690dbe32155647a8d7e6dd3a81543e8f838dc1b449a993be4a2d24511c11418cddc94bc2
|
|
7
|
+
data.tar.gz: f5397fe792ad89555aed6e81bb40be6ced0cfdc0e88ebd9c20e09c6466351498dc83293a6a5a2f41dd86d978721ad702ca8f8e87e4e9d999bc970b21e6e278d7
|
data/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
|
|
4
4
|
## [Unreleased]
|
|
5
5
|
|
|
6
|
+
## [0.7.2] – 2026-09-21
|
|
7
|
+
|
|
8
|
+
- Reduced the overhead of operation-scoped cache access.
|
|
9
|
+
|
|
10
|
+
## [0.7.1] – 2026-09-21
|
|
11
|
+
|
|
12
|
+
- Added `Sequel::Privacy.with_cache_scope` for nested, exception-safe policy
|
|
13
|
+
caches isolated between concurrent threads and fibers.
|
|
14
|
+
|
|
6
15
|
## [0.7.0] – 2026-08-26
|
|
7
16
|
- Removed `#for_vc` on `Sequel::Model` instances. Instead, call `#reset_viewer_context(vc, reason)`.
|
|
8
17
|
- Removed `#viewer_context=` from `Sequel::Model` instances.
|
data/README.md
CHANGED
|
@@ -402,7 +402,9 @@ Sequel::Privacy.logger = SemanticLogger['Privacy']
|
|
|
402
402
|
|
|
403
403
|
## Cache Management
|
|
404
404
|
|
|
405
|
-
Policy results are cached per
|
|
405
|
+
Policy results are cached per operation to avoid redundant evaluation. Wrap
|
|
406
|
+
each request, job, or other independent operation in a cache scope. Scopes are
|
|
407
|
+
isolated between concurrent threads and fibers:
|
|
406
408
|
|
|
407
409
|
```ruby
|
|
408
410
|
# In Rack middleware
|
|
@@ -412,13 +414,14 @@ class PrivacyCacheMiddleware
|
|
|
412
414
|
end
|
|
413
415
|
|
|
414
416
|
def call(env)
|
|
415
|
-
Sequel::Privacy.
|
|
416
|
-
@app.call(env)
|
|
417
|
+
Sequel::Privacy.with_cache_scope { @app.call(env) }
|
|
417
418
|
end
|
|
418
419
|
end
|
|
419
420
|
```
|
|
420
421
|
|
|
421
|
-
|
|
422
|
+
Scopes may be nested and are restored after exceptions. `clear_cache!` clears
|
|
423
|
+
only the active scope. Applications not yet using scopes retain the legacy
|
|
424
|
+
process-global cache and can clear it manually:
|
|
422
425
|
|
|
423
426
|
```ruby
|
|
424
427
|
Sequel::Privacy.clear_cache!
|
data/lib/sequel/privacy/cache.rb
CHANGED
|
@@ -2,28 +2,52 @@
|
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
module Sequel
|
|
5
|
+
# Privacy enforcement and operation-scoped policy caching.
|
|
5
6
|
module Privacy
|
|
6
|
-
# In-memory cache for policy evaluation results.
|
|
7
|
-
#
|
|
7
|
+
# In-memory cache for policy evaluation results. Concurrent applications
|
|
8
|
+
# should wrap each independent operation in with_cache_scope.
|
|
8
9
|
class << self
|
|
9
10
|
extend T::Sig
|
|
10
11
|
|
|
12
|
+
CACHE_SCOPE_KEY = :sequel_privacy_cache_scope
|
|
13
|
+
private_constant :CACHE_SCOPE_KEY
|
|
14
|
+
|
|
15
|
+
sig do
|
|
16
|
+
type_parameters(:U)
|
|
17
|
+
.params(block: T.proc.returns(T.type_parameter(:U)))
|
|
18
|
+
.returns(T.type_parameter(:U))
|
|
19
|
+
end
|
|
20
|
+
def with_cache_scope(&block)
|
|
21
|
+
previous = Thread.current[CACHE_SCOPE_KEY]
|
|
22
|
+
Thread.current[CACHE_SCOPE_KEY] = [{}, {}]
|
|
23
|
+
block.()
|
|
24
|
+
ensure
|
|
25
|
+
Thread.current[CACHE_SCOPE_KEY] = previous
|
|
26
|
+
end
|
|
27
|
+
|
|
11
28
|
sig { returns(T::Hash[Integer, Symbol]) }
|
|
12
29
|
def cache
|
|
13
|
-
|
|
30
|
+
scope = Thread.current[CACHE_SCOPE_KEY]
|
|
31
|
+
scope ? scope[0] : (@cache ||= T.let({}, T.nilable(T::Hash[Integer, Symbol])))
|
|
14
32
|
end
|
|
15
33
|
|
|
16
34
|
# Tracks single-match optimization state.
|
|
17
35
|
# Key: [policy, actor, viewer_context].hash → Value: subject.hash
|
|
18
36
|
sig { returns(T::Hash[Integer, Integer]) }
|
|
19
37
|
def single_matches
|
|
20
|
-
|
|
38
|
+
scope = Thread.current[CACHE_SCOPE_KEY]
|
|
39
|
+
scope ? scope[1] : (@single_matches ||= T.let({}, T.nilable(T::Hash[Integer, Integer])))
|
|
21
40
|
end
|
|
22
41
|
|
|
23
42
|
sig { void }
|
|
24
43
|
def clear_cache!
|
|
25
|
-
|
|
26
|
-
|
|
44
|
+
if (scope = Thread.current[CACHE_SCOPE_KEY])
|
|
45
|
+
scope[0] = {}
|
|
46
|
+
scope[1] = {}
|
|
47
|
+
else
|
|
48
|
+
@cache = {}
|
|
49
|
+
@single_matches = {}
|
|
50
|
+
end
|
|
27
51
|
end
|
|
28
52
|
end
|
|
29
53
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sequel-privacy
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.7.
|
|
4
|
+
version: 0.7.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Austin Bales
|
|
@@ -152,7 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
152
152
|
- !ruby/object:Gem::Version
|
|
153
153
|
version: '0'
|
|
154
154
|
requirements: []
|
|
155
|
-
rubygems_version: 4.0.
|
|
155
|
+
rubygems_version: 4.0.21
|
|
156
156
|
specification_version: 4
|
|
157
157
|
summary: Privacy enforcement plugin for Sequel models
|
|
158
158
|
test_files: []
|