Skip to content

Commit 58f42db

Browse files
authored
feat: add cidr matching, semver lte and semver gte constraints (#340)
1 parent ee5f6ba commit 58f42db

File tree

6 files changed

+35
-11
lines changed

6 files changed

+35
-11
lines changed

.github/workflows/sarif-and-test.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ jobs:
5151
uses: actions/checkout@v3
5252
with:
5353
repository: Unleash/client-specification
54-
ref: v6.0.0
54+
ref: v6.1.0
5555
path: client-specification
5656
- name: Run tests
5757
run: |

unleash-yggdrasil/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
edition = "2021"
33
name = "unleash-yggdrasil"
4-
version = "0.21.0"
4+
version = "0.21.1"
55
description = "This is the Unleash SDK domain logic extracted into a library to facilitate building your own Unleash SDKs in anything, anywhere."
66
license = "MIT"
77

@@ -21,7 +21,7 @@ pest_derive = "2.8.3"
2121
lazy_static = "1.5.0"
2222
semver = "1.0.27"
2323
convert_case = "0.8.0"
24-
unleash-types = {version = "0.15.22", default-features = false}
24+
unleash-types = {version = "0.15.23", default-features = false}
2525
chrono = { version = "0.4.42", default-features = false, features = ["serde", "std"] }
2626
dashmap = "6.1.0"
2727
hostname = { version = "0.4.1", optional = true }

unleash-yggdrasil/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use unleash_types::client_metrics::{MetricBucket, ToggleStats};
3535

3636
pub type CompiledState = AHashMap<String, CompiledToggle>;
3737

38-
pub const SUPPORTED_SPEC_VERSION: &str = "5.2.2";
38+
pub const SUPPORTED_SPEC_VERSION: &str = "6.1.0";
3939
const VARIANT_NORMALIZATION_SEED: u32 = 86028157;
4040
pub const CORE_VERSION: &str = env!("CARGO_PKG_VERSION");
4141

@@ -954,6 +954,7 @@ mod test {
954954
#[test_case("19-delta-api-hydration.json"; "Delta hydration tests")]
955955
#[test_case("20-delta-api-events.json"; "Delta events tests")]
956956
#[test_case("21-regex-constraint-operators.json"; "Regex constraint operators")]
957+
#[test_case("22-cidr-constraint-operators.json"; "Cidr constraints")]
957958

958959
fn run_client_spec(spec_name: &str) {
959960
let spec = load_spec(spec_name);

unleash-yggdrasil/src/strategy_grammar.pest

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ constraint = {
8282
hostname_constraint = { hostname ~ in ~ string_list }
8383
hostname = _{ "hostname" }
8484
in = _{ "in" }
85-
ip_constraint = { context_value ~ ip_contains_operation ~ string_list }
86-
ip_contains_operation = _{ "contains_ip" }
85+
ip_constraint = { context_value ~ in_cidr_operation ~ string_list }
86+
in_cidr_operation = _{ "in_cidr" }
8787
string_fragment_constraint = { context_value ~ ( string_list_operation_without_case | string_list_operation ) ~ string_list }
8888
regex_constraint = { context_value ~ regex_operation ~ string }
8989
list_constraint = { context_value ~ list_operation ~ ( numeric_list | string_list | empty_list ) }
@@ -108,4 +108,4 @@ context_value = { random | user_id | session_id | remote_address | app_name | en
108108
expr = { term ~ (boolean_operation ~ term)* }
109109
term = _{ constraint | "(" ~ expr ~ ")" }
110110

111-
strategy = _{ SOI ~ expr ~ EOI }
111+
strategy = _{ SOI ~ expr ~ EOI }

unleash-yggdrasil/src/strategy_parsing.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -798,10 +798,27 @@ mod tests {
798798
#[test_case("3.0.0", "user_id >= 3.0.0", true)]
799799
#[test_case("3.0.0-beta.stuff", "user_id == 3.0.0-beta.stuff", true)]
800800
#[test_case("3.0.0-beta.stuff+build1", "user_id == 3.0.0-beta.stuff+build1", true)]
801+
#[test_case("3.0.1", "user_id >= 3.0.1", true)]
802+
#[test_case("3.0.2", "user_id >= 3.0.1", true)]
801803
fn test_semver_gt(user_id: &str, rule: &str, expected: bool) {
802804
run_test(user_id, rule, expected);
803805
}
804806

807+
#[test_case("30.0.0", "user_id <= 30.0.0", true)]
808+
#[test_case("3.0.0", "user_id <= 3.0.0", true)]
809+
#[test_case("3.0.0-beta", "user_id <= 3.0.0-beta", true)]
810+
#[test_case("3.0.0-beta.2", "user_id <= 3.0.0-beta.1", false)]
811+
#[test_case("3.0.0-beta", "user_id <= 3.0.0-alpha", false)]
812+
#[test_case("3.0.1-beta", "user_id <= 3.0.1-alpha", false)]
813+
#[test_case("3.0.0", "user_id <= 3.0.0-alpha", false)]
814+
#[test_case("3.0.0-beta.stuff", "user_id <= 3.0.0-beta.stuff", true)]
815+
#[test_case("3.0.0-beta.stuff+build1", "user_id <= 3.0.0-beta.stuff+build1", true)]
816+
#[test_case("3.0.1", "user_id <= 3.0.1", true)]
817+
#[test_case("3.0.2", "user_id <= 3.0.1", false)]
818+
fn test_semver_lt(user_id: &str, rule: &str, expected: bool) {
819+
run_test(user_id, rule, expected);
820+
}
821+
805822
fn run_test(user_id: &str, rule: &str, expected: bool) {
806823
let rule = compile_rule(rule).expect("");
807824
let context = context_from_user_id(user_id);
@@ -1209,7 +1226,7 @@ mod tests {
12091226
.map(|x| format!("\"{}\"", x.trim()))
12101227
.collect::<Vec<String>>();
12111228

1212-
let rule = format!("remote_address contains_ip [{}]", constraint_ips.join(","));
1229+
let rule = format!("remote_address in_cidr [{}]", constraint_ips.join(","));
12131230
println!("Current rule {}", rule);
12141231
let rule = compile_rule(&rule).unwrap();
12151232

@@ -1223,7 +1240,7 @@ mod tests {
12231240

12241241
#[test]
12251242
fn remote_address_constraint_never_matches_missing_context() {
1226-
let rule = compile_rule("remote_address contains_ip [\"127.0.0.1\"]").unwrap();
1243+
let rule = compile_rule("remote_address in_cidr [\"127.0.0.1\"]").unwrap();
12271244
let context = Context::default();
12281245

12291246
assert!(!rule(&context));

unleash-yggdrasil/src/strategy_upgrade.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ fn upgrade_remote_address(strategy: &Strategy) -> String {
214214
.map(|x| format!("\"{x}\""))
215215
.collect::<Vec<String>>()
216216
.join(", ");
217-
format!("remote_address contains_ip [{ips}]")
217+
format!("remote_address in_cidr [{ips}]")
218218
}
219219
None => "false".into(),
220220
}
@@ -297,6 +297,7 @@ fn is_stringy(op: &Operator) -> bool {
297297
| Operator::StrEndsWith
298298
| Operator::StrStartsWith
299299
| Operator::StrContains
300+
| Operator::InCidr
300301
)
301302
}
302303

@@ -335,6 +336,8 @@ fn upgrade_constraint(constraint: &Constraint) -> String {
335336
if constraint.operator == Operator::SemverEq
336337
|| constraint.operator == Operator::SemverLt
337338
|| constraint.operator == Operator::SemverGt
339+
|| constraint.operator == Operator::SemverLte
340+
|| constraint.operator == Operator::SemverGte
338341
{
339342
// A silly special case where we want to ingest
340343
// broken semver operators so we can reject them.
@@ -392,6 +395,9 @@ fn upgrade_operator(op: &Operator, case_insensitive: bool) -> Option<String> {
392395
Operator::SemverEq => Some("==".into()),
393396
Operator::SemverLt => Some("<".into()),
394397
Operator::SemverGt => Some(">".into()),
398+
Operator::SemverLte => Some("<=".into()),
399+
Operator::SemverGte => Some(">=".into()),
400+
Operator::InCidr => Some("in_cidr".into()),
395401
Operator::Unknown(_) => None,
396402
}
397403
}
@@ -957,7 +963,7 @@ mod tests {
957963
let rule = upgrade_strategy(&strategy, &HashMap::new(), 0);
958964
assert_eq!(
959965
rule.as_str(),
960-
"remote_address contains_ip [\"192.168.0.1\", \"192.168.0.2\", \"192.168.0.3\"]"
966+
"remote_address in_cidr [\"192.168.0.1\", \"192.168.0.2\", \"192.168.0.3\"]"
961967
);
962968
}
963969

0 commit comments

Comments
 (0)