Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamically reloading input expressions #714

Open
jon-whit opened this issue Oct 9, 2024 · 1 comment
Open

Dynamically reloading input expressions #714

jon-whit opened this issue Oct 9, 2024 · 1 comment

Comments

@jon-whit
Copy link

jon-whit commented Oct 9, 2024

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?

@antonmedv
Copy link
Member

Are there any good projects out there doing something like this today?

There are a few open source project which uses Expr, what you can take a look at:

would you have any protips/recommendations on how to orchestrate this pattern with the API in expr today?

If I got your problem correctly, I'd say I go with a rule per resource instead.

So instead of writing a filtering inside filter(Resources, User.GeoCode not in .Resource?.GeoCodes), I'll go with a loop over resources and use filtering per resource:

User.GeoCode not in Resource?.GeoCodes

For your more complex example as well. Additionally we are in the process of developing if-else expressions which can simplify your complex rules.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants