Skip to content

Bug: Feature Flag Rule Conditions Values and Context Key Variables cannot have Falsy values #2051

Closed
@ajwad-shaikh

Description

@ajwad-shaikh

Expected Behaviour

Rule Conditions allow users to evaluate context attributes against values and actions defined in Rule Conditions.
The condition can easily be pivoted on a certain value in the context evaluating to falsy values. Consider the following example -

Context-

{
   "is_paid": 0,
}

Feature Flag -

{
  "sales_offer": {
    "default": false,
    "rules": {
      "unpaid_users": {
        "when_match": true,
        "conditions": [ {"action": "EQUALS", "key": "is_paid", "value": 0} ]
      }
   }
}

The values attribute should be able to accept any value except null
The condition should also honor any value for context key variable.

Current Behaviour

Definition - Falsy Values

In python, the following values evaluate to False in boolean context - these are known as falsy values.

empty_list = []
empty_string = ""
zero = 0
false_boolean = False

Falsy Values in Condition value

The values attribute in conditions cannot accept any of the falsy values, some of which are essential to framing conditions in practical use-cases.

If any of the falsy values are present in the condition - the utility throws the error below

File ~/venv/lib/python3.8/site-packages/aws_lambda_powertools/utilities/feature_flags/schema.py:330, in ConditionsValidator.validate_condition_value(condition, rule_name)
    328 value = condition.get(CONDITION_VALUE, "")
    329 if not value:
--> 330     raise SchemaValidationError(f"'value' key must not be empty, rule={rule_name}")
    331 action = condition.get(CONDITION_ACTION, "")
    333 # time actions need to be parsed to make sure date and time format is valid and timezone is recognized

SchemaValidationError: 'value' key must not be empty, rule=unpaid_users

Falsy Values in context value

The conditions simply return evaluate to false if the value for the key passed in context is falsy. These are also extremely essential to framing conditions in practical use-cases.

Example -

🚨 The condition below will evaluate to False even if the context value (0) is NOT EQUAL to condition value (1) 🚨

{
  "sales_offer": {
    "default": false,
    "rules": {
      "unpaid_users": {
        "when_match": true,
        "conditions": [ {"action": "NOT_EQUALS", "key": "is_paid", "value": 1} ]
      }
   }
}

Code snippet

Falsy Values in Condition value

// context.json

{
  "is_paid": 0
}
// features.json

{
  "sales_offer": {
    "default": false,
    "rules": {
      "unpaid_users": {
        "when_match": true,
        "conditions": [ {"action": "EQUALS", "key": "is_paid", "value": 0} ]
      }
   }
}
from aws_lambda_powertools.utilities.feature_flags import FeatureFlags, AppConfigStore

app_config = AppConfigStore(
    environment="dev",
    application="product-catalogue",
    name="features"
)

feature_flags = FeatureFlags(store=app_config)

def lambda_handler(event, context):
    # Get customer's tier from incoming request
    ctx = { "is_paid": 2 } # 1: Standard Plan | 2: Advanced Plan
    is_unpaid: bool = feature_flags.evaluate(name="sales_offer", context=ctx, default=True)

Falsy Values in Context key value

// context.json

{
  "is_paid": 0
}
// features.json

{
  "sales_offer": {
    "default": false,
    "rules": {
      "unpaid_users": {
        "when_match": true,
        "conditions": [ {"action": "NOT_EQUALS", "key": "is_paid", "value": 1} ]
      }
   }
}
from aws_lambda_powertools.utilities.feature_flags import FeatureFlags, AppConfigStore

app_config = AppConfigStore(
    environment="dev",
    application="product-catalogue",
    name="features"
)

feature_flags = FeatureFlags(store=app_config)

def lambda_handler(event, context):
    # Get customer's tier from incoming request
    ctx = { "is_paid": 2 } # 1: Standard Plan | 2: Advanced Plan
    is_unpaid: bool = feature_flags.evaluate(name="sales_offer", context=ctx, default=True)

Possible Solution

Falsy Values in condition value

Instead of
https://github.com/awslabs/aws-lambda-powertools-python/blob/f2435070d53aba8fced2901380438cc6015c6f49/aws_lambda_powertools/utilities/feature_flags/schema.py#L328-L330

suggest

value = condition.get(CONDITION_VALUE, None)
if value is None:
  raise SchemaValidationError(f"'value' key must not be null, rule={rule_name}")

Falsy Values in context key value

Instead of
https://github.com/awslabs/aws-lambda-powertools-python/blob/f2435070d53aba8fced2901380438cc6015c6f49/aws_lambda_powertools/utilities/feature_flags/feature_flags.py#L49-L51

suggest

def _match_by_action(self, action: str, condition_value: Any, context_value: Any) -> bool:
  if context_value is None:
    return False

Steps to Reproduce

Shared code snippet should reproduce the issue

AWS Lambda Powertools for Python version

latest

AWS Lambda function runtime

3.6

Packaging format used

PyPi

Debugging logs

No response

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingfeature_flagsFeature Flags utility

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions