Skip to content

Commit 046947d

Browse files
fix: GO Feature Flag provider fix issues + compatible with SDK 0.1.0 (#132)
* Fix CVE-2022-42003 on jackson Signed-off-by: Thomas Poignant <[email protected]> * #128 - Fix NPE when anonymous field is missing Signed-off-by: Thomas Poignant <[email protected]> * Change to be compatible with SDK 0.1.0 Signed-off-by: Thomas Poignant <[email protected]> * revert previous change Signed-off-by: Thomas Poignant <[email protected]> Signed-off-by: Thomas Poignant <[email protected]>
1 parent 590a046 commit 046947d

File tree

4 files changed

+39
-20
lines changed

4 files changed

+39
-20
lines changed

providers/go-feature-flag/pom.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@
2929
<dependency>
3030
<groupId>com.fasterxml.jackson.datatype</groupId>
3131
<artifactId>jackson-datatype-jsr310</artifactId>
32-
<version>2.13.4</version>
32+
<version>2.14.0</version>
3333
</dependency>
3434

3535
<dependency>
3636
<groupId>com.fasterxml.jackson.core</groupId>
3737
<artifactId>jackson-databind</artifactId>
38-
<version>2.13.4</version>
38+
<version>2.14.0</version>
3939
</dependency>
4040

4141
<dependency>

providers/go-feature-flag/src/main/java/dev/openfeature/contrib/providers/gofeatureflag/GoFeatureFlagProvider.java

+23-12
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,9 @@
11
package dev.openfeature.contrib.providers.gofeatureflag;
22

33
import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
4-
5-
import java.io.IOException;
6-
import java.time.Instant;
7-
import java.util.List;
8-
import java.util.Map;
9-
import java.util.concurrent.TimeUnit;
10-
import java.util.stream.Collectors;
11-
124
import com.fasterxml.jackson.databind.ObjectMapper;
135
import com.fasterxml.jackson.databind.SerializationFeature;
146
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
15-
167
import dev.openfeature.contrib.providers.gofeatureflag.bean.GoFeatureFlagRequest;
178
import dev.openfeature.contrib.providers.gofeatureflag.bean.GoFeatureFlagResponse;
189
import dev.openfeature.contrib.providers.gofeatureflag.bean.GoFeatureFlagUser;
@@ -40,6 +31,12 @@
4031
import okhttp3.RequestBody;
4132
import okhttp3.Response;
4233
import okhttp3.ResponseBody;
34+
import java.io.IOException;
35+
import java.time.Instant;
36+
import java.util.List;
37+
import java.util.Map;
38+
import java.util.concurrent.TimeUnit;
39+
import java.util.stream.Collectors;
4340

4441
/**
4542
* GoFeatureFlagProvider is the JAVA provider implementation for the feature flag solution GO Feature Flag.
@@ -120,7 +117,6 @@ public List<Hook> getProviderHooks() {
120117
return FeatureProvider.super.getProviderHooks();
121118
}
122119

123-
124120
@Override
125121
public ProviderEvaluation<Boolean> getBooleanEvaluation(
126122
String key, Boolean defaultValue, EvaluationContext evaluationContext
@@ -201,8 +197,7 @@ private <T> ProviderEvaluation<T> resolveEvaluationGoFeatureFlagProxy(
201197
if (Reason.DISABLED.name().equalsIgnoreCase(goffResp.getReason())) {
202198
// we don't set a variant since we are using the default value, and we are not able to know
203199
// which variant it is.
204-
return ProviderEvaluation.<T>builder().value(defaultValue).reason(Reason.DISABLED.toString())
205-
.build();
200+
return ProviderEvaluation.<T>builder().value(defaultValue).reason(Reason.DISABLED.name()).build();
206201
}
207202

208203
if (ErrorCode.FLAG_NOT_FOUND.name().equalsIgnoreCase(goffResp.getErrorCode())) {
@@ -218,6 +213,7 @@ private <T> ProviderEvaluation<T> resolveEvaluationGoFeatureFlagProxy(
218213
}
219214

220215
return ProviderEvaluation.<T>builder()
216+
.errorCode(mapErrorCode(goffResp.getErrorCode()))
221217
.reason(goffResp.getReason())
222218
.value(flagValue)
223219
.variant(goffResp.getVariationType())
@@ -229,6 +225,21 @@ private <T> ProviderEvaluation<T> resolveEvaluationGoFeatureFlagProxy(
229225
}
230226
}
231227

228+
/**
229+
* mapErrorCode is mapping the errorCode in string received by the API to our internal SDK ErrorCode enum.
230+
*
231+
* @param errorCode - string of the errorCode received from the API
232+
* @return an item from the enum
233+
*/
234+
private ErrorCode mapErrorCode(String errorCode) {
235+
try {
236+
return ErrorCode.valueOf(errorCode);
237+
} catch (IllegalArgumentException e) {
238+
return null;
239+
}
240+
}
241+
242+
232243
/**
233244
* convertValue is converting the object return by the proxy response in the right type.
234245
*

providers/go-feature-flag/src/main/java/dev/openfeature/contrib/providers/gofeatureflag/bean/GoFeatureFlagUser.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ public static GoFeatureFlagUser fromEvaluationContext(EvaluationContext ctx) {
3131
if (key == null || "".equals(key)) {
3232
throw new InvalidTargetingKey();
3333
}
34-
3534
Value anonymousValue = ctx.getValue(anonymousFieldName);
35+
if (anonymousValue == null) {
36+
anonymousValue = new Value(Boolean.FALSE);
37+
}
3638
boolean anonymous = anonymousValue.asBoolean();
3739
Map<String, Object> custom = new HashMap<>(ctx.asObjectMap());
3840
if (ctx.getValue(anonymousFieldName) != null) {

providers/go-feature-flag/src/test/java/dev/openfeature/contrib/providers/gofeatureflag/GoFeatureFlagProviderTest.java

+11-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
package dev.openfeature.contrib.providers.gofeatureflag;
22

3-
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
4-
import static org.junit.jupiter.api.Assertions.assertEquals;
5-
import static org.junit.jupiter.api.Assertions.assertThrows;
6-
73
import java.io.IOException;
84
import java.nio.file.Files;
95
import java.nio.file.Paths;
@@ -33,6 +29,8 @@
3329
import okhttp3.mockwebserver.MockWebServer;
3430
import okhttp3.mockwebserver.RecordedRequest;
3531

32+
import static org.junit.jupiter.api.Assertions.*;
33+
3634
class GoFeatureFlagProviderTest {
3735
// Dispatcher is the configuration of the mock server to test the provider.
3836
final Dispatcher dispatcher = new Dispatcher() {
@@ -138,15 +136,17 @@ void should_resolve_a_valid_boolean_flag_with_TARGETING_MATCH_reason() throws In
138136
GoFeatureFlagProvider g = new GoFeatureFlagProvider(GoFeatureFlagProviderOptions.builder().endpoint(this.baseUrl.toString()).timeout(1000).build());
139137
ProviderEvaluation<Boolean> res = g.getBooleanEvaluation("bool_targeting_match", false, this.evaluationContext);
140138
assertEquals(true, res.getValue());
139+
assertNull(res.getErrorCode());
141140
assertEquals(Reason.TARGETING_MATCH.toString(), res.getReason());
142141
assertEquals("True", res.getVariant());
143142
}
144143

145144
@Test
146-
void should_return_unknown_reason_if_not_exists_in_SDK() throws InvalidOptions {
145+
void should_return_custom_reason_if_returned_by_relay_proxy() throws InvalidOptions {
147146
GoFeatureFlagProvider g = new GoFeatureFlagProvider(GoFeatureFlagProviderOptions.builder().endpoint(this.baseUrl.toString()).timeout(1000).build());
148147
ProviderEvaluation<Boolean> res = g.getBooleanEvaluation("unknown_reason", false, this.evaluationContext);
149148
assertEquals(true, res.getValue());
149+
assertNull(res.getErrorCode());
150150
assertEquals("CUSTOM_REASON", res.getReason());
151151
assertEquals("True", res.getVariant());
152152
}
@@ -170,6 +170,7 @@ void should_resolve_a_valid_string_flag_with_TARGETING_MATCH_reason() throws Inv
170170
GoFeatureFlagProvider g = new GoFeatureFlagProvider(GoFeatureFlagProviderOptions.builder().endpoint(this.baseUrl.toString()).timeout(1000).build());
171171
ProviderEvaluation<String> res = g.getStringEvaluation("string_key", "defaultValue", this.evaluationContext);
172172
assertEquals("CC0000", res.getValue());
173+
assertNull(res.getErrorCode());
173174
assertEquals(Reason.TARGETING_MATCH.toString(), res.getReason());
174175
assertEquals("True", res.getVariant());
175176
}
@@ -193,6 +194,7 @@ void should_resolve_a_valid_integer_flag_with_TARGETING_MATCH_reason() throws In
193194
GoFeatureFlagProvider g = new GoFeatureFlagProvider(GoFeatureFlagProviderOptions.builder().endpoint(this.baseUrl.toString()).timeout(1000).build());
194195
ProviderEvaluation<Integer> res = g.getIntegerEvaluation("integer_key", 1200, this.evaluationContext);
195196
assertEquals(100, res.getValue());
197+
assertNull(res.getErrorCode());
196198
assertEquals(Reason.TARGETING_MATCH.toString(), res.getReason());
197199
assertEquals("True", res.getVariant());
198200
}
@@ -216,6 +218,7 @@ void should_resolve_a_valid_double_flag_with_TARGETING_MATCH_reason() throws Inv
216218
GoFeatureFlagProvider g = new GoFeatureFlagProvider(GoFeatureFlagProviderOptions.builder().endpoint(this.baseUrl.toString()).timeout(1000).build());
217219
ProviderEvaluation<Double> res = g.getDoubleEvaluation("double_key", 1200.25, this.evaluationContext);
218220
assertEquals(100.25, res.getValue());
221+
assertNull(res.getErrorCode());
219222
assertEquals(Reason.TARGETING_MATCH.toString(), res.getReason());
220223
assertEquals("True", res.getVariant());
221224
}
@@ -234,6 +237,7 @@ void should_resolve_a_valid_value_flag_with_TARGETING_MATCH_reason() throws Inva
234237
ProviderEvaluation<Value> res = g.getObjectEvaluation("object_key", null, this.evaluationContext);
235238
Value want = new Value(new MutableStructure().add("test", "test1").add("test2", false).add("test3", 123.3).add("test4", 1));
236239
assertEquals(want, res.getValue());
240+
assertNull(res.getErrorCode());
237241
assertEquals(Reason.TARGETING_MATCH.toString(), res.getReason());
238242
assertEquals("True", res.getVariant());
239243
}
@@ -244,6 +248,7 @@ void should_wrap_into_value_if_wrong_type() throws InvalidOptions {
244248
ProviderEvaluation<Value> res = g.getObjectEvaluation("string_key", null, this.evaluationContext);
245249
Value want = new Value("CC0000");
246250
assertEquals(want, res.getValue());
251+
assertNull(res.getErrorCode());
247252
assertEquals(Reason.TARGETING_MATCH.toString(), res.getReason());
248253
assertEquals("True", res.getVariant());
249254
}
@@ -274,6 +279,7 @@ void should_throw_an_error_if_no_targeting_key() throws InvalidOptions {
274279
new Value("false"),
275280
new Value("test3"))));
276281
assertEquals(want, res.getValue());
282+
assertNull(res.getErrorCode());
277283
assertEquals(Reason.TARGETING_MATCH.toString(), res.getReason());
278284
assertEquals("True", res.getVariant());
279285
}

0 commit comments

Comments
 (0)