Skip to content

Dynamically reloading input expressions #714

Closed
@jon-whit

Description

@jon-whit

I am evaluating the usage of expr for a work project. We are experimenting with usage of expr to filter resources based on certain content policy definitions. For example, we may have some content policies that express the following:

  • Any user should be blocked from viewing a resource if the resource's GeoCode restriction aligns with the user's' GeoCode.
  • Any user should be blocked from viewing a resource if the resource requires age verification and the user is not age verified.

I have an Env and policy definition that looks like this:

type User struct {
	Id      string
	GeoCode string
        AgeVerified bool
}

type Resource struct {
	Id          string

        // A slice of geo codes this resource is restricted in.
	GeoRestrictions []string

        // A map of consumer content privacy classifiers such as "profanity", "drugs", "political"
        ContentPrivacyClassifications map[string]struct{}
}

type Tweet struct {
	Resource
        UserId string 
}

type Comment struct {
	Resource
	UserId string
}

type Env struct {
	User      User
	Resources []any
}

func main() {
	policy := `filter(Resources,  User.GeoCode not in .Resource?.GeoCodes)`

	program, err := expr.Compile(policy, expr.Env(Env{}))
	if err != nil {
		panic(err)
	}

	output, err := expr.Run(program, Env{
		User: User{Id: "cool_dude", GeoCode: "us", AgeVerified: false},
		Resources: []any{
			Tweet{
				Resource: Resource{
					Id:          "tweet:1",
					GeoRestrictions: []string{"ru"}},
                                         ContentPrivacyClassifications: map[string]struct{}{
                                             "profanity": {},
                                         },
				},
				UserId: "other_dude",
			},
			Comment{Resource: Resource{Id: "comment:x"}},
		},
	})
	if err != nil {
		panic(err)
	}

	fmt.Println(output)
}

Today the content filtering policy only depends on the User.GeoCode not in .Resource?.GeoCodes, but tomorrow we may want to change the policy so that a user with additional content privacy restrictions doesn't see resources with those classification codes. For example, we would want to change the policy to something like:

// any resource with content classified as "profanity" or "drugs" should not be viewable by non age verified users

filter(Resources,  User.GeoCode not in .Resource?.LegalBlocks?.GeoCodes && (any(keys(.Resource.ContentPrivacyClassifications), # in ["profanity", "drugs"]) && User.AgeVerified) || all(keys(.Resource.ContentPrivacyClassifications), # not in ["profanity", "drugs"]))

But we don't want to change the code itself. In other words, we want more dynamic resource filtering.

Are there any good projects out there doing something like this today? If not, would you have any protips/recommendations on how to orchestrate this pattern with the API in expr today?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions