Skip to content

Commit 4f39e18

Browse files
committed
use case-sensitive comparisons
1 parent b37df4f commit 4f39e18

File tree

2 files changed

+28
-38
lines changed

2 files changed

+28
-38
lines changed

posthog/client.py

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -714,9 +714,6 @@ def get_feature_flag(
714714
if self.disabled:
715715
return None
716716

717-
# Normalize key to lowercase
718-
key = str(key).lower()
719-
720717
person_properties, group_properties = self._add_local_person_and_group_properties(
721718
distinct_id, groups, person_properties, group_properties
722719
)
@@ -727,8 +724,7 @@ def get_feature_flag(
727724

728725
if self.feature_flags:
729726
for flag in self.feature_flags:
730-
# Compare lowercase keys
731-
if str(flag["key"]).lower() == key:
727+
if flag["key"] == key:
732728
try:
733729
response = self._compute_flag_locally(
734730
flag,
@@ -826,7 +822,7 @@ def get_feature_flag_payload(
826822
distinct_id, groups, person_properties, group_properties, disable_geoip
827823
)
828824
response = responses_and_payloads["featureFlags"].get(key, None)
829-
payload = responses_and_payloads["featureFlagPayloads"].get(str(key).lower(), None)
825+
payload = responses_and_payloads["featureFlagPayloads"].get(str(key), None)
830826
except Exception as e:
831827
self.log.exception(f"[FEATURE FLAGS] Unable to get feature flags and payloads: {e}")
832828

@@ -859,19 +855,10 @@ def _compute_payload_locally(self, key, match_value):
859855
if self.feature_flags_by_key is None:
860856
return payload
861857

862-
# Normalize key to lowercase when looking up flag definition
863-
key = str(key).lower()
864-
flag_definition = None
865-
for flag_key, flag in self.feature_flags_by_key.items():
866-
if str(flag_key).lower() == key:
867-
flag_definition = flag
868-
break
869-
870-
if flag_definition:
871-
flag_filters = flag_definition.get("filters") or {}
872-
flag_payloads = flag_filters.get("payloads") or {}
873-
payload = flag_payloads.get(str(match_value).lower(), None)
874-
return payload
858+
flag_definition = self.feature_flags_by_key.get(key) or {}
859+
flag_filters = flag_definition.get("filters") or {}
860+
flag_payloads = flag_filters.get("payloads") or {}
861+
payload = flag_payloads.get(str(match_value), None)
875862

876863
def get_all_flags(
877864
self,

posthog/test/test_feature_flags.py

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4642,7 +4642,7 @@ def test_multivariate_flag_consistency(self, patch_get):
46424642
self.assertFalse(feature_flag_match)
46434643

46444644
@mock.patch("posthog.client.decide")
4645-
def test_feature_flag_case_insensitive(self, mock_decide):
4645+
def test_feature_flag_case_sensitive(self, mock_decide):
46464646
client = Client(api_key=FAKE_TEST_API_KEY, personal_api_key=FAKE_TEST_API_KEY)
46474647
client.feature_flags = [
46484648
{
@@ -4655,16 +4655,16 @@ def test_feature_flag_case_insensitive(self, mock_decide):
46554655
}
46564656
]
46574657

4658-
# Test that flag evaluation works regardless of case
4658+
# Test that flag evaluation is case-sensitive
46594659
self.assertTrue(client.feature_enabled("Beta-Feature", "user1"))
4660-
self.assertTrue(client.feature_enabled("beta-feature", "user1"))
4661-
self.assertTrue(client.feature_enabled("BETA-FEATURE", "user1"))
4660+
self.assertFalse(client.feature_enabled("beta-feature", "user1"))
4661+
self.assertFalse(client.feature_enabled("BETA-FEATURE", "user1"))
46624662

46634663
@mock.patch("posthog.client.decide")
4664-
def test_feature_flag_payload_case_insensitive(self, mock_decide):
4664+
def test_feature_flag_payload_case_sensitive(self, mock_decide):
46654665
mock_decide.return_value = {
4666-
"featureFlags": {"beta-feature": True},
4667-
"featureFlagPayloads": {"beta-feature": {"some": "value"}},
4666+
"featureFlags": {"Beta-Feature": True},
4667+
"featureFlagPayloads": {"Beta-Feature": {"some": "value"}},
46684668
}
46694669

46704670
client = Client(api_key=FAKE_TEST_API_KEY, personal_api_key=FAKE_TEST_API_KEY)
@@ -4682,16 +4682,16 @@ def test_feature_flag_payload_case_insensitive(self, mock_decide):
46824682
}
46834683
]
46844684

4685-
# Test that payload retrieval works regardless of case
4685+
# Test that payload retrieval is case-sensitive
46864686
self.assertEqual(client.get_feature_flag_payload("Beta-Feature", "user1"), {"some": "value"})
4687-
self.assertEqual(client.get_feature_flag_payload("beta-feature", "user1"), {"some": "value"})
4688-
self.assertEqual(client.get_feature_flag_payload("BETA-FEATURE", "user1"), {"some": "value"})
4687+
self.assertIsNone(client.get_feature_flag_payload("beta-feature", "user1"))
4688+
self.assertIsNone(client.get_feature_flag_payload("BETA-FEATURE", "user1"))
46894689

46904690
@mock.patch("posthog.client.decide")
4691-
def test_feature_flag_mixed_case_consistency(self, mock_decide):
4691+
def test_feature_flag_case_sensitive_consistency(self, mock_decide):
46924692
mock_decide.return_value = {
4693-
"featureFlags": {"beta-feature": True},
4694-
"featureFlagPayloads": {"beta-feature": {"some": "value"}},
4693+
"featureFlags": {"Beta-Feature": True},
4694+
"featureFlagPayloads": {"Beta-Feature": {"some": "value"}},
46954695
}
46964696

46974697
client = Client(api_key=FAKE_TEST_API_KEY, personal_api_key=FAKE_TEST_API_KEY)
@@ -4709,10 +4709,13 @@ def test_feature_flag_mixed_case_consistency(self, mock_decide):
47094709
}
47104710
]
47114711

4712-
# Test that flag evaluation and payload retrieval are consistent
4713-
# regardless of the case used
4714-
test_cases = ["Beta-Feature", "beta-feature", "BETA-FEATURE", "bEtA-FeAtUrE"]
4712+
# Test that flag evaluation and payload retrieval are consistently case-sensitive
4713+
# Only exact match should work
4714+
self.assertTrue(client.feature_enabled("Beta-Feature", "user1"))
4715+
self.assertEqual(client.get_feature_flag_payload("Beta-Feature", "user1"), {"some": "value"})
4716+
4717+
# Different cases should not match
4718+
test_cases = ["beta-feature", "BETA-FEATURE", "bEtA-FeAtUrE"]
47154719
for case in test_cases:
4716-
# Both the flag evaluation and payload retrieval should work
4717-
self.assertTrue(client.feature_enabled(case, "user1"))
4718-
self.assertEqual(client.get_feature_flag_payload(case, "user1"), {"some": "value"})
4720+
self.assertFalse(client.feature_enabled(case, "user1"))
4721+
self.assertIsNone(client.get_feature_flag_payload(case, "user1"))

0 commit comments

Comments
 (0)