Reducers: Routing and Identity

Reducers are an SDK feature that "reduce" event input to a single value for use in a Flow.

Overview

The Sym SDK uses special Reducer functions to manage request routing, as well as special cases for user identity matching.

Reducers run at specific points in the Flow defined by the Sym backend, and will be triggered with every run of a given Flow.

ReducerRequiredFunction
get_approversyesRoute requests.
get_identitynoMatch and persist user identities in cases where a requester's Slack email address does not match a third party system.

get_approvers

The only required reducer. Accepts an Event representing a Sym Request, and returns a destination that defines where that request should go.

This reducer is the core of Sym's routing logic. For more detail, see How Do I Choose Where My Requests Go.

from sym.sdk.annotations import reducer
from sym.sdk.integrations import pagerduty, okta, slack

@reducer 
def get_approvers(event):
    """Returns a set of approvers, given a user and a target."""
   
    if pagerduty.is_on_call(event.user, schedule_name="prod_on_call_schedule"):
        # This is a self-approval in a DM
        return slack.user(event.user)

    if event.payload.fields["urgency"] == "High":
        # This is a self-approval in a channel
        return slack.channel("#break-glass", allow_self=True)

    on_call_mgrs = okta.users_in_group(group_id="00g12345689")
    # This would create a group DM for on-call managers
    return slack.group(on_call_mgrs)

get_identity

Accepts an Event, a service type, the service's external ID, and a User object, and returns either a string or None. If it returns a value, that value will be used; if it returns None, the normal auto-discovery is still performed.

Normally, Sym attempts to auto-discover users' identities in third-party services you integrate with based on the user's email address. If this isn't possible for whatever reason, this reducer can be used to construct the user's identity instead.

from sym.sdk.annotations import reducer
from sym.sdk.integrations import okta


@reducer
def get_identity(event, service_type, external_id, user):
    """For a given combination of service and user, returns an identifier for
    that user in the service; or, return None to perform automated identity
    discovery in the service."""
  
    if service_type == "aws_iam":
        # For AWS IAM, construct the user's ARN based on the external ID (for
        # AWS IAM, this is the AWS account ID) and the username portion of the
        # user's email
        return f"arn:aws:iam::{external_id}:user/{user.email.split('@')[0]}"
    elif service_type == "okta":
        # For Okta, we need to hard-code the IDs for some users because their
        # emails in Slack don't match their Okta emails.
        email_to_okta_uid = {
            "[email protected]": "00u12345678",
            "[email protected]": "00u9abcdefg",
            "[email protected]": "00uhijklmno"
        }
        
        # For all other users, return None to indicate that we want to perform
        # auto-discovery of the user's identity as normal
        return email_to_okta_uid.get(user.email, None)
      
    return None # For all other services, perform normal auto-discovery