From a0612ee3fec9717a930b9c0429a16c40cf741343 Mon Sep 17 00:00:00 2001 From: Simon Hornby Date: Fri, 13 Mar 2026 09:35:50 +0200 Subject: [PATCH 1/3] feat: add semver gte, lte and cidr matching constraint --- .../14-constraint-semver-operators.json | 98 ++++++++++++- .../22-cidr-constraint-operators.json | 136 ++++++++++++++++++ specifications/index.json | 5 +- 3 files changed, 236 insertions(+), 3 deletions(-) create mode 100644 specifications/22-cidr-constraint-operators.json diff --git a/specifications/14-constraint-semver-operators.json b/specifications/14-constraint-semver-operators.json index 2f9c4e4..d924b3d 100644 --- a/specifications/14-constraint-semver-operators.json +++ b/specifications/14-constraint-semver-operators.json @@ -39,6 +39,24 @@ } ] }, + { + "name": "F8.semverGTE", + "description": "semver", + "enabled": true, + "strategies": [ + { + "name": "default", + "parameters": {}, + "constraints": [ + { + "contextName": "version", + "operator": "SEMVER_GTE", + "value": "1.2.2" + } + ] + } + ] + }, { "name": "F8.semverLT", "description": "semver", @@ -57,6 +75,24 @@ } ] }, + { + "name": "F8.semverLTE", + "description": "semver", + "enabled": true, + "strategies": [ + { + "name": "default", + "parameters": {}, + "constraints": [ + { + "contextName": "version", + "operator": "SEMVER_LTE", + "value": "1.2.2" + } + ] + } + ] + }, { "name": "F8.semverAlphaGT", "description": "semver", @@ -208,6 +244,36 @@ "toggleName": "F8.semverGT", "expectedResult": false }, + { + "description": "F8.semverGTE should be enabled", + "context": { + "properties": { + "version": "1.2.2" + } + }, + "toggleName": "F8.semverGTE", + "expectedResult": true + }, + { + "description": "F8.semverGTE should be enabled for greater", + "context": { + "properties": { + "version": "1.2.3" + } + }, + "toggleName": "F8.semverGTE", + "expectedResult": true + }, + { + "description": "F8.semverGTE should be disabled", + "context": { + "properties": { + "version": "1.2.1" + } + }, + "toggleName": "F8.semverGTE", + "expectedResult": false + }, { "description": "F8.semverLT should be enabled", "context": { @@ -228,6 +294,36 @@ "toggleName": "F8.semverLT", "expectedResult": false }, + { + "description": "F8.semverLTE should be enabled", + "context": { + "properties": { + "version": "1.2.2" + } + }, + "toggleName": "F8.semverLTE", + "expectedResult": true + }, + { + "description": "F8.semverLTE should be enabled for less", + "context": { + "properties": { + "version": "1.2.1" + } + }, + "toggleName": "F8.semverLTE", + "expectedResult": true + }, + { + "description": "F8.semverLTE should be disabled", + "context": { + "properties": { + "version": "1.2.3" + } + }, + "toggleName": "F8.semverLTE", + "expectedResult": false + }, { "description": "F8.semverAlphaGT is less than beta", "context": { @@ -359,4 +455,4 @@ "expectedResult": false } ] -} \ No newline at end of file +} diff --git a/specifications/22-cidr-constraint-operators.json b/specifications/22-cidr-constraint-operators.json new file mode 100644 index 0000000..2814da5 --- /dev/null +++ b/specifications/22-cidr-constraint-operators.json @@ -0,0 +1,136 @@ +{ + "name": "22-cidr-constraint-operator", + "state": { + "version": 1, + "features": [ + { + "name": "CIDR.exact.match", + "description": "Exact IP match using IN_CIDR", + "enabled": true, + "strategies": [ + { + "name": "default", + "parameters": {}, + "constraints": [ + { + "contextName": "remoteAddress", + "operator": "IN_CIDR", + "values": ["127.0.0.1"] + } + ] + } + ] + }, + { + "name": "CIDR.range.match", + "description": "CIDR range match using IN_CIDR", + "enabled": true, + "strategies": [ + { + "name": "default", + "parameters": {}, + "constraints": [ + { + "contextName": "remoteAddress", + "operator": "IN_CIDR", + "values": ["160.33.0.0/16"] + } + ] + } + ] + }, + { + "name": "CIDR.mixed.values", + "description": "Invalid values should be ignored when valid ones exist", + "enabled": true, + "strategies": [ + { + "name": "default", + "parameters": {}, + "constraints": [ + { + "contextName": "remoteAddress", + "operator": "IN_CIDR", + "values": ["127.invalid", "192.168.1.0/24"] + } + ] + } + ] + }, + { + "name": "CIDR.invalid.only", + "description": "Only invalid values should not match anything", + "enabled": true, + "strategies": [ + { + "name": "default", + "parameters": {}, + "constraints": [ + { + "contextName": "remoteAddress", + "operator": "IN_CIDR", + "values": ["127.invalid"] + } + ] + } + ] + } + ] + }, + "tests": [ + { + "description": "Exact IP match should be enabled", + "context": { + "remoteAddress": "127.0.0.1" + }, + "toggleName": "CIDR.exact.match", + "expectedResult": true + }, + { + "description": "Exact IP mismatch should be disabled", + "context": { + "remoteAddress": "127.0.0.2" + }, + "toggleName": "CIDR.exact.match", + "expectedResult": false + }, + { + "description": "CIDR range should enable matching IP", + "context": { + "remoteAddress": "160.33.0.33" + }, + "toggleName": "CIDR.range.match", + "expectedResult": true + }, + { + "description": "CIDR range should disable non-matching IP", + "context": { + "remoteAddress": "160.34.0.1" + }, + "toggleName": "CIDR.range.match", + "expectedResult": false + }, + { + "description": "Valid CIDR should match even when invalid entries exist", + "context": { + "remoteAddress": "192.168.1.42" + }, + "toggleName": "CIDR.mixed.values", + "expectedResult": true + }, + { + "description": "Invalid-only values should not match", + "context": { + "remoteAddress": "127.0.0.1" + }, + "toggleName": "CIDR.invalid.only", + "expectedResult": false + }, + { + "description": "Missing remoteAddress should not match", + "context": {}, + "toggleName": "CIDR.range.match", + "expectedResult": false + } + ] +} diff --git a/specifications/index.json b/specifications/index.json index 8dfe905..6295361 100644 --- a/specifications/index.json +++ b/specifications/index.json @@ -19,5 +19,6 @@ "18-utf8-flag-names.json", "19-delta-api-hydration.json", "20-delta-api-events.json", - "21-regex-constraint-operators.json" -] \ No newline at end of file + "21-regex-constraint-operators.json", + "22-cidr-constraint-operators.json" +] From a949231773df637486c2f3ed07f8fb452a0eb997 Mon Sep 17 00:00:00 2001 From: Simon Hornby Date: Fri, 13 Mar 2026 10:55:03 +0200 Subject: [PATCH 2/3] feat: add support for ipv6 in cidr matches --- .../22-cidr-constraint-operators.json | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/specifications/22-cidr-constraint-operators.json b/specifications/22-cidr-constraint-operators.json index 2814da5..e5308a6 100644 --- a/specifications/22-cidr-constraint-operators.json +++ b/specifications/22-cidr-constraint-operators.json @@ -74,6 +74,60 @@ ] } ] + }, + { + "name": "CIDR.ipv6.exact.match", + "description": "Exact IPv6 match using IN_CIDR", + "enabled": true, + "strategies": [ + { + "name": "default", + "parameters": {}, + "constraints": [ + { + "contextName": "remoteAddress", + "operator": "IN_CIDR", + "values": ["2001:db8::1"] + } + ] + } + ] + }, + { + "name": "CIDR.ipv6.range.match", + "description": "IPv6 CIDR range match using IN_CIDR", + "enabled": true, + "strategies": [ + { + "name": "default", + "parameters": {}, + "constraints": [ + { + "contextName": "remoteAddress", + "operator": "IN_CIDR", + "values": ["2001:db8::/32"] + } + ] + } + ] + }, + { + "name": "CIDR.ipv6.mixed.values", + "description": "Invalid values should be ignored when valid IPv6 CIDR exists", + "enabled": true, + "strategies": [ + { + "name": "default", + "parameters": {}, + "constraints": [ + { + "contextName": "remoteAddress", + "operator": "IN_CIDR", + "values": ["bad::cidr", "2001:db8::/32"] + } + ] + } + ] } ] }, @@ -131,6 +185,46 @@ "context": {}, "toggleName": "CIDR.range.match", "expectedResult": false + }, + { + "description": "Exact IPv6 match should be enabled", + "context": { + "remoteAddress": "2001:db8::1" + }, + "toggleName": "CIDR.ipv6.exact.match", + "expectedResult": true + }, + { + "description": "Exact IPv6 mismatch should be disabled", + "context": { + "remoteAddress": "2001:db8::2" + }, + "toggleName": "CIDR.ipv6.exact.match", + "expectedResult": false + }, + { + "description": "IPv6 CIDR range should enable matching IP", + "context": { + "remoteAddress": "2001:db8:0:1::42" + }, + "toggleName": "CIDR.ipv6.range.match", + "expectedResult": true + }, + { + "description": "IPv6 CIDR range should disable non-matching IP", + "context": { + "remoteAddress": "2001:db9::1" + }, + "toggleName": "CIDR.ipv6.range.match", + "expectedResult": false + }, + { + "description": "Valid IPv6 CIDR should match even when invalid entries exist", + "context": { + "remoteAddress": "2001:db8::abcd" + }, + "toggleName": "CIDR.ipv6.mixed.values", + "expectedResult": true } ] } From 3b0dc0a021aabbd44ac8aab730753e4343ab763b Mon Sep 17 00:00:00 2001 From: Simon Hornby Date: Fri, 13 Mar 2026 11:50:34 +0200 Subject: [PATCH 3/3] chore: bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c3386df..c6a9745 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@unleash/client-specification", - "version": "6.0.1", + "version": "6.1.0", "description": "A collection of test specifications to guide client implementations in various languages", "scripts": { "test": "node index",