Description
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?