optify-config 1.23.2 → 1.24.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 +4 -4
- data/ext/optify_ruby/Cargo.toml +2 -2
- data/ext/optify_ruby/src/lib.rs +84 -0
- data/ext/optify_ruby/src/preferences.rs +18 -0
- data/lib/optify_ruby/policies.rb +33 -0
- data/lib/optify_ruby/provider_module.rb +27 -1
- data/rbi/optify.rbi +72 -0
- data/sig/optify.rbs +44 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f295ac7d00dec19d6aac47bdd92452ec0768181e482a24fdcc5de2d85900df31
|
|
4
|
+
data.tar.gz: 9429b9927048c2fb85c7343a839b78947212ba6192091852d9a30bcbd8078420
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3225dcc9006955335b31f0cfa934c97c9460fad48b2adfc5521a2a21597047f9057fc057c6f9699660d4bdee4346b0d827e73e7bd7a1af338cb9f974cde0d42c
|
|
7
|
+
data.tar.gz: 80247e4b63f23e9625365c39e725dbfe4976135a08ec7ec8c497c0be3bbf197ea5437448971b181c1b6255c13198341790f0f4dc003bb0056423f76592cf7881
|
data/ext/optify_ruby/Cargo.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "optify_ruby"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.25.0"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
|
|
6
6
|
description = "optify bindings for Ruby"
|
|
@@ -22,6 +22,6 @@ crate-type = ["cdylib"]
|
|
|
22
22
|
[dependencies]
|
|
23
23
|
magnus = "0.8.2"
|
|
24
24
|
# Can't put a relative path here because then others can't install the source gem: https://github.com/juharris/optify/pull/176
|
|
25
|
-
optify = "1.
|
|
25
|
+
optify = "1.4.0"
|
|
26
26
|
rb-sys = { version = "0.9.124", default-features = false, features = ["ruby-static"] }
|
|
27
27
|
serde_json = "1.0.149"
|
data/ext/optify_ruby/src/lib.rs
CHANGED
|
@@ -17,18 +17,29 @@ use crate::preferences::MutGetOptionsPreferences;
|
|
|
17
17
|
mod preferences;
|
|
18
18
|
|
|
19
19
|
const UNKNOWN_FEATURE_PATTERN: &str = "is not a known feature.";
|
|
20
|
+
const POLICY_DENIED_PATTERN: &str = "is not permitted to use feature";
|
|
20
21
|
|
|
21
22
|
fn get_unknown_feature_error(ruby: &Ruby) -> Result<ExceptionClass, magnus::Error> {
|
|
22
23
|
let module: RModule = ruby.class_object().const_get("Optify")?;
|
|
23
24
|
module.const_get("UnknownFeatureError")
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
fn get_policy_denied_error(ruby: &Ruby) -> Result<ExceptionClass, magnus::Error> {
|
|
28
|
+
let module: RModule = ruby.class_object().const_get("Optify")?;
|
|
29
|
+
module.const_get("PolicyDeniedError")
|
|
30
|
+
}
|
|
31
|
+
|
|
26
32
|
fn map_feature_error(ruby: &Ruby, error: String) -> magnus::Error {
|
|
27
33
|
if error.contains(UNKNOWN_FEATURE_PATTERN) {
|
|
28
34
|
match get_unknown_feature_error(ruby) {
|
|
29
35
|
Ok(exception_class) => magnus::Error::new(exception_class, error),
|
|
30
36
|
Err(_) => magnus::Error::new(ruby.exception_runtime_error(), error),
|
|
31
37
|
}
|
|
38
|
+
} else if error.contains(POLICY_DENIED_PATTERN) {
|
|
39
|
+
match get_policy_denied_error(ruby) {
|
|
40
|
+
Ok(exception_class) => magnus::Error::new(exception_class, error),
|
|
41
|
+
Err(_) => magnus::Error::new(ruby.exception_runtime_error(), error),
|
|
42
|
+
}
|
|
32
43
|
} else {
|
|
33
44
|
magnus::Error::new(ruby.exception_runtime_error(), error)
|
|
34
45
|
}
|
|
@@ -115,6 +126,19 @@ impl WrappedOptionsProvider {
|
|
|
115
126
|
}
|
|
116
127
|
}
|
|
117
128
|
|
|
129
|
+
fn check_policies(
|
|
130
|
+
ruby: &Ruby,
|
|
131
|
+
rb_self: &Self,
|
|
132
|
+
requester: String,
|
|
133
|
+
feature_names: Vec<String>,
|
|
134
|
+
) -> Result<(), magnus::Error> {
|
|
135
|
+
rb_self
|
|
136
|
+
.0
|
|
137
|
+
.borrow()
|
|
138
|
+
.check_policies(&requester, &feature_names, None)
|
|
139
|
+
.map_err(|e| map_feature_error(ruby, e))
|
|
140
|
+
}
|
|
141
|
+
|
|
118
142
|
fn get_aliases(&self) -> Vec<String> {
|
|
119
143
|
self.0.borrow().get_aliases()
|
|
120
144
|
}
|
|
@@ -291,6 +315,13 @@ impl WrappedOptionsProvider {
|
|
|
291
315
|
self.0.borrow().has_conditions(&canonical_feature_name)
|
|
292
316
|
}
|
|
293
317
|
|
|
318
|
+
fn get_policies_json(&self, canonical_feature_name: String) -> Option<String> {
|
|
319
|
+
self.0
|
|
320
|
+
.borrow()
|
|
321
|
+
.get_policies(&canonical_feature_name)
|
|
322
|
+
.map(|p| serde_json::to_string(&p).unwrap())
|
|
323
|
+
}
|
|
324
|
+
|
|
294
325
|
fn map_feature_names(
|
|
295
326
|
ruby: &Ruby,
|
|
296
327
|
rb_self: &Self,
|
|
@@ -380,6 +411,19 @@ impl WrappedOptionsWatcher {
|
|
|
380
411
|
}
|
|
381
412
|
}
|
|
382
413
|
|
|
414
|
+
fn check_policies(
|
|
415
|
+
ruby: &Ruby,
|
|
416
|
+
rb_self: &Self,
|
|
417
|
+
requester: String,
|
|
418
|
+
feature_names: Vec<String>,
|
|
419
|
+
) -> Result<(), magnus::Error> {
|
|
420
|
+
rb_self
|
|
421
|
+
.0
|
|
422
|
+
.borrow()
|
|
423
|
+
.check_policies(&requester, &feature_names, None)
|
|
424
|
+
.map_err(|e| map_feature_error(ruby, e))
|
|
425
|
+
}
|
|
426
|
+
|
|
383
427
|
fn get_aliases(&self) -> Vec<String> {
|
|
384
428
|
self.0.borrow().get_aliases()
|
|
385
429
|
}
|
|
@@ -552,6 +596,13 @@ impl WrappedOptionsWatcher {
|
|
|
552
596
|
self.0.borrow().has_conditions(&canonical_feature_name)
|
|
553
597
|
}
|
|
554
598
|
|
|
599
|
+
fn get_policies_json(&self, canonical_feature_name: String) -> Option<String> {
|
|
600
|
+
self.0
|
|
601
|
+
.borrow()
|
|
602
|
+
.get_policies(&canonical_feature_name)
|
|
603
|
+
.map(|p| serde_json::to_string(&p).unwrap())
|
|
604
|
+
}
|
|
605
|
+
|
|
555
606
|
fn last_modified(&self) -> std::time::SystemTime {
|
|
556
607
|
self.0.borrow().last_modified()
|
|
557
608
|
}
|
|
@@ -607,6 +658,7 @@ fn init(ruby: &Ruby) -> Result<(), magnus::Error> {
|
|
|
607
658
|
let module = ruby.define_module("Optify")?;
|
|
608
659
|
|
|
609
660
|
module.define_error("UnknownFeatureError", ruby.exception_standard_error())?;
|
|
661
|
+
module.define_error("PolicyDeniedError", ruby.exception_standard_error())?;
|
|
610
662
|
|
|
611
663
|
let builder_class = module.define_class("OptionsProviderBuilder", ruby.class_object())?;
|
|
612
664
|
|
|
@@ -636,6 +688,10 @@ fn init(ruby: &Ruby) -> Result<(), magnus::Error> {
|
|
|
636
688
|
),
|
|
637
689
|
)?;
|
|
638
690
|
provider_class.define_method("aliases", method!(WrappedOptionsProvider::get_aliases, 0))?;
|
|
691
|
+
provider_class.define_private_method(
|
|
692
|
+
"_check_policies",
|
|
693
|
+
method!(WrappedOptionsProvider::check_policies, 2),
|
|
694
|
+
)?;
|
|
639
695
|
provider_class.define_method("features", method!(WrappedOptionsProvider::get_features, 0))?;
|
|
640
696
|
provider_class.define_method(
|
|
641
697
|
"features_and_aliases",
|
|
@@ -695,6 +751,10 @@ fn init(ruby: &Ruby) -> Result<(), magnus::Error> {
|
|
|
695
751
|
"get_feature_metadata_json",
|
|
696
752
|
method!(WrappedOptionsProvider::get_feature_metadata_json, 1),
|
|
697
753
|
)?;
|
|
754
|
+
provider_class.define_private_method(
|
|
755
|
+
"get_policies_json",
|
|
756
|
+
method!(WrappedOptionsProvider::get_policies_json, 1),
|
|
757
|
+
)?;
|
|
698
758
|
|
|
699
759
|
let get_options_preferences_class =
|
|
700
760
|
module.define_class("GetOptionsPreferences", ruby.class_object())?;
|
|
@@ -757,6 +817,22 @@ fn init(ruby: &Ruby) -> Result<(), magnus::Error> {
|
|
|
757
817
|
"skip_feature_name_conversion",
|
|
758
818
|
method!(MutGetOptionsPreferences::skip_feature_name_conversion, 0),
|
|
759
819
|
)?;
|
|
820
|
+
get_options_preferences_class.define_method(
|
|
821
|
+
"requester=",
|
|
822
|
+
method!(MutGetOptionsPreferences::set_requester, 1),
|
|
823
|
+
)?;
|
|
824
|
+
get_options_preferences_class.define_method(
|
|
825
|
+
"requester",
|
|
826
|
+
method!(MutGetOptionsPreferences::get_requester, 0),
|
|
827
|
+
)?;
|
|
828
|
+
get_options_preferences_class.define_method(
|
|
829
|
+
"raise_if_policy_denied=",
|
|
830
|
+
method!(MutGetOptionsPreferences::set_raise_if_policy_denied, 1),
|
|
831
|
+
)?;
|
|
832
|
+
get_options_preferences_class.define_method(
|
|
833
|
+
"raise_if_policy_denied",
|
|
834
|
+
method!(MutGetOptionsPreferences::get_raise_if_policy_denied, 0),
|
|
835
|
+
)?;
|
|
760
836
|
|
|
761
837
|
let watcher_builder_class =
|
|
762
838
|
module.define_class("OptionsWatcherBuilder", ruby.class_object())?;
|
|
@@ -784,6 +860,10 @@ fn init(ruby: &Ruby) -> Result<(), magnus::Error> {
|
|
|
784
860
|
function!(WrappedOptionsWatcher::build_from_directories_with_schema, 2),
|
|
785
861
|
)?;
|
|
786
862
|
watcher_class.define_method("aliases", method!(WrappedOptionsWatcher::get_aliases, 0))?;
|
|
863
|
+
watcher_class.define_private_method(
|
|
864
|
+
"_check_policies",
|
|
865
|
+
method!(WrappedOptionsWatcher::check_policies, 2),
|
|
866
|
+
)?;
|
|
787
867
|
watcher_class.define_method("features", method!(WrappedOptionsWatcher::get_features, 0))?;
|
|
788
868
|
watcher_class.define_method(
|
|
789
869
|
"features_and_aliases",
|
|
@@ -847,6 +927,10 @@ fn init(ruby: &Ruby) -> Result<(), magnus::Error> {
|
|
|
847
927
|
"get_feature_metadata_json",
|
|
848
928
|
method!(WrappedOptionsWatcher::get_feature_metadata_json, 1),
|
|
849
929
|
)?;
|
|
930
|
+
watcher_class.define_private_method(
|
|
931
|
+
"get_policies_json",
|
|
932
|
+
method!(WrappedOptionsWatcher::get_policies_json, 1),
|
|
933
|
+
)?;
|
|
850
934
|
|
|
851
935
|
Ok(())
|
|
852
936
|
}
|
|
@@ -71,4 +71,22 @@ impl MutGetOptionsPreferences {
|
|
|
71
71
|
pub fn skip_feature_name_conversion(&self) -> bool {
|
|
72
72
|
self.0.borrow().skip_feature_name_conversion
|
|
73
73
|
}
|
|
74
|
+
|
|
75
|
+
// Requester Section
|
|
76
|
+
pub fn set_requester(&self, requester: Option<String>) {
|
|
77
|
+
self.0.borrow_mut().requester = requester;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
pub fn get_requester(&self) -> Option<String> {
|
|
81
|
+
self.0.borrow().requester.clone()
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Policy Section
|
|
85
|
+
pub fn set_raise_if_policy_denied(&self, value: bool) {
|
|
86
|
+
self.0.borrow_mut().raise_if_policy_denied = value;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
pub fn get_raise_if_policy_denied(&self) -> bool {
|
|
90
|
+
self.0.borrow().raise_if_policy_denied
|
|
91
|
+
}
|
|
74
92
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'sorbet-runtime'
|
|
5
|
+
|
|
6
|
+
require 'optify-from_hash'
|
|
7
|
+
|
|
8
|
+
module Optify
|
|
9
|
+
# The policy for the requester identifier passed via preferences.
|
|
10
|
+
#
|
|
11
|
+
# Either `allow` or `block` will be set, not both.
|
|
12
|
+
# - `allow`: only the listed requesters may use the feature; can be empty.
|
|
13
|
+
# - `block`: the listed requesters may not use the feature; all others are allowed.
|
|
14
|
+
class RequesterPolicy < FromHashable
|
|
15
|
+
extend T::Sig
|
|
16
|
+
|
|
17
|
+
sig { returns(T.nilable(T::Set[String])) }
|
|
18
|
+
attr_reader :allow
|
|
19
|
+
|
|
20
|
+
sig { returns(T.nilable(T::Set[String])) }
|
|
21
|
+
attr_reader :block
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Policies that restrict access to a feature based on values in the request's preferences.
|
|
25
|
+
#
|
|
26
|
+
# See https://github.com/juharris/optify#policies for details.
|
|
27
|
+
class Policies < FromHashable
|
|
28
|
+
extend T::Sig
|
|
29
|
+
|
|
30
|
+
sig { returns(T.nilable(RequesterPolicy)) }
|
|
31
|
+
attr_reader :requester
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -5,9 +5,27 @@ require 'json'
|
|
|
5
5
|
require 'lru_redux'
|
|
6
6
|
require 'sorbet-runtime'
|
|
7
7
|
|
|
8
|
+
require_relative './policies'
|
|
9
|
+
|
|
8
10
|
module Optify
|
|
9
11
|
# @!visibility private
|
|
10
|
-
module ProviderModule
|
|
12
|
+
module ProviderModule # rubocop:disable Metrics/ModuleLength
|
|
13
|
+
#: (String, Array[String], ?CacheOptions?) -> void
|
|
14
|
+
def check_policies(requester, feature_names, cache_options = nil)
|
|
15
|
+
if cache_options
|
|
16
|
+
init unless @cache
|
|
17
|
+
ProviderModule._cache_getset(
|
|
18
|
+
@cache, #: as !nil
|
|
19
|
+
[:check_policies, feature_names, requester],
|
|
20
|
+
cache_options.on_cache_event,
|
|
21
|
+
) do
|
|
22
|
+
_check_policies(requester, feature_names)
|
|
23
|
+
end
|
|
24
|
+
else
|
|
25
|
+
_check_policies(requester, feature_names)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
11
29
|
#: [T] (LruRedux::Cache | Hash[Array[untyped], T], Array[untyped], (^(Array[untyped] key, T value, bool is_cache_hit) -> void)?) { -> T } -> T
|
|
12
30
|
def self._cache_getset(cache, cache_key, on_cache_event, &block)
|
|
13
31
|
is_cache_hit = true #: bool
|
|
@@ -69,6 +87,14 @@ module Optify
|
|
|
69
87
|
OptionsMetadata.from_hash(JSON.parse(metadata_json))
|
|
70
88
|
end
|
|
71
89
|
|
|
90
|
+
#: (String canonical_feature_name) -> Optify::Policies?
|
|
91
|
+
def get_policies(canonical_feature_name)
|
|
92
|
+
policies_json = get_policies_json(canonical_feature_name)
|
|
93
|
+
return nil if policies_json.nil?
|
|
94
|
+
|
|
95
|
+
Policies.from_hash(JSON.parse(policies_json))
|
|
96
|
+
end
|
|
97
|
+
|
|
72
98
|
private
|
|
73
99
|
|
|
74
100
|
#: -> Hash[String, OptionsMetadata]
|
data/rbi/optify.rbi
CHANGED
|
@@ -7,6 +7,31 @@ module Optify
|
|
|
7
7
|
class UnknownFeatureError < StandardError
|
|
8
8
|
end
|
|
9
9
|
|
|
10
|
+
# The policy for the requester identifier passed via preferences.
|
|
11
|
+
#
|
|
12
|
+
# Either `allow` or `block` will be set, not both.
|
|
13
|
+
# - `allow`: only the listed requesters may use the feature; can be empty.
|
|
14
|
+
# - `block`: the listed requesters may not use the feature; all others are allowed.
|
|
15
|
+
class RequesterPolicy < FromHashable
|
|
16
|
+
sig { returns(T.nilable(T::Set[String])) }
|
|
17
|
+
attr_reader :allow
|
|
18
|
+
|
|
19
|
+
sig { returns(T.nilable(T::Set[String])) }
|
|
20
|
+
attr_reader :block
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Policies that restrict access to a feature based on values in the request's preferences.
|
|
24
|
+
#
|
|
25
|
+
# See https://github.com/juharris/optify#policies for details.
|
|
26
|
+
class Policies < FromHashable
|
|
27
|
+
sig { returns(T.nilable(RequesterPolicy)) }
|
|
28
|
+
attr_reader :requester
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Raised when a requester is not permitted to use a feature due to its policies.
|
|
32
|
+
class PolicyDeniedError < StandardError
|
|
33
|
+
end
|
|
34
|
+
|
|
10
35
|
# DEPRECATED: Use `Optify::FromHashable` instead.
|
|
11
36
|
# A base class for classes from configuration files.
|
|
12
37
|
# Classes that derive from this can easily be used with `Optify::OptionsProvider.get_options`
|
|
@@ -162,6 +187,22 @@ module Optify
|
|
|
162
187
|
|
|
163
188
|
sig { returns(T::Boolean) }
|
|
164
189
|
def skip_feature_name_conversion; end
|
|
190
|
+
|
|
191
|
+
# The requester identifier to use for policy enforcement.
|
|
192
|
+
# If not set, policy checks are bypassed.
|
|
193
|
+
sig { params(value: T.nilable(String)).void }
|
|
194
|
+
def requester=(value); end
|
|
195
|
+
|
|
196
|
+
sig { returns(T.nilable(String)) }
|
|
197
|
+
def requester; end
|
|
198
|
+
|
|
199
|
+
# When `true`, raises `PolicyDeniedError` if a feature is not permitted for the requester.
|
|
200
|
+
# When `false` (default), denied features are silently filtered out.
|
|
201
|
+
sig { params(value: T::Boolean).void }
|
|
202
|
+
def raise_if_policy_denied=(value); end
|
|
203
|
+
|
|
204
|
+
sig { returns(T::Boolean) }
|
|
205
|
+
def raise_if_policy_denied; end
|
|
165
206
|
end
|
|
166
207
|
|
|
167
208
|
# A registry of features that provides configurations.
|
|
@@ -233,6 +274,19 @@ module Optify
|
|
|
233
274
|
# Some of the methods shown within this module are implemented in Rust
|
|
234
275
|
# and are declared in this common module to avoid duplicate declarations in different classes.
|
|
235
276
|
module ProviderModule
|
|
277
|
+
# Checks policies for a list of features for the given requester.
|
|
278
|
+
# Returns `nil` if there are no policy issues (or no policies defined).
|
|
279
|
+
# Raises `Optify::PolicyDeniedError` if any of the features are not allowed for the requester.
|
|
280
|
+
sig do
|
|
281
|
+
params(
|
|
282
|
+
requester: String,
|
|
283
|
+
feature_names: T::Array[String],
|
|
284
|
+
cache_options: T.nilable(CacheOptions),
|
|
285
|
+
)
|
|
286
|
+
.returns(T.nilable(String))
|
|
287
|
+
end
|
|
288
|
+
def check_policies(requester, feature_names, cache_options = nil); end
|
|
289
|
+
|
|
236
290
|
# @param canonical_feature_name [String] A canonical feature name
|
|
237
291
|
# @return Whether the feature has conditions.
|
|
238
292
|
sig { params(canonical_feature_name: String).returns(T::Boolean) }
|
|
@@ -358,8 +412,22 @@ module Optify
|
|
|
358
412
|
end
|
|
359
413
|
def map_feature_names(feature_names, preferences); end
|
|
360
414
|
|
|
415
|
+
# @return The policies for the feature, or `nil` if the feature has no policies.
|
|
416
|
+
sig { params(canonical_feature_name: String).returns(T.nilable(Optify::Policies)) }
|
|
417
|
+
def get_policies(canonical_feature_name); end
|
|
418
|
+
|
|
361
419
|
private
|
|
362
420
|
|
|
421
|
+
# Rust implementation.
|
|
422
|
+
sig do
|
|
423
|
+
params(
|
|
424
|
+
requester: String,
|
|
425
|
+
feature_names: T::Array[String],
|
|
426
|
+
)
|
|
427
|
+
.returns(T.nilable(String))
|
|
428
|
+
end
|
|
429
|
+
def _check_policies(requester, feature_names); end
|
|
430
|
+
|
|
363
431
|
# Map aliases or canonical feature names (perhaps derived from a file names) to the canonical feature names.
|
|
364
432
|
# Canonical feature names map to themselves.
|
|
365
433
|
# This implementation calls the Rust implementation directly.
|
|
@@ -372,6 +440,10 @@ module Optify
|
|
|
372
440
|
# @return The metadata for the feature.
|
|
373
441
|
sig { params(canonical_feature_name: String).returns(T.nilable(String)) }
|
|
374
442
|
def get_feature_metadata_json(canonical_feature_name); end
|
|
443
|
+
|
|
444
|
+
# @return The policies for the feature as JSON, or `nil` if the feature has no policies.
|
|
445
|
+
sig { params(canonical_feature_name: String).returns(T.nilable(String)) }
|
|
446
|
+
def get_policies_json(canonical_feature_name); end
|
|
375
447
|
end
|
|
376
448
|
|
|
377
449
|
# Provides configurations based on keys and enabled feature names.
|
data/sig/optify.rbs
CHANGED
|
@@ -6,6 +6,24 @@ end
|
|
|
6
6
|
class Optify::UnknownFeatureError < StandardError
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
+
# The policy for the requester identifier passed via preferences.
|
|
10
|
+
#
|
|
11
|
+
# Either `allow` or `block` will be set, not both.
|
|
12
|
+
# - `allow`: only the listed requesters may use the feature; can be empty.
|
|
13
|
+
# - `block`: the listed requesters may not use the feature; all others are allowed.
|
|
14
|
+
class Optify::RequesterPolicy < FromHashable
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Policies that restrict access to a feature based on values in the request's preferences.
|
|
18
|
+
#
|
|
19
|
+
# See https://github.com/juharris/optify#policies for details.
|
|
20
|
+
class Optify::Policies < FromHashable
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Raised when a requester is not permitted to use a feature due to its policies.
|
|
24
|
+
class Optify::PolicyDeniedError < StandardError
|
|
25
|
+
end
|
|
26
|
+
|
|
9
27
|
# DEPRECATED: Use `Optify::FromHashable` instead.
|
|
10
28
|
# A base class for classes from configuration files.
|
|
11
29
|
# Classes that derive from this can easily be used with `Optify::OptionsProvider.get_options`
|
|
@@ -18,7 +36,10 @@ end
|
|
|
18
36
|
|
|
19
37
|
# Options for caching.
|
|
20
38
|
class Optify::CacheOptions
|
|
21
|
-
def initialize: () ->
|
|
39
|
+
def initialize: () -> ::Set[String]?
|
|
40
|
+
| () -> ::Set[String]?
|
|
41
|
+
| () -> RequesterPolicy?
|
|
42
|
+
| () -> (^(::Array[untyped] key, untyped value, bool is_cache_hit) -> void)?
|
|
22
43
|
| (?on_cache_event: (^(::Array[untyped] key, untyped value, bool is_cache_hit) -> void)? on_cache_event) -> void
|
|
23
44
|
end
|
|
24
45
|
|
|
@@ -100,6 +121,18 @@ class Optify::GetOptionsPreferences
|
|
|
100
121
|
def skip_feature_name_conversion=: (bool value) -> void
|
|
101
122
|
|
|
102
123
|
def skip_feature_name_conversion: () -> bool
|
|
124
|
+
|
|
125
|
+
# The requester identifier to use for policy enforcement.
|
|
126
|
+
# If not set, policy checks are bypassed.
|
|
127
|
+
def requester=: (String? value) -> void
|
|
128
|
+
|
|
129
|
+
def requester: () -> String?
|
|
130
|
+
|
|
131
|
+
# When `true`, raises `PolicyDeniedError` if a feature is not permitted for the requester.
|
|
132
|
+
# When `false` (default), denied features are silently filtered out.
|
|
133
|
+
def raise_if_policy_denied=: (bool value) -> void
|
|
134
|
+
|
|
135
|
+
def raise_if_policy_denied: () -> bool
|
|
103
136
|
end
|
|
104
137
|
|
|
105
138
|
# A registry of features that provides configurations.
|
|
@@ -149,6 +182,8 @@ end
|
|
|
149
182
|
# Some of the methods shown within this module are implemented in Rust
|
|
150
183
|
# and are declared in this common module to avoid duplicate declarations in different classes.
|
|
151
184
|
module Optify::ProviderModule
|
|
185
|
+
def check_policies: (String requester, ::Array[String] feature_names, ?CacheOptions? cache_options) -> String?
|
|
186
|
+
|
|
152
187
|
# @param canonical_feature_name [String] A canonical feature name
|
|
153
188
|
# @return Whether the feature has conditions.
|
|
154
189
|
def conditions?: (String canonical_feature_name) -> bool
|
|
@@ -200,6 +235,11 @@ module Optify::ProviderModule
|
|
|
200
235
|
|
|
201
236
|
def map_feature_names: (::Array[String] feature_names, GetOptionsPreferences preferences) -> ::Array[String?]
|
|
202
237
|
|
|
238
|
+
# @return The policies for the feature, or `nil` if the feature has no policies.
|
|
239
|
+
def get_policies: (String canonical_feature_name) -> Optify::Policies?
|
|
240
|
+
|
|
241
|
+
def _check_policies: (String requester, ::Array[String] feature_names) -> String?
|
|
242
|
+
|
|
203
243
|
# Map aliases or canonical feature names (perhaps derived from a file names) to the canonical feature names.
|
|
204
244
|
# Canonical feature names map to themselves.
|
|
205
245
|
# This implementation calls the Rust implementation directly.
|
|
@@ -210,6 +250,9 @@ module Optify::ProviderModule
|
|
|
210
250
|
|
|
211
251
|
# @return The metadata for the feature.
|
|
212
252
|
def get_feature_metadata_json: (String canonical_feature_name) -> String?
|
|
253
|
+
|
|
254
|
+
# @return The policies for the feature as JSON, or `nil` if the feature has no policies.
|
|
255
|
+
def get_policies_json: (String canonical_feature_name) -> String?
|
|
213
256
|
end
|
|
214
257
|
|
|
215
258
|
# Provides configurations based on keys and enabled feature names.
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: optify-config
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.24.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Justin D. Harris
|
|
@@ -193,6 +193,7 @@ files:
|
|
|
193
193
|
- lib/optify_ruby/get_options_preferences.rb
|
|
194
194
|
- lib/optify_ruby/implementation.rb
|
|
195
195
|
- lib/optify_ruby/options_metadata.rb
|
|
196
|
+
- lib/optify_ruby/policies.rb
|
|
196
197
|
- lib/optify_ruby/provider_module.rb
|
|
197
198
|
- lib/optify_ruby/watcher_implementation.rb
|
|
198
199
|
- rbi/optify.rbi
|