From 678ca31dc6c581c4b79aab0f172a7dc4828c1aa8 Mon Sep 17 00:00:00 2001 From: Fabrizio Demaria Date: Fri, 20 Feb 2026 16:12:46 +0100 Subject: [PATCH] fix(resolver): skip unrecognized targeting rules in flag resolution Updated the flag resolution logic to skip unrecognized targeting rules instead of returning an error. Added a test to ensure that unrecognized rules do not cause the flag resolution to fail, confirming that the expected behavior is maintained. --- confidence-resolver/src/lib.rs | 119 +++++++++++++++--- .../assets/confidence_resolver.wasm | Bin 468923 -> 468854 bytes 2 files changed, 102 insertions(+), 17 deletions(-) diff --git a/confidence-resolver/src/lib.rs b/confidence-resolver/src/lib.rs index 05525cc5..ea93c9c5 100644 --- a/confidence-resolver/src/lib.rs +++ b/confidence-resolver/src/lib.rs @@ -927,12 +927,7 @@ impl<'a, H: Host> AccountResolver<'a, H> { ) { Ok(matched) => matched, Err(e) if e == value::UNRECOGNIZED_RULE_ERROR => { - return Ok(FlagResolveResult { - resolved_value: resolved_value.error( - ResolveReason::UnrecognizedTargetingRule, - ), - updates: vec![], - }); + continue; } Err(_) => { return Err( @@ -1003,12 +998,7 @@ impl<'a, H: Host> AccountResolver<'a, H> { ) { Ok(matched) => matched, Err(e) if e == value::UNRECOGNIZED_RULE_ERROR => { - return Ok(FlagResolveResult { - resolved_value: resolved_value.error( - ResolveReason::UnrecognizedTargetingRule, - ), - updates: vec![], - }); + continue; } Err(_) => { return Err( @@ -1039,11 +1029,7 @@ impl<'a, H: Host> AccountResolver<'a, H> { continue; } Err(e) if e == value::UNRECOGNIZED_RULE_ERROR => { - return Ok(FlagResolveResult { - resolved_value: resolved_value - .error(ResolveReason::UnrecognizedTargetingRule), - updates: vec![], - }); + continue; } Err(_) => { return Err(ResolveFlagError::missing_materializations()); @@ -4464,4 +4450,103 @@ mod tests { assert_eq!(resolved_value.reason as i32, ResolveReason::Match as i32); } + + #[test] + fn test_resolve_flag_skips_unrecognized_targeting_rule() { + let segment_json = r#"{ + "name": "segments/unrecognized-rule", + "targeting": { + "criteria": { + "c": { + "attribute": { + "attributeName": "user.email" + } + } + }, + "expression": { + "ref": "c" + } + }, + "allocation": { + "proportion": { "value": "1.0" }, + "exclusivityTags": [], + "exclusiveTo": [] + } + }"#; + let segment: Segment = serde_json::from_str(segment_json).unwrap(); + + let flag_json = r#"{ + "name": "flags/unrecognized-rule-flag", + "state": "ACTIVE", + "variants": [ + { + "name": "flags/unrecognized-rule-flag/variants/on", + "value": { "data": "on" } + } + ], + "clients": ["clients/test"], + "rules": [ + { + "name": "flags/unrecognized-rule-flag/rules/rule1", + "segment": "segments/unrecognized-rule", + "enabled": true, + "assignmentSpec": { + "bucketCount": 1, + "assignments": [ + { + "assignmentId": "flags/unrecognized-rule-flag/variants/on", + "variant": { + "variant": "flags/unrecognized-rule-flag/variants/on" + }, + "bucketRanges": [{ "lower": 0, "upper": 1 }] + } + ] + } + } + ] + }"#; + let flag: Flag = serde_json::from_str(flag_json).unwrap(); + + let mut segments = HashMap::new(); + segments.insert(segment.name.clone(), segment); + let mut flags = HashMap::new(); + flags.insert(flag.name.clone(), flag); + + let mut secrets = HashMap::new(); + secrets.insert( + SECRET.to_string(), + Client { + account: Account::new("accounts/test"), + client_name: "clients/test".to_string(), + client_credential_name: "clients/test/clientCredentials/abcdef".to_string(), + environments: vec![], + }, + ); + + let state = ResolverState { + secrets, + flags, + segments, + bitsets: HashMap::new(), + }; + + let context_json = r#"{"targeting_key": "roug", "user": {"email": "test@example.com"}}"#; + let resolver: AccountResolver<'_, L> = state + .get_resolver_with_json_context(SECRET, context_json, &ENCRYPTION_KEY) + .unwrap(); + let flag = resolver + .state + .flags + .get("flags/unrecognized-rule-flag") + .unwrap(); + let resolve_result = resolver.resolve_flag(flag, vec![]).unwrap(); + let resolved_value = &resolve_result.resolved_value; + + assert_eq!( + resolved_value.reason as i32, + ResolveReason::NoSegmentMatch as i32, + "Unrecognized targeting rule should cause the rule to be skipped, not fail the flag" + ); + assert!(resolved_value.assignment_match.is_none()); + } } diff --git a/openfeature-provider/go/confidence/internal/local_resolver/assets/confidence_resolver.wasm b/openfeature-provider/go/confidence/internal/local_resolver/assets/confidence_resolver.wasm index b209ecae8c52f684b5d583cd2956a017ded92c7e..68f1320b026b4237709bb01623140b8caa1d5005 100755 GIT binary patch delta 590 zcmYjNOK1~O6n*#2JYOc6X(sj)kyPHK5~C(c3|L&XFPQ2=Btln8TNO8^D;I*h1QhDd zgi8%l1!5!JiDJ1=4~ z@!L;GfKIBaqHR=1eTKTCgmAA_ZBcxi%#HXpp-Z@8 zF;l}icNlcM>YfY+P4@4KVo{w>?l=TdchmUO9j2y*yXs@z$0?!`%i@w7wM>)#Ujc8a zo{9nYUaw!!7?;FhUb=M&`YGPsc&0LN7@qnP!NR+ZKJw0P4ghex{QeGOQgb+d{yL__ zA8bdJKixjB4z9It4Gmm}edakpO>wq$9f1^@s6 delta 696 zcmZuuK}b|l6n*#odGqG`|CbqOa!6GEw`rPUMi|VjMLJK?7C~goB0?7}2BO+U5Ka_W z(89RMry@`X)J7N5Cx!~5C}5tv`o6s~sz#Tp(V($I3n&n*#B_^QiO+3tq2FY{w9y^fl(DB`L!qHVIpW@8c zmFeg3jY6To>?XpojXFk(&6>1z+*j;BB8hTw{W~j|)c{ zDm`E^>P@!f?W9WoX<*FYIjWNEVzDhG=@v4gdzE5^ySeiaz|u@JSomrt(;l?bDZT_7 zDuWi-X;lN?O-I*&1!&G@iQYTwg2d|V;_j1{Af*MK_q{adl?;zvqb1BJnai*{Lcvi> zLwC+0{?oa)7U@!be7(-F?b#V_M)66hi<=Q#ebm~(?SO(ymNYqrOFJNlxw%0S(Y6(d zY>JREQ{dH74@B@^X_vks;oCi4YCkk&apLv+&vw&4Mtk@IHybx+Y1D6Tvx4EBn$IRd zc(*?eYeFdINO$T2#JphT1YqB{F1%H}i^1;>_I|2T9~|lJTxtXmm|DIkq|zLLlWPfF zUGBiuwKN`F>BeKVPVd3WNUTZGU)K1hua~Tcf4y$h$Ba5qa0;z#)B~UYW?yTJbuz|I z$HQzd<@Nw$eOvHh!fjjdNV(;Q_yW-9{;rEr*k8W#Q_LsDlwizuUqplPF%=J%Ra|z5 F{{wT(yO00?